@@ -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
118131struct 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+
540701static 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+
730964static 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};
10601317MODULE_DEVICE_TABLE (hid , magic_mice );
0 commit comments