diff options
| author | Henrik Rydberg <rydberg@euromail.se> | 2008-10-23 10:12:43 +0200 |
|---|---|---|
| committer | Henrik Rydberg <rydberg@euromail.se> | 2008-10-23 10:12:43 +0200 |
| commit | fca7f164708033819b48b765d9b80e1b47a3ed2a (patch) | |
| tree | 6ff923518e90ed1ffe528d568f3405f6ae7cf95c /bcm5974.c | |
| parent | 262c292d2d4241301476dbbefffe0b1ff827f2b2 (diff) | |
bcm5974-0.66-rc11: Add support for Macbook5 (Unibody)
This version is not final, but good enough to base tests on.
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'bcm5974.c')
| -rw-r--r-- | bcm5974.c | 96 |
1 files changed, 71 insertions, 25 deletions
| @@ -42,6 +42,8 @@ | |||
| 42 | #include <linux/mutex.h> | 42 | #include <linux/mutex.h> |
| 43 | 43 | ||
| 44 | #define USB_VENDOR_ID_APPLE 0x05ac | 44 | #define USB_VENDOR_ID_APPLE 0x05ac |
| 45 | #define BTN_TOOL_PRESS 0x148 | ||
| 46 | #define BTN_TOOL_QUADTAP 0x14f | ||
| 45 | 47 | ||
| 46 | /* MacbookAir, aka wellspring */ | 48 | /* MacbookAir, aka wellspring */ |
| 47 | #define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223 | 49 | #define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223 |
| @@ -51,6 +53,10 @@ | |||
| 51 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 | 53 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 |
| 52 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 | 54 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 |
| 53 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 | 55 | #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 |
| 56 | /* Macbook5,1 (unibody), aka wellspring3 */ | ||
| 57 | #define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 | ||
| 58 | #define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 | ||
| 59 | #define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 | ||
| 54 | 60 | ||
| 55 | #define BCM5974_DEVICE(prod) { \ | 61 | #define BCM5974_DEVICE(prod) { \ |
| 56 | .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ | 62 | .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ |
| @@ -72,6 +78,10 @@ static const struct usb_device_id bcm5974_table[] = { | |||
| 72 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI), | 78 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI), |
| 73 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO), | 79 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO), |
| 74 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), | 80 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), |
| 81 | /* Macbook5,1 */ | ||
| 82 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI), | ||
| 83 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO), | ||
| 84 | BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS), | ||
| 75 | /* Terminating entry */ | 85 | /* Terminating entry */ |
| 76 | {} | 86 | {} |
| 77 | }; | 87 | }; |
| @@ -96,13 +106,22 @@ struct bt_data { | |||
| 96 | u8 rel_y; /* relative y coordinate */ | 106 | u8 rel_y; /* relative y coordinate */ |
| 97 | }; | 107 | }; |
| 98 | 108 | ||
| 99 | /* trackpad header structure */ | 109 | /* trackpad header types */ |
| 100 | struct tp_header { | 110 | enum tp_type { |
| 101 | u8 unknown1[16]; /* constants, timers, etc */ | 111 | TYPE1, /* plain trackpad */ |
| 102 | u8 fingers; /* number of fingers on trackpad */ | 112 | TYPE2 /* button integrated in trackpad */ |
| 103 | u8 unknown2[9]; /* constants, timers, etc */ | ||
| 104 | }; | 113 | }; |
| 105 | 114 | ||
| 115 | /* trackpad finger data offsets */ | ||
| 116 | #define FINGER_TYPE1 26 | ||
| 117 | #define FINGER_TYPE2 30 | ||
| 118 | |||
| 119 | /* trackpad button data offsets */ | ||
| 120 | #define BUTTON_TYPE2 15 | ||
| 121 | |||
| 122 | /* integrated button capability by configuration */ | ||
| 123 | #define HAS_INTEGRATED_BUTTON(c) (c->tp_type == TYPE2) | ||
| 124 | |||
| 106 | /* trackpad finger structure */ | 125 | /* trackpad finger structure */ |
| 107 | struct tp_finger { | 126 | struct tp_finger { |
| 108 | __le16 origin; /* zero when switching track finger */ | 127 | __le16 origin; /* zero when switching track finger */ |
| @@ -119,11 +138,9 @@ struct tp_finger { | |||
| 119 | __le16 multi; /* one finger: varies, more fingers: constant */ | 138 | __le16 multi; /* one finger: varies, more fingers: constant */ |
| 120 | }; | 139 | }; |
| 121 | 140 | ||
| 122 | /* trackpad data structure, empirically at least ten fingers */ | 141 | /* trackpad finger data size, empirically at least ten fingers */ |
| 123 | struct tp_data { | 142 | #define SIZEOF_FINGER sizeof(struct tp_finger) |
| 124 | struct tp_header header; | 143 | #define SIZEOF_ALL_FINGERS (16 * SIZEOF_FINGER) |
| 125 | struct tp_finger finger[16]; | ||
| 126 | }; | ||
| 127 | 144 | ||
| 128 | /* device-specific parameters */ | 145 | /* device-specific parameters */ |
| 129 | struct bcm5974_param { | 146 | struct bcm5974_param { |
| @@ -139,6 +156,8 @@ struct bcm5974_config { | |||
| 139 | int bt_ep; /* the endpoint of the button interface */ | 156 | int bt_ep; /* the endpoint of the button interface */ |
| 140 | int bt_datalen; /* data length of the button interface */ | 157 | int bt_datalen; /* data length of the button interface */ |
| 141 | int tp_ep; /* the endpoint of the trackpad interface */ | 158 | int tp_ep; /* the endpoint of the trackpad interface */ |
| 159 | enum tp_type tp_type; /* type of trackpad interface */ | ||
| 160 | int tp_offset; /* offset to trackpad finger data */ | ||
| 142 | int tp_datalen; /* data length of the trackpad interface */ | 161 | int tp_datalen; /* data length of the trackpad interface */ |
| 143 | struct bcm5974_param p; /* finger pressure limits */ | 162 | struct bcm5974_param p; /* finger pressure limits */ |
| 144 | struct bcm5974_param w; /* finger width limits */ | 163 | struct bcm5974_param w; /* finger width limits */ |
| @@ -158,7 +177,7 @@ struct bcm5974 { | |||
| 158 | struct urb *bt_urb; /* button usb request block */ | 177 | struct urb *bt_urb; /* button usb request block */ |
| 159 | struct bt_data *bt_data; /* button transferred data */ | 178 | struct bt_data *bt_data; /* button transferred data */ |
| 160 | struct urb *tp_urb; /* trackpad usb request block */ | 179 | struct urb *tp_urb; /* trackpad usb request block */ |
| 161 | struct tp_data *tp_data; /* trackpad transferred data */ | 180 | u8 *tp_data; /* trackpad transferred data */ |
| 162 | int fingers; /* number of fingers on trackpad */ | 181 | int fingers; /* number of fingers on trackpad */ |
| 163 | }; | 182 | }; |
| 164 | 183 | ||
| @@ -184,7 +203,7 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 184 | USB_DEVICE_ID_APPLE_WELLSPRING_ISO, | 203 | USB_DEVICE_ID_APPLE_WELLSPRING_ISO, |
| 185 | USB_DEVICE_ID_APPLE_WELLSPRING_JIS, | 204 | USB_DEVICE_ID_APPLE_WELLSPRING_JIS, |
| 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 }, |
| @@ -195,12 +214,23 @@ static const struct bcm5974_config bcm5974_config_table[] = { | |||
| 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, |
| 197 | 0x84, sizeof(struct bt_data), | 216 | 0x84, sizeof(struct bt_data), |
| 198 | 0x81, sizeof(struct tp_data), | 217 | 0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS, |
| 199 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, | 218 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, |
| 200 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | 219 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, |
| 201 | { DIM_X, DIM_X / SN_COORD, -4824, 4824 }, | 220 | { DIM_X, DIM_X / SN_COORD, -4824, 4824 }, |
| 202 | { DIM_Y, DIM_Y / SN_COORD, -172, 4290 } | 221 | { DIM_Y, DIM_Y / SN_COORD, -172, 4290 } |
| 203 | }, | 222 | }, |
| 223 | { | ||
| 224 | USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI, | ||
| 225 | USB_DEVICE_ID_APPLE_WELLSPRING3_ISO, | ||
| 226 | USB_DEVICE_ID_APPLE_WELLSPRING3_JIS, | ||
| 227 | 0x84, sizeof(struct bt_data), | ||
| 228 | 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, | ||
| 229 | { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 768 }, | ||
| 230 | { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, | ||
| 231 | { DIM_X, DIM_X / SN_COORD, -4460, 5166 }, | ||
| 232 | { DIM_Y, DIM_Y / SN_COORD, -75, 6700 } | ||
| 233 | }, | ||
| 204 | {} | 234 | {} |
| 205 | }; | 235 | }; |
| 206 | 236 | ||
| @@ -258,6 +288,9 @@ static void setup_events_to_report(struct input_dev *input_dev, | |||
| 258 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); | 288 | __set_bit(BTN_TOOL_FINGER, input_dev->keybit); |
| 259 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); | 289 | __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); |
| 260 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); | 290 | __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); |
| 291 | __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit); | ||
| 292 | if (HAS_INTEGRATED_BUTTON(cfg)) | ||
| 293 | __set_bit(BTN_TOOL_PRESS, input_dev->keybit); | ||
| 261 | __set_bit(BTN_LEFT, input_dev->keybit); | 294 | __set_bit(BTN_LEFT, input_dev->keybit); |
| 262 | } | 295 | } |
| 263 | 296 | ||
| @@ -267,6 +300,11 @@ static int report_bt_state(struct bcm5974 *dev, int size) | |||
| 267 | if (size != sizeof(struct bt_data)) | 300 | if (size != sizeof(struct bt_data)) |
| 268 | return -EIO; | 301 | return -EIO; |
| 269 | 302 | ||
| 303 | dprintk(7, | ||
| 304 | "bcm5974: button data: %x %x %x %x\n", | ||
| 305 | dev->bt_data->unknown1, dev->bt_data->button, | ||
| 306 | dev->bt_data->rel_x, dev->bt_data->rel_y); | ||
| 307 | |||
| 270 | input_report_key(dev->input, BTN_LEFT, dev->bt_data->button); | 308 | input_report_key(dev->input, BTN_LEFT, dev->bt_data->button); |
| 271 | input_sync(dev->input); | 309 | input_sync(dev->input); |
| 272 | 310 | ||
| @@ -277,29 +315,35 @@ static int report_bt_state(struct bcm5974 *dev, int size) | |||
| 277 | static int report_tp_state(struct bcm5974 *dev, int size) | 315 | static int report_tp_state(struct bcm5974 *dev, int size) |
| 278 | { | 316 | { |
| 279 | const struct bcm5974_config *c = &dev->cfg; | 317 | const struct bcm5974_config *c = &dev->cfg; |
| 280 | const struct tp_finger *f = dev->tp_data->finger; | 318 | const struct tp_finger *f; |
| 281 | struct input_dev *input = dev->input; | 319 | struct input_dev *input = dev->input; |
| 282 | const int fingers = (size - 26) / 28; | 320 | int raw_p, raw_w, raw_x, raw_y, raw_n; |
| 283 | int raw_p, raw_w, raw_x, raw_y; | 321 | int ptest = 0, origin = 0, ibt = 0, nmin = 0, nmax = 0; |
| 284 | int ptest = 0, origin = 0, nmin = 0, nmax = 0; | ||
| 285 | int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0; | 322 | int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0; |
| 286 | 323 | ||
| 287 | if (size < 26 || (size - 26) % 28 != 0) | 324 | if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0) |
| 288 | return -EIO; | 325 | return -EIO; |
| 289 | 326 | ||
| 327 | f = (const struct tp_finger *)(dev->tp_data + c->tp_offset); | ||
| 328 | raw_n = (size - c->tp_offset) / SIZEOF_FINGER; | ||
| 329 | |||
| 290 | /* always track the first finger; when detached, start over */ | 330 | /* always track the first finger; when detached, start over */ |
| 291 | if (fingers) { | 331 | if (raw_n) { |
| 292 | raw_p = raw2int(f->force_major); | 332 | raw_p = raw2int(f->force_major); |
| 293 | raw_w = raw2int(f->size_major); | 333 | raw_w = raw2int(f->size_major); |
| 294 | raw_x = raw2int(f->abs_x); | 334 | raw_x = raw2int(f->abs_x); |
| 295 | raw_y = raw2int(f->abs_y); | 335 | raw_y = raw2int(f->abs_y); |
| 296 | 336 | ||
| 297 | dprintk(9, | 337 | dprintk(9, |
| 298 | "bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n", | 338 | "bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d " |
| 299 | raw_p, raw_w, raw_x, raw_y); | 339 | "n: %d\n", raw_p, raw_w, raw_x, raw_y, raw_n); |
| 300 | 340 | ||
| 301 | ptest = int2bound(&c->p, raw_p); | 341 | ptest = int2bound(&c->p, raw_p); |
| 302 | origin = raw2int(f->origin); | 342 | origin = raw2int(f->origin); |
| 343 | |||
| 344 | /* set the integrated button if applicable */ | ||
| 345 | if (c->tp_type == TYPE2) | ||
| 346 | ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); | ||
| 303 | } | 347 | } |
| 304 | 348 | ||
| 305 | /* while tracking finger still valid, count all fingers */ | 349 | /* while tracking finger still valid, count all fingers */ |
| @@ -308,12 +352,13 @@ static int report_tp_state(struct bcm5974 *dev, int size) | |||
| 308 | abs_w = int2bound(&c->w, raw_w); | 352 | abs_w = int2bound(&c->w, raw_w); |
| 309 | abs_x = int2bound(&c->x, raw_x - c->x.devmin); | 353 | abs_x = int2bound(&c->x, raw_x - c->x.devmin); |
| 310 | abs_y = int2bound(&c->y, c->y.devmax - raw_y); | 354 | abs_y = int2bound(&c->y, c->y.devmax - raw_y); |
| 311 | for (; f != dev->tp_data->finger + fingers; f++) { | 355 | while (raw_n--) { |
| 312 | ptest = int2bound(&c->p, raw2int(f->force_major)); | 356 | ptest = int2bound(&c->p, raw2int(f->force_major)); |
| 313 | if (ptest > PRESSURE_LOW) | 357 | if (ptest > PRESSURE_LOW) |
| 314 | nmax++; | 358 | nmax++; |
| 315 | if (ptest > PRESSURE_HIGH) | 359 | if (ptest > PRESSURE_HIGH) |
| 316 | nmin++; | 360 | nmin++; |
| 361 | f++; | ||
| 317 | } | 362 | } |
| 318 | } | 363 | } |
| 319 | 364 | ||
| @@ -325,7 +370,8 @@ static int report_tp_state(struct bcm5974 *dev, int size) | |||
| 325 | input_report_key(input, BTN_TOUCH, dev->fingers > 0); | 370 | input_report_key(input, BTN_TOUCH, dev->fingers > 0); |
| 326 | input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1); | 371 | input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1); |
| 327 | input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2); | 372 | input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2); |
| 328 | input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2); | 373 | input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers == 3); |
| 374 | input_report_key(input, BTN_TOOL_QUADTAP, dev->fingers > 3); | ||
| 329 | 375 | ||
| 330 | input_report_abs(input, ABS_PRESSURE, abs_p); | 376 | input_report_abs(input, ABS_PRESSURE, abs_p); |
| 331 | input_report_abs(input, ABS_TOOL_WIDTH, abs_w); | 377 | input_report_abs(input, ABS_TOOL_WIDTH, abs_w); |
| @@ -336,8 +382,8 @@ static int report_tp_state(struct bcm5974 *dev, int size) | |||
| 336 | 382 | ||
| 337 | dprintk(8, | 383 | dprintk(8, |
| 338 | "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d " | 384 | "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d " |
| 339 | "nmin: %d nmax: %d n: %d\n", | 385 | "nmin: %d nmax: %d n: %d ibt: %d\n", abs_p, abs_w, |
| 340 | abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers); | 386 | abs_x, abs_y, nmin, nmax, dev->fingers, ibt); |
| 341 | 387 | ||
| 342 | } | 388 | } |
| 343 | 389 | ||
