| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * HID driver for some logitech "special" devices |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 10 | 11 | */ |
|---|
| 11 | 12 | |
|---|
| 12 | 13 | /* |
|---|
| 13 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 14 | | - * under the terms of the GNU General Public License as published by the Free |
|---|
| 15 | | - * Software Foundation; either version 2 of the License, or (at your option) |
|---|
| 16 | | - * any later version. |
|---|
| 17 | 14 | */ |
|---|
| 18 | 15 | |
|---|
| 19 | 16 | #include <linux/device.h> |
|---|
| .. | .. |
|---|
| 50 | 47 | #define MOMO_RDESC_ORIG_SIZE 87 |
|---|
| 51 | 48 | #define MOMO2_RDESC_ORIG_SIZE 87 |
|---|
| 52 | 49 | #define FFG_RDESC_ORIG_SIZE 85 |
|---|
| 50 | +#define FG_RDESC_ORIG_SIZE 82 |
|---|
| 53 | 51 | |
|---|
| 54 | 52 | /* Fixed report descriptors for Logitech Driving Force (and Pro) |
|---|
| 55 | 53 | * wheel controllers |
|---|
| .. | .. |
|---|
| 381 | 379 | 0xC0 /* End Collection */ |
|---|
| 382 | 380 | }; |
|---|
| 383 | 381 | |
|---|
| 382 | +static __u8 fg_rdesc_fixed[] = { |
|---|
| 383 | +0x05, 0x01, /* Usage Page (Desktop), */ |
|---|
| 384 | +0x09, 0x04, /* Usage (Joystik), */ |
|---|
| 385 | +0xA1, 0x01, /* Collection (Application), */ |
|---|
| 386 | +0xA1, 0x02, /* Collection (Logical), */ |
|---|
| 387 | +0x15, 0x00, /* Logical Minimum (0), */ |
|---|
| 388 | +0x26, 0xFF, 0x00, /* Logical Maximum (255), */ |
|---|
| 389 | +0x35, 0x00, /* Physical Minimum (0), */ |
|---|
| 390 | +0x46, 0xFF, 0x00, /* Physical Maximum (255), */ |
|---|
| 391 | +0x75, 0x08, /* Report Size (8), */ |
|---|
| 392 | +0x95, 0x01, /* Report Count (1), */ |
|---|
| 393 | +0x09, 0x30, /* Usage (X), */ |
|---|
| 394 | +0x81, 0x02, /* Input (Variable), */ |
|---|
| 395 | +0xA4, /* Push, */ |
|---|
| 396 | +0x25, 0x01, /* Logical Maximum (1), */ |
|---|
| 397 | +0x45, 0x01, /* Physical Maximum (1), */ |
|---|
| 398 | +0x75, 0x01, /* Report Size (1), */ |
|---|
| 399 | +0x95, 0x02, /* Report Count (2), */ |
|---|
| 400 | +0x81, 0x01, /* Input (Constant), */ |
|---|
| 401 | +0x95, 0x06, /* Report Count (6), */ |
|---|
| 402 | +0x05, 0x09, /* Usage Page (Button), */ |
|---|
| 403 | +0x19, 0x01, /* Usage Minimum (01h), */ |
|---|
| 404 | +0x29, 0x06, /* Usage Maximum (06h), */ |
|---|
| 405 | +0x81, 0x02, /* Input (Variable), */ |
|---|
| 406 | +0x05, 0x01, /* Usage Page (Desktop), */ |
|---|
| 407 | +0xB4, /* Pop, */ |
|---|
| 408 | +0x81, 0x02, /* Input (Constant), */ |
|---|
| 409 | +0x09, 0x31, /* Usage (Y), */ |
|---|
| 410 | +0x81, 0x02, /* Input (Variable), */ |
|---|
| 411 | +0x09, 0x32, /* Usage (Z), */ |
|---|
| 412 | +0x81, 0x02, /* Input (Variable), */ |
|---|
| 413 | +0xC0, /* End Collection, */ |
|---|
| 414 | +0xA1, 0x02, /* Collection (Logical), */ |
|---|
| 415 | +0x26, 0xFF, 0x00, /* Logical Maximum (255), */ |
|---|
| 416 | +0x46, 0xFF, 0x00, /* Physical Maximum (255), */ |
|---|
| 417 | +0x75, 0x08, /* Report Size (8), */ |
|---|
| 418 | +0x95, 0x04, /* Report Count (4), */ |
|---|
| 419 | +0x09, 0x02, /* Usage (02h), */ |
|---|
| 420 | +0xB1, 0x02, /* Feature (Variable), */ |
|---|
| 421 | +0xC0, /* End Collection, */ |
|---|
| 422 | +0xC0 /* End Collection, */ |
|---|
| 423 | +}; |
|---|
| 424 | + |
|---|
| 384 | 425 | /* |
|---|
| 385 | 426 | * Certain Logitech keyboards send in report #3 keys which are far |
|---|
| 386 | 427 | * above the logical maximum described in descriptor. This extends |
|---|
| .. | .. |
|---|
| 407 | 448 | } |
|---|
| 408 | 449 | |
|---|
| 409 | 450 | switch (hdev->product) { |
|---|
| 451 | + |
|---|
| 452 | + case USB_DEVICE_ID_LOGITECH_WINGMAN_FG: |
|---|
| 453 | + if (*rsize == FG_RDESC_ORIG_SIZE) { |
|---|
| 454 | + hid_info(hdev, |
|---|
| 455 | + "fixing up Logitech Wingman Formula GP report descriptor\n"); |
|---|
| 456 | + rdesc = fg_rdesc_fixed; |
|---|
| 457 | + *rsize = sizeof(fg_rdesc_fixed); |
|---|
| 458 | + } else { |
|---|
| 459 | + hid_info(hdev, |
|---|
| 460 | + "rdesc size test failed for formula gp\n"); |
|---|
| 461 | + } |
|---|
| 462 | + break; |
|---|
| 463 | + |
|---|
| 410 | 464 | |
|---|
| 411 | 465 | case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG: |
|---|
| 412 | 466 | if (*rsize == FFG_RDESC_ORIG_SIZE) { |
|---|
| .. | .. |
|---|
| 664 | 718 | usage->code == ABS_RZ)) { |
|---|
| 665 | 719 | switch (hdev->product) { |
|---|
| 666 | 720 | case USB_DEVICE_ID_LOGITECH_G29_WHEEL: |
|---|
| 721 | + case USB_DEVICE_ID_LOGITECH_WINGMAN_FG: |
|---|
| 667 | 722 | case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG: |
|---|
| 668 | 723 | case USB_DEVICE_ID_LOGITECH_WHEEL: |
|---|
| 669 | 724 | case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: |
|---|
| .. | .. |
|---|
| 822 | 877 | } |
|---|
| 823 | 878 | |
|---|
| 824 | 879 | static const struct hid_device_id lg_devices[] = { |
|---|
| 825 | | - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), |
|---|
| 826 | | - .driver_data = LG_RDESC | LG_WIRELESS }, |
|---|
| 827 | 880 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER), |
|---|
| 828 | | - .driver_data = LG_RDESC | LG_WIRELESS }, |
|---|
| 829 | | - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2), |
|---|
| 830 | 881 | .driver_data = LG_RDESC | LG_WIRELESS }, |
|---|
| 831 | 882 | |
|---|
| 832 | 883 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER), |
|---|
| .. | .. |
|---|
| 879 | 930 | .driver_data = LG_NOGET | LG_FF4 }, |
|---|
| 880 | 931 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), |
|---|
| 881 | 932 | .driver_data = LG_FF4 }, |
|---|
| 933 | + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG), |
|---|
| 934 | + .driver_data = LG_NOGET }, |
|---|
| 882 | 935 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG), |
|---|
| 883 | 936 | .driver_data = LG_NOGET | LG_FF4 }, |
|---|
| 884 | 937 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), |
|---|