Skip to content

Commit

Permalink
HID: logitech-hidpp: make .probe usbhid capable
Browse files Browse the repository at this point in the history
The current custom solution for the G920 is not the best because
hid_hw_start() is not called at the end of the .probe().
It means that any configuration retrieved after the initial hid_hw_start
would not be exposed to user space without races.

We can simply force hid_hw_start to just enable the transport layer by
not using a connect_mask. This way, we can have a common path between
USB, Unifying and Bluetooth devices.

With this change, we can now support the non DJ receivers for low end
devices, which will allow us to fetch the actual names of the paired
device (instead of 'Logitech Wireless Receiver')

Tested with a M185 with the non unifying receiver, a T650 and many other
unifying devices, and the T651 over Bluetooth.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
  • Loading branch information
bentiss committed Apr 23, 2019
1 parent fe3ee1e commit 91cf9a9
Showing 1 changed file with 45 additions and 41 deletions.
86 changes: 45 additions & 41 deletions drivers/hid/hid-logitech-hidpp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3316,24 +3316,23 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
hid_warn(hdev, "Cannot allocate sysfs group for %s\n",
hdev->name);

if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
connect_mask &= ~HID_CONNECT_HIDINPUT;

if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto hid_hw_start_fail;
}
ret = hid_hw_open(hdev);
if (ret < 0) {
dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
__func__, ret);
hid_hw_stop(hdev);
goto hid_hw_start_fail;
}
/*
* Plain USB connections need to actually call start and open
* on the transport driver to allow incoming data.
*/
ret = hid_hw_start(hdev, 0);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto hid_hw_start_fail;
}

ret = hid_hw_open(hdev);
if (ret < 0) {
dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
__func__, ret);
hid_hw_stop(hdev);
goto hid_hw_open_fail;
}

/* Allow incoming packets */
hid_device_io_start(hdev);
Expand All @@ -3347,7 +3346,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!connected) {
ret = -ENODEV;
hid_err(hdev, "Device not connected");
goto hid_hw_open_failed;
goto hid_hw_init_fail;
}

hidpp_overwrite_name(hdev);
Expand All @@ -3356,37 +3355,36 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
ret = wtp_get_config(hidpp);
if (ret)
goto hid_hw_open_failed;
goto hid_hw_init_fail;
} else if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
ret = g920_get_config(hidpp);
if (ret)
goto hid_hw_open_failed;
goto hid_hw_init_fail;
}

/* Block incoming packets */
hid_device_io_stop(hdev);
hidpp_connect_event(hidpp);

if (!(hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
goto hid_hw_start_fail;
}
}
/* Reset the HID node state */
hid_device_io_stop(hdev);
hid_hw_close(hdev);
hid_hw_stop(hdev);

/* Allow incoming packets */
hid_device_io_start(hdev);
if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
connect_mask &= ~HID_CONNECT_HIDINPUT;

hidpp_connect_event(hidpp);
/* Now export the actual inputs and hidraw nodes to the world */
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
goto hid_hw_start_fail;
}

return ret;

hid_hw_open_failed:
hid_device_io_stop(hdev);
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
hid_hw_init_fail:
hid_hw_close(hdev);
hid_hw_open_fail:
hid_hw_stop(hdev);
hid_hw_start_fail:
sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
cancel_work_sync(&hidpp->work);
Expand All @@ -3403,10 +3401,9 @@ static void hidpp_remove(struct hid_device *hdev)

sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);

if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)
hidpp_ff_deinit(hdev);
hid_hw_close(hdev);
}

hid_hw_stop(hdev);
cancel_work_sync(&hidpp->work);
mutex_destroy(&hidpp->send_mutex);
Expand Down Expand Up @@ -3470,7 +3467,14 @@ static const struct hid_device_id hidpp_devices[] = {

{ LDJ_DEVICE(HID_ANY_ID) },

{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
{ /* Logitech G403 Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC082) },
{ /* Logitech G700 Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC06B) },
{ /* Logitech G900 Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC081) },
{ /* Logitech G920 Wheel over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
{}
};
Expand Down

0 comments on commit 91cf9a9

Please sign in to comment.