xref: /openbmc/linux/drivers/hid/hid-magicmouse.c (revision 278002edb19bce2c628fafb0af936e77000f3a5b)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2128537ceSMichael Poole /*
3128537ceSMichael Poole  *   Apple "Magic" Wireless Mouse driver
4128537ceSMichael Poole  *
5128537ceSMichael Poole  *   Copyright (c) 2010 Michael Poole <mdpoole@troilus.org>
6a462230eSChase Douglas  *   Copyright (c) 2010 Chase Douglas <chase.douglas@canonical.com>
7128537ceSMichael Poole  */
8128537ceSMichael Poole 
9128537ceSMichael Poole /*
10128537ceSMichael Poole  */
11128537ceSMichael Poole 
124291ee30SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
134291ee30SJoe Perches 
14128537ceSMichael Poole #include <linux/device.h>
15128537ceSMichael Poole #include <linux/hid.h>
16a6d1bc1dSYufeng Shen #include <linux/input/mt.h>
17128537ceSMichael Poole #include <linux/module.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
19c0dc5582SJohn Chen #include <linux/workqueue.h>
20128537ceSMichael Poole 
21128537ceSMichael Poole #include "hid-ids.h"
22128537ceSMichael Poole 
2371b38bd4SMichael Poole static bool emulate_3button = true;
24128537ceSMichael Poole module_param(emulate_3button, bool, 0644);
25128537ceSMichael Poole MODULE_PARM_DESC(emulate_3button, "Emulate a middle button");
26128537ceSMichael Poole 
27128537ceSMichael Poole static int middle_button_start = -350;
28128537ceSMichael Poole static int middle_button_stop = +350;
29128537ceSMichael Poole 
3071b38bd4SMichael Poole static bool emulate_scroll_wheel = true;
31128537ceSMichael Poole module_param(emulate_scroll_wheel, bool, 0644);
32128537ceSMichael Poole MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");
33128537ceSMichael Poole 
340b778e76SChase Douglas static unsigned int scroll_speed = 32;
param_set_scroll_speed(const char * val,const struct kernel_param * kp)35e4dca7b7SKees Cook static int param_set_scroll_speed(const char *val,
36e4dca7b7SKees Cook 				  const struct kernel_param *kp) {
370b778e76SChase Douglas 	unsigned long speed;
38dfc450b5SJingoo Han 	if (!val || kstrtoul(val, 0, &speed) || speed > 63)
390b778e76SChase Douglas 		return -EINVAL;
400b778e76SChase Douglas 	scroll_speed = speed;
410b778e76SChase Douglas 	return 0;
420b778e76SChase Douglas }
430b778e76SChase Douglas module_param_call(scroll_speed, param_set_scroll_speed, param_get_uint, &scroll_speed, 0644);
440b778e76SChase Douglas MODULE_PARM_DESC(scroll_speed, "Scroll speed, value from 0 (slow) to 63 (fast)");
450b778e76SChase Douglas 
469846f350SChase Douglas static bool scroll_acceleration = false;
479846f350SChase Douglas module_param(scroll_acceleration, bool, 0644);
489846f350SChase Douglas MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events");
499846f350SChase Douglas 
5071b38bd4SMichael Poole static bool report_undeciphered;
51128537ceSMichael Poole module_param(report_undeciphered, bool, 0644);
52128537ceSMichael Poole MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event");
53128537ceSMichael Poole 
545768701eSJosé Expósito #define TRACKPAD2_2021_BT_VERSION 0x110
555768701eSJosé Expósito 
56a462230eSChase Douglas #define TRACKPAD_REPORT_ID 0x28
579d7b1866SSean O'Brien #define TRACKPAD2_USB_REPORT_ID 0x02
589d7b1866SSean O'Brien #define TRACKPAD2_BT_REPORT_ID 0x31
59a462230eSChase Douglas #define MOUSE_REPORT_ID    0x29
602b0c086cSJohn Chen #define MOUSE2_REPORT_ID   0x12
61a462230eSChase Douglas #define DOUBLE_REPORT_ID   0xf7
620b91b4e4SJosé Expósito #define USB_BATTERY_TIMEOUT_MS 60000
630b91b4e4SJosé Expósito 
64128537ceSMichael Poole /* These definitions are not precise, but they're close enough.  (Bits
65128537ceSMichael Poole  * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
66128537ceSMichael Poole  * to be some kind of bit mask -- 0x20 may be a near-field reading,
67128537ceSMichael Poole  * and 0x40 is actual contact, and 0x10 may be a start/stop or change
68128537ceSMichael Poole  * indication.)
69128537ceSMichael Poole  */
70128537ceSMichael Poole #define TOUCH_STATE_MASK  0xf0
71128537ceSMichael Poole #define TOUCH_STATE_NONE  0x00
72128537ceSMichael Poole #define TOUCH_STATE_START 0x30
73128537ceSMichael Poole #define TOUCH_STATE_DRAG  0x40
74128537ceSMichael Poole 
75d4b9f10aSJosé Expósito /* Number of high-resolution events for each low-resolution detent. */
76d4b9f10aSJosé Expósito #define SCROLL_HR_STEPS 10
77d4b9f10aSJosé Expósito #define SCROLL_HR_MULT (120 / SCROLL_HR_STEPS)
789d60648cSJosé Expósito #define SCROLL_HR_THRESHOLD 90 /* units */
790b778e76SChase Douglas #define SCROLL_ACCEL_DEFAULT 7
800b778e76SChase Douglas 
814f6fdf08SChase Douglas /* Touch surface information. Dimension is in hundredths of a mm, min and max
824f6fdf08SChase Douglas  * are in units. */
834f6fdf08SChase Douglas #define MOUSE_DIMENSION_X (float)9056
844f6fdf08SChase Douglas #define MOUSE_MIN_X -1100
854f6fdf08SChase Douglas #define MOUSE_MAX_X 1258
864f6fdf08SChase Douglas #define MOUSE_RES_X ((MOUSE_MAX_X - MOUSE_MIN_X) / (MOUSE_DIMENSION_X / 100))
874f6fdf08SChase Douglas #define MOUSE_DIMENSION_Y (float)5152
884f6fdf08SChase Douglas #define MOUSE_MIN_Y -1589
894f6fdf08SChase Douglas #define MOUSE_MAX_Y 2047
904f6fdf08SChase Douglas #define MOUSE_RES_Y ((MOUSE_MAX_Y - MOUSE_MIN_Y) / (MOUSE_DIMENSION_Y / 100))
914f6fdf08SChase Douglas 
924f6fdf08SChase Douglas #define TRACKPAD_DIMENSION_X (float)13000
934f6fdf08SChase Douglas #define TRACKPAD_MIN_X -2909
944f6fdf08SChase Douglas #define TRACKPAD_MAX_X 3167
954f6fdf08SChase Douglas #define TRACKPAD_RES_X \
964f6fdf08SChase Douglas 	((TRACKPAD_MAX_X - TRACKPAD_MIN_X) / (TRACKPAD_DIMENSION_X / 100))
974f6fdf08SChase Douglas #define TRACKPAD_DIMENSION_Y (float)11000
984f6fdf08SChase Douglas #define TRACKPAD_MIN_Y -2456
994f6fdf08SChase Douglas #define TRACKPAD_MAX_Y 2565
1004f6fdf08SChase Douglas #define TRACKPAD_RES_Y \
1014f6fdf08SChase Douglas 	((TRACKPAD_MAX_Y - TRACKPAD_MIN_Y) / (TRACKPAD_DIMENSION_Y / 100))
1024f6fdf08SChase Douglas 
1039d7b1866SSean O'Brien #define TRACKPAD2_DIMENSION_X (float)16000
1049d7b1866SSean O'Brien #define TRACKPAD2_MIN_X -3678
1059d7b1866SSean O'Brien #define TRACKPAD2_MAX_X 3934
1069d7b1866SSean O'Brien #define TRACKPAD2_RES_X \
1079d7b1866SSean O'Brien 	((TRACKPAD2_MAX_X - TRACKPAD2_MIN_X) / (TRACKPAD2_DIMENSION_X / 100))
1089d7b1866SSean O'Brien #define TRACKPAD2_DIMENSION_Y (float)11490
1099d7b1866SSean O'Brien #define TRACKPAD2_MIN_Y -2478
1109d7b1866SSean O'Brien #define TRACKPAD2_MAX_Y 2587
1119d7b1866SSean O'Brien #define TRACKPAD2_RES_Y \
1129d7b1866SSean O'Brien 	((TRACKPAD2_MAX_Y - TRACKPAD2_MIN_Y) / (TRACKPAD2_DIMENSION_Y / 100))
1139d7b1866SSean O'Brien 
114128537ceSMichael Poole /**
115128537ceSMichael Poole  * struct magicmouse_sc - Tracks Magic Mouse-specific data.
116128537ceSMichael Poole  * @input: Input device through which we report events.
117128537ceSMichael Poole  * @quirks: Currently unused.
118128537ceSMichael Poole  * @ntouches: Number of touches in most recent touch report.
119128537ceSMichael Poole  * @scroll_accel: Number of consecutive scroll motions.
120128537ceSMichael Poole  * @scroll_jiffies: Time of last scroll motion.
121128537ceSMichael Poole  * @touches: Most recent data for a touch, indexed by tracking ID.
122128537ceSMichael Poole  * @tracking_ids: Mapping of current touch input data to @touches.
123128537ceSMichael Poole  */
124128537ceSMichael Poole struct magicmouse_sc {
125128537ceSMichael Poole 	struct input_dev *input;
126128537ceSMichael Poole 	unsigned long quirks;
127128537ceSMichael Poole 
128128537ceSMichael Poole 	int ntouches;
129128537ceSMichael Poole 	int scroll_accel;
130128537ceSMichael Poole 	unsigned long scroll_jiffies;
131128537ceSMichael Poole 
132128537ceSMichael Poole 	struct {
133128537ceSMichael Poole 		short x;
134128537ceSMichael Poole 		short y;
135c0426688SChase Douglas 		short scroll_x;
136128537ceSMichael Poole 		short scroll_y;
137d4b9f10aSJosé Expósito 		short scroll_x_hr;
138d4b9f10aSJosé Expósito 		short scroll_y_hr;
139128537ceSMichael Poole 		u8 size;
1409d60648cSJosé Expósito 		bool scroll_x_active;
1419d60648cSJosé Expósito 		bool scroll_y_active;
142128537ceSMichael Poole 	} touches[16];
143128537ceSMichael Poole 	int tracking_ids[16];
144c0dc5582SJohn Chen 
145c0dc5582SJohn Chen 	struct hid_device *hdev;
146c0dc5582SJohn Chen 	struct delayed_work work;
1470b91b4e4SJosé Expósito 	struct timer_list battery_timer;
148128537ceSMichael Poole };
149128537ceSMichael Poole 
magicmouse_firm_touch(struct magicmouse_sc * msc)150128537ceSMichael Poole static int magicmouse_firm_touch(struct magicmouse_sc *msc)
151128537ceSMichael Poole {
152128537ceSMichael Poole 	int touch = -1;
153128537ceSMichael Poole 	int ii;
154128537ceSMichael Poole 
155128537ceSMichael Poole 	/* If there is only one "firm" touch, set touch to its
156128537ceSMichael Poole 	 * tracking ID.
157128537ceSMichael Poole 	 */
158128537ceSMichael Poole 	for (ii = 0; ii < msc->ntouches; ii++) {
159128537ceSMichael Poole 		int idx = msc->tracking_ids[ii];
160128537ceSMichael Poole 		if (msc->touches[idx].size < 8) {
161128537ceSMichael Poole 			/* Ignore this touch. */
162128537ceSMichael Poole 		} else if (touch >= 0) {
163128537ceSMichael Poole 			touch = -1;
164128537ceSMichael Poole 			break;
165128537ceSMichael Poole 		} else {
166128537ceSMichael Poole 			touch = idx;
167128537ceSMichael Poole 		}
168128537ceSMichael Poole 	}
169128537ceSMichael Poole 
170128537ceSMichael Poole 	return touch;
171128537ceSMichael Poole }
172128537ceSMichael Poole 
magicmouse_emit_buttons(struct magicmouse_sc * msc,int state)173128537ceSMichael Poole static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state)
174128537ceSMichael Poole {
175128537ceSMichael Poole 	int last_state = test_bit(BTN_LEFT, msc->input->key) << 0 |
176128537ceSMichael Poole 		test_bit(BTN_RIGHT, msc->input->key) << 1 |
177128537ceSMichael Poole 		test_bit(BTN_MIDDLE, msc->input->key) << 2;
178128537ceSMichael Poole 
179128537ceSMichael Poole 	if (emulate_3button) {
180128537ceSMichael Poole 		int id;
181128537ceSMichael Poole 
182128537ceSMichael Poole 		/* If some button was pressed before, keep it held
183128537ceSMichael Poole 		 * down.  Otherwise, if there's exactly one firm
184128537ceSMichael Poole 		 * touch, use that to override the mouse's guess.
185128537ceSMichael Poole 		 */
186128537ceSMichael Poole 		if (state == 0) {
187128537ceSMichael Poole 			/* The button was released. */
188128537ceSMichael Poole 		} else if (last_state != 0) {
189128537ceSMichael Poole 			state = last_state;
190128537ceSMichael Poole 		} else if ((id = magicmouse_firm_touch(msc)) >= 0) {
191128537ceSMichael Poole 			int x = msc->touches[id].x;
192128537ceSMichael Poole 			if (x < middle_button_start)
193128537ceSMichael Poole 				state = 1;
194128537ceSMichael Poole 			else if (x > middle_button_stop)
195128537ceSMichael Poole 				state = 2;
196128537ceSMichael Poole 			else
197128537ceSMichael Poole 				state = 4;
198128537ceSMichael Poole 		} /* else: we keep the mouse's guess */
199128537ceSMichael Poole 
200128537ceSMichael Poole 		input_report_key(msc->input, BTN_MIDDLE, state & 4);
201128537ceSMichael Poole 	}
202128537ceSMichael Poole 
203128537ceSMichael Poole 	input_report_key(msc->input, BTN_LEFT, state & 1);
204128537ceSMichael Poole 	input_report_key(msc->input, BTN_RIGHT, state & 2);
205128537ceSMichael Poole 
206128537ceSMichael Poole 	if (state != last_state)
2070b778e76SChase Douglas 		msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
208128537ceSMichael Poole }
209128537ceSMichael Poole 
magicmouse_emit_touch(struct magicmouse_sc * msc,int raw_id,u8 * tdata)210128537ceSMichael Poole static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata)
211128537ceSMichael Poole {
212128537ceSMichael Poole 	struct input_dev *input = msc->input;
213a462230eSChase Douglas 	int id, x, y, size, orientation, touch_major, touch_minor, state, down;
2149d7b1866SSean O'Brien 	int pressure = 0;
215a462230eSChase Douglas 
2162b0c086cSJohn Chen 	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
2172b0c086cSJohn Chen 	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
218a462230eSChase Douglas 		id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf;
219a462230eSChase Douglas 		x = (tdata[1] << 28 | tdata[0] << 20) >> 20;
220a462230eSChase Douglas 		y = -((tdata[2] << 24 | tdata[1] << 16) >> 20);
221a462230eSChase Douglas 		size = tdata[5] & 0x3f;
222a462230eSChase Douglas 		orientation = (tdata[6] >> 2) - 32;
223a462230eSChase Douglas 		touch_major = tdata[3];
224a462230eSChase Douglas 		touch_minor = tdata[4];
225a462230eSChase Douglas 		state = tdata[7] & TOUCH_STATE_MASK;
226a462230eSChase Douglas 		down = state != TOUCH_STATE_NONE;
227*6e8348ecSCallahan Kovacs 	} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
228*6e8348ecSCallahan Kovacs 		   input->id.product ==
229*6e8348ecSCallahan Kovacs 			   USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
2309d7b1866SSean O'Brien 		id = tdata[8] & 0xf;
2319d7b1866SSean O'Brien 		x = (tdata[1] << 27 | tdata[0] << 19) >> 19;
2329d7b1866SSean O'Brien 		y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19);
2339d7b1866SSean O'Brien 		size = tdata[6];
2349d7b1866SSean O'Brien 		orientation = (tdata[8] >> 5) - 4;
2359d7b1866SSean O'Brien 		touch_major = tdata[4];
2369d7b1866SSean O'Brien 		touch_minor = tdata[5];
2379d7b1866SSean O'Brien 		pressure = tdata[7];
2389d7b1866SSean O'Brien 		state = tdata[3] & 0xC0;
2399d7b1866SSean O'Brien 		down = state == 0x80;
240a462230eSChase Douglas 	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
241a462230eSChase Douglas 		id = (tdata[7] << 2 | tdata[6] >> 6) & 0xf;
242a462230eSChase Douglas 		x = (tdata[1] << 27 | tdata[0] << 19) >> 19;
243a462230eSChase Douglas 		y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19);
244a462230eSChase Douglas 		size = tdata[6] & 0x3f;
245a462230eSChase Douglas 		orientation = (tdata[7] >> 2) - 32;
246a462230eSChase Douglas 		touch_major = tdata[4];
247a462230eSChase Douglas 		touch_minor = tdata[5];
248a462230eSChase Douglas 		state = tdata[8] & TOUCH_STATE_MASK;
249a462230eSChase Douglas 		down = state != TOUCH_STATE_NONE;
250a462230eSChase Douglas 	}
251128537ceSMichael Poole 
252128537ceSMichael Poole 	/* Store tracking ID and other fields. */
253128537ceSMichael Poole 	msc->tracking_ids[raw_id] = id;
254128537ceSMichael Poole 	msc->touches[id].x = x;
255128537ceSMichael Poole 	msc->touches[id].y = y;
2566de048bfSChase Douglas 	msc->touches[id].size = size;
257128537ceSMichael Poole 
258128537ceSMichael Poole 	/* If requested, emulate a scroll wheel by detecting small
259ef566d30SChase Douglas 	 * vertical touch motions.
260128537ceSMichael Poole 	 */
261*6e8348ecSCallahan Kovacs 	if (emulate_scroll_wheel &&
262*6e8348ecSCallahan Kovacs 	    input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
263*6e8348ecSCallahan Kovacs 	    input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
264128537ceSMichael Poole 		unsigned long now = jiffies;
265c0426688SChase Douglas 		int step_x = msc->touches[id].scroll_x - x;
266c0426688SChase Douglas 		int step_y = msc->touches[id].scroll_y - y;
267a1091118SClaudia Pellegrino 		int step_hr =
268a1091118SClaudia Pellegrino 			max_t(int,
269a1091118SClaudia Pellegrino 			      ((64 - (int)scroll_speed) * msc->scroll_accel) /
270a1091118SClaudia Pellegrino 					SCROLL_HR_STEPS,
271a1091118SClaudia Pellegrino 			      1);
272d4b9f10aSJosé Expósito 		int step_x_hr = msc->touches[id].scroll_x_hr - x;
273d4b9f10aSJosé Expósito 		int step_y_hr = msc->touches[id].scroll_y_hr - y;
274128537ceSMichael Poole 
275128537ceSMichael Poole 		/* Calculate and apply the scroll motion. */
2766de048bfSChase Douglas 		switch (state) {
277128537ceSMichael Poole 		case TOUCH_STATE_START:
278c0426688SChase Douglas 			msc->touches[id].scroll_x = x;
279128537ceSMichael Poole 			msc->touches[id].scroll_y = y;
280d4b9f10aSJosé Expósito 			msc->touches[id].scroll_x_hr = x;
281d4b9f10aSJosé Expósito 			msc->touches[id].scroll_y_hr = y;
2829d60648cSJosé Expósito 			msc->touches[id].scroll_x_active = false;
2839d60648cSJosé Expósito 			msc->touches[id].scroll_y_active = false;
2840b778e76SChase Douglas 
2850b778e76SChase Douglas 			/* Reset acceleration after half a second. */
2860b778e76SChase Douglas 			if (scroll_acceleration && time_before(now,
2870b778e76SChase Douglas 						msc->scroll_jiffies + HZ / 2))
2880b778e76SChase Douglas 				msc->scroll_accel = max_t(int,
2890b778e76SChase Douglas 						msc->scroll_accel - 1, 1);
2900b778e76SChase Douglas 			else
2910b778e76SChase Douglas 				msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
2920b778e76SChase Douglas 
293128537ceSMichael Poole 			break;
294128537ceSMichael Poole 		case TOUCH_STATE_DRAG:
295c0426688SChase Douglas 			step_x /= (64 - (int)scroll_speed) * msc->scroll_accel;
296c0426688SChase Douglas 			if (step_x != 0) {
297c0426688SChase Douglas 				msc->touches[id].scroll_x -= step_x *
2980b778e76SChase Douglas 					(64 - scroll_speed) * msc->scroll_accel;
299128537ceSMichael Poole 				msc->scroll_jiffies = now;
300c0426688SChase Douglas 				input_report_rel(input, REL_HWHEEL, -step_x);
301c0426688SChase Douglas 			}
302c0426688SChase Douglas 
303c0426688SChase Douglas 			step_y /= (64 - (int)scroll_speed) * msc->scroll_accel;
304c0426688SChase Douglas 			if (step_y != 0) {
305c0426688SChase Douglas 				msc->touches[id].scroll_y -= step_y *
306c0426688SChase Douglas 					(64 - scroll_speed) * msc->scroll_accel;
307c0426688SChase Douglas 				msc->scroll_jiffies = now;
308c0426688SChase Douglas 				input_report_rel(input, REL_WHEEL, step_y);
309128537ceSMichael Poole 			}
310d4b9f10aSJosé Expósito 
3119d60648cSJosé Expósito 			if (!msc->touches[id].scroll_x_active &&
3129d60648cSJosé Expósito 			    abs(step_x_hr) > SCROLL_HR_THRESHOLD) {
3139d60648cSJosé Expósito 				msc->touches[id].scroll_x_active = true;
3149d60648cSJosé Expósito 				msc->touches[id].scroll_x_hr = x;
3159d60648cSJosé Expósito 				step_x_hr = 0;
3169d60648cSJosé Expósito 			}
3179d60648cSJosé Expósito 
318d4b9f10aSJosé Expósito 			step_x_hr /= step_hr;
3199d60648cSJosé Expósito 			if (step_x_hr != 0 &&
3209d60648cSJosé Expósito 			    msc->touches[id].scroll_x_active) {
321d4b9f10aSJosé Expósito 				msc->touches[id].scroll_x_hr -= step_x_hr *
322d4b9f10aSJosé Expósito 					step_hr;
323d4b9f10aSJosé Expósito 				input_report_rel(input,
324d4b9f10aSJosé Expósito 						 REL_HWHEEL_HI_RES,
325d4b9f10aSJosé Expósito 						 -step_x_hr * SCROLL_HR_MULT);
326d4b9f10aSJosé Expósito 			}
327d4b9f10aSJosé Expósito 
3289d60648cSJosé Expósito 			if (!msc->touches[id].scroll_y_active &&
3299d60648cSJosé Expósito 			    abs(step_y_hr) > SCROLL_HR_THRESHOLD) {
3309d60648cSJosé Expósito 				msc->touches[id].scroll_y_active = true;
3319d60648cSJosé Expósito 				msc->touches[id].scroll_y_hr = y;
3329d60648cSJosé Expósito 				step_y_hr = 0;
3339d60648cSJosé Expósito 			}
3349d60648cSJosé Expósito 
335d4b9f10aSJosé Expósito 			step_y_hr /= step_hr;
3369d60648cSJosé Expósito 			if (step_y_hr != 0 &&
3379d60648cSJosé Expósito 			    msc->touches[id].scroll_y_active) {
338d4b9f10aSJosé Expósito 				msc->touches[id].scroll_y_hr -= step_y_hr *
339d4b9f10aSJosé Expósito 					step_hr;
340d4b9f10aSJosé Expósito 				input_report_rel(input,
341d4b9f10aSJosé Expósito 						 REL_WHEEL_HI_RES,
342d4b9f10aSJosé Expósito 						 step_y_hr * SCROLL_HR_MULT);
343d4b9f10aSJosé Expósito 			}
344128537ceSMichael Poole 			break;
345128537ceSMichael Poole 		}
346128537ceSMichael Poole 	}
347128537ceSMichael Poole 
348a6d1bc1dSYufeng Shen 	if (down)
349a462230eSChase Douglas 		msc->ntouches++;
350a6d1bc1dSYufeng Shen 
351a6d1bc1dSYufeng Shen 	input_mt_slot(input, id);
352a6d1bc1dSYufeng Shen 	input_mt_report_slot_state(input, MT_TOOL_FINGER, down);
353a462230eSChase Douglas 
354128537ceSMichael Poole 	/* Generate the input events for this touch. */
3556264307eSYufeng Shen 	if (down) {
356921990b7SHenrik Rydberg 		input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2);
357921990b7SHenrik Rydberg 		input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2);
3582d9ca4e9SHenrik Rydberg 		input_report_abs(input, ABS_MT_ORIENTATION, -orientation);
359128537ceSMichael Poole 		input_report_abs(input, ABS_MT_POSITION_X, x);
360128537ceSMichael Poole 		input_report_abs(input, ABS_MT_POSITION_Y, y);
361128537ceSMichael Poole 
362*6e8348ecSCallahan Kovacs 		if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
363*6e8348ecSCallahan Kovacs 		    input->id.product ==
364*6e8348ecSCallahan Kovacs 			    USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC)
3659d7b1866SSean O'Brien 			input_report_abs(input, ABS_MT_PRESSURE, pressure);
3669d7b1866SSean O'Brien 
367a462230eSChase Douglas 		if (report_undeciphered) {
3682b0c086cSJohn Chen 			if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
3692b0c086cSJohn Chen 			    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
370128537ceSMichael Poole 				input_event(input, EV_MSC, MSC_RAW, tdata[7]);
3719d7b1866SSean O'Brien 			else if (input->id.product !=
372*6e8348ecSCallahan Kovacs 					 USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
373*6e8348ecSCallahan Kovacs 				 input->id.product !=
374*6e8348ecSCallahan Kovacs 					 USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC)
375a462230eSChase Douglas 				input_event(input, EV_MSC, MSC_RAW, tdata[8]);
376a462230eSChase Douglas 		}
377128537ceSMichael Poole 	}
378128537ceSMichael Poole }
379128537ceSMichael Poole 
magicmouse_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)380128537ceSMichael Poole static int magicmouse_raw_event(struct hid_device *hdev,
381128537ceSMichael Poole 		struct hid_report *report, u8 *data, int size)
382128537ceSMichael Poole {
383128537ceSMichael Poole 	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
384128537ceSMichael Poole 	struct input_dev *input = msc->input;
385a462230eSChase Douglas 	int x = 0, y = 0, ii, clicks = 0, npoints;
386128537ceSMichael Poole 
387128537ceSMichael Poole 	switch (data[0]) {
388a462230eSChase Douglas 	case TRACKPAD_REPORT_ID:
3899d7b1866SSean O'Brien 	case TRACKPAD2_BT_REPORT_ID:
390a462230eSChase Douglas 		/* Expect four bytes of prefix, and N*9 bytes of touch data. */
391a462230eSChase Douglas 		if (size < 4 || ((size - 4) % 9) != 0)
392a462230eSChase Douglas 			return 0;
393a462230eSChase Douglas 		npoints = (size - 4) / 9;
394c54def7bSJiri Kosina 		if (npoints > 15) {
395c54def7bSJiri Kosina 			hid_warn(hdev, "invalid size value (%d) for TRACKPAD_REPORT_ID\n",
396c54def7bSJiri Kosina 					size);
397c54def7bSJiri Kosina 			return 0;
398c54def7bSJiri Kosina 		}
399a462230eSChase Douglas 		msc->ntouches = 0;
400a462230eSChase Douglas 		for (ii = 0; ii < npoints; ii++)
401a462230eSChase Douglas 			magicmouse_emit_touch(msc, ii, data + ii * 9 + 4);
402a462230eSChase Douglas 
403a462230eSChase Douglas 		clicks = data[1];
404a462230eSChase Douglas 
405a462230eSChase Douglas 		/* The following bits provide a device specific timestamp. They
406a462230eSChase Douglas 		 * are unused here.
407a462230eSChase Douglas 		 *
408a462230eSChase Douglas 		 * ts = data[1] >> 6 | data[2] << 2 | data[3] << 10;
409a462230eSChase Douglas 		 */
410a462230eSChase Douglas 		break;
4119d7b1866SSean O'Brien 	case TRACKPAD2_USB_REPORT_ID:
4129d7b1866SSean O'Brien 		/* Expect twelve bytes of prefix and N*9 bytes of touch data. */
4139d7b1866SSean O'Brien 		if (size < 12 || ((size - 12) % 9) != 0)
4149d7b1866SSean O'Brien 			return 0;
4159d7b1866SSean O'Brien 		npoints = (size - 12) / 9;
4169d7b1866SSean O'Brien 		if (npoints > 15) {
4179d7b1866SSean O'Brien 			hid_warn(hdev, "invalid size value (%d) for TRACKPAD2_USB_REPORT_ID\n",
4189d7b1866SSean O'Brien 					size);
4199d7b1866SSean O'Brien 			return 0;
4209d7b1866SSean O'Brien 		}
4219d7b1866SSean O'Brien 		msc->ntouches = 0;
4229d7b1866SSean O'Brien 		for (ii = 0; ii < npoints; ii++)
4239d7b1866SSean O'Brien 			magicmouse_emit_touch(msc, ii, data + ii * 9 + 12);
4249d7b1866SSean O'Brien 
4259d7b1866SSean O'Brien 		clicks = data[1];
4269d7b1866SSean O'Brien 		break;
427a462230eSChase Douglas 	case MOUSE_REPORT_ID:
428128537ceSMichael Poole 		/* Expect six bytes of prefix, and N*8 bytes of touch data. */
429128537ceSMichael Poole 		if (size < 6 || ((size - 6) % 8) != 0)
430128537ceSMichael Poole 			return 0;
4310228db70SChase Douglas 		npoints = (size - 6) / 8;
432c54def7bSJiri Kosina 		if (npoints > 15) {
433c54def7bSJiri Kosina 			hid_warn(hdev, "invalid size value (%d) for MOUSE_REPORT_ID\n",
434c54def7bSJiri Kosina 					size);
435c54def7bSJiri Kosina 			return 0;
436c54def7bSJiri Kosina 		}
4370228db70SChase Douglas 		msc->ntouches = 0;
4380228db70SChase Douglas 		for (ii = 0; ii < npoints; ii++)
439128537ceSMichael Poole 			magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
440e3612e86SChase Douglas 
441128537ceSMichael Poole 		/* When emulating three-button mode, it is important
442128537ceSMichael Poole 		 * to have the current touch information before
443128537ceSMichael Poole 		 * generating a click event.
444128537ceSMichael Poole 		 */
4457d876c05SMichael Poole 		x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22;
4467d876c05SMichael Poole 		y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22;
447128537ceSMichael Poole 		clicks = data[3];
448c61b7ceeSChase Douglas 
449c61b7ceeSChase Douglas 		/* The following bits provide a device specific timestamp. They
450c61b7ceeSChase Douglas 		 * are unused here.
451c61b7ceeSChase Douglas 		 *
452c61b7ceeSChase Douglas 		 * ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
453c61b7ceeSChase Douglas 		 */
454128537ceSMichael Poole 		break;
4552b0c086cSJohn Chen 	case MOUSE2_REPORT_ID:
4562b0c086cSJohn Chen 		/* Size is either 8 or (14 + 8 * N) */
4572b0c086cSJohn Chen 		if (size != 8 && (size < 14 || (size - 14) % 8 != 0))
4582b0c086cSJohn Chen 			return 0;
4592b0c086cSJohn Chen 		npoints = (size - 14) / 8;
4602b0c086cSJohn Chen 		if (npoints > 15) {
4612b0c086cSJohn Chen 			hid_warn(hdev, "invalid size value (%d) for MOUSE2_REPORT_ID\n",
4622b0c086cSJohn Chen 					size);
4632b0c086cSJohn Chen 			return 0;
4642b0c086cSJohn Chen 		}
4652b0c086cSJohn Chen 		msc->ntouches = 0;
4662b0c086cSJohn Chen 		for (ii = 0; ii < npoints; ii++)
4672b0c086cSJohn Chen 			magicmouse_emit_touch(msc, ii, data + ii * 8 + 14);
4682b0c086cSJohn Chen 
4692b0c086cSJohn Chen 		/* When emulating three-button mode, it is important
4702b0c086cSJohn Chen 		 * to have the current touch information before
4712b0c086cSJohn Chen 		 * generating a click event.
4722b0c086cSJohn Chen 		 */
4732b0c086cSJohn Chen 		x = (int)((data[3] << 24) | (data[2] << 16)) >> 16;
4742b0c086cSJohn Chen 		y = (int)((data[5] << 24) | (data[4] << 16)) >> 16;
4752b0c086cSJohn Chen 		clicks = data[1];
4762b0c086cSJohn Chen 
4772b0c086cSJohn Chen 		/* The following bits provide a device specific timestamp. They
4782b0c086cSJohn Chen 		 * are unused here.
4792b0c086cSJohn Chen 		 *
4802b0c086cSJohn Chen 		 * ts = data[11] >> 6 | data[12] << 2 | data[13] << 10;
4812b0c086cSJohn Chen 		 */
4822b0c086cSJohn Chen 		break;
483a462230eSChase Douglas 	case DOUBLE_REPORT_ID:
484a462230eSChase Douglas 		/* Sometimes the trackpad sends two touch reports in one
485a462230eSChase Douglas 		 * packet.
486a462230eSChase Douglas 		 */
487a462230eSChase Douglas 		magicmouse_raw_event(hdev, report, data + 2, data[1]);
488a462230eSChase Douglas 		magicmouse_raw_event(hdev, report, data + 2 + data[1],
489a462230eSChase Douglas 			size - 2 - data[1]);
490bb5f0c85SJosé Expósito 		return 0;
491128537ceSMichael Poole 	default:
492128537ceSMichael Poole 		return 0;
493128537ceSMichael Poole 	}
494128537ceSMichael Poole 
4952b0c086cSJohn Chen 	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
4962b0c086cSJohn Chen 	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
497128537ceSMichael Poole 		magicmouse_emit_buttons(msc, clicks & 3);
498128537ceSMichael Poole 		input_report_rel(input, REL_X, x);
499128537ceSMichael Poole 		input_report_rel(input, REL_Y, y);
500*6e8348ecSCallahan Kovacs 	} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
501*6e8348ecSCallahan Kovacs 		   input->id.product ==
502*6e8348ecSCallahan Kovacs 			   USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
5039d7b1866SSean O'Brien 		input_mt_sync_frame(input);
5049d7b1866SSean O'Brien 		input_report_key(input, BTN_MOUSE, clicks & 1);
505a462230eSChase Douglas 	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
506a462230eSChase Douglas 		input_report_key(input, BTN_MOUSE, clicks & 1);
507a6d1bc1dSYufeng Shen 		input_mt_report_pointer_emulation(input, true);
508a462230eSChase Douglas 	}
509a462230eSChase Douglas 
510128537ceSMichael Poole 	input_sync(input);
511128537ceSMichael Poole 	return 1;
512128537ceSMichael Poole }
513128537ceSMichael Poole 
magicmouse_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)5143dcc5f7bSJohn Chen static int magicmouse_event(struct hid_device *hdev, struct hid_field *field,
5153dcc5f7bSJohn Chen 		struct hid_usage *usage, __s32 value)
5163dcc5f7bSJohn Chen {
5173dcc5f7bSJohn Chen 	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
5183dcc5f7bSJohn Chen 	if (msc->input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
5193dcc5f7bSJohn Chen 	    field->report->id == MOUSE2_REPORT_ID) {
5203dcc5f7bSJohn Chen 		/*
5213dcc5f7bSJohn Chen 		 * magic_mouse_raw_event has done all the work. Skip hidinput.
5223dcc5f7bSJohn Chen 		 *
5233dcc5f7bSJohn Chen 		 * Specifically, hidinput may modify BTN_LEFT and BTN_RIGHT,
5243dcc5f7bSJohn Chen 		 * breaking emulate_3button.
5253dcc5f7bSJohn Chen 		 */
5263dcc5f7bSJohn Chen 		return 1;
5273dcc5f7bSJohn Chen 	}
5283dcc5f7bSJohn Chen 	return 0;
5293dcc5f7bSJohn Chen }
5303dcc5f7bSJohn Chen 
magicmouse_setup_input(struct input_dev * input,struct hid_device * hdev)531a6d1bc1dSYufeng Shen static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
532128537ceSMichael Poole {
533a6d1bc1dSYufeng Shen 	int error;
5349d7b1866SSean O'Brien 	int mt_flags = 0;
535a6d1bc1dSYufeng Shen 
53671b38bd4SMichael Poole 	__set_bit(EV_KEY, input->evbit);
537a462230eSChase Douglas 
5382b0c086cSJohn Chen 	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
5392b0c086cSJohn Chen 	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
54071b38bd4SMichael Poole 		__set_bit(BTN_LEFT, input->keybit);
54171b38bd4SMichael Poole 		__set_bit(BTN_RIGHT, input->keybit);
542128537ceSMichael Poole 		if (emulate_3button)
54371b38bd4SMichael Poole 			__set_bit(BTN_MIDDLE, input->keybit);
544128537ceSMichael Poole 
54571b38bd4SMichael Poole 		__set_bit(EV_REL, input->evbit);
54671b38bd4SMichael Poole 		__set_bit(REL_X, input->relbit);
54771b38bd4SMichael Poole 		__set_bit(REL_Y, input->relbit);
548c0426688SChase Douglas 		if (emulate_scroll_wheel) {
54971b38bd4SMichael Poole 			__set_bit(REL_WHEEL, input->relbit);
550c0426688SChase Douglas 			__set_bit(REL_HWHEEL, input->relbit);
551d4b9f10aSJosé Expósito 			__set_bit(REL_WHEEL_HI_RES, input->relbit);
552d4b9f10aSJosé Expósito 			__set_bit(REL_HWHEEL_HI_RES, input->relbit);
553c0426688SChase Douglas 		}
554*6e8348ecSCallahan Kovacs 	} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
555*6e8348ecSCallahan Kovacs 		   input->id.product ==
556*6e8348ecSCallahan Kovacs 			   USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
5570aa45fccSJosé Expósito 		/* If the trackpad has been connected to a Mac, the name is
5580aa45fccSJosé Expósito 		 * automatically personalized, e.g., "José Expósito's Trackpad".
5590aa45fccSJosé Expósito 		 * When connected through Bluetooth, the personalized name is
5600aa45fccSJosé Expósito 		 * reported, however, when connected through USB the generic
5610aa45fccSJosé Expósito 		 * name is reported.
5620aa45fccSJosé Expósito 		 * Set the device name to ensure the same driver settings get
5630aa45fccSJosé Expósito 		 * loaded, whether connected through bluetooth or USB.
5649d7b1866SSean O'Brien 		 */
5655768701eSJosé Expósito 		if (hdev->vendor == BT_VENDOR_ID_APPLE) {
5665768701eSJosé Expósito 			if (input->id.version == TRACKPAD2_2021_BT_VERSION)
5675768701eSJosé Expósito 				input->name = "Apple Inc. Magic Trackpad";
5685768701eSJosé Expósito 			else
5699d7b1866SSean O'Brien 				input->name = "Apple Inc. Magic Trackpad 2";
5705768701eSJosé Expósito 		} else { /* USB_VENDOR_ID_APPLE */
5710aa45fccSJosé Expósito 			input->name = hdev->name;
5725768701eSJosé Expósito 		}
5739d7b1866SSean O'Brien 
5749d7b1866SSean O'Brien 		__clear_bit(EV_MSC, input->evbit);
5759d7b1866SSean O'Brien 		__clear_bit(BTN_0, input->keybit);
5769d7b1866SSean O'Brien 		__clear_bit(BTN_RIGHT, input->keybit);
5779d7b1866SSean O'Brien 		__clear_bit(BTN_MIDDLE, input->keybit);
5789d7b1866SSean O'Brien 		__set_bit(BTN_MOUSE, input->keybit);
5799d7b1866SSean O'Brien 		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
5809d7b1866SSean O'Brien 		__set_bit(BTN_TOOL_FINGER, input->keybit);
5819d7b1866SSean O'Brien 
5829d7b1866SSean O'Brien 		mt_flags = INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
5839d7b1866SSean O'Brien 				INPUT_MT_TRACK;
584a462230eSChase Douglas 	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
585bca62142SDaniel van Vugt 		/* input->keybit is initialized with incorrect button info
586bca62142SDaniel van Vugt 		 * for Magic Trackpad. There really is only one physical
587bca62142SDaniel van Vugt 		 * button (BTN_LEFT == BTN_MOUSE). Make sure we don't
588bca62142SDaniel van Vugt 		 * advertise buttons that don't exist...
589bca62142SDaniel van Vugt 		 */
590bca62142SDaniel van Vugt 		__clear_bit(BTN_RIGHT, input->keybit);
591bca62142SDaniel van Vugt 		__clear_bit(BTN_MIDDLE, input->keybit);
592a462230eSChase Douglas 		__set_bit(BTN_MOUSE, input->keybit);
593a462230eSChase Douglas 		__set_bit(BTN_TOOL_FINGER, input->keybit);
594a462230eSChase Douglas 		__set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
595a462230eSChase Douglas 		__set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
596a462230eSChase Douglas 		__set_bit(BTN_TOOL_QUADTAP, input->keybit);
597a6d1bc1dSYufeng Shen 		__set_bit(BTN_TOOL_QUINTTAP, input->keybit);
598a462230eSChase Douglas 		__set_bit(BTN_TOUCH, input->keybit);
599503f7d53SChase Douglas 		__set_bit(INPUT_PROP_POINTER, input->propbit);
60053145c2eSDaniel Stone 		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
60153145c2eSDaniel Stone 	}
60253145c2eSDaniel Stone 
6036264307eSYufeng Shen 
60471b38bd4SMichael Poole 	__set_bit(EV_ABS, input->evbit);
605128537ceSMichael Poole 
6069d7b1866SSean O'Brien 	error = input_mt_init_slots(input, 16, mt_flags);
607a6d1bc1dSYufeng Shen 	if (error)
608a6d1bc1dSYufeng Shen 		return error;
609e75561b3SYufeng Shen 	input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2,
610e75561b3SYufeng Shen 			     4, 0);
611e75561b3SYufeng Shen 	input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255 << 2,
612e75561b3SYufeng Shen 			     4, 0);
613a462230eSChase Douglas 
614128537ceSMichael Poole 	/* Note: Touch Y position from the device is inverted relative
615128537ceSMichael Poole 	 * to how pointer motion is reported (and relative to how USB
616128537ceSMichael Poole 	 * HID recommends the coordinates work).  This driver keeps
617128537ceSMichael Poole 	 * the origin at the same position, and just uses the additive
618128537ceSMichael Poole 	 * inverse of the reported Y.
619128537ceSMichael Poole 	 */
6202b0c086cSJohn Chen 	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
6212b0c086cSJohn Chen 	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
6229d7b1866SSean O'Brien 		input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
6234f6fdf08SChase Douglas 		input_set_abs_params(input, ABS_MT_POSITION_X,
6244f6fdf08SChase Douglas 				     MOUSE_MIN_X, MOUSE_MAX_X, 4, 0);
6254f6fdf08SChase Douglas 		input_set_abs_params(input, ABS_MT_POSITION_Y,
6264f6fdf08SChase Douglas 				     MOUSE_MIN_Y, MOUSE_MAX_Y, 4, 0);
6274f6fdf08SChase Douglas 
6284f6fdf08SChase Douglas 		input_abs_set_res(input, ABS_MT_POSITION_X,
6294f6fdf08SChase Douglas 				  MOUSE_RES_X);
6304f6fdf08SChase Douglas 		input_abs_set_res(input, ABS_MT_POSITION_Y,
6314f6fdf08SChase Douglas 				  MOUSE_RES_Y);
632*6e8348ecSCallahan Kovacs 	} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
633*6e8348ecSCallahan Kovacs 		   input->id.product ==
634*6e8348ecSCallahan Kovacs 			   USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
6359d7b1866SSean O'Brien 		input_set_abs_params(input, ABS_MT_PRESSURE, 0, 253, 0, 0);
6369d7b1866SSean O'Brien 		input_set_abs_params(input, ABS_PRESSURE, 0, 253, 0, 0);
6379d7b1866SSean O'Brien 		input_set_abs_params(input, ABS_MT_ORIENTATION, -3, 4, 0, 0);
6389d7b1866SSean O'Brien 		input_set_abs_params(input, ABS_X, TRACKPAD2_MIN_X,
6399d7b1866SSean O'Brien 				     TRACKPAD2_MAX_X, 0, 0);
6409d7b1866SSean O'Brien 		input_set_abs_params(input, ABS_Y, TRACKPAD2_MIN_Y,
6419d7b1866SSean O'Brien 				     TRACKPAD2_MAX_Y, 0, 0);
6429d7b1866SSean O'Brien 		input_set_abs_params(input, ABS_MT_POSITION_X,
6439d7b1866SSean O'Brien 				     TRACKPAD2_MIN_X, TRACKPAD2_MAX_X, 0, 0);
6449d7b1866SSean O'Brien 		input_set_abs_params(input, ABS_MT_POSITION_Y,
6459d7b1866SSean O'Brien 				     TRACKPAD2_MIN_Y, TRACKPAD2_MAX_Y, 0, 0);
6469d7b1866SSean O'Brien 
6479d7b1866SSean O'Brien 		input_abs_set_res(input, ABS_X, TRACKPAD2_RES_X);
6489d7b1866SSean O'Brien 		input_abs_set_res(input, ABS_Y, TRACKPAD2_RES_Y);
6499d7b1866SSean O'Brien 		input_abs_set_res(input, ABS_MT_POSITION_X, TRACKPAD2_RES_X);
6509d7b1866SSean O'Brien 		input_abs_set_res(input, ABS_MT_POSITION_Y, TRACKPAD2_RES_Y);
651a462230eSChase Douglas 	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
6529d7b1866SSean O'Brien 		input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
6534f6fdf08SChase Douglas 		input_set_abs_params(input, ABS_X, TRACKPAD_MIN_X,
6544f6fdf08SChase Douglas 				     TRACKPAD_MAX_X, 4, 0);
6554f6fdf08SChase Douglas 		input_set_abs_params(input, ABS_Y, TRACKPAD_MIN_Y,
6564f6fdf08SChase Douglas 				     TRACKPAD_MAX_Y, 4, 0);
6574f6fdf08SChase Douglas 		input_set_abs_params(input, ABS_MT_POSITION_X,
6584f6fdf08SChase Douglas 				     TRACKPAD_MIN_X, TRACKPAD_MAX_X, 4, 0);
6594f6fdf08SChase Douglas 		input_set_abs_params(input, ABS_MT_POSITION_Y,
6604f6fdf08SChase Douglas 				     TRACKPAD_MIN_Y, TRACKPAD_MAX_Y, 4, 0);
6614f6fdf08SChase Douglas 
6624f6fdf08SChase Douglas 		input_abs_set_res(input, ABS_X, TRACKPAD_RES_X);
6634f6fdf08SChase Douglas 		input_abs_set_res(input, ABS_Y, TRACKPAD_RES_Y);
6644f6fdf08SChase Douglas 		input_abs_set_res(input, ABS_MT_POSITION_X,
6654f6fdf08SChase Douglas 				  TRACKPAD_RES_X);
6664f6fdf08SChase Douglas 		input_abs_set_res(input, ABS_MT_POSITION_Y,
6674f6fdf08SChase Douglas 				  TRACKPAD_RES_Y);
668a462230eSChase Douglas 	}
669cc5e0f08SChase Douglas 
670cc5e0f08SChase Douglas 	input_set_events_per_packet(input, 60);
671128537ceSMichael Poole 
6729d7b1866SSean O'Brien 	if (report_undeciphered &&
673*6e8348ecSCallahan Kovacs 	    input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
674*6e8348ecSCallahan Kovacs 	    input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
67571b38bd4SMichael Poole 		__set_bit(EV_MSC, input->evbit);
67671b38bd4SMichael Poole 		__set_bit(MSC_RAW, input->mscbit);
677128537ceSMichael Poole 	}
678a6d1bc1dSYufeng Shen 
6796363d206SDmitry Torokhov 	/*
6806363d206SDmitry Torokhov 	 * hid-input may mark device as using autorepeat, but neither
6816363d206SDmitry Torokhov 	 * the trackpad, nor the mouse actually want it.
6826363d206SDmitry Torokhov 	 */
6836363d206SDmitry Torokhov 	__clear_bit(EV_REP, input->evbit);
6846363d206SDmitry Torokhov 
685a6d1bc1dSYufeng Shen 	return 0;
686128537ceSMichael Poole }
687128537ceSMichael Poole 
magicmouse_input_mapping(struct hid_device * hdev,struct hid_input * hi,struct hid_field * field,struct hid_usage * usage,unsigned long ** bit,int * max)68864eb105dSMichael Poole static int magicmouse_input_mapping(struct hid_device *hdev,
68964eb105dSMichael Poole 		struct hid_input *hi, struct hid_field *field,
69064eb105dSMichael Poole 		struct hid_usage *usage, unsigned long **bit, int *max)
69164eb105dSMichael Poole {
69264eb105dSMichael Poole 	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
69364eb105dSMichael Poole 
69464eb105dSMichael Poole 	if (!msc->input)
69564eb105dSMichael Poole 		msc->input = hi->input;
69664eb105dSMichael Poole 
6976a66bbd6SChase Douglas 	/* Magic Trackpad does not give relative data after switching to MT */
6989d7b1866SSean O'Brien 	if ((hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD ||
699*6e8348ecSCallahan Kovacs 	     hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
700*6e8348ecSCallahan Kovacs 	     hi->input->id.product ==
701*6e8348ecSCallahan Kovacs 		     USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
7026a66bbd6SChase Douglas 	    field->flags & HID_MAIN_ITEM_RELATIVE)
7036a66bbd6SChase Douglas 		return -1;
7046a66bbd6SChase Douglas 
70564eb105dSMichael Poole 	return 0;
70664eb105dSMichael Poole }
70764eb105dSMichael Poole 
magicmouse_input_configured(struct hid_device * hdev,struct hid_input * hi)7089154301aSDmitry Torokhov static int magicmouse_input_configured(struct hid_device *hdev,
709f1a9a149SBenjamin Tissoires 		struct hid_input *hi)
710f1a9a149SBenjamin Tissoires 
711f1a9a149SBenjamin Tissoires {
712f1a9a149SBenjamin Tissoires 	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
7139154301aSDmitry Torokhov 	int ret;
714f1a9a149SBenjamin Tissoires 
7159154301aSDmitry Torokhov 	ret = magicmouse_setup_input(msc->input, hdev);
716f1a9a149SBenjamin Tissoires 	if (ret) {
717f1a9a149SBenjamin Tissoires 		hid_err(hdev, "magicmouse setup input failed (%d)\n", ret);
718f1a9a149SBenjamin Tissoires 		/* clean msc->input to notify probe() of the failure */
719f1a9a149SBenjamin Tissoires 		msc->input = NULL;
7209154301aSDmitry Torokhov 		return ret;
721f1a9a149SBenjamin Tissoires 	}
7229154301aSDmitry Torokhov 
7239154301aSDmitry Torokhov 	return 0;
724f1a9a149SBenjamin Tissoires }
725f1a9a149SBenjamin Tissoires 
magicmouse_enable_multitouch(struct hid_device * hdev)726c0dc5582SJohn Chen static int magicmouse_enable_multitouch(struct hid_device *hdev)
727128537ceSMichael Poole {
7289d7b1866SSean O'Brien 	const u8 *feature;
7299d7b1866SSean O'Brien 	const u8 feature_mt[] = { 0xD7, 0x01 };
7302b0c086cSJohn Chen 	const u8 feature_mt_mouse2[] = { 0xF1, 0x02, 0x01 };
7319d7b1866SSean O'Brien 	const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 };
7329d7b1866SSean O'Brien 	const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 };
733b7a87ad6SBenjamin Tissoires 	u8 *buf;
734c0dc5582SJohn Chen 	int ret;
735c0dc5582SJohn Chen 	int feature_size;
736c0dc5582SJohn Chen 
737*6e8348ecSCallahan Kovacs 	if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
738*6e8348ecSCallahan Kovacs 	    hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
739c0dc5582SJohn Chen 		if (hdev->vendor == BT_VENDOR_ID_APPLE) {
740c0dc5582SJohn Chen 			feature_size = sizeof(feature_mt_trackpad2_bt);
741c0dc5582SJohn Chen 			feature = feature_mt_trackpad2_bt;
742c0dc5582SJohn Chen 		} else { /* USB_VENDOR_ID_APPLE */
743c0dc5582SJohn Chen 			feature_size = sizeof(feature_mt_trackpad2_usb);
744c0dc5582SJohn Chen 			feature = feature_mt_trackpad2_usb;
745c0dc5582SJohn Chen 		}
746c0dc5582SJohn Chen 	} else if (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
747c0dc5582SJohn Chen 		feature_size = sizeof(feature_mt_mouse2);
748c0dc5582SJohn Chen 		feature = feature_mt_mouse2;
749c0dc5582SJohn Chen 	} else {
750c0dc5582SJohn Chen 		feature_size = sizeof(feature_mt);
751c0dc5582SJohn Chen 		feature = feature_mt;
752c0dc5582SJohn Chen 	}
753c0dc5582SJohn Chen 
754c0dc5582SJohn Chen 	buf = kmemdup(feature, feature_size, GFP_KERNEL);
755c0dc5582SJohn Chen 	if (!buf)
756c0dc5582SJohn Chen 		return -ENOMEM;
757c0dc5582SJohn Chen 
758c0dc5582SJohn Chen 	ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size,
759c0dc5582SJohn Chen 				HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
760c0dc5582SJohn Chen 	kfree(buf);
761c0dc5582SJohn Chen 	return ret;
762c0dc5582SJohn Chen }
763c0dc5582SJohn Chen 
magicmouse_enable_mt_work(struct work_struct * work)764c0dc5582SJohn Chen static void magicmouse_enable_mt_work(struct work_struct *work)
765c0dc5582SJohn Chen {
766c0dc5582SJohn Chen 	struct magicmouse_sc *msc =
767c0dc5582SJohn Chen 		container_of(work, struct magicmouse_sc, work.work);
768c0dc5582SJohn Chen 	int ret;
769c0dc5582SJohn Chen 
770c0dc5582SJohn Chen 	ret = magicmouse_enable_multitouch(msc->hdev);
771c0dc5582SJohn Chen 	if (ret < 0)
772c0dc5582SJohn Chen 		hid_err(msc->hdev, "unable to request touch data (%d)\n", ret);
773c0dc5582SJohn Chen }
774c0dc5582SJohn Chen 
magicmouse_fetch_battery(struct hid_device * hdev)7750b91b4e4SJosé Expósito static int magicmouse_fetch_battery(struct hid_device *hdev)
7760b91b4e4SJosé Expósito {
7770b91b4e4SJosé Expósito #ifdef CONFIG_HID_BATTERY_STRENGTH
7780b91b4e4SJosé Expósito 	struct hid_report_enum *report_enum;
7790b91b4e4SJosé Expósito 	struct hid_report *report;
7800b91b4e4SJosé Expósito 
7810b91b4e4SJosé Expósito 	if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE ||
7820b91b4e4SJosé Expósito 	    (hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
783*6e8348ecSCallahan Kovacs 	     hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
784*6e8348ecSCallahan Kovacs 	     hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC))
7850b91b4e4SJosé Expósito 		return -1;
7860b91b4e4SJosé Expósito 
7870b91b4e4SJosé Expósito 	report_enum = &hdev->report_enum[hdev->battery_report_type];
7880b91b4e4SJosé Expósito 	report = report_enum->report_id_hash[hdev->battery_report_id];
7890b91b4e4SJosé Expósito 
7900b91b4e4SJosé Expósito 	if (!report || report->maxfield < 1)
7910b91b4e4SJosé Expósito 		return -1;
7920b91b4e4SJosé Expósito 
7930b91b4e4SJosé Expósito 	if (hdev->battery_capacity == hdev->battery_max)
7940b91b4e4SJosé Expósito 		return -1;
7950b91b4e4SJosé Expósito 
7960b91b4e4SJosé Expósito 	hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
7970b91b4e4SJosé Expósito 	return 0;
7980b91b4e4SJosé Expósito #else
7990b91b4e4SJosé Expósito 	return -1;
8000b91b4e4SJosé Expósito #endif
8010b91b4e4SJosé Expósito }
8020b91b4e4SJosé Expósito 
magicmouse_battery_timer_tick(struct timer_list * t)8030b91b4e4SJosé Expósito static void magicmouse_battery_timer_tick(struct timer_list *t)
8040b91b4e4SJosé Expósito {
8050b91b4e4SJosé Expósito 	struct magicmouse_sc *msc = from_timer(msc, t, battery_timer);
8060b91b4e4SJosé Expósito 	struct hid_device *hdev = msc->hdev;
8070b91b4e4SJosé Expósito 
8080b91b4e4SJosé Expósito 	if (magicmouse_fetch_battery(hdev) == 0) {
8090b91b4e4SJosé Expósito 		mod_timer(&msc->battery_timer,
8100b91b4e4SJosé Expósito 			  jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS));
8110b91b4e4SJosé Expósito 	}
8120b91b4e4SJosé Expósito }
8130b91b4e4SJosé Expósito 
magicmouse_probe(struct hid_device * hdev,const struct hid_device_id * id)814c0dc5582SJohn Chen static int magicmouse_probe(struct hid_device *hdev,
815c0dc5582SJohn Chen 	const struct hid_device_id *id)
816c0dc5582SJohn Chen {
817128537ceSMichael Poole 	struct magicmouse_sc *msc;
818128537ceSMichael Poole 	struct hid_report *report;
819128537ceSMichael Poole 	int ret;
8209d7b1866SSean O'Brien 
821abf832bfSBenjamin Tissoires 	msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL);
822128537ceSMichael Poole 	if (msc == NULL) {
8234291ee30SJoe Perches 		hid_err(hdev, "can't alloc magicmouse descriptor\n");
824128537ceSMichael Poole 		return -ENOMEM;
825128537ceSMichael Poole 	}
826128537ceSMichael Poole 
8270b778e76SChase Douglas 	msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
828c0dc5582SJohn Chen 	msc->hdev = hdev;
829c0dc5582SJohn Chen 	INIT_DEFERRABLE_WORK(&msc->work, magicmouse_enable_mt_work);
8300b778e76SChase Douglas 
831128537ceSMichael Poole 	msc->quirks = id->driver_data;
832128537ceSMichael Poole 	hid_set_drvdata(hdev, msc);
833128537ceSMichael Poole 
834128537ceSMichael Poole 	ret = hid_parse(hdev);
835128537ceSMichael Poole 	if (ret) {
8364291ee30SJoe Perches 		hid_err(hdev, "magicmouse hid parse failed\n");
837abf832bfSBenjamin Tissoires 		return ret;
838128537ceSMichael Poole 	}
839128537ceSMichael Poole 
84023d02116SJiri Kosina 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
841128537ceSMichael Poole 	if (ret) {
8424291ee30SJoe Perches 		hid_err(hdev, "magicmouse hw start failed\n");
843abf832bfSBenjamin Tissoires 		return ret;
844128537ceSMichael Poole 	}
845128537ceSMichael Poole 
8460b91b4e4SJosé Expósito 	timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0);
8470b91b4e4SJosé Expósito 	mod_timer(&msc->battery_timer,
8480b91b4e4SJosé Expósito 		  jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS));
8490b91b4e4SJosé Expósito 	magicmouse_fetch_battery(hdev);
8500b91b4e4SJosé Expósito 
8510b91b4e4SJosé Expósito 	if (id->vendor == USB_VENDOR_ID_APPLE &&
8520b91b4e4SJosé Expósito 	    (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
853*6e8348ecSCallahan Kovacs 	     ((id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
854*6e8348ecSCallahan Kovacs 	       id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
855*6e8348ecSCallahan Kovacs 	      hdev->type != HID_TYPE_USBMOUSE)))
8560b91b4e4SJosé Expósito 		return 0;
8570b91b4e4SJosé Expósito 
858f1a9a149SBenjamin Tissoires 	if (!msc->input) {
859f1a9a149SBenjamin Tissoires 		hid_err(hdev, "magicmouse input not registered\n");
860f1a9a149SBenjamin Tissoires 		ret = -ENOMEM;
861a6d1bc1dSYufeng Shen 		goto err_stop_hw;
862a6d1bc1dSYufeng Shen 	}
86323d02116SJiri Kosina 
864a462230eSChase Douglas 	if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
865a462230eSChase Douglas 		report = hid_register_report(hdev, HID_INPUT_REPORT,
866f07b3c1dSBenjamin Tissoires 			MOUSE_REPORT_ID, 0);
8672b0c086cSJohn Chen 	else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
8682b0c086cSJohn Chen 		report = hid_register_report(hdev, HID_INPUT_REPORT,
8692b0c086cSJohn Chen 			MOUSE2_REPORT_ID, 0);
870*6e8348ecSCallahan Kovacs 	else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
871*6e8348ecSCallahan Kovacs 		 id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) {
8729d7b1866SSean O'Brien 		if (id->vendor == BT_VENDOR_ID_APPLE)
8739d7b1866SSean O'Brien 			report = hid_register_report(hdev, HID_INPUT_REPORT,
8749d7b1866SSean O'Brien 				TRACKPAD2_BT_REPORT_ID, 0);
8759d7b1866SSean O'Brien 		else /* USB_VENDOR_ID_APPLE */
8769d7b1866SSean O'Brien 			report = hid_register_report(hdev, HID_INPUT_REPORT,
8779d7b1866SSean O'Brien 				TRACKPAD2_USB_REPORT_ID, 0);
8789d7b1866SSean O'Brien 	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
879a462230eSChase Douglas 		report = hid_register_report(hdev, HID_INPUT_REPORT,
880f07b3c1dSBenjamin Tissoires 			TRACKPAD_REPORT_ID, 0);
881a462230eSChase Douglas 		report = hid_register_report(hdev, HID_INPUT_REPORT,
882f07b3c1dSBenjamin Tissoires 			DOUBLE_REPORT_ID, 0);
883a462230eSChase Douglas 	}
884a462230eSChase Douglas 
885128537ceSMichael Poole 	if (!report) {
8864291ee30SJoe Perches 		hid_err(hdev, "unable to register touch report\n");
887128537ceSMichael Poole 		ret = -ENOMEM;
88871b38bd4SMichael Poole 		goto err_stop_hw;
889128537ceSMichael Poole 	}
890128537ceSMichael Poole 	report->size = 6;
891128537ceSMichael Poole 
89235d851dfSJiri Kosina 	/*
89335d851dfSJiri Kosina 	 * Some devices repond with 'invalid report id' when feature
89435d851dfSJiri Kosina 	 * report switching it into multitouch mode is sent to it.
89535d851dfSJiri Kosina 	 *
89635d851dfSJiri Kosina 	 * This results in -EIO from the _raw low-level transport callback,
89735d851dfSJiri Kosina 	 * but there seems to be no other way of switching the mode.
89835d851dfSJiri Kosina 	 * Thus the super-ugly hacky success check below.
89935d851dfSJiri Kosina 	 */
900c0dc5582SJohn Chen 	ret = magicmouse_enable_multitouch(hdev);
901c0dc5582SJohn Chen 	if (ret != -EIO && ret < 0) {
9024291ee30SJoe Perches 		hid_err(hdev, "unable to request touch data (%d)\n", ret);
90371b38bd4SMichael Poole 		goto err_stop_hw;
904128537ceSMichael Poole 	}
905c0dc5582SJohn Chen 	if (ret == -EIO && id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
906c0dc5582SJohn Chen 		schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
907c0dc5582SJohn Chen 	}
908128537ceSMichael Poole 
909128537ceSMichael Poole 	return 0;
91071b38bd4SMichael Poole err_stop_hw:
91133812fc7SChristophe JAILLET 	del_timer_sync(&msc->battery_timer);
91271b38bd4SMichael Poole 	hid_hw_stop(hdev);
913128537ceSMichael Poole 	return ret;
914128537ceSMichael Poole }
915128537ceSMichael Poole 
magicmouse_remove(struct hid_device * hdev)916c0dc5582SJohn Chen static void magicmouse_remove(struct hid_device *hdev)
917c0dc5582SJohn Chen {
918c0dc5582SJohn Chen 	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
9194fb12519SJosé Expósito 
9200b91b4e4SJosé Expósito 	if (msc) {
921c0dc5582SJohn Chen 		cancel_delayed_work_sync(&msc->work);
9220b91b4e4SJosé Expósito 		del_timer_sync(&msc->battery_timer);
9230b91b4e4SJosé Expósito 	}
9244fb12519SJosé Expósito 
925c0dc5582SJohn Chen 	hid_hw_stop(hdev);
926c0dc5582SJohn Chen }
927c0dc5582SJohn Chen 
magicmouse_report_fixup(struct hid_device * hdev,__u8 * rdesc,unsigned int * rsize)9280b91b4e4SJosé Expósito static __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
9290b91b4e4SJosé Expósito 				     unsigned int *rsize)
9300b91b4e4SJosé Expósito {
9310b91b4e4SJosé Expósito 	/*
9320b91b4e4SJosé Expósito 	 * Change the usage from:
9330b91b4e4SJosé Expósito 	 *   0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1)  0
9340b91b4e4SJosé Expósito 	 *   0x09, 0x0b,       // Usage (Vendor Usage 0x0b)           3
9350b91b4e4SJosé Expósito 	 * To:
9360b91b4e4SJosé Expósito 	 *   0x05, 0x01,       // Usage Page (Generic Desktop)        0
9370b91b4e4SJosé Expósito 	 *   0x09, 0x02,       // Usage (Mouse)                       2
9380b91b4e4SJosé Expósito 	 */
9390b91b4e4SJosé Expósito 	if (hdev->vendor == USB_VENDOR_ID_APPLE &&
9400b91b4e4SJosé Expósito 	    (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
941*6e8348ecSCallahan Kovacs 	     hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 ||
942*6e8348ecSCallahan Kovacs 	     hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) &&
9430b91b4e4SJosé Expósito 	    *rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
9440b91b4e4SJosé Expósito 		hid_info(hdev,
9450b91b4e4SJosé Expósito 			 "fixing up magicmouse battery report descriptor\n");
9460b91b4e4SJosé Expósito 		*rsize = *rsize - 1;
9470b91b4e4SJosé Expósito 		rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL);
9480b91b4e4SJosé Expósito 		if (!rdesc)
9490b91b4e4SJosé Expósito 			return NULL;
9500b91b4e4SJosé Expósito 
9510b91b4e4SJosé Expósito 		rdesc[0] = 0x05;
9520b91b4e4SJosé Expósito 		rdesc[1] = 0x01;
9530b91b4e4SJosé Expósito 		rdesc[2] = 0x09;
9540b91b4e4SJosé Expósito 		rdesc[3] = 0x02;
9550b91b4e4SJosé Expósito 	}
9560b91b4e4SJosé Expósito 
9570b91b4e4SJosé Expósito 	return rdesc;
9580b91b4e4SJosé Expósito }
9590b91b4e4SJosé Expósito 
960128537ceSMichael Poole static const struct hid_device_id magic_mice[] = {
961a462230eSChase Douglas 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
962a462230eSChase Douglas 		USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
9632b0c086cSJohn Chen 	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
9642b0c086cSJohn Chen 		USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 },
9650b91b4e4SJosé Expósito 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
9660b91b4e4SJosé Expósito 		USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 },
967a462230eSChase Douglas 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
968a462230eSChase Douglas 		USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 },
9699d7b1866SSean O'Brien 	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
9709d7b1866SSean O'Brien 		USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 },
9719d7b1866SSean O'Brien 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
9729d7b1866SSean O'Brien 		USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 },
973*6e8348ecSCallahan Kovacs 	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
974*6e8348ecSCallahan Kovacs 		USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 },
975*6e8348ecSCallahan Kovacs 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
976*6e8348ecSCallahan Kovacs 		USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 },
977128537ceSMichael Poole 	{ }
978128537ceSMichael Poole };
979128537ceSMichael Poole MODULE_DEVICE_TABLE(hid, magic_mice);
980128537ceSMichael Poole 
981128537ceSMichael Poole static struct hid_driver magicmouse_driver = {
982128537ceSMichael Poole 	.name = "magicmouse",
983128537ceSMichael Poole 	.id_table = magic_mice,
984128537ceSMichael Poole 	.probe = magicmouse_probe,
985c0dc5582SJohn Chen 	.remove = magicmouse_remove,
9860b91b4e4SJosé Expósito 	.report_fixup = magicmouse_report_fixup,
987128537ceSMichael Poole 	.raw_event = magicmouse_raw_event,
9883dcc5f7bSJohn Chen 	.event = magicmouse_event,
98964eb105dSMichael Poole 	.input_mapping = magicmouse_input_mapping,
990f1a9a149SBenjamin Tissoires 	.input_configured = magicmouse_input_configured,
991128537ceSMichael Poole };
992f425458eSH Hartley Sweeten module_hid_driver(magicmouse_driver);
993128537ceSMichael Poole 
994128537ceSMichael Poole MODULE_LICENSE("GPL");
995