Hi,

Changes v3:
* port to 4.15-rc8
* small code cleanups (isolation of type casts to functions pertaining
  to the Apple Magic Trackpad 2
* clean up all checkpatch.pl errors and warnings (except those
  where the patch uses the structure of existing code fragments)
* updated horizontal and vertical limits to capture start of movements
  in the outer areas of the pad

---8<---

Add support for Apple Magic Trackpad 2 in bcm5974 (MacBook Tochpad) driver.
The Magic Trackpad 2 needs to be switched into the finger-reporting-mode,
just like the other macbook touchpads as well. But the format is different
to the ones before. The Header is 12 Bytes long and each reported finger
is additional 9 Bytes. The data order reported by the hardware is
different as well.

Signed-off-by: Marek Wyborski <marek.wybor...@emwesoft.com>
Signed-off-by: Stephan Mueller <smuel...@chronox.de>
---
 drivers/input/mouse/bcm5974.c | 127 +++++++++++++++++++++++++++++++++++++
+----
 1 file changed, 116 insertions(+), 11 deletions(-)

diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index d0122134f320..11868321992c 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -96,6 +96,8 @@
 #define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI   0x0272
 #define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO    0x0273
 #define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS    0x0274
+/* MagicTrackpad2 (2015) */
+#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2     0x0265
 
 #define BCM5974_DEVICE(prod) {                                 \
        .match_flags = (USB_DEVICE_ID_MATCH_DEVICE |            \
@@ -161,6 +163,8 @@ static const struct usb_device_id bcm5974_table[] = {
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
+       /* MagicTrackpad2 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_MAGICTRACKPAD2),
        /* Terminating entry */
        {}
 };
@@ -190,7 +194,8 @@ enum tp_type {
        TYPE1,                  /* plain trackpad */
        TYPE2,                  /* button integrated in trackpad */
        TYPE3,                  /* additional header fields since June 2013 */
-       TYPE4                   /* additional header field for pressure data */
+       TYPE4,                  /* additional header field for pressure data */
+       TYPE5                   /* format for magic trackpad 2 */
 };
 
 /* trackpad finger data offsets, le16-aligned */
@@ -198,12 +203,14 @@ enum tp_type {
 #define HEADER_TYPE2           (15 * sizeof(__le16))
 #define HEADER_TYPE3           (19 * sizeof(__le16))
 #define HEADER_TYPE4           (23 * sizeof(__le16))
+#define HEADER_TYPE5           (6  * sizeof(__le16))
 
 /* trackpad button data offsets */
 #define BUTTON_TYPE1           0
 #define BUTTON_TYPE2           15
 #define BUTTON_TYPE3           23
 #define BUTTON_TYPE4           31
+#define BUTTON_TYPE5           1
 
 /* list of device capability bits */
 #define HAS_INTEGRATED_BUTTON  1
@@ -213,18 +220,21 @@ enum tp_type {
 #define FSIZE_TYPE2            (14 * sizeof(__le16))
 #define FSIZE_TYPE3            (14 * sizeof(__le16))
 #define FSIZE_TYPE4            (15 * sizeof(__le16))
+#define FSIZE_TYPE5            (9)
 
 /* offset from header to finger struct */
 #define DELTA_TYPE1            (0 * sizeof(__le16))
 #define DELTA_TYPE2            (0 * sizeof(__le16))
 #define DELTA_TYPE3            (0 * sizeof(__le16))
 #define DELTA_TYPE4            (1 * sizeof(__le16))
+#define DELTA_TYPE5            (0 * sizeof(__le16))
 
 /* usb control message mode switch data */
 #define USBMSG_TYPE1           8, 0x300, 0, 0, 0x1, 0x8
 #define USBMSG_TYPE2           8, 0x300, 0, 0, 0x1, 0x8
 #define USBMSG_TYPE3           8, 0x300, 0, 0, 0x1, 0x8
 #define USBMSG_TYPE4           2, 0x302, 2, 1, 0x1, 0x0
+#define USBMSG_TYPE5           2, 0x302, 1, 1, 0x1, 0x0
 
 /* Wellspring initialization constants */
 #define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID                1
@@ -247,6 +257,18 @@ struct tp_finger {
        __le16 multi;           /* one finger: varies, more fingers: constant */
 } __attribute__((packed,aligned(2)));
 
+/* trackpad finger structure for type5 (magic trackpad), le16-aligned */
+struct tp_finger_type5 {
+       u8 abs_x;               /* absolute x coodinate */
+       u8 abs_x_y;             /* absolute x,y coodinate */
+       u8 abs_y[2];            /* absolute y coodinate */
+       u8 touch_major;         /* touch area, major axis */
+       u8 touch_minor;         /* touch area, minor axis */
+       u8 size;                /* tool area, size */
+       u8 pressure;            /* pressure on forcetouch touchpad */
+       u8 orientation_origin;  /* orientation and id */
+} __attribute__((packed,aligned(2)));
+
 /* trackpad finger data size, empirically at least ten fingers */
 #define MAX_FINGERS            16
 #define MAX_FINGER_ORIENTATION 16384
@@ -497,6 +519,19 @@ static const struct bcm5974_config bcm5974_config_table[] 
= {
                { SN_COORD, -203, 6803 },
                { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
        },
+       {
+               USB_DEVICE_ID_APPLE_MAGICTRACKPAD2,
+               USB_DEVICE_ID_APPLE_MAGICTRACKPAD2,
+               USB_DEVICE_ID_APPLE_MAGICTRACKPAD2,
+               HAS_INTEGRATED_BUTTON,
+               0, sizeof(struct bt_data),
+               0x83, DATAFORMAT(TYPE5),
+               { SN_PRESSURE, 0, 300 },
+               { SN_WIDTH, 0, 2048 },
+               { SN_COORD, -9000, 9000 },
+               { SN_COORD, -6803, 6803 },
+               { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
+       },
        {}
 };
 
@@ -539,9 +574,13 @@ static void setup_events_to_report(struct input_dev 
*input_dev,
        /* finger touch area */
        set_abs(input_dev, ABS_MT_TOUCH_MAJOR, &cfg->w);
        set_abs(input_dev, ABS_MT_TOUCH_MINOR, &cfg->w);
+
        /* finger approach area */
-       set_abs(input_dev, ABS_MT_WIDTH_MAJOR, &cfg->w);
-       set_abs(input_dev, ABS_MT_WIDTH_MINOR, &cfg->w);
+       if (cfg->tp_type != TYPE5) {
+               set_abs(input_dev, ABS_MT_WIDTH_MAJOR, &cfg->w);
+               set_abs(input_dev, ABS_MT_WIDTH_MINOR, &cfg->w);
+       }
+
        /* finger orientation */
        set_abs(input_dev, ABS_MT_ORIENTATION, &cfg->o);
        /* finger position */
@@ -596,6 +635,25 @@ static void report_finger_data(struct input_dev *input, 
int slot,
        input_report_abs(input, ABS_MT_POSITION_Y, pos->y);
 }
 
+static void report_finger_data_type5(struct input_dev *input, int slot,
+                                    const struct input_mt_pos *pos,
+                                    const struct tp_finger *f)
+{
+       const struct tp_finger_type5 *f5 = (const struct tp_finger_type5 *)f;
+
+       input_mt_slot(input, slot);
+       input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+
+       input_report_abs(input, ABS_MT_TOUCH_MAJOR,
+                        raw2int(f5->touch_major) << 2);
+       input_report_abs(input, ABS_MT_TOUCH_MINOR,
+                        raw2int(f5->touch_minor) << 2);
+       input_report_abs(input, ABS_MT_ORIENTATION,
+               MAX_FINGER_ORIENTATION - ((f5->orientation_origin & 0xf0) << 
6));
+       input_report_abs(input, ABS_MT_POSITION_X, pos->x << 1);
+       input_report_abs(input, ABS_MT_POSITION_Y, pos->y << 1);
+}
+
 static void report_synaptics_data(struct input_dev *input,
                                  const struct bcm5974_config *cfg,
                                  const struct tp_finger *f, int raw_n)
@@ -615,11 +673,34 @@ static void report_synaptics_data(struct input_dev 
*input,
        input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
 }
 
+static void report_synaptics_data_type5(struct input_dev *input,
+                                       const struct bcm5974_config *cfg,
+                                       const struct tp_finger *f,
+                                       int raw_n)
+{
+       const struct tp_finger_type5 *f5 = (const struct tp_finger_type5 *)f;
+       int abs_p = 0, abs_w = 0;
+
+       if (raw_n) {
+               int p = f5->pressure;
+               int w = f5->size;
+
+               if (p && w) {
+                       abs_p = p;
+                       abs_w = w;
+               }
+       }
+
+       input_report_abs(input, ABS_PRESSURE, abs_p);
+       input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
+}
+
 /* report trackpad data as logical trackpad state */
 static int report_tp_state(struct bcm5974 *dev, int size)
 {
        const struct bcm5974_config *c = &dev->cfg;
        const struct tp_finger *f;
+       const struct tp_finger_type5 *f_type5;
        struct input_dev *input = dev->input;
        int raw_n, i, n = 0;
 
@@ -629,23 +710,47 @@ static int report_tp_state(struct bcm5974 *dev, int 
size)
        raw_n = (size - c->tp_header) / c->tp_fsize;
 
        for (i = 0; i < raw_n; i++) {
+
                f = get_tp_finger(dev, i);
-               if (raw2int(f->touch_major) == 0)
-                       continue;
-               dev->pos[n].x = raw2int(f->abs_x);
-               dev->pos[n].y = c->y.min + c->y.max - raw2int(f->abs_y);
+
+               if (c->tp_type != TYPE5) {
+                       if (raw2int(f->touch_major) == 0)
+                               continue;
+                       dev->pos[n].x = raw2int(f->abs_x);
+                       dev->pos[n].y = c->y.min + c->y.max - raw2int(f->abs_y);
+               } else {
+                       u16 tmp_x;
+                       u32 tmp_y;
+
+                       f_type5 = (const struct tp_finger_type5 *) f;
+                       if (f_type5->pressure == 0)
+                               continue;
+                       tmp_x = le16_to_cpu(*((__le16 *)f_type5)) & 0x1fff;
+                       dev->pos[n].x = (s16) (tmp_x << 3) >> 3;
+                       tmp_y = (s32) le32_to_cpu(*((__le32 *)f_type5));
+                       dev->pos[n].y = -(s32) (tmp_y << 6) >> 19;
+               }
                dev->index[n++] = f;
        }
 
        input_mt_assign_slots(input, dev->slots, dev->pos, n, 0);
 
-       for (i = 0; i < n; i++)
-               report_finger_data(input, dev->slots[i],
-                                  &dev->pos[i], dev->index[i]);
+       for (i = 0; i < n; i++) {
+               if (c->tp_type != TYPE5)
+                       report_finger_data(input, dev->slots[i],
+                                          &dev->pos[i], dev->index[i]);
+               else
+                       report_finger_data_type5(input, dev->slots[i],
+                                                &dev->pos[i], dev->index[i]);
+       }
 
        input_mt_sync_frame(input);
 
-       report_synaptics_data(input, c, get_tp_finger(dev, 0), raw_n);
+       if (c->tp_type != TYPE5)
+               report_synaptics_data(input, c, get_tp_finger(dev, 0), raw_n);
+       else
+               report_synaptics_data_type5(input, c, get_tp_finger(dev, 0),
+                                           raw_n);
 
        /* later types report button events via integrated button only */
        if (c->caps & HAS_INTEGRATED_BUTTON) {
-- 
2.14.3




Reply via email to