Starting up the CD on a Macbook Air or Macbook Pro Penryn, both of
which use the bcm5974 trackpad driver, the mouse pointer is initially
frozen. The reason is that the bcm5974 driver only mimics a synaptics
touchpad, not a mouse. After configuring the synaptics driver
everything is fine, but the default behavior is simply not going to
work well for first time users.  This patch upgrades Intrepid to
bcm5974-0.6, which by default operates as a regular mouse.

Bug: https://bugs.launchpad.net/ubuntu/+source/linux-meta/+bug/263451

Signed-off-by: Henrik Rydberg <[EMAIL PROTECTED]>
---
 drivers/input/mouse/bcm5974.c |  230 ++++++++++++++++++++++++++++++++++-------
 1 files changed, 193 insertions(+), 37 deletions(-)

diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 2ec921b..adc7102 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/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),
@@ -84,10 +84,33 @@ MODULE_LICENSE("GPL");
 #define dprintk(level, format, a...)\
        { if (debug >= level) printk(KERN_DEBUG format, ##a); }

+#define MODE_MOUSE     1
+#define MODE_TOUCHPAD  2
+
 static int debug = 1;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Activate debugging output");

+static int driver_mode = MODE_MOUSE;
+module_param(driver_mode, int, 0644);
+MODULE_PARM_DESC(driver_mode, "Driver mode (1 - mouse; 2 - touchpad)");
+
+static int mouse_motion_damping = 8;
+module_param(mouse_motion_damping, int, 0644);
+MODULE_PARM_DESC(mouse_motion_damping, "Mouse motion damping");
+
+static int mouse_wheel_damping = 256;
+module_param(mouse_wheel_damping, int, 0644);
+MODULE_PARM_DESC(mouse_wheel_damping, "Vertical mouse wheel damping");
+
+static int mouse_hwheel_damping = 256;
+module_param(mouse_hwheel_damping, int, 0644);
+MODULE_PARM_DESC(mouse_hwheel_damping, "Horizontal mouse wheel damping");
+
+static int mouse_button_mode = 2;
+module_param(mouse_button_mode, int, 0644);
+MODULE_PARM_DESC(mouse_button_mode, "Mouse button mode (1 - unix; 2 - macos)");
+
 /* button data structure */
 struct bt_data {
        u8 unknown1;            /* constant */
@@ -146,6 +169,13 @@ struct bcm5974_config {
        struct bcm5974_param y; /* vertical limits */
 };

+/* mouse driver state */
+struct bcm5974_mouse_state {
+       int fingers;                    /* number of fingers on trackpad */
+       int wheel;                      /* vertical wheel counter */
+       int hwheel;                     /* horizontal wheel counter */
+};
+
 /* logical device structure */
 struct bcm5974 {
        char phys[64];
@@ -159,6 +189,7 @@ struct bcm5974 {
        struct bt_data *bt_data;        /* button transferred data */
        struct urb *tp_urb;             /* trackpad usb request block */
        struct tp_data *tp_data;        /* trackpad transferred data */
+       struct bcm5974_mouse_state ms;  /* mouse state */
 };

 /* logical dimensions */
@@ -236,71 +267,196 @@ static inline int int2bound(const struct bcm5974_param 
*p, int x)
 static void setup_events_to_report(struct input_dev *input_dev,
                                   const struct bcm5974_config *cfg)
 {
-       __set_bit(EV_ABS, input_dev->evbit);
-
-       input_set_abs_params(input_dev, ABS_PRESSURE,
-                               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);
-       input_set_abs_params(input_dev, ABS_X,
-                               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);
+
+       switch (driver_mode) {
+       case MODE_MOUSE:
+               __set_bit(EV_REL, input_dev->evbit);
+               __set_bit(REL_X, input_dev->relbit);
+               __set_bit(REL_Y, input_dev->relbit);
+               __set_bit(REL_WHEEL, input_dev->relbit);
+               __set_bit(REL_HWHEEL, input_dev->relbit);
+               __set_bit(BTN_MIDDLE, input_dev->keybit);
+               __set_bit(BTN_RIGHT, input_dev->keybit);
+               break;
+       case MODE_TOUCHPAD:
+               __set_bit(EV_ABS, 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);
+
+               input_set_abs_params(input_dev, ABS_PRESSURE,
+                                       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);
+               input_set_abs_params(input_dev, ABS_X,
+                                       0, cfg->x.dim, cfg->x.fuzz, 0);
+               input_set_abs_params(input_dev, ABS_Y,
+                                       0, cfg->y.dim, cfg->y.fuzz, 0);
+               break;
+       }
 }

-/* report button data as logical button state */
+/* update logical mouse button state */
+static void update_bt_mouse_state(struct input_dev *dev,
+                               const struct bcm5974_mouse_state *ms,
+                               const struct bt_data *bt)
+{
+       const int n = ms->fingers;
+
+       bool left, middle, right;
+       switch (mouse_button_mode) {
+       case 1:
+               left = n <= 1 && bt->button;
+               middle = n == 2 && bt->button;
+               right = n >= 3 && bt->button;
+               break;
+       case 2:
+               left = n <= 1 && bt->button;
+               middle = n >= 3 && bt->button;
+               right = n == 2 && bt->button;
+               break;
+       default:
+               left = bt->button;
+               middle = false;
+               right = false;
+               break;
+       };
+       input_report_key(dev, BTN_LEFT, left);
+       input_report_key(dev, BTN_MIDDLE, middle);
+       input_report_key(dev, BTN_RIGHT, right);
+}
+
+/* update logical touchpad button state */
+static void update_bt_touchpad_state(struct input_dev *dev,
+                               const struct bt_data *bt)
+{
+       input_report_key(dev, BTN_LEFT, bt->button);
+}
+
+/* report button data as logical mouse/touchpad button state */
 static int report_bt_state(struct bcm5974 *dev, int size)
 {
        if (size != sizeof(struct bt_data))
                return -EIO;

-       input_report_key(dev->input, BTN_LEFT, dev->bt_data->button);
+       switch (driver_mode) {
+       case MODE_MOUSE:
+               update_bt_mouse_state(dev->input, &dev->ms, dev->bt_data);
+               break;
+       case MODE_TOUCHPAD:
+               update_bt_touchpad_state(dev->input, dev->bt_data);
+               break;
+       }
+
        input_sync(dev->input);

        return 0;
 }

-/* report trackpad data as logical trackpad state */
-static int report_tp_state(struct bcm5974 *dev, int size)
+/* update logical mouse motion state */
+static void update_tp_mouse_state(struct input_dev *dev,
+                               struct bcm5974_mouse_state *ms,
+                               const struct bcm5974_config *c,
+                               const struct tp_finger *f,
+                               int p, int n)
 {
-       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 = 0, w, x, y, n = 0;
+       int dx = 0, dy = 0, sx = 0, sy = 0, sw = 0, shw = 0;

-       if (size < 26 || (size - 26) % 28 != 0)
-               return -EIO;
+       if (f) {
+               dx = raw2int(f->rel_x);
+               dy = raw2int(f->rel_y);

-       if (fingers) {
-               p = raw2int(f->force_major);
+               dprintk(9,
+                       "bcm5974: p: %+05d dx: %+05d dy: %+05d n: %d\n",
+                       p, dx, dy, n);
+       }
+
+       if (n >= 3) {
+               /* swipe */
+               ms->wheel = 0;
+               ms->hwheel += int2scale(&c->x, dx);
+               shw = ms->hwheel / mouse_hwheel_damping;
+               ms->hwheel -= shw * mouse_hwheel_damping;
+       } else if (n == 2) {
+               /* scroll */
+               ms->wheel += int2scale(&c->y, dy);
+               ms->hwheel = 0;
+               sw = ms->wheel / mouse_wheel_damping;
+               ms->wheel -= sw * mouse_wheel_damping;
+       } else {
+               /* pointer */
+               ms->wheel = 0;
+               ms->hwheel = 0;
+               sx = int2scale(&c->x, dx) / mouse_motion_damping;
+               sy = int2scale(&c->y, -dy) / mouse_motion_damping;
+       }
+
+       ms->fingers = n;
+
+       input_report_rel(dev, REL_X, sx);
+       input_report_rel(dev, REL_Y, sy);
+       input_report_rel(dev, REL_WHEEL, sw);
+       input_report_rel(dev, REL_HWHEEL, shw);
+}
+
+/* update logical touchpad state */
+static void update_tp_touchpad_state(struct input_dev *dev,
+                               const struct bcm5974_config *c,
+                               const struct tp_finger *f,
+                               int p, int n)
+{
+       int w, x, y;
+
+       if (f) {
                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(input, ABS_TOOL_WIDTH, int2bound(&c->w, w));
-               input_report_abs(input, ABS_X, int2bound(&c->x, x - 
c->x.devmin));
-               input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - 
y));
+               input_report_abs(dev, ABS_TOOL_WIDTH, int2bound(&c->w, w));
+               input_report_abs(dev, ABS_X, int2bound(&c->x, x - c->x.devmin));
+               input_report_abs(dev, ABS_Y, int2bound(&c->y, c->y.devmax - y));
        }

-       input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p));
+       input_report_abs(dev, ABS_PRESSURE, int2bound(&c->p, p));
+
+       input_report_key(dev, BTN_TOOL_FINGER, n == 1);
+       input_report_key(dev, BTN_TOOL_DOUBLETAP, n == 2);
+       input_report_key(dev, BTN_TOOL_TRIPLETAP, n > 2);
+}
+
+/* report trackpad data as logical mouse/touchpad state */
+static int report_tp_state(struct bcm5974 *dev, int size)
+{
+       const struct bcm5974_config *c = &dev->cfg;
+       const int fingers = (size - 26) / 28;
+       const struct tp_finger *f = 0;
+       int p = 0, n = 0;
+
+       if (size < 26 || (size - 26) % 28 != 0)
+               return -EIO;
+
+       if (fingers) {
+               f = dev->tp_data->finger;
+               p = raw2int(f->force_major);
+               n = p > 0 ? fingers : 0;
+       }

-       input_report_key(input, BTN_TOOL_FINGER, n == 1);
-       input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2);
-       input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2);
+       switch (driver_mode) {
+       case MODE_MOUSE:
+               update_tp_mouse_state(dev->input, &dev->ms, c, f, p, n);
+               break;
+       case MODE_TOUCHPAD:
+               update_tp_touchpad_state(dev->input, c, f, p, n);
+               break;
+       }

-       input_sync(input);
+       input_sync(dev->input);

        return 0;
 }
-- 
1.5.4.3


_______________________________________________
Mailing list: https://launchpad.net/~mactel-support
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~mactel-support
More help   : https://help.launchpad.net/ListHelp

Reply via email to