[PATCH v3] input: bcm5974 - Add driver for Apple Magic Trackpad 2
From: Stephan Müller <hidden>
Date: 2018-01-21 22:07:00
Also in:
lkml
Subsystem:
apple bcm5974 multitouch driver, input (keyboard, mouse, joystick, touchscreen) drivers, the rest · Maintainers:
Henrik Rydberg, Dmitry Torokhov, Linus Torvalds
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 <redacted> Signed-off-by: Stephan Mueller <redacted> --- 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