From f345c37c37641beceb0e52f61bb4cbc72904ee09 Mon Sep 17 00:00:00 2001 From: Pekka Sarnila Date: Thu, 6 Mar 2008 13:23:14 +0100 Subject: HID: fixup fullspeed interval on highspeed Afatech DVB-T IR kbd Many vendors highspeed devices give erroneously fullspeed interval value in endpoint descriptor for interrupt endpoints. This quirk fixes up that by recalculating the right value for highspeed device. At the time of hid configuration this quirk calculates which highspeed interval value gives same interval delay as, or next smaller then, what it would be if the original value would be interpreted as fullspeed value. In subsequent urbs that new value is used instead. Forming the 'hid->name' in usb_hid_config() was moved up to accommodate more descriptive printk reporting the fixup. In this patch the quirk is set for one such device: Afatech DVB-T 2 infrared HID-keyboard. It reports value 16 which means 4,069s in highspeed while obviously 16ms was intended. In this case quirk calculates new value to be 8 which gives when interpreted as highspeed value 16ms as wanted. The behavior of the device was verified to be what expected both before and after the patch. Signed-off-by: Pekka Sarnila Signed-off-by: Jiri Kosina --- include/linux/hid.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/hid.h b/include/linux/hid.h index 74ff57596eb1..af1f7e57a12d 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -284,6 +284,7 @@ struct hid_item { #define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000 #define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000 #define HID_QUIRK_MICROSOFT_KEYS 0x08000000 +#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 /* * Separate quirks for runtime report descriptor fixup -- cgit v1.2.3 From 974faac46455076c709a745f546b348017ad18dc Mon Sep 17 00:00:00 2001 From: Jim Duchek Date: Fri, 14 Mar 2008 15:53:49 +0100 Subject: HID: quirk for MS Wireless Desktop Receiver (model 1028) Microsoft's wireless desktop receiver (Model 1028) has a bug in the report descriptor -- namely, in four seperate places it uses USAGE_MIN and _MAX when it quite obviously doesn't intend to. In other words, it reports that it has pretty much _everything_ in 'consumer' and 'generic desktop'. And then the X evdev driver believes I have a mouse with 36 absolute axes and a huge pile of keys and buttons, when I in fact, should have zero. 255/256 in three of the cases, and 0-1024 in another. This patch fixes the report descriptor of this device before it enters the HID parser. Signed-off-by: Jim Duchek Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-quirks.c | 26 ++++++++++++++++++++++++++ include/linux/hid.h | 1 + 2 files changed, 27 insertions(+) (limited to 'include/linux') diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 54b8f8311f94..81dc5e353dd8 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -335,6 +335,7 @@ #define USB_VENDOR_ID_MICROSOFT 0x045e #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b #define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d +#define USB_DEVICE_ID_DESKTOP_RECV_1028 0x00f9 #define USB_DEVICE_ID_MS_NE4K 0x00db #define USB_DEVICE_ID_MS_LK6K 0x00f9 @@ -724,6 +725,7 @@ static const struct hid_rdesc_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_DESKTOP_RECV_1028, HID_QUIRK_RDESC_MICROSOFT_RECV_1028 }, { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER }, @@ -1094,6 +1096,28 @@ static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rs } } +/* + * Microsoft Wireless Desktop Receiver (Model 1028) has several + * 'Usage Min/Max' where it ought to have 'Physical Min/Max' + */ +static void usbhid_fixup_microsoft_descriptor(unsigned char *rdesc, int rsize) +{ + if (rsize == 571 && rdesc[284] == 0x19 + && rdesc[286] == 0x2a + && rdesc[304] == 0x19 + && rdesc[306] == 0x29 + && rdesc[352] == 0x1a + && rdesc[355] == 0x2a + && rdesc[557] == 0x19 + && rdesc[559] == 0x29) { + printk(KERN_INFO "Fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n"); + rdesc[284] = rdesc[304] = rdesc[558] = 0x35; + rdesc[352] = 0x36; + rdesc[286] = rdesc[355] = 0x46; + rdesc[306] = rdesc[559] = 0x45; + } +} + static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) { if ((quirks & HID_QUIRK_RDESC_CYMOTION)) @@ -1117,6 +1141,8 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE) usbhid_fixup_samsung_irda_descriptor(rdesc, rsize); + if (quirks & HID_QUIRK_RDESC_MICROSOFT_RECV_1028) + usbhid_fixup_microsoft_descriptor(rdesc, rsize); } /** diff --git a/include/linux/hid.h b/include/linux/hid.h index af1f7e57a12d..e9701f22d423 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -297,6 +297,7 @@ struct hid_item { #define HID_QUIRK_RDESC_MACBOOK_JIS 0x00000010 #define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020 #define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 +#define HID_QUIRK_RDESC_MICROSOFT_RECV_1028 0x00000080 /* * This is the global environment of the parser. This information is -- cgit v1.2.3 From 5f1ab74f650b392ebcaa7cf3283e56d8dc6c7e56 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 14 Mar 2008 16:53:07 +0100 Subject: HID: Sunplus Wireless Desktop needs report descriptor fixup This device has reports lower logical maximum compared to the real usages for Zoom+ and Zoom- it emits. This patch bumps the values in the report descriptor up, and also adjusts HID_MAX_USAGE accordingly. Reported-by: Khelben Blackstaff Signed-off-by: Jiri Kosina --- drivers/hid/hid-input-quirks.c | 22 +++++++++++++++++++++- drivers/hid/usbhid/hid-quirks.c | 19 +++++++++++++++++++ include/linux/hid.h | 3 ++- 3 files changed, 42 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index dceadd0c1419..845d31d08fa5 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -276,6 +276,21 @@ static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input, return 1; } +static int quirk_sunplus_wdesktop(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x2003: map_key_clear(KEY_ZOOMIN); break; + case 0x2103: map_key_clear(KEY_ZOOMOUT); break; + default: + return 0; + } + return 1; +} + #define VENDOR_ID_BELKIN 0x1020 #define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006 @@ -306,6 +321,9 @@ static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input, #define VENDOR_ID_PETALYNX 0x18b1 #define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 +#define VENDOR_ID_SUNPLUS 0x04fc +#define DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8 + static const struct hid_input_blacklist { __u16 idVendor; __u16 idProduct; @@ -332,7 +350,9 @@ static const struct hid_input_blacklist { { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e }, { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote }, - + + { VENDOR_ID_SUNPLUS, DEVICE_ID_SUNPLUS_WDESKTOP, quirk_sunplus_wdesktop }, + { 0, 0, 0 } }; diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 81dc5e353dd8..f06356512067 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -381,6 +381,9 @@ #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab +#define USB_VENDOR_ID_SUNPLUS 0x04fc +#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8 + #define USB_VENDOR_ID_TOPMAX 0x0663 #define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 @@ -735,6 +738,8 @@ static const struct hid_rdesc_blacklist { { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE }, + { USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP, HID_QUIRK_RDESC_SUNPLUS_WDESKTOP }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, @@ -1009,6 +1014,17 @@ static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize) } } +static void usbhid_fixup_sunplus_wdesktop(unsigned char *rdesc, int rsize) +{ + if (rsize >= 107 && rdesc[104] == 0x26 + && rdesc[105] == 0x80 + && rdesc[106] == 0x03) { + printk(KERN_INFO "Fixing up Sunplus Wireless Desktop report descriptor\n"); + rdesc[105] = rdesc[110] = 0x03; + rdesc[106] = rdesc[111] = 0x21; + } +} + /* * Samsung IrDA remote controller (reports as Cypress USB Mouse). * @@ -1182,4 +1198,7 @@ void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct, __usbhid_fixup_report_descriptor(quirks, rdesc, rsize); } + if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP) + usbhid_fixup_sunplus_wdesktop(rdesc, rsize); + } diff --git a/include/linux/hid.h b/include/linux/hid.h index e9701f22d423..5bf6282f1635 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -298,6 +298,7 @@ struct hid_item { #define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020 #define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040 #define HID_QUIRK_RDESC_MICROSOFT_RECV_1028 0x00000080 +#define HID_QUIRK_RDESC_SUNPLUS_WDESKTOP 0x00000100 /* * This is the global environment of the parser. This information is @@ -322,7 +323,7 @@ struct hid_global { * This is the local environment. It is persistent up the next main-item. */ -#define HID_MAX_USAGES 8192 +#define HID_MAX_USAGES 12288 #define HID_DEFAULT_NUM_COLLECTIONS 16 struct hid_local { -- cgit v1.2.3 From 1b184cf37f5cf098f07725b483a2055e95725476 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 9 Mar 2008 16:29:24 +0100 Subject: HID: make function from dbg_hid To check paramters even if debug is disabled, convert dbg_hid to inline function with __attribute__(format) checking. Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- include/linux/hid.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/hid.h b/include/linux/hid.h index 5bf6282f1635..69ba58434dcb 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -569,7 +569,11 @@ static inline int hid_ff_init(struct hid_device *hid) { return -1; } #define dbg_hid_line(format, arg...) if (hid_debug) \ printk(format, ## arg) #else -#define dbg_hid(format, arg...) do {} while (0) +static inline int __attribute__((format(printf, 1, 2))) +dbg_hid(const char *fmt, ...) +{ + return 0; +} #define dbg_hid_line dbg_hid #endif -- cgit v1.2.3 From 1d1bdd20008416a744c0c844e231e7ba69c11699 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 19 Mar 2008 21:55:04 +0100 Subject: HID: move wait from hid to usbhid Since only place where this is used is usbhid, move it there. Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 16 ++++++++-------- drivers/hid/usbhid/usbhid.h | 3 ++- include/linux/hid.h | 2 -- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 120b49d2b4a6..f6a5d8930348 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -341,7 +341,7 @@ static void hid_irq_out(struct urb *urb) if (usbhid->outhead != usbhid->outtail) { if (hid_submit_out(hid)) { clear_bit(HID_OUT_RUNNING, &usbhid->iofl); - wake_up(&hid->wait); + wake_up(&usbhid->wait); } spin_unlock_irqrestore(&usbhid->outlock, flags); return; @@ -349,7 +349,7 @@ static void hid_irq_out(struct urb *urb) clear_bit(HID_OUT_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->outlock, flags); - wake_up(&hid->wait); + wake_up(&usbhid->wait); } /* @@ -391,7 +391,7 @@ static void hid_ctrl(struct urb *urb) if (usbhid->ctrlhead != usbhid->ctrltail) { if (hid_submit_ctrl(hid)) { clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); - wake_up(&hid->wait); + wake_up(&usbhid->wait); } spin_unlock_irqrestore(&usbhid->ctrllock, flags); return; @@ -399,7 +399,7 @@ static void hid_ctrl(struct urb *urb) clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); spin_unlock_irqrestore(&usbhid->ctrllock, flags); - wake_up(&hid->wait); + wake_up(&usbhid->wait); } void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) @@ -478,8 +478,9 @@ int usbhid_wait_io(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; - if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && - !test_bit(HID_OUT_RUNNING, &usbhid->iofl)), + if (!wait_event_timeout(usbhid->wait, + (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && + !test_bit(HID_OUT_RUNNING, &usbhid->iofl)), 10*HZ)) { dbg_hid("timeout waiting for ctrl or out queue to clear\n"); return -1; @@ -869,8 +870,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) goto fail; } - init_waitqueue_head(&hid->wait); - + init_waitqueue_head(&usbhid->wait); INIT_WORK(&usbhid->reset_work, hid_reset); setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index 0023f96d4294..62d2d7c925bd 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -77,7 +78,7 @@ struct usbhid_device { unsigned long stop_retry; /* Time to give up, in jiffies */ unsigned int retry_delay; /* Delay length in ms */ struct work_struct reset_work; /* Task context for resets */ - + wait_queue_head_t wait; /* For sleeping */ }; #define hid_to_usb_dev(hid_dev) \ diff --git a/include/linux/hid.h b/include/linux/hid.h index 69ba58434dcb..9db600f72e2a 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -455,8 +455,6 @@ struct hid_device { /* device report descriptor */ void *hidraw; int minor; /* Hiddev minor number */ - wait_queue_head_t wait; /* For sleeping */ - int open; /* is the device open by anyone? */ char name[128]; /* Device name */ char phys[64]; /* Device physical location */ -- cgit v1.2.3 From c17f9c901c4e62cbf857b831bcc3070380449b88 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Tue, 1 Apr 2008 01:51:11 +0200 Subject: HID: force feedback driver for Logitech Rumblepad 2 Add force feedback support for Logitech Rumblepad 2. Tested-By: Edgar Simo Signed-off-by: Anssi Hannula Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/Kconfig | 8 +++ drivers/hid/usbhid/Makefile | 3 ++ drivers/hid/usbhid/hid-ff.c | 3 ++ drivers/hid/usbhid/hid-lg2ff.c | 114 +++++++++++++++++++++++++++++++++++++++++ include/linux/hid.h | 1 + 5 files changed, 129 insertions(+) create mode 100644 drivers/hid/usbhid/hid-lg2ff.c (limited to 'include/linux') diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index 7160fa65d79b..a5f0fb0fdaf4 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -71,6 +71,14 @@ config LOGITECH_FF Note: if you say N here, this device will still be supported, but without force feedback. +config LOGIRUMBLEPAD2_FF + bool "Logitech Rumblepad 2 support" + depends on HID_FF + select INPUT_FF_MEMLESS if USB_HID + help + Say Y here if you want to enable force feedback support for Logitech + Rumblepad 2 devices. + config PANTHERLORD_FF bool "PantherLord/GreenAsia based device support" depends on HID_FF diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile index 8e6ab5b164a2..00a7b7090192 100644 --- a/drivers/hid/usbhid/Makefile +++ b/drivers/hid/usbhid/Makefile @@ -16,6 +16,9 @@ endif ifeq ($(CONFIG_LOGITECH_FF),y) usbhid-objs += hid-lgff.o endif +ifeq ($(CONFIG_LOGIRUMBLEPAD2_FF),y) + usbhid-objs += hid-lg2ff.o +endif ifeq ($(CONFIG_PANTHERLORD_FF),y) usbhid-objs += hid-plff.o endif diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c index 4c210e16b1b4..1d0dac52f166 100644 --- a/drivers/hid/usbhid/hid-ff.c +++ b/drivers/hid/usbhid/hid-ff.c @@ -59,6 +59,9 @@ static struct hid_ff_initializer inits[] = { { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */ { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ #endif +#ifdef CONFIG_LOGIRUMBLEPAD2_FF + { 0x46d, 0xc218, hid_lg2ff_init }, /* Logitech Rumblepad 2 */ +#endif #ifdef CONFIG_PANTHERLORD_FF { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */ { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */ diff --git a/drivers/hid/usbhid/hid-lg2ff.c b/drivers/hid/usbhid/hid-lg2ff.c new file mode 100644 index 000000000000..d469bd0061c9 --- /dev/null +++ b/drivers/hid/usbhid/hid-lg2ff.c @@ -0,0 +1,114 @@ +/* + * Force feedback support for Logitech Rumblepad 2 + * + * Copyright (c) 2008 Anssi Hannula + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include "usbhid.h" + +struct lg2ff_device { + struct hid_report *report; +}; + +static int play_effect(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct lg2ff_device *lg2ff = data; + int weak, strong; + + strong = effect->u.rumble.strong_magnitude; + weak = effect->u.rumble.weak_magnitude; + + if (weak || strong) { + weak = weak * 0xff / 0xffff; + strong = strong * 0xff / 0xffff; + + lg2ff->report->field[0]->value[0] = 0x51; + lg2ff->report->field[0]->value[2] = weak; + lg2ff->report->field[0]->value[4] = strong; + } else { + lg2ff->report->field[0]->value[0] = 0xf3; + lg2ff->report->field[0]->value[2] = 0x00; + lg2ff->report->field[0]->value[4] = 0x00; + } + + usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT); + return 0; +} + +int hid_lg2ff_init(struct hid_device *hid) +{ + struct lg2ff_device *lg2ff; + struct hid_report *report; + struct hid_input *hidinput = list_entry(hid->inputs.next, + struct hid_input, list); + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + int error; + + if (list_empty(report_list)) { + printk(KERN_ERR "hid-lg2ff: no output report found\n"); + return -ENODEV; + } + + report = list_entry(report_list->next, struct hid_report, list); + + if (report->maxfield < 1) { + printk(KERN_ERR "hid-lg2ff: output report is empty\n"); + return -ENODEV; + } + if (report->field[0]->report_count < 7) { + printk(KERN_ERR "hid-lg2ff: not enough values in the field\n"); + return -ENODEV; + } + + lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL); + if (!lg2ff) + return -ENOMEM; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, lg2ff, play_effect); + if (error) { + kfree(lg2ff); + return error; + } + + lg2ff->report = report; + report->field[0]->value[0] = 0xf3; + report->field[0]->value[1] = 0x00; + report->field[0]->value[2] = 0x00; + report->field[0]->value[3] = 0x00; + report->field[0]->value[4] = 0x00; + report->field[0]->value[5] = 0x00; + report->field[0]->value[6] = 0x00; + + usbhid_submit_report(hid, report, USB_DIR_OUT); + + printk(KERN_INFO "Force feedback for Logitech Rumblepad 2 by " + "Anssi Hannula \n"); + + return 0; +} diff --git a/include/linux/hid.h b/include/linux/hid.h index 9db600f72e2a..cd526af12d7b 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -547,6 +547,7 @@ void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char int hid_ff_init(struct hid_device *hid); int hid_lgff_init(struct hid_device *hid); +int hid_lg2ff_init(struct hid_device *hid); int hid_plff_init(struct hid_device *hid); int hid_tmff_init(struct hid_device *hid); int hid_zpff_init(struct hid_device *hid); -- cgit v1.2.3 From abdff0f7749a6696ba2a4238b675cbc55abcdb7a Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 31 Mar 2008 01:53:56 +0200 Subject: HID: make hid_input_field and usbhid_modify_dquirk static This patch makes the following needlessly global functions static: - hid-core.c:hid_input_field() - usbhid/hid-quirks.c:usbhid_modify_dquirk() Signed-off-by: Adrian Bunk Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 4 ++-- drivers/hid/usbhid/hid-quirks.c | 4 ++-- include/linux/hid.h | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 10f925b892d7..e03c67dd3e63 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -830,7 +830,8 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s * reporting to the layer). */ -void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt) +static void hid_input_field(struct hid_device *hid, struct hid_field *field, + __u8 *data, int interrupt) { unsigned n; unsigned count = field->report_count; @@ -876,7 +877,6 @@ void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data exit: kfree(value); } -EXPORT_SYMBOL_GPL(hid_input_field); /* * Output the field into the report. diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 6ad33fe2c165..433feb67ca1a 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -809,8 +809,8 @@ static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor, * * Returns: 0 OK, -error on failure. */ -int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, - const u32 quirks) +static int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, + const u32 quirks) { struct quirks_list_struct *q_new, *q; int list_edited = 0; diff --git a/include/linux/hid.h b/include/linux/hid.h index cd526af12d7b..fe4ac31eced2 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -531,14 +531,12 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int int hidinput_mapping_quirks(struct hid_usage *, struct input_dev *, unsigned long **, int *); int hidinput_event_quirks(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); int hidinput_apple_event(struct hid_device *, struct input_dev *, struct hid_usage *, __s32); -void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt); void hid_output_report(struct hid_report *report, __u8 *data); void hid_free_device(struct hid_device *device); struct hid_device *hid_parse_report(__u8 *start, unsigned size); /* HID quirks API */ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct); -int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, const u32 quirks); int usbhid_quirks_init(char **quirks_param); void usbhid_quirks_exit(void); void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **); -- cgit v1.2.3 From 69626f23bce6521367ac1e6a2a6e8fba8f0a848a Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 31 Mar 2008 16:27:30 +0200 Subject: HID: fix race between open() and disconnect() in usbhid There is a window: task A task B spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ usb_set_intfdata(intf, NULL); spin_unlock_irq(&usbhid->inlock); usb_kill_urb(usbhid->urbin); usb_kill_urb(usbhid->urbout); usb_kill_urb(usbhid->urbctrl); del_timer_sync(&usbhid->io_retry); cancel_work_sync(&usbhid->reset_work); if (!hid->open++) { res = usb_autopm_get_interface(usbhid->intf); if (res < 0) { hid->open--; return -EIO; } } if (hid_start_in(hid)) if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); in which an open() to an already disconnected device will submit an URB to an undead device. In case disconnect() was called by an ioctl, this'll oops. Fix by introducing a new flag and checking it in hid_start_in(). Signed-off-by: Oliver Neukum Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 4 +++- include/linux/hid.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index f6a5d8930348..e0d805f1b2bf 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -82,6 +82,7 @@ static int hid_start_in(struct hid_device *hid) spin_lock_irqsave(&usbhid->inlock, flags); if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) && + !test_bit(HID_DISCONNECTED, &usbhid->iofl) && !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); if (rc != 0) @@ -155,7 +156,7 @@ static void hid_io_error(struct hid_device *hid) spin_lock_irqsave(&usbhid->inlock, flags); /* Stop when disconnected */ - if (usb_get_intfdata(usbhid->intf) == NULL) + if (test_bit(HID_DISCONNECTED, &usbhid->iofl)) goto done; /* If it has been a while since the last error, we'll assume @@ -941,6 +942,7 @@ static void hid_disconnect(struct usb_interface *intf) spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ usb_set_intfdata(intf, NULL); + set_bit(HID_DISCONNECTED, &usbhid->iofl); spin_unlock_irq(&usbhid->inlock); usb_kill_urb(usbhid->urbin); usb_kill_urb(usbhid->urbout); diff --git a/include/linux/hid.h b/include/linux/hid.h index fe4ac31eced2..d951ec411241 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -424,6 +424,7 @@ struct hid_control_fifo { #define HID_RESET_PENDING 4 #define HID_SUSPENDED 5 #define HID_CLEAR_HALT 6 +#define HID_DISCONNECTED 7 struct hid_input { struct list_head list; -- cgit v1.2.3 From 0dd91544429188b496a8136e3cffb337ff6f056b Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 8 Apr 2008 10:20:36 +0200 Subject: HID: export headers properly I have people whining about using these headers in userspace, and they have __KERNEL__ markings which implies they're supposed to be exported. I also added the required linux/types.h include to hidraw.h since it uses the __u## kernel types. Signed-off-by: Mike Frysinger Cc: Jiri Kosina Cc: Dmitry Torokhov Signed-off-by: Andrew Morton Signed-off-by: Jiri Kosina --- include/linux/Kbuild | 2 ++ include/linux/hidraw.h | 1 + 2 files changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index b3d9ccde0c27..5d741720332a 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -210,7 +210,9 @@ unifdef-y += hdlcdrv.h unifdef-y += hdlc.h unifdef-y += hdreg.h unifdef-y += hdsmart.h +unifdef-y += hid.h unifdef-y += hiddev.h +unifdef-y += hidraw.h unifdef-y += hpet.h unifdef-y += i2c.h unifdef-y += i2c-dev.h diff --git a/include/linux/hidraw.h b/include/linux/hidraw.h index 0536f299f7ff..dbb5c8c374f0 100644 --- a/include/linux/hidraw.h +++ b/include/linux/hidraw.h @@ -16,6 +16,7 @@ */ #include +#include struct hidraw_report_descriptor { __u32 size; -- cgit v1.2.3