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 2998a6ac9ae4..2d8fc0bf6923 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c | |||
@@ -51,6 +51,10 @@ | |||
51 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 | 51 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 |
52 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 | 52 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 |
53 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 | 53 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 |
54 | /* Macbook5,1 (unibody), aka wellspring3 */ | ||
55 | #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 | ||
56 | #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 | ||
57 | #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 | ||
54 | 58 | ||
55 | #define BCM5974_DEVICE(prod) { \ | 59 | #define BCM5974_DEVICE(prod) { \ |
56 | .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ | 60 | .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ |
@@ -72,6 +76,10 @@ static const struct usb_device_id bcm5974_table[] = { | |||
72 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI), | 76 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI), |
73 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO), | 77 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO), |
74 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), | 78 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), |
79 | /* Macbook5,1 */ | ||
80 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI), | ||
81 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO), | ||
82 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS), | ||
75 | /* Terminating entry */ | 83 | /* Terminating entry */ |
76 | {} | 84 | {} |
77 | }; | 85 | }; |
@@ -96,14 +104,23 @@ struct bt_data { | |||
96 | u8 rel_y; /* relative y coordinate */ | 104 | u8 rel_y; /* relative y coordinate */ |
97 | }; | 105 | }; |
98 | 106 | ||
99 | /* trackpad header structure */ | 107 | /* trackpad header types */ |
100 | struct tp_header { | 108 | enum tp_type { |
101 | u8 unknown1[16]; /* constants, timers, etc */ | 109 | TYPE1, /* plain trackpad */ |
102 | u8 fingers; /* number of fingers on trackpad */ | 110 | TYPE2 /* button integrated in trackpad */ |
103 | u8 unknown2[9]; /* constants, timers, etc */ | ||
104 | }; | 111 | }; |
105 | 112 | ||
106 | /* trackpad finger structure */ | 113 | /* trackpad finger data offsets, le16-aligned */ |
114 | #define FINGER_TYPE1 (13 * sizeof(__le16)) | ||
115 | #define FINGER_TYPE2 (15 * sizeof(__le16)) | ||
116 | |||
117 | /* trackpad button data offsets */ | ||
118 | #define BUTTON_TYPE2 15 | ||
119 | |||
120 | /* list of device capability bits */ | ||
121 | #define HAS_INTEGRATED_BUTTON 1 | ||
122 | |||
123 | /* trackpad finger structure, le16-aligned */ | ||
107 | struct tp_finger { | 124 | struct tp_finger { |
108 | __le16 origin; /* zero when switching track finger */ | 125 | __le16 origin; /* zero when switching track finger */ |
109 | __le16 abs_x; /* absolute x coodinate */ | 126 | __le16 abs_x; /* absolute x coodinate */ |
@@ -117,13 +134,11 @@ struct tp_finger { | |||
117 | __le16 force_minor; /* trackpad force, minor axis? */ | 134 | __le16 force_minor; /* trackpad force, minor axis? */ |
118 | __le16 unused[3]; /* zeros */ | 135 | __le16 unused[3]; /* zeros */ |
119 | __le16 multi; /* one finger: varies, more fingers: constant */ | 136 | __le16 multi; /* one finger: varies, more fingers: constant */ |
120 | }; | 137 | } __attribute__((packed,aligned(2))); |
121 | 138 | ||
122 | /* trackpad data structure, empirically at least ten fingers */ | 139 | /* trackpad finger data size, empirically at least ten fingers */ |
123 | struct tp_data { | 140 | #define SIZEOF_FINGER sizeof(struct tp_finger) |
124 | struct tp_header header; | 141 | #define SIZEOF_ALL_FINGERS (16 * SIZEOF_FINGER) |
125 | struct tp_finger finger[16]; | ||
126 | }; | ||
127 | 142 | ||
128 | /* device-specific parameters */ | 143 | /* device-specific parameters */ |
129 | struct bcm5974_param { | 144 | struct bcm5974_param { |
@@ -136,9 +151,12 @@ struct bcm5974_param { | |||
136 | /* device-specific configuration */ | 151 | /* device-specific configuration */ |
137 | struct bcm5974_config { | 152 | struct bcm5974_config { |
138 | int ansi, iso, jis; /* the product id of this device */ | 153 | int ansi, iso, jis; /* the product id of this device */ |
154 | int caps; /* device capability bitmask */ | ||
139 | int bt_ep; /* the endpoint of the button interface */ | 155 | int bt_ep; /* the endpoint of the button interface */ |
140 | int bt_datalen; /* data length of the button interface */ | 156 | int bt_datalen; /* data length of the button interface */ |
141 | int tp_ep; /* the endpoint of the trackpad interface */ | 157 | int tp_ep; /* the endpoint of the trackpad interface */ |
158 | enum tp_type tp_type; /* type of trackpad interface */ | ||
159 | int tp_offset; /* offset to trackpad finger data */ | ||
142 | int tp_datalen; /* data length of the trackpad interface */ | 160 | int tp_datalen; /* data length of the trackpad interface */ |
143 | struct bcm5974_param p; /* finger pressure limits */ | 161 | struct bcm5974_param p; /* finger pressure limits */ |
144 | struct bcm5974_param w; /* finger width limits */ | 162 | struct bcm5974_param w; /* finger width limits */ |
@@ -158,7 +176,7 @@ struct bcm5974 { | |||
158 | struct urb *bt_urb; /* button usb request block */ | 176 | struct urb *bt_urb; /* button usb request block */ |
159 | struct bt_data *bt_data; /* button transferred data */ | 177 | struct bt_data *bt_data; /* button transferred data */ |
160 | struct urb *tp_urb; /* trackpad usb request block */ | 178 | struct urb *tp_urb; /* trackpad usb request block */ |
161 | struct tp_data *tp_data; /* trackpad transferred data */ | 179 | u8 *tp_data; /* trackpad transferred data */ |
162 | int fingers; /* number of fingers on trackpad */ | 180 | int fingers; /* number of fingers on trackpad */ |
163 | }; | 181 | }; |
164 | 182 | ||
@@ -183,8 +201,9 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
183 | USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, | 201 | USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, |
184 | USB_DEVICE_ID_APPLE_WELLSPRING_ISO, | 202 | USB_DEVICE_ID_APPLE_WELLSPRING_ISO, |
185 | USB_DEVICE_ID_APPLE_WELLSPRING_JIS, | 203 | USB_DEVICE_ID_APPLE_WELLSPRING_JIS, |
204 | 0, | ||
186 | 0x84, sizeof(struct bt_data), | 205 | 0x84, sizeof(struct bt_data), |
187 | 0x81, sizeof(struct tp_data), | 206 | 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, |
188 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, | 207 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, |
189 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 208 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, |
190 | { DIM_X, DIM_X / SN_COORD, -4824, 5342 }, | 209 | { DIM_X, DIM_X / SN_COORD, -4824, 5342 }, |
@@ -194,13 +213,26 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
194 | USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, | 213 | USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, |
195 | USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, | 214 | USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, |
196 | USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, | 215 | USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, |
216 | 0, | ||
197 | 0x84, sizeof(struct bt_data), | 217 | 0x84, sizeof(struct bt_data), |
198 | 0x81, sizeof(struct tp_data), | 218 | 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, |
199 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, | 219 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, |
200 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 220 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, |
201 | { DIM_X, DIM_X / SN_COORD, -4824, 4824 }, | 221 | { DIM_X, DIM_X / SN_COORD, -4824, 4824 }, |
202 | { DIM_Y, DIM_Y / SN_COORD, -172, 4290 } | 222 | { DIM_Y, DIM_Y / SN_COORD, -172, 4290 } |
203 | }, | 223 | }, |
224 | { | ||
225 | USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI, | ||
226 | USB_DEVICE_ID_APPLE_WELLSPRING3_ISO, | ||
227 | USB_DEVICE_ID_APPLE_WELLSPRING3_JIS, | ||
228 | HAS_INTEGRATED_BUTTON, | ||
229 | 0x84, sizeof(struct bt_data), | ||
230 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, | ||
231 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, | ||
232 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | ||
233 | { DIM_X, DIM_X / SN_COORD, -4460, 5166 }, | ||
234 | { DIM_Y, DIM_Y / SN_COORD, -75, 6700 } | ||
235 | }, | ||
204 | {} | 236 | {} |
205 | }; | 237 | }; |
206 | 238 | ||
@@ -257,6 +289,7 @@ static void setup_events_to_report(struct input_dev *input_dev, | |||
257 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); | 289 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); |
258 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); | 290 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); |
259 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); | 291 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); |
292 | __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); | ||
260 | __set_bit(BTN_LEFT, input_dev->keybit); | 293 | __set_bit(BTN_LEFT, input_dev->keybit); |
261 | } | 294 | } |
262 | 295 | ||
@@ -266,6 +299,11 @@ static int report_bt_state(struct bcm5974 *dev, int size) | |||
266 | if (size != sizeof(struct bt_data)) | 299 | if (size != sizeof(struct bt_data)) |
267 | return -EIO; | 300 | return -EIO; |
268 | 301 | ||
302 | dprintk(7, | ||
303 | "bcm5974: button data: %x %x %x %x\n", | ||
304 | dev->bt_data->unknown1, dev->bt_data->button, | ||
305 | dev->bt_data->rel_x, dev->bt_data->rel_y); | ||
306 | |||
269 | input_report_key(dev->input, BTN_LEFT, dev->bt_data->button); | 307 | input_report_key(dev->input, BTN_LEFT, dev->bt_data->button); |
270 | input_sync(dev->input); | 308 | input_sync(dev->input); |
271 | 309 | ||
@@ -276,29 +314,37 @@ static int report_bt_state(struct bcm5974 *dev, int size) | |||
276 | static int report_tp_state(struct bcm5974 *dev, int size) | 314 | static int report_tp_state(struct bcm5974 *dev, int size) |
277 | { | 315 | { |
278 | const struct bcm5974_config *c = &dev->cfg; | 316 | const struct bcm5974_config *c = &dev->cfg; |
279 | const struct tp_finger *f = dev->tp_data->finger; | 317 | const struct tp_finger *f; |
280 | struct input_dev *input = dev->input; | 318 | struct input_dev *input = dev->input; |
281 | const int fingers = (size - 26) / 28; | 319 | int raw_p, raw_w, raw_x, raw_y, raw_n; |
282 | int raw_p, raw_w, raw_x, raw_y; | 320 | int ptest = 0, origin = 0, ibt = 0, nmin = 0, nmax = 0; |
283 | int ptest = 0, origin = 0, nmin = 0, nmax = 0; | ||
284 | int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0; | 321 | int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0; |
285 | 322 | ||
286 | if (size < 26 || (size - 26) % 28 != 0) | 323 | if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0) |
287 | return -EIO; | 324 | return -EIO; |
288 | 325 | ||
326 | /* finger data, le16-aligned */ | ||
327 | f = (const struct tp_finger *)(dev->tp_data + c->tp_offset); | ||
328 | raw_n = (size - c->tp_offset) / SIZEOF_FINGER; | ||
329 | |||
289 | /* always track the first finger; when detached, start over */ | 330 | /* always track the first finger; when detached, start over */ |
290 | if (fingers) { | 331 | if (raw_n) { |
291 | raw_p = raw2int(f->force_major); | 332 | raw_p = raw2int(f->force_major); |
292 | raw_w = raw2int(f->size_major); | 333 | raw_w = raw2int(f->size_major); |
293 | raw_x = raw2int(f->abs_x); | 334 | raw_x = raw2int(f->abs_x); |
294 | raw_y = raw2int(f->abs_y); | 335 | raw_y = raw2int(f->abs_y); |
295 | 336 | ||
296 | dprintk(9, | 337 | dprintk(9, |
297 | "bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n", | 338 | "bcm5974: " |
298 | raw_p, raw_w, raw_x, raw_y); | 339 | "raw: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n", |
340 | raw_p, raw_w, raw_x, raw_y, raw_n); | ||
299 | 341 | ||
300 | ptest = int2bound(&c->p, raw_p); | 342 | ptest = int2bound(&c->p, raw_p); |
301 | origin = raw2int(f->origin); | 343 | origin = raw2int(f->origin); |
344 | |||
345 | /* set the integrated button if applicable */ | ||
346 | if (c->tp_type == TYPE2) | ||
347 | ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); | ||
302 | } | 348 | } |
303 | 349 | ||
304 | /* while tracking finger still valid, count all fingers */ | 350 | /* while tracking finger still valid, count all fingers */ |
@@ -307,12 +353,13 @@ static int report_tp_state(struct bcm5974 *dev, int size) | |||
307 | abs_w = int2bound(&c->w, raw_w); | 353 | abs_w = int2bound(&c->w, raw_w); |
308 | abs_x = int2bound(&c->x, raw_x - c->x.devmin); | 354 | abs_x = int2bound(&c->x, raw_x - c->x.devmin); |
309 | abs_y = int2bound(&c->y, c->y.devmax - raw_y); | 355 | abs_y = int2bound(&c->y, c->y.devmax - raw_y); |
310 | for (; f != dev->tp_data->finger + fingers; f++) { | 356 | while (raw_n--) { |
311 | ptest = int2bound(&c->p, raw2int(f->force_major)); | 357 | ptest = int2bound(&c->p, raw2int(f->force_major)); |
312 | if (ptest > PRESSURE_LOW) | 358 | if (ptest > PRESSURE_LOW) |
313 | nmax++; | 359 | nmax++; |
314 | if (ptest > PRESSURE_HIGH) | 360 | if (ptest > PRESSURE_HIGH) |
315 | nmin++; | 361 | nmin++; |
362 | f++; | ||
316 | } | 363 | } |
317 | } | 364 | } |
318 | 365 | ||
@@ -324,7 +371,8 @@ static int report_tp_state(struct bcm5974 *dev, int size) | |||
324 | input_report_key(input, BTN_TOUCH, dev->fingers > 0); | 371 | input_report_key(input, BTN_TOUCH, dev->fingers > 0); |
325 | input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1); | 372 | input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1); |
326 | input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2); | 373 | input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2); |
327 | input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2); | 374 | input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers == 3); |
375 | input_report_key(input, BTN_TOOL_QUADTAP, dev->fingers > 3); | ||
328 | 376 | ||
329 | input_report_abs(input, ABS_PRESSURE, abs_p); | 377 | input_report_abs(input, ABS_PRESSURE, abs_p); |
330 | input_report_abs(input, ABS_TOOL_WIDTH, abs_w); | 378 | input_report_abs(input, ABS_TOOL_WIDTH, abs_w); |
@@ -335,11 +383,15 @@ static int report_tp_state(struct bcm5974 *dev, int size) | |||
335 | 383 | ||
336 | dprintk(8, | 384 | dprintk(8, |
337 | "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d " | 385 | "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d " |
338 | "nmin: %d nmax: %d n: %d\n", | 386 | "nmin: %d nmax: %d n: %d ibt: %d\n", abs_p, abs_w, |
339 | abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers); | 387 | abs_x, abs_y, nmin, nmax, dev->fingers, ibt); |
340 | 388 | ||
341 | } | 389 | } |
342 | 390 | ||
391 | /* type 2 reports button events via ibt only */ | ||
392 | if (c->tp_type == TYPE2) | ||
393 | input_report_key(input, BTN_LEFT, ibt); | ||
394 | |||
343 | input_sync(input); | 395 | input_sync(input); |
344 | 396 | ||
345 | return 0; | 397 | return 0; |
@@ -649,6 +701,8 @@ static int bcm5974_probe(struct usb_interface *iface, | |||
649 | input_dev->name = "bcm5974"; | 701 | input_dev->name = "bcm5974"; |
650 | input_dev->phys = dev->phys; | 702 | input_dev->phys = dev->phys; |
651 | usb_to_input_id(dev->udev, &input_dev->id); | 703 | usb_to_input_id(dev->udev, &input_dev->id); |
704 | /* report driver capabilities via the version field */ | ||
705 | input_dev->id.version = cfg->caps; | ||
652 | input_dev->dev.parent = &iface->dev; | 706 | input_dev->dev.parent = &iface->dev; |
653 | 707 | ||
654 | input_set_drvdata(input_dev, dev); | 708 | input_set_drvdata(input_dev, dev); |