162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   Apple "Magic" Wireless Mouse driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *   Copyright (c) 2010 Michael Poole <mdpoole@troilus.org>
662306a36Sopenharmony_ci *   Copyright (c) 2010 Chase Douglas <chase.douglas@canonical.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/hid.h>
1662306a36Sopenharmony_ci#include <linux/input/mt.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/workqueue.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "hid-ids.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic bool emulate_3button = true;
2462306a36Sopenharmony_cimodule_param(emulate_3button, bool, 0644);
2562306a36Sopenharmony_ciMODULE_PARM_DESC(emulate_3button, "Emulate a middle button");
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int middle_button_start = -350;
2862306a36Sopenharmony_cistatic int middle_button_stop = +350;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic bool emulate_scroll_wheel = true;
3162306a36Sopenharmony_cimodule_param(emulate_scroll_wheel, bool, 0644);
3262306a36Sopenharmony_ciMODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic unsigned int scroll_speed = 32;
3562306a36Sopenharmony_cistatic int param_set_scroll_speed(const char *val,
3662306a36Sopenharmony_ci				  const struct kernel_param *kp) {
3762306a36Sopenharmony_ci	unsigned long speed;
3862306a36Sopenharmony_ci	if (!val || kstrtoul(val, 0, &speed) || speed > 63)
3962306a36Sopenharmony_ci		return -EINVAL;
4062306a36Sopenharmony_ci	scroll_speed = speed;
4162306a36Sopenharmony_ci	return 0;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_cimodule_param_call(scroll_speed, param_set_scroll_speed, param_get_uint, &scroll_speed, 0644);
4462306a36Sopenharmony_ciMODULE_PARM_DESC(scroll_speed, "Scroll speed, value from 0 (slow) to 63 (fast)");
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic bool scroll_acceleration = false;
4762306a36Sopenharmony_cimodule_param(scroll_acceleration, bool, 0644);
4862306a36Sopenharmony_ciMODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events");
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic bool report_undeciphered;
5162306a36Sopenharmony_cimodule_param(report_undeciphered, bool, 0644);
5262306a36Sopenharmony_ciMODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event");
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define TRACKPAD2_2021_BT_VERSION 0x110
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define TRACKPAD_REPORT_ID 0x28
5762306a36Sopenharmony_ci#define TRACKPAD2_USB_REPORT_ID 0x02
5862306a36Sopenharmony_ci#define TRACKPAD2_BT_REPORT_ID 0x31
5962306a36Sopenharmony_ci#define MOUSE_REPORT_ID    0x29
6062306a36Sopenharmony_ci#define MOUSE2_REPORT_ID   0x12
6162306a36Sopenharmony_ci#define DOUBLE_REPORT_ID   0xf7
6262306a36Sopenharmony_ci#define USB_BATTERY_TIMEOUT_MS 60000
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* These definitions are not precise, but they're close enough.  (Bits
6562306a36Sopenharmony_ci * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
6662306a36Sopenharmony_ci * to be some kind of bit mask -- 0x20 may be a near-field reading,
6762306a36Sopenharmony_ci * and 0x40 is actual contact, and 0x10 may be a start/stop or change
6862306a36Sopenharmony_ci * indication.)
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_ci#define TOUCH_STATE_MASK  0xf0
7162306a36Sopenharmony_ci#define TOUCH_STATE_NONE  0x00
7262306a36Sopenharmony_ci#define TOUCH_STATE_START 0x30
7362306a36Sopenharmony_ci#define TOUCH_STATE_DRAG  0x40
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* Number of high-resolution events for each low-resolution detent. */
7662306a36Sopenharmony_ci#define SCROLL_HR_STEPS 10
7762306a36Sopenharmony_ci#define SCROLL_HR_MULT (120 / SCROLL_HR_STEPS)
7862306a36Sopenharmony_ci#define SCROLL_HR_THRESHOLD 90 /* units */
7962306a36Sopenharmony_ci#define SCROLL_ACCEL_DEFAULT 7
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/* Touch surface information. Dimension is in hundredths of a mm, min and max
8262306a36Sopenharmony_ci * are in units. */
8362306a36Sopenharmony_ci#define MOUSE_DIMENSION_X (float)9056
8462306a36Sopenharmony_ci#define MOUSE_MIN_X -1100
8562306a36Sopenharmony_ci#define MOUSE_MAX_X 1258
8662306a36Sopenharmony_ci#define MOUSE_RES_X ((MOUSE_MAX_X - MOUSE_MIN_X) / (MOUSE_DIMENSION_X / 100))
8762306a36Sopenharmony_ci#define MOUSE_DIMENSION_Y (float)5152
8862306a36Sopenharmony_ci#define MOUSE_MIN_Y -1589
8962306a36Sopenharmony_ci#define MOUSE_MAX_Y 2047
9062306a36Sopenharmony_ci#define MOUSE_RES_Y ((MOUSE_MAX_Y - MOUSE_MIN_Y) / (MOUSE_DIMENSION_Y / 100))
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define TRACKPAD_DIMENSION_X (float)13000
9362306a36Sopenharmony_ci#define TRACKPAD_MIN_X -2909
9462306a36Sopenharmony_ci#define TRACKPAD_MAX_X 3167
9562306a36Sopenharmony_ci#define TRACKPAD_RES_X \
9662306a36Sopenharmony_ci	((TRACKPAD_MAX_X - TRACKPAD_MIN_X) / (TRACKPAD_DIMENSION_X / 100))
9762306a36Sopenharmony_ci#define TRACKPAD_DIMENSION_Y (float)11000
9862306a36Sopenharmony_ci#define TRACKPAD_MIN_Y -2456
9962306a36Sopenharmony_ci#define TRACKPAD_MAX_Y 2565
10062306a36Sopenharmony_ci#define TRACKPAD_RES_Y \
10162306a36Sopenharmony_ci	((TRACKPAD_MAX_Y - TRACKPAD_MIN_Y) / (TRACKPAD_DIMENSION_Y / 100))
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define TRACKPAD2_DIMENSION_X (float)16000
10462306a36Sopenharmony_ci#define TRACKPAD2_MIN_X -3678
10562306a36Sopenharmony_ci#define TRACKPAD2_MAX_X 3934
10662306a36Sopenharmony_ci#define TRACKPAD2_RES_X \
10762306a36Sopenharmony_ci	((TRACKPAD2_MAX_X - TRACKPAD2_MIN_X) / (TRACKPAD2_DIMENSION_X / 100))
10862306a36Sopenharmony_ci#define TRACKPAD2_DIMENSION_Y (float)11490
10962306a36Sopenharmony_ci#define TRACKPAD2_MIN_Y -2478
11062306a36Sopenharmony_ci#define TRACKPAD2_MAX_Y 2587
11162306a36Sopenharmony_ci#define TRACKPAD2_RES_Y \
11262306a36Sopenharmony_ci	((TRACKPAD2_MAX_Y - TRACKPAD2_MIN_Y) / (TRACKPAD2_DIMENSION_Y / 100))
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/**
11562306a36Sopenharmony_ci * struct magicmouse_sc - Tracks Magic Mouse-specific data.
11662306a36Sopenharmony_ci * @input: Input device through which we report events.
11762306a36Sopenharmony_ci * @quirks: Currently unused.
11862306a36Sopenharmony_ci * @ntouches: Number of touches in most recent touch report.
11962306a36Sopenharmony_ci * @scroll_accel: Number of consecutive scroll motions.
12062306a36Sopenharmony_ci * @scroll_jiffies: Time of last scroll motion.
12162306a36Sopenharmony_ci * @touches: Most recent data for a touch, indexed by tracking ID.
12262306a36Sopenharmony_ci * @tracking_ids: Mapping of current touch input data to @touches.
12362306a36Sopenharmony_ci */
12462306a36Sopenharmony_cistruct magicmouse_sc {
12562306a36Sopenharmony_ci	struct input_dev *input;
12662306a36Sopenharmony_ci	unsigned long quirks;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	int ntouches;
12962306a36Sopenharmony_ci	int scroll_accel;
13062306a36Sopenharmony_ci	unsigned long scroll_jiffies;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	struct {
13362306a36Sopenharmony_ci		short x;
13462306a36Sopenharmony_ci		short y;
13562306a36Sopenharmony_ci		short scroll_x;
13662306a36Sopenharmony_ci		short scroll_y;
13762306a36Sopenharmony_ci		short scroll_x_hr;
13862306a36Sopenharmony_ci		short scroll_y_hr;
13962306a36Sopenharmony_ci		u8 size;
14062306a36Sopenharmony_ci		bool scroll_x_active;
14162306a36Sopenharmony_ci		bool scroll_y_active;
14262306a36Sopenharmony_ci	} touches[16];
14362306a36Sopenharmony_ci	int tracking_ids[16];
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	struct hid_device *hdev;
14662306a36Sopenharmony_ci	struct delayed_work work;
14762306a36Sopenharmony_ci	struct timer_list battery_timer;
14862306a36Sopenharmony_ci};
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int magicmouse_firm_touch(struct magicmouse_sc *msc)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	int touch = -1;
15362306a36Sopenharmony_ci	int ii;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* If there is only one "firm" touch, set touch to its
15662306a36Sopenharmony_ci	 * tracking ID.
15762306a36Sopenharmony_ci	 */
15862306a36Sopenharmony_ci	for (ii = 0; ii < msc->ntouches; ii++) {
15962306a36Sopenharmony_ci		int idx = msc->tracking_ids[ii];
16062306a36Sopenharmony_ci		if (msc->touches[idx].size < 8) {
16162306a36Sopenharmony_ci			/* Ignore this touch. */
16262306a36Sopenharmony_ci		} else if (touch >= 0) {
16362306a36Sopenharmony_ci			touch = -1;
16462306a36Sopenharmony_ci			break;
16562306a36Sopenharmony_ci		} else {
16662306a36Sopenharmony_ci			touch = idx;
16762306a36Sopenharmony_ci		}
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	return touch;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	int last_state = test_bit(BTN_LEFT, msc->input->key) << 0 |
17662306a36Sopenharmony_ci		test_bit(BTN_RIGHT, msc->input->key) << 1 |
17762306a36Sopenharmony_ci		test_bit(BTN_MIDDLE, msc->input->key) << 2;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (emulate_3button) {
18062306a36Sopenharmony_ci		int id;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		/* If some button was pressed before, keep it held
18362306a36Sopenharmony_ci		 * down.  Otherwise, if there's exactly one firm
18462306a36Sopenharmony_ci		 * touch, use that to override the mouse's guess.
18562306a36Sopenharmony_ci		 */
18662306a36Sopenharmony_ci		if (state == 0) {
18762306a36Sopenharmony_ci			/* The button was released. */
18862306a36Sopenharmony_ci		} else if (last_state != 0) {
18962306a36Sopenharmony_ci			state = last_state;
19062306a36Sopenharmony_ci		} else if ((id = magicmouse_firm_touch(msc)) >= 0) {
19162306a36Sopenharmony_ci			int x = msc->touches[id].x;
19262306a36Sopenharmony_ci			if (x < middle_button_start)
19362306a36Sopenharmony_ci				state = 1;
19462306a36Sopenharmony_ci			else if (x > middle_button_stop)
19562306a36Sopenharmony_ci				state = 2;
19662306a36Sopenharmony_ci			else
19762306a36Sopenharmony_ci				state = 4;
19862306a36Sopenharmony_ci		} /* else: we keep the mouse's guess */
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		input_report_key(msc->input, BTN_MIDDLE, state & 4);
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	input_report_key(msc->input, BTN_LEFT, state & 1);
20462306a36Sopenharmony_ci	input_report_key(msc->input, BTN_RIGHT, state & 2);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (state != last_state)
20762306a36Sopenharmony_ci		msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct input_dev *input = msc->input;
21362306a36Sopenharmony_ci	int id, x, y, size, orientation, touch_major, touch_minor, state, down;
21462306a36Sopenharmony_ci	int pressure = 0;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
21762306a36Sopenharmony_ci	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
21862306a36Sopenharmony_ci		id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf;
21962306a36Sopenharmony_ci		x = (tdata[1] << 28 | tdata[0] << 20) >> 20;
22062306a36Sopenharmony_ci		y = -((tdata[2] << 24 | tdata[1] << 16) >> 20);
22162306a36Sopenharmony_ci		size = tdata[5] & 0x3f;
22262306a36Sopenharmony_ci		orientation = (tdata[6] >> 2) - 32;
22362306a36Sopenharmony_ci		touch_major = tdata[3];
22462306a36Sopenharmony_ci		touch_minor = tdata[4];
22562306a36Sopenharmony_ci		state = tdata[7] & TOUCH_STATE_MASK;
22662306a36Sopenharmony_ci		down = state != TOUCH_STATE_NONE;
22762306a36Sopenharmony_ci	} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
22862306a36Sopenharmony_ci		id = tdata[8] & 0xf;
22962306a36Sopenharmony_ci		x = (tdata[1] << 27 | tdata[0] << 19) >> 19;
23062306a36Sopenharmony_ci		y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19);
23162306a36Sopenharmony_ci		size = tdata[6];
23262306a36Sopenharmony_ci		orientation = (tdata[8] >> 5) - 4;
23362306a36Sopenharmony_ci		touch_major = tdata[4];
23462306a36Sopenharmony_ci		touch_minor = tdata[5];
23562306a36Sopenharmony_ci		pressure = tdata[7];
23662306a36Sopenharmony_ci		state = tdata[3] & 0xC0;
23762306a36Sopenharmony_ci		down = state == 0x80;
23862306a36Sopenharmony_ci	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
23962306a36Sopenharmony_ci		id = (tdata[7] << 2 | tdata[6] >> 6) & 0xf;
24062306a36Sopenharmony_ci		x = (tdata[1] << 27 | tdata[0] << 19) >> 19;
24162306a36Sopenharmony_ci		y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19);
24262306a36Sopenharmony_ci		size = tdata[6] & 0x3f;
24362306a36Sopenharmony_ci		orientation = (tdata[7] >> 2) - 32;
24462306a36Sopenharmony_ci		touch_major = tdata[4];
24562306a36Sopenharmony_ci		touch_minor = tdata[5];
24662306a36Sopenharmony_ci		state = tdata[8] & TOUCH_STATE_MASK;
24762306a36Sopenharmony_ci		down = state != TOUCH_STATE_NONE;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	/* Store tracking ID and other fields. */
25162306a36Sopenharmony_ci	msc->tracking_ids[raw_id] = id;
25262306a36Sopenharmony_ci	msc->touches[id].x = x;
25362306a36Sopenharmony_ci	msc->touches[id].y = y;
25462306a36Sopenharmony_ci	msc->touches[id].size = size;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/* If requested, emulate a scroll wheel by detecting small
25762306a36Sopenharmony_ci	 * vertical touch motions.
25862306a36Sopenharmony_ci	 */
25962306a36Sopenharmony_ci	if (emulate_scroll_wheel && (input->id.product !=
26062306a36Sopenharmony_ci			USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) {
26162306a36Sopenharmony_ci		unsigned long now = jiffies;
26262306a36Sopenharmony_ci		int step_x = msc->touches[id].scroll_x - x;
26362306a36Sopenharmony_ci		int step_y = msc->touches[id].scroll_y - y;
26462306a36Sopenharmony_ci		int step_hr =
26562306a36Sopenharmony_ci			max_t(int,
26662306a36Sopenharmony_ci			      ((64 - (int)scroll_speed) * msc->scroll_accel) /
26762306a36Sopenharmony_ci					SCROLL_HR_STEPS,
26862306a36Sopenharmony_ci			      1);
26962306a36Sopenharmony_ci		int step_x_hr = msc->touches[id].scroll_x_hr - x;
27062306a36Sopenharmony_ci		int step_y_hr = msc->touches[id].scroll_y_hr - y;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		/* Calculate and apply the scroll motion. */
27362306a36Sopenharmony_ci		switch (state) {
27462306a36Sopenharmony_ci		case TOUCH_STATE_START:
27562306a36Sopenharmony_ci			msc->touches[id].scroll_x = x;
27662306a36Sopenharmony_ci			msc->touches[id].scroll_y = y;
27762306a36Sopenharmony_ci			msc->touches[id].scroll_x_hr = x;
27862306a36Sopenharmony_ci			msc->touches[id].scroll_y_hr = y;
27962306a36Sopenharmony_ci			msc->touches[id].scroll_x_active = false;
28062306a36Sopenharmony_ci			msc->touches[id].scroll_y_active = false;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci			/* Reset acceleration after half a second. */
28362306a36Sopenharmony_ci			if (scroll_acceleration && time_before(now,
28462306a36Sopenharmony_ci						msc->scroll_jiffies + HZ / 2))
28562306a36Sopenharmony_ci				msc->scroll_accel = max_t(int,
28662306a36Sopenharmony_ci						msc->scroll_accel - 1, 1);
28762306a36Sopenharmony_ci			else
28862306a36Sopenharmony_ci				msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci			break;
29162306a36Sopenharmony_ci		case TOUCH_STATE_DRAG:
29262306a36Sopenharmony_ci			step_x /= (64 - (int)scroll_speed) * msc->scroll_accel;
29362306a36Sopenharmony_ci			if (step_x != 0) {
29462306a36Sopenharmony_ci				msc->touches[id].scroll_x -= step_x *
29562306a36Sopenharmony_ci					(64 - scroll_speed) * msc->scroll_accel;
29662306a36Sopenharmony_ci				msc->scroll_jiffies = now;
29762306a36Sopenharmony_ci				input_report_rel(input, REL_HWHEEL, -step_x);
29862306a36Sopenharmony_ci			}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci			step_y /= (64 - (int)scroll_speed) * msc->scroll_accel;
30162306a36Sopenharmony_ci			if (step_y != 0) {
30262306a36Sopenharmony_ci				msc->touches[id].scroll_y -= step_y *
30362306a36Sopenharmony_ci					(64 - scroll_speed) * msc->scroll_accel;
30462306a36Sopenharmony_ci				msc->scroll_jiffies = now;
30562306a36Sopenharmony_ci				input_report_rel(input, REL_WHEEL, step_y);
30662306a36Sopenharmony_ci			}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci			if (!msc->touches[id].scroll_x_active &&
30962306a36Sopenharmony_ci			    abs(step_x_hr) > SCROLL_HR_THRESHOLD) {
31062306a36Sopenharmony_ci				msc->touches[id].scroll_x_active = true;
31162306a36Sopenharmony_ci				msc->touches[id].scroll_x_hr = x;
31262306a36Sopenharmony_ci				step_x_hr = 0;
31362306a36Sopenharmony_ci			}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci			step_x_hr /= step_hr;
31662306a36Sopenharmony_ci			if (step_x_hr != 0 &&
31762306a36Sopenharmony_ci			    msc->touches[id].scroll_x_active) {
31862306a36Sopenharmony_ci				msc->touches[id].scroll_x_hr -= step_x_hr *
31962306a36Sopenharmony_ci					step_hr;
32062306a36Sopenharmony_ci				input_report_rel(input,
32162306a36Sopenharmony_ci						 REL_HWHEEL_HI_RES,
32262306a36Sopenharmony_ci						 -step_x_hr * SCROLL_HR_MULT);
32362306a36Sopenharmony_ci			}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci			if (!msc->touches[id].scroll_y_active &&
32662306a36Sopenharmony_ci			    abs(step_y_hr) > SCROLL_HR_THRESHOLD) {
32762306a36Sopenharmony_ci				msc->touches[id].scroll_y_active = true;
32862306a36Sopenharmony_ci				msc->touches[id].scroll_y_hr = y;
32962306a36Sopenharmony_ci				step_y_hr = 0;
33062306a36Sopenharmony_ci			}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci			step_y_hr /= step_hr;
33362306a36Sopenharmony_ci			if (step_y_hr != 0 &&
33462306a36Sopenharmony_ci			    msc->touches[id].scroll_y_active) {
33562306a36Sopenharmony_ci				msc->touches[id].scroll_y_hr -= step_y_hr *
33662306a36Sopenharmony_ci					step_hr;
33762306a36Sopenharmony_ci				input_report_rel(input,
33862306a36Sopenharmony_ci						 REL_WHEEL_HI_RES,
33962306a36Sopenharmony_ci						 step_y_hr * SCROLL_HR_MULT);
34062306a36Sopenharmony_ci			}
34162306a36Sopenharmony_ci			break;
34262306a36Sopenharmony_ci		}
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (down)
34662306a36Sopenharmony_ci		msc->ntouches++;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	input_mt_slot(input, id);
34962306a36Sopenharmony_ci	input_mt_report_slot_state(input, MT_TOOL_FINGER, down);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* Generate the input events for this touch. */
35262306a36Sopenharmony_ci	if (down) {
35362306a36Sopenharmony_ci		input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2);
35462306a36Sopenharmony_ci		input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2);
35562306a36Sopenharmony_ci		input_report_abs(input, ABS_MT_ORIENTATION, -orientation);
35662306a36Sopenharmony_ci		input_report_abs(input, ABS_MT_POSITION_X, x);
35762306a36Sopenharmony_ci		input_report_abs(input, ABS_MT_POSITION_Y, y);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)
36062306a36Sopenharmony_ci			input_report_abs(input, ABS_MT_PRESSURE, pressure);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci		if (report_undeciphered) {
36362306a36Sopenharmony_ci			if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
36462306a36Sopenharmony_ci			    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
36562306a36Sopenharmony_ci				input_event(input, EV_MSC, MSC_RAW, tdata[7]);
36662306a36Sopenharmony_ci			else if (input->id.product !=
36762306a36Sopenharmony_ci					USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)
36862306a36Sopenharmony_ci				input_event(input, EV_MSC, MSC_RAW, tdata[8]);
36962306a36Sopenharmony_ci		}
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic int magicmouse_raw_event(struct hid_device *hdev,
37462306a36Sopenharmony_ci		struct hid_report *report, u8 *data, int size)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
37762306a36Sopenharmony_ci	struct input_dev *input = msc->input;
37862306a36Sopenharmony_ci	int x = 0, y = 0, ii, clicks = 0, npoints;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	switch (data[0]) {
38162306a36Sopenharmony_ci	case TRACKPAD_REPORT_ID:
38262306a36Sopenharmony_ci	case TRACKPAD2_BT_REPORT_ID:
38362306a36Sopenharmony_ci		/* Expect four bytes of prefix, and N*9 bytes of touch data. */
38462306a36Sopenharmony_ci		if (size < 4 || ((size - 4) % 9) != 0)
38562306a36Sopenharmony_ci			return 0;
38662306a36Sopenharmony_ci		npoints = (size - 4) / 9;
38762306a36Sopenharmony_ci		if (npoints > 15) {
38862306a36Sopenharmony_ci			hid_warn(hdev, "invalid size value (%d) for TRACKPAD_REPORT_ID\n",
38962306a36Sopenharmony_ci					size);
39062306a36Sopenharmony_ci			return 0;
39162306a36Sopenharmony_ci		}
39262306a36Sopenharmony_ci		msc->ntouches = 0;
39362306a36Sopenharmony_ci		for (ii = 0; ii < npoints; ii++)
39462306a36Sopenharmony_ci			magicmouse_emit_touch(msc, ii, data + ii * 9 + 4);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		clicks = data[1];
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		/* The following bits provide a device specific timestamp. They
39962306a36Sopenharmony_ci		 * are unused here.
40062306a36Sopenharmony_ci		 *
40162306a36Sopenharmony_ci		 * ts = data[1] >> 6 | data[2] << 2 | data[3] << 10;
40262306a36Sopenharmony_ci		 */
40362306a36Sopenharmony_ci		break;
40462306a36Sopenharmony_ci	case TRACKPAD2_USB_REPORT_ID:
40562306a36Sopenharmony_ci		/* Expect twelve bytes of prefix and N*9 bytes of touch data. */
40662306a36Sopenharmony_ci		if (size < 12 || ((size - 12) % 9) != 0)
40762306a36Sopenharmony_ci			return 0;
40862306a36Sopenharmony_ci		npoints = (size - 12) / 9;
40962306a36Sopenharmony_ci		if (npoints > 15) {
41062306a36Sopenharmony_ci			hid_warn(hdev, "invalid size value (%d) for TRACKPAD2_USB_REPORT_ID\n",
41162306a36Sopenharmony_ci					size);
41262306a36Sopenharmony_ci			return 0;
41362306a36Sopenharmony_ci		}
41462306a36Sopenharmony_ci		msc->ntouches = 0;
41562306a36Sopenharmony_ci		for (ii = 0; ii < npoints; ii++)
41662306a36Sopenharmony_ci			magicmouse_emit_touch(msc, ii, data + ii * 9 + 12);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		clicks = data[1];
41962306a36Sopenharmony_ci		break;
42062306a36Sopenharmony_ci	case MOUSE_REPORT_ID:
42162306a36Sopenharmony_ci		/* Expect six bytes of prefix, and N*8 bytes of touch data. */
42262306a36Sopenharmony_ci		if (size < 6 || ((size - 6) % 8) != 0)
42362306a36Sopenharmony_ci			return 0;
42462306a36Sopenharmony_ci		npoints = (size - 6) / 8;
42562306a36Sopenharmony_ci		if (npoints > 15) {
42662306a36Sopenharmony_ci			hid_warn(hdev, "invalid size value (%d) for MOUSE_REPORT_ID\n",
42762306a36Sopenharmony_ci					size);
42862306a36Sopenharmony_ci			return 0;
42962306a36Sopenharmony_ci		}
43062306a36Sopenharmony_ci		msc->ntouches = 0;
43162306a36Sopenharmony_ci		for (ii = 0; ii < npoints; ii++)
43262306a36Sopenharmony_ci			magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		/* When emulating three-button mode, it is important
43562306a36Sopenharmony_ci		 * to have the current touch information before
43662306a36Sopenharmony_ci		 * generating a click event.
43762306a36Sopenharmony_ci		 */
43862306a36Sopenharmony_ci		x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22;
43962306a36Sopenharmony_ci		y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22;
44062306a36Sopenharmony_ci		clicks = data[3];
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		/* The following bits provide a device specific timestamp. They
44362306a36Sopenharmony_ci		 * are unused here.
44462306a36Sopenharmony_ci		 *
44562306a36Sopenharmony_ci		 * ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
44662306a36Sopenharmony_ci		 */
44762306a36Sopenharmony_ci		break;
44862306a36Sopenharmony_ci	case MOUSE2_REPORT_ID:
44962306a36Sopenharmony_ci		/* Size is either 8 or (14 + 8 * N) */
45062306a36Sopenharmony_ci		if (size != 8 && (size < 14 || (size - 14) % 8 != 0))
45162306a36Sopenharmony_ci			return 0;
45262306a36Sopenharmony_ci		npoints = (size - 14) / 8;
45362306a36Sopenharmony_ci		if (npoints > 15) {
45462306a36Sopenharmony_ci			hid_warn(hdev, "invalid size value (%d) for MOUSE2_REPORT_ID\n",
45562306a36Sopenharmony_ci					size);
45662306a36Sopenharmony_ci			return 0;
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci		msc->ntouches = 0;
45962306a36Sopenharmony_ci		for (ii = 0; ii < npoints; ii++)
46062306a36Sopenharmony_ci			magicmouse_emit_touch(msc, ii, data + ii * 8 + 14);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		/* When emulating three-button mode, it is important
46362306a36Sopenharmony_ci		 * to have the current touch information before
46462306a36Sopenharmony_ci		 * generating a click event.
46562306a36Sopenharmony_ci		 */
46662306a36Sopenharmony_ci		x = (int)((data[3] << 24) | (data[2] << 16)) >> 16;
46762306a36Sopenharmony_ci		y = (int)((data[5] << 24) | (data[4] << 16)) >> 16;
46862306a36Sopenharmony_ci		clicks = data[1];
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		/* The following bits provide a device specific timestamp. They
47162306a36Sopenharmony_ci		 * are unused here.
47262306a36Sopenharmony_ci		 *
47362306a36Sopenharmony_ci		 * ts = data[11] >> 6 | data[12] << 2 | data[13] << 10;
47462306a36Sopenharmony_ci		 */
47562306a36Sopenharmony_ci		break;
47662306a36Sopenharmony_ci	case DOUBLE_REPORT_ID:
47762306a36Sopenharmony_ci		/* Sometimes the trackpad sends two touch reports in one
47862306a36Sopenharmony_ci		 * packet.
47962306a36Sopenharmony_ci		 */
48062306a36Sopenharmony_ci		magicmouse_raw_event(hdev, report, data + 2, data[1]);
48162306a36Sopenharmony_ci		magicmouse_raw_event(hdev, report, data + 2 + data[1],
48262306a36Sopenharmony_ci			size - 2 - data[1]);
48362306a36Sopenharmony_ci		return 0;
48462306a36Sopenharmony_ci	default:
48562306a36Sopenharmony_ci		return 0;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
48962306a36Sopenharmony_ci	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
49062306a36Sopenharmony_ci		magicmouse_emit_buttons(msc, clicks & 3);
49162306a36Sopenharmony_ci		input_report_rel(input, REL_X, x);
49262306a36Sopenharmony_ci		input_report_rel(input, REL_Y, y);
49362306a36Sopenharmony_ci	} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
49462306a36Sopenharmony_ci		input_mt_sync_frame(input);
49562306a36Sopenharmony_ci		input_report_key(input, BTN_MOUSE, clicks & 1);
49662306a36Sopenharmony_ci	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
49762306a36Sopenharmony_ci		input_report_key(input, BTN_MOUSE, clicks & 1);
49862306a36Sopenharmony_ci		input_mt_report_pointer_emulation(input, true);
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	input_sync(input);
50262306a36Sopenharmony_ci	return 1;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic int magicmouse_event(struct hid_device *hdev, struct hid_field *field,
50662306a36Sopenharmony_ci		struct hid_usage *usage, __s32 value)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
50962306a36Sopenharmony_ci	if (msc->input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
51062306a36Sopenharmony_ci	    field->report->id == MOUSE2_REPORT_ID) {
51162306a36Sopenharmony_ci		/*
51262306a36Sopenharmony_ci		 * magic_mouse_raw_event has done all the work. Skip hidinput.
51362306a36Sopenharmony_ci		 *
51462306a36Sopenharmony_ci		 * Specifically, hidinput may modify BTN_LEFT and BTN_RIGHT,
51562306a36Sopenharmony_ci		 * breaking emulate_3button.
51662306a36Sopenharmony_ci		 */
51762306a36Sopenharmony_ci		return 1;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci	return 0;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic int magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	int error;
52562306a36Sopenharmony_ci	int mt_flags = 0;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	__set_bit(EV_KEY, input->evbit);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
53062306a36Sopenharmony_ci	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
53162306a36Sopenharmony_ci		__set_bit(BTN_LEFT, input->keybit);
53262306a36Sopenharmony_ci		__set_bit(BTN_RIGHT, input->keybit);
53362306a36Sopenharmony_ci		if (emulate_3button)
53462306a36Sopenharmony_ci			__set_bit(BTN_MIDDLE, input->keybit);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		__set_bit(EV_REL, input->evbit);
53762306a36Sopenharmony_ci		__set_bit(REL_X, input->relbit);
53862306a36Sopenharmony_ci		__set_bit(REL_Y, input->relbit);
53962306a36Sopenharmony_ci		if (emulate_scroll_wheel) {
54062306a36Sopenharmony_ci			__set_bit(REL_WHEEL, input->relbit);
54162306a36Sopenharmony_ci			__set_bit(REL_HWHEEL, input->relbit);
54262306a36Sopenharmony_ci			__set_bit(REL_WHEEL_HI_RES, input->relbit);
54362306a36Sopenharmony_ci			__set_bit(REL_HWHEEL_HI_RES, input->relbit);
54462306a36Sopenharmony_ci		}
54562306a36Sopenharmony_ci	} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
54662306a36Sopenharmony_ci		/* If the trackpad has been connected to a Mac, the name is
54762306a36Sopenharmony_ci		 * automatically personalized, e.g., "José Expósito's Trackpad".
54862306a36Sopenharmony_ci		 * When connected through Bluetooth, the personalized name is
54962306a36Sopenharmony_ci		 * reported, however, when connected through USB the generic
55062306a36Sopenharmony_ci		 * name is reported.
55162306a36Sopenharmony_ci		 * Set the device name to ensure the same driver settings get
55262306a36Sopenharmony_ci		 * loaded, whether connected through bluetooth or USB.
55362306a36Sopenharmony_ci		 */
55462306a36Sopenharmony_ci		if (hdev->vendor == BT_VENDOR_ID_APPLE) {
55562306a36Sopenharmony_ci			if (input->id.version == TRACKPAD2_2021_BT_VERSION)
55662306a36Sopenharmony_ci				input->name = "Apple Inc. Magic Trackpad";
55762306a36Sopenharmony_ci			else
55862306a36Sopenharmony_ci				input->name = "Apple Inc. Magic Trackpad 2";
55962306a36Sopenharmony_ci		} else { /* USB_VENDOR_ID_APPLE */
56062306a36Sopenharmony_ci			input->name = hdev->name;
56162306a36Sopenharmony_ci		}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		__clear_bit(EV_MSC, input->evbit);
56462306a36Sopenharmony_ci		__clear_bit(BTN_0, input->keybit);
56562306a36Sopenharmony_ci		__clear_bit(BTN_RIGHT, input->keybit);
56662306a36Sopenharmony_ci		__clear_bit(BTN_MIDDLE, input->keybit);
56762306a36Sopenharmony_ci		__set_bit(BTN_MOUSE, input->keybit);
56862306a36Sopenharmony_ci		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
56962306a36Sopenharmony_ci		__set_bit(BTN_TOOL_FINGER, input->keybit);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		mt_flags = INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
57262306a36Sopenharmony_ci				INPUT_MT_TRACK;
57362306a36Sopenharmony_ci	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
57462306a36Sopenharmony_ci		/* input->keybit is initialized with incorrect button info
57562306a36Sopenharmony_ci		 * for Magic Trackpad. There really is only one physical
57662306a36Sopenharmony_ci		 * button (BTN_LEFT == BTN_MOUSE). Make sure we don't
57762306a36Sopenharmony_ci		 * advertise buttons that don't exist...
57862306a36Sopenharmony_ci		 */
57962306a36Sopenharmony_ci		__clear_bit(BTN_RIGHT, input->keybit);
58062306a36Sopenharmony_ci		__clear_bit(BTN_MIDDLE, input->keybit);
58162306a36Sopenharmony_ci		__set_bit(BTN_MOUSE, input->keybit);
58262306a36Sopenharmony_ci		__set_bit(BTN_TOOL_FINGER, input->keybit);
58362306a36Sopenharmony_ci		__set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
58462306a36Sopenharmony_ci		__set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
58562306a36Sopenharmony_ci		__set_bit(BTN_TOOL_QUADTAP, input->keybit);
58662306a36Sopenharmony_ci		__set_bit(BTN_TOOL_QUINTTAP, input->keybit);
58762306a36Sopenharmony_ci		__set_bit(BTN_TOUCH, input->keybit);
58862306a36Sopenharmony_ci		__set_bit(INPUT_PROP_POINTER, input->propbit);
58962306a36Sopenharmony_ci		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	__set_bit(EV_ABS, input->evbit);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	error = input_mt_init_slots(input, 16, mt_flags);
59662306a36Sopenharmony_ci	if (error)
59762306a36Sopenharmony_ci		return error;
59862306a36Sopenharmony_ci	input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2,
59962306a36Sopenharmony_ci			     4, 0);
60062306a36Sopenharmony_ci	input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255 << 2,
60162306a36Sopenharmony_ci			     4, 0);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/* Note: Touch Y position from the device is inverted relative
60462306a36Sopenharmony_ci	 * to how pointer motion is reported (and relative to how USB
60562306a36Sopenharmony_ci	 * HID recommends the coordinates work).  This driver keeps
60662306a36Sopenharmony_ci	 * the origin at the same position, and just uses the additive
60762306a36Sopenharmony_ci	 * inverse of the reported Y.
60862306a36Sopenharmony_ci	 */
60962306a36Sopenharmony_ci	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
61062306a36Sopenharmony_ci	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
61162306a36Sopenharmony_ci		input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
61262306a36Sopenharmony_ci		input_set_abs_params(input, ABS_MT_POSITION_X,
61362306a36Sopenharmony_ci				     MOUSE_MIN_X, MOUSE_MAX_X, 4, 0);
61462306a36Sopenharmony_ci		input_set_abs_params(input, ABS_MT_POSITION_Y,
61562306a36Sopenharmony_ci				     MOUSE_MIN_Y, MOUSE_MAX_Y, 4, 0);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci		input_abs_set_res(input, ABS_MT_POSITION_X,
61862306a36Sopenharmony_ci				  MOUSE_RES_X);
61962306a36Sopenharmony_ci		input_abs_set_res(input, ABS_MT_POSITION_Y,
62062306a36Sopenharmony_ci				  MOUSE_RES_Y);
62162306a36Sopenharmony_ci	} else if (input->id.product ==  USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
62262306a36Sopenharmony_ci		input_set_abs_params(input, ABS_MT_PRESSURE, 0, 253, 0, 0);
62362306a36Sopenharmony_ci		input_set_abs_params(input, ABS_PRESSURE, 0, 253, 0, 0);
62462306a36Sopenharmony_ci		input_set_abs_params(input, ABS_MT_ORIENTATION, -3, 4, 0, 0);
62562306a36Sopenharmony_ci		input_set_abs_params(input, ABS_X, TRACKPAD2_MIN_X,
62662306a36Sopenharmony_ci				     TRACKPAD2_MAX_X, 0, 0);
62762306a36Sopenharmony_ci		input_set_abs_params(input, ABS_Y, TRACKPAD2_MIN_Y,
62862306a36Sopenharmony_ci				     TRACKPAD2_MAX_Y, 0, 0);
62962306a36Sopenharmony_ci		input_set_abs_params(input, ABS_MT_POSITION_X,
63062306a36Sopenharmony_ci				     TRACKPAD2_MIN_X, TRACKPAD2_MAX_X, 0, 0);
63162306a36Sopenharmony_ci		input_set_abs_params(input, ABS_MT_POSITION_Y,
63262306a36Sopenharmony_ci				     TRACKPAD2_MIN_Y, TRACKPAD2_MAX_Y, 0, 0);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		input_abs_set_res(input, ABS_X, TRACKPAD2_RES_X);
63562306a36Sopenharmony_ci		input_abs_set_res(input, ABS_Y, TRACKPAD2_RES_Y);
63662306a36Sopenharmony_ci		input_abs_set_res(input, ABS_MT_POSITION_X, TRACKPAD2_RES_X);
63762306a36Sopenharmony_ci		input_abs_set_res(input, ABS_MT_POSITION_Y, TRACKPAD2_RES_Y);
63862306a36Sopenharmony_ci	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
63962306a36Sopenharmony_ci		input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
64062306a36Sopenharmony_ci		input_set_abs_params(input, ABS_X, TRACKPAD_MIN_X,
64162306a36Sopenharmony_ci				     TRACKPAD_MAX_X, 4, 0);
64262306a36Sopenharmony_ci		input_set_abs_params(input, ABS_Y, TRACKPAD_MIN_Y,
64362306a36Sopenharmony_ci				     TRACKPAD_MAX_Y, 4, 0);
64462306a36Sopenharmony_ci		input_set_abs_params(input, ABS_MT_POSITION_X,
64562306a36Sopenharmony_ci				     TRACKPAD_MIN_X, TRACKPAD_MAX_X, 4, 0);
64662306a36Sopenharmony_ci		input_set_abs_params(input, ABS_MT_POSITION_Y,
64762306a36Sopenharmony_ci				     TRACKPAD_MIN_Y, TRACKPAD_MAX_Y, 4, 0);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci		input_abs_set_res(input, ABS_X, TRACKPAD_RES_X);
65062306a36Sopenharmony_ci		input_abs_set_res(input, ABS_Y, TRACKPAD_RES_Y);
65162306a36Sopenharmony_ci		input_abs_set_res(input, ABS_MT_POSITION_X,
65262306a36Sopenharmony_ci				  TRACKPAD_RES_X);
65362306a36Sopenharmony_ci		input_abs_set_res(input, ABS_MT_POSITION_Y,
65462306a36Sopenharmony_ci				  TRACKPAD_RES_Y);
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	input_set_events_per_packet(input, 60);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	if (report_undeciphered &&
66062306a36Sopenharmony_ci	    input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
66162306a36Sopenharmony_ci		__set_bit(EV_MSC, input->evbit);
66262306a36Sopenharmony_ci		__set_bit(MSC_RAW, input->mscbit);
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/*
66662306a36Sopenharmony_ci	 * hid-input may mark device as using autorepeat, but neither
66762306a36Sopenharmony_ci	 * the trackpad, nor the mouse actually want it.
66862306a36Sopenharmony_ci	 */
66962306a36Sopenharmony_ci	__clear_bit(EV_REP, input->evbit);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return 0;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic int magicmouse_input_mapping(struct hid_device *hdev,
67562306a36Sopenharmony_ci		struct hid_input *hi, struct hid_field *field,
67662306a36Sopenharmony_ci		struct hid_usage *usage, unsigned long **bit, int *max)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (!msc->input)
68162306a36Sopenharmony_ci		msc->input = hi->input;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	/* Magic Trackpad does not give relative data after switching to MT */
68462306a36Sopenharmony_ci	if ((hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD ||
68562306a36Sopenharmony_ci	     hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) &&
68662306a36Sopenharmony_ci	    field->flags & HID_MAIN_ITEM_RELATIVE)
68762306a36Sopenharmony_ci		return -1;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	return 0;
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic int magicmouse_input_configured(struct hid_device *hdev,
69362306a36Sopenharmony_ci		struct hid_input *hi)
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
69762306a36Sopenharmony_ci	int ret;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	ret = magicmouse_setup_input(msc->input, hdev);
70062306a36Sopenharmony_ci	if (ret) {
70162306a36Sopenharmony_ci		hid_err(hdev, "magicmouse setup input failed (%d)\n", ret);
70262306a36Sopenharmony_ci		/* clean msc->input to notify probe() of the failure */
70362306a36Sopenharmony_ci		msc->input = NULL;
70462306a36Sopenharmony_ci		return ret;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	return 0;
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic int magicmouse_enable_multitouch(struct hid_device *hdev)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	const u8 *feature;
71362306a36Sopenharmony_ci	const u8 feature_mt[] = { 0xD7, 0x01 };
71462306a36Sopenharmony_ci	const u8 feature_mt_mouse2[] = { 0xF1, 0x02, 0x01 };
71562306a36Sopenharmony_ci	const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 };
71662306a36Sopenharmony_ci	const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 };
71762306a36Sopenharmony_ci	u8 *buf;
71862306a36Sopenharmony_ci	int ret;
71962306a36Sopenharmony_ci	int feature_size;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
72262306a36Sopenharmony_ci		if (hdev->vendor == BT_VENDOR_ID_APPLE) {
72362306a36Sopenharmony_ci			feature_size = sizeof(feature_mt_trackpad2_bt);
72462306a36Sopenharmony_ci			feature = feature_mt_trackpad2_bt;
72562306a36Sopenharmony_ci		} else { /* USB_VENDOR_ID_APPLE */
72662306a36Sopenharmony_ci			feature_size = sizeof(feature_mt_trackpad2_usb);
72762306a36Sopenharmony_ci			feature = feature_mt_trackpad2_usb;
72862306a36Sopenharmony_ci		}
72962306a36Sopenharmony_ci	} else if (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
73062306a36Sopenharmony_ci		feature_size = sizeof(feature_mt_mouse2);
73162306a36Sopenharmony_ci		feature = feature_mt_mouse2;
73262306a36Sopenharmony_ci	} else {
73362306a36Sopenharmony_ci		feature_size = sizeof(feature_mt);
73462306a36Sopenharmony_ci		feature = feature_mt;
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	buf = kmemdup(feature, feature_size, GFP_KERNEL);
73862306a36Sopenharmony_ci	if (!buf)
73962306a36Sopenharmony_ci		return -ENOMEM;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size,
74262306a36Sopenharmony_ci				HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
74362306a36Sopenharmony_ci	kfree(buf);
74462306a36Sopenharmony_ci	return ret;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic void magicmouse_enable_mt_work(struct work_struct *work)
74862306a36Sopenharmony_ci{
74962306a36Sopenharmony_ci	struct magicmouse_sc *msc =
75062306a36Sopenharmony_ci		container_of(work, struct magicmouse_sc, work.work);
75162306a36Sopenharmony_ci	int ret;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	ret = magicmouse_enable_multitouch(msc->hdev);
75462306a36Sopenharmony_ci	if (ret < 0)
75562306a36Sopenharmony_ci		hid_err(msc->hdev, "unable to request touch data (%d)\n", ret);
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic int magicmouse_fetch_battery(struct hid_device *hdev)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci#ifdef CONFIG_HID_BATTERY_STRENGTH
76162306a36Sopenharmony_ci	struct hid_report_enum *report_enum;
76262306a36Sopenharmony_ci	struct hid_report *report;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE ||
76562306a36Sopenharmony_ci	    (hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
76662306a36Sopenharmony_ci	     hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2))
76762306a36Sopenharmony_ci		return -1;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	report_enum = &hdev->report_enum[hdev->battery_report_type];
77062306a36Sopenharmony_ci	report = report_enum->report_id_hash[hdev->battery_report_id];
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if (!report || report->maxfield < 1)
77362306a36Sopenharmony_ci		return -1;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (hdev->battery_capacity == hdev->battery_max)
77662306a36Sopenharmony_ci		return -1;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
77962306a36Sopenharmony_ci	return 0;
78062306a36Sopenharmony_ci#else
78162306a36Sopenharmony_ci	return -1;
78262306a36Sopenharmony_ci#endif
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistatic void magicmouse_battery_timer_tick(struct timer_list *t)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	struct magicmouse_sc *msc = from_timer(msc, t, battery_timer);
78862306a36Sopenharmony_ci	struct hid_device *hdev = msc->hdev;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	if (magicmouse_fetch_battery(hdev) == 0) {
79162306a36Sopenharmony_ci		mod_timer(&msc->battery_timer,
79262306a36Sopenharmony_ci			  jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS));
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic int magicmouse_probe(struct hid_device *hdev,
79762306a36Sopenharmony_ci	const struct hid_device_id *id)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	struct magicmouse_sc *msc;
80062306a36Sopenharmony_ci	struct hid_report *report;
80162306a36Sopenharmony_ci	int ret;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	msc = devm_kzalloc(&hdev->dev, sizeof(*msc), GFP_KERNEL);
80462306a36Sopenharmony_ci	if (msc == NULL) {
80562306a36Sopenharmony_ci		hid_err(hdev, "can't alloc magicmouse descriptor\n");
80662306a36Sopenharmony_ci		return -ENOMEM;
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
81062306a36Sopenharmony_ci	msc->hdev = hdev;
81162306a36Sopenharmony_ci	INIT_DEFERRABLE_WORK(&msc->work, magicmouse_enable_mt_work);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	msc->quirks = id->driver_data;
81462306a36Sopenharmony_ci	hid_set_drvdata(hdev, msc);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	ret = hid_parse(hdev);
81762306a36Sopenharmony_ci	if (ret) {
81862306a36Sopenharmony_ci		hid_err(hdev, "magicmouse hid parse failed\n");
81962306a36Sopenharmony_ci		return ret;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
82362306a36Sopenharmony_ci	if (ret) {
82462306a36Sopenharmony_ci		hid_err(hdev, "magicmouse hw start failed\n");
82562306a36Sopenharmony_ci		return ret;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0);
82962306a36Sopenharmony_ci	mod_timer(&msc->battery_timer,
83062306a36Sopenharmony_ci		  jiffies + msecs_to_jiffies(USB_BATTERY_TIMEOUT_MS));
83162306a36Sopenharmony_ci	magicmouse_fetch_battery(hdev);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	if (id->vendor == USB_VENDOR_ID_APPLE &&
83462306a36Sopenharmony_ci	    (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
83562306a36Sopenharmony_ci	     (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && hdev->type != HID_TYPE_USBMOUSE)))
83662306a36Sopenharmony_ci		return 0;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (!msc->input) {
83962306a36Sopenharmony_ci		hid_err(hdev, "magicmouse input not registered\n");
84062306a36Sopenharmony_ci		ret = -ENOMEM;
84162306a36Sopenharmony_ci		goto err_stop_hw;
84262306a36Sopenharmony_ci	}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
84562306a36Sopenharmony_ci		report = hid_register_report(hdev, HID_INPUT_REPORT,
84662306a36Sopenharmony_ci			MOUSE_REPORT_ID, 0);
84762306a36Sopenharmony_ci	else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
84862306a36Sopenharmony_ci		report = hid_register_report(hdev, HID_INPUT_REPORT,
84962306a36Sopenharmony_ci			MOUSE2_REPORT_ID, 0);
85062306a36Sopenharmony_ci	else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
85162306a36Sopenharmony_ci		if (id->vendor == BT_VENDOR_ID_APPLE)
85262306a36Sopenharmony_ci			report = hid_register_report(hdev, HID_INPUT_REPORT,
85362306a36Sopenharmony_ci				TRACKPAD2_BT_REPORT_ID, 0);
85462306a36Sopenharmony_ci		else /* USB_VENDOR_ID_APPLE */
85562306a36Sopenharmony_ci			report = hid_register_report(hdev, HID_INPUT_REPORT,
85662306a36Sopenharmony_ci				TRACKPAD2_USB_REPORT_ID, 0);
85762306a36Sopenharmony_ci	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
85862306a36Sopenharmony_ci		report = hid_register_report(hdev, HID_INPUT_REPORT,
85962306a36Sopenharmony_ci			TRACKPAD_REPORT_ID, 0);
86062306a36Sopenharmony_ci		report = hid_register_report(hdev, HID_INPUT_REPORT,
86162306a36Sopenharmony_ci			DOUBLE_REPORT_ID, 0);
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	if (!report) {
86562306a36Sopenharmony_ci		hid_err(hdev, "unable to register touch report\n");
86662306a36Sopenharmony_ci		ret = -ENOMEM;
86762306a36Sopenharmony_ci		goto err_stop_hw;
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci	report->size = 6;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	/*
87262306a36Sopenharmony_ci	 * Some devices repond with 'invalid report id' when feature
87362306a36Sopenharmony_ci	 * report switching it into multitouch mode is sent to it.
87462306a36Sopenharmony_ci	 *
87562306a36Sopenharmony_ci	 * This results in -EIO from the _raw low-level transport callback,
87662306a36Sopenharmony_ci	 * but there seems to be no other way of switching the mode.
87762306a36Sopenharmony_ci	 * Thus the super-ugly hacky success check below.
87862306a36Sopenharmony_ci	 */
87962306a36Sopenharmony_ci	ret = magicmouse_enable_multitouch(hdev);
88062306a36Sopenharmony_ci	if (ret != -EIO && ret < 0) {
88162306a36Sopenharmony_ci		hid_err(hdev, "unable to request touch data (%d)\n", ret);
88262306a36Sopenharmony_ci		goto err_stop_hw;
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci	if (ret == -EIO && id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
88562306a36Sopenharmony_ci		schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	return 0;
88962306a36Sopenharmony_cierr_stop_hw:
89062306a36Sopenharmony_ci	del_timer_sync(&msc->battery_timer);
89162306a36Sopenharmony_ci	hid_hw_stop(hdev);
89262306a36Sopenharmony_ci	return ret;
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistatic void magicmouse_remove(struct hid_device *hdev)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	if (msc) {
90062306a36Sopenharmony_ci		cancel_delayed_work_sync(&msc->work);
90162306a36Sopenharmony_ci		del_timer_sync(&msc->battery_timer);
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	hid_hw_stop(hdev);
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
90862306a36Sopenharmony_ci				     unsigned int *rsize)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	/*
91162306a36Sopenharmony_ci	 * Change the usage from:
91262306a36Sopenharmony_ci	 *   0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1)  0
91362306a36Sopenharmony_ci	 *   0x09, 0x0b,       // Usage (Vendor Usage 0x0b)           3
91462306a36Sopenharmony_ci	 * To:
91562306a36Sopenharmony_ci	 *   0x05, 0x01,       // Usage Page (Generic Desktop)        0
91662306a36Sopenharmony_ci	 *   0x09, 0x02,       // Usage (Mouse)                       2
91762306a36Sopenharmony_ci	 */
91862306a36Sopenharmony_ci	if (hdev->vendor == USB_VENDOR_ID_APPLE &&
91962306a36Sopenharmony_ci	    (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 ||
92062306a36Sopenharmony_ci	     hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) &&
92162306a36Sopenharmony_ci	    *rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
92262306a36Sopenharmony_ci		hid_info(hdev,
92362306a36Sopenharmony_ci			 "fixing up magicmouse battery report descriptor\n");
92462306a36Sopenharmony_ci		*rsize = *rsize - 1;
92562306a36Sopenharmony_ci		rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL);
92662306a36Sopenharmony_ci		if (!rdesc)
92762306a36Sopenharmony_ci			return NULL;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		rdesc[0] = 0x05;
93062306a36Sopenharmony_ci		rdesc[1] = 0x01;
93162306a36Sopenharmony_ci		rdesc[2] = 0x09;
93262306a36Sopenharmony_ci		rdesc[3] = 0x02;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return rdesc;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic const struct hid_device_id magic_mice[] = {
93962306a36Sopenharmony_ci	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
94062306a36Sopenharmony_ci		USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
94162306a36Sopenharmony_ci	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
94262306a36Sopenharmony_ci		USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 },
94362306a36Sopenharmony_ci	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
94462306a36Sopenharmony_ci		USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 },
94562306a36Sopenharmony_ci	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
94662306a36Sopenharmony_ci		USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 },
94762306a36Sopenharmony_ci	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
94862306a36Sopenharmony_ci		USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 },
94962306a36Sopenharmony_ci	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
95062306a36Sopenharmony_ci		USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 },
95162306a36Sopenharmony_ci	{ }
95262306a36Sopenharmony_ci};
95362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(hid, magic_mice);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistatic struct hid_driver magicmouse_driver = {
95662306a36Sopenharmony_ci	.name = "magicmouse",
95762306a36Sopenharmony_ci	.id_table = magic_mice,
95862306a36Sopenharmony_ci	.probe = magicmouse_probe,
95962306a36Sopenharmony_ci	.remove = magicmouse_remove,
96062306a36Sopenharmony_ci	.report_fixup = magicmouse_report_fixup,
96162306a36Sopenharmony_ci	.raw_event = magicmouse_raw_event,
96262306a36Sopenharmony_ci	.event = magicmouse_event,
96362306a36Sopenharmony_ci	.input_mapping = magicmouse_input_mapping,
96462306a36Sopenharmony_ci	.input_configured = magicmouse_input_configured,
96562306a36Sopenharmony_ci};
96662306a36Sopenharmony_cimodule_hid_driver(magicmouse_driver);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
969