diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-14 12:03:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-14 12:03:42 -0400 |
commit | 52d4e661ac92ab8e1a312fe527221a1311fe4cda (patch) | |
tree | 907f37beba526bac7dcffbef7253de3b445a2c1e | |
parent | f248488b397d52717f6683e2e53200aa687ffc89 (diff) | |
parent | d057fd4cb892087955568a139d15eae4115a0174 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (21 commits)
HID: hidraw_connect() memleak fix
HID: add hidraw interface
USB HID: provide hook for hidraw write()
HID: hiddev: Add 32bit ioctl compatibilty
HID: Add GeneralTouch touchscreen to the blacklist
HID: add support for Microsoft Wireless Laser Keyboard 6000
Input: add KEY_LOGOFF
USBHID: report descriptor fix for MacBook JIS keyboard
HID: trivial fixes in hid-debug
HID: fix input mapping for Microsoft Ergonomic Keyboard
HID: use hid-plff driver for GreenAsia 0e8f:0003 devices
USBHID: Add HID_QUIRK_NOGET for ELO Touch Screen 2700 display
HID: enable hiddev for the SantaRosa MacBookPro IR receiver
USBHID: add CM109 device to blacklist
HID: Report usage codes of keys as EV_MSC scancode events
HID: ignore all non-LED usages in output fields in hid-input
HID: fix whitespace damage
HID: add support for Thrustmaster FGT Force Feedback wheel
HID: minimal autosuspend support for USB HID devices
HID: add support for Microsoft Natural Ergonomic Keyboard 4000
...
-rw-r--r-- | drivers/hid/Kconfig | 19 | ||||
-rw-r--r-- | drivers/hid/Makefile | 2 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 16 | ||||
-rw-r--r-- | drivers/hid/hid-debug.c | 40 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 92 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 401 | ||||
-rw-r--r-- | drivers/hid/usbhid/Kconfig | 11 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 54 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-ff.c | 5 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-plff.c | 24 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 33 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-tmff.c | 161 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 12 | ||||
-rw-r--r-- | include/linux/hid.h | 7 | ||||
-rw-r--r-- | include/linux/hidraw.h | 86 | ||||
-rw-r--r-- | include/linux/input.h | 2 |
16 files changed, 877 insertions, 88 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 19667fcc722a..cacf89e65af4 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
@@ -46,6 +46,25 @@ config HID_DEBUG | |||
46 | 46 | ||
47 | If unsure, say N | 47 | If unsure, say N |
48 | 48 | ||
49 | config HIDRAW | ||
50 | bool "/dev/hidraw raw HID device support" | ||
51 | depends on HID | ||
52 | ---help--- | ||
53 | Say Y here if you want to support HID devices (from the USB | ||
54 | specification standpoint) that aren't strictly user interface | ||
55 | devices, like monitor controls and Uninterruptable Power Supplies. | ||
56 | |||
57 | This module supports these devices separately using a separate | ||
58 | event interface on /dev/hidraw. | ||
59 | |||
60 | There is also a /dev/hiddev configuration option in the USB HID | ||
61 | configuration menu. In comparison to hiddev, this device does not process | ||
62 | the hid events at all (no parsing, no lookups). This lets applications | ||
63 | to work on raw hid events when they want to, and avoid using transport-specific | ||
64 | userspace libhid/libusb libraries. | ||
65 | |||
66 | If unsure, say Y. | ||
67 | |||
49 | source "drivers/hid/usbhid/Kconfig" | 68 | source "drivers/hid/usbhid/Kconfig" |
50 | 69 | ||
51 | endif # HID_SUPPORT | 70 | endif # HID_SUPPORT |
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 68d1376a53fb..1ac5103f7c93 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile | |||
@@ -4,7 +4,9 @@ | |||
4 | hid-objs := hid-core.o hid-input.o | 4 | hid-objs := hid-core.o hid-input.o |
5 | 5 | ||
6 | obj-$(CONFIG_HID) += hid.o | 6 | obj-$(CONFIG_HID) += hid.o |
7 | |||
7 | hid-$(CONFIG_HID_DEBUG) += hid-debug.o | 8 | hid-$(CONFIG_HID_DEBUG) += hid-debug.o |
9 | hid-$(CONFIG_HIDRAW) += hidraw.o | ||
8 | 10 | ||
9 | obj-$(CONFIG_USB_HID) += usbhid/ | 11 | obj-$(CONFIG_USB_HID) += usbhid/ |
10 | obj-$(CONFIG_USB_MOUSE) += usbhid/ | 12 | obj-$(CONFIG_USB_MOUSE) += usbhid/ |
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 317cf8a7b63c..2884b036495a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/hid.h> | 30 | #include <linux/hid.h> |
31 | #include <linux/hiddev.h> | 31 | #include <linux/hiddev.h> |
32 | #include <linux/hid-debug.h> | 32 | #include <linux/hid-debug.h> |
33 | #include <linux/hidraw.h> | ||
33 | 34 | ||
34 | /* | 35 | /* |
35 | * Version Information | 36 | * Version Information |
@@ -979,6 +980,8 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
979 | 980 | ||
980 | if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) | 981 | if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) |
981 | hid->hiddev_report_event(hid, report); | 982 | hid->hiddev_report_event(hid, report); |
983 | if (hid->claimed & HID_CLAIMED_HIDRAW) | ||
984 | hidraw_report_event(hid, data, size); | ||
982 | 985 | ||
983 | for (n = 0; n < report->maxfield; n++) | 986 | for (n = 0; n < report->maxfield; n++) |
984 | hid_input_field(hid, report->field[n], data, interrupt); | 987 | hid_input_field(hid, report->field[n], data, interrupt); |
@@ -990,5 +993,18 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
990 | } | 993 | } |
991 | EXPORT_SYMBOL_GPL(hid_input_report); | 994 | EXPORT_SYMBOL_GPL(hid_input_report); |
992 | 995 | ||
996 | static int __init hid_init(void) | ||
997 | { | ||
998 | return hidraw_init(); | ||
999 | } | ||
1000 | |||
1001 | static void __exit hid_exit(void) | ||
1002 | { | ||
1003 | hidraw_exit(); | ||
1004 | } | ||
1005 | |||
1006 | module_init(hid_init); | ||
1007 | module_exit(hid_exit); | ||
1008 | |||
993 | MODULE_LICENSE(DRIVER_LICENSE); | 1009 | MODULE_LICENSE(DRIVER_LICENSE); |
994 | 1010 | ||
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index a13757b78980..5c24fe46d8eb 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c | |||
@@ -34,7 +34,7 @@ | |||
34 | struct hid_usage_entry { | 34 | struct hid_usage_entry { |
35 | unsigned page; | 35 | unsigned page; |
36 | unsigned usage; | 36 | unsigned usage; |
37 | char *description; | 37 | const char *description; |
38 | }; | 38 | }; |
39 | 39 | ||
40 | static const struct hid_usage_entry hid_usage_table[] = { | 40 | static const struct hid_usage_entry hid_usage_table[] = { |
@@ -365,8 +365,8 @@ void hid_resolv_usage(unsigned usage) { | |||
365 | } | 365 | } |
366 | EXPORT_SYMBOL_GPL(hid_resolv_usage); | 366 | EXPORT_SYMBOL_GPL(hid_resolv_usage); |
367 | 367 | ||
368 | __inline__ static void tab(int n) { | 368 | static void tab(int n) { |
369 | while (n--) printk(" "); | 369 | printk(KERN_DEBUG "%*s", n, ""); |
370 | } | 370 | } |
371 | 371 | ||
372 | void hid_dump_field(struct hid_field *field, int n) { | 372 | void hid_dump_field(struct hid_field *field, int n) { |
@@ -401,8 +401,8 @@ void hid_dump_field(struct hid_field *field, int n) { | |||
401 | tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); | 401 | tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); |
402 | } | 402 | } |
403 | if (field->unit) { | 403 | if (field->unit) { |
404 | char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; | 404 | static const char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; |
405 | char *units[5][8] = { | 405 | static const char *units[5][8] = { |
406 | { "None", "None", "None", "None", "None", "None", "None", "None" }, | 406 | { "None", "None", "None", "None", "None", "None", "None", "None" }, |
407 | { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, | 407 | { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, |
408 | { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, | 408 | { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, |
@@ -457,7 +457,7 @@ void hid_dump_field(struct hid_field *field, int n) { | |||
457 | printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); | 457 | printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); |
458 | printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); | 458 | printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); |
459 | printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); | 459 | printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); |
460 | printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); | 460 | printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : ""); |
461 | printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); | 461 | printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); |
462 | printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); | 462 | printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); |
463 | printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); | 463 | printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); |
@@ -470,7 +470,7 @@ void hid_dump_device(struct hid_device *device) { | |||
470 | struct hid_report *report; | 470 | struct hid_report *report; |
471 | struct list_head *list; | 471 | struct list_head *list; |
472 | unsigned i,k; | 472 | unsigned i,k; |
473 | static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; | 473 | static const char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; |
474 | 474 | ||
475 | if (!hid_debug) | 475 | if (!hid_debug) |
476 | return; | 476 | return; |
@@ -501,13 +501,13 @@ void hid_dump_input(struct hid_usage *usage, __s32 value) { | |||
501 | if (!hid_debug) | 501 | if (!hid_debug) |
502 | return; | 502 | return; |
503 | 503 | ||
504 | printk("hid-debug: input "); | 504 | printk(KERN_DEBUG "hid-debug: input "); |
505 | hid_resolv_usage(usage->hid); | 505 | hid_resolv_usage(usage->hid); |
506 | printk(" = %d\n", value); | 506 | printk(" = %d\n", value); |
507 | } | 507 | } |
508 | EXPORT_SYMBOL_GPL(hid_dump_input); | 508 | EXPORT_SYMBOL_GPL(hid_dump_input); |
509 | 509 | ||
510 | static char *events[EV_MAX + 1] = { | 510 | static const char *events[EV_MAX + 1] = { |
511 | [EV_SYN] = "Sync", [EV_KEY] = "Key", | 511 | [EV_SYN] = "Sync", [EV_KEY] = "Key", |
512 | [EV_REL] = "Relative", [EV_ABS] = "Absolute", | 512 | [EV_REL] = "Relative", [EV_ABS] = "Absolute", |
513 | [EV_MSC] = "Misc", [EV_LED] = "LED", | 513 | [EV_MSC] = "Misc", [EV_LED] = "LED", |
@@ -516,10 +516,10 @@ static char *events[EV_MAX + 1] = { | |||
516 | [EV_FF_STATUS] = "ForceFeedbackStatus", | 516 | [EV_FF_STATUS] = "ForceFeedbackStatus", |
517 | }; | 517 | }; |
518 | 518 | ||
519 | static char *syncs[2] = { | 519 | static const char *syncs[2] = { |
520 | [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", | 520 | [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", |
521 | }; | 521 | }; |
522 | static char *keys[KEY_MAX + 1] = { | 522 | static const char *keys[KEY_MAX + 1] = { |
523 | [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", | 523 | [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", |
524 | [KEY_1] = "1", [KEY_2] = "2", | 524 | [KEY_1] = "1", [KEY_2] = "2", |
525 | [KEY_3] = "3", [KEY_4] = "4", | 525 | [KEY_3] = "3", [KEY_4] = "4", |
@@ -697,7 +697,8 @@ static char *keys[KEY_MAX + 1] = { | |||
697 | [KEY_DEL_LINE] = "DeleteLine", | 697 | [KEY_DEL_LINE] = "DeleteLine", |
698 | [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", | 698 | [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", |
699 | [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", | 699 | [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", |
700 | [KEY_DOCUMENTS] = "Documents", | 700 | [KEY_DOCUMENTS] = "Documents", [KEY_SPELLCHECK] = "SpellCheck", |
701 | [KEY_LOGOFF] = "Logoff", | ||
701 | [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", | 702 | [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", |
702 | [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", | 703 | [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", |
703 | [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", | 704 | [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", |
@@ -715,7 +716,7 @@ static char *keys[KEY_MAX + 1] = { | |||
715 | [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", | 716 | [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", |
716 | }; | 717 | }; |
717 | 718 | ||
718 | static char *relatives[REL_MAX + 1] = { | 719 | static const char *relatives[REL_MAX + 1] = { |
719 | [REL_X] = "X", [REL_Y] = "Y", | 720 | [REL_X] = "X", [REL_Y] = "Y", |
720 | [REL_Z] = "Z", [REL_RX] = "Rx", | 721 | [REL_Z] = "Z", [REL_RX] = "Rx", |
721 | [REL_RY] = "Ry", [REL_RZ] = "Rz", | 722 | [REL_RY] = "Ry", [REL_RZ] = "Rz", |
@@ -723,7 +724,7 @@ static char *relatives[REL_MAX + 1] = { | |||
723 | [REL_WHEEL] = "Wheel", [REL_MISC] = "Misc", | 724 | [REL_WHEEL] = "Wheel", [REL_MISC] = "Misc", |
724 | }; | 725 | }; |
725 | 726 | ||
726 | static char *absolutes[ABS_MAX + 1] = { | 727 | static const char *absolutes[ABS_MAX + 1] = { |
727 | [ABS_X] = "X", [ABS_Y] = "Y", | 728 | [ABS_X] = "X", [ABS_Y] = "Y", |
728 | [ABS_Z] = "Z", [ABS_RX] = "Rx", | 729 | [ABS_Z] = "Z", [ABS_RX] = "Rx", |
729 | [ABS_RY] = "Ry", [ABS_RZ] = "Rz", | 730 | [ABS_RY] = "Ry", [ABS_RZ] = "Rz", |
@@ -739,12 +740,12 @@ static char *absolutes[ABS_MAX + 1] = { | |||
739 | [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", | 740 | [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", |
740 | }; | 741 | }; |
741 | 742 | ||
742 | static char *misc[MSC_MAX + 1] = { | 743 | static const char *misc[MSC_MAX + 1] = { |
743 | [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", | 744 | [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", |
744 | [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" | 745 | [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" |
745 | }; | 746 | }; |
746 | 747 | ||
747 | static char *leds[LED_MAX + 1] = { | 748 | static const char *leds[LED_MAX + 1] = { |
748 | [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", | 749 | [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", |
749 | [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", | 750 | [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", |
750 | [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", | 751 | [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", |
@@ -752,16 +753,16 @@ static char *leds[LED_MAX + 1] = { | |||
752 | [LED_MISC] = "Misc", | 753 | [LED_MISC] = "Misc", |
753 | }; | 754 | }; |
754 | 755 | ||
755 | static char *repeats[REP_MAX + 1] = { | 756 | static const char *repeats[REP_MAX + 1] = { |
756 | [REP_DELAY] = "Delay", [REP_PERIOD] = "Period" | 757 | [REP_DELAY] = "Delay", [REP_PERIOD] = "Period" |
757 | }; | 758 | }; |
758 | 759 | ||
759 | static char *sounds[SND_MAX + 1] = { | 760 | static const char *sounds[SND_MAX + 1] = { |
760 | [SND_CLICK] = "Click", [SND_BELL] = "Bell", | 761 | [SND_CLICK] = "Click", [SND_BELL] = "Bell", |
761 | [SND_TONE] = "Tone" | 762 | [SND_TONE] = "Tone" |
762 | }; | 763 | }; |
763 | 764 | ||
764 | static char **names[EV_MAX + 1] = { | 765 | static const char **names[EV_MAX + 1] = { |
765 | [EV_SYN] = syncs, [EV_KEY] = keys, | 766 | [EV_SYN] = syncs, [EV_KEY] = keys, |
766 | [EV_REL] = relatives, [EV_ABS] = absolutes, | 767 | [EV_REL] = relatives, [EV_ABS] = absolutes, |
767 | [EV_MSC] = misc, [EV_LED] = leds, | 768 | [EV_MSC] = misc, [EV_LED] = leds, |
@@ -777,4 +778,3 @@ void hid_resolv_event(__u8 type, __u16 code) { | |||
777 | names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); | 778 | names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); |
778 | } | 779 | } |
779 | EXPORT_SYMBOL_GPL(hid_resolv_event); | 780 | EXPORT_SYMBOL_GPL(hid_resolv_event); |
780 | |||
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 8edbd30cf795..0c3e12c1794c 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -53,7 +53,7 @@ static const unsigned char hid_keyboard[256] = { | |||
53 | 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, | 53 | 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, |
54 | 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, | 54 | 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, |
55 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, | 55 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, |
56 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, | 56 | unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk, |
57 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, | 57 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, |
58 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, | 58 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, |
59 | 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, | 59 | 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, |
@@ -86,6 +86,10 @@ static const struct { | |||
86 | #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) | 86 | #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) |
87 | #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) | 87 | #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) |
88 | 88 | ||
89 | /* hardware needing special handling due to colliding MSVENDOR page usages */ | ||
90 | #define IS_CHICONY_TACTICAL_PAD(x) (x->vendor == 0x04f2 && device->product == 0x0418) | ||
91 | #define IS_MS_KB(x) (x->vendor == 0x045e && (x->product == 0x00db || x->product == 0x00f9)) | ||
92 | |||
89 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK | 93 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK |
90 | 94 | ||
91 | struct hidinput_key_translation { | 95 | struct hidinput_key_translation { |
@@ -295,7 +299,7 @@ static int hidinput_getkeycode(struct input_dev *dev, int scancode, | |||
295 | { | 299 | { |
296 | struct hid_device *hid = dev->private; | 300 | struct hid_device *hid = dev->private; |
297 | struct hid_usage *usage; | 301 | struct hid_usage *usage; |
298 | 302 | ||
299 | usage = hidinput_find_key(hid, scancode, 0); | 303 | usage = hidinput_find_key(hid, scancode, 0); |
300 | if (usage) { | 304 | if (usage) { |
301 | *keycode = usage->code; | 305 | *keycode = usage->code; |
@@ -310,15 +314,15 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode, | |||
310 | struct hid_device *hid = dev->private; | 314 | struct hid_device *hid = dev->private; |
311 | struct hid_usage *usage; | 315 | struct hid_usage *usage; |
312 | int old_keycode; | 316 | int old_keycode; |
313 | 317 | ||
314 | if (keycode < 0 || keycode > KEY_MAX) | 318 | if (keycode < 0 || keycode > KEY_MAX) |
315 | return -EINVAL; | 319 | return -EINVAL; |
316 | 320 | ||
317 | usage = hidinput_find_key(hid, scancode, 0); | 321 | usage = hidinput_find_key(hid, scancode, 0); |
318 | if (usage) { | 322 | if (usage) { |
319 | old_keycode = usage->code; | 323 | old_keycode = usage->code; |
320 | usage->code = keycode; | 324 | usage->code = keycode; |
321 | 325 | ||
322 | clear_bit(old_keycode, dev->keybit); | 326 | clear_bit(old_keycode, dev->keybit); |
323 | set_bit(usage->code, dev->keybit); | 327 | set_bit(usage->code, dev->keybit); |
324 | dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode); | 328 | dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode); |
@@ -326,10 +330,10 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode, | |||
326 | * by another key */ | 330 | * by another key */ |
327 | if (hidinput_find_key (hid, 0, old_keycode)) | 331 | if (hidinput_find_key (hid, 0, old_keycode)) |
328 | set_bit(old_keycode, dev->keybit); | 332 | set_bit(old_keycode, dev->keybit); |
329 | 333 | ||
330 | return 0; | 334 | return 0; |
331 | } | 335 | } |
332 | 336 | ||
333 | return -EINVAL; | 337 | return -EINVAL; |
334 | } | 338 | } |
335 | 339 | ||
@@ -351,6 +355,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
351 | if (field->flags & HID_MAIN_ITEM_CONSTANT) | 355 | if (field->flags & HID_MAIN_ITEM_CONSTANT) |
352 | goto ignore; | 356 | goto ignore; |
353 | 357 | ||
358 | /* only LED usages are supported in output fields */ | ||
359 | if (field->report_type == HID_OUTPUT_REPORT && | ||
360 | (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { | ||
361 | dbg_hid_line(" [non-LED output field] "); | ||
362 | goto ignore; | ||
363 | } | ||
364 | |||
354 | switch (usage->hid & HID_USAGE_PAGE) { | 365 | switch (usage->hid & HID_USAGE_PAGE) { |
355 | 366 | ||
356 | case HID_UP_UNDEFINED: | 367 | case HID_UP_UNDEFINED: |
@@ -595,6 +606,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
595 | case 0x0f6: map_key_clear(KEY_NEXT); break; | 606 | case 0x0f6: map_key_clear(KEY_NEXT); break; |
596 | case 0x0fa: map_key_clear(KEY_BACK); break; | 607 | case 0x0fa: map_key_clear(KEY_BACK); break; |
597 | 608 | ||
609 | case 0x182: map_key_clear(KEY_BOOKMARKS); break; | ||
598 | case 0x183: map_key_clear(KEY_CONFIG); break; | 610 | case 0x183: map_key_clear(KEY_CONFIG); break; |
599 | case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; | 611 | case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; |
600 | case 0x185: map_key_clear(KEY_EDITOR); break; | 612 | case 0x185: map_key_clear(KEY_EDITOR); break; |
@@ -611,9 +623,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
611 | case 0x192: map_key_clear(KEY_CALC); break; | 623 | case 0x192: map_key_clear(KEY_CALC); break; |
612 | case 0x194: map_key_clear(KEY_FILE); break; | 624 | case 0x194: map_key_clear(KEY_FILE); break; |
613 | case 0x196: map_key_clear(KEY_WWW); break; | 625 | case 0x196: map_key_clear(KEY_WWW); break; |
626 | case 0x19c: map_key_clear(KEY_LOGOFF); break; | ||
614 | case 0x19e: map_key_clear(KEY_COFFEE); break; | 627 | case 0x19e: map_key_clear(KEY_COFFEE); break; |
615 | case 0x1a6: map_key_clear(KEY_HELP); break; | 628 | case 0x1a6: map_key_clear(KEY_HELP); break; |
616 | case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; | 629 | case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; |
630 | case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; | ||
631 | case 0x1b6: map_key_clear(KEY_MEDIA); break; | ||
632 | case 0x1b7: map_key_clear(KEY_SOUND); break; | ||
617 | case 0x1bc: map_key_clear(KEY_MESSENGER); break; | 633 | case 0x1bc: map_key_clear(KEY_MESSENGER); break; |
618 | case 0x1bd: map_key_clear(KEY_INFO); break; | 634 | case 0x1bd: map_key_clear(KEY_INFO); break; |
619 | case 0x201: map_key_clear(KEY_NEW); break; | 635 | case 0x201: map_key_clear(KEY_NEW); break; |
@@ -720,8 +736,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
720 | 736 | ||
721 | case HID_UP_MSVENDOR: | 737 | case HID_UP_MSVENDOR: |
722 | 738 | ||
723 | /* special case - Chicony Chicony KU-0418 tactical pad */ | 739 | /* Unfortunately, there are multiple devices which |
724 | if (device->vendor == 0x04f2 && device->product == 0x0418) { | 740 | * emit usages from MSVENDOR page that require different |
741 | * handling. If this list grows too much in the future, | ||
742 | * more general handling will have to be introduced here | ||
743 | * (i.e. another blacklist). | ||
744 | */ | ||
745 | |||
746 | /* Chicony Chicony KU-0418 tactical pad */ | ||
747 | if (IS_CHICONY_TACTICAL_PAD(device)) { | ||
725 | set_bit(EV_REP, input->evbit); | 748 | set_bit(EV_REP, input->evbit); |
726 | switch(usage->hid & HID_USAGE) { | 749 | switch(usage->hid & HID_USAGE) { |
727 | case 0xff01: map_key_clear(BTN_1); break; | 750 | case 0xff01: map_key_clear(BTN_1); break; |
@@ -737,6 +760,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
737 | case 0xff0b: map_key_clear(BTN_B); break; | 760 | case 0xff0b: map_key_clear(BTN_B); break; |
738 | default: goto ignore; | 761 | default: goto ignore; |
739 | } | 762 | } |
763 | |||
764 | /* Microsoft Natural Ergonomic Keyboard 4000 */ | ||
765 | } else if (IS_MS_KB(device)) { | ||
766 | switch(usage->hid & HID_USAGE) { | ||
767 | case 0xfd06: | ||
768 | map_key_clear(KEY_CHAT); | ||
769 | break; | ||
770 | case 0xfd07: | ||
771 | map_key_clear(KEY_PHONE); | ||
772 | break; | ||
773 | case 0xff05: | ||
774 | set_bit(EV_REP, input->evbit); | ||
775 | map_key_clear(KEY_F13); | ||
776 | set_bit(KEY_F14, input->keybit); | ||
777 | set_bit(KEY_F15, input->keybit); | ||
778 | set_bit(KEY_F16, input->keybit); | ||
779 | set_bit(KEY_F17, input->keybit); | ||
780 | set_bit(KEY_F18, input->keybit); | ||
781 | default: goto ignore; | ||
782 | } | ||
740 | } else { | 783 | } else { |
741 | goto ignore; | 784 | goto ignore; |
742 | } | 785 | } |
@@ -888,6 +931,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
888 | set_bit(KEY_VOLUMEDOWN, input->keybit); | 931 | set_bit(KEY_VOLUMEDOWN, input->keybit); |
889 | } | 932 | } |
890 | 933 | ||
934 | if (usage->type == EV_KEY) { | ||
935 | set_bit(EV_MSC, input->evbit); | ||
936 | set_bit(MSC_SCAN, input->mscbit); | ||
937 | } | ||
938 | |||
891 | hid_resolv_event(usage->type, usage->code); | 939 | hid_resolv_event(usage->type, usage->code); |
892 | 940 | ||
893 | dbg_hid_line("\n"); | 941 | dbg_hid_line("\n"); |
@@ -991,6 +1039,29 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
991 | return; | 1039 | return; |
992 | } | 1040 | } |
993 | 1041 | ||
1042 | /* Handling MS keyboards special buttons */ | ||
1043 | if (IS_MS_KB(hid) && usage->hid == (HID_UP_MSVENDOR | 0xff05)) { | ||
1044 | int key = 0; | ||
1045 | static int last_key = 0; | ||
1046 | switch (value) { | ||
1047 | case 0x01: key = KEY_F14; break; | ||
1048 | case 0x02: key = KEY_F15; break; | ||
1049 | case 0x04: key = KEY_F16; break; | ||
1050 | case 0x08: key = KEY_F17; break; | ||
1051 | case 0x10: key = KEY_F18; break; | ||
1052 | default: break; | ||
1053 | } | ||
1054 | if (key) { | ||
1055 | input_event(input, usage->type, key, 1); | ||
1056 | last_key = key; | ||
1057 | } else { | ||
1058 | input_event(input, usage->type, last_key, 0); | ||
1059 | } | ||
1060 | } | ||
1061 | /* report the usage code as scancode if the key status has changed */ | ||
1062 | if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) | ||
1063 | input_event(input, EV_MSC, MSC_SCAN, usage->hid); | ||
1064 | |||
994 | input_event(input, usage->type, usage->code, value); | 1065 | input_event(input, usage->type, usage->code, value); |
995 | 1066 | ||
996 | if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) | 1067 | if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) |
@@ -1051,6 +1122,9 @@ int hidinput_connect(struct hid_device *hid) | |||
1051 | int i, j, k; | 1122 | int i, j, k; |
1052 | int max_report_type = HID_OUTPUT_REPORT; | 1123 | int max_report_type = HID_OUTPUT_REPORT; |
1053 | 1124 | ||
1125 | if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT) | ||
1126 | return -1; | ||
1127 | |||
1054 | INIT_LIST_HEAD(&hid->inputs); | 1128 | INIT_LIST_HEAD(&hid->inputs); |
1055 | 1129 | ||
1056 | for (i = 0; i < hid->maxcollection; i++) | 1130 | for (i = 0; i < hid->maxcollection; i++) |
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c new file mode 100644 index 000000000000..8503197a8131 --- /dev/null +++ b/drivers/hid/hidraw.c | |||
@@ -0,0 +1,401 @@ | |||
1 | /* | ||
2 | * HID raw devices, giving access to raw HID events. | ||
3 | * | ||
4 | * In comparison to hiddev, this device does not process the | ||
5 | * hid events at all (no parsing, no lookups). This lets applications | ||
6 | * to work on raw hid events as they want to, and avoids a need to | ||
7 | * use a transport-specific userspace libhid/libusb libraries. | ||
8 | * | ||
9 | * Copyright (c) 2007 Jiri Kosina | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms and conditions of the GNU General Public License, | ||
15 | * version 2, as published by the Free Software Foundation. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/fs.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/cdev.h> | ||
28 | #include <linux/poll.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/major.h> | ||
31 | #include <linux/hid.h> | ||
32 | #include <linux/mutex.h> | ||
33 | |||
34 | #include <linux/hidraw.h> | ||
35 | |||
36 | static int hidraw_major; | ||
37 | static struct cdev hidraw_cdev; | ||
38 | static struct class *hidraw_class; | ||
39 | static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; | ||
40 | static DEFINE_SPINLOCK(minors_lock); | ||
41 | |||
42 | static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | ||
43 | { | ||
44 | struct hidraw_list *list = file->private_data; | ||
45 | int ret = 0, len; | ||
46 | char *report; | ||
47 | DECLARE_WAITQUEUE(wait, current); | ||
48 | |||
49 | while (ret == 0) { | ||
50 | |||
51 | mutex_lock(&list->read_mutex); | ||
52 | |||
53 | if (list->head == list->tail) { | ||
54 | add_wait_queue(&list->hidraw->wait, &wait); | ||
55 | set_current_state(TASK_INTERRUPTIBLE); | ||
56 | |||
57 | while (list->head == list->tail) { | ||
58 | if (file->f_flags & O_NONBLOCK) { | ||
59 | ret = -EAGAIN; | ||
60 | break; | ||
61 | } | ||
62 | if (signal_pending(current)) { | ||
63 | ret = -ERESTARTSYS; | ||
64 | break; | ||
65 | } | ||
66 | if (!list->hidraw->exist) { | ||
67 | ret = -EIO; | ||
68 | break; | ||
69 | } | ||
70 | |||
71 | /* allow O_NONBLOCK to work well from other threads */ | ||
72 | mutex_unlock(&list->read_mutex); | ||
73 | schedule(); | ||
74 | mutex_lock(&list->read_mutex); | ||
75 | set_current_state(TASK_INTERRUPTIBLE); | ||
76 | } | ||
77 | |||
78 | set_current_state(TASK_RUNNING); | ||
79 | remove_wait_queue(&list->hidraw->wait, &wait); | ||
80 | } | ||
81 | |||
82 | if (ret) | ||
83 | goto out; | ||
84 | |||
85 | report = list->buffer[list->tail].value; | ||
86 | len = list->buffer[list->tail].len > count ? | ||
87 | count : list->buffer[list->tail].len; | ||
88 | |||
89 | if (copy_to_user(buffer, list->buffer[list->tail].value, len)) { | ||
90 | ret = -EFAULT; | ||
91 | goto out; | ||
92 | } | ||
93 | ret += len; | ||
94 | |||
95 | kfree(list->buffer[list->tail].value); | ||
96 | list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); | ||
97 | } | ||
98 | out: | ||
99 | mutex_unlock(&list->read_mutex); | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | /* the first byte is expected to be a report number */ | ||
104 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | ||
105 | { | ||
106 | unsigned int minor = iminor(file->f_path.dentry->d_inode); | ||
107 | struct hid_device *dev = hidraw_table[minor]->hid; | ||
108 | __u8 *buf; | ||
109 | int ret = 0; | ||
110 | |||
111 | if (!dev->hid_output_raw_report) | ||
112 | return -ENODEV; | ||
113 | |||
114 | if (count > HID_MIN_BUFFER_SIZE) { | ||
115 | printk(KERN_WARNING "hidraw: pid %d passed too large report\n", | ||
116 | current->pid); | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | |||
120 | if (count < 2) { | ||
121 | printk(KERN_WARNING "hidraw: pid %d passed too short report\n", | ||
122 | current->pid); | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | |||
126 | buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); | ||
127 | if (!buf) | ||
128 | return -ENOMEM; | ||
129 | |||
130 | if (copy_from_user(buf, buffer, count)) { | ||
131 | ret = -EFAULT; | ||
132 | goto out; | ||
133 | } | ||
134 | |||
135 | ret = dev->hid_output_raw_report(dev, buf, count); | ||
136 | out: | ||
137 | kfree(buf); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static unsigned int hidraw_poll(struct file *file, poll_table *wait) | ||
142 | { | ||
143 | struct hidraw_list *list = file->private_data; | ||
144 | |||
145 | poll_wait(file, &list->hidraw->wait, wait); | ||
146 | if (list->head != list->tail) | ||
147 | return POLLIN | POLLRDNORM; | ||
148 | if (!list->hidraw->exist) | ||
149 | return POLLERR | POLLHUP; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int hidraw_open(struct inode *inode, struct file *file) | ||
154 | { | ||
155 | unsigned int minor = iminor(inode); | ||
156 | struct hidraw *dev; | ||
157 | struct hidraw_list *list; | ||
158 | int err = 0; | ||
159 | |||
160 | if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) { | ||
161 | err = -ENOMEM; | ||
162 | goto out; | ||
163 | } | ||
164 | |||
165 | spin_lock(&minors_lock); | ||
166 | if (!hidraw_table[minor]) { | ||
167 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | ||
168 | minor); | ||
169 | kfree(list); | ||
170 | err = -ENODEV; | ||
171 | goto out_unlock; | ||
172 | } | ||
173 | |||
174 | list->hidraw = hidraw_table[minor]; | ||
175 | mutex_init(&list->read_mutex); | ||
176 | list_add_tail(&list->node, &hidraw_table[minor]->list); | ||
177 | file->private_data = list; | ||
178 | |||
179 | dev = hidraw_table[minor]; | ||
180 | if (!dev->open++) | ||
181 | dev->hid->hid_open(dev->hid); | ||
182 | |||
183 | out_unlock: | ||
184 | spin_unlock(&minors_lock); | ||
185 | out: | ||
186 | return err; | ||
187 | |||
188 | } | ||
189 | |||
190 | static int hidraw_release(struct inode * inode, struct file * file) | ||
191 | { | ||
192 | unsigned int minor = iminor(inode); | ||
193 | struct hidraw *dev; | ||
194 | struct hidraw_list *list = file->private_data; | ||
195 | |||
196 | if (!hidraw_table[minor]) { | ||
197 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | ||
198 | minor); | ||
199 | return -ENODEV; | ||
200 | } | ||
201 | |||
202 | list_del(&list->node); | ||
203 | dev = hidraw_table[minor]; | ||
204 | if (!dev->open--) { | ||
205 | if (list->hidraw->exist) | ||
206 | dev->hid->hid_close(dev->hid); | ||
207 | else | ||
208 | kfree(list->hidraw); | ||
209 | } | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
215 | { | ||
216 | unsigned int minor = iminor(inode); | ||
217 | struct hidraw *dev = hidraw_table[minor]; | ||
218 | void __user *user_arg = (void __user*) arg; | ||
219 | |||
220 | switch (cmd) { | ||
221 | case HIDIOCGRDESCSIZE: | ||
222 | if (put_user(dev->hid->rsize, (int __user *)arg)) | ||
223 | return -EFAULT; | ||
224 | return 0; | ||
225 | |||
226 | case HIDIOCGRDESC: | ||
227 | { | ||
228 | __u32 len; | ||
229 | |||
230 | if (get_user(len, (int __user *)arg)) | ||
231 | return -EFAULT; | ||
232 | if (copy_to_user(*((__u8 **)(user_arg + | ||
233 | sizeof(__u32))), | ||
234 | dev->hid->rdesc, len)) | ||
235 | return -EFAULT; | ||
236 | return 0; | ||
237 | } | ||
238 | case HIDIOCGRAWINFO: | ||
239 | { | ||
240 | struct hidraw_devinfo dinfo; | ||
241 | |||
242 | dinfo.bustype = dev->hid->bus; | ||
243 | dinfo.vendor = dev->hid->vendor; | ||
244 | dinfo.product = dev->hid->product; | ||
245 | if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) | ||
246 | return -EFAULT; | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | default: | ||
251 | printk(KERN_EMERG "hidraw: unsupported ioctl() %x\n", | ||
252 | cmd); | ||
253 | } | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | |||
257 | static const struct file_operations hidraw_ops = { | ||
258 | .owner = THIS_MODULE, | ||
259 | .read = hidraw_read, | ||
260 | .write = hidraw_write, | ||
261 | .poll = hidraw_poll, | ||
262 | .open = hidraw_open, | ||
263 | .release = hidraw_release, | ||
264 | .ioctl = hidraw_ioctl, | ||
265 | }; | ||
266 | |||
267 | void hidraw_report_event(struct hid_device *hid, u8 *data, int len) | ||
268 | { | ||
269 | struct hidraw *dev = hid->hidraw; | ||
270 | struct hidraw_list *list; | ||
271 | |||
272 | list_for_each_entry(list, &dev->list, node) { | ||
273 | list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC); | ||
274 | list->buffer[list->head].len = len; | ||
275 | list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1); | ||
276 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
277 | } | ||
278 | |||
279 | wake_up_interruptible(&dev->wait); | ||
280 | } | ||
281 | EXPORT_SYMBOL_GPL(hidraw_report_event); | ||
282 | |||
283 | int hidraw_connect(struct hid_device *hid) | ||
284 | { | ||
285 | int minor, result; | ||
286 | struct hidraw *dev; | ||
287 | |||
288 | /* TODO currently we accept any HID device. This should later | ||
289 | * probably be fixed to accept only those devices which provide | ||
290 | * non-input applications | ||
291 | */ | ||
292 | |||
293 | dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL); | ||
294 | if (!dev) | ||
295 | return -ENOMEM; | ||
296 | |||
297 | result = -EINVAL; | ||
298 | |||
299 | spin_lock(&minors_lock); | ||
300 | |||
301 | for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) { | ||
302 | if (hidraw_table[minor]) | ||
303 | continue; | ||
304 | hidraw_table[minor] = dev; | ||
305 | result = 0; | ||
306 | break; | ||
307 | } | ||
308 | |||
309 | spin_unlock(&minors_lock); | ||
310 | |||
311 | if (result) { | ||
312 | kfree(dev); | ||
313 | goto out; | ||
314 | } | ||
315 | |||
316 | dev->dev = device_create(hidraw_class, NULL, MKDEV(hidraw_major, minor), | ||
317 | "%s%d", "hidraw", minor); | ||
318 | |||
319 | if (IS_ERR(dev->dev)) { | ||
320 | spin_lock(&minors_lock); | ||
321 | hidraw_table[minor] = NULL; | ||
322 | spin_unlock(&minors_lock); | ||
323 | result = PTR_ERR(dev->dev); | ||
324 | kfree(dev); | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | init_waitqueue_head(&dev->wait); | ||
329 | INIT_LIST_HEAD(&dev->list); | ||
330 | |||
331 | dev->hid = hid; | ||
332 | dev->minor = minor; | ||
333 | |||
334 | dev->exist = 1; | ||
335 | hid->hidraw = dev; | ||
336 | |||
337 | out: | ||
338 | return result; | ||
339 | |||
340 | } | ||
341 | EXPORT_SYMBOL_GPL(hidraw_connect); | ||
342 | |||
343 | void hidraw_disconnect(struct hid_device *hid) | ||
344 | { | ||
345 | struct hidraw *hidraw = hid->hidraw; | ||
346 | |||
347 | hidraw->exist = 0; | ||
348 | |||
349 | spin_lock(&minors_lock); | ||
350 | hidraw_table[hidraw->minor] = NULL; | ||
351 | spin_unlock(&minors_lock); | ||
352 | |||
353 | device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); | ||
354 | |||
355 | if (hidraw->open) { | ||
356 | hid->hid_close(hid); | ||
357 | wake_up_interruptible(&hidraw->wait); | ||
358 | } else { | ||
359 | kfree(hidraw); | ||
360 | } | ||
361 | } | ||
362 | EXPORT_SYMBOL_GPL(hidraw_disconnect); | ||
363 | |||
364 | int __init hidraw_init(void) | ||
365 | { | ||
366 | int result; | ||
367 | dev_t dev_id; | ||
368 | |||
369 | result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR, | ||
370 | HIDRAW_MAX_DEVICES, "hidraw"); | ||
371 | |||
372 | hidraw_major = MAJOR(dev_id); | ||
373 | |||
374 | if (result < 0) { | ||
375 | printk(KERN_WARNING "hidraw: can't get major number\n"); | ||
376 | result = 0; | ||
377 | goto out; | ||
378 | } | ||
379 | |||
380 | hidraw_class = class_create(THIS_MODULE, "hidraw"); | ||
381 | if (IS_ERR(hidraw_class)) { | ||
382 | result = PTR_ERR(hidraw_class); | ||
383 | unregister_chrdev(hidraw_major, "hidraw"); | ||
384 | goto out; | ||
385 | } | ||
386 | |||
387 | cdev_init(&hidraw_cdev, &hidraw_ops); | ||
388 | cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES); | ||
389 | out: | ||
390 | return result; | ||
391 | } | ||
392 | |||
393 | void __exit hidraw_exit(void) | ||
394 | { | ||
395 | dev_t dev_id = MKDEV(hidraw_major, 0); | ||
396 | |||
397 | cdev_del(&hidraw_cdev); | ||
398 | class_destroy(hidraw_class); | ||
399 | unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); | ||
400 | |||
401 | } | ||
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index 1b4b572f899b..c557d7040a69 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig | |||
@@ -71,19 +71,20 @@ config LOGITECH_FF | |||
71 | force feedback. | 71 | force feedback. |
72 | 72 | ||
73 | config PANTHERLORD_FF | 73 | config PANTHERLORD_FF |
74 | bool "PantherLord USB/PS2 2in1 Adapter support" | 74 | bool "PantherLord/GreenAsia based device support" |
75 | depends on HID_FF | 75 | depends on HID_FF |
76 | select INPUT_FF_MEMLESS if USB_HID | 76 | select INPUT_FF_MEMLESS if USB_HID |
77 | help | 77 | help |
78 | Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want | 78 | Say Y here if you have a PantherLord/GreenAsia based game controller |
79 | to enable force feedback support for it. | 79 | or adapter and want to enable force feedback support for it. |
80 | 80 | ||
81 | config THRUSTMASTER_FF | 81 | config THRUSTMASTER_FF |
82 | bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" | 82 | bool "ThrustMaster devices support (EXPERIMENTAL)" |
83 | depends on HID_FF && EXPERIMENTAL | 83 | depends on HID_FF && EXPERIMENTAL |
84 | select INPUT_FF_MEMLESS if USB_HID | 84 | select INPUT_FF_MEMLESS if USB_HID |
85 | help | 85 | help |
86 | Say Y here if you have a THRUSTMASTER FireStore Dual Power 2, | 86 | Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or |
87 | a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel, | ||
87 | and want to enable force feedback support for it. | 88 | and want to enable force feedback support for it. |
88 | Note: if you say N here, this device will still be supported, but without | 89 | Note: if you say N here, this device will still be supported, but without |
89 | force feedback. | 90 | force feedback. |
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 0a1f2b52a12f..b38e559b7a46 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/hid.h> | 32 | #include <linux/hid.h> |
33 | #include <linux/hiddev.h> | 33 | #include <linux/hiddev.h> |
34 | #include <linux/hid-debug.h> | 34 | #include <linux/hid-debug.h> |
35 | #include <linux/hidraw.h> | ||
35 | #include "usbhid.h" | 36 | #include "usbhid.h" |
36 | 37 | ||
37 | /* | 38 | /* |
@@ -512,7 +513,16 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, | |||
512 | 513 | ||
513 | int usbhid_open(struct hid_device *hid) | 514 | int usbhid_open(struct hid_device *hid) |
514 | { | 515 | { |
515 | ++hid->open; | 516 | struct usbhid_device *usbhid = hid->driver_data; |
517 | int res; | ||
518 | |||
519 | if (!hid->open++) { | ||
520 | res = usb_autopm_get_interface(usbhid->intf); | ||
521 | if (res < 0) { | ||
522 | hid->open--; | ||
523 | return -EIO; | ||
524 | } | ||
525 | } | ||
516 | if (hid_start_in(hid)) | 526 | if (hid_start_in(hid)) |
517 | hid_io_error(hid); | 527 | hid_io_error(hid); |
518 | return 0; | 528 | return 0; |
@@ -522,8 +532,10 @@ void usbhid_close(struct hid_device *hid) | |||
522 | { | 532 | { |
523 | struct usbhid_device *usbhid = hid->driver_data; | 533 | struct usbhid_device *usbhid = hid->driver_data; |
524 | 534 | ||
525 | if (!--hid->open) | 535 | if (!--hid->open) { |
526 | usb_kill_urb(usbhid->urbin); | 536 | usb_kill_urb(usbhid->urbin); |
537 | usb_autopm_put_interface(usbhid->intf); | ||
538 | } | ||
527 | } | 539 | } |
528 | 540 | ||
529 | /* | 541 | /* |
@@ -628,6 +640,28 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) | |||
628 | return 0; | 640 | return 0; |
629 | } | 641 | } |
630 | 642 | ||
643 | static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count) | ||
644 | { | ||
645 | struct usbhid_device *usbhid = hid->driver_data; | ||
646 | struct usb_device *dev = hid_to_usb_dev(hid); | ||
647 | struct usb_interface *intf = usbhid->intf; | ||
648 | struct usb_host_interface *interface = intf->cur_altsetting; | ||
649 | int ret; | ||
650 | |||
651 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
652 | HID_REQ_SET_REPORT, | ||
653 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
654 | cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf), | ||
655 | interface->desc.bInterfaceNumber, buf + 1, count - 1, | ||
656 | USB_CTRL_SET_TIMEOUT); | ||
657 | |||
658 | /* count also the report id */ | ||
659 | if (ret > 0) | ||
660 | ret++; | ||
661 | |||
662 | return ret; | ||
663 | } | ||
664 | |||
631 | static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) | 665 | static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) |
632 | { | 666 | { |
633 | struct usbhid_device *usbhid = hid->driver_data; | 667 | struct usbhid_device *usbhid = hid->driver_data; |
@@ -871,6 +905,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) | |||
871 | hid->hiddev_hid_event = hiddev_hid_event; | 905 | hid->hiddev_hid_event = hiddev_hid_event; |
872 | hid->hiddev_report_event = hiddev_report_event; | 906 | hid->hiddev_report_event = hiddev_report_event; |
873 | #endif | 907 | #endif |
908 | hid->hid_output_raw_report = usbhid_output_raw_report; | ||
874 | return hid; | 909 | return hid; |
875 | 910 | ||
876 | fail: | 911 | fail: |
@@ -909,6 +944,8 @@ static void hid_disconnect(struct usb_interface *intf) | |||
909 | hidinput_disconnect(hid); | 944 | hidinput_disconnect(hid); |
910 | if (hid->claimed & HID_CLAIMED_HIDDEV) | 945 | if (hid->claimed & HID_CLAIMED_HIDDEV) |
911 | hiddev_disconnect(hid); | 946 | hiddev_disconnect(hid); |
947 | if (hid->claimed & HID_CLAIMED_HIDRAW) | ||
948 | hidraw_disconnect(hid); | ||
912 | 949 | ||
913 | usb_free_urb(usbhid->urbin); | 950 | usb_free_urb(usbhid->urbin); |
914 | usb_free_urb(usbhid->urbctrl); | 951 | usb_free_urb(usbhid->urbctrl); |
@@ -941,11 +978,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
941 | hid->claimed |= HID_CLAIMED_INPUT; | 978 | hid->claimed |= HID_CLAIMED_INPUT; |
942 | if (!hiddev_connect(hid)) | 979 | if (!hiddev_connect(hid)) |
943 | hid->claimed |= HID_CLAIMED_HIDDEV; | 980 | hid->claimed |= HID_CLAIMED_HIDDEV; |
981 | if (!hidraw_connect(hid)) | ||
982 | hid->claimed |= HID_CLAIMED_HIDRAW; | ||
944 | 983 | ||
945 | usb_set_intfdata(intf, hid); | 984 | usb_set_intfdata(intf, hid); |
946 | 985 | ||
947 | if (!hid->claimed) { | 986 | if (!hid->claimed) { |
948 | printk ("HID device not claimed by input or hiddev\n"); | 987 | printk ("HID device claimed by neither input, hiddev nor hidraw\n"); |
949 | hid_disconnect(intf); | 988 | hid_disconnect(intf); |
950 | return -ENODEV; | 989 | return -ENODEV; |
951 | } | 990 | } |
@@ -961,10 +1000,16 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
961 | 1000 | ||
962 | if (hid->claimed & HID_CLAIMED_INPUT) | 1001 | if (hid->claimed & HID_CLAIMED_INPUT) |
963 | printk("input"); | 1002 | printk("input"); |
964 | if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV)) | 1003 | if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) || |
1004 | hid->claimed & HID_CLAIMED_HIDRAW)) | ||
965 | printk(","); | 1005 | printk(","); |
966 | if (hid->claimed & HID_CLAIMED_HIDDEV) | 1006 | if (hid->claimed & HID_CLAIMED_HIDDEV) |
967 | printk("hiddev%d", hid->minor); | 1007 | printk("hiddev%d", hid->minor); |
1008 | if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) && | ||
1009 | (hid->claimed & HID_CLAIMED_HIDRAW)) | ||
1010 | printk(","); | ||
1011 | if (hid->claimed & HID_CLAIMED_HIDRAW) | ||
1012 | printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor); | ||
968 | 1013 | ||
969 | c = "Device"; | 1014 | c = "Device"; |
970 | for (i = 0; i < hid->maxcollection; i++) { | 1015 | for (i = 0; i < hid->maxcollection; i++) { |
@@ -1048,6 +1093,7 @@ static struct usb_driver hid_driver = { | |||
1048 | .pre_reset = hid_pre_reset, | 1093 | .pre_reset = hid_pre_reset, |
1049 | .post_reset = hid_post_reset, | 1094 | .post_reset = hid_post_reset, |
1050 | .id_table = hid_usb_ids, | 1095 | .id_table = hid_usb_ids, |
1096 | .supports_autosuspend = 1, | ||
1051 | }; | 1097 | }; |
1052 | 1098 | ||
1053 | static int __init hid_init(void) | 1099 | static int __init hid_init(void) |
diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c index 23431fbbc3d7..22329feb3b5a 100644 --- a/drivers/hid/usbhid/hid-ff.c +++ b/drivers/hid/usbhid/hid-ff.c | |||
@@ -62,11 +62,14 @@ static struct hid_ff_initializer inits[] = { | |||
62 | { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ | 62 | { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ |
63 | #endif | 63 | #endif |
64 | #ifdef CONFIG_PANTHERLORD_FF | 64 | #ifdef CONFIG_PANTHERLORD_FF |
65 | { 0x810, 0x0001, hid_plff_init }, | 65 | { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */ |
66 | { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */ | ||
66 | #endif | 67 | #endif |
67 | #ifdef CONFIG_THRUSTMASTER_FF | 68 | #ifdef CONFIG_THRUSTMASTER_FF |
68 | { 0x44f, 0xb300, hid_tmff_init }, | 69 | { 0x44f, 0xb300, hid_tmff_init }, |
69 | { 0x44f, 0xb304, hid_tmff_init }, | 70 | { 0x44f, 0xb304, hid_tmff_init }, |
71 | { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */ | ||
72 | { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */ | ||
70 | #endif | 73 | #endif |
71 | #ifdef CONFIG_ZEROPLUS_FF | 74 | #ifdef CONFIG_ZEROPLUS_FF |
72 | { 0xc12, 0x0005, hid_zpff_init }, | 75 | { 0xc12, 0x0005, hid_zpff_init }, |
diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c index d6a8f2b49bd2..9eb83cf9d22b 100644 --- a/drivers/hid/usbhid/hid-plff.c +++ b/drivers/hid/usbhid/hid-plff.c | |||
@@ -1,5 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices | 2 | * Force feedback support for PantherLord/GreenAsia based devices |
3 | * | ||
4 | * The devices are distributed under various names and the same USB device ID | ||
5 | * can be used in both adapters and actual game controllers. | ||
6 | * | ||
7 | * 0810:0001 "Twin USB Joystick" | ||
8 | * - tested with PantherLord USB/PS2 2in1 Adapter | ||
9 | * - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT) | ||
10 | * | ||
11 | * 0e8f:0003 "GreenAsia Inc. USB Joystick " | ||
12 | * - tested with Köng Gaming gamepad | ||
3 | * | 13 | * |
4 | * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> | 14 | * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> |
5 | */ | 15 | */ |
@@ -67,11 +77,11 @@ int hid_plff_init(struct hid_device *hid) | |||
67 | struct input_dev *dev; | 77 | struct input_dev *dev; |
68 | int error; | 78 | int error; |
69 | 79 | ||
70 | /* The device contains 2 output reports (one for each | 80 | /* The device contains one output report per physical device, all |
71 | HID_QUIRK_MULTI_INPUT device), both containing 1 field, which | 81 | containing 1 field, which contains 4 ff00.0002 usages and 4 16bit |
72 | contains 4 ff00.0002 usages and 4 16bit absolute values. | 82 | absolute values. |
73 | 83 | ||
74 | The 2 input reports also contain a field which contains | 84 | The input reports also contain a field which contains |
75 | 8 ff00.0001 usages and 8 boolean values. Their meaning is | 85 | 8 ff00.0001 usages and 8 boolean values. Their meaning is |
76 | currently unknown. */ | 86 | currently unknown. */ |
77 | 87 | ||
@@ -122,8 +132,8 @@ int hid_plff_init(struct hid_device *hid) | |||
122 | usbhid_submit_report(hid, plff->report, USB_DIR_OUT); | 132 | usbhid_submit_report(hid, plff->report, USB_DIR_OUT); |
123 | } | 133 | } |
124 | 134 | ||
125 | printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 " | 135 | printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia " |
126 | "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n"); | 136 | "devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); |
127 | 137 | ||
128 | return 0; | 138 | return 0; |
129 | } | 139 | } |
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 6b21a214f419..41a59a80e7ed 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c | |||
@@ -61,6 +61,7 @@ | |||
61 | #define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c | 61 | #define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c |
62 | #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a | 62 | #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a |
63 | #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b | 63 | #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b |
64 | #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 | ||
64 | 65 | ||
65 | #define USB_VENDOR_ID_ASUS 0x0b05 | 66 | #define USB_VENDOR_ID_ASUS 0x0b05 |
66 | #define USB_DEVICE_ID_ASUS_LCM 0x1726 | 67 | #define USB_DEVICE_ID_ASUS_LCM 0x1726 |
@@ -86,6 +87,9 @@ | |||
86 | 87 | ||
87 | #define USB_VENDOR_ID_CIDC 0x1677 | 88 | #define USB_VENDOR_ID_CIDC 0x1677 |
88 | 89 | ||
90 | #define USB_VENDOR_ID_CMEDIA 0x0d8c | ||
91 | #define USB_DEVICE_ID_CM109 0x000e | ||
92 | |||
89 | #define USB_VENDOR_ID_CODEMERCS 0x07c0 | 93 | #define USB_VENDOR_ID_CODEMERCS 0x07c0 |
90 | #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 | 94 | #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 |
91 | #define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff | 95 | #define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff |
@@ -104,12 +108,17 @@ | |||
104 | #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 | 108 | #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 |
105 | #define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 | 109 | #define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 |
106 | 110 | ||
111 | #define USB_VENDOR_ID_ELO 0x04E7 | ||
112 | #define USB_DEVICE_ID_ELO_TS2700 0x0020 | ||
113 | |||
107 | #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f | 114 | #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f |
108 | #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 | 115 | #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 |
109 | 116 | ||
110 | #define USB_VENDOR_ID_GAMERON 0x0810 | 117 | #define USB_VENDOR_ID_GAMERON 0x0810 |
111 | #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 | 118 | #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 |
112 | 119 | ||
120 | #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc | ||
121 | |||
113 | #define USB_VENDOR_ID_GLAB 0x06c2 | 122 | #define USB_VENDOR_ID_GLAB 0x06c2 |
114 | #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 | 123 | #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 |
115 | #define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 | 124 | #define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 |
@@ -373,6 +382,7 @@ static const struct hid_blacklist { | |||
373 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, | 382 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, |
374 | 383 | ||
375 | { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, | 384 | { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, |
385 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, | ||
376 | { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, | 386 | { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, |
377 | 387 | ||
378 | { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, | 388 | { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, |
@@ -387,11 +397,16 @@ static const struct hid_blacklist { | |||
387 | { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE}, | 397 | { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE}, |
388 | { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, | 398 | { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, |
389 | { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE }, | 399 | { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE }, |
400 | { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE }, | ||
390 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, | 401 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, |
391 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, | 402 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, |
392 | { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, | 403 | { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, |
393 | { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, | 404 | { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, |
394 | { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, | 405 | { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, |
406 | { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE }, | ||
407 | { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE }, | ||
408 | { USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE }, | ||
409 | { USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE }, | ||
395 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, | 410 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, |
396 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, | 411 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, |
397 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE }, | 412 | { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE }, |
@@ -507,6 +522,7 @@ static const struct hid_blacklist { | |||
507 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, | 522 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, |
508 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, | 523 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, |
509 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, | 524 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, |
525 | { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, | ||
510 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, | 526 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, |
511 | { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, | 527 | { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, |
512 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, | 528 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, |
@@ -614,6 +630,8 @@ static const struct hid_rdesc_blacklist { | |||
614 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, | 630 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, |
615 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH }, | 631 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH }, |
616 | 632 | ||
633 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS }, | ||
634 | |||
617 | { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, | 635 | { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, |
618 | 636 | ||
619 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, | 637 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, |
@@ -927,6 +945,18 @@ static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize) | |||
927 | printk(KERN_INFO "Fixing up Cypress report descriptor\n"); | 945 | printk(KERN_INFO "Fixing up Cypress report descriptor\n"); |
928 | } | 946 | } |
929 | 947 | ||
948 | /* | ||
949 | * MacBook JIS keyboard has wrong logical maximum | ||
950 | */ | ||
951 | static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize) | ||
952 | { | ||
953 | if (rsize >= 60 && rdesc[53] == 0x65 | ||
954 | && rdesc[59] == 0x65) { | ||
955 | printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n"); | ||
956 | rdesc[53] = rdesc[59] = 0xe7; | ||
957 | } | ||
958 | } | ||
959 | |||
930 | 960 | ||
931 | static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) | 961 | static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) |
932 | { | 962 | { |
@@ -941,6 +971,9 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned | |||
941 | 971 | ||
942 | if (quirks & HID_QUIRK_RDESC_PETALYNX) | 972 | if (quirks & HID_QUIRK_RDESC_PETALYNX) |
943 | usbhid_fixup_petalynx_descriptor(rdesc, rsize); | 973 | usbhid_fixup_petalynx_descriptor(rdesc, rsize); |
974 | |||
975 | if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS) | ||
976 | usbhid_fixup_macbook_descriptor(rdesc, rsize); | ||
944 | } | 977 | } |
945 | 978 | ||
946 | /** | 979 | /** |
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c index 555bb48b4295..69882a726e99 100644 --- a/drivers/hid/usbhid/hid-tmff.c +++ b/drivers/hid/usbhid/hid-tmff.c | |||
@@ -36,16 +36,39 @@ | |||
36 | #include "usbhid.h" | 36 | #include "usbhid.h" |
37 | 37 | ||
38 | /* Usages for thrustmaster devices I know about */ | 38 | /* Usages for thrustmaster devices I know about */ |
39 | #define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) | 39 | #define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb) |
40 | 40 | ||
41 | struct dev_type { | ||
42 | u16 idVendor; | ||
43 | u16 idProduct; | ||
44 | const signed short *ff; | ||
45 | }; | ||
46 | |||
47 | static const signed short ff_rumble[] = { | ||
48 | FF_RUMBLE, | ||
49 | -1 | ||
50 | }; | ||
51 | |||
52 | static const signed short ff_joystick[] = { | ||
53 | FF_CONSTANT, | ||
54 | -1 | ||
55 | }; | ||
56 | |||
57 | static const struct dev_type devices[] = { | ||
58 | { 0x44f, 0xb300, ff_rumble }, | ||
59 | { 0x44f, 0xb304, ff_rumble }, | ||
60 | { 0x44f, 0xb651, ff_rumble }, /* FGT Rumble Force Wheel */ | ||
61 | { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */ | ||
62 | }; | ||
41 | 63 | ||
42 | struct tmff_device { | 64 | struct tmff_device { |
43 | struct hid_report *report; | 65 | struct hid_report *report; |
44 | struct hid_field *rumble; | 66 | struct hid_field *ff_field; |
45 | }; | 67 | }; |
46 | 68 | ||
47 | /* Changes values from 0 to 0xffff into values from minimum to maximum */ | 69 | /* Changes values from 0 to 0xffff into values from minimum to maximum */ |
48 | static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum) | 70 | static inline int hid_tmff_scale_u16(unsigned int in, |
71 | int minimum, int maximum) | ||
49 | { | 72 | { |
50 | int ret; | 73 | int ret; |
51 | 74 | ||
@@ -57,22 +80,57 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum) | |||
57 | return ret; | 80 | return ret; |
58 | } | 81 | } |
59 | 82 | ||
83 | /* Changes values from -0x80 to 0x7f into values from minimum to maximum */ | ||
84 | static inline int hid_tmff_scale_s8(int in, | ||
85 | int minimum, int maximum) | ||
86 | { | ||
87 | int ret; | ||
88 | |||
89 | ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum; | ||
90 | if (ret < minimum) | ||
91 | return minimum; | ||
92 | if (ret > maximum) | ||
93 | return maximum; | ||
94 | return ret; | ||
95 | } | ||
96 | |||
60 | static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) | 97 | static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) |
61 | { | 98 | { |
62 | struct hid_device *hid = input_get_drvdata(dev); | 99 | struct hid_device *hid = input_get_drvdata(dev); |
63 | struct tmff_device *tmff = data; | 100 | struct tmff_device *tmff = data; |
101 | struct hid_field *ff_field = tmff->ff_field; | ||
102 | int x, y; | ||
64 | int left, right; /* Rumbling */ | 103 | int left, right; /* Rumbling */ |
65 | 104 | ||
66 | left = hid_tmff_scale(effect->u.rumble.weak_magnitude, | 105 | switch (effect->type) { |
67 | tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); | 106 | case FF_CONSTANT: |
68 | right = hid_tmff_scale(effect->u.rumble.strong_magnitude, | 107 | x = hid_tmff_scale_s8(effect->u.ramp.start_level, |
69 | tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); | 108 | ff_field->logical_minimum, |
70 | 109 | ff_field->logical_maximum); | |
71 | tmff->rumble->value[0] = left; | 110 | y = hid_tmff_scale_s8(effect->u.ramp.end_level, |
72 | tmff->rumble->value[1] = right; | 111 | ff_field->logical_minimum, |
73 | dbg_hid("(left,right)=(%08x, %08x)\n", left, right); | 112 | ff_field->logical_maximum); |
74 | usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); | 113 | |
75 | 114 | dbg_hid("(x, y)=(%04x, %04x)\n", x, y); | |
115 | ff_field->value[0] = x; | ||
116 | ff_field->value[1] = y; | ||
117 | usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); | ||
118 | break; | ||
119 | |||
120 | case FF_RUMBLE: | ||
121 | left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude, | ||
122 | ff_field->logical_minimum, | ||
123 | ff_field->logical_maximum); | ||
124 | right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude, | ||
125 | ff_field->logical_minimum, | ||
126 | ff_field->logical_maximum); | ||
127 | |||
128 | dbg_hid("(left,right)=(%08x, %08x)\n", left, right); | ||
129 | ff_field->value[0] = left; | ||
130 | ff_field->value[1] = right; | ||
131 | usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); | ||
132 | break; | ||
133 | } | ||
76 | return 0; | 134 | return 0; |
77 | } | 135 | } |
78 | 136 | ||
@@ -82,14 +140,16 @@ int hid_tmff_init(struct hid_device *hid) | |||
82 | struct list_head *pos; | 140 | struct list_head *pos; |
83 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | 141 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); |
84 | struct input_dev *input_dev = hidinput->input; | 142 | struct input_dev *input_dev = hidinput->input; |
143 | const signed short *ff_bits = ff_joystick; | ||
85 | int error; | 144 | int error; |
145 | int i; | ||
86 | 146 | ||
87 | tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); | 147 | tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); |
88 | if (!tmff) | 148 | if (!tmff) |
89 | return -ENOMEM; | 149 | return -ENOMEM; |
90 | 150 | ||
91 | /* Find the report to use */ | 151 | /* Find the report to use */ |
92 | __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) { | 152 | list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) { |
93 | struct hid_report *report = (struct hid_report *)pos; | 153 | struct hid_report *report = (struct hid_report *)pos; |
94 | int fieldnum; | 154 | int fieldnum; |
95 | 155 | ||
@@ -100,48 +160,65 @@ int hid_tmff_init(struct hid_device *hid) | |||
100 | continue; | 160 | continue; |
101 | 161 | ||
102 | switch (field->usage[0].hid) { | 162 | switch (field->usage[0].hid) { |
103 | case THRUSTMASTER_USAGE_RUMBLE_LR: | 163 | case THRUSTMASTER_USAGE_FF: |
104 | if (field->report_count < 2) { | 164 | if (field->report_count < 2) { |
105 | warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2"); | 165 | warn("ignoring FF field with report_count < 2"); |
106 | continue; | 166 | continue; |
107 | } | 167 | } |
108 | 168 | ||
109 | if (field->logical_maximum == field->logical_minimum) { | 169 | if (field->logical_maximum == field->logical_minimum) { |
110 | warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum"); | 170 | warn("ignoring FF field with logical_maximum == logical_minimum"); |
111 | continue; | 171 | continue; |
112 | } | 172 | } |
113 | 173 | ||
114 | if (tmff->report && tmff->report != report) { | 174 | if (tmff->report && tmff->report != report) { |
115 | warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report"); | 175 | warn("ignoring FF field in other report"); |
116 | continue; | 176 | continue; |
117 | } | 177 | } |
118 | 178 | ||
119 | if (tmff->rumble && tmff->rumble != field) { | 179 | if (tmff->ff_field && tmff->ff_field != field) { |
120 | warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR"); | 180 | warn("ignoring duplicate FF field"); |
121 | continue; | 181 | continue; |
182 | } | ||
183 | |||
184 | tmff->report = report; | ||
185 | tmff->ff_field = field; | ||
186 | |||
187 | for (i = 0; i < ARRAY_SIZE(devices); i++) { | ||
188 | if (input_dev->id.vendor == devices[i].idVendor && | ||
189 | input_dev->id.product == devices[i].idProduct) { | ||
190 | ff_bits = devices[i].ff; | ||
191 | break; | ||
122 | } | 192 | } |
193 | } | ||
123 | 194 | ||
124 | tmff->report = report; | 195 | for (i = 0; ff_bits[i] >= 0; i++) |
125 | tmff->rumble = field; | 196 | set_bit(ff_bits[i], input_dev->ffbit); |
126 | 197 | ||
127 | set_bit(FF_RUMBLE, input_dev->ffbit); | 198 | break; |
128 | break; | ||
129 | 199 | ||
130 | default: | 200 | default: |
131 | warn("ignoring unknown output usage %08x", field->usage[0].hid); | 201 | warn("ignoring unknown output usage %08x", field->usage[0].hid); |
132 | continue; | 202 | continue; |
133 | } | 203 | } |
134 | } | 204 | } |
135 | } | 205 | } |
136 | 206 | ||
137 | error = input_ff_create_memless(input_dev, tmff, hid_tmff_play); | 207 | if (!tmff->report) { |
138 | if (error) { | 208 | err("cant find FF field in output reports\n"); |
139 | kfree(tmff); | 209 | error = -ENODEV; |
140 | return error; | 210 | goto fail; |
141 | } | 211 | } |
142 | 212 | ||
143 | info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>"); | 213 | error = input_ff_create_memless(input_dev, tmff, hid_tmff_play); |
214 | if (error) | ||
215 | goto fail; | ||
144 | 216 | ||
217 | info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>"); | ||
145 | return 0; | 218 | return 0; |
219 | |||
220 | fail: | ||
221 | kfree(tmff); | ||
222 | return error; | ||
146 | } | 223 | } |
147 | 224 | ||
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index e793127f971e..9837adcb17e9 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/usb.h> | 34 | #include <linux/usb.h> |
35 | #include <linux/hid.h> | 35 | #include <linux/hid.h> |
36 | #include <linux/hiddev.h> | 36 | #include <linux/hiddev.h> |
37 | #include <linux/compat.h> | ||
37 | #include "usbhid.h" | 38 | #include "usbhid.h" |
38 | 39 | ||
39 | #ifdef CONFIG_USB_DYNAMIC_MINORS | 40 | #ifdef CONFIG_USB_DYNAMIC_MINORS |
@@ -738,6 +739,14 @@ inval: | |||
738 | return -EINVAL; | 739 | return -EINVAL; |
739 | } | 740 | } |
740 | 741 | ||
742 | #ifdef CONFIG_COMPAT | ||
743 | static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
744 | { | ||
745 | struct inode *inode = file->f_path.dentry->d_inode; | ||
746 | return hiddev_ioctl(inode, file, cmd, compat_ptr(arg)); | ||
747 | } | ||
748 | #endif | ||
749 | |||
741 | static const struct file_operations hiddev_fops = { | 750 | static const struct file_operations hiddev_fops = { |
742 | .owner = THIS_MODULE, | 751 | .owner = THIS_MODULE, |
743 | .read = hiddev_read, | 752 | .read = hiddev_read, |
@@ -747,6 +756,9 @@ static const struct file_operations hiddev_fops = { | |||
747 | .release = hiddev_release, | 756 | .release = hiddev_release, |
748 | .ioctl = hiddev_ioctl, | 757 | .ioctl = hiddev_ioctl, |
749 | .fasync = hiddev_fasync, | 758 | .fasync = hiddev_fasync, |
759 | #ifdef CONFIG_COMPAT | ||
760 | .compat_ioctl = hiddev_compat_ioctl, | ||
761 | #endif | ||
750 | }; | 762 | }; |
751 | 763 | ||
752 | static struct usb_class_driver hiddev_class = { | 764 | static struct usb_class_driver hiddev_class = { |
diff --git a/include/linux/hid.h b/include/linux/hid.h index 898103b401f1..55e51f9f76cb 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -276,6 +276,7 @@ struct hid_item { | |||
276 | #define HID_QUIRK_HIDINPUT 0x00200000 | 276 | #define HID_QUIRK_HIDINPUT 0x00200000 |
277 | #define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL 0x00400000 | 277 | #define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL 0x00400000 |
278 | #define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP 0x00800000 | 278 | #define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP 0x00800000 |
279 | #define HID_QUIRK_IGNORE_HIDINPUT 0x01000000 | ||
279 | 280 | ||
280 | /* | 281 | /* |
281 | * Separate quirks for runtime report descriptor fixup | 282 | * Separate quirks for runtime report descriptor fixup |
@@ -285,6 +286,7 @@ struct hid_item { | |||
285 | #define HID_QUIRK_RDESC_LOGITECH 0x00000002 | 286 | #define HID_QUIRK_RDESC_LOGITECH 0x00000002 |
286 | #define HID_QUIRK_RDESC_SWAPPED_MIN_MAX 0x00000004 | 287 | #define HID_QUIRK_RDESC_SWAPPED_MIN_MAX 0x00000004 |
287 | #define HID_QUIRK_RDESC_PETALYNX 0x00000008 | 288 | #define HID_QUIRK_RDESC_PETALYNX 0x00000008 |
289 | #define HID_QUIRK_RDESC_MACBOOK_JIS 0x00000010 | ||
288 | 290 | ||
289 | /* | 291 | /* |
290 | * This is the global environment of the parser. This information is | 292 | * This is the global environment of the parser. This information is |
@@ -403,6 +405,7 @@ struct hid_control_fifo { | |||
403 | 405 | ||
404 | #define HID_CLAIMED_INPUT 1 | 406 | #define HID_CLAIMED_INPUT 1 |
405 | #define HID_CLAIMED_HIDDEV 2 | 407 | #define HID_CLAIMED_HIDDEV 2 |
408 | #define HID_CLAIMED_HIDRAW 4 | ||
406 | 409 | ||
407 | #define HID_CTRL_RUNNING 1 | 410 | #define HID_CTRL_RUNNING 1 |
408 | #define HID_OUT_RUNNING 2 | 411 | #define HID_OUT_RUNNING 2 |
@@ -438,6 +441,7 @@ struct hid_device { /* device report descriptor */ | |||
438 | 441 | ||
439 | struct list_head inputs; /* The list of inputs */ | 442 | struct list_head inputs; /* The list of inputs */ |
440 | void *hiddev; /* The hiddev structure */ | 443 | void *hiddev; /* The hiddev structure */ |
444 | void *hidraw; | ||
441 | int minor; /* Hiddev minor number */ | 445 | int minor; /* Hiddev minor number */ |
442 | 446 | ||
443 | wait_queue_head_t wait; /* For sleeping */ | 447 | wait_queue_head_t wait; /* For sleeping */ |
@@ -458,6 +462,9 @@ struct hid_device { /* device report descriptor */ | |||
458 | void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field, | 462 | void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field, |
459 | struct hid_usage *, __s32); | 463 | struct hid_usage *, __s32); |
460 | void (*hiddev_report_event) (struct hid_device *, struct hid_report *); | 464 | void (*hiddev_report_event) (struct hid_device *, struct hid_report *); |
465 | |||
466 | /* handler for raw output data, used by hidraw */ | ||
467 | int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t); | ||
461 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK | 468 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK |
462 | unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; | 469 | unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; |
463 | unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; | 470 | unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; |
diff --git a/include/linux/hidraw.h b/include/linux/hidraw.h new file mode 100644 index 000000000000..6676cd5e9954 --- /dev/null +++ b/include/linux/hidraw.h | |||
@@ -0,0 +1,86 @@ | |||
1 | #ifndef _HIDRAW_H | ||
2 | #define _HIDRAW_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (c) 2007 Jiri Kosina | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | */ | ||
17 | |||
18 | struct hidraw_report_descriptor { | ||
19 | __u32 size; | ||
20 | __u8 *value; | ||
21 | }; | ||
22 | |||
23 | struct hidraw_devinfo { | ||
24 | __u32 bustype; | ||
25 | __s16 vendor; | ||
26 | __s16 product; | ||
27 | }; | ||
28 | |||
29 | /* ioctl interface */ | ||
30 | #define HIDIOCGRDESCSIZE _IOR('H', 0x01, int) | ||
31 | #define HIDIOCGRDESC _IOR('H', 0x02, struct hidraw_report_descriptor) | ||
32 | #define HIDIOCGRAWINFO _IOR('H', 0x03, struct hidraw_devinfo) | ||
33 | |||
34 | #define HIDRAW_FIRST_MINOR 0 | ||
35 | #define HIDRAW_MAX_DEVICES 64 | ||
36 | /* number of reports to buffer */ | ||
37 | #define HIDRAW_BUFFER_SIZE 64 | ||
38 | |||
39 | |||
40 | /* kernel-only API declarations */ | ||
41 | #ifdef __KERNEL__ | ||
42 | |||
43 | #include <linux/hid.h> | ||
44 | |||
45 | struct hidraw { | ||
46 | unsigned int minor; | ||
47 | int exist; | ||
48 | int open; | ||
49 | wait_queue_head_t wait; | ||
50 | struct hid_device *hid; | ||
51 | struct device *dev; | ||
52 | struct list_head list; | ||
53 | }; | ||
54 | |||
55 | struct hidraw_report { | ||
56 | __u8 *value; | ||
57 | int len; | ||
58 | }; | ||
59 | |||
60 | struct hidraw_list { | ||
61 | struct hidraw_report buffer[HIDRAW_BUFFER_SIZE]; | ||
62 | int head; | ||
63 | int tail; | ||
64 | struct fasync_struct *fasync; | ||
65 | struct hidraw *hidraw; | ||
66 | struct list_head node; | ||
67 | struct mutex read_mutex; | ||
68 | }; | ||
69 | |||
70 | #ifdef CONFIG_HIDRAW | ||
71 | int hidraw_init(void); | ||
72 | void hidraw_exit(void); | ||
73 | void hidraw_report_event(struct hid_device *, u8 *, int); | ||
74 | int hidraw_connect(struct hid_device *); | ||
75 | void hidraw_disconnect(struct hid_device *); | ||
76 | #else | ||
77 | static inline int hidraw_init(void) { return 0; } | ||
78 | static inline void hidraw_exit(void) { } | ||
79 | static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { } | ||
80 | static inline int hidraw_connect(struct hid_device *hid) { return -1; } | ||
81 | static inline void hidraw_disconnect(struct hid_device *hid) { } | ||
82 | #endif | ||
83 | |||
84 | #endif | ||
85 | |||
86 | #endif | ||
diff --git a/include/linux/input.h b/include/linux/input.h index 6eb3aead7f1d..52d1bd434a50 100644 --- a/include/linux/input.h +++ b/include/linux/input.h | |||
@@ -523,6 +523,8 @@ struct input_absinfo { | |||
523 | #define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ | 523 | #define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ |
524 | #define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ | 524 | #define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ |
525 | #define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ | 525 | #define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ |
526 | #define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ | ||
527 | #define KEY_LOGOFF 0x1b1 /* AL Logoff */ | ||
526 | 528 | ||
527 | #define KEY_DEL_EOL 0x1c0 | 529 | #define KEY_DEL_EOL 0x1c0 |
528 | #define KEY_DEL_EOS 0x1c1 | 530 | #define KEY_DEL_EOS 0x1c1 |