Merge branches 'for-3.10/appleir', 'for-3.10/hid-debug', 'for-3.10/hid-driver-transport-cleanups', 'for-3.10/i2c-hid' and 'for-3.10/logitech' into for-linus

This commit is contained in:
Jiri Kosina 2013-04-30 10:12:44 +02:00
commit 4f5a810429
44 changed files with 406 additions and 313 deletions

View File

@ -92,14 +92,14 @@ menu "Special HID drivers"
config HID_A4TECH config HID_A4TECH
tristate "A4 tech mice" if EXPERT tristate "A4 tech mice" if EXPERT
depends on USB_HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice. Support for A4 tech X5 and WOP-35 / Trust 450L mice.
config HID_ACRUX config HID_ACRUX
tristate "ACRUX game controller support" tristate "ACRUX game controller support"
depends on USB_HID depends on HID
---help--- ---help---
Say Y here if you want to enable support for ACRUX game controllers. Say Y here if you want to enable support for ACRUX game controllers.
@ -113,7 +113,7 @@ config HID_ACRUX_FF
config HID_APPLE config HID_APPLE
tristate "Apple {i,Power,Mac}Books" if EXPERT tristate "Apple {i,Power,Mac}Books" if EXPERT
depends on (USB_HID || BT_HIDP) depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for some Apple devices which less or more break Support for some Apple devices which less or more break
@ -135,34 +135,34 @@ config HID_APPLEIR
config HID_AUREAL config HID_AUREAL
tristate "Aureal" tristate "Aureal"
depends on USB_HID depends on HID
---help--- ---help---
Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes. Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
config HID_BELKIN config HID_BELKIN
tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
depends on USB_HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for Belkin Flip KVM and Wireless keyboard. Support for Belkin Flip KVM and Wireless keyboard.
config HID_CHERRY config HID_CHERRY
tristate "Cherry Cymotion keyboard" if EXPERT tristate "Cherry Cymotion keyboard" if EXPERT
depends on USB_HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for Cherry Cymotion keyboard. Support for Cherry Cymotion keyboard.
config HID_CHICONY config HID_CHICONY
tristate "Chicony Tactical pad" if EXPERT tristate "Chicony Tactical pad" if EXPERT
depends on USB_HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for Chicony Tactical pad. Support for Chicony Tactical pad.
config HID_PRODIKEYS config HID_PRODIKEYS
tristate "Prodikeys PC-MIDI Keyboard support" tristate "Prodikeys PC-MIDI Keyboard support"
depends on USB_HID && SND depends on HID && SND
select SND_RAWMIDI select SND_RAWMIDI
---help--- ---help---
Support for Prodikeys PC-MIDI Keyboard device support. Support for Prodikeys PC-MIDI Keyboard device support.
@ -177,14 +177,14 @@ config HID_PRODIKEYS
config HID_CYPRESS config HID_CYPRESS
tristate "Cypress mouse and barcode readers" if EXPERT tristate "Cypress mouse and barcode readers" if EXPERT
depends on USB_HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for cypress mouse and barcode readers. Support for cypress mouse and barcode readers.
config HID_DRAGONRISE config HID_DRAGONRISE
tristate "DragonRise Inc. game controller" tristate "DragonRise Inc. game controller"
depends on USB_HID depends on HID
---help--- ---help---
Say Y here if you have DragonRise Inc. game controllers. Say Y here if you have DragonRise Inc. game controllers.
These might be branded as: These might be branded as:
@ -203,7 +203,7 @@ config DRAGONRISE_FF
config HID_EMS_FF config HID_EMS_FF
tristate "EMS Production Inc. force feedback support" tristate "EMS Production Inc. force feedback support"
depends on USB_HID depends on HID
select INPUT_FF_MEMLESS select INPUT_FF_MEMLESS
---help--- ---help---
Say Y here if you want to enable force feedback support for devices by Say Y here if you want to enable force feedback support for devices by
@ -213,13 +213,13 @@ config HID_EMS_FF
config HID_ELECOM config HID_ELECOM
tristate "ELECOM BM084 bluetooth mouse" tristate "ELECOM BM084 bluetooth mouse"
depends on BT_HIDP depends on HID
---help--- ---help---
Support for the ELECOM BM084 (bluetooth mouse). Support for the ELECOM BM084 (bluetooth mouse).
config HID_EZKEY config HID_EZKEY
tristate "Ezkey BTC 8193 keyboard" if EXPERT tristate "Ezkey BTC 8193 keyboard" if EXPERT
depends on USB_HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for Ezkey BTC 8193 keyboard. Support for Ezkey BTC 8193 keyboard.
@ -242,7 +242,7 @@ config HOLTEK_FF
config HID_KEYTOUCH config HID_KEYTOUCH
tristate "Keytouch HID devices" tristate "Keytouch HID devices"
depends on USB_HID depends on HID
---help--- ---help---
Support for Keytouch HID devices not fully compliant with Support for Keytouch HID devices not fully compliant with
the specification. Currently supported: the specification. Currently supported:
@ -250,7 +250,7 @@ config HID_KEYTOUCH
config HID_KYE config HID_KYE
tristate "KYE/Genius devices" tristate "KYE/Genius devices"
depends on USB_HID depends on HID
---help--- ---help---
Support for KYE/Genius devices not fully compliant with HID standard: Support for KYE/Genius devices not fully compliant with HID standard:
- Ergo Mouse - Ergo Mouse
@ -260,25 +260,25 @@ config HID_KYE
config HID_UCLOGIC config HID_UCLOGIC
tristate "UC-Logic" tristate "UC-Logic"
depends on USB_HID depends on HID
---help--- ---help---
Support for UC-Logic tablets. Support for UC-Logic tablets.
config HID_WALTOP config HID_WALTOP
tristate "Waltop" tristate "Waltop"
depends on USB_HID depends on HID
---help--- ---help---
Support for Waltop tablets. Support for Waltop tablets.
config HID_GYRATION config HID_GYRATION
tristate "Gyration remote control" tristate "Gyration remote control"
depends on USB_HID depends on HID
---help--- ---help---
Support for Gyration remote control. Support for Gyration remote control.
config HID_ICADE config HID_ICADE
tristate "ION iCade arcade controller" tristate "ION iCade arcade controller"
depends on BT_HIDP depends on HID
---help--- ---help---
Support for the ION iCade arcade controller to work as a joystick. Support for the ION iCade arcade controller to work as a joystick.
@ -287,20 +287,20 @@ config HID_ICADE
config HID_TWINHAN config HID_TWINHAN
tristate "Twinhan IR remote control" tristate "Twinhan IR remote control"
depends on USB_HID depends on HID
---help--- ---help---
Support for Twinhan IR remote control. Support for Twinhan IR remote control.
config HID_KENSINGTON config HID_KENSINGTON
tristate "Kensington Slimblade Trackball" if EXPERT tristate "Kensington Slimblade Trackball" if EXPERT
depends on USB_HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for Kensington Slimblade Trackball. Support for Kensington Slimblade Trackball.
config HID_LCPOWER config HID_LCPOWER
tristate "LC-Power" tristate "LC-Power"
depends on USB_HID depends on HID
---help--- ---help---
Support for LC-Power RC1000MCE RF remote control. Support for LC-Power RC1000MCE RF remote control.
@ -319,7 +319,7 @@ config HID_LENOVO_TPKBD
config HID_LOGITECH config HID_LOGITECH
tristate "Logitech devices" if EXPERT tristate "Logitech devices" if EXPERT
depends on USB_HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for Logitech devices that are not fully compliant with HID standard. Support for Logitech devices that are not fully compliant with HID standard.
@ -385,7 +385,7 @@ config LOGIWHEELS_FF
config HID_MAGICMOUSE config HID_MAGICMOUSE
tristate "Apple MagicMouse multi-touch support" tristate "Apple MagicMouse multi-touch support"
depends on BT_HIDP depends on HID
---help--- ---help---
Support for the Apple Magic Mouse multi-touch. Support for the Apple Magic Mouse multi-touch.
@ -394,21 +394,21 @@ config HID_MAGICMOUSE
config HID_MICROSOFT config HID_MICROSOFT
tristate "Microsoft non-fully HID-compliant devices" if EXPERT tristate "Microsoft non-fully HID-compliant devices" if EXPERT
depends on USB_HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for Microsoft devices that are not fully compliant with HID standard. Support for Microsoft devices that are not fully compliant with HID standard.
config HID_MONTEREY config HID_MONTEREY
tristate "Monterey Genius KB29E keyboard" if EXPERT tristate "Monterey Genius KB29E keyboard" if EXPERT
depends on USB_HID depends on HID
default !EXPERT default !EXPERT
---help--- ---help---
Support for Monterey Genius KB29E. Support for Monterey Genius KB29E.
config HID_MULTITOUCH config HID_MULTITOUCH
tristate "HID Multitouch panels" tristate "HID Multitouch panels"
depends on USB_HID depends on HID
---help--- ---help---
Generic support for HID multitouch panels. Generic support for HID multitouch panels.
@ -456,7 +456,7 @@ config HID_NTRIG
config HID_ORTEK config HID_ORTEK
tristate "Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad" tristate "Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad"
depends on USB_HID depends on HID
---help--- ---help---
There are certain devices which have LogicalMaximum wrong in the keyboard There are certain devices which have LogicalMaximum wrong in the keyboard
usage page of their report descriptor. The most prevailing ones so far usage page of their report descriptor. The most prevailing ones so far
@ -469,7 +469,7 @@ config HID_ORTEK
config HID_PANTHERLORD config HID_PANTHERLORD
tristate "Pantherlord/GreenAsia game controller" tristate "Pantherlord/GreenAsia game controller"
depends on USB_HID depends on HID
---help--- ---help---
Say Y here if you have a PantherLord/GreenAsia based game controller Say Y here if you have a PantherLord/GreenAsia based game controller
or adapter. or adapter.
@ -484,13 +484,13 @@ config PANTHERLORD_FF
config HID_PETALYNX config HID_PETALYNX
tristate "Petalynx Maxter remote control" tristate "Petalynx Maxter remote control"
depends on USB_HID depends on HID
---help--- ---help---
Support for Petalynx Maxter remote control. Support for Petalynx Maxter remote control.
config HID_PICOLCD config HID_PICOLCD
tristate "PicoLCD (graphic version)" tristate "PicoLCD (graphic version)"
depends on USB_HID depends on HID
---help--- ---help---
This provides support for Minibox PicoLCD devices, currently This provides support for Minibox PicoLCD devices, currently
only the graphical ones are supported. only the graphical ones are supported.
@ -556,14 +556,14 @@ config HID_PICOLCD_CIR
config HID_PRIMAX config HID_PRIMAX
tristate "Primax non-fully HID-compliant devices" tristate "Primax non-fully HID-compliant devices"
depends on USB_HID depends on HID
---help--- ---help---
Support for Primax devices that are not fully compliant with the Support for Primax devices that are not fully compliant with the
HID standard. HID standard.
config HID_PS3REMOTE config HID_PS3REMOTE
tristate "Sony PS3 BD Remote Control" tristate "Sony PS3 BD Remote Control"
depends on BT_HIDP depends on HID
---help--- ---help---
Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech
Harmony Adapter for PS3, which connect over Bluetooth. Harmony Adapter for PS3, which connect over Bluetooth.
@ -580,7 +580,7 @@ config HID_ROCCAT
config HID_SAITEK config HID_SAITEK
tristate "Saitek non-fully HID-compliant devices" tristate "Saitek non-fully HID-compliant devices"
depends on USB_HID depends on HID
---help--- ---help---
Support for Saitek devices that are not fully compliant with the Support for Saitek devices that are not fully compliant with the
HID standard. HID standard.
@ -589,7 +589,7 @@ config HID_SAITEK
config HID_SAMSUNG config HID_SAMSUNG
tristate "Samsung InfraRed remote control or keyboards" tristate "Samsung InfraRed remote control or keyboards"
depends on USB_HID depends on HID
---help--- ---help---
Support for Samsung InfraRed remote control or keyboards. Support for Samsung InfraRed remote control or keyboards.
@ -603,25 +603,25 @@ config HID_SONY
config HID_SPEEDLINK config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support" tristate "Speedlink VAD Cezanne mouse support"
depends on USB_HID depends on HID
---help--- ---help---
Support for Speedlink Vicious and Divine Cezanne mouse. Support for Speedlink Vicious and Divine Cezanne mouse.
config HID_STEELSERIES config HID_STEELSERIES
tristate "Steelseries SRW-S1 steering wheel support" tristate "Steelseries SRW-S1 steering wheel support"
depends on USB_HID depends on HID
---help--- ---help---
Support for Steelseries SRW-S1 steering wheel Support for Steelseries SRW-S1 steering wheel
config HID_SUNPLUS config HID_SUNPLUS
tristate "Sunplus wireless desktop" tristate "Sunplus wireless desktop"
depends on USB_HID depends on HID
---help--- ---help---
Support for Sunplus wireless desktop. Support for Sunplus wireless desktop.
config HID_GREENASIA config HID_GREENASIA
tristate "GreenAsia (Product ID 0x12) game controller support" tristate "GreenAsia (Product ID 0x12) game controller support"
depends on USB_HID depends on HID
---help--- ---help---
Say Y here if you have a GreenAsia (Product ID 0x12) based game Say Y here if you have a GreenAsia (Product ID 0x12) based game
controller or adapter. controller or adapter.
@ -643,7 +643,7 @@ config HID_HYPERV_MOUSE
config HID_SMARTJOYPLUS config HID_SMARTJOYPLUS
tristate "SmartJoy PLUS PS2/USB adapter support" tristate "SmartJoy PLUS PS2/USB adapter support"
depends on USB_HID depends on HID
---help--- ---help---
Support for SmartJoy PLUS PS2/USB adapter, Super Dual Box, Support for SmartJoy PLUS PS2/USB adapter, Super Dual Box,
Super Joy Box 3 Pro, Super Dual Box Pro, and Super Joy Box 5 Pro. Super Joy Box 3 Pro, Super Dual Box Pro, and Super Joy Box 5 Pro.
@ -661,20 +661,20 @@ config SMARTJOYPLUS_FF
config HID_TIVO config HID_TIVO
tristate "TiVo Slide Bluetooth remote control support" tristate "TiVo Slide Bluetooth remote control support"
depends on (USB_HID || BT_HIDP) depends on HID
---help--- ---help---
Say Y if you have a TiVo Slide Bluetooth remote control. Say Y if you have a TiVo Slide Bluetooth remote control.
config HID_TOPSEED config HID_TOPSEED
tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support" tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support"
depends on USB_HID depends on HID
---help--- ---help---
Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic
CLLRCMCE remote control. CLLRCMCE remote control.
config HID_THINGM config HID_THINGM
tristate "ThingM blink(1) USB RGB LED" tristate "ThingM blink(1) USB RGB LED"
depends on USB_HID depends on HID
depends on LEDS_CLASS depends on LEDS_CLASS
---help--- ---help---
Support for the ThingM blink(1) USB RGB LED. This driver registers a Support for the ThingM blink(1) USB RGB LED. This driver registers a
@ -684,7 +684,7 @@ config HID_THINGM
config HID_THRUSTMASTER config HID_THRUSTMASTER
tristate "ThrustMaster devices support" tristate "ThrustMaster devices support"
depends on USB_HID depends on HID
---help--- ---help---
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
a THRUSTMASTER Ferrari GT Rumble Wheel. a THRUSTMASTER Ferrari GT Rumble Wheel.
@ -700,7 +700,7 @@ config THRUSTMASTER_FF
config HID_WACOM config HID_WACOM
tristate "Wacom Bluetooth devices support" tristate "Wacom Bluetooth devices support"
depends on BT_HIDP depends on HID
depends on LEDS_CLASS depends on LEDS_CLASS
select POWER_SUPPLY select POWER_SUPPLY
---help--- ---help---
@ -708,7 +708,7 @@ config HID_WACOM
config HID_WIIMOTE config HID_WIIMOTE
tristate "Nintendo Wii Remote support" tristate "Nintendo Wii Remote support"
depends on BT_HIDP depends on HID
depends on LEDS_CLASS depends on LEDS_CLASS
select POWER_SUPPLY select POWER_SUPPLY
select INPUT_FF_MEMLESS select INPUT_FF_MEMLESS
@ -726,7 +726,7 @@ config HID_WIIMOTE_EXT
config HID_ZEROPLUS config HID_ZEROPLUS
tristate "Zeroplus based game controller support" tristate "Zeroplus based game controller support"
depends on USB_HID depends on HID
---help--- ---help---
Say Y here if you have a Zeroplus based game controller. Say Y here if you have a Zeroplus based game controller.
@ -740,13 +740,13 @@ config ZEROPLUS_FF
config HID_ZYDACRON config HID_ZYDACRON
tristate "Zydacron remote control support" tristate "Zydacron remote control support"
depends on USB_HID depends on HID
---help--- ---help---
Support for Zydacron remote control. Support for Zydacron remote control.
config HID_SENSOR_HUB config HID_SENSOR_HUB
tristate "HID Sensors framework support" tristate "HID Sensors framework support"
depends on USB_HID && GENERIC_HARDIRQS depends on HID && GENERIC_HARDIRQS
select MFD_CORE select MFD_CORE
default n default n
-- help--- -- help---

View File

@ -21,7 +21,6 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include "hid-ids.h" #include "hid-ids.h"

View File

@ -29,14 +29,12 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include "hid-ids.h" #include "hid-ids.h"
#ifdef CONFIG_HID_ACRUX_FF #ifdef CONFIG_HID_ACRUX_FF
#include "usbhid/usbhid.h"
struct axff_device { struct axff_device {
struct hid_report *report; struct hid_report *report;
@ -68,7 +66,7 @@ static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect
} }
dbg_hid("running with 0x%02x 0x%02x", left, right); dbg_hid("running with 0x%02x 0x%02x", left, right);
usbhid_submit_report(hid, axff->report, USB_DIR_OUT); hid_hw_request(hid, axff->report, HID_REQ_SET_REPORT);
return 0; return 0;
} }
@ -114,7 +112,7 @@ static int axff_init(struct hid_device *hid)
goto err_free_mem; goto err_free_mem;
axff->report = report; axff->report = report;
usbhid_submit_report(hid, axff->report, USB_DIR_OUT); hid_hw_request(hid, axff->report, HID_REQ_SET_REPORT);
hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun <x0r@dv-life.ru>\n"); hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun <x0r@dv-life.ru>\n");

View File

@ -728,8 +728,7 @@ static int hid_scan_report(struct hid_device *hid)
} else if (page == HID_UP_SENSOR && } else if (page == HID_UP_SENSOR &&
item.type == HID_ITEM_TYPE_MAIN && item.type == HID_ITEM_TYPE_MAIN &&
item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION && item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION &&
(item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL && (item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL)
(hid->bus == BUS_USB || hid->bus == BUS_I2C))
hid->group = HID_GROUP_SENSOR_HUB; hid->group = HID_GROUP_SENSOR_HUB;
} }
@ -1260,14 +1259,12 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
struct hid_report_enum *report_enum; struct hid_report_enum *report_enum;
struct hid_driver *hdrv; struct hid_driver *hdrv;
struct hid_report *report; struct hid_report *report;
char *buf;
unsigned int i;
int ret = 0; int ret = 0;
if (!hid) if (!hid)
return -ENODEV; return -ENODEV;
if (down_trylock(&hid->driver_lock)) if (down_trylock(&hid->driver_input_lock))
return -EBUSY; return -EBUSY;
if (!hid->driver) { if (!hid->driver) {
@ -1284,28 +1281,9 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
} }
/* Avoid unnecessary overhead if debugfs is disabled */ /* Avoid unnecessary overhead if debugfs is disabled */
if (list_empty(&hid->debug_list)) if (!list_empty(&hid->debug_list))
goto nomem; hid_dump_report(hid, type, data, size);
buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
if (!buf)
goto nomem;
/* dump the report */
snprintf(buf, HID_DEBUG_BUFSIZE - 1,
"\nreport (size %u) (%snumbered) = ", size, report_enum->numbered ? "" : "un");
hid_debug_event(hid, buf);
for (i = 0; i < size; i++) {
snprintf(buf, HID_DEBUG_BUFSIZE - 1,
" %02x", data[i]);
hid_debug_event(hid, buf);
}
hid_debug_event(hid, "\n");
kfree(buf);
nomem:
report = hid_get_report(report_enum, data); report = hid_get_report(report_enum, data);
if (!report) { if (!report) {
@ -1324,7 +1302,7 @@ nomem:
ret = hid_report_raw_event(hid, type, data, size, interrupt); ret = hid_report_raw_event(hid, type, data, size, interrupt);
unlock: unlock:
up(&hid->driver_lock); up(&hid->driver_input_lock);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(hid_input_report); EXPORT_SYMBOL_GPL(hid_input_report);
@ -1848,6 +1826,11 @@ static int hid_device_probe(struct device *dev)
if (down_interruptible(&hdev->driver_lock)) if (down_interruptible(&hdev->driver_lock))
return -EINTR; return -EINTR;
if (down_interruptible(&hdev->driver_input_lock)) {
ret = -EINTR;
goto unlock_driver_lock;
}
hdev->io_started = false;
if (!hdev->driver) { if (!hdev->driver) {
id = hid_match_device(hdev, hdrv); id = hid_match_device(hdev, hdrv);
@ -1870,6 +1853,9 @@ static int hid_device_probe(struct device *dev)
} }
} }
unlock: unlock:
if (!hdev->io_started)
up(&hdev->driver_input_lock);
unlock_driver_lock:
up(&hdev->driver_lock); up(&hdev->driver_lock);
return ret; return ret;
} }
@ -1878,9 +1864,15 @@ static int hid_device_remove(struct device *dev)
{ {
struct hid_device *hdev = container_of(dev, struct hid_device, dev); struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct hid_driver *hdrv; struct hid_driver *hdrv;
int ret = 0;
if (down_interruptible(&hdev->driver_lock)) if (down_interruptible(&hdev->driver_lock))
return -EINTR; return -EINTR;
if (down_interruptible(&hdev->driver_input_lock)) {
ret = -EINTR;
goto unlock_driver_lock;
}
hdev->io_started = false;
hdrv = hdev->driver; hdrv = hdev->driver;
if (hdrv) { if (hdrv) {
@ -1892,8 +1884,11 @@ static int hid_device_remove(struct device *dev)
hdev->driver = NULL; hdev->driver = NULL;
} }
if (!hdev->io_started)
up(&hdev->driver_input_lock);
unlock_driver_lock:
up(&hdev->driver_lock); up(&hdev->driver_lock);
return 0; return ret;
} }
static ssize_t modalias_show(struct device *dev, struct device_attribute *a, static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
@ -2343,7 +2338,9 @@ struct hid_device *hid_allocate_device(void)
init_waitqueue_head(&hdev->debug_wait); init_waitqueue_head(&hdev->debug_wait);
INIT_LIST_HEAD(&hdev->debug_list); INIT_LIST_HEAD(&hdev->debug_list);
mutex_init(&hdev->debug_list_lock);
sema_init(&hdev->driver_lock, 1); sema_init(&hdev->driver_lock, 1);
sema_init(&hdev->driver_input_lock, 1);
return hdev; return hdev;
} }

View File

@ -580,17 +580,49 @@ void hid_debug_event(struct hid_device *hdev, char *buf)
int i; int i;
struct hid_debug_list *list; struct hid_debug_list *list;
mutex_lock(&hdev->debug_list_lock);
list_for_each_entry(list, &hdev->debug_list, node) { list_for_each_entry(list, &hdev->debug_list, node) {
for (i = 0; i < strlen(buf); i++) for (i = 0; i < strlen(buf); i++)
list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] = list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
buf[i]; buf[i];
list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE; list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
} }
mutex_unlock(&hdev->debug_list_lock);
wake_up_interruptible(&hdev->debug_wait); wake_up_interruptible(&hdev->debug_wait);
} }
EXPORT_SYMBOL_GPL(hid_debug_event); EXPORT_SYMBOL_GPL(hid_debug_event);
void hid_dump_report(struct hid_device *hid, int type, u8 *data,
int size)
{
struct hid_report_enum *report_enum;
char *buf;
unsigned int i;
buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
if (!buf)
return;
report_enum = hid->report_enum + type;
/* dump the report */
snprintf(buf, HID_DEBUG_BUFSIZE - 1,
"\nreport (size %u) (%snumbered) = ", size,
report_enum->numbered ? "" : "un");
hid_debug_event(hid, buf);
for (i = 0; i < size; i++) {
snprintf(buf, HID_DEBUG_BUFSIZE - 1,
" %02x", data[i]);
hid_debug_event(hid, buf);
}
hid_debug_event(hid, "\n");
kfree(buf);
}
EXPORT_SYMBOL_GPL(hid_dump_report);
void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage, __s32 value) void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage, __s32 value)
{ {
char *buf; char *buf;
@ -960,7 +992,9 @@ static int hid_debug_events_open(struct inode *inode, struct file *file)
file->private_data = list; file->private_data = list;
mutex_init(&list->read_mutex); mutex_init(&list->read_mutex);
mutex_lock(&list->hdev->debug_list_lock);
list_add_tail(&list->node, &list->hdev->debug_list); list_add_tail(&list->node, &list->hdev->debug_list);
mutex_unlock(&list->hdev->debug_list_lock);
out: out:
return err; return err;
@ -1055,7 +1089,9 @@ static int hid_debug_events_release(struct inode *inode, struct file *file)
{ {
struct hid_debug_list *list = file->private_data; struct hid_debug_list *list = file->private_data;
mutex_lock(&list->hdev->debug_list_lock);
list_del(&list->node); list_del(&list->node);
mutex_unlock(&list->hdev->debug_list_lock);
kfree(list->hid_debug_buf); kfree(list->hid_debug_buf);
kfree(list); kfree(list);

View File

@ -29,14 +29,12 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include "hid-ids.h" #include "hid-ids.h"
#ifdef CONFIG_DRAGONRISE_FF #ifdef CONFIG_DRAGONRISE_FF
#include "usbhid/usbhid.h"
struct drff_device { struct drff_device {
struct hid_report *report; struct hid_report *report;
@ -68,7 +66,7 @@ static int drff_play(struct input_dev *dev, void *data,
drff->report->field[0]->value[1] = 0x00; drff->report->field[0]->value[1] = 0x00;
drff->report->field[0]->value[2] = weak; drff->report->field[0]->value[2] = weak;
drff->report->field[0]->value[4] = strong; drff->report->field[0]->value[4] = strong;
usbhid_submit_report(hid, drff->report, USB_DIR_OUT); hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
drff->report->field[0]->value[0] = 0xfa; drff->report->field[0]->value[0] = 0xfa;
drff->report->field[0]->value[1] = 0xfe; drff->report->field[0]->value[1] = 0xfe;
@ -80,7 +78,7 @@ static int drff_play(struct input_dev *dev, void *data,
drff->report->field[0]->value[2] = 0x00; drff->report->field[0]->value[2] = 0x00;
drff->report->field[0]->value[4] = 0x00; drff->report->field[0]->value[4] = 0x00;
dbg_hid("running with 0x%02x 0x%02x", strong, weak); dbg_hid("running with 0x%02x 0x%02x", strong, weak);
usbhid_submit_report(hid, drff->report, USB_DIR_OUT); hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
return 0; return 0;
} }
@ -132,7 +130,7 @@ static int drff_init(struct hid_device *hid)
drff->report->field[0]->value[4] = 0x00; drff->report->field[0]->value[4] = 0x00;
drff->report->field[0]->value[5] = 0x00; drff->report->field[0]->value[5] = 0x00;
drff->report->field[0]->value[6] = 0x00; drff->report->field[0]->value[6] = 0x00;
usbhid_submit_report(hid, drff->report, USB_DIR_OUT); hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
hid_info(hid, "Force Feedback for DragonRise Inc. " hid_info(hid, "Force Feedback for DragonRise Inc. "
"game controllers by Richard Walmsley <richwalm@gmail.com>\n"); "game controllers by Richard Walmsley <richwalm@gmail.com>\n");

View File

@ -23,11 +23,9 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include "hid-ids.h" #include "hid-ids.h"
#include "usbhid/usbhid.h"
struct emsff_device { struct emsff_device {
struct hid_report *report; struct hid_report *report;
@ -52,7 +50,7 @@ static int emsff_play(struct input_dev *dev, void *data,
emsff->report->field[0]->value[2] = strong; emsff->report->field[0]->value[2] = strong;
dbg_hid("running with 0x%02x 0x%02x\n", strong, weak); dbg_hid("running with 0x%02x 0x%02x\n", strong, weak);
usbhid_submit_report(hid, emsff->report, USB_DIR_OUT); hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
return 0; return 0;
} }
@ -104,7 +102,7 @@ static int emsff_init(struct hid_device *hid)
emsff->report->field[0]->value[4] = 0x00; emsff->report->field[0]->value[4] = 0x00;
emsff->report->field[0]->value[5] = 0x00; emsff->report->field[0]->value[5] = 0x00;
emsff->report->field[0]->value[6] = 0x00; emsff->report->field[0]->value[6] = 0x00;
usbhid_submit_report(hid, emsff->report, USB_DIR_OUT); hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
hid_info(hid, "force feedback for EMS based devices by Ignaz Forster <ignaz.forster@gmx.de>\n"); hid_info(hid, "force feedback for EMS based devices by Ignaz Forster <ignaz.forster@gmx.de>\n");

View File

@ -29,13 +29,11 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include "hid-ids.h" #include "hid-ids.h"
#ifdef CONFIG_GREENASIA_FF #ifdef CONFIG_GREENASIA_FF
#include "usbhid/usbhid.h"
struct gaff_device { struct gaff_device {
struct hid_report *report; struct hid_report *report;
@ -63,14 +61,14 @@ static int hid_gaff_play(struct input_dev *dev, void *data,
gaff->report->field[0]->value[4] = left; gaff->report->field[0]->value[4] = left;
gaff->report->field[0]->value[5] = 0; gaff->report->field[0]->value[5] = 0;
dbg_hid("running with 0x%02x 0x%02x", left, right); dbg_hid("running with 0x%02x 0x%02x", left, right);
usbhid_submit_report(hid, gaff->report, USB_DIR_OUT); hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
gaff->report->field[0]->value[0] = 0xfa; gaff->report->field[0]->value[0] = 0xfa;
gaff->report->field[0]->value[1] = 0xfe; gaff->report->field[0]->value[1] = 0xfe;
gaff->report->field[0]->value[2] = 0x0; gaff->report->field[0]->value[2] = 0x0;
gaff->report->field[0]->value[4] = 0x0; gaff->report->field[0]->value[4] = 0x0;
usbhid_submit_report(hid, gaff->report, USB_DIR_OUT); hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
return 0; return 0;
} }
@ -122,12 +120,12 @@ static int gaff_init(struct hid_device *hid)
gaff->report->field[0]->value[1] = 0x00; gaff->report->field[0]->value[1] = 0x00;
gaff->report->field[0]->value[2] = 0x00; gaff->report->field[0]->value[2] = 0x00;
gaff->report->field[0]->value[3] = 0x00; gaff->report->field[0]->value[3] = 0x00;
usbhid_submit_report(hid, gaff->report, USB_DIR_OUT); hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
gaff->report->field[0]->value[0] = 0xfa; gaff->report->field[0]->value[0] = 0xfa;
gaff->report->field[0]->value[1] = 0xfe; gaff->report->field[0]->value[1] = 0xfe;
usbhid_submit_report(hid, gaff->report, USB_DIR_OUT); hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
hid_info(hid, "Force Feedback for GreenAsia 0x12 devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n"); hid_info(hid, "Force Feedback for GreenAsia 0x12 devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n");

View File

@ -27,12 +27,10 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include "hid-ids.h" #include "hid-ids.h"
#ifdef CONFIG_HOLTEK_FF #ifdef CONFIG_HOLTEK_FF
#include "usbhid/usbhid.h"
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>"); MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
@ -102,7 +100,7 @@ static void holtekff_send(struct holtekff_device *holtekff,
dbg_hid("sending %*ph\n", 7, data); dbg_hid("sending %*ph\n", 7, data);
usbhid_submit_report(hid, holtekff->field->report, USB_DIR_OUT); hid_hw_request(hid, holtekff->field->report, HID_REQ_SET_REPORT);
} }
static int holtekff_play(struct input_dev *dev, void *data, static int holtekff_play(struct input_dev *dev, void *data,

View File

@ -16,8 +16,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h" #include "hid-ids.h"
@ -361,7 +359,7 @@ static int kye_tablet_enable(struct hid_device *hdev)
value[4] = 0x00; value[4] = 0x00;
value[5] = 0x00; value[5] = 0x00;
value[6] = 0x00; value[6] = 0x00;
usbhid_submit_report(hdev, report, USB_DIR_OUT); hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
return 0; return 0;
} }

View File

@ -68,7 +68,7 @@ static int tpkbd_features_set(struct hid_device *hdev)
report->field[2]->value[0] = data_pointer->sensitivity; report->field[2]->value[0] = data_pointer->sensitivity;
report->field[3]->value[0] = data_pointer->press_speed; report->field[3]->value[0] = data_pointer->press_speed;
usbhid_submit_report(hdev, report, USB_DIR_OUT); hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
return 0; return 0;
} }
@ -332,7 +332,7 @@ static void tpkbd_led_brightness_set(struct led_classdev *led_cdev,
report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3]; report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3];
report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1; report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1;
report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1; report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1;
usbhid_submit_report(hdev, report, USB_DIR_OUT); hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
} }
static int tpkbd_probe_tp(struct hid_device *hdev) static int tpkbd_probe_tp(struct hid_device *hdev)

View File

@ -23,10 +23,8 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
#include "usbhid/usbhid.h"
#include "hid-lg.h" #include "hid-lg.h"
struct lg2ff_device { struct lg2ff_device {
@ -56,7 +54,7 @@ static int play_effect(struct input_dev *dev, void *data,
lg2ff->report->field[0]->value[4] = 0x00; lg2ff->report->field[0]->value[4] = 0x00;
} }
usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT); hid_hw_request(hid, lg2ff->report, HID_REQ_SET_REPORT);
return 0; return 0;
} }
@ -108,7 +106,7 @@ int lg2ff_init(struct hid_device *hid)
report->field[0]->value[5] = 0x00; report->field[0]->value[5] = 0x00;
report->field[0]->value[6] = 0x00; report->field[0]->value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula <anssi.hannula@gmail.com>\n"); hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula <anssi.hannula@gmail.com>\n");

View File

@ -22,10 +22,8 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
#include "usbhid/usbhid.h"
#include "hid-lg.h" #include "hid-lg.h"
/* /*
@ -92,7 +90,7 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data,
report->field[0]->value[1] = (unsigned char)(-x); report->field[0]->value[1] = (unsigned char)(-x);
report->field[0]->value[31] = (unsigned char)(-y); report->field[0]->value[31] = (unsigned char)(-y);
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break; break;
} }
return 0; return 0;
@ -118,7 +116,7 @@ static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude)
report->field[0]->value[33] = 0x7F; report->field[0]->value[33] = 0x7F;
report->field[0]->value[34] = 0x7F; report->field[0]->value[34] = 0x7F;
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
} }

View File

@ -34,6 +34,7 @@
#define DFGT_REV_MAJ 0x13 #define DFGT_REV_MAJ 0x13
#define DFGT_REV_MIN 0x22 #define DFGT_REV_MIN 0x22
#define DFGT2_REV_MIN 0x26
#define DFP_REV_MAJ 0x11 #define DFP_REV_MAJ 0x11
#define DFP_REV_MIN 0x06 #define DFP_REV_MIN 0x06
#define FFEX_REV_MAJ 0x21 #define FFEX_REV_MAJ 0x21
@ -125,6 +126,7 @@ static const struct lg4ff_native_cmd native_g27 = {
static const struct lg4ff_usb_revision lg4ff_revs[] = { static const struct lg4ff_usb_revision lg4ff_revs[] = {
{DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Driving Force GT */ {DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Driving Force GT */
{DFGT_REV_MAJ, DFGT2_REV_MIN, &native_dfgt}, /* Driving Force GT v2 */
{DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */ {DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */
{G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */ {G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */
{G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */ {G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */
@ -202,7 +204,7 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e
value[5] = 0x00; value[5] = 0x00;
value[6] = 0x00; value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break; break;
} }
return 0; return 0;
@ -225,7 +227,7 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud
value[5] = 0x00; value[5] = 0x00;
value[6] = 0x00; value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
} }
/* Sends autocentering command compatible with Formula Force EX */ /* Sends autocentering command compatible with Formula Force EX */
@ -245,7 +247,7 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
value[5] = 0x00; value[5] = 0x00;
value[6] = 0x00; value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
} }
/* Sends command to set range compatible with G25/G27/Driving Force GT */ /* Sends command to set range compatible with G25/G27/Driving Force GT */
@ -265,7 +267,7 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range)
value[5] = 0x00; value[5] = 0x00;
value[6] = 0x00; value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
} }
/* Sends commands to set range compatible with Driving Force Pro wheel */ /* Sends commands to set range compatible with Driving Force Pro wheel */
@ -294,7 +296,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
report->field[0]->value[1] = 0x02; report->field[0]->value[1] = 0x02;
full_range = 200; full_range = 200;
} }
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
/* Prepare "fine" limit command */ /* Prepare "fine" limit command */
value[0] = 0x81; value[0] = 0x81;
@ -306,7 +308,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
value[6] = 0x00; value[6] = 0x00;
if (range == 200 || range == 900) { /* Do not apply any fine limit */ if (range == 200 || range == 900) { /* Do not apply any fine limit */
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
return; return;
} }
@ -320,7 +322,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
value[5] = (start_right & 0xe) << 4 | (start_left & 0xe); value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
value[6] = 0xff; value[6] = 0xff;
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
} }
static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_native_cmd *cmd) static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_native_cmd *cmd)
@ -334,7 +336,7 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
for (i = 0; i < 7; i++) for (i = 0; i < 7; i++)
report->field[0]->value[i] = cmd->cmd[j++]; report->field[0]->value[i] = cmd->cmd[j++];
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
} }
} }
@ -410,7 +412,7 @@ static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
value[4] = 0x00; value[4] = 0x00;
value[5] = 0x00; value[5] = 0x00;
value[6] = 0x00; value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
} }
static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,

View File

@ -30,10 +30,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/input.h> #include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
#include "usbhid/usbhid.h"
#include "hid-lg.h" #include "hid-lg.h"
struct dev_type { struct dev_type {
@ -89,7 +87,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
report->field[0]->value[2] = x; report->field[0]->value[2] = x;
report->field[0]->value[3] = y; report->field[0]->value[3] = y;
dbg_hid("(x, y)=(%04x, %04x)\n", x, y); dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break; break;
case FF_RUMBLE: case FF_RUMBLE:
@ -104,7 +102,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
report->field[0]->value[2] = left; report->field[0]->value[2] = left;
report->field[0]->value[3] = right; report->field[0]->value[3] = right;
dbg_hid("(left, right)=(%04x, %04x)\n", left, right); dbg_hid("(left, right)=(%04x, %04x)\n", left, right);
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break; break;
} }
return 0; return 0;
@ -124,7 +122,7 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
*value++ = 0x80; *value++ = 0x80;
*value++ = 0x00; *value++ = 0x00;
*value = 0x00; *value = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
} }
int lgff_init(struct hid_device* hid) int lgff_init(struct hid_device* hid)

View File

@ -27,7 +27,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h" #include "hid-ids.h"
#include "hid-logitech-dj.h" #include "hid-logitech-dj.h"
@ -193,7 +192,6 @@ static struct hid_ll_driver logi_dj_ll_driver;
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
size_t count, size_t count,
unsigned char report_type); unsigned char report_type);
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev, static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
struct dj_report *dj_report) struct dj_report *dj_report)
@ -234,7 +232,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] & if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
SPFUNCTION_DEVICE_LIST_EMPTY) { SPFUNCTION_DEVICE_LIST_EMPTY) {
dbg_hid("%s: device list is empty\n", __func__); dbg_hid("%s: device list is empty\n", __func__);
djrcv_dev->querying_devices = false;
return; return;
} }
@ -245,12 +242,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
return; return;
} }
if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
/* The device is already known. No need to reallocate it. */
dbg_hid("%s: device is already known\n", __func__);
return;
}
dj_hiddev = hid_allocate_device(); dj_hiddev = hid_allocate_device();
if (IS_ERR(dj_hiddev)) { if (IS_ERR(dj_hiddev)) {
dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n", dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
@ -314,7 +305,6 @@ static void delayedwork_callback(struct work_struct *work)
struct dj_report dj_report; struct dj_report dj_report;
unsigned long flags; unsigned long flags;
int count; int count;
int retval;
dbg_hid("%s\n", __func__); dbg_hid("%s\n", __func__);
@ -347,25 +337,6 @@ static void delayedwork_callback(struct work_struct *work)
logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report); logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
break; break;
default: default:
/* A normal report (i. e. not belonging to a pair/unpair notification)
* arriving here, means that the report arrived but we did not have a
* paired dj_device associated to the report's device_index, this
* means that the original "device paired" notification corresponding
* to this dj_device never arrived to this driver. The reason is that
* hid-core discards all packets coming from a device while probe() is
* executing. */
if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
/* ok, we don't know the device, just re-ask the
* receiver for the list of connected devices. */
retval = logi_dj_recv_query_paired_devices(djrcv_dev);
if (!retval) {
/* everything went fine, so just leave */
break;
}
dev_err(&djrcv_dev->hdev->dev,
"%s:logi_dj_recv_query_paired_devices "
"error:%d\n", __func__, retval);
}
dbg_hid("%s: unexpected report type\n", __func__); dbg_hid("%s: unexpected report type\n", __func__);
} }
} }
@ -396,12 +367,6 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
if (!djdev) { if (!djdev) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index); " is NULL, index %d\n", dj_report->device_index);
kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
if (schedule_work(&djrcv_dev->work) == 0) {
dbg_hid("%s: did not schedule the work item, was already "
"queued\n", __func__);
}
return; return;
} }
@ -432,12 +397,6 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
if (dj_device == NULL) { if (dj_device == NULL) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]" dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index); " is NULL, index %d\n", dj_report->device_index);
kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
if (schedule_work(&djrcv_dev->work) == 0) {
dbg_hid("%s: did not schedule the work item, was already "
"queued\n", __func__);
}
return; return;
} }
@ -475,7 +434,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
for (i = 0; i < report->field[0]->report_count; i++) for (i = 0; i < report->field[0]->report_count; i++)
report->field[0]->value[i] = data[i]; report->field[0]->value[i] = data[i];
usbhid_submit_report(hdev, report, USB_DIR_OUT); hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
return 0; return 0;
} }
@ -485,10 +444,6 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
struct dj_report *dj_report; struct dj_report *dj_report;
int retval; int retval;
/* no need to protect djrcv_dev->querying_devices */
if (djrcv_dev->querying_devices)
return 0;
dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
if (!dj_report) if (!dj_report)
return -ENOMEM; return -ENOMEM;
@ -500,7 +455,6 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
return retval; return retval;
} }
static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
unsigned timeout) unsigned timeout)
{ {
@ -644,7 +598,7 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS); hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS);
hid_set_field(report->field[0], 2, data[1]); hid_set_field(report->field[0], 2, data[1]);
usbhid_submit_report(dj_rcv_hiddev, report, USB_DIR_OUT); hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
return 0; return 0;
@ -809,6 +763,9 @@ static int logi_dj_probe(struct hid_device *hdev,
goto llopen_failed; goto llopen_failed;
} }
/* Allow incoming packets to arrive: */
hid_device_io_start(hdev);
retval = logi_dj_recv_query_paired_devices(djrcv_dev); retval = logi_dj_recv_query_paired_devices(djrcv_dev);
if (retval < 0) { if (retval < 0) {
dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices " dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices "

View File

@ -101,7 +101,6 @@ struct dj_receiver_dev {
struct work_struct work; struct work_struct work;
struct kfifo notif_fifo; struct kfifo notif_fifo;
spinlock_t lock; spinlock_t lock;
bool querying_devices;
}; };
struct dj_device { struct dj_device {

View File

@ -19,7 +19,6 @@
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include "hid-ids.h" #include "hid-ids.h"

View File

@ -2,8 +2,9 @@
* HID driver for multitouch panels * HID driver for multitouch panels
* *
* Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> * Copyright (c) 2010-2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France * Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France
* Copyright (c) 2012-2013 Red Hat, Inc
* *
* This code is partly based on hid-egalax.c: * This code is partly based on hid-egalax.c:
* *
@ -26,13 +27,23 @@
* any later version. * any later version.
*/ */
/*
* This driver is regularly tested thanks to the tool hid-test[1].
* This tool relies on hid-replay[2] and a database of hid devices[3].
* Please run these regression tests before patching this module so that
* your patch won't break existing known devices.
*
* [1] https://github.com/bentiss/hid-test
* [2] https://github.com/bentiss/hid-replay
* [3] https://github.com/bentiss/hid-devices
*/
#include <linux/device.h> #include <linux/device.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include "usbhid/usbhid.h"
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
@ -740,7 +751,7 @@ static void mt_set_input_mode(struct hid_device *hdev)
r = re->report_id_hash[td->inputmode]; r = re->report_id_hash[td->inputmode];
if (r) { if (r) {
r->field[0]->value[td->inputmode_index] = 0x02; r->field[0]->value[td->inputmode_index] = 0x02;
usbhid_submit_report(hdev, r, USB_DIR_OUT); hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
} }
} }
@ -765,7 +776,7 @@ static void mt_set_maxcontacts(struct hid_device *hdev)
max = min(fieldmax, max); max = min(fieldmax, max);
if (r->field[0]->value[0] != max) { if (r->field[0]->value[0] != max) {
r->field[0]->value[0] = max; r->field[0]->value[0] = max;
usbhid_submit_report(hdev, r, USB_DIR_OUT); hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
} }
} }
} }
@ -902,26 +913,11 @@ static int mt_reset_resume(struct hid_device *hdev)
static int mt_resume(struct hid_device *hdev) static int mt_resume(struct hid_device *hdev)
{ {
struct usb_interface *intf;
struct usb_host_interface *interface;
struct usb_device *dev;
if (hdev->bus != BUS_USB)
return 0;
intf = to_usb_interface(hdev->dev.parent);
interface = intf->cur_altsetting;
dev = hid_to_usb_dev(hdev);
/* Some Elan legacy devices require SET_IDLE to be set on resume. /* Some Elan legacy devices require SET_IDLE to be set on resume.
* It should be safe to send it to other devices too. * It should be safe to send it to other devices too.
* Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */ * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
usb_control_msg(dev, usb_sndctrlpipe(dev, 0), hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE);
HID_REQ_SET_IDLE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, interface->desc.bInterfaceNumber,
NULL, 0, USB_CTRL_SET_TIMEOUT);
return 0; return 0;
} }

View File

@ -118,8 +118,8 @@ static inline int ntrig_get_mode(struct hid_device *hdev)
if (!report) if (!report)
return -EINVAL; return -EINVAL;
usbhid_submit_report(hdev, report, USB_DIR_IN); hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
usbhid_wait_io(hdev); hid_hw_wait(hdev);
return (int)report->field[0]->value[0]; return (int)report->field[0]->value[0];
} }
@ -137,7 +137,7 @@ static inline void ntrig_set_mode(struct hid_device *hdev, const int mode)
if (!report) if (!report)
return; return;
usbhid_submit_report(hdev, report, USB_DIR_IN); hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
} }
static void ntrig_report_version(struct hid_device *hdev) static void ntrig_report_version(struct hid_device *hdev)
@ -937,8 +937,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (report) { if (report) {
/* Let the device settle to ensure the wakeup message gets /* Let the device settle to ensure the wakeup message gets
* through */ * through */
usbhid_wait_io(hdev); hid_hw_wait(hdev);
usbhid_submit_report(hdev, report, USB_DIR_IN); hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
/* /*
* Sanity check: if the current mode is invalid reset it to * Sanity check: if the current mode is invalid reset it to

View File

@ -142,10 +142,10 @@ struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
void picolcd_debug_out_report(struct picolcd_data *data, void picolcd_debug_out_report(struct picolcd_data *data,
struct hid_device *hdev, struct hid_report *report); struct hid_device *hdev, struct hid_report *report);
#define usbhid_submit_report(a, b, c) \ #define hid_hw_request(a, b, c) \
do { \ do { \
picolcd_debug_out_report(hid_get_drvdata(a), a, b); \ picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
usbhid_submit_report(a, b, c); \ hid_hw_request(a, b, c); \
} while (0) } while (0)
void picolcd_debug_raw_event(struct picolcd_data *data, void picolcd_debug_raw_event(struct picolcd_data *data,

View File

@ -18,8 +18,6 @@
***************************************************************************/ ***************************************************************************/
#include <linux/hid.h> #include <linux/hid.h>
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/backlight.h> #include <linux/backlight.h>
@ -46,7 +44,7 @@ static int picolcd_set_brightness(struct backlight_device *bdev)
spin_lock_irqsave(&data->lock, flags); spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0); hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
if (!(data->status & PICOLCD_FAILED)) if (!(data->status & PICOLCD_FAILED))
usbhid_submit_report(data->hdev, report, USB_DIR_OUT); hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
return 0; return 0;
} }

View File

@ -21,8 +21,6 @@
#include <linux/hid-debug.h> #include <linux/hid-debug.h>
#include <linux/input.h> #include <linux/input.h>
#include "hid-ids.h" #include "hid-ids.h"
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>

View File

@ -21,8 +21,6 @@
#include <linux/hid-debug.h> #include <linux/hid-debug.h>
#include <linux/input.h> #include <linux/input.h>
#include "hid-ids.h" #include "hid-ids.h"
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
@ -110,7 +108,7 @@ struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
work = NULL; work = NULL;
} else { } else {
data->pending = work; data->pending = work;
usbhid_submit_report(data->hdev, report, USB_DIR_OUT); hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
wait_for_completion_interruptible_timeout(&work->ready, HZ*2); wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
spin_lock_irqsave(&data->lock, flags); spin_lock_irqsave(&data->lock, flags);
@ -244,7 +242,7 @@ int picolcd_reset(struct hid_device *hdev)
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
return -ENODEV; return -ENODEV;
} }
usbhid_submit_report(hdev, report, USB_DIR_OUT); hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
error = picolcd_check_version(hdev); error = picolcd_check_version(hdev);
@ -303,7 +301,7 @@ static ssize_t picolcd_operation_mode_store(struct device *dev,
spin_lock_irqsave(&data->lock, flags); spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, timeout & 0xff); hid_set_field(report->field[0], 0, timeout & 0xff);
hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff); hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
usbhid_submit_report(data->hdev, report, USB_DIR_OUT); hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
return count; return count;
} }

View File

@ -19,8 +19,6 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/hid-debug.h> #include <linux/hid-debug.h>
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>

View File

@ -19,8 +19,6 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/module.h> #include <linux/module.h>
@ -143,8 +141,8 @@ static int picolcd_fb_send_tile(struct picolcd_data *data, u8 *vbitmap,
else else
hid_set_field(report2->field[0], 4 + i - 32, tdata[i]); hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
usbhid_submit_report(data->hdev, report1, USB_DIR_OUT); hid_hw_request(data->hdev, report1, HID_REQ_SET_REPORT);
usbhid_submit_report(data->hdev, report2, USB_DIR_OUT); hid_hw_request(data->hdev, report2, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
return 0; return 0;
} }
@ -214,7 +212,7 @@ int picolcd_fb_reset(struct picolcd_data *data, int clear)
hid_set_field(report->field[0], j, mapcmd[j]); hid_set_field(report->field[0], j, mapcmd[j]);
else else
hid_set_field(report->field[0], j, 0); hid_set_field(report->field[0], j, 0);
usbhid_submit_report(data->hdev, report, USB_DIR_OUT); hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
} }
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
@ -270,7 +268,7 @@ static void picolcd_fb_update(struct fb_info *info)
mutex_unlock(&info->lock); mutex_unlock(&info->lock);
if (!data) if (!data)
return; return;
usbhid_wait_io(data->hdev); hid_hw_wait(data->hdev);
mutex_lock(&info->lock); mutex_lock(&info->lock);
n = 0; n = 0;
} }
@ -288,7 +286,7 @@ static void picolcd_fb_update(struct fb_info *info)
spin_unlock_irqrestore(&fbdata->lock, flags); spin_unlock_irqrestore(&fbdata->lock, flags);
mutex_unlock(&info->lock); mutex_unlock(&info->lock);
if (data) if (data)
usbhid_wait_io(data->hdev); hid_hw_wait(data->hdev);
return; return;
} }
out: out:

View File

@ -18,8 +18,6 @@
***************************************************************************/ ***************************************************************************/
#include <linux/hid.h> #include <linux/hid.h>
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/lcd.h> #include <linux/lcd.h>
@ -48,7 +46,7 @@ static int picolcd_set_contrast(struct lcd_device *ldev, int contrast)
spin_lock_irqsave(&data->lock, flags); spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, data->lcd_contrast); hid_set_field(report->field[0], 0, data->lcd_contrast);
if (!(data->status & PICOLCD_FAILED)) if (!(data->status & PICOLCD_FAILED))
usbhid_submit_report(data->hdev, report, USB_DIR_OUT); hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
return 0; return 0;
} }

View File

@ -21,8 +21,6 @@
#include <linux/hid-debug.h> #include <linux/hid-debug.h>
#include <linux/input.h> #include <linux/input.h>
#include "hid-ids.h" #include "hid-ids.h"
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
@ -55,7 +53,7 @@ void picolcd_leds_set(struct picolcd_data *data)
spin_lock_irqsave(&data->lock, flags); spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, data->led_state); hid_set_field(report->field[0], 0, data->led_state);
if (!(data->status & PICOLCD_FAILED)) if (!(data->status & PICOLCD_FAILED))
usbhid_submit_report(data->hdev, report, USB_DIR_OUT); hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
} }

View File

@ -43,13 +43,11 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
#include "hid-ids.h" #include "hid-ids.h"
#ifdef CONFIG_PANTHERLORD_FF #ifdef CONFIG_PANTHERLORD_FF
#include "usbhid/usbhid.h"
struct plff_device { struct plff_device {
struct hid_report *report; struct hid_report *report;
@ -75,7 +73,7 @@ static int hid_plff_play(struct input_dev *dev, void *data,
*plff->strong = left; *plff->strong = left;
*plff->weak = right; *plff->weak = right;
debug("running with 0x%02x 0x%02x", left, right); debug("running with 0x%02x 0x%02x", left, right);
usbhid_submit_report(hid, plff->report, USB_DIR_OUT); hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT);
return 0; return 0;
} }
@ -169,7 +167,7 @@ static int plff_init(struct hid_device *hid)
*strong = 0x00; *strong = 0x00;
*weak = 0x00; *weak = 0x00;
usbhid_submit_report(hid, plff->report, USB_DIR_OUT); hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT);
} }
hid_info(hid, "Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); hid_info(hid, "Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>\n");

View File

@ -26,7 +26,6 @@
#include <sound/core.h> #include <sound/core.h>
#include <sound/initval.h> #include <sound/initval.h>
#include <sound/rawmidi.h> #include <sound/rawmidi.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h" #include "hid-ids.h"
@ -306,7 +305,7 @@ static void pcmidi_submit_output_report(struct pcmidi_snd *pm, int state)
report->field[0]->value[0] = 0x01; report->field[0]->value[0] = 0x01;
report->field[0]->value[1] = state; report->field[0]->value[1] = state;
usbhid_submit_report(hdev, report, USB_DIR_OUT); hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
} }
static int pcmidi_handle_report1(struct pcmidi_snd *pm, u8 *data) static int pcmidi_handle_report1(struct pcmidi_snd *pm, u8 *data)

View File

@ -18,8 +18,6 @@
*/ */
#include <linux/device.h> #include <linux/device.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/usb.h>
#include "usbhid/usbhid.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
@ -204,8 +202,8 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
goto done_proc; goto done_proc;
} }
hid_set_field(report->field[field_index], 0, value); hid_set_field(report->field[field_index], 0, value);
usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT); hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT);
usbhid_wait_io(hsdev->hdev); hid_hw_wait(hsdev->hdev);
done_proc: done_proc:
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
@ -227,8 +225,8 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
ret = -EINVAL; ret = -EINVAL;
goto done_proc; goto done_proc;
} }
usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN); hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
usbhid_wait_io(hsdev->hdev); hid_hw_wait(hsdev->hdev);
*value = report->field[field_index]->value[0]; *value = report->field[field_index]->value[0];
done_proc: done_proc:
@ -262,7 +260,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
goto err_free; goto err_free;
} }
usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN); hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5); wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
switch (data->pending.raw_size) { switch (data->pending.raw_size) {

View File

@ -28,13 +28,11 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include "hid-ids.h" #include "hid-ids.h"
#ifdef CONFIG_SMARTJOYPLUS_FF #ifdef CONFIG_SMARTJOYPLUS_FF
#include "usbhid/usbhid.h"
struct sjoyff_device { struct sjoyff_device {
struct hid_report *report; struct hid_report *report;
@ -57,7 +55,7 @@ static int hid_sjoyff_play(struct input_dev *dev, void *data,
sjoyff->report->field[0]->value[1] = right; sjoyff->report->field[0]->value[1] = right;
sjoyff->report->field[0]->value[2] = left; sjoyff->report->field[0]->value[2] = left;
dev_dbg(&dev->dev, "running with 0x%02x 0x%02x\n", left, right); dev_dbg(&dev->dev, "running with 0x%02x 0x%02x\n", left, right);
usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT); hid_hw_request(hid, sjoyff->report, HID_REQ_SET_REPORT);
return 0; return 0;
} }
@ -115,7 +113,7 @@ static int sjoyff_init(struct hid_device *hid)
sjoyff->report->field[0]->value[0] = 0x01; sjoyff->report->field[0]->value[0] = 0x01;
sjoyff->report->field[0]->value[1] = 0x00; sjoyff->report->field[0]->value[1] = 0x00;
sjoyff->report->field[0]->value[2] = 0x00; sjoyff->report->field[0]->value[2] = 0x00;
usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT); hid_hw_request(hid, sjoyff->report, HID_REQ_SET_REPORT);
} }
hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n"); hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n");

View File

@ -16,10 +16,8 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb.h>
#include "hid-ids.h" #include "hid-ids.h"
#include "usbhid/usbhid.h"
static const struct hid_device_id speedlink_devices[] = { static const struct hid_device_id speedlink_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE)}, { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE)},

View File

@ -16,7 +16,6 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h" #include "hid-ids.h"
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
@ -132,7 +131,7 @@ static void steelseries_srws1_set_leds(struct hid_device *hdev, __u16 leds)
value[14] = 0x00; value[14] = 0x00;
value[15] = 0x00; value[15] = 0x00;
usbhid_submit_report(hdev, report, USB_DIR_OUT); hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
/* Note: LED change does not show on device until the device is read/polled */ /* Note: LED change does not show on device until the device is read/polled */
} }

View File

@ -12,7 +12,6 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/usb.h>
#include "hid-ids.h" #include "hid-ids.h"

View File

@ -30,7 +30,6 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include "hid-ids.h" #include "hid-ids.h"
@ -46,7 +45,6 @@ static const signed short ff_joystick[] = {
}; };
#ifdef CONFIG_THRUSTMASTER_FF #ifdef CONFIG_THRUSTMASTER_FF
#include "usbhid/usbhid.h"
/* Usages for thrustmaster devices I know about */ /* Usages for thrustmaster devices I know about */
#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb) #define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb)
@ -103,7 +101,7 @@ static int tmff_play(struct input_dev *dev, void *data,
dbg_hid("(x, y)=(%04x, %04x)\n", x, y); dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
ff_field->value[0] = x; ff_field->value[0] = x;
ff_field->value[1] = y; ff_field->value[1] = y;
usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
break; break;
case FF_RUMBLE: case FF_RUMBLE:
@ -117,7 +115,7 @@ static int tmff_play(struct input_dev *dev, void *data,
dbg_hid("(left,right)=(%08x, %08x)\n", left, right); dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
ff_field->value[0] = left; ff_field->value[0] = left;
ff_field->value[1] = right; ff_field->value[1] = right;
usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
break; break;
} }
return 0; return 0;

View File

@ -24,13 +24,11 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include "hid-ids.h" #include "hid-ids.h"
#ifdef CONFIG_ZEROPLUS_FF #ifdef CONFIG_ZEROPLUS_FF
#include "usbhid/usbhid.h"
struct zpff_device { struct zpff_device {
struct hid_report *report; struct hid_report *report;
@ -59,7 +57,7 @@ static int zpff_play(struct input_dev *dev, void *data,
zpff->report->field[2]->value[0] = left; zpff->report->field[2]->value[0] = left;
zpff->report->field[3]->value[0] = right; zpff->report->field[3]->value[0] = right;
dbg_hid("running with 0x%02x 0x%02x\n", left, right); dbg_hid("running with 0x%02x 0x%02x\n", left, right);
usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT);
return 0; return 0;
} }
@ -104,7 +102,7 @@ static int zpff_init(struct hid_device *hid)
zpff->report->field[1]->value[0] = 0x02; zpff->report->field[1]->value[0] = 0x02;
zpff->report->field[2]->value[0] = 0x00; zpff->report->field[2]->value[0] = 0x00;
zpff->report->field[3]->value[0] = 0x00; zpff->report->field[3]->value[0] = 0x00;
usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT);
hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <anssi.hannula@gmail.com>\n");

View File

@ -563,6 +563,36 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
return ret; return ret;
} }
static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
int reqtype)
{
struct i2c_client *client = hid->driver_data;
char *buf;
int ret;
int len = i2c_hid_get_report_length(rep) - 2;
buf = kzalloc(len, GFP_KERNEL);
if (!buf)
return;
switch (reqtype) {
case HID_REQ_GET_REPORT:
ret = i2c_hid_get_raw_report(hid, rep->id, buf, len, rep->type);
if (ret < 0)
dev_err(&client->dev, "%s: unable to get report: %d\n",
__func__, ret);
else
hid_input_report(hid, rep->type, buf, ret, 0);
break;
case HID_REQ_SET_REPORT:
hid_output_report(rep, buf);
i2c_hid_output_raw_report(hid, buf, len, rep->type);
break;
}
kfree(buf);
}
static int i2c_hid_parse(struct hid_device *hid) static int i2c_hid_parse(struct hid_device *hid)
{ {
struct i2c_client *client = hid->driver_data; struct i2c_client *client = hid->driver_data;
@ -742,6 +772,7 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
.open = i2c_hid_open, .open = i2c_hid_open,
.close = i2c_hid_close, .close = i2c_hid_close,
.power = i2c_hid_power, .power = i2c_hid_power,
.request = i2c_hid_request,
.hidinput_input_event = i2c_hid_hidinput_input_event, .hidinput_input_event = i2c_hid_hidinput_input_event,
}; };

View File

@ -639,7 +639,7 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
} }
} }
void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) static void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
{ {
struct usbhid_device *usbhid = hid->driver_data; struct usbhid_device *usbhid = hid->driver_data;
unsigned long flags; unsigned long flags;
@ -648,7 +648,6 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
__usbhid_submit_report(hid, report, dir); __usbhid_submit_report(hid, report, dir);
spin_unlock_irqrestore(&usbhid->lock, flags); spin_unlock_irqrestore(&usbhid->lock, flags);
} }
EXPORT_SYMBOL_GPL(usbhid_submit_report);
/* Workqueue routine to send requests to change LEDs */ /* Workqueue routine to send requests to change LEDs */
static void hid_led(struct work_struct *work) static void hid_led(struct work_struct *work)
@ -706,7 +705,7 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un
return 0; return 0;
} }
int usbhid_wait_io(struct hid_device *hid) static int usbhid_wait_io(struct hid_device *hid)
{ {
struct usbhid_device *usbhid = hid->driver_data; struct usbhid_device *usbhid = hid->driver_data;
@ -720,7 +719,6 @@ int usbhid_wait_io(struct hid_device *hid)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(usbhid_wait_io);
static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle) static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
{ {
@ -1243,6 +1241,32 @@ static int usbhid_power(struct hid_device *hid, int lvl)
return r; return r;
} }
static void usbhid_request(struct hid_device *hid, struct hid_report *rep, int reqtype)
{
switch (reqtype) {
case HID_REQ_GET_REPORT:
usbhid_submit_report(hid, rep, USB_DIR_IN);
break;
case HID_REQ_SET_REPORT:
usbhid_submit_report(hid, rep, USB_DIR_OUT);
break;
}
}
static int usbhid_idle(struct hid_device *hid, int report, int idle,
int reqtype)
{
struct usb_device *dev = hid_to_usb_dev(hid);
struct usb_interface *intf = to_usb_interface(hid->dev.parent);
struct usb_host_interface *interface = intf->cur_altsetting;
int ifnum = interface->desc.bInterfaceNumber;
if (reqtype != HID_REQ_SET_IDLE)
return -EINVAL;
return hid_set_idle(dev, ifnum, report, idle);
}
static struct hid_ll_driver usb_hid_driver = { static struct hid_ll_driver usb_hid_driver = {
.parse = usbhid_parse, .parse = usbhid_parse,
.start = usbhid_start, .start = usbhid_start,
@ -1251,6 +1275,9 @@ static struct hid_ll_driver usb_hid_driver = {
.close = usbhid_close, .close = usbhid_close,
.power = usbhid_power, .power = usbhid_power,
.hidinput_input_event = usb_hidinput_input_event, .hidinput_input_event = usb_hidinput_input_event,
.request = usbhid_request,
.wait = usbhid_wait_io,
.idle = usbhid_idle,
}; };
static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id) static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id)

View File

@ -263,8 +263,8 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
envelope->attack_level, envelope->attack_level,
pidff->set_envelope[PID_ATTACK_LEVEL].value[0]); pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE], hid_hw_request(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
/* /*
@ -290,8 +290,8 @@ static void pidff_set_constant_force_report(struct pidff_device *pidff,
pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE], pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
effect->u.constant.level); effect->u.constant.level);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT], hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONSTANT],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
/* /*
@ -325,8 +325,8 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
pidff->effect_direction); pidff->effect_direction);
pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
/* /*
@ -357,8 +357,8 @@ static void pidff_set_periodic_report(struct pidff_device *pidff,
pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase); pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period; pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC], hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
@ -399,8 +399,8 @@ static void pidff_set_condition_report(struct pidff_device *pidff,
effect->u.condition[i].left_saturation); effect->u.condition[i].left_saturation);
pidff_set(&pidff->set_condition[PID_DEAD_BAND], pidff_set(&pidff->set_condition[PID_DEAD_BAND],
effect->u.condition[i].deadband); effect->u.condition[i].deadband);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONDITION],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
} }
@ -440,8 +440,8 @@ static void pidff_set_ramp_force_report(struct pidff_device *pidff,
effect->u.ramp.start_level); effect->u.ramp.start_level);
pidff_set_signed(&pidff->set_ramp[PID_RAMP_END], pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
effect->u.ramp.end_level); effect->u.ramp.end_level);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP], hid_hw_request(pidff->hid, pidff->reports[PID_SET_RAMP],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
/* /*
@ -465,19 +465,19 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
int j; int j;
pidff->create_new_effect_type->value[0] = efnum; pidff->create_new_effect_type->value[0] = efnum;
usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], hid_hw_request(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
USB_DIR_OUT); HID_REQ_SET_REPORT);
hid_dbg(pidff->hid, "create_new_effect sent, type: %d\n", efnum); hid_dbg(pidff->hid, "create_new_effect sent, type: %d\n", efnum);
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0; pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
pidff->block_load_status->value[0] = 0; pidff->block_load_status->value[0] = 0;
usbhid_wait_io(pidff->hid); hid_hw_wait(pidff->hid);
for (j = 0; j < 60; j++) { for (j = 0; j < 60; j++) {
hid_dbg(pidff->hid, "pid_block_load requested\n"); hid_dbg(pidff->hid, "pid_block_load requested\n");
usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD], hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
USB_DIR_IN); HID_REQ_GET_REPORT);
usbhid_wait_io(pidff->hid); hid_hw_wait(pidff->hid);
if (pidff->block_load_status->value[0] == if (pidff->block_load_status->value[0] ==
pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) { pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
hid_dbg(pidff->hid, "device reported free memory: %d bytes\n", hid_dbg(pidff->hid, "device reported free memory: %d bytes\n",
@ -513,8 +513,8 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
} }
usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
/** /**
@ -535,8 +535,8 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value)
static void pidff_erase_pid(struct pidff_device *pidff, int pid_id) static void pidff_erase_pid(struct pidff_device *pidff, int pid_id)
{ {
pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE], hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_FREE],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
/* /*
@ -551,7 +551,7 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id)
effect_id, pidff->pid_id[effect_id]); effect_id, pidff->pid_id[effect_id]);
/* Wait for the queue to clear. We do not want a full fifo to /* Wait for the queue to clear. We do not want a full fifo to
prevent the effect removal. */ prevent the effect removal. */
usbhid_wait_io(pidff->hid); hid_hw_wait(pidff->hid);
pidff_playback_pid(pidff, pid_id, 0); pidff_playback_pid(pidff, pid_id, 0);
pidff_erase_pid(pidff, pid_id); pidff_erase_pid(pidff, pid_id);
@ -718,8 +718,8 @@ static void pidff_set_gain(struct input_dev *dev, u16 gain)
struct pidff_device *pidff = dev->ff->private; struct pidff_device *pidff = dev->ff->private;
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
@ -744,8 +744,8 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
pidff->set_effect[PID_START_DELAY].value[0] = 0; pidff->set_effect[PID_START_DELAY].value[0] = 0;
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
/* /*
@ -1158,19 +1158,19 @@ static void pidff_reset(struct pidff_device *pidff)
pidff->device_control->value[0] = pidff->control_id[PID_RESET]; pidff->device_control->value[0] = pidff->control_id[PID_RESET];
/* We reset twice as sometimes hid_wait_io isn't waiting long enough */ /* We reset twice as sometimes hid_wait_io isn't waiting long enough */
usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
usbhid_wait_io(hid); hid_hw_wait(hid);
usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
usbhid_wait_io(hid); hid_hw_wait(hid);
pidff->device_control->value[0] = pidff->device_control->value[0] =
pidff->control_id[PID_ENABLE_ACTUATORS]; pidff->control_id[PID_ENABLE_ACTUATORS];
usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
usbhid_wait_io(hid); hid_hw_wait(hid);
/* pool report is sometimes messed up, refetch it */ /* pool report is sometimes messed up, refetch it */
usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT);
usbhid_wait_io(hid); hid_hw_wait(hid);
if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) { while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) {
@ -1181,9 +1181,9 @@ static void pidff_reset(struct pidff_device *pidff)
break; break;
} }
hid_dbg(pidff->hid, "pid_pool requested again\n"); hid_dbg(pidff->hid, "pid_pool requested again\n");
usbhid_submit_report(hid, pidff->reports[PID_POOL], hid_hw_request(hid, pidff->reports[PID_POOL],
USB_DIR_IN); HID_REQ_GET_REPORT);
usbhid_wait_io(hid); hid_hw_wait(hid);
} }
} }
} }
@ -1269,8 +1269,8 @@ int hid_pidff_init(struct hid_device *hid)
if (test_bit(FF_GAIN, dev->ffbit)) { if (test_bit(FF_GAIN, dev->ffbit)) {
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff); pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
usbhid_submit_report(hid, pidff->reports[PID_DEVICE_GAIN], hid_hw_request(hid, pidff->reports[PID_DEVICE_GAIN],
USB_DIR_OUT); HID_REQ_SET_REPORT);
} }
error = pidff_check_autocenter(pidff, dev); error = pidff_check_autocenter(pidff, dev);

View File

@ -705,8 +705,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (report == NULL) if (report == NULL)
break; break;
usbhid_submit_report(hid, report, USB_DIR_IN); hid_hw_request(hid, report, HID_REQ_GET_REPORT);
usbhid_wait_io(hid); hid_hw_wait(hid);
r = 0; r = 0;
break; break;
@ -724,8 +724,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (report == NULL) if (report == NULL)
break; break;
usbhid_submit_report(hid, report, USB_DIR_OUT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
usbhid_wait_io(hid); hid_hw_wait(hid);
r = 0; r = 0;
break; break;

View File

@ -34,12 +34,9 @@
#include <linux/input.h> #include <linux/input.h>
/* API provided by hid-core.c for USB HID drivers */ /* API provided by hid-core.c for USB HID drivers */
int usbhid_wait_io(struct hid_device* hid);
void usbhid_close(struct hid_device *hid); void usbhid_close(struct hid_device *hid);
int usbhid_open(struct hid_device *hid); int usbhid_open(struct hid_device *hid);
void usbhid_init_reports(struct hid_device *hid); void usbhid_init_reports(struct hid_device *hid);
void usbhid_submit_report
(struct hid_device *hid, struct hid_report *report, unsigned char dir);
int usbhid_get_power(struct hid_device *hid); int usbhid_get_power(struct hid_device *hid);
void usbhid_put_power(struct hid_device *hid); void usbhid_put_power(struct hid_device *hid);
struct usb_interface *usbhid_find_interface(int minor); struct usb_interface *usbhid_find_interface(int minor);

View File

@ -22,11 +22,12 @@
* *
*/ */
#define HID_DEBUG_BUFSIZE 512
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
#define HID_DEBUG_BUFSIZE 512
void hid_dump_input(struct hid_device *, struct hid_usage *, __s32); void hid_dump_input(struct hid_device *, struct hid_usage *, __s32);
void hid_dump_report(struct hid_device *, int , u8 *, int);
void hid_dump_device(struct hid_device *, struct seq_file *); void hid_dump_device(struct hid_device *, struct seq_file *);
void hid_dump_field(struct hid_field *, int, struct seq_file *); void hid_dump_field(struct hid_field *, int, struct seq_file *);
char *hid_resolv_usage(unsigned, struct seq_file *); char *hid_resolv_usage(unsigned, struct seq_file *);
@ -50,6 +51,7 @@ struct hid_debug_list {
#else #else
#define hid_dump_input(a,b,c) do { } while (0) #define hid_dump_input(a,b,c) do { } while (0)
#define hid_dump_report(a,b,c,d) do { } while (0)
#define hid_dump_device(a,b) do { } while (0) #define hid_dump_device(a,b) do { } while (0)
#define hid_dump_field(a,b,c) do { } while (0) #define hid_dump_field(a,b,c) do { } while (0)
#define hid_resolv_usage(a,b) do { } while (0) #define hid_resolv_usage(a,b) do { } while (0)

View File

@ -456,7 +456,8 @@ struct hid_device { /* device report descriptor */
unsigned country; /* HID country */ unsigned country; /* HID country */
struct hid_report_enum report_enum[HID_REPORT_TYPES]; struct hid_report_enum report_enum[HID_REPORT_TYPES];
struct semaphore driver_lock; /* protects the current driver */ struct semaphore driver_lock; /* protects the current driver, except during input */
struct semaphore driver_input_lock; /* protects the current driver */
struct device dev; /* device */ struct device dev; /* device */
struct hid_driver *driver; struct hid_driver *driver;
struct hid_ll_driver *ll_driver; struct hid_ll_driver *ll_driver;
@ -477,6 +478,7 @@ struct hid_device { /* device report descriptor */
unsigned int status; /* see STAT flags above */ unsigned int status; /* see STAT flags above */
unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */ unsigned quirks; /* Various quirks the device can pull on us */
bool io_started; /* Protected by driver_lock. If IO has started */
struct list_head inputs; /* The list of inputs */ struct list_head inputs; /* The list of inputs */
void *hiddev; /* The hiddev structure */ void *hiddev; /* The hiddev structure */
@ -512,6 +514,7 @@ struct hid_device { /* device report descriptor */
struct dentry *debug_rdesc; struct dentry *debug_rdesc;
struct dentry *debug_events; struct dentry *debug_events;
struct list_head debug_list; struct list_head debug_list;
struct mutex debug_list_lock;
wait_queue_head_t debug_wait; wait_queue_head_t debug_wait;
}; };
@ -599,6 +602,10 @@ struct hid_usage_id {
* @resume: invoked on resume if device was not reset (NULL means nop) * @resume: invoked on resume if device was not reset (NULL means nop)
* @reset_resume: invoked on resume if device was reset (NULL means nop) * @reset_resume: invoked on resume if device was reset (NULL means nop)
* *
* probe should return -errno on error, or 0 on success. During probe,
* input will not be passed to raw_event unless hid_device_io_start is
* called.
*
* raw_event and event should return 0 on no action performed, 1 when no * raw_event and event should return 0 on no action performed, 1 when no
* further processing should be done and negative on error * further processing should be done and negative on error
* *
@ -662,6 +669,9 @@ struct hid_driver {
* @hidinput_input_event: event input event (e.g. ff or leds) * @hidinput_input_event: event input event (e.g. ff or leds)
* @parse: this method is called only once to parse the device data, * @parse: this method is called only once to parse the device data,
* shouldn't allocate anything to not leak memory * shouldn't allocate anything to not leak memory
* @request: send report request to device (e.g. feature report)
* @wait: wait for buffered io to complete (send/recv reports)
* @idle: send idle request to device
*/ */
struct hid_ll_driver { struct hid_ll_driver {
int (*start)(struct hid_device *hdev); int (*start)(struct hid_device *hdev);
@ -676,6 +686,13 @@ struct hid_ll_driver {
unsigned int code, int value); unsigned int code, int value);
int (*parse)(struct hid_device *hdev); int (*parse)(struct hid_device *hdev);
void (*request)(struct hid_device *hdev,
struct hid_report *report, int reqtype);
int (*wait)(struct hid_device *hdev);
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
}; };
#define PM_HINT_FULLON 1<<5 #define PM_HINT_FULLON 1<<5
@ -737,6 +754,44 @@ const struct hid_device_id *hid_match_id(struct hid_device *hdev,
const struct hid_device_id *id); const struct hid_device_id *id);
s32 hid_snto32(__u32 value, unsigned n); s32 hid_snto32(__u32 value, unsigned n);
/**
* hid_device_io_start - enable HID input during probe, remove
*
* @hid - the device
*
* This should only be called during probe or remove and only be
* called by the thread calling probe or remove. It will allow
* incoming packets to be delivered to the driver.
*/
static inline void hid_device_io_start(struct hid_device *hid) {
if (hid->io_started) {
dev_warn(&hid->dev, "io already started");
return;
}
hid->io_started = true;
up(&hid->driver_input_lock);
}
/**
* hid_device_io_stop - disable HID input during probe, remove
*
* @hid - the device
*
* Should only be called after hid_device_io_start. It will prevent
* incoming packets from going to the driver for the duration of
* probe, remove. If called during probe, packets will still go to the
* driver after probe is complete. This function should only be called
* by the thread calling probe or remove.
*/
static inline void hid_device_io_stop(struct hid_device *hid) {
if (!hid->io_started) {
dev_warn(&hid->dev, "io already stopped");
return;
}
hid->io_started = false;
down(&hid->driver_input_lock);
}
/** /**
* hid_map_usage - map usage input bits * hid_map_usage - map usage input bits
* *
@ -883,6 +938,49 @@ static inline int hid_hw_power(struct hid_device *hdev, int level)
return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0; return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0;
} }
/**
* hid_hw_request - send report request to device
*
* @hdev: hid device
* @report: report to send
* @reqtype: hid request type
*/
static inline void hid_hw_request(struct hid_device *hdev,
struct hid_report *report, int reqtype)
{
if (hdev->ll_driver->request)
hdev->ll_driver->request(hdev, report, reqtype);
}
/**
* hid_hw_idle - send idle request to device
*
* @hdev: hid device
* @report: report to control
* @idle: idle state
* @reqtype: hid request type
*/
static inline int hid_hw_idle(struct hid_device *hdev, int report, int idle,
int reqtype)
{
if (hdev->ll_driver->idle)
return hdev->ll_driver->idle(hdev, report, idle, reqtype);
return 0;
}
/**
* hid_hw_wait - wait for buffered io to complete
*
* @hdev: hid device
*/
static inline void hid_hw_wait(struct hid_device *hdev)
{
if (hdev->ll_driver->wait)
hdev->ll_driver->wait(hdev);
}
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
int interrupt); int interrupt);