[PATCH v3] input: bcm5974 - Add driver for Apple Magic Trackpad 2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.wyborski@xxxxxxxxxxxx>
Signed-off-by: Stephan Mueller <smueller@xxxxxxxxxx>
---
 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




--
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



[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux