Hi, Changes v2: * port to 4.14-rc5 * test hardware with 4.14-rc5 This patch was originally posted by Marek Wyborski. The patch has been tested by several people with a dkms: https://github.com/robbi5/magictrackpad2-dkms https://github.com/torvalds/linux/pull/332 The driver currently only supports USB. One option would be to integrate bluetooth support into the bcm driver or to move the driver to the hid-magicmouse which supports bluetooth. I integrated the driver into the bcm and not the magicmouse driver, because this way i was able to compare the outcome with the macbook touchpad as i dont own a magicmouse or a magictrackpad. ---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.wyborski@xxxxxxxxxxxx> Signed-off-by: Stephan Mueller <smueller@xxxxxxxxxx> --- drivers/hid/hid-apple.c | 2 + drivers/hid/hid-core.c | 2 + drivers/hid/hid-ids.h | 1 + drivers/input/mouse/bcm5974.c | 123 ++++++++++++++++++++++++++++++++++++++---- 4 files changed, 117 insertions(+), 11 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 25b7bd56ae11..969f87e6ae6c 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -550,6 +550,8 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), + .driver_data = APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 330ca983828b..982061de9c05 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1957,6 +1957,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, @@ -2839,6 +2840,7 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index be2e005c3c51..0f1a6e821920 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -88,6 +88,7 @@ #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 #define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e +#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 0x0265 #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e #define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f #define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index d0122134f320..2fe645c068cd 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -16,6 +16,7 @@ * Copyright (C) 2005 Peter Osterlund (petero2@xxxxxxxxx) * Copyright (C) 2005 Michael Hanselmann (linux-kernel@xxxxxxxxx) * Copyright (C) 2006 Nicolas Boichat (nicolas@xxxxxxxxxx) + * Copyright (C) 2016 Marek Wyborski (marek.wyborski@xxxxxxxxxxxx) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -96,6 +97,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 +164,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 +195,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 +204,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 +221,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 +258,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 +520,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, -3678, 3934 }, + { SN_COORD, -2479, 2586 }, + { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION } + }, {} }; @@ -539,9 +575,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 +636,23 @@ 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_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(f->touch_major) << 2); + input_report_abs(input, ABS_MT_TOUCH_MINOR, + raw2int(f->touch_minor) << 2); + input_report_abs(input, ABS_MT_ORIENTATION, + MAX_FINGER_ORIENTATION - ((f->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 +672,31 @@ 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_type5 *f, int raw_n) +{ + int abs_p = 0, abs_w = 0; + + if (raw_n) { + int p = f->pressure; + int w = f->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 +706,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], + (const struct tp_finger_type5 *) 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, + (const struct tp_finger_type5*) get_tp_finger(dev, 0), raw_n); /* later types report button events via integrated button only */ if (c->caps & HAS_INTEGRATED_BUTTON) { -- 2.13.6 -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html