1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/device.h>
17#include <linux/hid.h>
18#include <linux/module.h>
19#include <linux/random.h>
20#include <linux/sched.h>
21#include <linux/usb.h>
22#include <linux/wait.h>
23
24#include "usbhid/usbhid.h"
25#include "hid-ids.h"
26#include "hid-lg.h"
27#include "hid-lg4ff.h"
28
29#define LG_RDESC 0x001
30#define LG_BAD_RELATIVE_KEYS 0x002
31#define LG_DUPLICATE_USAGES 0x004
32#define LG_EXPANDED_KEYMAP 0x010
33#define LG_IGNORE_DOUBLED_WHEEL 0x020
34#define LG_WIRELESS 0x040
35#define LG_INVERT_HWHEEL 0x080
36#define LG_NOGET 0x100
37#define LG_FF 0x200
38#define LG_FF2 0x400
39#define LG_RDESC_REL_ABS 0x800
40#define LG_FF3 0x1000
41#define LG_FF4 0x2000
42
43
44#define DF_RDESC_ORIG_SIZE 130
45#define DFP_RDESC_ORIG_SIZE 97
46#define FV_RDESC_ORIG_SIZE 130
47#define MOMO_RDESC_ORIG_SIZE 87
48#define MOMO2_RDESC_ORIG_SIZE 87
49#define FFG_RDESC_ORIG_SIZE 85
50#define FG_RDESC_ORIG_SIZE 82
51
52
53
54
55
56
57
58
59
60
61static __u8 df_rdesc_fixed[] = {
620x05, 0x01,
630x09, 0x04,
640xA1, 0x01,
650xA1, 0x02,
660x95, 0x01,
670x75, 0x0A,
680x14,
690x26, 0xFF, 0x03,
700x34,
710x46, 0xFF, 0x03,
720x09, 0x30,
730x81, 0x02,
740x95, 0x0C,
750x75, 0x01,
760x25, 0x01,
770x45, 0x01,
780x05, 0x09,
790x19, 0x01,
800x29, 0x0c,
810x81, 0x02,
820x95, 0x02,
830x06, 0x00, 0xFF,
840x09, 0x01,
850x81, 0x02,
860x05, 0x01,
870x26, 0xFF, 0x00,
880x46, 0xFF, 0x00,
890x95, 0x01,
900x75, 0x08,
910x81, 0x02,
920x25, 0x07,
930x46, 0x3B, 0x01,
940x75, 0x04,
950x65, 0x14,
960x09, 0x39,
970x81, 0x42,
980x75, 0x01,
990x95, 0x04,
1000x65, 0x00,
1010x06, 0x00, 0xFF,
1020x09, 0x01,
1030x25, 0x01,
1040x45, 0x01,
1050x81, 0x02,
1060x05, 0x01,
1070x95, 0x01,
1080x75, 0x08,
1090x26, 0xFF, 0x00,
1100x46, 0xFF, 0x00,
1110x09, 0x31,
1120x81, 0x02,
1130x09, 0x35,
1140x81, 0x02,
1150xC0,
1160xA1, 0x02,
1170x26, 0xFF, 0x00,
1180x46, 0xFF, 0x00,
1190x95, 0x07,
1200x75, 0x08,
1210x09, 0x03,
1220x91, 0x02,
1230xC0,
1240xC0
125};
126
127static __u8 dfp_rdesc_fixed[] = {
1280x05, 0x01,
1290x09, 0x04,
1300xA1, 0x01,
1310xA1, 0x02,
1320x95, 0x01,
1330x75, 0x0E,
1340x14,
1350x26, 0xFF, 0x3F,
1360x34,
1370x46, 0xFF, 0x3F,
1380x09, 0x30,
1390x81, 0x02,
1400x95, 0x0E,
1410x75, 0x01,
1420x25, 0x01,
1430x45, 0x01,
1440x05, 0x09,
1450x19, 0x01,
1460x29, 0x0E,
1470x81, 0x02,
1480x05, 0x01,
1490x95, 0x01,
1500x75, 0x04,
1510x25, 0x07,
1520x46, 0x3B, 0x01,
1530x65, 0x14,
1540x09, 0x39,
1550x81, 0x42,
1560x65, 0x00,
1570x26, 0xFF, 0x00,
1580x46, 0xFF, 0x00,
1590x75, 0x08,
1600x81, 0x01,
1610x09, 0x31,
1620x81, 0x02,
1630x09, 0x35,
1640x81, 0x02,
1650x81, 0x01,
1660xC0,
1670xA1, 0x02,
1680x09, 0x02,
1690x95, 0x07,
1700x91, 0x02,
1710xC0,
1720xC0
173};
174
175static __u8 fv_rdesc_fixed[] = {
1760x05, 0x01,
1770x09, 0x04,
1780xA1, 0x01,
1790xA1, 0x02,
1800x95, 0x01,
1810x75, 0x0A,
1820x15, 0x00,
1830x26, 0xFF, 0x03,
1840x35, 0x00,
1850x46, 0xFF, 0x03,
1860x09, 0x30,
1870x81, 0x02,
1880x95, 0x0C,
1890x75, 0x01,
1900x25, 0x01,
1910x45, 0x01,
1920x05, 0x09,
1930x19, 0x01,
1940x29, 0x0C,
1950x81, 0x02,
1960x95, 0x02,
1970x06, 0x00, 0xFF,
1980x09, 0x01,
1990x81, 0x02,
2000x09, 0x02,
2010x26, 0xFF, 0x00,
2020x46, 0xFF, 0x00,
2030x95, 0x01,
2040x75, 0x08,
2050x81, 0x02,
2060x05, 0x01,
2070x25, 0x07,
2080x46, 0x3B, 0x01,
2090x75, 0x04,
2100x65, 0x14,
2110x09, 0x39,
2120x81, 0x42,
2130x75, 0x01,
2140x95, 0x04,
2150x65, 0x00,
2160x06, 0x00, 0xFF,
2170x09, 0x01,
2180x25, 0x01,
2190x45, 0x01,
2200x81, 0x02,
2210x05, 0x01,
2220x95, 0x01,
2230x75, 0x08,
2240x26, 0xFF, 0x00,
2250x46, 0xFF, 0x00,
2260x09, 0x31,
2270x81, 0x02,
2280x09, 0x32,
2290x81, 0x02,
2300xC0,
2310xA1, 0x02,
2320x26, 0xFF, 0x00,
2330x46, 0xFF, 0x00,
2340x95, 0x07,
2350x75, 0x08,
2360x09, 0x03,
2370x91, 0x02,
2380xC0,
2390xC0
240};
241
242static __u8 momo_rdesc_fixed[] = {
2430x05, 0x01,
2440x09, 0x04,
2450xA1, 0x01,
2460xA1, 0x02,
2470x95, 0x01,
2480x75, 0x0A,
2490x15, 0x00,
2500x26, 0xFF, 0x03,
2510x35, 0x00,
2520x46, 0xFF, 0x03,
2530x09, 0x30,
2540x81, 0x02,
2550x95, 0x08,
2560x75, 0x01,
2570x25, 0x01,
2580x45, 0x01,
2590x05, 0x09,
2600x19, 0x01,
2610x29, 0x08,
2620x81, 0x02,
2630x06, 0x00, 0xFF,
2640x75, 0x0E,
2650x95, 0x01,
2660x26, 0xFF, 0x00,
2670x46, 0xFF, 0x00,
2680x09, 0x00,
2690x81, 0x02,
2700x05, 0x01,
2710x75, 0x08,
2720x09, 0x31,
2730x81, 0x02,
2740x09, 0x32,
2750x81, 0x02,
2760x06, 0x00, 0xFF,
2770x09, 0x01,
2780x81, 0x02,
2790xC0,
2800xA1, 0x02,
2810x09, 0x02,
2820x95, 0x07,
2830x91, 0x02,
2840xC0,
2850xC0
286};
287
288static __u8 momo2_rdesc_fixed[] = {
2890x05, 0x01,
2900x09, 0x04,
2910xA1, 0x01,
2920xA1, 0x02,
2930x95, 0x01,
2940x75, 0x0A,
2950x15, 0x00,
2960x26, 0xFF, 0x03,
2970x35, 0x00,
2980x46, 0xFF, 0x03,
2990x09, 0x30,
3000x81, 0x02,
3010x95, 0x0A,
3020x75, 0x01,
3030x25, 0x01,
3040x45, 0x01,
3050x05, 0x09,
3060x19, 0x01,
3070x29, 0x0A,
3080x81, 0x02,
3090x06, 0x00, 0xFF,
3100x09, 0x00,
3110x95, 0x04,
3120x81, 0x02,
3130x95, 0x01,
3140x75, 0x08,
3150x26, 0xFF, 0x00,
3160x46, 0xFF, 0x00,
3170x09, 0x01,
3180x81, 0x02,
3190x05, 0x01,
3200x09, 0x31,
3210x81, 0x02,
3220x09, 0x32,
3230x81, 0x02,
3240x06, 0x00, 0xFF,
3250x09, 0x00,
3260x81, 0x02,
3270xC0,
3280xA1, 0x02,
3290x09, 0x02,
3300x95, 0x07,
3310x91, 0x02,
3320xC0,
3330xC0
334};
335
336static __u8 ffg_rdesc_fixed[] = {
3370x05, 0x01,
3380x09, 0x04,
3390xA1, 0x01,
3400xA1, 0x02,
3410x95, 0x01,
3420x75, 0x0A,
3430x15, 0x00,
3440x26, 0xFF, 0x03,
3450x35, 0x00,
3460x46, 0xFF, 0x03,
3470x09, 0x30,
3480x81, 0x02,
3490x95, 0x06,
3500x75, 0x01,
3510x25, 0x01,
3520x45, 0x01,
3530x05, 0x09,
3540x19, 0x01,
3550x29, 0x06,
3560x81, 0x02,
3570x95, 0x01,
3580x75, 0x08,
3590x26, 0xFF, 0x00,
3600x46, 0xFF, 0x00,
3610x06, 0x00, 0xFF,
3620x09, 0x01,
3630x81, 0x02,
3640x05, 0x01,
3650x81, 0x01,
3660x09, 0x31,
3670x81, 0x02,
3680x09, 0x32,
3690x81, 0x02,
3700x06, 0x00, 0xFF,
3710x09, 0x01,
3720x81, 0x02,
3730xC0,
3740xA1, 0x02,
3750x09, 0x02,
3760x95, 0x07,
3770x91, 0x02,
3780xC0,
3790xC0
380};
381
382static __u8 fg_rdesc_fixed[] = {
3830x05, 0x01,
3840x09, 0x04,
3850xA1, 0x01,
3860xA1, 0x02,
3870x15, 0x00,
3880x26, 0xFF, 0x00,
3890x35, 0x00,
3900x46, 0xFF, 0x00,
3910x75, 0x08,
3920x95, 0x01,
3930x09, 0x30,
3940x81, 0x02,
3950xA4,
3960x25, 0x01,
3970x45, 0x01,
3980x75, 0x01,
3990x95, 0x02,
4000x81, 0x01,
4010x95, 0x06,
4020x05, 0x09,
4030x19, 0x01,
4040x29, 0x06,
4050x81, 0x02,
4060x05, 0x01,
4070xB4,
4080x81, 0x02,
4090x09, 0x31,
4100x81, 0x02,
4110x09, 0x32,
4120x81, 0x02,
4130xC0,
4140xA1, 0x02,
4150x26, 0xFF, 0x00,
4160x46, 0xFF, 0x00,
4170x75, 0x08,
4180x95, 0x04,
4190x09, 0x02,
4200xB1, 0x02,
4210xC0,
4220xC0
423};
424
425
426
427
428
429
430static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
431 unsigned int *rsize)
432{
433 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
434
435 if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
436 rdesc[84] == 0x8c && rdesc[85] == 0x02) {
437 hid_info(hdev,
438 "fixing up Logitech keyboard report descriptor\n");
439 rdesc[84] = rdesc[89] = 0x4d;
440 rdesc[85] = rdesc[90] = 0x10;
441 }
442 if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
443 rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
444 rdesc[49] == 0x81 && rdesc[50] == 0x06) {
445 hid_info(hdev,
446 "fixing up rel/abs in Logitech report descriptor\n");
447 rdesc[33] = rdesc[50] = 0x02;
448 }
449
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
464
465 case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
466 if (*rsize == FFG_RDESC_ORIG_SIZE) {
467 hid_info(hdev,
468 "fixing up Logitech Wingman Formula Force GP report descriptor\n");
469 rdesc = ffg_rdesc_fixed;
470 *rsize = sizeof(ffg_rdesc_fixed);
471 }
472 break;
473
474
475 case USB_DEVICE_ID_LOGITECH_WHEEL:
476 if (*rsize == DF_RDESC_ORIG_SIZE) {
477 hid_info(hdev,
478 "fixing up Logitech Driving Force report descriptor\n");
479 rdesc = df_rdesc_fixed;
480 *rsize = sizeof(df_rdesc_fixed);
481 }
482 break;
483
484 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
485 if (*rsize == MOMO_RDESC_ORIG_SIZE) {
486 hid_info(hdev,
487 "fixing up Logitech Momo Force (Red) report descriptor\n");
488 rdesc = momo_rdesc_fixed;
489 *rsize = sizeof(momo_rdesc_fixed);
490 }
491 break;
492
493 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
494 if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
495 hid_info(hdev,
496 "fixing up Logitech Momo Racing Force (Black) report descriptor\n");
497 rdesc = momo2_rdesc_fixed;
498 *rsize = sizeof(momo2_rdesc_fixed);
499 }
500 break;
501
502 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
503 if (*rsize == FV_RDESC_ORIG_SIZE) {
504 hid_info(hdev,
505 "fixing up Logitech Formula Vibration report descriptor\n");
506 rdesc = fv_rdesc_fixed;
507 *rsize = sizeof(fv_rdesc_fixed);
508 }
509 break;
510
511 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
512 if (*rsize == DFP_RDESC_ORIG_SIZE) {
513 hid_info(hdev,
514 "fixing up Logitech Driving Force Pro report descriptor\n");
515 rdesc = dfp_rdesc_fixed;
516 *rsize = sizeof(dfp_rdesc_fixed);
517 }
518 break;
519
520 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
521 if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
522 rdesc[47] == 0x05 && rdesc[48] == 0x09) {
523 hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
524 rdesc[41] = 0x05;
525 rdesc[42] = 0x09;
526 rdesc[47] = 0x95;
527 rdesc[48] = 0x0B;
528 }
529 break;
530 }
531
532 return rdesc;
533}
534
535#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
536 EV_KEY, (c))
537
538static int lg_ultrax_remote_mapping(struct hid_input *hi,
539 struct hid_usage *usage, unsigned long **bit, int *max)
540{
541 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
542 return 0;
543
544 set_bit(EV_REP, hi->input->evbit);
545 switch (usage->hid & HID_USAGE) {
546
547 case 0x004: lg_map_key_clear(KEY_AGAIN); break;
548 case 0x00d: lg_map_key_clear(KEY_HOME); break;
549 case 0x024: lg_map_key_clear(KEY_SHUFFLE); break;
550 case 0x025: lg_map_key_clear(KEY_TV); break;
551 case 0x026: lg_map_key_clear(KEY_MENU); break;
552 case 0x031: lg_map_key_clear(KEY_AUDIO); break;
553 case 0x032: lg_map_key_clear(KEY_TEXT); break;
554 case 0x033: lg_map_key_clear(KEY_LAST); break;
555 case 0x047: lg_map_key_clear(KEY_MP3); break;
556 case 0x048: lg_map_key_clear(KEY_DVD); break;
557 case 0x049: lg_map_key_clear(KEY_MEDIA); break;
558 case 0x04a: lg_map_key_clear(KEY_VIDEO); break;
559 case 0x04b: lg_map_key_clear(KEY_ANGLE); break;
560 case 0x04c: lg_map_key_clear(KEY_LANGUAGE); break;
561 case 0x04d: lg_map_key_clear(KEY_SUBTITLE); break;
562 case 0x051: lg_map_key_clear(KEY_RED); break;
563 case 0x052: lg_map_key_clear(KEY_CLOSE); break;
564
565 default:
566 return 0;
567 }
568 return 1;
569}
570
571static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
572 unsigned long **bit, int *max)
573{
574 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
575 return 0;
576
577 switch (usage->hid & HID_USAGE) {
578 case 0x1001: lg_map_key_clear(KEY_MESSENGER); break;
579 case 0x1003: lg_map_key_clear(KEY_SOUND); break;
580 case 0x1004: lg_map_key_clear(KEY_VIDEO); break;
581 case 0x1005: lg_map_key_clear(KEY_AUDIO); break;
582 case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break;
583
584 case 0x100f: lg_map_key_clear(KEY_FN_1); break;
585 case 0x1010: lg_map_key_clear(KEY_FN_2); break;
586 case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break;
587 case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break;
588 case 0x1013: lg_map_key_clear(KEY_CAMERA); break;
589 case 0x1014: lg_map_key_clear(KEY_MESSENGER); break;
590 case 0x1015: lg_map_key_clear(KEY_RECORD); break;
591 case 0x1016: lg_map_key_clear(KEY_PLAYER); break;
592 case 0x1017: lg_map_key_clear(KEY_EJECTCD); break;
593 case 0x1018: lg_map_key_clear(KEY_MEDIA); break;
594 case 0x1019: lg_map_key_clear(KEY_PROG1); break;
595 case 0x101a: lg_map_key_clear(KEY_PROG2); break;
596 case 0x101b: lg_map_key_clear(KEY_PROG3); break;
597 case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
598 case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break;
599 case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break;
600 case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break;
601 case 0x1023: lg_map_key_clear(KEY_CLOSE); break;
602 case 0x1027: lg_map_key_clear(KEY_MENU); break;
603
604 case 0x1028: lg_map_key_clear(KEY_ANGLE); break;
605 case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break;
606 case 0x102a: lg_map_key_clear(KEY_BACK); break;
607 case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
608 case 0x102d: lg_map_key_clear(KEY_WWW); break;
609
610
611 case 0x1031: lg_map_key_clear(KEY_OK); break;
612 case 0x1032: lg_map_key_clear(KEY_CANCEL); break;
613 case 0x1041: lg_map_key_clear(KEY_BATTERY); break;
614 case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break;
615 case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break;
616 case 0x1044: lg_map_key_clear(KEY_PRESENTATION); break;
617 case 0x1045: lg_map_key_clear(KEY_UNDO); break;
618 case 0x1046: lg_map_key_clear(KEY_REDO); break;
619 case 0x1047: lg_map_key_clear(KEY_PRINT); break;
620 case 0x1048: lg_map_key_clear(KEY_SAVE); break;
621 case 0x1049: lg_map_key_clear(KEY_PROG1); break;
622 case 0x104a: lg_map_key_clear(KEY_PROG2); break;
623 case 0x104b: lg_map_key_clear(KEY_PROG3); break;
624 case 0x104c: lg_map_key_clear(KEY_PROG4); break;
625
626 default:
627 return 0;
628 }
629 return 1;
630}
631
632static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
633 struct hid_field *field, struct hid_usage *usage,
634 unsigned long **bit, int *max)
635{
636
637
638 static const u8 e_keymap[] = {
639 0,216, 0,213,175,156, 0, 0, 0, 0,
640 144, 0, 0, 0, 0, 0, 0, 0, 0,212,
641 174,167,152,161,112, 0, 0, 0,154, 0,
642 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
643 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
644 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
645 0, 0, 0, 0, 0,183,184,185,186,187,
646 188,189,190,191,192,193,194, 0, 0, 0
647 };
648 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
649 unsigned int hid = usage->hid;
650
651 if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
652 lg_ultrax_remote_mapping(hi, usage, bit, max))
653 return 1;
654
655 if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
656 return 1;
657
658 if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
659 return 0;
660
661 hid &= HID_USAGE;
662
663
664 if (field->application == HID_GD_MOUSE) {
665 if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
666 (hid == 7 || hid == 8))
667 return -1;
668 } else {
669 if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
670 hid < ARRAY_SIZE(e_keymap) &&
671 e_keymap[hid] != 0) {
672 hid_map_usage(hi, usage, bit, max, EV_KEY,
673 e_keymap[hid]);
674 return 1;
675 }
676 }
677
678 return 0;
679}
680
681static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
682 struct hid_field *field, struct hid_usage *usage,
683 unsigned long **bit, int *max)
684{
685 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
686
687 if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
688 (field->flags & HID_MAIN_ITEM_RELATIVE))
689 field->flags &= ~HID_MAIN_ITEM_RELATIVE;
690
691 if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
692 usage->type == EV_REL || usage->type == EV_ABS))
693 clear_bit(usage->code, *bit);
694
695
696 if (usage->type == EV_ABS && (usage->code == ABS_X ||
697 usage->code == ABS_Y || usage->code == ABS_Z ||
698 usage->code == ABS_RZ)) {
699 switch (hdev->product) {
700 case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
701 case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
702 case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
703 case USB_DEVICE_ID_LOGITECH_WHEEL:
704 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
705 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
706 case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
707 case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
708 case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
709 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
710 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
711 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
712 field->application = HID_GD_MULTIAXIS;
713 break;
714 default:
715 break;
716 }
717 }
718
719 return 0;
720}
721
722static int lg_event(struct hid_device *hdev, struct hid_field *field,
723 struct hid_usage *usage, __s32 value)
724{
725 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
726
727 if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
728 input_event(field->hidinput->input, usage->type, usage->code,
729 -value);
730 return 1;
731 }
732 if (drv_data->quirks & LG_FF4) {
733 return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
734 }
735
736 return 0;
737}
738
739static int lg_raw_event(struct hid_device *hdev, struct hid_report *report,
740 u8 *rd, int size)
741{
742 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
743
744 if (drv_data->quirks & LG_FF4)
745 return lg4ff_raw_event(hdev, report, rd, size, drv_data);
746
747 return 0;
748}
749
750static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
751{
752 struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
753 __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
754 unsigned int connect_mask = HID_CONNECT_DEFAULT;
755 struct lg_drv_data *drv_data;
756 int ret;
757
758
759 if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
760 (iface_num != 0)) {
761 dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
762 return -ENODEV;
763 }
764
765 drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
766 if (!drv_data) {
767 hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
768 return -ENOMEM;
769 }
770 drv_data->quirks = id->driver_data;
771
772 hid_set_drvdata(hdev, (void *)drv_data);
773
774 if (drv_data->quirks & LG_NOGET)
775 hdev->quirks |= HID_QUIRK_NOGET;
776
777 ret = hid_parse(hdev);
778 if (ret) {
779 hid_err(hdev, "parse failed\n");
780 goto err_free;
781 }
782
783 if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
784 connect_mask &= ~HID_CONNECT_FF;
785
786 ret = hid_hw_start(hdev, connect_mask);
787 if (ret) {
788 hid_err(hdev, "hw start failed\n");
789 goto err_free;
790 }
791
792
793 if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
794 static const unsigned char cbuf[] = {
795 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
796 };
797 u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
798
799 if (!buf) {
800 ret = -ENOMEM;
801 goto err_stop;
802 }
803
804 ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
805 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
806 if (ret >= 0) {
807
808 wait_queue_head_t wait;
809 init_waitqueue_head (&wait);
810 wait_event_interruptible_timeout(wait, 0,
811 msecs_to_jiffies(40));
812
813
814 buf[1] = 0xB2;
815 get_random_bytes(&buf[2], 2);
816
817 ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
818 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
819 }
820 kfree(buf);
821 }
822
823 if (drv_data->quirks & LG_FF)
824 ret = lgff_init(hdev);
825 else if (drv_data->quirks & LG_FF2)
826 ret = lg2ff_init(hdev);
827 else if (drv_data->quirks & LG_FF3)
828 ret = lg3ff_init(hdev);
829 else if (drv_data->quirks & LG_FF4)
830 ret = lg4ff_init(hdev);
831
832 if (ret)
833 goto err_stop;
834
835 return 0;
836
837err_stop:
838 hid_hw_stop(hdev);
839err_free:
840 kfree(drv_data);
841 return ret;
842}
843
844static void lg_remove(struct hid_device *hdev)
845{
846 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
847 if (drv_data->quirks & LG_FF4)
848 lg4ff_deinit(hdev);
849 hid_hw_stop(hdev);
850 kfree(drv_data);
851}
852
853static const struct hid_device_id lg_devices[] = {
854 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
855 .driver_data = LG_RDESC | LG_WIRELESS },
856
857 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
858 .driver_data = LG_BAD_RELATIVE_KEYS },
859
860 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
861 .driver_data = LG_DUPLICATE_USAGES },
862
863 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
864 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
865 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
866 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
867
868 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
869 .driver_data = LG_NOGET },
870 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
871 .driver_data = LG_NOGET },
872 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
873 .driver_data = LG_NOGET | LG_FF4 },
874
875 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
876 .driver_data = LG_FF2 },
877 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
878 .driver_data = LG_FF },
879 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
880 .driver_data = LG_FF },
881 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL),
882 .driver_data = LG_FF4 },
883 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
884 .driver_data = LG_FF },
885 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
886 .driver_data = LG_FF },
887 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
888 .driver_data = LG_NOGET | LG_FF4 },
889 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
890 .driver_data = LG_FF4 },
891 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
892 .driver_data = LG_FF2 },
893 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
894 .driver_data = LG_FF4 },
895 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
896 .driver_data = LG_FF4 },
897 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
898 .driver_data = LG_FF4 },
899 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
900 .driver_data = LG_NOGET | LG_FF4 },
901 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
902 .driver_data = LG_FF4 },
903 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG),
904 .driver_data = LG_NOGET },
905 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
906 .driver_data = LG_NOGET | LG_FF4 },
907 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
908 .driver_data = LG_NOGET | LG_FF2 },
909 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
910 .driver_data = LG_FF3 },
911 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
912 .driver_data = LG_RDESC_REL_ABS },
913 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
914 .driver_data = LG_RDESC_REL_ABS },
915 { }
916};
917
918MODULE_DEVICE_TABLE(hid, lg_devices);
919
920static struct hid_driver lg_driver = {
921 .name = "logitech",
922 .id_table = lg_devices,
923 .report_fixup = lg_report_fixup,
924 .input_mapping = lg_input_mapping,
925 .input_mapped = lg_input_mapped,
926 .event = lg_event,
927 .raw_event = lg_raw_event,
928 .probe = lg_probe,
929 .remove = lg_remove,
930};
931module_hid_driver(lg_driver);
932
933#ifdef CONFIG_LOGIWHEELS_FF
934int lg4ff_no_autoswitch = 0;
935module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
936MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
937#endif
938
939MODULE_LICENSE("GPL");
940