[PATCH] hardy-lbm: Upgrading to bcm5974-0.65

Henrik Rydberg rydberg at euromail.se
Sat Sep 27 17:39:02 BST 2008


This patch brings hardy-lbm to the same version as is already present upstream and in intrepid,
but with the lbm-specific quirks patch preserved.

Signed-off-by: Henrik Rydberg <rydberg at euromail.se>
---
 updates/input/mouse/bcm5974.c |  296 ++++++++++++++++++++++++-----------------
 1 files changed, 174 insertions(+), 122 deletions(-)

diff --git a/updates/input/mouse/bcm5974.c b/updates/input/mouse/bcm5974.c
index 5edc784..2c92c80 100644
--- a/updates/input/mouse/bcm5974.c
+++ b/updates/input/mouse/bcm5974.c
@@ -63,7 +63,7 @@
 }
 
 /* table of devices that work with this driver */
-static const struct usb_device_id bcm5974_table [] = {
+static const struct usb_device_id bcm5974_table[] = {
 	/* MacbookAir1.1 */
 	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
 	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
@@ -105,7 +105,7 @@ struct tp_header {
 
 /* trackpad finger structure */
 struct tp_finger {
-	__le16 origin;		/* left/right origin? */
+	__le16 origin;		/* zero when switching track finger */
 	__le16 abs_x;		/* absolute x coodinate */
 	__le16 abs_y;		/* absolute y coodinate */
 	__le16 rel_x;		/* relative x coodinate */
@@ -150,15 +150,16 @@ struct bcm5974_config {
 struct bcm5974 {
 	char phys[64];
 	struct usb_device *udev;	/* usb device */
+	struct usb_interface *intf;	/* our interface */
 	struct input_dev *input;	/* input dev */
 	struct bcm5974_config cfg;	/* device configuration */
-	struct mutex mutex;		/* serialize access to open/suspend */
-	int opened;			/* >0: opened, else closed */
-	int manually_suspended;		/* >0: manually suspended */
+	struct mutex pm_mutex;		/* serialize access to open/suspend */
+	int opened;			/* 1: opened, 0: closed */
 	struct urb *bt_urb;		/* button usb request block */
 	struct bt_data *bt_data;	/* button transferred data */
 	struct urb *tp_urb;		/* trackpad usb request block */
 	struct tp_data *tp_data;	/* trackpad transferred data */
+	int fingers;			/* number of fingers on trackpad */
 };
 
 /* logical dimensions */
@@ -172,6 +173,10 @@ struct bcm5974 {
 #define SN_WIDTH	100		/* width signal-to-noise ratio */
 #define SN_COORD	250		/* coordinate signal-to-noise ratio */
 
+/* pressure thresholds */
+#define PRESSURE_LOW	(2 * DIM_PRESSURE / SN_PRESSURE)
+#define PRESSURE_HIGH	(3 * PRESSURE_LOW)
+
 /* device constants */
 static const struct bcm5974_config bcm5974_config_table[] = {
 	{
@@ -204,9 +209,11 @@ static const struct bcm5974_config *bcm5974_get_config(struct usb_device *udev)
 {
 	u16 id = le16_to_cpu(udev->descriptor.idProduct);
 	const struct bcm5974_config *cfg;
+
 	for (cfg = bcm5974_config_table; cfg->ansi; ++cfg)
 		if (cfg->ansi == id || cfg->iso == id || cfg->jis == id)
 			return cfg;
+
 	return bcm5974_config_table;
 }
 
@@ -231,23 +238,25 @@ static inline int int2bound(const struct bcm5974_param *p, int x)
 
 /* setup which logical events to report */
 static void setup_events_to_report(struct input_dev *input_dev,
-	const struct bcm5974_config *cfg)
+				   const struct bcm5974_config *cfg)
 {
-	set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_ABS, input_dev->evbit);
+
 	input_set_abs_params(input_dev, ABS_PRESSURE,
-		0, cfg->p.dim, cfg->p.fuzz, 0);
+				0, cfg->p.dim, cfg->p.fuzz, 0);
 	input_set_abs_params(input_dev, ABS_TOOL_WIDTH,
-		0, cfg->w.dim, cfg->w.fuzz, 0);
+				0, cfg->w.dim, cfg->w.fuzz, 0);
 	input_set_abs_params(input_dev, ABS_X,
-		0, cfg->x.dim, cfg->x.fuzz, 0);
+				0, cfg->x.dim, cfg->x.fuzz, 0);
 	input_set_abs_params(input_dev, ABS_Y,
-		0, cfg->y.dim, cfg->y.fuzz, 0);
-
-	set_bit(EV_KEY, input_dev->evbit);
-	set_bit(BTN_TOOL_FINGER, input_dev->keybit);
-	set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-	set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
-	set_bit(BTN_LEFT, input_dev->keybit);
+				0, cfg->y.dim, cfg->y.fuzz, 0);
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+	__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+	__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+	__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
+	__set_bit(BTN_LEFT, input_dev->keybit);
 }
 
 /* report button data as logical button state */
@@ -267,38 +276,71 @@ static int report_tp_state(struct bcm5974 *dev, int size)
 {
 	const struct bcm5974_config *c = &dev->cfg;
 	const struct tp_finger *f = dev->tp_data->finger;
+	struct input_dev *input = dev->input;
 	const int fingers = (size - 26) / 28;
-	int p, w, x, y, n;
+	int raw_p, raw_w, raw_x, raw_y;
+	int ptest = 0, origin = 0, nmin = 0, nmax = 0;
+	int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
 
 	if (size < 26 || (size - 26) % 28 != 0)
 		return -EIO;
 
-	if (!fingers) {
-		input_report_abs(dev->input, ABS_PRESSURE, 0);
-		input_report_key(dev->input, BTN_TOOL_FINGER, false);
-		input_report_key(dev->input, BTN_TOOL_DOUBLETAP, false);
-		input_report_key(dev->input, BTN_TOOL_TRIPLETAP, false);
-		input_sync(dev->input);
-		return 0;
+	/* always track the first finger; when detached, start over */
+	if (fingers) {
+		raw_p = raw2int(f->force_major);
+		raw_w = raw2int(f->size_major);
+		raw_x = raw2int(f->abs_x);
+		raw_y = raw2int(f->abs_y);
+
+		dprintk(9,
+			"bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n",
+			raw_p, raw_w, raw_x, raw_y);
+
+		ptest = int2bound(&c->p, raw_p);
+		origin = raw2int(f->origin);
 	}
 
-	p = raw2int(f->force_major);
-	w = raw2int(f->size_major);
-	x = raw2int(f->abs_x);
-	y = raw2int(f->abs_y);
-	n = p > 0 ? fingers : 0;
-
-	dprintk(9, "bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
-		p, w, x, y, n);
-
-	input_report_abs(dev->input, ABS_PRESSURE, int2bound(&c->p, p));
-	input_report_abs(dev->input, ABS_TOOL_WIDTH, int2bound(&c->w, w));
-	input_report_abs(dev->input, ABS_X, int2bound(&c->x, x - c->x.devmin));
-	input_report_abs(dev->input, ABS_Y, int2bound(&c->y, c->y.devmax - y));
-	input_report_key(dev->input, BTN_TOOL_FINGER, n == 1);
-	input_report_key(dev->input, BTN_TOOL_DOUBLETAP, n == 2);
-	input_report_key(dev->input, BTN_TOOL_TRIPLETAP, n > 2);
-	input_sync(dev->input);
+	/* while tracking finger still valid, count all fingers */
+	if (ptest > PRESSURE_LOW && origin) {
+		abs_p = ptest;
+		abs_w = int2bound(&c->w, raw_w);
+		abs_x = int2bound(&c->x, raw_x - c->x.devmin);
+		abs_y = int2bound(&c->y, c->y.devmax - raw_y);
+		for (; f != dev->tp_data->finger + fingers; f++) {
+			ptest = int2bound(&c->p, raw2int(f->force_major));
+			if (ptest > PRESSURE_LOW)
+				nmax++;
+			if (ptest > PRESSURE_HIGH)
+				nmin++;
+		}
+	}
+
+	if (dev->fingers < nmin)
+		dev->fingers = nmin;
+	if (dev->fingers > nmax)
+		dev->fingers = nmax;
+
+	input_report_key(input, BTN_TOUCH, dev->fingers > 0);
+	input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);
+	input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2);
+	input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2);
+
+	input_report_abs(input, ABS_PRESSURE, abs_p);
+	input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
+
+	if (abs_p) {
+		input_report_abs(input, ABS_X, abs_x);
+		input_report_abs(input, ABS_Y, abs_y);
+
+		dprintk(8,
+			"bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d "
+			"nmin: %d nmax: %d n: %d\n",
+			abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers);
+
+	}
+
+	input_sync(input);
+
 	return 0;
 }
 
@@ -308,58 +350,59 @@ static int report_tp_state(struct bcm5974 *dev, int size)
 #define BCM5974_WELLSPRING_MODE_REQUEST_VALUE		0x300
 #define BCM5974_WELLSPRING_MODE_REQUEST_INDEX		0
 #define BCM5974_WELLSPRING_MODE_VENDOR_VALUE		0x01
+#define BCM5974_WELLSPRING_MODE_NORMAL_VALUE		0x08
 
-static int bcm5974_wellspring_mode(struct bcm5974 *dev)
+static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
 {
 	char *data = kmalloc(8, GFP_KERNEL);
-	int error = 0, size;
+	int retval = 0, size;
 
 	if (!data) {
 		err("bcm5974: out of memory");
-		error = -ENOMEM;
-		goto error;
+		retval = -ENOMEM;
+		goto out;
 	}
 
 	/* read configuration */
 	size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
-		BCM5974_WELLSPRING_MODE_READ_REQUEST_ID,
-		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-		BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
-		BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
+			BCM5974_WELLSPRING_MODE_READ_REQUEST_ID,
+			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
+			BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
 
 	if (size != 8) {
 		err("bcm5974: could not read from device");
-		error = -EIO;
-		goto error;
+		retval = -EIO;
+		goto out;
 	}
 
 	/* apply the mode switch */
-	data[0] = BCM5974_WELLSPRING_MODE_VENDOR_VALUE;
+	data[0] = on ?
+		BCM5974_WELLSPRING_MODE_VENDOR_VALUE :
+		BCM5974_WELLSPRING_MODE_NORMAL_VALUE;
 
 	/* write configuration */
 	size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
-		BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID,
-		USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-		BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
-		BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
+			BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID,
+			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
+			BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
 
 	if (size != 8) {
 		err("bcm5974: could not write to device");
-		error = -EIO;
-		goto error;
+		retval = -EIO;
+		goto out;
 	}
 
-	dprintk(2, "bcm5974: switched to wellspring mode.\n");
-
-	kfree(data);
-	return 0;
+	dprintk(2, "bcm5974: switched to %s mode.\n",
+		on ? "wellspring" : "normal");
 
-error:
+ out:
 	kfree(data);
-	return error;
+	return retval;
 }
 
-static void irq_button(struct urb *urb)
+static void bcm5974_irq_button(struct urb *urb)
 {
 	struct bcm5974 *dev = urb->context;
 	int error;
@@ -388,7 +431,7 @@ exit:
 		err("bcm5974: button urb failed: %d", error);
 }
 
-static void irq_trackpad(struct urb *urb)
+static void bcm5974_irq_trackpad(struct urb *urb)
 {
 	struct bcm5974 *dev = urb->context;
 	int error;
@@ -439,28 +482,32 @@ exit:
  * plus start_traffic, it seems easier to always do the switch when
  * starting traffic on the device.
  */
-static int start_traffic(struct bcm5974 *dev)
+static int bcm5974_start_traffic(struct bcm5974 *dev)
 {
-	if (bcm5974_wellspring_mode(dev)) {
+	if (bcm5974_wellspring_mode(dev, true)) {
 		dprintk(1, "bcm5974: mode switch failed\n");
 		goto error;
 	}
+
 	if (usb_submit_urb(dev->bt_urb, GFP_KERNEL))
 		goto error;
+
 	if (usb_submit_urb(dev->tp_urb, GFP_KERNEL))
 		goto err_kill_bt;
 
 	return 0;
+
 err_kill_bt:
 	usb_kill_urb(dev->bt_urb);
 error:
 	return -EIO;
 }
 
-static void pause_traffic(struct bcm5974 *dev)
+static void bcm5974_pause_traffic(struct bcm5974 *dev)
 {
 	usb_kill_urb(dev->tp_urb);
 	usb_kill_urb(dev->bt_urb);
+	bcm5974_wellspring_mode(dev, false);
 }
 
 /*
@@ -474,15 +521,22 @@ static void pause_traffic(struct bcm5974 *dev)
 static int bcm5974_open(struct input_dev *input)
 {
 	struct bcm5974 *dev = input_get_drvdata(input);
-	int error = 0;
+	int error;
 
-	mutex_lock(&dev->mutex);
-	if (dev->manually_suspended)
-		error = -EACCES;
-	else if (!dev->opened)
-		error = start_traffic(dev);
-	dev->opened = !error;
-	mutex_unlock(&dev->mutex);
+	error = usb_autopm_get_interface(dev->intf);
+	if (error)
+		return error;
+
+	mutex_lock(&dev->pm_mutex);
+
+	error = bcm5974_start_traffic(dev);
+	if (!error)
+		dev->opened = 1;
+
+	mutex_unlock(&dev->pm_mutex);
+
+	if (error)
+		usb_autopm_put_interface(dev->intf);
 
 	return error;
 }
@@ -491,24 +545,26 @@ static void bcm5974_close(struct input_dev *input)
 {
 	struct bcm5974 *dev = input_get_drvdata(input);
 
-	mutex_lock(&dev->mutex);
-	if (!dev->manually_suspended)
-		pause_traffic(dev);
+	mutex_lock(&dev->pm_mutex);
+
+	bcm5974_pause_traffic(dev);
 	dev->opened = 0;
-	mutex_unlock(&dev->mutex);
+
+	mutex_unlock(&dev->pm_mutex);
+
+	usb_autopm_put_interface(dev->intf);
 }
 
 static int bcm5974_suspend(struct usb_interface *iface, pm_message_t message)
 {
 	struct bcm5974 *dev = usb_get_intfdata(iface);
 
-	if (dev) {
-		mutex_lock(&dev->mutex);
-		if (dev->opened && !dev->manually_suspended)
-			pause_traffic(dev);
-		dev->manually_suspended++;
-		mutex_unlock(&dev->mutex);
-	}
+	mutex_lock(&dev->pm_mutex);
+
+	if (dev->opened)
+		bcm5974_pause_traffic(dev);
+
+	mutex_unlock(&dev->pm_mutex);
 
 	return 0;
 }
@@ -518,22 +574,18 @@ static int bcm5974_resume(struct usb_interface *iface)
 	struct bcm5974 *dev = usb_get_intfdata(iface);
 	int error = 0;
 
-	if (dev) {
-		mutex_lock(&dev->mutex);
-		if (dev->manually_suspended)
-			dev->manually_suspended--;
-		if (dev->opened && !dev->manually_suspended)
-			error = start_traffic(dev);
-		if (error)
-			dev->opened = 0;
-		mutex_unlock(&dev->mutex);
-	}
+	mutex_lock(&dev->pm_mutex);
+
+	if (dev->opened)
+		error = bcm5974_start_traffic(dev);
+
+	mutex_unlock(&dev->pm_mutex);
 
 	return error;
 }
 
 static int bcm5974_probe(struct usb_interface *iface,
-		     const struct usb_device_id *id)
+			 const struct usb_device_id *id)
 {
 	struct usb_device *udev = interface_to_usbdev(iface);
 	const struct bcm5974_config *cfg;
@@ -553,9 +605,10 @@ static int bcm5974_probe(struct usb_interface *iface,
 	}
 
 	dev->udev = udev;
+	dev->intf = iface;
 	dev->input = input_dev;
 	dev->cfg = *cfg;
-	mutex_init(&dev->mutex);
+	mutex_init(&dev->pm_mutex);
 
 	/* setup urbs */
 	dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -567,26 +620,26 @@ static int bcm5974_probe(struct usb_interface *iface,
 		goto err_free_bt_urb;
 
 	dev->bt_data = usb_buffer_alloc(dev->udev,
-		dev->cfg.bt_datalen, GFP_KERNEL,
-		&dev->bt_urb->transfer_dma);
+					dev->cfg.bt_datalen, GFP_KERNEL,
+					&dev->bt_urb->transfer_dma);
 	if (!dev->bt_data)
 		goto err_free_urb;
 
 	dev->tp_data = usb_buffer_alloc(dev->udev,
-		dev->cfg.tp_datalen, GFP_KERNEL,
-		&dev->tp_urb->transfer_dma);
+					dev->cfg.tp_datalen, GFP_KERNEL,
+					&dev->tp_urb->transfer_dma);
 	if (!dev->tp_data)
 		goto err_free_bt_buffer;
 
 	usb_fill_int_urb(dev->bt_urb, udev,
-		usb_rcvintpipe(udev, cfg->bt_ep),
-		dev->bt_data, dev->cfg.bt_datalen,
-		irq_button, dev, 1);
+			 usb_rcvintpipe(udev, cfg->bt_ep),
+			 dev->bt_data, dev->cfg.bt_datalen,
+			 bcm5974_irq_button, dev, 1);
 
 	usb_fill_int_urb(dev->tp_urb, udev,
-		usb_rcvintpipe(udev, cfg->tp_ep),
-		dev->tp_data, dev->cfg.tp_datalen,
-		irq_trackpad, dev, 1);
+			 usb_rcvintpipe(udev, cfg->tp_ep),
+			 dev->tp_data, dev->cfg.tp_datalen,
+			 bcm5974_irq_trackpad, dev, 1);
 
 	/* create bcm5974 device */
 	usb_make_path(udev, dev->phys, sizeof(dev->phys));
@@ -638,24 +691,23 @@ static void bcm5974_disconnect(struct usb_interface *iface)
 
 	input_unregister_device(dev->input);
 	usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
-		dev->tp_data, dev->tp_urb->transfer_dma);
+			dev->tp_data, dev->tp_urb->transfer_dma);
 	usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
-		dev->bt_data, dev->bt_urb->transfer_dma);
+			dev->bt_data, dev->bt_urb->transfer_dma);
 	usb_free_urb(dev->tp_urb);
 	usb_free_urb(dev->bt_urb);
 	kfree(dev);
-
-	printk(KERN_INFO "bcm5974: disconnected\n");
 }
 
 static struct usb_driver bcm5974_driver = {
-	.name = "bcm5974",
-	.probe = bcm5974_probe,
-	.disconnect = bcm5974_disconnect,
-	.suspend = bcm5974_suspend,
-	.resume = bcm5974_resume,
-	.reset_resume = bcm5974_resume,
-	.id_table = bcm5974_table,
+	.name			= "bcm5974",
+	.probe			= bcm5974_probe,
+	.disconnect		= bcm5974_disconnect,
+	.suspend		= bcm5974_suspend,
+	.resume			= bcm5974_resume,
+	.reset_resume		= bcm5974_resume,
+	.id_table		= bcm5974_table,
+	.supports_autosuspend	= 1,
 };
 
 static const struct hid_blacklist {
-- 
1.5.6.3


--------------090506030802080007050108--



More information about the kernel-team mailing list