1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/device.h>
20#include <linux/hid.h>
21#include <linux/module.h>
22#include <linux/random.h>
23#include <linux/sched.h>
24#include <linux/usb.h>
25#include <linux/wait.h>
26
27#include "usbhid/usbhid.h"
28#include "hid-ids.h"
29#include "hid-lg.h"
30
31#define LG_RDESC 0x001
32#define LG_BAD_RELATIVE_KEYS 0x002
33#define LG_DUPLICATE_USAGES 0x004
34#define LG_EXPANDED_KEYMAP 0x010
35#define LG_IGNORE_DOUBLED_WHEEL 0x020
36#define LG_WIRELESS 0x040
37#define LG_INVERT_HWHEEL 0x080
38#define LG_NOGET 0x100
39#define LG_FF 0x200
40#define LG_FF2 0x400
41#define LG_RDESC_REL_ABS 0x800
42#define LG_FF3 0x1000
43#define LG_FF4 0x2000
44
45
46#define DF_RDESC_ORIG_SIZE 130
47#define DFP_RDESC_ORIG_SIZE 97
48#define FV_RDESC_ORIG_SIZE 130
49#define MOMO_RDESC_ORIG_SIZE 87
50#define MOMO2_RDESC_ORIG_SIZE 87
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
336
337
338
339
340
341static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
342 unsigned int *rsize)
343{
344 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
345 struct usb_device_descriptor *udesc;
346 __u16 bcdDevice, rev_maj, rev_min;
347
348 if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
349 rdesc[84] == 0x8c && rdesc[85] == 0x02) {
350 hid_info(hdev,
351 "fixing up Logitech keyboard report descriptor\n");
352 rdesc[84] = rdesc[89] = 0x4d;
353 rdesc[85] = rdesc[90] = 0x10;
354 }
355 if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
356 rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
357 rdesc[49] == 0x81 && rdesc[50] == 0x06) {
358 hid_info(hdev,
359 "fixing up rel/abs in Logitech report descriptor\n");
360 rdesc[33] = rdesc[50] = 0x02;
361 }
362
363 switch (hdev->product) {
364
365
366 case USB_DEVICE_ID_LOGITECH_WHEEL:
367 udesc = &(hid_to_usb_dev(hdev)->descriptor);
368 if (!udesc) {
369 hid_err(hdev, "NULL USB device descriptor\n");
370 break;
371 }
372 bcdDevice = le16_to_cpu(udesc->bcdDevice);
373 rev_maj = bcdDevice >> 8;
374 rev_min = bcdDevice & 0xff;
375
376
377 if (rev_maj == 1 && rev_min == 2 &&
378 *rsize == DF_RDESC_ORIG_SIZE) {
379 hid_info(hdev,
380 "fixing up Logitech Driving Force report descriptor\n");
381 rdesc = df_rdesc_fixed;
382 *rsize = sizeof(df_rdesc_fixed);
383 }
384 break;
385
386 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
387 if (*rsize == MOMO_RDESC_ORIG_SIZE) {
388 hid_info(hdev,
389 "fixing up Logitech Momo Force (Red) report descriptor\n");
390 rdesc = momo_rdesc_fixed;
391 *rsize = sizeof(momo_rdesc_fixed);
392 }
393 break;
394
395 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
396 if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
397 hid_info(hdev,
398 "fixing up Logitech Momo Racing Force (Black) report descriptor\n");
399 rdesc = momo2_rdesc_fixed;
400 *rsize = sizeof(momo2_rdesc_fixed);
401 }
402 break;
403
404 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
405 if (*rsize == FV_RDESC_ORIG_SIZE) {
406 hid_info(hdev,
407 "fixing up Logitech Formula Vibration report descriptor\n");
408 rdesc = fv_rdesc_fixed;
409 *rsize = sizeof(fv_rdesc_fixed);
410 }
411 break;
412
413 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
414 if (*rsize == DFP_RDESC_ORIG_SIZE) {
415 hid_info(hdev,
416 "fixing up Logitech Driving Force Pro report descriptor\n");
417 rdesc = dfp_rdesc_fixed;
418 *rsize = sizeof(dfp_rdesc_fixed);
419 }
420 break;
421
422 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
423 if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
424 rdesc[47] == 0x05 && rdesc[48] == 0x09) {
425 hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
426 rdesc[41] = 0x05;
427 rdesc[42] = 0x09;
428 rdesc[47] = 0x95;
429 rdesc[48] = 0x0B;
430 }
431 break;
432 }
433
434 return rdesc;
435}
436
437#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
438 EV_KEY, (c))
439
440static int lg_ultrax_remote_mapping(struct hid_input *hi,
441 struct hid_usage *usage, unsigned long **bit, int *max)
442{
443 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
444 return 0;
445
446 set_bit(EV_REP, hi->input->evbit);
447 switch (usage->hid & HID_USAGE) {
448
449 case 0x004: lg_map_key_clear(KEY_AGAIN); break;
450 case 0x00d: lg_map_key_clear(KEY_HOME); break;
451 case 0x024: lg_map_key_clear(KEY_SHUFFLE); break;
452 case 0x025: lg_map_key_clear(KEY_TV); break;
453 case 0x026: lg_map_key_clear(KEY_MENU); break;
454 case 0x031: lg_map_key_clear(KEY_AUDIO); break;
455 case 0x032: lg_map_key_clear(KEY_TEXT); break;
456 case 0x033: lg_map_key_clear(KEY_LAST); break;
457 case 0x047: lg_map_key_clear(KEY_MP3); break;
458 case 0x048: lg_map_key_clear(KEY_DVD); break;
459 case 0x049: lg_map_key_clear(KEY_MEDIA); break;
460 case 0x04a: lg_map_key_clear(KEY_VIDEO); break;
461 case 0x04b: lg_map_key_clear(KEY_ANGLE); break;
462 case 0x04c: lg_map_key_clear(KEY_LANGUAGE); break;
463 case 0x04d: lg_map_key_clear(KEY_SUBTITLE); break;
464 case 0x051: lg_map_key_clear(KEY_RED); break;
465 case 0x052: lg_map_key_clear(KEY_CLOSE); break;
466
467 default:
468 return 0;
469 }
470 return 1;
471}
472
473static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
474 unsigned long **bit, int *max)
475{
476 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
477 return 0;
478
479 switch (usage->hid & HID_USAGE) {
480
481 case 0x00d: lg_map_key_clear(KEY_MEDIA); break;
482 default:
483 return 0;
484
485 }
486 return 1;
487}
488
489static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
490 unsigned long **bit, int *max)
491{
492 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
493 return 0;
494
495 switch (usage->hid & HID_USAGE) {
496 case 0x1001: lg_map_key_clear(KEY_MESSENGER); break;
497 case 0x1003: lg_map_key_clear(KEY_SOUND); break;
498 case 0x1004: lg_map_key_clear(KEY_VIDEO); break;
499 case 0x1005: lg_map_key_clear(KEY_AUDIO); break;
500 case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break;
501
502 case 0x100f: lg_map_key_clear(KEY_FN_1); break;
503 case 0x1010: lg_map_key_clear(KEY_FN_2); break;
504 case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break;
505 case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break;
506 case 0x1013: lg_map_key_clear(KEY_CAMERA); break;
507 case 0x1014: lg_map_key_clear(KEY_MESSENGER); break;
508 case 0x1015: lg_map_key_clear(KEY_RECORD); break;
509 case 0x1016: lg_map_key_clear(KEY_PLAYER); break;
510 case 0x1017: lg_map_key_clear(KEY_EJECTCD); break;
511 case 0x1018: lg_map_key_clear(KEY_MEDIA); break;
512 case 0x1019: lg_map_key_clear(KEY_PROG1); break;
513 case 0x101a: lg_map_key_clear(KEY_PROG2); break;
514 case 0x101b: lg_map_key_clear(KEY_PROG3); break;
515 case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
516 case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break;
517 case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break;
518 case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break;
519 case 0x1023: lg_map_key_clear(KEY_CLOSE); break;
520 case 0x1027: lg_map_key_clear(KEY_MENU); break;
521
522 case 0x1028: lg_map_key_clear(KEY_ANGLE); break;
523 case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break;
524 case 0x102a: lg_map_key_clear(KEY_BACK); break;
525 case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
526 case 0x102d: lg_map_key_clear(KEY_WWW); break;
527
528
529 case 0x1031: lg_map_key_clear(KEY_OK); break;
530 case 0x1032: lg_map_key_clear(KEY_CANCEL); break;
531 case 0x1041: lg_map_key_clear(KEY_BATTERY); break;
532 case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break;
533 case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break;
534 case 0x1044: lg_map_key_clear(KEY_PRESENTATION); break;
535 case 0x1045: lg_map_key_clear(KEY_UNDO); break;
536 case 0x1046: lg_map_key_clear(KEY_REDO); break;
537 case 0x1047: lg_map_key_clear(KEY_PRINT); break;
538 case 0x1048: lg_map_key_clear(KEY_SAVE); break;
539 case 0x1049: lg_map_key_clear(KEY_PROG1); break;
540 case 0x104a: lg_map_key_clear(KEY_PROG2); break;
541 case 0x104b: lg_map_key_clear(KEY_PROG3); break;
542 case 0x104c: lg_map_key_clear(KEY_PROG4); break;
543
544 default:
545 return 0;
546 }
547 return 1;
548}
549
550static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
551 struct hid_field *field, struct hid_usage *usage,
552 unsigned long **bit, int *max)
553{
554
555
556 static const u8 e_keymap[] = {
557 0,216, 0,213,175,156, 0, 0, 0, 0,
558 144, 0, 0, 0, 0, 0, 0, 0, 0,212,
559 174,167,152,161,112, 0, 0, 0,154, 0,
560 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
561 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
562 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
563 0, 0, 0, 0, 0,183,184,185,186,187,
564 188,189,190,191,192,193,194, 0, 0, 0
565 };
566 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
567 unsigned int hid = usage->hid;
568
569 if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
570 lg_ultrax_remote_mapping(hi, usage, bit, max))
571 return 1;
572
573 if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
574 lg_dinovo_mapping(hi, usage, bit, max))
575 return 1;
576
577 if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
578 return 1;
579
580 if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
581 return 0;
582
583 hid &= HID_USAGE;
584
585
586 if (field->application == HID_GD_MOUSE) {
587 if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
588 (hid == 7 || hid == 8))
589 return -1;
590 } else {
591 if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
592 hid < ARRAY_SIZE(e_keymap) &&
593 e_keymap[hid] != 0) {
594 hid_map_usage(hi, usage, bit, max, EV_KEY,
595 e_keymap[hid]);
596 return 1;
597 }
598 }
599
600 return 0;
601}
602
603static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
604 struct hid_field *field, struct hid_usage *usage,
605 unsigned long **bit, int *max)
606{
607 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
608
609 if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
610 (field->flags & HID_MAIN_ITEM_RELATIVE))
611 field->flags &= ~HID_MAIN_ITEM_RELATIVE;
612
613 if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
614 usage->type == EV_REL || usage->type == EV_ABS))
615 clear_bit(usage->code, *bit);
616
617
618 if (usage->type == EV_ABS && (usage->code == ABS_X ||
619 usage->code == ABS_Y || usage->code == ABS_Z ||
620 usage->code == ABS_RZ)) {
621 switch (hdev->product) {
622 case USB_DEVICE_ID_LOGITECH_WHEEL:
623 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
624 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
625 case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
626 case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
627 case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
628 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
629 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
630 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
631 field->application = HID_GD_MULTIAXIS;
632 break;
633 default:
634 break;
635 }
636 }
637
638 return 0;
639}
640
641static int lg_event(struct hid_device *hdev, struct hid_field *field,
642 struct hid_usage *usage, __s32 value)
643{
644 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
645
646 if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
647 input_event(field->hidinput->input, usage->type, usage->code,
648 -value);
649 return 1;
650 }
651 if (drv_data->quirks & LG_FF4) {
652 return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
653 }
654
655 return 0;
656}
657
658static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
659{
660 unsigned int connect_mask = HID_CONNECT_DEFAULT;
661 struct lg_drv_data *drv_data;
662 int ret;
663
664 drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
665 if (!drv_data) {
666 hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
667 return -ENOMEM;
668 }
669 drv_data->quirks = id->driver_data;
670
671 hid_set_drvdata(hdev, (void *)drv_data);
672
673 if (drv_data->quirks & LG_NOGET)
674 hdev->quirks |= HID_QUIRK_NOGET;
675
676 ret = hid_parse(hdev);
677 if (ret) {
678 hid_err(hdev, "parse failed\n");
679 goto err_free;
680 }
681
682 if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
683 connect_mask &= ~HID_CONNECT_FF;
684
685 ret = hid_hw_start(hdev, connect_mask);
686 if (ret) {
687 hid_err(hdev, "hw start failed\n");
688 goto err_free;
689 }
690
691
692 if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
693 unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
694
695 ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
696 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
697
698 if (ret >= 0) {
699
700 wait_queue_head_t wait;
701 init_waitqueue_head (&wait);
702 wait_event_interruptible_timeout(wait, 0, 10);
703
704
705 buf[1] = 0xB2;
706 get_random_bytes(&buf[2], 2);
707
708 ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
709 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
710 }
711 }
712
713 if (drv_data->quirks & LG_FF)
714 lgff_init(hdev);
715 if (drv_data->quirks & LG_FF2)
716 lg2ff_init(hdev);
717 if (drv_data->quirks & LG_FF3)
718 lg3ff_init(hdev);
719 if (drv_data->quirks & LG_FF4)
720 lg4ff_init(hdev);
721
722 return 0;
723err_free:
724 kfree(drv_data);
725 return ret;
726}
727
728static void lg_remove(struct hid_device *hdev)
729{
730 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
731 if (drv_data->quirks & LG_FF4)
732 lg4ff_deinit(hdev);
733
734 hid_hw_stop(hdev);
735 kfree(drv_data);
736}
737
738static const struct hid_device_id lg_devices[] = {
739 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
740 .driver_data = LG_RDESC | LG_WIRELESS },
741 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
742 .driver_data = LG_RDESC | LG_WIRELESS },
743 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
744 .driver_data = LG_RDESC | LG_WIRELESS },
745
746 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
747 .driver_data = LG_BAD_RELATIVE_KEYS },
748
749 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
750 .driver_data = LG_DUPLICATE_USAGES },
751 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
752 .driver_data = LG_DUPLICATE_USAGES },
753 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
754 .driver_data = LG_DUPLICATE_USAGES },
755
756 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
757 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
758 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
759 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
760
761 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
762 .driver_data = LG_NOGET },
763 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
764 .driver_data = LG_NOGET },
765 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
766 .driver_data = LG_NOGET | LG_FF4 },
767
768 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
769 .driver_data = LG_FF2 },
770 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
771 .driver_data = LG_FF },
772 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
773 .driver_data = LG_FF },
774 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
775 .driver_data = LG_FF },
776 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
777 .driver_data = LG_FF },
778 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
779 .driver_data = LG_NOGET | LG_FF4 },
780 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
781 .driver_data = LG_FF4 },
782 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
783 .driver_data = LG_FF2 },
784 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
785 .driver_data = LG_FF4 },
786 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
787 .driver_data = LG_FF4 },
788 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
789 .driver_data = LG_FF4 },
790 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
791 .driver_data = LG_NOGET | LG_FF4 },
792 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
793 .driver_data = LG_FF4 },
794 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
795 .driver_data = LG_FF },
796 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
797 .driver_data = LG_FF2 },
798 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
799 .driver_data = LG_FF3 },
800 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
801 .driver_data = LG_RDESC_REL_ABS },
802 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
803 .driver_data = LG_RDESC_REL_ABS },
804 { }
805};
806
807MODULE_DEVICE_TABLE(hid, lg_devices);
808
809static struct hid_driver lg_driver = {
810 .name = "logitech",
811 .id_table = lg_devices,
812 .report_fixup = lg_report_fixup,
813 .input_mapping = lg_input_mapping,
814 .input_mapped = lg_input_mapped,
815 .event = lg_event,
816 .probe = lg_probe,
817 .remove = lg_remove,
818};
819module_hid_driver(lg_driver);
820
821MODULE_LICENSE("GPL");
822