From patchwork Sat Jul 8 00:59:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Wyborski X-Patchwork-Id: 9831283 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id AF29860352 for ; Sat, 8 Jul 2017 00:59:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9C5EA2847B for ; Sat, 8 Jul 2017 00:59:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 906F0284E4; Sat, 8 Jul 2017 00:59:52 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0E0A92847B for ; Sat, 8 Jul 2017 00:59:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751812AbdGHA7u (ORCPT ); Fri, 7 Jul 2017 20:59:50 -0400 Received: from mail-wr0-f196.google.com ([209.85.128.196]:35535 "EHLO mail-wr0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751034AbdGHA7s (ORCPT ); Fri, 7 Jul 2017 20:59:48 -0400 Received: by mail-wr0-f196.google.com with SMTP id z45so11128400wrb.2; Fri, 07 Jul 2017 17:59:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:date:from:to:subject:message-id:mime-version :content-disposition:user-agent; bh=RFbPYFBocEXlxxZ6YjWHCwlgNKHRzsaq1rTAWBDZVGM=; b=vJpwJ5PJG7kb82XCF9gJ8NCg63rddeDfB54xUMjvdeZjz1H6QTeQXjzBSGWzMFLzP5 L67TosrKRDhHCC4YpyAHeOZKegU6tkWpIMML5EIx6GC4dgT/Ryjz2qihAubxLG1QvfUD fj2e3RMrnzSHbB+MzG4lAaeRIxX36Y0+hOb63fE4tpsKH/O7yCcY/tO0JGgOeLX4vpIW Gjx+xj1ucgqMdybPXFqrsSdBpfAckzJ7Ni654hiaqy5mPQyx1ZJZAQ1qGWaptnPuzXUm Pc/JiKIMzAFpsrZzhm2ixyq8GqFE52qpjhg2Q5uLe8DuChXE8kjVvDomHAyYkuNCpor8 Kadw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:subject:message-id :mime-version:content-disposition:user-agent; bh=RFbPYFBocEXlxxZ6YjWHCwlgNKHRzsaq1rTAWBDZVGM=; b=BzCnpMUuc9I0lXCFBHYEmDhSP2vtO4t0CTHAvQGgUHIiipKLfmzHYHcensdlyqDGfz ukvz3fRmRNUTNnluej86SHiuUg42yXWPBQLqSjt7URVBt5xdUqOr3QGKEK87NtlsGEsB a78lvK8YPdJdqhdTHEA1ZXY/N55kTyHSCVQpNwuTRFLxTdwKrEeOrUHbQy7M9ph2IkrF dl3YPwU9p8gOxELvF2oNDhjtck6B84OYY4qGACkgUGBl9gvRsQDacApDsQTpNUhgL0hN xxNYCvDCciO3NyPjuJvjVrPTc+GjytnZM8Adw+c7/FYFir9JEObkc/M3WRxwDqI6RFII O3dg== X-Gm-Message-State: AIVw112eWMZwf1p1qBZkZXHDKTMYx2V1LxUfRPCTcHMU2jfM27VgK44t VCK4hD5BK+BH08B5 X-Received: by 10.28.32.5 with SMTP id g5mr813819wmg.70.1499475586720; Fri, 07 Jul 2017 17:59:46 -0700 (PDT) Received: from schenker.localdomain (178.66.216.87.dynamic.jazztel.es. [87.216.66.178]) by smtp.gmail.com with ESMTPSA id u80sm4986601wrb.1.2017.07.07.17.59.45 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 07 Jul 2017 17:59:45 -0700 (PDT) Date: Sat, 8 Jul 2017 02:59:44 +0200 From: Marek Wyborski To: rydberg@bitmath.org, linux-kernel@vger.kernel.org, linux-input@vger.kernel.org Subject: [PATCH] input: mouse: bcm5974: Add driver for Apple Magic Trackpad 2 Message-ID: <20170708005944.GC7064@schenker.localdomain> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.8.3 (2017-05-23) Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Marek Wyborski Added 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 is as well different. 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. The patch has been tested by several people with a dkms: https://github.com/robbi5/magictrackpad2-dkms https://github.com/torvalds/linux/pull/332 Signed-off-by: Marek Wyborski Acked-By: Alex Manoussakis --- 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(-) -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 2e046082210f..c28af08d23ee 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -554,6 +554,8 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, { 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 2241e7913c0d..c57cec669ac8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1869,6 +1869,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) }, @@ -2746,6 +2747,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 4f9a3938189a..6b3e7ee177f2 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -86,6 +86,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@telia.com) * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch) + * Copyright (C) 2016 Marek Wyborski (marek.wyborski@emwesoft.com) * * 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) {