Skip to content

Commit 6379250

Browse files
marcanjannau
authored andcommitted
HID: magicmouse: Add MTP multi-touch device support
Apple M2 devices expose the multi-touch device over the HID over DockChannel transport, which we represent as the HOST bus type. The report format is the same, except the legacy mouse header is gone and there is no enable request needed. Signed-off-by: Hector Martin <marcan@marcan.st>
1 parent b4222f3 commit 6379250

1 file changed

Lines changed: 47 additions & 16 deletions

File tree

drivers/hid/hid-magicmouse.c

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
6161
#define MOUSE2_REPORT_ID 0x12
6262
#define DOUBLE_REPORT_ID 0xf7
6363
#define SPI_REPORT_ID 0x02
64+
#define MTP_REPORT_ID 0x75
6465
#define USB_BATTERY_TIMEOUT_SEC 60
6566

6667
#define MAX_CONTACTS 16
@@ -586,25 +587,32 @@ struct tp_finger {
586587
} __attribute__((packed, aligned(2)));
587588

588589
/**
589-
* struct trackpad report
590+
* vendor trackpad report
590591
*
591-
* @report_id: reportid
592-
* @buttons: HID Usage Buttons 3 1-bit reports
593592
* @num_fingers: the number of fingers being reported in @fingers
594-
* @clicked: same as @buttons
593+
* @buttons: same as HID buttons
595594
*/
596595
struct tp_header {
596+
// HID vendor part, up to 1751 bytes
597+
u8 unknown[22];
598+
u8 num_fingers;
599+
u8 buttons;
600+
u8 unknown3[14];
601+
};
602+
603+
/**
604+
* standard HID mouse report
605+
*
606+
* @report_id: reportid
607+
* @buttons: HID Usage Buttons 3 1-bit reports
608+
*/
609+
struct tp_mouse_report {
597610
// HID mouse report
598611
u8 report_id;
599612
u8 buttons;
600613
u8 rel_x;
601614
u8 rel_y;
602615
u8 padding[4];
603-
// HID vendor part, up to 1751 bytes
604-
u8 unknown[22];
605-
u8 num_fingers;
606-
u8 clicked;
607-
u8 unknown3[14];
608616
};
609617

610618
static inline int le16_to_int(__le16 x)
@@ -634,7 +642,7 @@ static void report_finger_data(struct input_dev *input, int slot,
634642
input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
635643
}
636644

637-
static int magicmouse_raw_event_spi(struct hid_device *hdev,
645+
static int magicmouse_raw_event_mtp(struct hid_device *hdev,
638646
struct hid_report *report, u8 *data, int size)
639647
{
640648
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
@@ -651,9 +659,6 @@ static int magicmouse_raw_event_spi(struct hid_device *hdev,
651659
// print_hex_dump_debug("appleft ev: ", DUMP_PREFIX_OFFSET, 16, 1, data,
652660
// size, false);
653661

654-
if (data[0] != SPI_REPORT_ID)
655-
return 0;
656-
657662
/* Expect 46 bytes of prefix, and N * 30 bytes of touch data. */
658663
if (size < hdr_sz || ((size - hdr_sz) % touch_sz) != 0)
659664
return 0;
@@ -692,12 +697,26 @@ static int magicmouse_raw_event_spi(struct hid_device *hdev,
692697
}
693698

694699
input_mt_sync_frame(input);
695-
input_report_key(input, BTN_MOUSE, data[1] & 1);
700+
input_report_key(input, BTN_MOUSE, tp_hdr->buttons & 1);
696701

697702
input_sync(input);
698703
return 1;
699704
}
700705

706+
static int magicmouse_raw_event_spi(struct hid_device *hdev,
707+
struct hid_report *report, u8 *data, int size)
708+
{
709+
const size_t hdr_sz = sizeof(struct tp_mouse_report);
710+
711+
if (size < hdr_sz)
712+
return 0;
713+
714+
if (data[0] != SPI_REPORT_ID)
715+
return 0;
716+
717+
return magicmouse_raw_event_mtp(hdev, report, data + hdr_sz, size - hdr_sz);
718+
}
719+
701720
static int magicmouse_event(struct hid_device *hdev, struct hid_field *field,
702721
struct hid_usage *usage, __s32 value)
703722
{
@@ -1119,7 +1138,7 @@ static int magicmouse_probe(struct hid_device *hdev,
11191138
struct hid_report *report;
11201139
int ret;
11211140

1122-
if (id->bus == BUS_SPI && id->vendor == SPI_VENDOR_ID_APPLE &&
1141+
if ((id->bus == BUS_SPI || id->bus == BUS_HOST) && id->vendor == SPI_VENDOR_ID_APPLE &&
11231142
hdev->type != HID_TYPE_SPI_MOUSE)
11241143
return -ENODEV;
11251144

@@ -1131,7 +1150,10 @@ static int magicmouse_probe(struct hid_device *hdev,
11311150

11321151
// internal trackpad use a data format use input ops to avoid
11331152
// conflicts with the report ID.
1134-
if (id->vendor == SPI_VENDOR_ID_APPLE) {
1153+
if (id->bus == BUS_HOST) {
1154+
msc->input_ops.raw_event = magicmouse_raw_event_mtp;
1155+
msc->input_ops.setup_input = magicmouse_setup_input_spi;
1156+
} else if (id->bus == BUS_SPI) {
11351157
msc->input_ops.raw_event = magicmouse_raw_event_spi;
11361158
msc->input_ops.setup_input = magicmouse_setup_input_spi;
11371159
} else {
@@ -1199,6 +1221,9 @@ static int magicmouse_probe(struct hid_device *hdev,
11991221
break;
12001222
default:
12011223
switch (id->bus) {
1224+
case BUS_HOST:
1225+
report = hid_register_report(hdev, HID_INPUT_REPORT, MTP_REPORT_ID, 0);
1226+
break;
12021227
case BUS_SPI:
12031228
report = hid_register_report(hdev, HID_INPUT_REPORT, SPI_REPORT_ID, 0);
12041229
break;
@@ -1217,6 +1242,10 @@ static int magicmouse_probe(struct hid_device *hdev,
12171242
}
12181243
report->size = 6;
12191244

1245+
/* MTP devices do not need the MT enable, this is handled by the MTP driver */
1246+
if (id->bus == BUS_HOST)
1247+
return 0;
1248+
12201249
/*
12211250
* Some devices repond with 'invalid report id' when feature
12221251
* report switching it into multitouch mode is sent to it.
@@ -1312,6 +1341,8 @@ static const struct hid_device_id magic_mice[] = {
13121341
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 },
13131342
{ HID_SPI_DEVICE(SPI_VENDOR_ID_APPLE, HID_ANY_ID),
13141343
.driver_data = 0 },
1344+
{ HID_DEVICE(BUS_HOST, HID_GROUP_ANY, HOST_VENDOR_ID_APPLE,
1345+
HID_ANY_ID), .driver_data = 0 },
13151346
{ }
13161347
};
13171348
MODULE_DEVICE_TABLE(hid, magic_mice);

0 commit comments

Comments
 (0)