Re: [PATCH 3/3] Enable high-resolution scrolling on Logitech mice

2 messages, 2 authors, 2018-08-30 · open the first message on its own page

Re: [PATCH 3/3] Enable high-resolution scrolling on Logitech mice

From: Benjamin Tissoires <hidden>
Date: 2018-08-30 07:18:38

Hi Harry,

On Thu, Aug 30, 2018 at 1:06 AM Harry Cutts [off-list ref] wrote:
Hi Benjamin,

On Tue, 28 Aug 2018 at 01:47, Benjamin Tissoires
[off-list ref] wrote:
quoted
On Thu, Aug 23, 2018 at 8:31 PM Harry Cutts [off-list ref] wrote:
quoted
[snip]
@@ -400,32 +409,53 @@ static void hidpp_prefix_name(char **name, int name_length)
 #define HIDPP_SET_LONG_REGISTER                                0x82
 #define HIDPP_GET_LONG_REGISTER                                0x83

-#define HIDPP_REG_GENERAL                              0x00
-
-static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
+/**
+ * hidpp10_set_register_bit() - Sets a single bit in a HID++ 1.0 register.
+ * @hidpp_dev: the device to set the register on.
+ * @register_address: the address of the register to modify.
+ * @byte: the byte of the register to modify. Should be less than 3.
+ * Return: 0 if successful, otherwise a negative error code.
+ */
+static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev,
+       u8 register_address, u8 byte, u8 bit)
 {
        struct hidpp_report response;
        int ret;
        u8 params[3] = { 0 };

        ret = hidpp_send_rap_command_sync(hidpp_dev,
-                                       REPORT_ID_HIDPP_SHORT,
-                                       HIDPP_GET_REGISTER,
-                                       HIDPP_REG_GENERAL,
-                                       NULL, 0, &response);
+                                         REPORT_ID_HIDPP_SHORT,
+                                         HIDPP_GET_REGISTER,
+                                         register_address,
+                                         NULL, 0, &response);
        if (ret)
                return ret;

        memcpy(params, response.rap.params, 3);

-       /* Set the battery bit */
-       params[0] |= BIT(4);
+       params[byte] |= BIT(bit);

        return hidpp_send_rap_command_sync(hidpp_dev,
-                                       REPORT_ID_HIDPP_SHORT,
-                                       HIDPP_SET_REGISTER,
-                                       HIDPP_REG_GENERAL,
-                                       params, 3, &response);
+                                          REPORT_ID_HIDPP_SHORT,
+                                          HIDPP_SET_REGISTER,
+                                          register_address,
+                                          params, 3, &response);
+}
+
+
+#define HIDPP_REG_GENERAL                              0x00
+
+static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
+{
+       return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_GENERAL, 0, 4);
+}
This hunk should be dealt in a separate patch (including the one function below)
OK, will do in v2.
quoted
quoted
[snip]
@@ -2399,7 +2524,8 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size)
                input_report_rel(mydata->input, REL_Y, v);

                v = hid_snto32(data[6], 8);
-               input_report_rel(mydata->input, REL_WHEEL, v);
+               hid_scroll_counter_handle_scroll(
+                               &hidpp->vertical_wheel_counter, v);
The conversion input_report_rel(... REL_WHEEL,...) to
hid_scroll_counter_handle_scroll() should be dealt in a separate
patch.
OK, I'll do that in v2, but might I ask why? I don't see how this
particular hunk is special.
I tend to consider that existing code rewrite need to be in their
special commit, especially if the change isn't supposed to change the
behaviour. This is my personal taste in case something goes wrong and
(in this case) a m560 suddenly starts complaining about an issue with
this mouse.
I wouldn't mind too much if you rather keep the
hid_scroll_counter_handle_scroll() introduction to this commit though.
quoted
quoted
                input_sync(mydata->input);
        }
@@ -2527,6 +2653,71 @@ static int g920_get_config(struct hidpp_device *hidpp)
        return 0;
 }

+/* -------------------------------------------------------------------------- */
+/* High-resolution scroll wheels                                              */
+/* -------------------------------------------------------------------------- */
+
+/**
+ * struct hi_res_scroll_info - Stores info on a device's high-res scroll wheel.
+ * @product_id: the HID product ID of the device being described.
+ * @mm256_per_hi_res_unit: the distance moved by the user's finger for each
+ *                         high-resolution unit reported by the device, in
+ *                         256ths of a millimetre.
+ */
+struct hi_res_scroll_info {
+       __u32 product_id;
+       int mm256_per_hi_res_unit;
+};
+
+static struct hi_res_scroll_info hi_res_scroll_devices[] = {
+       { /* Anywhere MX */
+         .product_id = 0x1017, .mm256_per_hi_res_unit = 114 },
+       { /* Performance MX */
+         .product_id = 0x101a, .mm256_per_hi_res_unit = 104 },
+       { /* M560 */
+         .product_id = 0x402d, .mm256_per_hi_res_unit = 111 },
+       { /* MX Master 2S */
+         .product_id = 0x4069, .mm256_per_hi_res_unit = 104 },
+       { .product_id = USB_DEVICE_ID_LOGITECH_MOUSE_MX_MASTER_2S_BT,
+         .mm256_per_hi_res_unit = 104 },
+};
+
+static int hi_res_scroll_look_up_mm256(__u32 product_id)
+{
+       int i;
+       int num_devices = sizeof(hi_res_scroll_devices)
+                         / sizeof(hi_res_scroll_devices[0]);
+       for (i = 0; i < num_devices; i++) {
+               if (hi_res_scroll_devices[i].product_id == product_id)
+                       return hi_res_scroll_devices[i].mm256_per_hi_res_unit;
+       }
+       return 104;
104?
This seems like a sensible default value in case we don't have a value
for this mouse in hi_res_scroll_devices. I'll add a comment explaining
this in v2.
quoted
quoted
[snip]
+static int hidpp_event(struct hid_device *hdev, struct hid_field *field,
+       struct hid_usage *usage, __s32 value)
+{
+       struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+       struct hid_scroll_counter *counter = &hidpp->vertical_wheel_counter;
+
+       /* A scroll event may occur before the multiplier has been retrieved or
+        * the input device set, or high-res scroll enabling may fail. In such
+        * cases we must return early (falling back to default behaviour) to
+        * avoid a crash in hid_scroll_counter_handle_scroll.
+        */
+       if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0
+           || counter->dev == NULL || counter->resolution_multiplier == 0)
+               return 0;
You are using usage_table to force the .event function to be called
only on the WHEEL events. This is correct, but I have a feeling this
will be harder to understand when we are going to extend the .event()
function for other events.
If you rather keep the cde that way, please add a comment at the
beginning of the function stating that we are only called against
WHEEL events because of usage_table.
OK, I'll add the comment in v2.
quoted
quoted
[snip]

+#define LDJ_DEVICE(product) \
+       HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \
+                  USB_VENDOR_ID_LOGITECH, (product))
+
 static const struct hid_device_id hidpp_devices[] = {
        { /* wireless touchpad */
-         HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
-               USB_VENDOR_ID_LOGITECH, 0x4011),
+         LDJ_DEVICE(0x4011),
          .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT |
                         HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS },
        { /* wireless touchpad T650 */
-         HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
-               USB_VENDOR_ID_LOGITECH, 0x4101),
+         LDJ_DEVICE(0x4101),
The rewrite of the existing supported devices should be in a separate patch too.
OK, will do.
quoted
quoted
[snip]
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 249d49b6b16c..7926c275f258 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -463,6 +463,17 @@ static const struct hid_device_id hid_have_special_driver[] = {
 #endif
 #if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP)
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_T651) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_M336_337_535_BT1) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_M336_337_535_BT2) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_M720_BT) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_MX_ANYWHERE_2_BT1) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_MX_ANYWHERE_2_BT2) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_MX_ANYWHERE_2_BT3) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_MX_ANYWHERE_2S_BT) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_MX_MASTER_BT1) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_MX_MASTER_BT2) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_MX_MASTER_BT3) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_MX_MASTER_2S_BT) },
Since v4.16, this should not be required anymore. Please drop the hunk
if I am correct.
Yes, it seems to work fine without it (at least for the MX Master 2S).
Unfortunately, while testing this I encountered a bug with high-res
scrolling over Bluetooth. (It seems that if you turn off the MX Master
2S while it's connected over Bluetooth, we don't detect that and
remove the input device, meaning that when it reconnects the driver
thinks it's in high-res mode but the mouse is in low-res.) I'm
investigating, but in the meantime I'll remove the Bluetooth support
from v2 and add it back in later.
As far as I can see, the MX Master 2S is connected over BLE. Bluez
keeps the uhid node opened (and thus the existing bluetooth HID
device) to be able to reconnect faster.
I would suppose you should get notified in the connect event of a
reconnection, but it doesn't seem to be the case.

Nestor, is there any event emitted by the mouse when it gets
reconnected over BLE or is that a bluez issue?

Cheers,
Benjamin
quoted
Cheers,
Benjamin
quoted
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) },
 #endif
 #if IS_ENABLED(CONFIG_HID_LOGITECH_DJ)
--
2.18.0.1017.ga543ac7ca45-goog
Thanks,

Harry Cutts
Chrome OS Touch/Input team

Re: [PATCH 3/3] Enable high-resolution scrolling on Logitech mice

From: Harry Cutts <hidden>
Date: 2018-08-30 20:38:15

Hi Benjamin,

On Thu, 30 Aug 2018 at 00:18, Benjamin Tissoires
[off-list ref] wrote:
quoted
On Thu, Aug 30, 2018 at 1:06 AM Harry Cutts [off-list ref] wrote:
quoted
The conversion input_report_rel(... REL_WHEEL,...) to
hid_scroll_counter_handle_scroll() should be dealt in a separate
patch.
OK, I'll do that in v2, but might I ask why? I don't see how this
particular hunk is special.
I tend to consider that existing code rewrite need to be in their
special commit, especially if the change isn't supposed to change the
behaviour. This is my personal taste in case something goes wrong and
(in this case) a m560 suddenly starts complaining about an issue with
this mouse.
I wouldn't mind too much if you rather keep the
hid_scroll_counter_handle_scroll() introduction to this commit though.
Yes, I see the reasoning for that, but this hunk is pretty tied to the
main change in that scrolling on the M560 would be 8x too fast without
it. I'll keep it in the same one, if you don't mind.
quoted
[snip]
Yes, it seems to work fine without it (at least for the MX Master 2S).
Unfortunately, while testing this I encountered a bug with high-res
scrolling over Bluetooth. (It seems that if you turn off the MX Master
2S while it's connected over Bluetooth, we don't detect that and
remove the input device, meaning that when it reconnects the driver
thinks it's in high-res mode but the mouse is in low-res.) I'm
investigating, but in the meantime I'll remove the Bluetooth support
from v2 and add it back in later.
As far as I can see, the MX Master 2S is connected over BLE. Bluez
keeps the uhid node opened (and thus the existing bluetooth HID
device) to be able to reconnect faster.
I would suppose you should get notified in the connect event of a
reconnection, but it doesn't seem to be the case.

Nestor, is there any event emitted by the mouse when it gets
reconnected over BLE or is that a bluez issue?
Ah, interesting. The MX Master 2S is indeed using BLE, and testing
with another Logitech BLE mouse (the M585) also leaves the input
device around. I think this is something Logitech-specific, though, as
the Microsoft Surface Precision mouse (also BLE) does have its input
device removed when it turns off. I notice that btmon does show
"device disconnected" and "device connected" events when I turn the
M585 on and off; maybe we need to plumb those through to the driver.
We've decided to delay Bluetooth support for high-res scrolling until
the Chrome OS Bluetooth stack is more stable.

Harry Cutts
Chrome OS Touch/Input team
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help