From: Kirill A. Korinsky Subject: Help with backport support of Apple MagicTracpad 2 To: tech@openbsd.org Date: Sun, 03 Mar 2024 22:57:38 +0100 Dear tech@, I need help with backporting support of Apple MagicTracpad 2. As a base implementation I've used code from FreeBSD [1] which seems quite trivial. Anyway, a naive reimplementation doesn't work. When I attach the device I have inside dmesg: uhidev0 at uhub0 port 1 configuration 1 interface 0 "Apple Inc. Magic Trackpad" rev 2.00/8.60 addr 4 uhidev0: iclass 3/0, 224 report ids uhid0 at uhidev0 reportid 144: input=2, output=0, feature=0 uhid1 at uhidev0 reportid 154: input=1, output=0, feature=0 uhid2 at uhidev0 reportid 224: input=4, output=0, feature=0 ubcmtp0 at uhub0 port 1 configuration 1 interface 1 "Apple Inc. Magic Trackpad" rev 2.00/8.60 addr 4 ubcmtp0: attached to 0x5ac/0x265 type 5 wsmouse4 at ubcmtp0 ubcmtp0: ubcmtp_raw_mode: failed to toggle raw mode ubcmtp0: failed to enter raw mode attach error=1 uhidev1 at uhub0 port 1 configuration 1 interface 3 "Apple Inc. Magic Trackpad" rev 2.00/8.60 addr 4 uhidev1: iclass 3/0, 192 report ids uhid3 at uhidev1 reportid 192: input=107, output=0, feature=0 uhid0 detached uhid1 detached uhid2 detached uhidev0 detached wsmouse4 detached ubcmtp0 detached uhid3 detached uhidev1 detached that means that it can't enter into raw mode. So, I deffently had missed something. Footnotes: [1] https://github.com/freebsd/freebsd-src/commit/ef8397c28e981e0115d435aabcf57cee7ea5f5ee -- wbr, Kirill diff --git sys/dev/usb/ubcmtp.c sys/dev/usb/ubcmtp.c index fd53f52281b..a502c87a39c 100644 --- sys/dev/usb/ubcmtp.c +++ sys/dev/usb/ubcmtp.c @@ -78,9 +78,32 @@ struct ubcmtp_finger { uint16_t multi; } __packed __attribute((aligned(2))); +struct ubcmtp_finger_compact { + uint32_t coords; + uint8_t touch_major; + uint8_t touch_minor; + uint8_t size; + uint8_t pressure; + unsigned int orientation: 3; + unsigned int _unknown1: 1; + unsigned int id: 4; +} __packed __attribute((aligned(2))); + +union ubcmtp_finger_compact_coords { + uint32_t num; + struct { + signed int x: 13; + signed int y: 13; + signed int _unknown: 4; + signed int state: 2; + } __packed __attribute((aligned(2))); +}; + #define UBCMTP_MAX_FINGERS 16 #define UBCMTP_ALL_FINGER_SIZE (UBCMTP_MAX_FINGERS * sizeof(struct ubcmtp_finger)) +#define UBCMTP_COMPACT_FINGER_SIZE (UBCMTP_MAX_FINGERS * sizeof(struct ubcmtp_finger_compact)) + #define UBCMTP_TYPE1 1 #define UBCMTP_TYPE1_TPOFF (13 * sizeof(uint16_t)) #define UBCMTP_TYPE1_TPLEN UBCMTP_TYPE1_TPOFF + UBCMTP_ALL_FINGER_SIZE @@ -106,6 +129,13 @@ struct ubcmtp_finger { #define UBCMTP_TYPE4_BTOFF 31 #define UBCMTP_TYPE4_FINGERPAD (1 * sizeof(uint16_t)) +// TODO: ??? +#define UBCMTP_TYPE_MT2U 5 +#define UBCMTP_TYPE_MT2U_TPOFF 12 +#define UBCMTP_TYPE_MT2U_TPLEN UBCMTP_TYPE_MT2U_TPOFF + UBCMTP_COMPACT_FINGER_SIZE +#define UBCMTP_TYPE_MT2U_TPIFACE 2 +#define UBCMTP_TYPE_MT2U_BTOFF 1 + #define UBCMTP_FINGER_ORIENT 16384 #define UBCMTP_SN_PRESSURE 45 #define UBCMTP_SN_WIDTH 25 @@ -307,6 +337,18 @@ static const struct ubcmtp_dev ubcmtp_devices[] = { { UBCMTP_SN_COORD, -203, 6803 }, { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, }, + { + USB_VENDOR_APPLE, + USB_PRODUCT_APPLE_MAGIC_TRACKPAD2, + USB_PRODUCT_APPLE_MAGIC_TRACKPAD2, + USB_PRODUCT_APPLE_MAGIC_TRACKPAD2, + UBCMTP_TYPE_MT2U, + { UBCMTP_SN_PRESSURE, 0, 256 }, + { UBCMTP_SN_WIDTH, 0, 2048 }, + { UBCMTP_SN_COORD, -3678, 3934 }, + { UBCMTP_SN_COORD, -2478, 2587 }, + { UBCMTP_SN_ORIENT, -UBCMTP_FINGER_ORIENT, UBCMTP_FINGER_ORIENT }, + }, }; static struct wsmouse_param ubcmtp_wsmousecfg[] = { @@ -481,6 +523,13 @@ ubcmtp_attach(struct device *parent, struct device *self, void *aux) sc->tp_fingerpad = UBCMTP_TYPE4_FINGERPAD; usbd_claim_iface(sc->sc_udev, UBCMTP_TYPE4_TPIFACE); break; + + case UBCMTP_TYPE_MT2U: + sc->tp_maxlen = UBCMTP_TYPE_MT2U_TPLEN; + sc->tp_offset = UBCMTP_TYPE_MT2U_TPOFF; + sc->sc_tp_iface = uaa->ifaces[UBCMTP_TYPE_MT2U_TPIFACE]; + usbd_claim_iface(sc->sc_udev, UBCMTP_TYPE_MT2U_TPIFACE); + break; } a.accessops = &ubcmtp_accessops; @@ -531,7 +580,9 @@ ubcmtp_configure(struct ubcmtp_softc *sc) hw->y_min = sc->dev_type->l_y.min; hw->y_max = sc->dev_type->l_y.max; hw->mt_slots = UBCMTP_MAX_FINGERS; - hw->flags = WSMOUSEHW_MT_TRACKING; + // TODO: ??? + if (sc->dev_type->type != UBCMTP_TYPE_MT2U) + hw->flags = WSMOUSEHW_MT_TRACKING; return wsmouse_configure(sc->sc_wsmousedev, ubcmtp_wsmousecfg, nitems(ubcmtp_wsmousecfg)); @@ -651,6 +702,12 @@ ubcmtp_raw_mode(struct ubcmtp_softc *sc, int enable) if (sc->dev_type->type == UBCMTP_TYPE3) return (0); + if (sc->dev_type->type == UBCMTP_TYPE_MT2U) { + buf[0] = 2; + goto bypass_read; + } + r.bRequest = UR_GET_REPORT; r.bmRequestType = UT_READ_CLASS_INTERFACE; if (sc->dev_type->type < UBCMTP_TYPE4) { @@ -670,6 +727,7 @@ ubcmtp_raw_mode(struct ubcmtp_softc *sc, int enable) return (err); } +bypass_read: /* toggle magic byte and write everything back */ if (sc->dev_type->type < UBCMTP_TYPE4) buf[0] = (enable ? UBCMTP_WELLSPRING_MODE_RAW : @@ -779,6 +837,8 @@ ubcmtp_tp_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) { struct ubcmtp_softc *sc = priv; struct ubcmtp_finger *finger; + struct ubcmtp_finger_compact *compact_finger; + union ubcmtp_finger_compact_coords compact_finger_coords; u_int32_t pktlen; int off, s, btn, contacts = 0; @@ -802,6 +862,28 @@ ubcmtp_tp_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) return; contacts = 0; + + /* Magic Trackpad 2 has so-called compact report */ + if (sc->dev_type->type == UBCMTP_TYPE_MT2U) { + for (off = sc->tp_offset; off < pktlen; + off += (sizeof(struct ubcmtp_finger_compact) + sc->tp_fingerpad)) { + compact_finger = (struct ubcmtp_finger_compact *)(sc->tp_pkt + off); + + if (letoh32(compact_finger->touch_major) == 0) + continue; /* finger lifted */ + + compact_finger_coords.num = letoh32(compact_finger->coords); + + sc->frame[contacts].x = compact_finger_coords.x; + sc->frame[contacts].y = sc->dev_type->l_y.min + + sc->dev_type->l_y.max- compact_finger_coords.y; + sc->frame[contacts].pressure = DEFAULT_PRESSURE; + contacts++; + } + + goto done; + } + for (off = sc->tp_offset; off < pktlen; off += (sizeof(struct ubcmtp_finger) + sc->tp_fingerpad)) { finger = (struct ubcmtp_finger *)(sc->tp_pkt + off); @@ -815,6 +897,8 @@ ubcmtp_tp_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) contacts++; } +done: + btn = sc->btn; if (sc->dev_type->type == UBCMTP_TYPE2) sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE2_BTOFF])); @@ -822,6 +906,8 @@ ubcmtp_tp_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE3_BTOFF])); else if (sc->dev_type->type == UBCMTP_TYPE4) sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE4_BTOFF])); + else if (sc->dev_type->type == UBCMTP_TYPE_MT2U) + sc->btn = !!((int16_t)letoh16(sc->tp_pkt[UBCMTP_TYPE_MT2U_BTOFF])); if (contacts || sc->contacts || sc->btn != btn) { sc->contacts = contacts; diff --git sys/dev/usb/usbdevs sys/dev/usb/usbdevs index 40346863f84..20ccd15b7c3 100644 --- sys/dev/usb/usbdevs +++ sys/dev/usb/usbdevs @@ -998,6 +998,7 @@ product APPLE WELLSPRING7A_JIS 0x025b Keyboard/Trackpad product APPLE WELLSPRING7_ANSI 0x0262 Keyboard/Trackpad product APPLE WELLSPRING7_ISO 0x0263 Keyboard/Trackpad product APPLE WELLSPRING7_JIS 0x0264 Keyboard/Trackpad +product APPLE MAGIC_TRACKPAD2 0x0265 Apple Magic Trackpad 2 product APPLE WELLSPRING9_ANSI 0x0272 Keyboard/Trackpad product APPLE WELLSPRING9_ISO 0x0273 Keyboard/Trackpad product APPLE WELLSPRING9_JIS 0x0274 Keyboard/Trackpad diff --git sys/dev/usb/usbdevs.h sys/dev/usb/usbdevs.h index 9a7e68f213b..1b0eaa35cc3 100644 --- sys/dev/usb/usbdevs.h +++ sys/dev/usb/usbdevs.h @@ -1005,6 +1005,7 @@ #define USB_PRODUCT_APPLE_WELLSPRING7_ANSI 0x0262 /* Keyboard/Trackpad */ #define USB_PRODUCT_APPLE_WELLSPRING7_ISO 0x0263 /* Keyboard/Trackpad */ #define USB_PRODUCT_APPLE_WELLSPRING7_JIS 0x0264 /* Keyboard/Trackpad */ +#define USB_PRODUCT_APPLE_MAGIC_TRACKPAD2 0x0265 /* Apple Magic Trackpad 2 */ #define USB_PRODUCT_APPLE_WELLSPRING9_ANSI 0x0272 /* Keyboard/Trackpad */ #define USB_PRODUCT_APPLE_WELLSPRING9_ISO 0x0273 /* Keyboard/Trackpad */ #define USB_PRODUCT_APPLE_WELLSPRING9_JIS 0x0274 /* Keyboard/Trackpad */ diff --git sys/dev/usb/usbdevs_data.h sys/dev/usb/usbdevs_data.h index 3cf210c7e8d..93ee045aa03 100644 --- sys/dev/usb/usbdevs_data.h +++ sys/dev/usb/usbdevs_data.h @@ -901,6 +901,10 @@ const struct usb_known_product usb_known_products[] = { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_WELLSPRING7_JIS, "Keyboard/Trackpad", }, + { + USB_VENDOR_APPLE, USB_PRODUCT_APPLE_MAGIC_TRACKPAD2, + "Apple Magic Trackpad 2", + }, { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_WELLSPRING9_ANSI, "Keyboard/Trackpad",