All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] Hid: add Apple Magic Mouse 2 support
@ 2021-03-30 11:33 John Chen
  2021-03-30 11:33 ` [PATCH v2 1/4] HID: magicmouse: " John Chen
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: John Chen @ 2021-03-30 11:33 UTC (permalink / raw)
  To: linux-input
  Cc: Rohit Pidaparthi, RicardoEPRodrigues, Jiri Kosina,
	Benjamin Tissoires, John Chen

The HID descriptor of Magic Mouse 2 contains BTN_LEFT, BTN_RIGHT, REL_X,
REL_Y, whether it's charging, whether it's fully charged, and battery
capacity.

$ xxd -p report_descriptor
05010902a101851205091901290215002501950275018102950175068103
05010901a1001601f826ff073601fb46ff046513550d0930093175109502
8106750895028101c00602ff09558555150026ff0075089540b1a2c00600
ff0914a10185900584750195031500250109610585094409468102950581
0175089501150026ff0009658102c000

As hidinput can handle the BTNs and RELs, the Magic Mouse 2 already
functions as a basic mouse. Nevertheless, It should be reasonable to
extend hid-magicmouse to support Magic Mouse 2 as well. Furthermore,
hidinput is patched to handle the battery capacity.

This work is based on Recardo's, which is in turned based on Rohitpid's.
Their GitHub repositories are linked below:
https://github.com/RicardoEPRodrigues/magicmouse-hid
https://github.com/rohitpid/Linux-Magic-Trackpad-2-Driver

Change v1->v2: An extra parameter is passed to hidinput_setup_battery
instead of directly modifying battery_{min,max}.

John Chen (4):
  HID: magicmouse: add Apple Magic Mouse 2 support
  HID: magicmouse: fix 3 button emulation of Mouse 2
  HID: magicmouse: fix reconnection of Magic Mouse 2
  HID: input: map battery capacity (00850065)

 drivers/hid/hid-debug.c      |   1 +
 drivers/hid/hid-ids.h        |   1 +
 drivers/hid/hid-input.c      |  22 +++--
 drivers/hid/hid-magicmouse.c | 156 ++++++++++++++++++++++++++++-------
 include/linux/hid.h          |   3 +
 5 files changed, 145 insertions(+), 38 deletions(-)

-- 
2.31.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 1/4] HID: magicmouse: add Apple Magic Mouse 2 support
  2021-03-30 11:33 [PATCH v2 0/4] Hid: add Apple Magic Mouse 2 support John Chen
@ 2021-03-30 11:33 ` John Chen
  2021-04-05 17:30   ` Felix Hädicke
  2021-03-30 11:33 ` [PATCH v2 2/4] HID: magicmouse: fix 3 button emulation of Mouse 2 John Chen
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: John Chen @ 2021-03-30 11:33 UTC (permalink / raw)
  To: linux-input
  Cc: Rohit Pidaparthi, RicardoEPRodrigues, Jiri Kosina,
	Benjamin Tissoires, John Chen

Bluetooth device
	Vendor 004c (Apple)
	Device 0269 (Magic Mouse 2)

Add support for Apple Magic Mouse 2, putting the device in multi-touch
mode.

Co-authored-by: Rohit Pidaparthi <rohitpid@gmail.com>
Co-authored-by: RicardoEPRodrigues <ricardo.e.p.rodrigues@gmail.com>
Signed-off-by: John Chen <johnchen902@gmail.com>
---
 drivers/hid/hid-ids.h        |  1 +
 drivers/hid/hid-magicmouse.c | 53 ++++++++++++++++++++++++++++++++----
 2 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index e42aaae3138f..fa0edf03570a 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -93,6 +93,7 @@
 #define BT_VENDOR_ID_APPLE		0x004c
 #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE	0x0304
 #define USB_DEVICE_ID_APPLE_MAGICMOUSE	0x030d
+#define USB_DEVICE_ID_APPLE_MAGICMOUSE2	0x0269
 #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD	0x030e
 #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2	0x0265
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI	0x020e
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index abd86903875f..7aad6ca56780 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -54,6 +54,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
 #define TRACKPAD2_USB_REPORT_ID 0x02
 #define TRACKPAD2_BT_REPORT_ID 0x31
 #define MOUSE_REPORT_ID    0x29
+#define MOUSE2_REPORT_ID   0x12
 #define DOUBLE_REPORT_ID   0xf7
 /* These definitions are not precise, but they're close enough.  (Bits
  * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
@@ -195,7 +196,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
 	int id, x, y, size, orientation, touch_major, touch_minor, state, down;
 	int pressure = 0;
 
-	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
+	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
 		id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf;
 		x = (tdata[1] << 28 | tdata[0] << 20) >> 20;
 		y = -((tdata[2] << 24 | tdata[1] << 16) >> 20);
@@ -296,7 +298,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
 			input_report_abs(input, ABS_MT_PRESSURE, pressure);
 
 		if (report_undeciphered) {
-			if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
+			if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
+			    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
 				input_event(input, EV_MSC, MSC_RAW, tdata[7]);
 			else if (input->id.product !=
 					USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)
@@ -380,6 +383,34 @@ static int magicmouse_raw_event(struct hid_device *hdev,
 		 * ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
 		 */
 		break;
+	case MOUSE2_REPORT_ID:
+		/* Size is either 8 or (14 + 8 * N) */
+		if (size != 8 && (size < 14 || (size - 14) % 8 != 0))
+			return 0;
+		npoints = (size - 14) / 8;
+		if (npoints > 15) {
+			hid_warn(hdev, "invalid size value (%d) for MOUSE2_REPORT_ID\n",
+					size);
+			return 0;
+		}
+		msc->ntouches = 0;
+		for (ii = 0; ii < npoints; ii++)
+			magicmouse_emit_touch(msc, ii, data + ii * 8 + 14);
+
+		/* When emulating three-button mode, it is important
+		 * to have the current touch information before
+		 * generating a click event.
+		 */
+		x = (int)((data[3] << 24) | (data[2] << 16)) >> 16;
+		y = (int)((data[5] << 24) | (data[4] << 16)) >> 16;
+		clicks = data[1];
+
+		/* The following bits provide a device specific timestamp. They
+		 * are unused here.
+		 *
+		 * ts = data[11] >> 6 | data[12] << 2 | data[13] << 10;
+		 */
+		break;
 	case DOUBLE_REPORT_ID:
 		/* Sometimes the trackpad sends two touch reports in one
 		 * packet.
@@ -392,7 +423,8 @@ static int magicmouse_raw_event(struct hid_device *hdev,
 		return 0;
 	}
 
-	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
+	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
 		magicmouse_emit_buttons(msc, clicks & 3);
 		input_report_rel(input, REL_X, x);
 		input_report_rel(input, REL_Y, y);
@@ -415,7 +447,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
 
 	__set_bit(EV_KEY, input->evbit);
 
-	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
+	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
 		__set_bit(BTN_LEFT, input->keybit);
 		__set_bit(BTN_RIGHT, input->keybit);
 		if (emulate_3button)
@@ -480,7 +513,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
 	 * the origin at the same position, and just uses the additive
 	 * inverse of the reported Y.
 	 */
-	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
+	    input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
 		input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
 		input_set_abs_params(input, ABS_MT_POSITION_X,
 				     MOUSE_MIN_X, MOUSE_MAX_X, 4, 0);
@@ -586,6 +620,7 @@ static int magicmouse_probe(struct hid_device *hdev,
 {
 	const u8 *feature;
 	const u8 feature_mt[] = { 0xD7, 0x01 };
+	const u8 feature_mt_mouse2[] = { 0xF1, 0x02, 0x01 };
 	const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 };
 	const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 };
 	u8 *buf;
@@ -631,6 +666,9 @@ static int magicmouse_probe(struct hid_device *hdev,
 	if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
 		report = hid_register_report(hdev, HID_INPUT_REPORT,
 			MOUSE_REPORT_ID, 0);
+	else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
+		report = hid_register_report(hdev, HID_INPUT_REPORT,
+			MOUSE2_REPORT_ID, 0);
 	else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
 		if (id->vendor == BT_VENDOR_ID_APPLE)
 			report = hid_register_report(hdev, HID_INPUT_REPORT,
@@ -660,6 +698,9 @@ static int magicmouse_probe(struct hid_device *hdev,
 			feature_size = sizeof(feature_mt_trackpad2_usb);
 			feature = feature_mt_trackpad2_usb;
 		}
+	} else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
+		feature_size = sizeof(feature_mt_mouse2);
+		feature = feature_mt_mouse2;
 	} else {
 		feature_size = sizeof(feature_mt);
 		feature = feature_mt;
@@ -696,6 +737,8 @@ static int magicmouse_probe(struct hid_device *hdev,
 static const struct hid_device_id magic_mice[] = {
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
 		USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
+	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
+		USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
 		USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 },
 	{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 2/4] HID: magicmouse: fix 3 button emulation of Mouse 2
  2021-03-30 11:33 [PATCH v2 0/4] Hid: add Apple Magic Mouse 2 support John Chen
  2021-03-30 11:33 ` [PATCH v2 1/4] HID: magicmouse: " John Chen
@ 2021-03-30 11:33 ` John Chen
  2021-04-07 11:15   ` Jiri Kosina
  2021-03-30 11:33 ` [PATCH v2 3/4] HID: magicmouse: fix reconnection of Magic " John Chen
  2021-03-30 11:33 ` [PATCH v2 4/4] HID: input: map battery capacity (00850065) John Chen
  3 siblings, 1 reply; 7+ messages in thread
From: John Chen @ 2021-03-30 11:33 UTC (permalink / raw)
  To: linux-input
  Cc: Rohit Pidaparthi, RicardoEPRodrigues, Jiri Kosina,
	Benjamin Tissoires, John Chen

It is observed that, with 3 button emulation, when middle button is
clicked, either the left button or right button is clicked as well. It
is caused by hidinput "correctly" acting on the event, oblivious to the
3 button emulation.

As raw_event has taken care of everything, no further processing is
needed. However, the only way to stop at raw_event is to return an error
(negative) value. Therefore, the processing is stopped at event instead.

Signed-off-by: John Chen <johnchen902@gmail.com>
---
 drivers/hid/hid-magicmouse.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 7aad6ca56780..c646b4cd3783 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -440,6 +440,21 @@ static int magicmouse_raw_event(struct hid_device *hdev,
 	return 1;
 }
 
+static int magicmouse_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+	if (msc->input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
+	    field->report->id == MOUSE2_REPORT_ID) {
+		// magic_mouse_raw_event has done all the work. Skip hidinput.
+		//
+		// Specifically, hidinput may modify BTN_LEFT and BTN_RIGHT,
+		// breaking emulate_3button.
+		return 1;
+	}
+	return 0;
+}
+
 static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
 {
 	int error;
@@ -754,6 +769,7 @@ static struct hid_driver magicmouse_driver = {
 	.id_table = magic_mice,
 	.probe = magicmouse_probe,
 	.raw_event = magicmouse_raw_event,
+	.event = magicmouse_event,
 	.input_mapping = magicmouse_input_mapping,
 	.input_configured = magicmouse_input_configured,
 };
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 3/4] HID: magicmouse: fix reconnection of Magic Mouse 2
  2021-03-30 11:33 [PATCH v2 0/4] Hid: add Apple Magic Mouse 2 support John Chen
  2021-03-30 11:33 ` [PATCH v2 1/4] HID: magicmouse: " John Chen
  2021-03-30 11:33 ` [PATCH v2 2/4] HID: magicmouse: fix 3 button emulation of Mouse 2 John Chen
@ 2021-03-30 11:33 ` John Chen
  2021-03-30 11:33 ` [PATCH v2 4/4] HID: input: map battery capacity (00850065) John Chen
  3 siblings, 0 replies; 7+ messages in thread
From: John Chen @ 2021-03-30 11:33 UTC (permalink / raw)
  To: linux-input
  Cc: Rohit Pidaparthi, RicardoEPRodrigues, Jiri Kosina,
	Benjamin Tissoires, John Chen

It is observed that the Magic Mouse 2 would not enter multi-touch mode
unless the mouse is connected before loading the module. It seems to be
a quirk specific to Magic Mouse 2

Retrying after 500ms fixes the problem for me. The delay can't be
reduced much further --- 300ms didn't work for me. Retrying immediately
after receiving an event didn't work either.

Signed-off-by: John Chen <johnchen902@gmail.com>
---
 drivers/hid/hid-magicmouse.c | 93 ++++++++++++++++++++++++------------
 1 file changed, 63 insertions(+), 30 deletions(-)

diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index c646b4cd3783..69aefef9fe07 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -16,6 +16,7 @@
 #include <linux/input/mt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/workqueue.h>
 
 #include "hid-ids.h"
 
@@ -128,6 +129,9 @@ struct magicmouse_sc {
 		u8 size;
 	} touches[16];
 	int tracking_ids[16];
+
+	struct hid_device *hdev;
+	struct delayed_work work;
 };
 
 static int magicmouse_firm_touch(struct magicmouse_sc *msc)
@@ -629,9 +633,7 @@ static int magicmouse_input_configured(struct hid_device *hdev,
 	return 0;
 }
 
-
-static int magicmouse_probe(struct hid_device *hdev,
-	const struct hid_device_id *id)
+static int magicmouse_enable_multitouch(struct hid_device *hdev)
 {
 	const u8 *feature;
 	const u8 feature_mt[] = { 0xD7, 0x01 };
@@ -639,10 +641,52 @@ static int magicmouse_probe(struct hid_device *hdev,
 	const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 };
 	const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 };
 	u8 *buf;
+	int ret;
+	int feature_size;
+
+	if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
+		if (hdev->vendor == BT_VENDOR_ID_APPLE) {
+			feature_size = sizeof(feature_mt_trackpad2_bt);
+			feature = feature_mt_trackpad2_bt;
+		} else { /* USB_VENDOR_ID_APPLE */
+			feature_size = sizeof(feature_mt_trackpad2_usb);
+			feature = feature_mt_trackpad2_usb;
+		}
+	} else if (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
+		feature_size = sizeof(feature_mt_mouse2);
+		feature = feature_mt_mouse2;
+	} else {
+		feature_size = sizeof(feature_mt);
+		feature = feature_mt;
+	}
+
+	buf = kmemdup(feature, feature_size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size,
+				HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+	kfree(buf);
+	return ret;
+}
+
+static void magicmouse_enable_mt_work(struct work_struct *work)
+{
+	struct magicmouse_sc *msc =
+		container_of(work, struct magicmouse_sc, work.work);
+	int ret;
+
+	ret = magicmouse_enable_multitouch(msc->hdev);
+	if (ret < 0)
+		hid_err(msc->hdev, "unable to request touch data (%d)\n", ret);
+}
+
+static int magicmouse_probe(struct hid_device *hdev,
+	const struct hid_device_id *id)
+{
 	struct magicmouse_sc *msc;
 	struct hid_report *report;
 	int ret;
-	int feature_size;
 
 	if (id->vendor == USB_VENDOR_ID_APPLE &&
 	    id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
@@ -656,6 +700,8 @@ static int magicmouse_probe(struct hid_device *hdev,
 	}
 
 	msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
+	msc->hdev = hdev;
+	INIT_DEFERRABLE_WORK(&msc->work, magicmouse_enable_mt_work);
 
 	msc->quirks = id->driver_data;
 	hid_set_drvdata(hdev, msc);
@@ -705,28 +751,6 @@ static int magicmouse_probe(struct hid_device *hdev,
 	}
 	report->size = 6;
 
-	if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
-		if (id->vendor == BT_VENDOR_ID_APPLE) {
-			feature_size = sizeof(feature_mt_trackpad2_bt);
-			feature = feature_mt_trackpad2_bt;
-		} else { /* USB_VENDOR_ID_APPLE */
-			feature_size = sizeof(feature_mt_trackpad2_usb);
-			feature = feature_mt_trackpad2_usb;
-		}
-	} else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
-		feature_size = sizeof(feature_mt_mouse2);
-		feature = feature_mt_mouse2;
-	} else {
-		feature_size = sizeof(feature_mt);
-		feature = feature_mt;
-	}
-
-	buf = kmemdup(feature, feature_size, GFP_KERNEL);
-	if (!buf) {
-		ret = -ENOMEM;
-		goto err_stop_hw;
-	}
-
 	/*
 	 * Some devices repond with 'invalid report id' when feature
 	 * report switching it into multitouch mode is sent to it.
@@ -735,13 +759,14 @@ static int magicmouse_probe(struct hid_device *hdev,
 	 * but there seems to be no other way of switching the mode.
 	 * Thus the super-ugly hacky success check below.
 	 */
-	ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size,
-				HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
-	kfree(buf);
-	if (ret != -EIO && ret != feature_size) {
+	ret = magicmouse_enable_multitouch(hdev);
+	if (ret != -EIO && ret < 0) {
 		hid_err(hdev, "unable to request touch data (%d)\n", ret);
 		goto err_stop_hw;
 	}
+	if (ret == -EIO && id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
+		schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
+	}
 
 	return 0;
 err_stop_hw:
@@ -749,6 +774,13 @@ static int magicmouse_probe(struct hid_device *hdev,
 	return ret;
 }
 
+static void magicmouse_remove(struct hid_device *hdev)
+{
+	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+	cancel_delayed_work_sync(&msc->work);
+	hid_hw_stop(hdev);
+}
+
 static const struct hid_device_id magic_mice[] = {
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
 		USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
@@ -768,6 +800,7 @@ static struct hid_driver magicmouse_driver = {
 	.name = "magicmouse",
 	.id_table = magic_mice,
 	.probe = magicmouse_probe,
+	.remove = magicmouse_remove,
 	.raw_event = magicmouse_raw_event,
 	.event = magicmouse_event,
 	.input_mapping = magicmouse_input_mapping,
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 4/4] HID: input: map battery capacity (00850065)
  2021-03-30 11:33 [PATCH v2 0/4] Hid: add Apple Magic Mouse 2 support John Chen
                   ` (2 preceding siblings ...)
  2021-03-30 11:33 ` [PATCH v2 3/4] HID: magicmouse: fix reconnection of Magic " John Chen
@ 2021-03-30 11:33 ` John Chen
  3 siblings, 0 replies; 7+ messages in thread
From: John Chen @ 2021-03-30 11:33 UTC (permalink / raw)
  To: linux-input
  Cc: Rohit Pidaparthi, RicardoEPRodrigues, Jiri Kosina,
	Benjamin Tissoires, John Chen

This is the capacity in percentage, relative to design capacity.
Specifically, it is present in Apple Magic Mouse 2.

In contrast, usage 00850064 is also the capacity in percentage, but is
relative to full capacity. It is not mapped here because I don't have
such device.

Signed-off-by: John Chen <johnchen902@gmail.com>
---
 drivers/hid/hid-debug.c |  1 +
 drivers/hid/hid-input.c | 22 ++++++++++++++++------
 include/linux/hid.h     |  3 +++
 3 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index d7eaf9100370..59f8d716d78f 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -417,6 +417,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
     { 0x85, 0x44, "Charging" },
     { 0x85, 0x45, "Discharging" },
     { 0x85, 0x4b, "NeedReplacement" },
+    { 0x85, 0x65, "AbsoluteStateOfCharge" },
     { 0x85, 0x66, "RemainingCapacity" },
     { 0x85, 0x68, "RunTimeToEmpty" },
     { 0x85, 0x6a, "AverageTimeToFull" },
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 236bccd37760..18f5e28d475c 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -435,7 +435,8 @@ static int hidinput_get_battery_property(struct power_supply *psy,
 	return ret;
 }
 
-static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field)
+static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
+				  struct hid_field *field, bool is_percentage)
 {
 	struct power_supply_desc *psy_desc;
 	struct power_supply_config psy_cfg = { .drv_data = dev, };
@@ -475,7 +476,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
 	min = field->logical_minimum;
 	max = field->logical_maximum;
 
-	if (quirks & HID_BATTERY_QUIRK_PERCENT) {
+	if (is_percentage || (quirks & HID_BATTERY_QUIRK_PERCENT)) {
 		min = 0;
 		max = 100;
 	}
@@ -552,7 +553,7 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
 }
 #else  /* !CONFIG_HID_BATTERY_STRENGTH */
 static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
-				  struct hid_field *field)
+				  struct hid_field *field, bool is_percentage)
 {
 	return 0;
 }
@@ -806,7 +807,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 			break;
 
 		case 0x3b: /* Battery Strength */
-			hidinput_setup_battery(device, HID_INPUT_REPORT, field);
+			hidinput_setup_battery(device, HID_INPUT_REPORT, field, false);
 			usage->type = EV_PWR;
 			return;
 
@@ -1068,7 +1069,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 	case HID_UP_GENDEVCTRLS:
 		switch (usage->hid) {
 		case HID_DC_BATTERYSTRENGTH:
-			hidinput_setup_battery(device, HID_INPUT_REPORT, field);
+			hidinput_setup_battery(device, HID_INPUT_REPORT, field, false);
+			usage->type = EV_PWR;
+			return;
+		}
+		goto unknown;
+
+	case HID_UP_BATTERY:
+		switch (usage->hid) {
+		case HID_BAT_ABSOLUTESTATEOFCHARGE:
+			hidinput_setup_battery(device, HID_INPUT_REPORT, field, true);
 			usage->type = EV_PWR;
 			return;
 		}
@@ -1672,7 +1682,7 @@ static void report_features(struct hid_device *hid)
 				/* Verify if Battery Strength feature is available */
 				if (usage->hid == HID_DC_BATTERYSTRENGTH)
 					hidinput_setup_battery(hid, HID_FEATURE_REPORT,
-							       rep->field[i]);
+							       rep->field[i], false);
 
 				if (drv->feature_mapping)
 					drv->feature_mapping(hid, rep->field[i], usage);
diff --git a/include/linux/hid.h b/include/linux/hid.h
index ef702b3f56e3..b40e1abbe11d 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -153,6 +153,7 @@ struct hid_item {
 #define HID_UP_CONSUMER		0x000c0000
 #define HID_UP_DIGITIZER	0x000d0000
 #define HID_UP_PID		0x000f0000
+#define HID_UP_BATTERY		0x00850000
 #define HID_UP_HPVENDOR         0xff7f0000
 #define HID_UP_HPVENDOR2        0xff010000
 #define HID_UP_MSVENDOR		0xff000000
@@ -297,6 +298,8 @@ struct hid_item {
 #define HID_DG_TOOLSERIALNUMBER	0x000d005b
 #define HID_DG_LATENCYMODE	0x000d0060
 
+#define HID_BAT_ABSOLUTESTATEOFCHARGE	0x00850065
+
 #define HID_VD_ASUS_CUSTOM_MEDIA_KEYS	0xff310076
 /*
  * HID report types --- Ouch! HID spec says 1 2 3!
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 1/4] HID: magicmouse: add Apple Magic Mouse 2 support
  2021-03-30 11:33 ` [PATCH v2 1/4] HID: magicmouse: " John Chen
@ 2021-04-05 17:30   ` Felix Hädicke
  0 siblings, 0 replies; 7+ messages in thread
From: Felix Hädicke @ 2021-04-05 17:30 UTC (permalink / raw)
  To: John Chen, linux-input

On Tue, 2021-03-30 at 19:33 +0800, John Chen wrote:
> Bluetooth device
>         Vendor 004c (Apple)
>         Device 0269 (Magic Mouse 2)
> 
> Add support for Apple Magic Mouse 2, putting the device in multi-
> touch
> mode.
> 
> Co-authored-by: Rohit Pidaparthi <rohitpid@gmail.com>
> Co-authored-by: RicardoEPRodrigues <ricardo.e.p.rodrigues@gmail.com>
> Signed-off-by: John Chen <johnchen902@gmail.com>
> ---
>  drivers/hid/hid-ids.h        |  1 +
>  drivers/hid/hid-magicmouse.c | 53 ++++++++++++++++++++++++++++++++--
> --
>  2 files changed, 49 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index e42aaae3138f..fa0edf03570a 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -93,6 +93,7 @@
>  #define BT_VENDOR_ID_APPLE             0x004c
>  #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE        0x0304
>  #define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
> +#define USB_DEVICE_ID_APPLE_MAGICMOUSE2        0x0269

This device ID should probably also be added to the
hid_have_special_driver list in hid-quirks.c.

>  #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD      0x030e
>  #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2     0x0265
>  #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI      0x020e
> diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-
> magicmouse.c
> index abd86903875f..7aad6ca56780 100644
> --- a/drivers/hid/hid-magicmouse.c
> +++ b/drivers/hid/hid-magicmouse.c
> @@ -54,6 +54,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report
> undeciphered multi-touch state fie
>  #define TRACKPAD2_USB_REPORT_ID 0x02
>  #define TRACKPAD2_BT_REPORT_ID 0x31
>  #define MOUSE_REPORT_ID    0x29
> +#define MOUSE2_REPORT_ID   0x12
>  #define DOUBLE_REPORT_ID   0xf7
>  /* These definitions are not precise, but they're close enough. 
> (Bits
>   * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70
> seem
> @@ -195,7 +196,8 @@ static void magicmouse_emit_touch(struct
> magicmouse_sc *msc, int raw_id, u8 *tda
>         int id, x, y, size, orientation, touch_major, touch_minor,
> state, down;
>         int pressure = 0;
>  
> -       if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
> +       if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
> +           input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
>                 id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf;
>                 x = (tdata[1] << 28 | tdata[0] << 20) >> 20;
>                 y = -((tdata[2] << 24 | tdata[1] << 16) >> 20);
> @@ -296,7 +298,8 @@ static void magicmouse_emit_touch(struct
> magicmouse_sc *msc, int raw_id, u8 *tda
>                         input_report_abs(input, ABS_MT_PRESSURE,
> pressure);
>  
>                 if (report_undeciphered) {
> -                       if (input->id.product ==
> USB_DEVICE_ID_APPLE_MAGICMOUSE)
> +                       if (input->id.product ==
> USB_DEVICE_ID_APPLE_MAGICMOUSE ||
> +                           input->id.product ==
> USB_DEVICE_ID_APPLE_MAGICMOUSE2)
>                                 input_event(input, EV_MSC, MSC_RAW,
> tdata[7]);
>                         else if (input->id.product !=
>                                         USB_DEVICE_ID_APPLE_MAGICTRAC
> KPAD2)
> @@ -380,6 +383,34 @@ static int magicmouse_raw_event(struct
> hid_device *hdev,
>                  * ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
>                  */
>                 break;
> +       case MOUSE2_REPORT_ID:
> +               /* Size is either 8 or (14 + 8 * N) */
> +               if (size != 8 && (size < 14 || (size - 14) % 8 != 0))
> +                       return 0;
> +               npoints = (size - 14) / 8;
> +               if (npoints > 15) {
> +                       hid_warn(hdev, "invalid size value (%d) for
> MOUSE2_REPORT_ID\n",
> +                                       size);
> +                       return 0;
> +               }
> +               msc->ntouches = 0;
> +               for (ii = 0; ii < npoints; ii++)
> +                       magicmouse_emit_touch(msc, ii, data + ii * 8
> + 14);
> +
> +               /* When emulating three-button mode, it is important
> +                * to have the current touch information before
> +                * generating a click event.
> +                */
> +               x = (int)((data[3] << 24) | (data[2] << 16)) >> 16;
> +               y = (int)((data[5] << 24) | (data[4] << 16)) >> 16;
> +               clicks = data[1];
> +
> +               /* The following bits provide a device specific
> timestamp. They
> +                * are unused here.
> +                *
> +                * ts = data[11] >> 6 | data[12] << 2 | data[13] <<
> 10;
> +                */
> +               break;
>         case DOUBLE_REPORT_ID:
>                 /* Sometimes the trackpad sends two touch reports in
> one
>                  * packet.
> @@ -392,7 +423,8 @@ static int magicmouse_raw_event(struct hid_device
> *hdev,
>                 return 0;
>         }
>  
> -       if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
> +       if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
> +           input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
>                 magicmouse_emit_buttons(msc, clicks & 3);
>                 input_report_rel(input, REL_X, x);
>                 input_report_rel(input, REL_Y, y);
> @@ -415,7 +447,8 @@ static int magicmouse_setup_input(struct
> input_dev *input, struct hid_device *hd
>  
>         __set_bit(EV_KEY, input->evbit);
>  
> -       if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
> +       if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
> +           input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
>                 __set_bit(BTN_LEFT, input->keybit);
>                 __set_bit(BTN_RIGHT, input->keybit);
>                 if (emulate_3button)
> @@ -480,7 +513,8 @@ static int magicmouse_setup_input(struct
> input_dev *input, struct hid_device *hd
>          * the origin at the same position, and just uses the
> additive
>          * inverse of the reported Y.
>          */
> -       if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
> +       if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
> +           input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
>                 input_set_abs_params(input, ABS_MT_ORIENTATION, -31,
> 32, 1, 0);
>                 input_set_abs_params(input, ABS_MT_POSITION_X,
>                                      MOUSE_MIN_X, MOUSE_MAX_X, 4, 0);
> @@ -586,6 +620,7 @@ static int magicmouse_probe(struct hid_device
> *hdev,
>  {
>         const u8 *feature;
>         const u8 feature_mt[] = { 0xD7, 0x01 };
> +       const u8 feature_mt_mouse2[] = { 0xF1, 0x02, 0x01 };
>         const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 };
>         const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 };
>         u8 *buf;
> @@ -631,6 +666,9 @@ static int magicmouse_probe(struct hid_device
> *hdev,
>         if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
>                 report = hid_register_report(hdev, HID_INPUT_REPORT,
>                         MOUSE_REPORT_ID, 0);
> +       else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
> +               report = hid_register_report(hdev, HID_INPUT_REPORT,
> +                       MOUSE2_REPORT_ID, 0);
>         else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
>                 if (id->vendor == BT_VENDOR_ID_APPLE)
>                         report = hid_register_report(hdev,
> HID_INPUT_REPORT,
> @@ -660,6 +698,9 @@ static int magicmouse_probe(struct hid_device
> *hdev,
>                         feature_size =
> sizeof(feature_mt_trackpad2_usb);
>                         feature = feature_mt_trackpad2_usb;
>                 }
> +       } else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
> +               feature_size = sizeof(feature_mt_mouse2);
> +               feature = feature_mt_mouse2;
>         } else {
>                 feature_size = sizeof(feature_mt);
>                 feature = feature_mt;
> @@ -696,6 +737,8 @@ static int magicmouse_probe(struct hid_device
> *hdev,
>  static const struct hid_device_id magic_mice[] = {
>         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
>                 USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
> +       { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
> +               USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 },
>         { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
>                 USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0
> },
>         { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 2/4] HID: magicmouse: fix 3 button emulation of Mouse 2
  2021-03-30 11:33 ` [PATCH v2 2/4] HID: magicmouse: fix 3 button emulation of Mouse 2 John Chen
@ 2021-04-07 11:15   ` Jiri Kosina
  0 siblings, 0 replies; 7+ messages in thread
From: Jiri Kosina @ 2021-04-07 11:15 UTC (permalink / raw)
  To: John Chen
  Cc: linux-input, Rohit Pidaparthi, RicardoEPRodrigues, Benjamin Tissoires

On Tue, 30 Mar 2021, John Chen wrote:

> It is observed that, with 3 button emulation, when middle button is
> clicked, either the left button or right button is clicked as well. It
> is caused by hidinput "correctly" acting on the event, oblivious to the
> 3 button emulation.
> 
> As raw_event has taken care of everything, no further processing is
> needed. However, the only way to stop at raw_event is to return an error
> (negative) value. Therefore, the processing is stopped at event instead.
> 
> Signed-off-by: John Chen <johnchen902@gmail.com>
> ---
>  drivers/hid/hid-magicmouse.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
> index 7aad6ca56780..c646b4cd3783 100644
> --- a/drivers/hid/hid-magicmouse.c
> +++ b/drivers/hid/hid-magicmouse.c
> @@ -440,6 +440,21 @@ static int magicmouse_raw_event(struct hid_device *hdev,
>  	return 1;
>  }
>  
> +static int magicmouse_event(struct hid_device *hdev, struct hid_field *field,
> +		struct hid_usage *usage, __s32 value)
> +{
> +	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
> +	if (msc->input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
> +	    field->report->id == MOUSE2_REPORT_ID) {
> +		// magic_mouse_raw_event has done all the work. Skip hidinput.
> +		//
> +		// Specifically, hidinput may modify BTN_LEFT and BTN_RIGHT,
> +		// breaking emulate_3button.
> +		return 1;

I have fixed the comment style here, and applied the series. Thanks,

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-04-07 11:15 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-30 11:33 [PATCH v2 0/4] Hid: add Apple Magic Mouse 2 support John Chen
2021-03-30 11:33 ` [PATCH v2 1/4] HID: magicmouse: " John Chen
2021-04-05 17:30   ` Felix Hädicke
2021-03-30 11:33 ` [PATCH v2 2/4] HID: magicmouse: fix 3 button emulation of Mouse 2 John Chen
2021-04-07 11:15   ` Jiri Kosina
2021-03-30 11:33 ` [PATCH v2 3/4] HID: magicmouse: fix reconnection of Magic " John Chen
2021-03-30 11:33 ` [PATCH v2 4/4] HID: input: map battery capacity (00850065) John Chen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.