|
@@ -49,11 +49,13 @@ MODULE_PARM_DESC(disable_tap_to_click,
|
|
|
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
|
|
|
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
|
|
|
#define HIDPP_QUIRK_CLASS_K400 BIT(2)
|
|
|
+#define HIDPP_QUIRK_CLASS_G920 BIT(3)
|
|
|
|
|
|
/* bits 2..20 are reserved for classes */
|
|
|
#define HIDPP_QUIRK_CONNECT_EVENTS BIT(21)
|
|
|
#define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22)
|
|
|
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
|
|
|
+#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
|
|
|
|
|
|
#define HIDPP_QUIRK_DELAYED_INIT (HIDPP_QUIRK_NO_HIDINPUT | \
|
|
|
HIDPP_QUIRK_CONNECT_EVENTS)
|
|
@@ -146,8 +148,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
|
|
|
static int __hidpp_send_report(struct hid_device *hdev,
|
|
|
struct hidpp_report *hidpp_report)
|
|
|
{
|
|
|
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
|
|
int fields_count, ret;
|
|
|
|
|
|
+ hidpp = hid_get_drvdata(hdev);
|
|
|
+
|
|
|
switch (hidpp_report->report_id) {
|
|
|
case REPORT_ID_HIDPP_SHORT:
|
|
|
fields_count = HIDPP_REPORT_SHORT_LENGTH;
|
|
@@ -168,9 +173,13 @@ static int __hidpp_send_report(struct hid_device *hdev,
|
|
|
*/
|
|
|
hidpp_report->device_index = 0xff;
|
|
|
|
|
|
- ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
|
|
|
- (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
|
|
|
- HID_REQ_SET_REPORT);
|
|
|
+ if (hidpp->quirks & HIDPP_QUIRK_FORCE_OUTPUT_REPORTS) {
|
|
|
+ ret = hid_hw_output_report(hdev, (u8 *)hidpp_report, fields_count);
|
|
|
+ } else {
|
|
|
+ ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
|
|
|
+ (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
|
|
|
+ HID_REQ_SET_REPORT);
|
|
|
+ }
|
|
|
|
|
|
return ret == fields_count ? 0 : -1;
|
|
|
}
|
|
@@ -1430,10 +1439,12 @@ static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying)
|
|
|
else
|
|
|
name = hidpp_get_device_name(hidpp);
|
|
|
|
|
|
- if (!name)
|
|
|
+ if (!name) {
|
|
|
hid_err(hdev, "unable to retrieve the name of the device");
|
|
|
- else
|
|
|
+ } else {
|
|
|
+ dbg_hid("HID++: Got name: %s\n", name);
|
|
|
snprintf(hdev->name, sizeof(hdev->name), "%s", name);
|
|
|
+ }
|
|
|
|
|
|
kfree(name);
|
|
|
}
|
|
@@ -1596,6 +1607,25 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
|
goto hid_parse_fail;
|
|
|
}
|
|
|
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
/* Allow incoming packets */
|
|
|
hid_device_io_start(hdev);
|
|
|
|
|
@@ -1604,8 +1634,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");
|
|
|
- hid_device_io_stop(hdev);
|
|
|
- goto hid_parse_fail;
|
|
|
+ goto hid_hw_open_failed;
|
|
|
}
|
|
|
|
|
|
hid_info(hdev, "HID++ %u.%u device connected.\n",
|
|
@@ -1618,19 +1647,18 @@ 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_parse_fail;
|
|
|
+ goto hid_hw_open_failed;
|
|
|
}
|
|
|
|
|
|
/* Block incoming packets */
|
|
|
hid_device_io_stop(hdev);
|
|
|
|
|
|
- if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
|
|
|
- connect_mask &= ~HID_CONNECT_HIDINPUT;
|
|
|
-
|
|
|
- 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;
|
|
|
+ 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;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) {
|
|
@@ -1642,6 +1670,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
|
|
|
|
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_start_fail:
|
|
|
hid_parse_fail:
|
|
|
cancel_work_sync(&hidpp->work);
|
|
@@ -1655,9 +1689,11 @@ static void hidpp_remove(struct hid_device *hdev)
|
|
|
{
|
|
|
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
|
|
|
|
|
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)
|
|
|
+ hid_hw_close(hdev);
|
|
|
+ hid_hw_stop(hdev);
|
|
|
cancel_work_sync(&hidpp->work);
|
|
|
mutex_destroy(&hidpp->send_mutex);
|
|
|
- hid_hw_stop(hdev);
|
|
|
}
|
|
|
|
|
|
static const struct hid_device_id hidpp_devices[] = {
|
|
@@ -1685,6 +1721,9 @@ static const struct hid_device_id hidpp_devices[] = {
|
|
|
|
|
|
{ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
|
|
USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
|
|
|
+
|
|
|
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
|
|
|
+ .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
|
|
|
{}
|
|
|
};
|
|
|
|