Re: [PATCH 001/002] linux-input: bcm5974-0.31: fixed resource leak, removed work struct, device data struct introduced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> Subject: [PATCH 001/002] linux-input:  bcm5974-0.31: fixed resource leak, removed work struct, device data struct introduced

hm, I wonder where [002/002] went.

Please copy the USB list on USB patches.

On Sat, 28 Jun 2008 14:54:20 +0200
Henrik Rydberg <rydberg@xxxxxxxxxxx> wrote:

> BCM5974: This driver adds support for the multitouch trackpad on the new
> Apple Macbook Air and Macbook Pro Penryn laptops. It replaces the
> appletouch driver on those computers, and integrates well with the
> synaptics driver of the Xorg system. 

- erk, the driver uses two-spaces for indenting all over the place. 
  Mayeb the email client mangled it in imaginative ways, but it _looks_
  to be intentional.

  If so, please don't do that.  Kernel code uses hard tabs at
  8-cols-per-tab for indenting.


> +config MOUSE_BCM5974
> +	tristate "Apple USB BCM5974 Multitouch trackpad support"
> +	depends on USB_ARCH_HAS_HCD
> +	select USB

selecting USB here seems like a bad idea, although I note that several
other drivers had bad ideas.  `depends on' would be better, IMO.

> +	help
> +	  Say Y here if you have an Apple USB BCM5974 Multitouch
> +	  trackpad.
> +
> +          The BCM5974 is the multitouch trackpad found in the Macbook
> +          Air (JAN2008) and Macbook Pro Penryn (FEB2008) laptops.
> +
> +          It is also found in the IPhone (2007) and Ipod Touch (2008).
> +
> +	  This driver provides multitouch functionality together with
> +          the synaptics X11 driver.
> +
> +          The interface is currently identical to the appletouch interface,
> +          for further information, see
> +          <file:Documentation/input/appletouch.txt>.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called bcm5974.
> +
>  config MOUSE_INPORT
>  	tristate "InPort/MS/ATIXL busmouse"
>  	depends on ISA
> diff -puN drivers/input/mouse/Makefile~input-support-for-bcm5974-multitouch-trackpad drivers/input/mouse/Makefile
> --- a/drivers/input/mouse/Makefile~input-support-for-bcm5974-multitouch-trackpad
> +++ a/drivers/input/mouse/Makefile
> @@ -6,6 +6,7 @@
>  
>  obj-$(CONFIG_MOUSE_AMIGA)	+= amimouse.o
>  obj-$(CONFIG_MOUSE_APPLETOUCH)	+= appletouch.o
> +obj-$(CONFIG_MOUSE_BCM5974)	+= bcm5974.o
>  obj-$(CONFIG_MOUSE_ATARI)	+= atarimouse.o
>  obj-$(CONFIG_MOUSE_RISCPC)	+= rpcmouse.o
>  obj-$(CONFIG_MOUSE_INPORT)	+= inport.o
>
> ...
>
> +static inline
> +const struct atp_config_t *atp_product_config(struct usb_device *udev)
> +{
> +  u16 id = le16_to_cpu(udev->descriptor.idProduct);
> +  const struct atp_config_t *config;
> +  for (config = atp_config_table; config->ansi; ++config)
> +    if (config->ansi == id || config->iso == id || config->jis == id)
> +      return config;
> +  return atp_config_table;
> +}

This is waaaaaaay too big for inlining.

> +/* Wellspring initialization constants */
> +#define ATP_WELLSPRING_MODE_READ_REQUEST_ID   1
> +#define ATP_WELLSPRING_MODE_WRITE_REQUEST_ID  9
> +#define ATP_WELLSPRING_MODE_REQUEST_VALUE     0x300
> +#define ATP_WELLSPRING_MODE_REQUEST_INDEX     0
> +#define ATP_WELLSPRING_MODE_VENDOR_VALUE_1    0x01
> +#define ATP_WELLSPRING_MODE_VENDOR_VALUE_2    0x05
> +
> +#define dprintk(format, a...) \
> +  { if (debug) printk(KERN_DEBUG format, ##a); }
> +
> +MODULE_AUTHOR("Henrik Rydberg");
> +MODULE_DESCRIPTION("Apple USB BCM5974 multitouch driver");
> +MODULE_LICENSE("GPL");
> +
> +static int debug = 1;
> +module_param(debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Activate debugging output");
> +
> +static int atp_wellspring_init(struct usb_device *udev)
> +{
> +  const struct atp_config_t *cfg = atp_product_config(udev);
> +  char *data = kmalloc(8, GFP_DMA);
> +  int size;
> +
> +  /* reset button endpoint */
> +  if (usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> +		      USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
> +		      0, cfg->bt_ep, NULL, 0, 5000)) {
> +    err("Could not reset button endpoint");
> +    goto error;
> +  }
> +
> +  /* reset trackpad endpoint */
> +  if (usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> +		      USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
> +		      0, cfg->tp_ep, NULL, 0, 5000)) {
> +    err("Could not reset trackpad endpoint");
> +    goto error;
> +  }
> +
> +  /* read configuration */
> +  size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> +			 ATP_WELLSPRING_MODE_READ_REQUEST_ID,
> +			 USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
> +			 ATP_WELLSPRING_MODE_REQUEST_VALUE,
> +			 ATP_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
> +
> +  if (size != 8) {
> +    err("Could not do mode read request from device (Wellspring Raw mode)");
> +    goto error;
> +  }
> +
> +  /* apply the mode switch */
> +  data[0] = ATP_WELLSPRING_MODE_VENDOR_VALUE_1;
> +  data[1] = ATP_WELLSPRING_MODE_VENDOR_VALUE_2;

This will crash the kernel if the kmalloc() failed.  And
kmalloc(GFP_DMA) can easily fail.

Do we really need memory from the GFP_DMA region for this driver?  It
would be terribly old-fashioned.

I dunno what USB driver normally use for their dma memory.  Perhaps
dma_alloc_coherent()?

> +  /* write configuration */
> +  size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> +			 ATP_WELLSPRING_MODE_WRITE_REQUEST_ID,
> +			 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
> +			 ATP_WELLSPRING_MODE_REQUEST_VALUE,
> +			 ATP_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
> +
> +  if (size != 8) {
> +    err("Could not do mode write request to device (Wellspring Raw mode)");
> +    goto error;
> +  }
> +
> +  kfree(data);
> +  return 0;
> +
> + error:
> +  kfree(data);
> +  return -EIO;
> +}
> +
> +/* Structure to hold all of our device specific stuff */
> +struct atp {
> +  char			phys[64];
> +  struct usb_device    *udev;	      /* usb device */
> +  struct input_dev     *input;	      /* input dev */
> +  struct atp_config_t	cfg;	      /* device configuration */
> +  unsigned		open;	      /* non-zero if opened */
> +  struct urb	       *bt_urb;	      /* button usb request block */
> +  signed char	       *bt_data;      /* button transferred data */
> +  unsigned		bt_valid;     /* are the button sensors valid ? */
> +  unsigned		bt_state;     /* current button state */
> +  struct urb	       *tp_urb;	      /* trackpad usb request block */
> +  signed char	       *tp_data;      /* trackpad transferred data */
> +  unsigned		tp_valid;     /* are the trackpad sensors valid ? */
> +};
> +
> +static inline int raw2int(__le16 x)
> +{
> +  return (short)le16_to_cpu(x);

Given that this function returns signed 32-bit, I'd worry about what it
does when it is presented with 0xffff.  otoh, perhaps you indeed
intended to handle negative 16-bit quantities in that fashion, which
would make sense.

> +}
> +
> +static inline int int2scale(const struct atp_params_t *p, int x)
> +{
> +  return ((p->max-p->min)*x)/(p->devmax-p->devmin);
> +}

Is there any way in which this can get a divide-by-zero?

> +/**
> + * all value ranges, both device and logical, are assumed to be [a,b).
> + */
> +static inline int int2bound(const struct atp_params_t *p, int x)
> +{
> +  int s = p->min+int2scale(p, x);

Please put a space around the operators in expressions like this.

> +  return s < p->min?p->min:s >= p->max?p->max-1:s;

That's just unreadable. Please simplify it.

> +}
> +
> +/**

This leadin is exclusively used to identify a kerneldoc-style comment.

> + * check quality of reading.
> + * -1: bad data
> + * 0:  ignore this reading
> + * 1:  good reading
> + */

But this is not a kerneldoc comment.  Please remove all the incorrect
/** instances.

>
> ...
>
> +/**
> + * convert raw data to synaptics sensor output.
> + * returns the number of fingers on the trackpad,
> + * or a negative number in vase of bad data.
> + */
> +static int compute_movement(int *abs_x, int *abs_y,
> +			    int *rel_x, int *rel_y,
> +			    int *pressure,
> +			    struct atp_config_t *cfg,
> +			    const unsigned char *data, int size)
> +{
> +  const int nfinger = (size-26)/28;
> +  const struct tp_data_t *tp = (struct tp_data_t *) data;
> +
> +  if (nfinger) {
> +    *abs_x = int2bound(&cfg->x, raw2int(tp->finger->abs_x) - cfg->x.devmin);
> +    *abs_y = int2bound(&cfg->y, cfg->y.devmax - raw2int(tp->finger->abs_y));
> +    *rel_x = int2scale(&cfg->x, raw2int(tp->finger->rel_x));
> +    *rel_y = int2scale(&cfg->y, -raw2int(tp->finger->rel_y));
> +    *pressure = int2bound(&cfg->p, raw2int(tp->finger->force_major));
> +  } else {
> +    *abs_x = 0;
> +    *abs_y = 0;
> +    *rel_x = 0;
> +    *rel_y = 0;
> +    *pressure = 0;
> +  }
> +
> +  /* report zero fingers for zero pressure */
> +  return *pressure > 0?nfinger:0;

Normal style is

	return *pressure > 0 ? nfinger : 0;

(lots of other places)

> +}
> +
> +static void atp_button(struct urb *urb)
> +{
> +  struct atp *dev = urb->context;
> +  const unsigned char *data = dev->bt_data;
> +  const int size = dev->bt_urb->actual_length;
> +  int button = 0, retval;
> +
> +  switch (urb->status) {
> +  case 0:
> +    /* success */
> +    break;
> +  case -EOVERFLOW:
> +  case -ECONNRESET:
> +  case -ENOENT:
> +  case -ESHUTDOWN:
> +    /* This urb is terminated, clean up */
> +    dbg("%s - urb shutting down with status: %d",
> +	__func__, urb->status);
> +    return;
> +  default:
> +    dbg("%s - nonzero urb status received: %d",
> +	__func__, urb->status);
> +    goto exit;
> +  }
> +
> +  /* first sample data ignored */
> +  if (!dev->bt_valid) {
> +    dev->bt_valid = 1;
> +    goto exit;
> +  }
> +
> +  /* drop incomplete datasets */
> +  if (size != 4) {
> +    dprintk("bcm5974: incomplete button package (first byte: %d, length: %d)\n",
> +	    (int)data[0], size);
> +    goto exit;
> +  }
> +
> +  button = data[1];
> +
> +  /* only report button state changes */
> +  if (button != dev->bt_state) {
> +    input_report_key(dev->input, BTN_LEFT, button);
> +    input_sync(dev->input);
> +  }
> +
> +  dev->bt_state = button;
> +
> + exit:
> +  retval = usb_submit_urb(dev->bt_urb, GFP_ATOMIC);

GFP_ATOMIC is a red flag.  Is this quite unrelaible allocation mode
really needed here?

> +  if (retval) {
> +    err("%s - button usb_submit_urb failed with result %d",
> +	__func__, retval);
> +  }
> +}
> +
> +static void atp_trackpad(struct urb *urb)
> +{
> +  struct atp *dev = urb->context;
> +  int abs_x, abs_y, rel_x, rel_y, pressure;
> +  int quality, nfinger, retval;
> +
> +  switch (urb->status) {
> +  case 0:
> +    /* success */
> +    break;
> +  case -EOVERFLOW:
> +  case -ECONNRESET:
> +  case -ENOENT:
> +  case -ESHUTDOWN:
> +    /* This urb is terminated, clean up */
> +    dbg("%s - urb shutting down with status: %d",
> +	__func__, urb->status);
> +    return;
> +  default:
> +    dbg("%s - nonzero urb status received: %d",
> +	__func__, urb->status);
> +    goto exit;
> +  }
> +
> +  /* first sample data ignored */
> +  if (!dev->tp_valid) {
> +    dev->tp_valid = 1;
> +    goto exit;
> +  }
> +
> +  /* determine quality of reading */
> +  quality = compute_quality(dev->tp_data, dev->tp_urb->actual_length);
> +
> +  /* drop incomplete datasets */
> +  if (quality < 0) {
> +    dprintk("bcm5974: incomplete trackpad package "
> +	    "(first byte: %d, length: %d)\n",
> +	    (int)dev->tp_data[0], dev->tp_urb->actual_length);
> +    goto exit;
> +  }
> +
> +  /* drop poor quality readings */
> +  if (quality == 0)
> +    goto exit;
> +
> +  nfinger = compute_movement(&abs_x, &abs_y, &rel_x, &rel_y, &pressure,
> +			     &dev->cfg,
> +			     dev->tp_data, dev->tp_urb->actual_length);
> +
> +  if (debug > 1) {
> +    printk(KERN_DEBUG "bcm5974: x: %04d y: %04d dx: %3d dy: %3d p: %3d\n",
> +	   abs_x, abs_y, rel_x, rel_y, pressure);
> +  }
> +
> +  /* input_report_key(dev->input,BTN_TOUCH,pressure>dev->cfg.p.fuzz); */
> +  input_report_abs(dev->input, ABS_PRESSURE, pressure);
> +  input_report_abs(dev->input, ABS_X, abs_x);
> +  input_report_abs(dev->input, ABS_Y, abs_y);
> +  /* input_report_rel(dev->input, REL_X, rel_x); */
> +  /* input_report_rel(dev->input, REL_Y, rel_y); */
> +  input_report_key(dev->input, BTN_TOOL_FINGER, nfinger == 1);
> +  input_report_key(dev->input, BTN_TOOL_DOUBLETAP, nfinger == 2);
> +  input_report_key(dev->input, BTN_TOOL_TRIPLETAP, nfinger > 2);
> +  input_sync(dev->input);
> +
> + exit:
> +  retval = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);

ditto.

> +  if (retval) {
> +    err("%s - trackpad usb_submit_urb failed with result %d",
> +	__func__, retval);
> +  }
> +}
> +
> +static int atp_open(struct input_dev *input)
> +{
> +  struct atp *dev = input_get_drvdata(input);
> +
> +  if (usb_submit_urb(dev->bt_urb, GFP_ATOMIC))
> +    goto error;
> +
> +  if (usb_submit_urb(dev->tp_urb, GFP_ATOMIC))
> +    goto err_free_bt_urb;

etc.

> +  dev->open = 1;
> +  return 0;
> +
> + err_free_bt_urb:
> +  usb_free_urb(dev->bt_urb);
> + error:
> +  return -EIO;
> +}
> +
>
> ...
>

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux