Skip to content

Commit b4222f3

Browse files
committed
HID: magicmouse: add support for Macbook trackpads
The trackpads in Macbooks beginning in 2015 are HID devices connected over SPI. On Intel Macbooks they are currently supported by applespi.c. This chang adds support for the trackpads on Apple Silicon Macbooks starting in late 2020. They use a new HID over SPI transport driver. The touch report format differs from USB/BT Magic Trackpads. It is the same format as the type 4 format supported by bcm5974.c. Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 786295d commit b4222f3

2 files changed

Lines changed: 267 additions & 9 deletions

File tree

drivers/hid/Kconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,8 @@ config HID_MAGICMOUSE
730730
Support for the Apple Magic Mouse/Trackpad multi-touch.
731731

732732
Say Y here if you want support for the multi-touch features of the
733-
Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad.
733+
Apple Wireless "Magic" Mouse, the Apple Wireless "Magic" Trackpad and
734+
force touch Trackpads in Macbooks starting from 2015.
734735

735736
config HID_MALTRON
736737
tristate "Maltron L90 keyboard"

drivers/hid/hid-magicmouse.c

Lines changed: 265 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
6060
#define MOUSE_REPORT_ID 0x29
6161
#define MOUSE2_REPORT_ID 0x12
6262
#define DOUBLE_REPORT_ID 0xf7
63+
#define SPI_REPORT_ID 0x02
6364
#define USB_BATTERY_TIMEOUT_SEC 60
6465

6566
#define MAX_CONTACTS 16
@@ -114,6 +115,18 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
114115
#define TRACKPAD2_RES_Y \
115116
((TRACKPAD2_MAX_Y - TRACKPAD2_MIN_Y) / (TRACKPAD2_DIMENSION_Y / 100))
116117

118+
#define J314_TP_DIMENSION_X (float)13000
119+
#define J314_TP_MIN_X -5900
120+
#define J314_TP_MAX_X 6500
121+
#define J314_TP_RES_X \
122+
((J314_TP_MAX_X - J314_TP_MIN_X) / (J314_TP_DIMENSION_X / 100))
123+
#define J314_TP_DIMENSION_Y (float)8100
124+
#define J314_TP_MIN_Y -200
125+
#define J314_TP_MAX_Y 7400
126+
#define J314_TP_RES_Y \
127+
((J314_TP_MAX_Y - J314_TP_MIN_Y) / (J314_TP_DIMENSION_Y / 100))
128+
129+
#define J314_TP_MAX_FINGER_ORIENTATION 16384
117130

118131
struct magicmouse_input_ops {
119132
int (*raw_event)(struct hid_device *hdev,
@@ -537,6 +550,154 @@ static int magicmouse_raw_event_usb(struct hid_device *hdev,
537550
return 1;
538551
}
539552

553+
/**
554+
* struct tp_finger - single trackpad finger structure, le16-aligned
555+
*
556+
* @unknown1: unknown
557+
* @unknown2: unknown
558+
* @abs_x: absolute x coordinate
559+
* @abs_y: absolute y coordinate
560+
* @rel_x: relative x coordinate
561+
* @rel_y: relative y coordinate
562+
* @tool_major: tool area, major axis
563+
* @tool_minor: tool area, minor axis
564+
* @orientation: 16384 when point, else 15 bit angle
565+
* @touch_major: touch area, major axis
566+
* @touch_minor: touch area, minor axis
567+
* @unused: zeros
568+
* @pressure: pressure on forcetouch touchpad
569+
* @multi: one finger: varies, more fingers: constant
570+
*/
571+
struct tp_finger {
572+
__le16 unknown1;
573+
__le16 unknown2;
574+
__le16 abs_x;
575+
__le16 abs_y;
576+
__le16 rel_x;
577+
__le16 rel_y;
578+
__le16 tool_major;
579+
__le16 tool_minor;
580+
__le16 orientation;
581+
__le16 touch_major;
582+
__le16 touch_minor;
583+
__le16 unused[2];
584+
__le16 pressure;
585+
__le16 multi;
586+
} __attribute__((packed, aligned(2)));
587+
588+
/**
589+
* struct trackpad report
590+
*
591+
* @report_id: reportid
592+
* @buttons: HID Usage Buttons 3 1-bit reports
593+
* @num_fingers: the number of fingers being reported in @fingers
594+
* @clicked: same as @buttons
595+
*/
596+
struct tp_header {
597+
// HID mouse report
598+
u8 report_id;
599+
u8 buttons;
600+
u8 rel_x;
601+
u8 rel_y;
602+
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];
608+
};
609+
610+
static inline int le16_to_int(__le16 x)
611+
{
612+
return (signed short)le16_to_cpu(x);
613+
}
614+
615+
static void report_finger_data(struct input_dev *input, int slot,
616+
const struct input_mt_pos *pos,
617+
const struct tp_finger *f)
618+
{
619+
input_mt_slot(input, slot);
620+
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
621+
622+
input_report_abs(input, ABS_MT_TOUCH_MAJOR,
623+
le16_to_int(f->touch_major) << 1);
624+
input_report_abs(input, ABS_MT_TOUCH_MINOR,
625+
le16_to_int(f->touch_minor) << 1);
626+
input_report_abs(input, ABS_MT_WIDTH_MAJOR,
627+
le16_to_int(f->tool_major) << 1);
628+
input_report_abs(input, ABS_MT_WIDTH_MINOR,
629+
le16_to_int(f->tool_minor) << 1);
630+
input_report_abs(input, ABS_MT_ORIENTATION,
631+
J314_TP_MAX_FINGER_ORIENTATION - le16_to_int(f->orientation));
632+
input_report_abs(input, ABS_MT_PRESSURE, le16_to_int(f->pressure));
633+
input_report_abs(input, ABS_MT_POSITION_X, pos->x);
634+
input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
635+
}
636+
637+
static int magicmouse_raw_event_spi(struct hid_device *hdev,
638+
struct hid_report *report, u8 *data, int size)
639+
{
640+
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
641+
struct input_dev *input = msc->input;
642+
struct tp_header *tp_hdr;
643+
struct tp_finger *f;
644+
int i, n;
645+
u32 npoints;
646+
const size_t hdr_sz = sizeof(struct tp_header);
647+
const size_t touch_sz = sizeof(struct tp_finger);
648+
u8 map_contacs[MAX_CONTACTS];
649+
650+
// hid_warn(hdev, "%s\n", __func__);
651+
// print_hex_dump_debug("appleft ev: ", DUMP_PREFIX_OFFSET, 16, 1, data,
652+
// size, false);
653+
654+
if (data[0] != SPI_REPORT_ID)
655+
return 0;
656+
657+
/* Expect 46 bytes of prefix, and N * 30 bytes of touch data. */
658+
if (size < hdr_sz || ((size - hdr_sz) % touch_sz) != 0)
659+
return 0;
660+
661+
tp_hdr = (struct tp_header *)data;
662+
663+
npoints = (size - hdr_sz) / touch_sz;
664+
if (npoints < tp_hdr->num_fingers || npoints > MAX_CONTACTS) {
665+
hid_warn(hdev,
666+
"unexpected number of touches (%u) for "
667+
"report\n",
668+
npoints);
669+
return 0;
670+
}
671+
672+
n = 0;
673+
for (i = 0; i < tp_hdr->num_fingers; i++) {
674+
f = (struct tp_finger *)(data + hdr_sz + i * touch_sz);
675+
if (le16_to_int(f->touch_major) == 0)
676+
continue;
677+
678+
hid_dbg(hdev, "ev x:%04x y:%04x\n", le16_to_int(f->abs_x),
679+
le16_to_int(f->abs_y));
680+
msc->pos[n].x = le16_to_int(f->abs_x);
681+
msc->pos[n].y = -le16_to_int(f->abs_y);
682+
map_contacs[n] = i;
683+
n++;
684+
}
685+
686+
input_mt_assign_slots(input, msc->tracking_ids, msc->pos, n, 0);
687+
688+
for (i = 0; i < n; i++) {
689+
int idx = map_contacs[i];
690+
f = (struct tp_finger *)(data + hdr_sz + idx * touch_sz);
691+
report_finger_data(input, msc->tracking_ids[i], &msc->pos[i], f);
692+
}
693+
694+
input_mt_sync_frame(input);
695+
input_report_key(input, BTN_MOUSE, data[1] & 1);
696+
697+
input_sync(input);
698+
return 1;
699+
}
700+
540701
static int magicmouse_event(struct hid_device *hdev, struct hid_field *field,
541702
struct hid_usage *usage, __s32 value)
542703
{
@@ -727,6 +888,79 @@ static int magicmouse_setup_input_usb(struct input_dev *input,
727888
return 0;
728889
}
729890

891+
static int magicmouse_setup_input_spi(struct input_dev *input,
892+
struct hid_device *hdev)
893+
{
894+
int error;
895+
int mt_flags = 0;
896+
897+
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
898+
__clear_bit(BTN_0, input->keybit);
899+
__clear_bit(BTN_RIGHT, input->keybit);
900+
__clear_bit(BTN_MIDDLE, input->keybit);
901+
__clear_bit(EV_REL, input->evbit);
902+
__clear_bit(REL_X, input->relbit);
903+
__clear_bit(REL_Y, input->relbit);
904+
905+
mt_flags = INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK;
906+
907+
/* finger touch area */
908+
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 5000, 0, 0);
909+
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 5000, 0, 0);
910+
911+
/* finger approach area */
912+
input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 5000, 0, 0);
913+
input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 5000, 0, 0);
914+
915+
/* Note: Touch Y position from the device is inverted relative
916+
* to how pointer motion is reported (and relative to how USB
917+
* HID recommends the coordinates work). This driver keeps
918+
* the origin at the same position, and just uses the additive
919+
* inverse of the reported Y.
920+
*/
921+
922+
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 6000, 0, 0);
923+
924+
/*
925+
* This makes libinput recognize this as a PressurePad and
926+
* stop trying to use pressure for touch size. Pressure unit
927+
* seems to be ~grams on these touchpads.
928+
*/
929+
input_abs_set_res(input, ABS_MT_PRESSURE, 1);
930+
931+
/* finger orientation */
932+
input_set_abs_params(input, ABS_MT_ORIENTATION, -J314_TP_MAX_FINGER_ORIENTATION,
933+
J314_TP_MAX_FINGER_ORIENTATION, 0, 0);
934+
935+
/* finger position */
936+
input_set_abs_params(input, ABS_MT_POSITION_X, J314_TP_MIN_X, J314_TP_MAX_X,
937+
0, 0);
938+
/* Y axis is inverted */
939+
input_set_abs_params(input, ABS_MT_POSITION_Y, -J314_TP_MAX_Y, -J314_TP_MIN_Y,
940+
0, 0);
941+
942+
/* X/Y resolution */
943+
input_abs_set_res(input, ABS_MT_POSITION_X, J314_TP_RES_X);
944+
input_abs_set_res(input, ABS_MT_POSITION_Y, J314_TP_RES_Y);
945+
946+
input_set_events_per_packet(input, 60);
947+
948+
/* touchpad button */
949+
input_set_capability(input, EV_KEY, BTN_MOUSE);
950+
951+
/*
952+
* hid-input may mark device as using autorepeat, but the trackpad does
953+
* not actually want it.
954+
*/
955+
__clear_bit(EV_REP, input->evbit);
956+
957+
error = input_mt_init_slots(input, MAX_CONTACTS, mt_flags);
958+
if (error)
959+
return error;
960+
961+
return 0;
962+
}
963+
730964
static int magicmouse_input_mapping(struct hid_device *hdev,
731965
struct hid_input *hi, struct hid_field *field,
732966
struct hid_usage *usage, unsigned long **bit, int *max)
@@ -777,14 +1011,18 @@ static int magicmouse_enable_multitouch(struct hid_device *hdev)
7771011
int feature_size;
7781012

7791013
switch (hdev->product) {
1014+
case SPI_DEVICE_ID_APPLE_MACBOOK_AIR_2020:
1015+
case SPI_DEVICE_ID_APPLE_MACBOOK_PRO13_2020:
1016+
case SPI_DEVICE_ID_APPLE_MACBOOK_PRO14_2021:
1017+
case SPI_DEVICE_ID_APPLE_MACBOOK_PRO16_2021:
7801018
case USB_DEVICE_ID_APPLE_MAGICTRACKPAD2:
7811019
case USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC:
7821020
switch (hdev->vendor) {
7831021
case BT_VENDOR_ID_APPLE:
7841022
feature_size = sizeof(feature_mt_trackpad2_bt);
7851023
feature = feature_mt_trackpad2_bt;
7861024
break;
787-
default: /* USB_VENDOR_ID_APPLE */
1025+
default: /* USB_VENDOR_ID_APPLE || SPI_VENDOR_ID_APPLE */
7881026
feature_size = sizeof(feature_mt_trackpad2_usb);
7891027
feature = feature_mt_trackpad2_usb;
7901028
}
@@ -881,14 +1119,25 @@ static int magicmouse_probe(struct hid_device *hdev,
8811119
struct hid_report *report;
8821120
int ret;
8831121

1122+
if (id->bus == BUS_SPI && id->vendor == SPI_VENDOR_ID_APPLE &&
1123+
hdev->type != HID_TYPE_SPI_MOUSE)
1124+
return -ENODEV;
1125+
8841126
msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL);
8851127
if (msc == NULL) {
8861128
hid_err(hdev, "can't alloc magicmouse descriptor\n");
8871129
return -ENOMEM;
8881130
}
8891131

890-
msc->input_ops.raw_event = magicmouse_raw_event_usb;
891-
msc->input_ops.setup_input = magicmouse_setup_input_usb;
1132+
// internal trackpad use a data format use input ops to avoid
1133+
// conflicts with the report ID.
1134+
if (id->vendor == SPI_VENDOR_ID_APPLE) {
1135+
msc->input_ops.raw_event = magicmouse_raw_event_spi;
1136+
msc->input_ops.setup_input = magicmouse_setup_input_spi;
1137+
} else {
1138+
msc->input_ops.raw_event = magicmouse_raw_event_usb;
1139+
msc->input_ops.setup_input = magicmouse_setup_input_usb;
1140+
}
8921141

8931142
msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
8941143
msc->hdev = hdev;
@@ -948,11 +1197,17 @@ static int magicmouse_probe(struct hid_device *hdev,
9481197
TRACKPAD2_USB_REPORT_ID, 0);
9491198
}
9501199
break;
951-
default: /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
952-
report = hid_register_report(hdev, HID_INPUT_REPORT,
953-
TRACKPAD_REPORT_ID, 0);
954-
report = hid_register_report(hdev, HID_INPUT_REPORT,
955-
DOUBLE_REPORT_ID, 0);
1200+
default:
1201+
switch (id->bus) {
1202+
case BUS_SPI:
1203+
report = hid_register_report(hdev, HID_INPUT_REPORT, SPI_REPORT_ID, 0);
1204+
break;
1205+
default: /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
1206+
report = hid_register_report(hdev, HID_INPUT_REPORT,
1207+
TRACKPAD_REPORT_ID, 0);
1208+
report = hid_register_report(hdev, HID_INPUT_REPORT,
1209+
DOUBLE_REPORT_ID, 0);
1210+
}
9561211
}
9571212

9581213
if (!report) {
@@ -1055,6 +1310,8 @@ static const struct hid_device_id magic_mice[] = {
10551310
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 },
10561311
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
10571312
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 },
1313+
{ HID_SPI_DEVICE(SPI_VENDOR_ID_APPLE, HID_ANY_ID),
1314+
.driver_data = 0 },
10581315
{ }
10591316
};
10601317
MODULE_DEVICE_TABLE(hid, magic_mice);

0 commit comments

Comments
 (0)