.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Apple "Magic" Wireless Mouse driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
6 | 7 | */ |
---|
7 | 8 | |
---|
8 | 9 | /* |
---|
9 | | - * This program is free software; you can redistribute it and/or modify it |
---|
10 | | - * under the terms of the GNU General Public License as published by the Free |
---|
11 | | - * Software Foundation; either version 2 of the License, or (at your option) |
---|
12 | | - * any later version. |
---|
13 | 10 | */ |
---|
14 | 11 | |
---|
15 | 12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
.. | .. |
---|
54 | 51 | MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event"); |
---|
55 | 52 | |
---|
56 | 53 | #define TRACKPAD_REPORT_ID 0x28 |
---|
| 54 | +#define TRACKPAD2_USB_REPORT_ID 0x02 |
---|
| 55 | +#define TRACKPAD2_BT_REPORT_ID 0x31 |
---|
57 | 56 | #define MOUSE_REPORT_ID 0x29 |
---|
58 | 57 | #define DOUBLE_REPORT_ID 0xf7 |
---|
59 | 58 | /* These definitions are not precise, but they're close enough. (Bits |
---|
.. | .. |
---|
90 | 89 | #define TRACKPAD_MAX_Y 2565 |
---|
91 | 90 | #define TRACKPAD_RES_Y \ |
---|
92 | 91 | ((TRACKPAD_MAX_Y - TRACKPAD_MIN_Y) / (TRACKPAD_DIMENSION_Y / 100)) |
---|
| 92 | + |
---|
| 93 | +#define TRACKPAD2_DIMENSION_X (float)16000 |
---|
| 94 | +#define TRACKPAD2_MIN_X -3678 |
---|
| 95 | +#define TRACKPAD2_MAX_X 3934 |
---|
| 96 | +#define TRACKPAD2_RES_X \ |
---|
| 97 | + ((TRACKPAD2_MAX_X - TRACKPAD2_MIN_X) / (TRACKPAD2_DIMENSION_X / 100)) |
---|
| 98 | +#define TRACKPAD2_DIMENSION_Y (float)11490 |
---|
| 99 | +#define TRACKPAD2_MIN_Y -2478 |
---|
| 100 | +#define TRACKPAD2_MAX_Y 2587 |
---|
| 101 | +#define TRACKPAD2_RES_Y \ |
---|
| 102 | + ((TRACKPAD2_MAX_Y - TRACKPAD2_MIN_Y) / (TRACKPAD2_DIMENSION_Y / 100)) |
---|
93 | 103 | |
---|
94 | 104 | /** |
---|
95 | 105 | * struct magicmouse_sc - Tracks Magic Mouse-specific data. |
---|
.. | .. |
---|
183 | 193 | { |
---|
184 | 194 | struct input_dev *input = msc->input; |
---|
185 | 195 | int id, x, y, size, orientation, touch_major, touch_minor, state, down; |
---|
| 196 | + int pressure = 0; |
---|
186 | 197 | |
---|
187 | 198 | if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { |
---|
188 | 199 | id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf; |
---|
.. | .. |
---|
194 | 205 | touch_minor = tdata[4]; |
---|
195 | 206 | state = tdata[7] & TOUCH_STATE_MASK; |
---|
196 | 207 | down = state != TOUCH_STATE_NONE; |
---|
| 208 | + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { |
---|
| 209 | + id = tdata[8] & 0xf; |
---|
| 210 | + x = (tdata[1] << 27 | tdata[0] << 19) >> 19; |
---|
| 211 | + y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19); |
---|
| 212 | + size = tdata[6]; |
---|
| 213 | + orientation = (tdata[8] >> 5) - 4; |
---|
| 214 | + touch_major = tdata[4]; |
---|
| 215 | + touch_minor = tdata[5]; |
---|
| 216 | + pressure = tdata[7]; |
---|
| 217 | + state = tdata[3] & 0xC0; |
---|
| 218 | + down = state == 0x80; |
---|
197 | 219 | } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ |
---|
198 | 220 | id = (tdata[7] << 2 | tdata[6] >> 6) & 0xf; |
---|
199 | 221 | x = (tdata[1] << 27 | tdata[0] << 19) >> 19; |
---|
.. | .. |
---|
215 | 237 | /* If requested, emulate a scroll wheel by detecting small |
---|
216 | 238 | * vertical touch motions. |
---|
217 | 239 | */ |
---|
218 | | - if (emulate_scroll_wheel) { |
---|
| 240 | + if (emulate_scroll_wheel && (input->id.product != |
---|
| 241 | + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) { |
---|
219 | 242 | unsigned long now = jiffies; |
---|
220 | 243 | int step_x = msc->touches[id].scroll_x - x; |
---|
221 | 244 | int step_y = msc->touches[id].scroll_y - y; |
---|
.. | .. |
---|
269 | 292 | input_report_abs(input, ABS_MT_POSITION_X, x); |
---|
270 | 293 | input_report_abs(input, ABS_MT_POSITION_Y, y); |
---|
271 | 294 | |
---|
| 295 | + if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) |
---|
| 296 | + input_report_abs(input, ABS_MT_PRESSURE, pressure); |
---|
| 297 | + |
---|
272 | 298 | if (report_undeciphered) { |
---|
273 | 299 | if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) |
---|
274 | 300 | input_event(input, EV_MSC, MSC_RAW, tdata[7]); |
---|
275 | | - else /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ |
---|
| 301 | + else if (input->id.product != |
---|
| 302 | + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) |
---|
276 | 303 | input_event(input, EV_MSC, MSC_RAW, tdata[8]); |
---|
277 | 304 | } |
---|
278 | 305 | } |
---|
.. | .. |
---|
287 | 314 | |
---|
288 | 315 | switch (data[0]) { |
---|
289 | 316 | case TRACKPAD_REPORT_ID: |
---|
| 317 | + case TRACKPAD2_BT_REPORT_ID: |
---|
290 | 318 | /* Expect four bytes of prefix, and N*9 bytes of touch data. */ |
---|
291 | 319 | if (size < 4 || ((size - 4) % 9) != 0) |
---|
292 | 320 | return 0; |
---|
.. | .. |
---|
307 | 335 | * |
---|
308 | 336 | * ts = data[1] >> 6 | data[2] << 2 | data[3] << 10; |
---|
309 | 337 | */ |
---|
| 338 | + break; |
---|
| 339 | + case TRACKPAD2_USB_REPORT_ID: |
---|
| 340 | + /* Expect twelve bytes of prefix and N*9 bytes of touch data. */ |
---|
| 341 | + if (size < 12 || ((size - 12) % 9) != 0) |
---|
| 342 | + return 0; |
---|
| 343 | + npoints = (size - 12) / 9; |
---|
| 344 | + if (npoints > 15) { |
---|
| 345 | + hid_warn(hdev, "invalid size value (%d) for TRACKPAD2_USB_REPORT_ID\n", |
---|
| 346 | + size); |
---|
| 347 | + return 0; |
---|
| 348 | + } |
---|
| 349 | + msc->ntouches = 0; |
---|
| 350 | + for (ii = 0; ii < npoints; ii++) |
---|
| 351 | + magicmouse_emit_touch(msc, ii, data + ii * 9 + 12); |
---|
| 352 | + |
---|
| 353 | + clicks = data[1]; |
---|
310 | 354 | break; |
---|
311 | 355 | case MOUSE_REPORT_ID: |
---|
312 | 356 | /* Expect six bytes of prefix, and N*8 bytes of touch data. */ |
---|
.. | .. |
---|
343 | 387 | magicmouse_raw_event(hdev, report, data + 2, data[1]); |
---|
344 | 388 | magicmouse_raw_event(hdev, report, data + 2 + data[1], |
---|
345 | 389 | size - 2 - data[1]); |
---|
346 | | - break; |
---|
| 390 | + return 0; |
---|
347 | 391 | default: |
---|
348 | 392 | return 0; |
---|
349 | 393 | } |
---|
.. | .. |
---|
352 | 396 | magicmouse_emit_buttons(msc, clicks & 3); |
---|
353 | 397 | input_report_rel(input, REL_X, x); |
---|
354 | 398 | input_report_rel(input, REL_Y, y); |
---|
| 399 | + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { |
---|
| 400 | + input_mt_sync_frame(input); |
---|
| 401 | + input_report_key(input, BTN_MOUSE, clicks & 1); |
---|
355 | 402 | } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ |
---|
356 | 403 | input_report_key(input, BTN_MOUSE, clicks & 1); |
---|
357 | 404 | input_mt_report_pointer_emulation(input, true); |
---|
.. | .. |
---|
364 | 411 | static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev) |
---|
365 | 412 | { |
---|
366 | 413 | int error; |
---|
| 414 | + int mt_flags = 0; |
---|
367 | 415 | |
---|
368 | 416 | __set_bit(EV_KEY, input->evbit); |
---|
369 | 417 | |
---|
.. | .. |
---|
380 | 428 | __set_bit(REL_WHEEL, input->relbit); |
---|
381 | 429 | __set_bit(REL_HWHEEL, input->relbit); |
---|
382 | 430 | } |
---|
| 431 | + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { |
---|
| 432 | + /* setting the device name to ensure the same driver settings |
---|
| 433 | + * get loaded, whether connected through bluetooth or USB |
---|
| 434 | + */ |
---|
| 435 | + input->name = "Apple Inc. Magic Trackpad 2"; |
---|
| 436 | + |
---|
| 437 | + __clear_bit(EV_MSC, input->evbit); |
---|
| 438 | + __clear_bit(BTN_0, input->keybit); |
---|
| 439 | + __clear_bit(BTN_RIGHT, input->keybit); |
---|
| 440 | + __clear_bit(BTN_MIDDLE, input->keybit); |
---|
| 441 | + __set_bit(BTN_MOUSE, input->keybit); |
---|
| 442 | + __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); |
---|
| 443 | + __set_bit(BTN_TOOL_FINGER, input->keybit); |
---|
| 444 | + |
---|
| 445 | + mt_flags = INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | |
---|
| 446 | + INPUT_MT_TRACK; |
---|
383 | 447 | } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ |
---|
384 | 448 | /* input->keybit is initialized with incorrect button info |
---|
385 | 449 | * for Magic Trackpad. There really is only one physical |
---|
.. | .. |
---|
402 | 466 | |
---|
403 | 467 | __set_bit(EV_ABS, input->evbit); |
---|
404 | 468 | |
---|
405 | | - error = input_mt_init_slots(input, 16, 0); |
---|
| 469 | + error = input_mt_init_slots(input, 16, mt_flags); |
---|
406 | 470 | if (error) |
---|
407 | 471 | return error; |
---|
408 | 472 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, |
---|
409 | 473 | 4, 0); |
---|
410 | 474 | input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255 << 2, |
---|
411 | 475 | 4, 0); |
---|
412 | | - input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0); |
---|
413 | 476 | |
---|
414 | 477 | /* Note: Touch Y position from the device is inverted relative |
---|
415 | 478 | * to how pointer motion is reported (and relative to how USB |
---|
.. | .. |
---|
418 | 481 | * inverse of the reported Y. |
---|
419 | 482 | */ |
---|
420 | 483 | if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) { |
---|
| 484 | + input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0); |
---|
421 | 485 | input_set_abs_params(input, ABS_MT_POSITION_X, |
---|
422 | 486 | MOUSE_MIN_X, MOUSE_MAX_X, 4, 0); |
---|
423 | 487 | input_set_abs_params(input, ABS_MT_POSITION_Y, |
---|
.. | .. |
---|
427 | 491 | MOUSE_RES_X); |
---|
428 | 492 | input_abs_set_res(input, ABS_MT_POSITION_Y, |
---|
429 | 493 | MOUSE_RES_Y); |
---|
| 494 | + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { |
---|
| 495 | + input_set_abs_params(input, ABS_MT_PRESSURE, 0, 253, 0, 0); |
---|
| 496 | + input_set_abs_params(input, ABS_PRESSURE, 0, 253, 0, 0); |
---|
| 497 | + input_set_abs_params(input, ABS_MT_ORIENTATION, -3, 4, 0, 0); |
---|
| 498 | + input_set_abs_params(input, ABS_X, TRACKPAD2_MIN_X, |
---|
| 499 | + TRACKPAD2_MAX_X, 0, 0); |
---|
| 500 | + input_set_abs_params(input, ABS_Y, TRACKPAD2_MIN_Y, |
---|
| 501 | + TRACKPAD2_MAX_Y, 0, 0); |
---|
| 502 | + input_set_abs_params(input, ABS_MT_POSITION_X, |
---|
| 503 | + TRACKPAD2_MIN_X, TRACKPAD2_MAX_X, 0, 0); |
---|
| 504 | + input_set_abs_params(input, ABS_MT_POSITION_Y, |
---|
| 505 | + TRACKPAD2_MIN_Y, TRACKPAD2_MAX_Y, 0, 0); |
---|
| 506 | + |
---|
| 507 | + input_abs_set_res(input, ABS_X, TRACKPAD2_RES_X); |
---|
| 508 | + input_abs_set_res(input, ABS_Y, TRACKPAD2_RES_Y); |
---|
| 509 | + input_abs_set_res(input, ABS_MT_POSITION_X, TRACKPAD2_RES_X); |
---|
| 510 | + input_abs_set_res(input, ABS_MT_POSITION_Y, TRACKPAD2_RES_Y); |
---|
430 | 511 | } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ |
---|
| 512 | + input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0); |
---|
431 | 513 | input_set_abs_params(input, ABS_X, TRACKPAD_MIN_X, |
---|
432 | 514 | TRACKPAD_MAX_X, 4, 0); |
---|
433 | 515 | input_set_abs_params(input, ABS_Y, TRACKPAD_MIN_Y, |
---|
.. | .. |
---|
447 | 529 | |
---|
448 | 530 | input_set_events_per_packet(input, 60); |
---|
449 | 531 | |
---|
450 | | - if (report_undeciphered) { |
---|
| 532 | + if (report_undeciphered && |
---|
| 533 | + input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { |
---|
451 | 534 | __set_bit(EV_MSC, input->evbit); |
---|
452 | 535 | __set_bit(MSC_RAW, input->mscbit); |
---|
453 | 536 | } |
---|
.. | .. |
---|
471 | 554 | msc->input = hi->input; |
---|
472 | 555 | |
---|
473 | 556 | /* Magic Trackpad does not give relative data after switching to MT */ |
---|
474 | | - if (hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD && |
---|
| 557 | + if ((hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD || |
---|
| 558 | + hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) && |
---|
475 | 559 | field->flags & HID_MAIN_ITEM_RELATIVE) |
---|
476 | 560 | return -1; |
---|
477 | 561 | |
---|
.. | .. |
---|
500 | 584 | static int magicmouse_probe(struct hid_device *hdev, |
---|
501 | 585 | const struct hid_device_id *id) |
---|
502 | 586 | { |
---|
503 | | - const u8 feature[] = { 0xd7, 0x01 }; |
---|
| 587 | + const u8 *feature; |
---|
| 588 | + const u8 feature_mt[] = { 0xD7, 0x01 }; |
---|
| 589 | + const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 }; |
---|
| 590 | + const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 }; |
---|
504 | 591 | u8 *buf; |
---|
505 | 592 | struct magicmouse_sc *msc; |
---|
506 | 593 | struct hid_report *report; |
---|
507 | 594 | int ret; |
---|
| 595 | + int feature_size; |
---|
| 596 | + |
---|
| 597 | + if (id->vendor == USB_VENDOR_ID_APPLE && |
---|
| 598 | + id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && |
---|
| 599 | + hdev->type != HID_TYPE_USBMOUSE) |
---|
| 600 | + return -ENODEV; |
---|
508 | 601 | |
---|
509 | 602 | msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL); |
---|
510 | 603 | if (msc == NULL) { |
---|
.. | .. |
---|
538 | 631 | if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE) |
---|
539 | 632 | report = hid_register_report(hdev, HID_INPUT_REPORT, |
---|
540 | 633 | MOUSE_REPORT_ID, 0); |
---|
541 | | - else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ |
---|
| 634 | + else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { |
---|
| 635 | + if (id->vendor == BT_VENDOR_ID_APPLE) |
---|
| 636 | + report = hid_register_report(hdev, HID_INPUT_REPORT, |
---|
| 637 | + TRACKPAD2_BT_REPORT_ID, 0); |
---|
| 638 | + else /* USB_VENDOR_ID_APPLE */ |
---|
| 639 | + report = hid_register_report(hdev, HID_INPUT_REPORT, |
---|
| 640 | + TRACKPAD2_USB_REPORT_ID, 0); |
---|
| 641 | + } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ |
---|
542 | 642 | report = hid_register_report(hdev, HID_INPUT_REPORT, |
---|
543 | 643 | TRACKPAD_REPORT_ID, 0); |
---|
544 | 644 | report = hid_register_report(hdev, HID_INPUT_REPORT, |
---|
.. | .. |
---|
552 | 652 | } |
---|
553 | 653 | report->size = 6; |
---|
554 | 654 | |
---|
555 | | - buf = kmemdup(feature, sizeof(feature), GFP_KERNEL); |
---|
| 655 | + if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { |
---|
| 656 | + if (id->vendor == BT_VENDOR_ID_APPLE) { |
---|
| 657 | + feature_size = sizeof(feature_mt_trackpad2_bt); |
---|
| 658 | + feature = feature_mt_trackpad2_bt; |
---|
| 659 | + } else { /* USB_VENDOR_ID_APPLE */ |
---|
| 660 | + feature_size = sizeof(feature_mt_trackpad2_usb); |
---|
| 661 | + feature = feature_mt_trackpad2_usb; |
---|
| 662 | + } |
---|
| 663 | + } else { |
---|
| 664 | + feature_size = sizeof(feature_mt); |
---|
| 665 | + feature = feature_mt; |
---|
| 666 | + } |
---|
| 667 | + |
---|
| 668 | + buf = kmemdup(feature, feature_size, GFP_KERNEL); |
---|
556 | 669 | if (!buf) { |
---|
557 | 670 | ret = -ENOMEM; |
---|
558 | 671 | goto err_stop_hw; |
---|
.. | .. |
---|
566 | 679 | * but there seems to be no other way of switching the mode. |
---|
567 | 680 | * Thus the super-ugly hacky success check below. |
---|
568 | 681 | */ |
---|
569 | | - ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(feature), |
---|
| 682 | + ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size, |
---|
570 | 683 | HID_FEATURE_REPORT, HID_REQ_SET_REPORT); |
---|
571 | 684 | kfree(buf); |
---|
572 | | - if (ret != -EIO && ret != sizeof(feature)) { |
---|
| 685 | + if (ret != -EIO && ret != feature_size) { |
---|
573 | 686 | hid_err(hdev, "unable to request touch data (%d)\n", ret); |
---|
574 | 687 | goto err_stop_hw; |
---|
575 | 688 | } |
---|
.. | .. |
---|
585 | 698 | USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 }, |
---|
586 | 699 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, |
---|
587 | 700 | USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 }, |
---|
| 701 | + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, |
---|
| 702 | + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, |
---|
| 703 | + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, |
---|
| 704 | + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, |
---|
588 | 705 | { } |
---|
589 | 706 | }; |
---|
590 | 707 | MODULE_DEVICE_TABLE(hid, magic_mice); |
---|