diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-14 09:03:42 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-14 09:03:42 -0700 |
commit | 52d4e661ac92ab8e1a312fe527221a1311fe4cda (patch) | |
tree | 907f37beba526bac7dcffbef7253de3b445a2c1e /drivers/hid/usbhid | |
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
...
Diffstat (limited to 'drivers/hid/usbhid')
-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 |
7 files changed, 241 insertions, 59 deletions
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index 1b4b572f899..c557d7040a6 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -71,19 +71,20 @@ config LOGITECH_FF force feedback. config PANTHERLORD_FF - bool "PantherLord USB/PS2 2in1 Adapter support" + bool "PantherLord/GreenAsia based device support" depends on HID_FF select INPUT_FF_MEMLESS if USB_HID help - Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want - to enable force feedback support for it. + Say Y here if you have a PantherLord/GreenAsia based game controller + or adapter and want to enable force feedback support for it. config THRUSTMASTER_FF - bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" + bool "ThrustMaster devices support (EXPERIMENTAL)" depends on HID_FF && EXPERIMENTAL select INPUT_FF_MEMLESS if USB_HID help - Say Y here if you have a THRUSTMASTER FireStore Dual Power 2, + Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or + a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel, and want to enable force feedback support for it. Note: if you say N here, this device will still be supported, but without force feedback. diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 0a1f2b52a12..b38e559b7a4 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -32,6 +32,7 @@ #include <linux/hid.h> #include <linux/hiddev.h> #include <linux/hid-debug.h> +#include <linux/hidraw.h> #include "usbhid.h" /* @@ -512,7 +513,16 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, int usbhid_open(struct hid_device *hid) { - ++hid->open; + struct usbhid_device *usbhid = hid->driver_data; + int res; + + if (!hid->open++) { + res = usb_autopm_get_interface(usbhid->intf); + if (res < 0) { + hid->open--; + return -EIO; + } + } if (hid_start_in(hid)) hid_io_error(hid); return 0; @@ -522,8 +532,10 @@ void usbhid_close(struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; - if (!--hid->open) + if (!--hid->open) { usb_kill_urb(usbhid->urbin); + usb_autopm_put_interface(usbhid->intf); + } } /* @@ -628,6 +640,28 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) return 0; } +static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count) +{ + struct usbhid_device *usbhid = hid->driver_data; + struct usb_device *dev = hid_to_usb_dev(hid); + struct usb_interface *intf = usbhid->intf; + struct usb_host_interface *interface = intf->cur_altsetting; + int ret; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + HID_REQ_SET_REPORT, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf), + interface->desc.bInterfaceNumber, buf + 1, count - 1, + USB_CTRL_SET_TIMEOUT); + + /* count also the report id */ + if (ret > 0) + ret++; + + return ret; +} + static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) { struct usbhid_device *usbhid = hid->driver_data; @@ -871,6 +905,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->hiddev_hid_event = hiddev_hid_event; hid->hiddev_report_event = hiddev_report_event; #endif + hid->hid_output_raw_report = usbhid_output_raw_report; return hid; fail: @@ -909,6 +944,8 @@ static void hid_disconnect(struct usb_interface *intf) hidinput_disconnect(hid); if (hid->claimed & HID_CLAIMED_HIDDEV) hiddev_disconnect(hid); + if (hid->claimed & HID_CLAIMED_HIDRAW) + hidraw_disconnect(hid); usb_free_urb(usbhid->urbin); usb_free_urb(usbhid->urbctrl); @@ -941,11 +978,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) hid->claimed |= HID_CLAIMED_INPUT; if (!hiddev_connect(hid)) hid->claimed |= HID_CLAIMED_HIDDEV; + if (!hidraw_connect(hid)) + hid->claimed |= HID_CLAIMED_HIDRAW; usb_set_intfdata(intf, hid); if (!hid->claimed) { - printk ("HID device not claimed by input or hiddev\n"); + printk ("HID device claimed by neither input, hiddev nor hidraw\n"); hid_disconnect(intf); return -ENODEV; } @@ -961,10 +1000,16 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) if (hid->claimed & HID_CLAIMED_INPUT) printk("input"); - if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV)) + if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) || + hid->claimed & HID_CLAIMED_HIDRAW)) printk(","); if (hid->claimed & HID_CLAIMED_HIDDEV) printk("hiddev%d", hid->minor); + if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) && + (hid->claimed & HID_CLAIMED_HIDRAW)) + printk(","); + if (hid->claimed & HID_CLAIMED_HIDRAW) + printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor); c = "Device"; for (i = 0; i < hid->maxcollection; i++) { @@ -1048,6 +1093,7 @@ static struct usb_driver hid_driver = { .pre_reset = hid_pre_reset, .post_reset = hid_post_reset, .id_table = hid_usb_ids, + .supports_autosuspend = 1, }; static int __init hid_init(void) diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c index 23431fbbc3d..22329feb3b5 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[] = { { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */ #endif #ifdef CONFIG_PANTHERLORD_FF - { 0x810, 0x0001, hid_plff_init }, + { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */ + { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */ #endif #ifdef CONFIG_THRUSTMASTER_FF { 0x44f, 0xb300, hid_tmff_init }, { 0x44f, 0xb304, hid_tmff_init }, + { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */ + { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */ #endif #ifdef CONFIG_ZEROPLUS_FF { 0xc12, 0x0005, hid_zpff_init }, diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c index d6a8f2b49bd..9eb83cf9d22 100644 --- a/drivers/hid/usbhid/hid-plff.c +++ b/drivers/hid/usbhid/hid-plff.c @@ -1,5 +1,15 @@ /* - * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices + * Force feedback support for PantherLord/GreenAsia based devices + * + * The devices are distributed under various names and the same USB device ID + * can be used in both adapters and actual game controllers. + * + * 0810:0001 "Twin USB Joystick" + * - tested with PantherLord USB/PS2 2in1 Adapter + * - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT) + * + * 0e8f:0003 "GreenAsia Inc. USB Joystick " + * - tested with Köng Gaming gamepad * * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> */ @@ -67,11 +77,11 @@ int hid_plff_init(struct hid_device *hid) struct input_dev *dev; int error; - /* The device contains 2 output reports (one for each - HID_QUIRK_MULTI_INPUT device), both containing 1 field, which - contains 4 ff00.0002 usages and 4 16bit absolute values. + /* The device contains one output report per physical device, all + containing 1 field, which contains 4 ff00.0002 usages and 4 16bit + absolute values. - The 2 input reports also contain a field which contains + The input reports also contain a field which contains 8 ff00.0001 usages and 8 boolean values. Their meaning is currently unknown. */ @@ -122,8 +132,8 @@ int hid_plff_init(struct hid_device *hid) usbhid_submit_report(hid, plff->report, USB_DIR_OUT); } - printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 " - "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n"); + printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia " + "devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); return 0; } diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 6b21a214f41..41a59a80e7e 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -61,6 +61,7 @@ #define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b +#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 #define USB_VENDOR_ID_ASUS 0x0b05 #define USB_DEVICE_ID_ASUS_LCM 0x1726 @@ -86,6 +87,9 @@ #define USB_VENDOR_ID_CIDC 0x1677 +#define USB_VENDOR_ID_CMEDIA 0x0d8c +#define USB_DEVICE_ID_CM109 0x000e + #define USB_VENDOR_ID_CODEMERCS 0x07c0 #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 #define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff @@ -104,12 +108,17 @@ #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 #define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 +#define USB_VENDOR_ID_ELO 0x04E7 +#define USB_DEVICE_ID_ELO_TS2700 0x0020 + #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 #define USB_VENDOR_ID_GAMERON 0x0810 #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 +#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc + #define USB_VENDOR_ID_GLAB 0x06c2 #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 #define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 @@ -373,6 +382,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, @@ -387,11 +397,16 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE}, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE }, @@ -507,6 +522,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, @@ -614,6 +630,8 @@ static const struct hid_rdesc_blacklist { { 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_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS }, + { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, { 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) printk(KERN_INFO "Fixing up Cypress report descriptor\n"); } +/* + * MacBook JIS keyboard has wrong logical maximum + */ +static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize) +{ + if (rsize >= 60 && rdesc[53] == 0x65 + && rdesc[59] == 0x65) { + printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n"); + rdesc[53] = rdesc[59] = 0xe7; + } +} + static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) { @@ -941,6 +971,9 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned if (quirks & HID_QUIRK_RDESC_PETALYNX) usbhid_fixup_petalynx_descriptor(rdesc, rsize); + + if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS) + usbhid_fixup_macbook_descriptor(rdesc, rsize); } /** diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c index 555bb48b429..69882a726e9 100644 --- a/drivers/hid/usbhid/hid-tmff.c +++ b/drivers/hid/usbhid/hid-tmff.c @@ -36,16 +36,39 @@ #include "usbhid.h" /* Usages for thrustmaster devices I know about */ -#define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) +#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb) +struct dev_type { + u16 idVendor; + u16 idProduct; + const signed short *ff; +}; + +static const signed short ff_rumble[] = { + FF_RUMBLE, + -1 +}; + +static const signed short ff_joystick[] = { + FF_CONSTANT, + -1 +}; + +static const struct dev_type devices[] = { + { 0x44f, 0xb300, ff_rumble }, + { 0x44f, 0xb304, ff_rumble }, + { 0x44f, 0xb651, ff_rumble }, /* FGT Rumble Force Wheel */ + { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */ +}; struct tmff_device { struct hid_report *report; - struct hid_field *rumble; + struct hid_field *ff_field; }; /* Changes values from 0 to 0xffff into values from minimum to maximum */ -static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum) +static inline int hid_tmff_scale_u16(unsigned int in, + int minimum, int maximum) { int ret; @@ -57,22 +80,57 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum) return ret; } +/* Changes values from -0x80 to 0x7f into values from minimum to maximum */ +static inline int hid_tmff_scale_s8(int in, + int minimum, int maximum) +{ + int ret; + + ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum; + if (ret < minimum) + return minimum; + if (ret > maximum) + return maximum; + return ret; +} + static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); struct tmff_device *tmff = data; + struct hid_field *ff_field = tmff->ff_field; + int x, y; int left, right; /* Rumbling */ - left = hid_tmff_scale(effect->u.rumble.weak_magnitude, - tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); - right = hid_tmff_scale(effect->u.rumble.strong_magnitude, - tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); - - tmff->rumble->value[0] = left; - tmff->rumble->value[1] = right; - dbg_hid("(left,right)=(%08x, %08x)\n", left, right); - usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); - + switch (effect->type) { + case FF_CONSTANT: + x = hid_tmff_scale_s8(effect->u.ramp.start_level, + ff_field->logical_minimum, + ff_field->logical_maximum); + y = hid_tmff_scale_s8(effect->u.ramp.end_level, + ff_field->logical_minimum, + ff_field->logical_maximum); + + dbg_hid("(x, y)=(%04x, %04x)\n", x, y); + ff_field->value[0] = x; + ff_field->value[1] = y; + usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); + break; + + case FF_RUMBLE: + left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude, + ff_field->logical_minimum, + ff_field->logical_maximum); + right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude, + ff_field->logical_minimum, + ff_field->logical_maximum); + + dbg_hid("(left,right)=(%08x, %08x)\n", left, right); + ff_field->value[0] = left; + ff_field->value[1] = right; + usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); + break; + } return 0; } @@ -82,14 +140,16 @@ int hid_tmff_init(struct hid_device *hid) struct list_head *pos; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *input_dev = hidinput->input; + const signed short *ff_bits = ff_joystick; int error; + int i; tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); if (!tmff) return -ENOMEM; /* Find the report to use */ - __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) { + list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) { struct hid_report *report = (struct hid_report *)pos; int fieldnum; @@ -100,48 +160,65 @@ int hid_tmff_init(struct hid_device *hid) continue; switch (field->usage[0].hid) { - case THRUSTMASTER_USAGE_RUMBLE_LR: - if (field->report_count < 2) { - warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2"); - continue; - } + case THRUSTMASTER_USAGE_FF: + if (field->report_count < 2) { + warn("ignoring FF field with report_count < 2"); + continue; + } - if (field->logical_maximum == field->logical_minimum) { - warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum"); - continue; - } + if (field->logical_maximum == field->logical_minimum) { + warn("ignoring FF field with logical_maximum == logical_minimum"); + continue; + } - if (tmff->report && tmff->report != report) { - warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report"); - continue; - } + if (tmff->report && tmff->report != report) { + warn("ignoring FF field in other report"); + continue; + } - if (tmff->rumble && tmff->rumble != field) { - warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR"); - continue; + if (tmff->ff_field && tmff->ff_field != field) { + warn("ignoring duplicate FF field"); + continue; + } + + tmff->report = report; + tmff->ff_field = field; + + for (i = 0; i < ARRAY_SIZE(devices); i++) { + if (input_dev->id.vendor == devices[i].idVendor && + input_dev->id.product == devices[i].idProduct) { + ff_bits = devices[i].ff; + break; } + } - tmff->report = report; - tmff->rumble = field; + for (i = 0; ff_bits[i] >= 0; i++) + set_bit(ff_bits[i], input_dev->ffbit); - set_bit(FF_RUMBLE, input_dev->ffbit); - break; + break; - default: - warn("ignoring unknown output usage %08x", field->usage[0].hid); - continue; + default: + warn("ignoring unknown output usage %08x", field->usage[0].hid); + continue; } } } - error = input_ff_create_memless(input_dev, tmff, hid_tmff_play); - if (error) { - kfree(tmff); - return error; + if (!tmff->report) { + err("cant find FF field in output reports\n"); + error = -ENODEV; + goto fail; } - info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>"); + error = input_ff_create_memless(input_dev, tmff, hid_tmff_play); + if (error) + goto fail; + info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>"); return 0; + + fail: + kfree(tmff); + return error; } diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index e793127f971..9837adcb17e 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -34,6 +34,7 @@ #include <linux/usb.h> #include <linux/hid.h> #include <linux/hiddev.h> +#include <linux/compat.h> #include "usbhid.h" #ifdef CONFIG_USB_DYNAMIC_MINORS @@ -738,6 +739,14 @@ inval: return -EINVAL; } +#ifdef CONFIG_COMPAT +static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = file->f_path.dentry->d_inode; + return hiddev_ioctl(inode, file, cmd, compat_ptr(arg)); +} +#endif + static const struct file_operations hiddev_fops = { .owner = THIS_MODULE, .read = hiddev_read, @@ -747,6 +756,9 @@ static const struct file_operations hiddev_fops = { .release = hiddev_release, .ioctl = hiddev_ioctl, .fasync = hiddev_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = hiddev_compat_ioctl, +#endif }; static struct usb_class_driver hiddev_class = { |