Skip to content

Commit c0dc558

Browse files
johnchen902Jiri Kosina
authored andcommitted
HID: magicmouse: fix reconnection of Magic Mouse 2
It is observed that the Magic Mouse 2 would not enter multi-touch mode unless the mouse is connected before loading the module. It seems to be a quirk specific to Magic Mouse 2 Retrying after 500ms fixes the problem for me. The delay can't be reduced much further --- 300ms didn't work for me. Retrying immediately after receiving an event didn't work either. Signed-off-by: John Chen <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 3dcc5f7 commit c0dc558

File tree

1 file changed

+63
-30
lines changed

1 file changed

+63
-30
lines changed

drivers/hid/hid-magicmouse.c

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/input/mt.h>
1717
#include <linux/module.h>
1818
#include <linux/slab.h>
19+
#include <linux/workqueue.h>
1920

2021
#include "hid-ids.h"
2122

@@ -128,6 +129,9 @@ struct magicmouse_sc {
128129
u8 size;
129130
} touches[16];
130131
int tracking_ids[16];
132+
133+
struct hid_device *hdev;
134+
struct delayed_work work;
131135
};
132136

133137
static int magicmouse_firm_touch(struct magicmouse_sc *msc)
@@ -631,20 +635,60 @@ static int magicmouse_input_configured(struct hid_device *hdev,
631635
return 0;
632636
}
633637

634-
635-
static int magicmouse_probe(struct hid_device *hdev,
636-
const struct hid_device_id *id)
638+
static int magicmouse_enable_multitouch(struct hid_device *hdev)
637639
{
638640
const u8 *feature;
639641
const u8 feature_mt[] = { 0xD7, 0x01 };
640642
const u8 feature_mt_mouse2[] = { 0xF1, 0x02, 0x01 };
641643
const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 };
642644
const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 };
643645
u8 *buf;
646+
int ret;
647+
int feature_size;
648+
649+
if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
650+
if (hdev->vendor == BT_VENDOR_ID_APPLE) {
651+
feature_size = sizeof(feature_mt_trackpad2_bt);
652+
feature = feature_mt_trackpad2_bt;
653+
} else { /* USB_VENDOR_ID_APPLE */
654+
feature_size = sizeof(feature_mt_trackpad2_usb);
655+
feature = feature_mt_trackpad2_usb;
656+
}
657+
} else if (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
658+
feature_size = sizeof(feature_mt_mouse2);
659+
feature = feature_mt_mouse2;
660+
} else {
661+
feature_size = sizeof(feature_mt);
662+
feature = feature_mt;
663+
}
664+
665+
buf = kmemdup(feature, feature_size, GFP_KERNEL);
666+
if (!buf)
667+
return -ENOMEM;
668+
669+
ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size,
670+
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
671+
kfree(buf);
672+
return ret;
673+
}
674+
675+
static void magicmouse_enable_mt_work(struct work_struct *work)
676+
{
677+
struct magicmouse_sc *msc =
678+
container_of(work, struct magicmouse_sc, work.work);
679+
int ret;
680+
681+
ret = magicmouse_enable_multitouch(msc->hdev);
682+
if (ret < 0)
683+
hid_err(msc->hdev, "unable to request touch data (%d)\n", ret);
684+
}
685+
686+
static int magicmouse_probe(struct hid_device *hdev,
687+
const struct hid_device_id *id)
688+
{
644689
struct magicmouse_sc *msc;
645690
struct hid_report *report;
646691
int ret;
647-
int feature_size;
648692

649693
if (id->vendor == USB_VENDOR_ID_APPLE &&
650694
id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
@@ -658,6 +702,8 @@ static int magicmouse_probe(struct hid_device *hdev,
658702
}
659703

660704
msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
705+
msc->hdev = hdev;
706+
INIT_DEFERRABLE_WORK(&msc->work, magicmouse_enable_mt_work);
661707

662708
msc->quirks = id->driver_data;
663709
hid_set_drvdata(hdev, msc);
@@ -707,28 +753,6 @@ static int magicmouse_probe(struct hid_device *hdev,
707753
}
708754
report->size = 6;
709755

710-
if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
711-
if (id->vendor == BT_VENDOR_ID_APPLE) {
712-
feature_size = sizeof(feature_mt_trackpad2_bt);
713-
feature = feature_mt_trackpad2_bt;
714-
} else { /* USB_VENDOR_ID_APPLE */
715-
feature_size = sizeof(feature_mt_trackpad2_usb);
716-
feature = feature_mt_trackpad2_usb;
717-
}
718-
} else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
719-
feature_size = sizeof(feature_mt_mouse2);
720-
feature = feature_mt_mouse2;
721-
} else {
722-
feature_size = sizeof(feature_mt);
723-
feature = feature_mt;
724-
}
725-
726-
buf = kmemdup(feature, feature_size, GFP_KERNEL);
727-
if (!buf) {
728-
ret = -ENOMEM;
729-
goto err_stop_hw;
730-
}
731-
732756
/*
733757
* Some devices repond with 'invalid report id' when feature
734758
* report switching it into multitouch mode is sent to it.
@@ -737,20 +761,28 @@ static int magicmouse_probe(struct hid_device *hdev,
737761
* but there seems to be no other way of switching the mode.
738762
* Thus the super-ugly hacky success check below.
739763
*/
740-
ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size,
741-
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
742-
kfree(buf);
743-
if (ret != -EIO && ret != feature_size) {
764+
ret = magicmouse_enable_multitouch(hdev);
765+
if (ret != -EIO && ret < 0) {
744766
hid_err(hdev, "unable to request touch data (%d)\n", ret);
745767
goto err_stop_hw;
746768
}
769+
if (ret == -EIO && id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
770+
schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
771+
}
747772

748773
return 0;
749774
err_stop_hw:
750775
hid_hw_stop(hdev);
751776
return ret;
752777
}
753778

779+
static void magicmouse_remove(struct hid_device *hdev)
780+
{
781+
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
782+
cancel_delayed_work_sync(&msc->work);
783+
hid_hw_stop(hdev);
784+
}
785+
754786
static const struct hid_device_id magic_mice[] = {
755787
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
756788
USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
@@ -770,6 +802,7 @@ static struct hid_driver magicmouse_driver = {
770802
.name = "magicmouse",
771803
.id_table = magic_mice,
772804
.probe = magicmouse_probe,
805+
.remove = magicmouse_remove,
773806
.raw_event = magicmouse_raw_event,
774807
.event = magicmouse_event,
775808
.input_mapping = magicmouse_input_mapping,

0 commit comments

Comments
 (0)