diff options
Diffstat (limited to 'drivers/input/mouse/bcm5974.c')
-rw-r--r-- | drivers/input/mouse/bcm5974.c | 108 |
1 files changed, 81 insertions, 27 deletions
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 2998a6ac9ae..2d8fc0bf692 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -51,6 +51,10 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 +/* Macbook5,1 (unibody), aka wellspring3 */ +#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 +#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 +#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 #define BCM5974_DEVICE(prod) { \ .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ @@ -72,6 +76,10 @@ static const struct usb_device_id bcm5974_table[] = { BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), + /* Macbook5,1 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS), /* Terminating entry */ {} }; @@ -96,14 +104,23 @@ struct bt_data { u8 rel_y; /* relative y coordinate */ }; -/* trackpad header structure */ -struct tp_header { - u8 unknown1[16]; /* constants, timers, etc */ - u8 fingers; /* number of fingers on trackpad */ - u8 unknown2[9]; /* constants, timers, etc */ +/* trackpad header types */ +enum tp_type { + TYPE1, /* plain trackpad */ + TYPE2 /* button integrated in trackpad */ }; -/* trackpad finger structure */ +/* trackpad finger data offsets, le16-aligned */ +#define FINGER_TYPE1 (13 * sizeof(__le16)) +#define FINGER_TYPE2 (15 * sizeof(__le16)) + +/* trackpad button data offsets */ +#define BUTTON_TYPE2 15 + +/* list of device capability bits */ +#define HAS_INTEGRATED_BUTTON 1 + +/* trackpad finger structure, le16-aligned */ struct tp_finger { __le16 origin; /* zero when switching track finger */ __le16 abs_x; /* absolute x coodinate */ @@ -117,13 +134,11 @@ struct tp_finger { __le16 force_minor; /* trackpad force, minor axis? */ __le16 unused[3]; /* zeros */ __le16 multi; /* one finger: varies, more fingers: constant */ -}; +} __attribute__((packed,aligned(2))); -/* trackpad data structure, empirically at least ten fingers */ -struct tp_data { - struct tp_header header; - struct tp_finger finger[16]; -}; +/* trackpad finger data size, empirically at least ten fingers */ +#define SIZEOF_FINGER sizeof(struct tp_finger) +#define SIZEOF_ALL_FINGERS (16 * SIZEOF_FINGER) /* device-specific parameters */ struct bcm5974_param { @@ -136,9 +151,12 @@ struct bcm5974_param { /* device-specific configuration */ struct bcm5974_config { int ansi, iso, jis; /* the product id of this device */ + int caps; /* device capability bitmask */ int bt_ep; /* the endpoint of the button interface */ int bt_datalen; /* data length of the button interface */ int tp_ep; /* the endpoint of the trackpad interface */ + enum tp_type tp_type; /* type of trackpad interface */ + int tp_offset; /* offset to trackpad finger data */ int tp_datalen; /* data length of the trackpad interface */ struct bcm5974_param p; /* finger pressure limits */ struct bcm5974_param w; /* finger width limits */ @@ -158,7 +176,7 @@ struct bcm5974 { 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 */ + u8 *tp_data; /* trackpad transferred data */ int fingers; /* number of fingers on trackpad */ }; @@ -183,8 +201,9 @@ static const struct bcm5974_config bcm5974_config_table[] = { USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, + 0, 0x84, sizeof(struct bt_data), - 0x81, sizeof(struct tp_data), + 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { DIM_X, DIM_X / SN_COORD, -4824, 5342 }, @@ -194,13 +213,26 @@ static const struct bcm5974_config bcm5974_config_table[] = { USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, + 0, 0x84, sizeof(struct bt_data), - 0x81, sizeof(struct tp_data), + 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, { DIM_X, DIM_X / SN_COORD, -4824, 4824 }, { DIM_Y, DIM_Y / SN_COORD, -172, 4290 } }, + { + USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING3_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING3_JIS, + HAS_INTEGRATED_BUTTON, + 0x84, sizeof(struct bt_data), + 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4460, 5166 }, + { DIM_Y, DIM_Y / SN_COORD, -75, 6700 } + }, {} }; @@ -257,6 +289,7 @@ static void setup_events_to_report(struct input_dev *input_dev, __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_TOOL_QUADTAP, input_dev->keybit); __set_bit(BTN_LEFT, input_dev->keybit); } @@ -266,6 +299,11 @@ static int report_bt_state(struct bcm5974 *dev, int size) if (size != sizeof(struct bt_data)) return -EIO; + dprintk(7, + "bcm5974: button data: %x %x %x %x\n", + dev->bt_data->unknown1, dev->bt_data->button, + dev->bt_data->rel_x, dev->bt_data->rel_y); + input_report_key(dev->input, BTN_LEFT, dev->bt_data->button); input_sync(dev->input); @@ -276,29 +314,37 @@ static int report_bt_state(struct bcm5974 *dev, int size) 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; + const struct tp_finger *f; struct input_dev *input = dev->input; - const int fingers = (size - 26) / 28; - int raw_p, raw_w, raw_x, raw_y; - int ptest = 0, origin = 0, nmin = 0, nmax = 0; + int raw_p, raw_w, raw_x, raw_y, raw_n; + int ptest = 0, origin = 0, ibt = 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) + if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0) return -EIO; + /* finger data, le16-aligned */ + f = (const struct tp_finger *)(dev->tp_data + c->tp_offset); + raw_n = (size - c->tp_offset) / SIZEOF_FINGER; + /* always track the first finger; when detached, start over */ - if (fingers) { + if (raw_n) { 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); + "bcm5974: " + "raw: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n", + raw_p, raw_w, raw_x, raw_y, raw_n); ptest = int2bound(&c->p, raw_p); origin = raw2int(f->origin); + + /* set the integrated button if applicable */ + if (c->tp_type == TYPE2) + ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); } /* while tracking finger still valid, count all fingers */ @@ -307,12 +353,13 @@ static int report_tp_state(struct bcm5974 *dev, int size) 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++) { + while (raw_n--) { ptest = int2bound(&c->p, raw2int(f->force_major)); if (ptest > PRESSURE_LOW) nmax++; if (ptest > PRESSURE_HIGH) nmin++; + f++; } } @@ -324,7 +371,8 @@ static int report_tp_state(struct bcm5974 *dev, int size) 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_key(input, BTN_TOOL_TRIPLETAP, dev->fingers == 3); + input_report_key(input, BTN_TOOL_QUADTAP, dev->fingers > 3); input_report_abs(input, ABS_PRESSURE, abs_p); input_report_abs(input, ABS_TOOL_WIDTH, abs_w); @@ -335,11 +383,15 @@ static int report_tp_state(struct bcm5974 *dev, int size) 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); + "nmin: %d nmax: %d n: %d ibt: %d\n", abs_p, abs_w, + abs_x, abs_y, nmin, nmax, dev->fingers, ibt); } + /* type 2 reports button events via ibt only */ + if (c->tp_type == TYPE2) + input_report_key(input, BTN_LEFT, ibt); + input_sync(input); return 0; @@ -649,6 +701,8 @@ static int bcm5974_probe(struct usb_interface *iface, input_dev->name = "bcm5974"; input_dev->phys = dev->phys; usb_to_input_id(dev->udev, &input_dev->id); + /* report driver capabilities via the version field */ + input_dev->id.version = cfg->caps; input_dev->dev.parent = &iface->dev; input_set_drvdata(input_dev, dev); |