Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina: - hid driver transport cleanup, finalizing the long-desired decoupling of core from transport layers, by Benjamin Tissoires and Henrik Rydberg - support for hybrid finger/pen multitouch HID devices, by Benjamin Tissoires - fix for long-standing issue in Logitech unifying driver sometimes not inializing properly due to device specifics, by Andrew de los Reyes - Wii remote driver updates to support 2nd generation of devices, by David Herrmann - support for Apple IR remote - roccat driver now supports new devices (Roccat Kone Pure, IskuFX), by Stefan Achatz - debugfs locking fixes in hid debug interface, by Jiri Kosina * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (43 commits) HID: protect hid_debug_list HID: debug: break out hid_dump_report() into hid-debug HID: Add PID for Japanese version of NE4K keyboard HID: hid-lg4ff add support for new version of DFGT wheel HID: icade: u16 which never < 0 HID: clarify Magic Mouse Kconfig description HID: appleir: add support for Apple ir devices HID: roccat: added media key support for Kone HID: hid-lenovo-tpkbd: remove doubled hid_get_drvdata HID: i2c-hid: fix length for set/get report in i2c hid HID: wiimote: parse reduced status reports HID: wiimote: add 2nd generation Wii Remote IDs HID: wiimote: use unique battery names HID: hidraw: warn if userspace headers are outdated HID: multitouch: force BTN_STYLUS for pen devices HID: multitouch: append " Pen" to the name of the stylus input HID: multitouch: add handling for pen in dual-sensors device HID: multitouch: change touch sensor detection in mt_input_configured() HID: multitouch: do not map usage from non used reports HID: multitouch: breaks out touch handling in specific functions ...
This commit is contained in:
commit
19b344efa3
61 changed files with 1600 additions and 420 deletions
|
@ -101,7 +101,8 @@ Date: June 2011
|
|||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When written, this file lets one set the backlight intensity for
|
||||
a specific profile. Profile number is included in written data.
|
||||
The data has to be 10 bytes long.
|
||||
The data has to be 10 bytes long for Isku, IskuFX needs 16 bytes
|
||||
of data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
@ -141,3 +142,12 @@ Description: When written, this file lets one trigger easyshift functionality
|
|||
The data has to be 16 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/talkfx
|
||||
Date: February 2013
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When written, this file lets one trigger temporary color schemes
|
||||
from the host.
|
||||
The data has to be 16 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
|
105
Documentation/ABI/testing/sysfs-driver-hid-roccat-konepure
Normal file
105
Documentation/ABI/testing/sysfs-driver-hid-roccat-konepure
Normal file
|
@ -0,0 +1,105 @@
|
|||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/actual_profile
|
||||
Date: December 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse can store 5 profiles which can be switched by the
|
||||
press of a button. actual_profile holds number of actual profile.
|
||||
This value is persistent, so its value determines the profile
|
||||
that's active when the mouse is powered on next time.
|
||||
When written, the mouse activates the set profile immediately.
|
||||
The data has to be 3 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/control
|
||||
Date: December 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When written, this file lets one select which data from which
|
||||
profile will be read next. The data has to be 3 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/info
|
||||
Date: December 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read, this file returns general data like firmware version.
|
||||
When written, the device can be reset.
|
||||
The data is 6 bytes long.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/macro
|
||||
Date: December 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse can store a macro with max 500 key/button strokes
|
||||
internally.
|
||||
When written, this file lets one set the sequence for a specific
|
||||
button for a specific profile. Button and profile numbers are
|
||||
included in written data. The data has to be 2082 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/profile_buttons
|
||||
Date: December 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse can store 5 profiles which can be switched by the
|
||||
press of a button. A profile is split in settings and buttons.
|
||||
profile_buttons holds information about button layout.
|
||||
When written, this file lets one write the respective profile
|
||||
buttons back to the mouse. The data has to be 59 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/profile_settings
|
||||
Date: December 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse can store 5 profiles which can be switched by the
|
||||
press of a button. A profile is split in settings and buttons.
|
||||
profile_settings holds information like resolution, sensitivity
|
||||
and light effects.
|
||||
When written, this file lets one write the respective profile
|
||||
settings back to the mouse. The data has to be 31 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/sensor
|
||||
Date: December 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse has a tracking- and a distance-control-unit. These
|
||||
can be activated/deactivated and the lift-off distance can be
|
||||
set. The data has to be 6 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/talk
|
||||
Date: December 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: Used to active some easy* functions of the mouse from outside.
|
||||
The data has to be 16 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/tcu
|
||||
Date: December 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When written a calibration process for the tracking control unit
|
||||
can be initiated/cancelled. Also lets one read/write sensor
|
||||
registers.
|
||||
The data has to be 4 bytes long.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/tcu_image
|
||||
Date: December 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read the mouse returns a 30x30 pixel image of the
|
||||
sampled underground. This works only in the course of a
|
||||
calibration process initiated with tcu.
|
||||
The returned data is 1028 bytes in size.
|
||||
This file is readonly.
|
||||
Users: http://roccat.sourceforge.net
|
|
@ -92,14 +92,14 @@ menu "Special HID drivers"
|
|||
|
||||
config HID_A4TECH
|
||||
tristate "A4 tech mice" if EXPERT
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for A4 tech X5 and WOP-35 / Trust 450L mice.
|
||||
|
||||
config HID_ACRUX
|
||||
tristate "ACRUX game controller support"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Say Y here if you want to enable support for ACRUX game controllers.
|
||||
|
||||
|
@ -113,7 +113,7 @@ config HID_ACRUX_FF
|
|||
|
||||
config HID_APPLE
|
||||
tristate "Apple {i,Power,Mac}Books" if EXPERT
|
||||
depends on (USB_HID || BT_HIDP)
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for some Apple devices which less or more break
|
||||
|
@ -122,36 +122,47 @@ config HID_APPLE
|
|||
Say Y here if you want support for keyboards of Apple iBooks, PowerBooks,
|
||||
MacBooks, MacBook Pros and Apple Aluminum.
|
||||
|
||||
config HID_APPLEIR
|
||||
tristate "Apple infrared receiver"
|
||||
depends on (USB_HID)
|
||||
---help---
|
||||
Support for Apple infrared remote control. All the Apple computers from
|
||||
2005 onwards include such a port, except the unibody Macbook (2009),
|
||||
and Mac Pros. This receiver is also used in the Apple TV set-top box
|
||||
prior to the 2010 model.
|
||||
|
||||
Say Y here if you want support for Apple infrared remote control.
|
||||
|
||||
config HID_AUREAL
|
||||
tristate "Aureal"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
|
||||
|
||||
config HID_BELKIN
|
||||
tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for Belkin Flip KVM and Wireless keyboard.
|
||||
|
||||
config HID_CHERRY
|
||||
tristate "Cherry Cymotion keyboard" if EXPERT
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for Cherry Cymotion keyboard.
|
||||
|
||||
config HID_CHICONY
|
||||
tristate "Chicony Tactical pad" if EXPERT
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for Chicony Tactical pad.
|
||||
|
||||
config HID_PRODIKEYS
|
||||
tristate "Prodikeys PC-MIDI Keyboard support"
|
||||
depends on USB_HID && SND
|
||||
depends on HID && SND
|
||||
select SND_RAWMIDI
|
||||
---help---
|
||||
Support for Prodikeys PC-MIDI Keyboard device support.
|
||||
|
@ -166,14 +177,14 @@ config HID_PRODIKEYS
|
|||
|
||||
config HID_CYPRESS
|
||||
tristate "Cypress mouse and barcode readers" if EXPERT
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for cypress mouse and barcode readers.
|
||||
|
||||
config HID_DRAGONRISE
|
||||
tristate "DragonRise Inc. game controller"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Say Y here if you have DragonRise Inc. game controllers.
|
||||
These might be branded as:
|
||||
|
@ -192,7 +203,7 @@ config DRAGONRISE_FF
|
|||
|
||||
config HID_EMS_FF
|
||||
tristate "EMS Production Inc. force feedback support"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
select INPUT_FF_MEMLESS
|
||||
---help---
|
||||
Say Y here if you want to enable force feedback support for devices by
|
||||
|
@ -202,13 +213,13 @@ config HID_EMS_FF
|
|||
|
||||
config HID_ELECOM
|
||||
tristate "ELECOM BM084 bluetooth mouse"
|
||||
depends on BT_HIDP
|
||||
depends on HID
|
||||
---help---
|
||||
Support for the ELECOM BM084 (bluetooth mouse).
|
||||
|
||||
config HID_EZKEY
|
||||
tristate "Ezkey BTC 8193 keyboard" if EXPERT
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for Ezkey BTC 8193 keyboard.
|
||||
|
@ -231,7 +242,7 @@ config HOLTEK_FF
|
|||
|
||||
config HID_KEYTOUCH
|
||||
tristate "Keytouch HID devices"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Keytouch HID devices not fully compliant with
|
||||
the specification. Currently supported:
|
||||
|
@ -239,7 +250,7 @@ config HID_KEYTOUCH
|
|||
|
||||
config HID_KYE
|
||||
tristate "KYE/Genius devices"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for KYE/Genius devices not fully compliant with HID standard:
|
||||
- Ergo Mouse
|
||||
|
@ -249,25 +260,25 @@ config HID_KYE
|
|||
|
||||
config HID_UCLOGIC
|
||||
tristate "UC-Logic"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for UC-Logic tablets.
|
||||
|
||||
config HID_WALTOP
|
||||
tristate "Waltop"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Waltop tablets.
|
||||
|
||||
config HID_GYRATION
|
||||
tristate "Gyration remote control"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Gyration remote control.
|
||||
|
||||
config HID_ICADE
|
||||
tristate "ION iCade arcade controller"
|
||||
depends on BT_HIDP
|
||||
depends on HID
|
||||
---help---
|
||||
Support for the ION iCade arcade controller to work as a joystick.
|
||||
|
||||
|
@ -276,20 +287,20 @@ config HID_ICADE
|
|||
|
||||
config HID_TWINHAN
|
||||
tristate "Twinhan IR remote control"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Twinhan IR remote control.
|
||||
|
||||
config HID_KENSINGTON
|
||||
tristate "Kensington Slimblade Trackball" if EXPERT
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for Kensington Slimblade Trackball.
|
||||
|
||||
config HID_LCPOWER
|
||||
tristate "LC-Power"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for LC-Power RC1000MCE RF remote control.
|
||||
|
||||
|
@ -308,7 +319,7 @@ config HID_LENOVO_TPKBD
|
|||
|
||||
config HID_LOGITECH
|
||||
tristate "Logitech devices" if EXPERT
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for Logitech devices that are not fully compliant with HID standard.
|
||||
|
@ -373,31 +384,31 @@ config LOGIWHEELS_FF
|
|||
- Logitech Formula Force EX
|
||||
|
||||
config HID_MAGICMOUSE
|
||||
tristate "Apple MagicMouse multi-touch support"
|
||||
depends on BT_HIDP
|
||||
tristate "Apple Magic Mouse/Trackpad multi-touch support"
|
||||
depends on HID
|
||||
---help---
|
||||
Support for the Apple Magic Mouse multi-touch.
|
||||
Support for the Apple Magic Mouse/Trackpad multi-touch.
|
||||
|
||||
Say Y here if you want support for the multi-touch features of the
|
||||
Apple Wireless "Magic" Mouse.
|
||||
Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad.
|
||||
|
||||
config HID_MICROSOFT
|
||||
tristate "Microsoft non-fully HID-compliant devices" if EXPERT
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for Microsoft devices that are not fully compliant with HID standard.
|
||||
|
||||
config HID_MONTEREY
|
||||
tristate "Monterey Genius KB29E keyboard" if EXPERT
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for Monterey Genius KB29E.
|
||||
|
||||
config HID_MULTITOUCH
|
||||
tristate "HID Multitouch panels"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Generic support for HID multitouch panels.
|
||||
|
||||
|
@ -445,7 +456,7 @@ config HID_NTRIG
|
|||
|
||||
config HID_ORTEK
|
||||
tristate "Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
There are certain devices which have LogicalMaximum wrong in the keyboard
|
||||
usage page of their report descriptor. The most prevailing ones so far
|
||||
|
@ -458,7 +469,7 @@ config HID_ORTEK
|
|||
|
||||
config HID_PANTHERLORD
|
||||
tristate "Pantherlord/GreenAsia game controller"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Say Y here if you have a PantherLord/GreenAsia based game controller
|
||||
or adapter.
|
||||
|
@ -473,13 +484,13 @@ config PANTHERLORD_FF
|
|||
|
||||
config HID_PETALYNX
|
||||
tristate "Petalynx Maxter remote control"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Petalynx Maxter remote control.
|
||||
|
||||
config HID_PICOLCD
|
||||
tristate "PicoLCD (graphic version)"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
This provides support for Minibox PicoLCD devices, currently
|
||||
only the graphical ones are supported.
|
||||
|
@ -545,14 +556,14 @@ config HID_PICOLCD_CIR
|
|||
|
||||
config HID_PRIMAX
|
||||
tristate "Primax non-fully HID-compliant devices"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Primax devices that are not fully compliant with the
|
||||
HID standard.
|
||||
|
||||
config HID_PS3REMOTE
|
||||
tristate "Sony PS3 BD Remote Control"
|
||||
depends on BT_HIDP
|
||||
depends on HID
|
||||
---help---
|
||||
Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech
|
||||
Harmony Adapter for PS3, which connect over Bluetooth.
|
||||
|
@ -569,7 +580,7 @@ config HID_ROCCAT
|
|||
|
||||
config HID_SAITEK
|
||||
tristate "Saitek non-fully HID-compliant devices"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Saitek devices that are not fully compliant with the
|
||||
HID standard.
|
||||
|
@ -578,7 +589,7 @@ config HID_SAITEK
|
|||
|
||||
config HID_SAMSUNG
|
||||
tristate "Samsung InfraRed remote control or keyboards"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Samsung InfraRed remote control or keyboards.
|
||||
|
||||
|
@ -592,25 +603,25 @@ config HID_SONY
|
|||
|
||||
config HID_SPEEDLINK
|
||||
tristate "Speedlink VAD Cezanne mouse support"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Speedlink Vicious and Divine Cezanne mouse.
|
||||
|
||||
config HID_STEELSERIES
|
||||
tristate "Steelseries SRW-S1 steering wheel support"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Steelseries SRW-S1 steering wheel
|
||||
|
||||
config HID_SUNPLUS
|
||||
tristate "Sunplus wireless desktop"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Sunplus wireless desktop.
|
||||
|
||||
config HID_GREENASIA
|
||||
tristate "GreenAsia (Product ID 0x12) game controller support"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Say Y here if you have a GreenAsia (Product ID 0x12) based game
|
||||
controller or adapter.
|
||||
|
@ -632,7 +643,7 @@ config HID_HYPERV_MOUSE
|
|||
|
||||
config HID_SMARTJOYPLUS
|
||||
tristate "SmartJoy PLUS PS2/USB adapter support"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
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.
|
||||
|
@ -650,20 +661,20 @@ config SMARTJOYPLUS_FF
|
|||
|
||||
config HID_TIVO
|
||||
tristate "TiVo Slide Bluetooth remote control support"
|
||||
depends on (USB_HID || BT_HIDP)
|
||||
depends on HID
|
||||
---help---
|
||||
Say Y if you have a TiVo Slide Bluetooth remote control.
|
||||
|
||||
config HID_TOPSEED
|
||||
tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic
|
||||
CLLRCMCE remote control.
|
||||
|
||||
config HID_THINGM
|
||||
tristate "ThingM blink(1) USB RGB LED"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
depends on LEDS_CLASS
|
||||
---help---
|
||||
Support for the ThingM blink(1) USB RGB LED. This driver registers a
|
||||
|
@ -673,7 +684,7 @@ config HID_THINGM
|
|||
|
||||
config HID_THRUSTMASTER
|
||||
tristate "ThrustMaster devices support"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
|
||||
a THRUSTMASTER Ferrari GT Rumble Wheel.
|
||||
|
@ -689,7 +700,7 @@ config THRUSTMASTER_FF
|
|||
|
||||
config HID_WACOM
|
||||
tristate "Wacom Bluetooth devices support"
|
||||
depends on BT_HIDP
|
||||
depends on HID
|
||||
depends on LEDS_CLASS
|
||||
select POWER_SUPPLY
|
||||
---help---
|
||||
|
@ -697,7 +708,7 @@ config HID_WACOM
|
|||
|
||||
config HID_WIIMOTE
|
||||
tristate "Nintendo Wii Remote support"
|
||||
depends on BT_HIDP
|
||||
depends on HID
|
||||
depends on LEDS_CLASS
|
||||
select POWER_SUPPLY
|
||||
select INPUT_FF_MEMLESS
|
||||
|
@ -715,7 +726,7 @@ config HID_WIIMOTE_EXT
|
|||
|
||||
config HID_ZEROPLUS
|
||||
tristate "Zeroplus based game controller support"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Say Y here if you have a Zeroplus based game controller.
|
||||
|
||||
|
@ -729,16 +740,16 @@ config ZEROPLUS_FF
|
|||
|
||||
config HID_ZYDACRON
|
||||
tristate "Zydacron remote control support"
|
||||
depends on USB_HID
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Zydacron remote control.
|
||||
|
||||
config HID_SENSOR_HUB
|
||||
tristate "HID Sensors framework support"
|
||||
depends on USB_HID && GENERIC_HARDIRQS
|
||||
depends on HID && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
default n
|
||||
-- help---
|
||||
---help---
|
||||
Support for HID Sensor framework. This creates a MFD instance
|
||||
for a sensor hub and identifies all the sensors connected to it.
|
||||
Each sensor is registered as a MFD cell, so that sensor specific
|
||||
|
|
|
@ -39,6 +39,7 @@ endif
|
|||
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
|
||||
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
|
||||
obj-$(CONFIG_HID_APPLE) += hid-apple.o
|
||||
obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
|
||||
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
|
||||
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
|
||||
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
|
||||
|
@ -94,8 +95,8 @@ obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
|
|||
obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o
|
||||
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
|
||||
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
|
||||
hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-lua.o \
|
||||
hid-roccat-pyra.o hid-roccat-savu.o
|
||||
hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \
|
||||
hid-roccat-lua.o hid-roccat-pyra.o hid-roccat-savu.o
|
||||
obj-$(CONFIG_HID_SAITEK) += hid-saitek.o
|
||||
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
|
||||
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
|
@ -390,10 +389,6 @@ static void apple_remove(struct hid_device *hdev)
|
|||
}
|
||||
|
||||
static const struct hid_device_id apple_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
|
||||
.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
|
||||
.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
|
||||
.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
|
||||
|
||||
|
|
352
drivers/hid/hid-appleir.c
Normal file
352
drivers/hid/hid-appleir.c
Normal file
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* HID driver for the apple ir device
|
||||
*
|
||||
* Original driver written by James McKenzie
|
||||
* Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
|
||||
* Updated to support newer remotes by Bastien Nocera <hadess@hadess.net>
|
||||
* Ported to HID subsystem by Benjamin Tissoires <benjamin.tissoires@gmail.com>
|
||||
*
|
||||
* Copyright (C) 2006 James McKenzie
|
||||
* Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
|
||||
* Copyright (C) 2008 Novell Inc.
|
||||
* Copyright (C) 2010, 2012 Bastien Nocera <hadess@hadess.net>
|
||||
* Copyright (C) 2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
|
||||
* Copyright (C) 2013 Red Hat Inc. All Rights Reserved
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include "hid-ids.h"
|
||||
|
||||
MODULE_AUTHOR("James McKenzie");
|
||||
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
|
||||
MODULE_DESCRIPTION("HID Apple IR remote controls");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define KEY_MASK 0x0F
|
||||
#define TWO_PACKETS_MASK 0x40
|
||||
|
||||
/*
|
||||
* James McKenzie has two devices both of which report the following
|
||||
* 25 87 ee 83 0a +
|
||||
* 25 87 ee 83 0c -
|
||||
* 25 87 ee 83 09 <<
|
||||
* 25 87 ee 83 06 >>
|
||||
* 25 87 ee 83 05 >"
|
||||
* 25 87 ee 83 03 menu
|
||||
* 26 00 00 00 00 for key repeat
|
||||
*/
|
||||
|
||||
/*
|
||||
* Thomas Glanzmann reports the following responses
|
||||
* 25 87 ee ca 0b +
|
||||
* 25 87 ee ca 0d -
|
||||
* 25 87 ee ca 08 <<
|
||||
* 25 87 ee ca 07 >>
|
||||
* 25 87 ee ca 04 >"
|
||||
* 25 87 ee ca 02 menu
|
||||
* 26 00 00 00 00 for key repeat
|
||||
*
|
||||
* He also observes the following event sometimes
|
||||
* sent after a key is release, which I interpret
|
||||
* as a flat battery message
|
||||
* 25 87 e0 ca 06 flat battery
|
||||
*/
|
||||
|
||||
/*
|
||||
* Alexandre Karpenko reports the following responses for Device ID 0x8242
|
||||
* 25 87 ee 47 0b +
|
||||
* 25 87 ee 47 0d -
|
||||
* 25 87 ee 47 08 <<
|
||||
* 25 87 ee 47 07 >>
|
||||
* 25 87 ee 47 04 >"
|
||||
* 25 87 ee 47 02 menu
|
||||
* 26 87 ee 47 ** for key repeat (** is the code of the key being held)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Bastien Nocera's remote
|
||||
* 25 87 ee 91 5f followed by
|
||||
* 25 87 ee 91 05 gives you >"
|
||||
*
|
||||
* 25 87 ee 91 5c followed by
|
||||
* 25 87 ee 91 05 gives you the middle button
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fabien Andre's remote
|
||||
* 25 87 ee a3 5e followed by
|
||||
* 25 87 ee a3 04 gives you >"
|
||||
*
|
||||
* 25 87 ee a3 5d followed by
|
||||
* 25 87 ee a3 04 gives you the middle button
|
||||
*/
|
||||
|
||||
static const unsigned short appleir_key_table[] = {
|
||||
KEY_RESERVED,
|
||||
KEY_MENU,
|
||||
KEY_PLAYPAUSE,
|
||||
KEY_FORWARD,
|
||||
KEY_BACK,
|
||||
KEY_VOLUMEUP,
|
||||
KEY_VOLUMEDOWN,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_ENTER,
|
||||
KEY_PLAYPAUSE,
|
||||
KEY_RESERVED,
|
||||
};
|
||||
|
||||
struct appleir {
|
||||
struct input_dev *input_dev;
|
||||
struct hid_device *hid;
|
||||
unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
|
||||
struct timer_list key_up_timer; /* timer for key up */
|
||||
spinlock_t lock; /* protects .current_key */
|
||||
int current_key; /* the currently pressed key */
|
||||
int prev_key_idx; /* key index in a 2 packets message */
|
||||
};
|
||||
|
||||
static int get_key(int data)
|
||||
{
|
||||
/*
|
||||
* The key is coded accross bits 2..9:
|
||||
*
|
||||
* 0x00 or 0x01 ( ) key: 0 -> KEY_RESERVED
|
||||
* 0x02 or 0x03 ( menu ) key: 1 -> KEY_MENU
|
||||
* 0x04 or 0x05 ( >" ) key: 2 -> KEY_PLAYPAUSE
|
||||
* 0x06 or 0x07 ( >> ) key: 3 -> KEY_FORWARD
|
||||
* 0x08 or 0x09 ( << ) key: 4 -> KEY_BACK
|
||||
* 0x0a or 0x0b ( + ) key: 5 -> KEY_VOLUMEUP
|
||||
* 0x0c or 0x0d ( - ) key: 6 -> KEY_VOLUMEDOWN
|
||||
* 0x0e or 0x0f ( ) key: 7 -> KEY_RESERVED
|
||||
* 0x50 or 0x51 ( ) key: 8 -> KEY_RESERVED
|
||||
* 0x52 or 0x53 ( ) key: 9 -> KEY_RESERVED
|
||||
* 0x54 or 0x55 ( ) key: 10 -> KEY_RESERVED
|
||||
* 0x56 or 0x57 ( ) key: 11 -> KEY_RESERVED
|
||||
* 0x58 or 0x59 ( ) key: 12 -> KEY_RESERVED
|
||||
* 0x5a or 0x5b ( ) key: 13 -> KEY_RESERVED
|
||||
* 0x5c or 0x5d ( middle ) key: 14 -> KEY_ENTER
|
||||
* 0x5e or 0x5f ( >" ) key: 15 -> KEY_PLAYPAUSE
|
||||
*
|
||||
* Packets starting with 0x5 are part of a two-packets message,
|
||||
* we notify the caller by sending a negative value.
|
||||
*/
|
||||
int key = (data >> 1) & KEY_MASK;
|
||||
|
||||
if ((data & TWO_PACKETS_MASK))
|
||||
/* Part of a 2 packets-command */
|
||||
key = -key;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static void key_up(struct hid_device *hid, struct appleir *appleir, int key)
|
||||
{
|
||||
input_report_key(appleir->input_dev, key, 0);
|
||||
input_sync(appleir->input_dev);
|
||||
}
|
||||
|
||||
static void key_down(struct hid_device *hid, struct appleir *appleir, int key)
|
||||
{
|
||||
input_report_key(appleir->input_dev, key, 1);
|
||||
input_sync(appleir->input_dev);
|
||||
}
|
||||
|
||||
static void battery_flat(struct appleir *appleir)
|
||||
{
|
||||
dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
|
||||
}
|
||||
|
||||
static void key_up_tick(unsigned long data)
|
||||
{
|
||||
struct appleir *appleir = (struct appleir *)data;
|
||||
struct hid_device *hid = appleir->hid;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&appleir->lock, flags);
|
||||
if (appleir->current_key) {
|
||||
key_up(hid, appleir, appleir->current_key);
|
||||
appleir->current_key = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&appleir->lock, flags);
|
||||
}
|
||||
|
||||
static int appleir_raw_event(struct hid_device *hid, struct hid_report *report,
|
||||
u8 *data, int len)
|
||||
{
|
||||
struct appleir *appleir = hid_get_drvdata(hid);
|
||||
static const u8 keydown[] = { 0x25, 0x87, 0xee };
|
||||
static const u8 keyrepeat[] = { 0x26, };
|
||||
static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
|
||||
unsigned long flags;
|
||||
|
||||
if (len != 5)
|
||||
goto out;
|
||||
|
||||
if (!memcmp(data, keydown, sizeof(keydown))) {
|
||||
int index;
|
||||
|
||||
spin_lock_irqsave(&appleir->lock, flags);
|
||||
/*
|
||||
* If we already have a key down, take it up before marking
|
||||
* this one down
|
||||
*/
|
||||
if (appleir->current_key)
|
||||
key_up(hid, appleir, appleir->current_key);
|
||||
|
||||
/* Handle dual packet commands */
|
||||
if (appleir->prev_key_idx > 0)
|
||||
index = appleir->prev_key_idx;
|
||||
else
|
||||
index = get_key(data[4]);
|
||||
|
||||
if (index >= 0) {
|
||||
appleir->current_key = appleir->keymap[index];
|
||||
|
||||
key_down(hid, appleir, appleir->current_key);
|
||||
/*
|
||||
* Remote doesn't do key up, either pull them up, in
|
||||
* the test above, or here set a timer which pulls
|
||||
* them up after 1/8 s
|
||||
*/
|
||||
mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
|
||||
appleir->prev_key_idx = 0;
|
||||
} else
|
||||
/* Remember key for next packet */
|
||||
appleir->prev_key_idx = -index;
|
||||
spin_unlock_irqrestore(&appleir->lock, flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
appleir->prev_key_idx = 0;
|
||||
|
||||
if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
|
||||
key_down(hid, appleir, appleir->current_key);
|
||||
/*
|
||||
* Remote doesn't do key up, either pull them up, in the test
|
||||
* above, or here set a timer which pulls them up after 1/8 s
|
||||
*/
|
||||
mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
|
||||
battery_flat(appleir);
|
||||
/* Fall through */
|
||||
}
|
||||
|
||||
out:
|
||||
/* let hidraw and hiddev handle the report */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void appleir_input_configured(struct hid_device *hid,
|
||||
struct hid_input *hidinput)
|
||||
{
|
||||
struct input_dev *input_dev = hidinput->input;
|
||||
struct appleir *appleir = hid_get_drvdata(hid);
|
||||
int i;
|
||||
|
||||
appleir->input_dev = input_dev;
|
||||
|
||||
input_dev->keycode = appleir->keymap;
|
||||
input_dev->keycodesize = sizeof(unsigned short);
|
||||
input_dev->keycodemax = ARRAY_SIZE(appleir->keymap);
|
||||
|
||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
|
||||
memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap));
|
||||
for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++)
|
||||
set_bit(appleir->keymap[i], input_dev->keybit);
|
||||
clear_bit(KEY_RESERVED, input_dev->keybit);
|
||||
}
|
||||
|
||||
static int appleir_input_mapping(struct hid_device *hid,
|
||||
struct hid_input *hi, struct hid_field *field,
|
||||
struct hid_usage *usage, unsigned long **bit, int *max)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int appleir_probe(struct hid_device *hid, const struct hid_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
struct appleir *appleir;
|
||||
|
||||
appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
|
||||
if (!appleir) {
|
||||
ret = -ENOMEM;
|
||||
goto allocfail;
|
||||
}
|
||||
|
||||
appleir->hid = hid;
|
||||
|
||||
spin_lock_init(&appleir->lock);
|
||||
setup_timer(&appleir->key_up_timer,
|
||||
key_up_tick, (unsigned long) appleir);
|
||||
|
||||
hid_set_drvdata(hid, appleir);
|
||||
|
||||
ret = hid_parse(hid);
|
||||
if (ret) {
|
||||
hid_err(hid, "parse failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = hid_hw_start(hid, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE);
|
||||
if (ret) {
|
||||
hid_err(hid, "hw start failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
kfree(appleir);
|
||||
allocfail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void appleir_remove(struct hid_device *hid)
|
||||
{
|
||||
struct appleir *appleir = hid_get_drvdata(hid);
|
||||
hid_hw_stop(hid);
|
||||
del_timer_sync(&appleir->key_up_timer);
|
||||
kfree(appleir);
|
||||
}
|
||||
|
||||
static const struct hid_device_id appleir_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, appleir_devices);
|
||||
|
||||
static struct hid_driver appleir_driver = {
|
||||
.name = "appleir",
|
||||
.id_table = appleir_devices,
|
||||
.raw_event = appleir_raw_event,
|
||||
.input_configured = appleir_input_configured,
|
||||
.probe = appleir_probe,
|
||||
.remove = appleir_remove,
|
||||
.input_mapping = appleir_input_mapping,
|
||||
};
|
||||
module_hid_driver(appleir_driver);
|
|
@ -29,14 +29,12 @@
|
|||
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
#ifdef CONFIG_HID_ACRUX_FF
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
struct axff_device {
|
||||
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);
|
||||
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
|
||||
hid_hw_request(hid, axff->report, HID_REQ_SET_REPORT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -114,7 +112,7 @@ static int axff_init(struct hid_device *hid)
|
|||
goto err_free_mem;
|
||||
|
||||
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");
|
||||
|
||||
|
|
|
@ -728,8 +728,7 @@ static int hid_scan_report(struct hid_device *hid)
|
|||
} else if (page == HID_UP_SENSOR &&
|
||||
item.type == HID_ITEM_TYPE_MAIN &&
|
||||
item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION &&
|
||||
(item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL &&
|
||||
(hid->bus == BUS_USB || hid->bus == BUS_I2C))
|
||||
(item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL)
|
||||
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_driver *hdrv;
|
||||
struct hid_report *report;
|
||||
char *buf;
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
if (!hid)
|
||||
return -ENODEV;
|
||||
|
||||
if (down_trylock(&hid->driver_lock))
|
||||
if (down_trylock(&hid->driver_input_lock))
|
||||
return -EBUSY;
|
||||
|
||||
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 */
|
||||
if (list_empty(&hid->debug_list))
|
||||
goto nomem;
|
||||
if (!list_empty(&hid->debug_list))
|
||||
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);
|
||||
|
||||
if (!report) {
|
||||
|
@ -1324,7 +1302,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
|
|||
ret = hid_report_raw_event(hid, type, data, size, interrupt);
|
||||
|
||||
unlock:
|
||||
up(&hid->driver_lock);
|
||||
up(&hid->driver_input_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_input_report);
|
||||
|
@ -1502,8 +1480,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
|
||||
|
@ -1527,6 +1503,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) },
|
||||
|
@ -1654,6 +1635,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
|
||||
|
@ -1687,6 +1669,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
|
||||
|
@ -1747,6 +1730,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -1845,6 +1829,11 @@ static int hid_device_probe(struct device *dev)
|
|||
|
||||
if (down_interruptible(&hdev->driver_lock))
|
||||
return -EINTR;
|
||||
if (down_interruptible(&hdev->driver_input_lock)) {
|
||||
ret = -EINTR;
|
||||
goto unlock_driver_lock;
|
||||
}
|
||||
hdev->io_started = false;
|
||||
|
||||
if (!hdev->driver) {
|
||||
id = hid_match_device(hdev, hdrv);
|
||||
|
@ -1867,6 +1856,9 @@ static int hid_device_probe(struct device *dev)
|
|||
}
|
||||
}
|
||||
unlock:
|
||||
if (!hdev->io_started)
|
||||
up(&hdev->driver_input_lock);
|
||||
unlock_driver_lock:
|
||||
up(&hdev->driver_lock);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1875,9 +1867,15 @@ static int hid_device_remove(struct device *dev)
|
|||
{
|
||||
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
|
||||
struct hid_driver *hdrv;
|
||||
int ret = 0;
|
||||
|
||||
if (down_interruptible(&hdev->driver_lock))
|
||||
return -EINTR;
|
||||
if (down_interruptible(&hdev->driver_input_lock)) {
|
||||
ret = -EINTR;
|
||||
goto unlock_driver_lock;
|
||||
}
|
||||
hdev->io_started = false;
|
||||
|
||||
hdrv = hdev->driver;
|
||||
if (hdrv) {
|
||||
|
@ -1889,8 +1887,11 @@ static int hid_device_remove(struct device *dev)
|
|||
hdev->driver = NULL;
|
||||
}
|
||||
|
||||
if (!hdev->io_started)
|
||||
up(&hdev->driver_input_lock);
|
||||
unlock_driver_lock:
|
||||
up(&hdev->driver_lock);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
|
||||
|
@ -2340,7 +2341,9 @@ struct hid_device *hid_allocate_device(void)
|
|||
|
||||
init_waitqueue_head(&hdev->debug_wait);
|
||||
INIT_LIST_HEAD(&hdev->debug_list);
|
||||
mutex_init(&hdev->debug_list_lock);
|
||||
sema_init(&hdev->driver_lock, 1);
|
||||
sema_init(&hdev->driver_input_lock, 1);
|
||||
|
||||
return hdev;
|
||||
}
|
||||
|
|
|
@ -580,17 +580,49 @@ void hid_debug_event(struct hid_device *hdev, char *buf)
|
|||
int i;
|
||||
struct hid_debug_list *list;
|
||||
|
||||
mutex_lock(&hdev->debug_list_lock);
|
||||
list_for_each_entry(list, &hdev->debug_list, node) {
|
||||
for (i = 0; i < strlen(buf); i++)
|
||||
list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
|
||||
buf[i];
|
||||
list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
|
||||
}
|
||||
mutex_unlock(&hdev->debug_list_lock);
|
||||
|
||||
wake_up_interruptible(&hdev->debug_wait);
|
||||
}
|
||||
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)
|
||||
{
|
||||
char *buf;
|
||||
|
@ -960,7 +992,9 @@ static int hid_debug_events_open(struct inode *inode, struct file *file)
|
|||
file->private_data = list;
|
||||
mutex_init(&list->read_mutex);
|
||||
|
||||
mutex_lock(&list->hdev->debug_list_lock);
|
||||
list_add_tail(&list->node, &list->hdev->debug_list);
|
||||
mutex_unlock(&list->hdev->debug_list_lock);
|
||||
|
||||
out:
|
||||
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;
|
||||
|
||||
mutex_lock(&list->hdev->debug_list_lock);
|
||||
list_del(&list->node);
|
||||
mutex_unlock(&list->hdev->debug_list_lock);
|
||||
kfree(list->hid_debug_buf);
|
||||
kfree(list);
|
||||
|
||||
|
|
|
@ -29,14 +29,12 @@
|
|||
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
#ifdef CONFIG_DRAGONRISE_FF
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
struct drff_device {
|
||||
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[2] = weak;
|
||||
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[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[4] = 0x00;
|
||||
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;
|
||||
}
|
||||
|
@ -132,7 +130,7 @@ static int drff_init(struct hid_device *hid)
|
|||
drff->report->field[0]->value[4] = 0x00;
|
||||
drff->report->field[0]->value[5] = 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. "
|
||||
"game controllers by Richard Walmsley <richwalm@gmail.com>\n");
|
||||
|
|
|
@ -23,11 +23,9 @@
|
|||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
struct emsff_device {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -104,7 +102,7 @@ static int emsff_init(struct hid_device *hid)
|
|||
emsff->report->field[0]->value[4] = 0x00;
|
||||
emsff->report->field[0]->value[5] = 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");
|
||||
|
||||
|
|
|
@ -29,13 +29,11 @@
|
|||
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include "hid-ids.h"
|
||||
|
||||
#ifdef CONFIG_GREENASIA_FF
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
struct gaff_device {
|
||||
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[5] = 0;
|
||||
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[1] = 0xfe;
|
||||
gaff->report->field[0]->value[2] = 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;
|
||||
}
|
||||
|
@ -122,12 +120,12 @@ static int gaff_init(struct hid_device *hid)
|
|||
gaff->report->field[0]->value[1] = 0x00;
|
||||
gaff->report->field[0]->value[2] = 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[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");
|
||||
|
||||
|
|
|
@ -27,12 +27,10 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
#ifdef CONFIG_HOLTEK_FF
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
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);
|
||||
|
||||
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,
|
||||
|
|
|
@ -159,7 +159,7 @@ static const struct icade_key icade_usage_table[30] = {
|
|||
|
||||
static const struct icade_key *icade_find_translation(u16 from)
|
||||
{
|
||||
if (from < 0 || from > ICADE_MAX_USAGE)
|
||||
if (from > ICADE_MAX_USAGE)
|
||||
return NULL;
|
||||
return &icade_usage_table[from];
|
||||
}
|
||||
|
|
|
@ -137,8 +137,11 @@
|
|||
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256
|
||||
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
|
||||
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
|
||||
#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241
|
||||
#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240
|
||||
#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440
|
||||
#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
|
||||
#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
|
||||
#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243
|
||||
|
||||
#define USB_VENDOR_ID_ASUS 0x0486
|
||||
#define USB_DEVICE_ID_ASUS_T91MT 0x0185
|
||||
|
@ -577,6 +580,7 @@
|
|||
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
|
||||
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
|
||||
#define USB_DEVICE_ID_MS_NE4K 0x00db
|
||||
#define USB_DEVICE_ID_MS_NE4K_JP 0x00dc
|
||||
#define USB_DEVICE_ID_MS_LK6K 0x00f9
|
||||
#define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701
|
||||
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
|
||||
|
@ -613,6 +617,7 @@
|
|||
|
||||
#define USB_VENDOR_ID_NINTENDO 0x057e
|
||||
#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306
|
||||
#define USB_DEVICE_ID_NINTENDO_WIIMOTE2 0x0330
|
||||
|
||||
#define USB_VENDOR_ID_NOVATEK 0x0603
|
||||
#define USB_DEVICE_ID_NOVATEK_PCT 0x0600
|
||||
|
@ -692,8 +697,10 @@
|
|||
#define USB_VENDOR_ID_ROCCAT 0x1e7d
|
||||
#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
|
||||
#define USB_DEVICE_ID_ROCCAT_ISKU 0x319c
|
||||
#define USB_DEVICE_ID_ROCCAT_ISKUFX 0x3264
|
||||
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
|
||||
#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
|
||||
#define USB_DEVICE_ID_ROCCAT_KONEPURE 0x2dbe
|
||||
#define USB_DEVICE_ID_ROCCAT_KONEXTD 0x2e22
|
||||
#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
|
||||
#define USB_DEVICE_ID_ROCCAT_LUA 0x2c2e
|
||||
|
|
|
@ -1198,6 +1198,67 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
|
|||
return hidinput;
|
||||
}
|
||||
|
||||
static bool hidinput_has_been_populated(struct hid_input *hidinput)
|
||||
{
|
||||
int i;
|
||||
unsigned long r = 0;
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(EV_CNT); i++)
|
||||
r |= hidinput->input->evbit[i];
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(KEY_CNT); i++)
|
||||
r |= hidinput->input->keybit[i];
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++)
|
||||
r |= hidinput->input->relbit[i];
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++)
|
||||
r |= hidinput->input->absbit[i];
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++)
|
||||
r |= hidinput->input->mscbit[i];
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(LED_CNT); i++)
|
||||
r |= hidinput->input->ledbit[i];
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(SND_CNT); i++)
|
||||
r |= hidinput->input->sndbit[i];
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(FF_CNT); i++)
|
||||
r |= hidinput->input->ffbit[i];
|
||||
|
||||
for (i = 0; i < BITS_TO_LONGS(SW_CNT); i++)
|
||||
r |= hidinput->input->swbit[i];
|
||||
|
||||
return !!r;
|
||||
}
|
||||
|
||||
static void hidinput_cleanup_hidinput(struct hid_device *hid,
|
||||
struct hid_input *hidinput)
|
||||
{
|
||||
struct hid_report *report;
|
||||
int i, k;
|
||||
|
||||
list_del(&hidinput->list);
|
||||
input_free_device(hidinput->input);
|
||||
|
||||
for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
|
||||
if (k == HID_OUTPUT_REPORT &&
|
||||
hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
|
||||
continue;
|
||||
|
||||
list_for_each_entry(report, &hid->report_enum[k].report_list,
|
||||
list) {
|
||||
|
||||
for (i = 0; i < report->maxfield; i++)
|
||||
if (report->field[i]->hidinput == hidinput)
|
||||
report->field[i]->hidinput = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(hidinput);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the input device; print a message.
|
||||
* Configure the input layer interface
|
||||
|
@ -1249,6 +1310,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
|||
hidinput_configure_usage(hidinput, report->field[i],
|
||||
report->field[i]->usage + j);
|
||||
|
||||
if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
|
||||
!hidinput_has_been_populated(hidinput))
|
||||
continue;
|
||||
|
||||
if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
|
||||
/* This will leave hidinput NULL, so that it
|
||||
* allocates another one if we have more inputs on
|
||||
|
@ -1265,6 +1330,18 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
|||
}
|
||||
}
|
||||
|
||||
if (hidinput && (hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
|
||||
!hidinput_has_been_populated(hidinput)) {
|
||||
/* no need to register an input device not populated */
|
||||
hidinput_cleanup_hidinput(hid, hidinput);
|
||||
hidinput = NULL;
|
||||
}
|
||||
|
||||
if (list_empty(&hid->inputs)) {
|
||||
hid_err(hid, "No inputs registered, leaving\n");
|
||||
goto out_unwind;
|
||||
}
|
||||
|
||||
if (hidinput) {
|
||||
if (drv->input_configured)
|
||||
drv->input_configured(hid, hidinput);
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
|
@ -361,7 +359,7 @@ static int kye_tablet_enable(struct hid_device *hdev)
|
|||
value[4] = 0x00;
|
||||
value[5] = 0x00;
|
||||
value[6] = 0x00;
|
||||
usbhid_submit_report(hdev, report, USB_DIR_OUT);
|
||||
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ static int tpkbd_features_set(struct hid_device *hdev)
|
|||
report->field[2]->value[0] = data_pointer->sensitivity;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -228,8 +228,6 @@ static ssize_t pointer_press_speed_show(struct device *dev,
|
|||
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
|
||||
struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
|
||||
|
||||
data_pointer = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n",
|
||||
data_pointer->press_speed);
|
||||
}
|
||||
|
@ -332,7 +330,7 @@ static void tpkbd_led_brightness_set(struct led_classdev *led_cdev,
|
|||
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[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)
|
||||
|
|
|
@ -23,10 +23,8 @@
|
|||
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
#include "usbhid/usbhid.h"
|
||||
#include "hid-lg.h"
|
||||
|
||||
struct lg2ff_device {
|
||||
|
@ -56,7 +54,7 @@ static int play_effect(struct input_dev *dev, void *data,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -108,7 +106,7 @@ int lg2ff_init(struct hid_device *hid)
|
|||
report->field[0]->value[5] = 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");
|
||||
|
||||
|
|
|
@ -22,10 +22,8 @@
|
|||
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
#include "usbhid/usbhid.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[31] = (unsigned char)(-y);
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
|
||||
break;
|
||||
}
|
||||
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[34] = 0x7F;
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#define DFGT_REV_MAJ 0x13
|
||||
#define DFGT_REV_MIN 0x22
|
||||
#define DFGT2_REV_MIN 0x26
|
||||
#define DFP_REV_MAJ 0x11
|
||||
#define DFP_REV_MIN 0x06
|
||||
#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[] = {
|
||||
{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 */
|
||||
{G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */
|
||||
{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[6] = 0x00;
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
@ -225,7 +227,7 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud
|
|||
value[5] = 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 */
|
||||
|
@ -245,7 +247,7 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
|
|||
value[5] = 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 */
|
||||
|
@ -265,7 +267,7 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range)
|
|||
value[5] = 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 */
|
||||
|
@ -294,7 +296,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
|
|||
report->field[0]->value[1] = 0x02;
|
||||
full_range = 200;
|
||||
}
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
|
||||
|
||||
/* Prepare "fine" limit command */
|
||||
value[0] = 0x81;
|
||||
|
@ -306,7 +308,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
|
|||
value[6] = 0x00;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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[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)
|
||||
|
@ -334,7 +336,7 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
|
|||
for (i = 0; i < 7; i++)
|
||||
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[5] = 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,
|
||||
|
|
|
@ -30,10 +30,8 @@
|
|||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
#include "usbhid/usbhid.h"
|
||||
#include "hid-lg.h"
|
||||
|
||||
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[3] = 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;
|
||||
|
||||
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[3] = 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;
|
||||
}
|
||||
return 0;
|
||||
|
@ -124,7 +122,7 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
|
|||
*value++ = 0x80;
|
||||
*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)
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "usbhid/usbhid.h"
|
||||
#include "hid-ids.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,
|
||||
size_t count,
|
||||
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,
|
||||
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] &
|
||||
SPFUNCTION_DEVICE_LIST_EMPTY) {
|
||||
dbg_hid("%s: device list is empty\n", __func__);
|
||||
djrcv_dev->querying_devices = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -245,12 +242,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
|||
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();
|
||||
if (IS_ERR(dj_hiddev)) {
|
||||
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;
|
||||
unsigned long flags;
|
||||
int count;
|
||||
int retval;
|
||||
|
||||
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);
|
||||
break;
|
||||
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__);
|
||||
}
|
||||
}
|
||||
|
@ -396,12 +367,6 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
|
|||
if (!djdev) {
|
||||
dbg_hid("djrcv_dev->paired_dj_devices[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;
|
||||
}
|
||||
|
||||
|
@ -432,12 +397,6 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
|
|||
if (dj_device == NULL) {
|
||||
dbg_hid("djrcv_dev->paired_dj_devices[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;
|
||||
}
|
||||
|
||||
|
@ -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++)
|
||||
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;
|
||||
}
|
||||
|
@ -485,10 +444,6 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
|
|||
struct dj_report *dj_report;
|
||||
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);
|
||||
if (!dj_report)
|
||||
return -ENOMEM;
|
||||
|
@ -500,7 +455,6 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
|
|||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
|
||||
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], 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;
|
||||
|
||||
|
@ -809,6 +763,9 @@ static int logi_dj_probe(struct hid_device *hdev,
|
|||
goto llopen_failed;
|
||||
}
|
||||
|
||||
/* Allow incoming packets to arrive: */
|
||||
hid_device_io_start(hdev);
|
||||
|
||||
retval = logi_dj_recv_query_paired_devices(djrcv_dev);
|
||||
if (retval < 0) {
|
||||
dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices "
|
||||
|
|
|
@ -101,7 +101,6 @@ struct dj_receiver_dev {
|
|||
struct work_struct work;
|
||||
struct kfifo notif_fifo;
|
||||
spinlock_t lock;
|
||||
bool querying_devices;
|
||||
};
|
||||
|
||||
struct dj_device {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <linux/input/mt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
|
|
|
@ -195,6 +195,8 @@ static const struct hid_device_id ms_devices[] = {
|
|||
.driver_data = MS_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K),
|
||||
.driver_data = MS_ERGONOMY },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
|
||||
.driver_data = MS_ERGONOMY },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
|
||||
.driver_data = MS_ERGONOMY | MS_RDESC },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
* HID driver for multitouch panels
|
||||
*
|
||||
* 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) 2012-2013 Red Hat, Inc
|
||||
*
|
||||
* This code is partly based on hid-egalax.c:
|
||||
*
|
||||
|
@ -26,13 +27,24 @@
|
|||
* 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/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/string.h>
|
||||
|
||||
|
||||
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
|
||||
|
@ -86,9 +98,9 @@ struct mt_device {
|
|||
multitouch fields */
|
||||
int cc_index; /* contact count field index in the report */
|
||||
int cc_value_index; /* contact count value index in the field */
|
||||
unsigned last_field_index; /* last field index of the report */
|
||||
unsigned last_slot_field; /* the last field of a slot */
|
||||
unsigned mt_report_id; /* the report ID of the multitouch device */
|
||||
unsigned pen_report_id; /* the report ID of the pen device */
|
||||
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */
|
||||
__s8 inputmode_index; /* InputMode HID feature index in the report */
|
||||
__s8 maxcontact_report_id; /* Maximum Contact Number HID feature,
|
||||
|
@ -104,6 +116,9 @@ struct mt_device {
|
|||
unsigned mt_flags; /* flags to pass to input-mt */
|
||||
};
|
||||
|
||||
static void mt_post_parse_default_settings(struct mt_device *td);
|
||||
static void mt_post_parse(struct mt_device *td);
|
||||
|
||||
/* classes of device behavior */
|
||||
#define MT_CLS_DEFAULT 0x0001
|
||||
|
||||
|
@ -246,6 +261,14 @@ static struct mt_class mt_classes[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static void mt_free_input_name(struct hid_input *hi)
|
||||
{
|
||||
struct hid_device *hdev = hi->report->device;
|
||||
|
||||
if (hi->input->name != hdev->name)
|
||||
kfree(hi->input->name);
|
||||
}
|
||||
|
||||
static ssize_t mt_show_quirks(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
@ -354,7 +377,53 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
|
|||
f->usages[f->length++] = usage->hid;
|
||||
}
|
||||
|
||||
static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
static int mt_pen_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
|
||||
td->pen_report_id = field->report->id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt_pen_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt_pen_event(struct hid_device *hid, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
/* let hid-input handle it */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mt_pen_report(struct hid_device *hid, struct hid_report *report)
|
||||
{
|
||||
struct hid_field *field = report->field[0];
|
||||
|
||||
input_sync(field->hidinput->input);
|
||||
}
|
||||
|
||||
static void mt_pen_input_configured(struct hid_device *hdev,
|
||||
struct hid_input *hi)
|
||||
{
|
||||
char *name = kzalloc(strlen(hi->input->name) + 5, GFP_KERNEL);
|
||||
if (name) {
|
||||
sprintf(name, "%s Pen", hi->input->name);
|
||||
mt_free_input_name(hi);
|
||||
hi->input->name = name;
|
||||
}
|
||||
|
||||
/* force BTN_STYLUS to allow tablet matching in udev */
|
||||
__set_bit(BTN_STYLUS, hi->input->keybit);
|
||||
}
|
||||
|
||||
static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
|
@ -363,13 +432,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
int code;
|
||||
struct hid_usage *prev_usage = NULL;
|
||||
|
||||
/* Only map fields from TouchScreen or TouchPad collections.
|
||||
* We need to ignore fields that belong to other collections
|
||||
* such as Mouse that might have the same GenericDesktop usages. */
|
||||
if (field->application == HID_DG_TOUCHSCREEN)
|
||||
td->mt_flags |= INPUT_MT_DIRECT;
|
||||
else if (field->application != HID_DG_TOUCHPAD)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Model touchscreens providing buttons as touchpads.
|
||||
|
@ -378,12 +442,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
(usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
|
||||
td->mt_flags |= INPUT_MT_POINTER;
|
||||
|
||||
/* eGalax devices provide a Digitizer.Stylus input which overrides
|
||||
* the correct Digitizers.Finger X/Y ranges.
|
||||
* Let's just ignore this input. */
|
||||
if (field->physical == HID_DG_STYLUS)
|
||||
return -1;
|
||||
|
||||
if (usage->usage_index)
|
||||
prev_usage = &field->usage[usage->usage_index - 1];
|
||||
|
||||
|
@ -405,7 +463,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
}
|
||||
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
case HID_GD_Y:
|
||||
if (prev_usage && (prev_usage->hid == usage->hid)) {
|
||||
|
@ -421,7 +478,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
}
|
||||
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -436,21 +492,17 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
ABS_MT_DISTANCE, 0, 1, 0, 0);
|
||||
}
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
case HID_DG_CONFIDENCE:
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
case HID_DG_TIPSWITCH:
|
||||
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
|
||||
input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
case HID_DG_CONTACTID:
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
td->touches_by_report++;
|
||||
td->mt_report_id = field->report->id;
|
||||
return 1;
|
||||
|
@ -461,7 +513,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
|
||||
cls->sn_width);
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
case HID_DG_HEIGHT:
|
||||
hid_map_usage(hi, usage, bit, max,
|
||||
|
@ -473,7 +524,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
ABS_MT_ORIENTATION, 0, 1, 0, 0);
|
||||
}
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
case HID_DG_TIPPRESSURE:
|
||||
hid_map_usage(hi, usage, bit, max,
|
||||
|
@ -481,17 +531,14 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
set_abs(hi->input, ABS_MT_PRESSURE, field,
|
||||
cls->sn_pressure);
|
||||
mt_store_field(usage, td, hi);
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
case HID_DG_CONTACTCOUNT:
|
||||
td->cc_index = field->index;
|
||||
td->cc_value_index = usage->usage_index;
|
||||
td->last_field_index = field->index;
|
||||
return 1;
|
||||
case HID_DG_CONTACTMAX:
|
||||
/* we don't set td->last_slot_field as contactcount and
|
||||
* contact max are global to the report */
|
||||
td->last_field_index = field->index;
|
||||
return -1;
|
||||
case HID_DG_TOUCH:
|
||||
/* Legacy devices use TIPSWITCH and not TOUCH.
|
||||
|
@ -515,7 +562,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
||||
static int mt_touch_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
|
@ -606,7 +653,7 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
|
|||
td->num_received = 0;
|
||||
}
|
||||
|
||||
static int mt_event(struct hid_device *hid, struct hid_field *field,
|
||||
static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
/* we will handle the hidinput part later, now remains hiddev */
|
||||
|
@ -680,29 +727,19 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
|
|||
if (usage->usage_index + 1 == field->report_count) {
|
||||
/* we only take into account the last report. */
|
||||
if (usage->hid == td->last_slot_field)
|
||||
mt_complete_slot(td, input);
|
||||
|
||||
if (field->index == td->last_field_index
|
||||
&& td->num_received >= td->num_expected)
|
||||
mt_sync_frame(td, field->hidinput->input);
|
||||
mt_complete_slot(td, field->hidinput->input);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void mt_report(struct hid_device *hid, struct hid_report *report)
|
||||
static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hid);
|
||||
struct hid_field *field;
|
||||
unsigned count;
|
||||
int r, n;
|
||||
|
||||
if (report->id != td->mt_report_id)
|
||||
return;
|
||||
|
||||
if (!(hid->claimed & HID_CLAIMED_INPUT))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Includes multi-packet support where subsequent
|
||||
* packets are sent with zero contactcount.
|
||||
|
@ -725,6 +762,91 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
|
|||
mt_process_mt_event(hid, field, &field->usage[n],
|
||||
field->value[n]);
|
||||
}
|
||||
|
||||
if (td->num_received >= td->num_expected)
|
||||
mt_sync_frame(td, report->field[0]->hidinput->input);
|
||||
}
|
||||
|
||||
static void mt_touch_input_configured(struct hid_device *hdev,
|
||||
struct hid_input *hi)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
struct mt_class *cls = &td->mtclass;
|
||||
struct input_dev *input = hi->input;
|
||||
|
||||
if (!td->maxcontacts)
|
||||
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
|
||||
|
||||
mt_post_parse(td);
|
||||
if (td->serial_maybe)
|
||||
mt_post_parse_default_settings(td);
|
||||
|
||||
if (cls->is_indirect)
|
||||
td->mt_flags |= INPUT_MT_POINTER;
|
||||
|
||||
if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
|
||||
td->mt_flags |= INPUT_MT_DROP_UNUSED;
|
||||
|
||||
input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
|
||||
|
||||
td->mt_flags = 0;
|
||||
}
|
||||
|
||||
static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
/* Only map fields from TouchScreen or TouchPad collections.
|
||||
* We need to ignore fields that belong to other collections
|
||||
* such as Mouse that might have the same GenericDesktop usages. */
|
||||
if (field->application != HID_DG_TOUCHSCREEN &&
|
||||
field->application != HID_DG_PEN &&
|
||||
field->application != HID_DG_TOUCHPAD)
|
||||
return -1;
|
||||
|
||||
if (field->physical == HID_DG_STYLUS)
|
||||
return mt_pen_input_mapping(hdev, hi, field, usage, bit, max);
|
||||
|
||||
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
|
||||
}
|
||||
|
||||
static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
if (field->physical == HID_DG_STYLUS)
|
||||
return mt_pen_input_mapped(hdev, hi, field, usage, bit, max);
|
||||
|
||||
return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
|
||||
}
|
||||
|
||||
static int mt_event(struct hid_device *hid, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hid);
|
||||
|
||||
if (field->report->id == td->mt_report_id)
|
||||
return mt_touch_event(hid, field, usage, value);
|
||||
|
||||
if (field->report->id == td->pen_report_id)
|
||||
return mt_pen_event(hid, field, usage, value);
|
||||
|
||||
/* ignore other reports */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void mt_report(struct hid_device *hid, struct hid_report *report)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hid);
|
||||
|
||||
if (!(hid->claimed & HID_CLAIMED_INPUT))
|
||||
return;
|
||||
|
||||
if (report->id == td->mt_report_id)
|
||||
mt_touch_report(hid, report);
|
||||
|
||||
if (report->id == td->pen_report_id)
|
||||
mt_pen_report(hid, report);
|
||||
}
|
||||
|
||||
static void mt_set_input_mode(struct hid_device *hdev)
|
||||
|
@ -740,7 +862,7 @@ static void mt_set_input_mode(struct hid_device *hdev)
|
|||
r = re->report_id_hash[td->inputmode];
|
||||
if (r) {
|
||||
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 +887,7 @@ static void mt_set_maxcontacts(struct hid_device *hdev)
|
|||
max = min(fieldmax, max);
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -801,32 +923,18 @@ static void mt_post_parse(struct mt_device *td)
|
|||
}
|
||||
|
||||
static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
struct mt_class *cls = &td->mtclass;
|
||||
struct input_dev *input = hi->input;
|
||||
char *name = kstrdup(hdev->name, GFP_KERNEL);
|
||||
|
||||
/* Only initialize slots for MT input devices */
|
||||
if (!test_bit(ABS_MT_POSITION_X, input->absbit))
|
||||
return;
|
||||
if (name)
|
||||
hi->input->name = name;
|
||||
|
||||
if (!td->maxcontacts)
|
||||
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
|
||||
if (hi->report->id == td->mt_report_id)
|
||||
mt_touch_input_configured(hdev, hi);
|
||||
|
||||
mt_post_parse(td);
|
||||
if (td->serial_maybe)
|
||||
mt_post_parse_default_settings(td);
|
||||
|
||||
if (cls->is_indirect)
|
||||
td->mt_flags |= INPUT_MT_POINTER;
|
||||
|
||||
if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
|
||||
td->mt_flags |= INPUT_MT_DROP_UNUSED;
|
||||
|
||||
input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
|
||||
|
||||
td->mt_flags = 0;
|
||||
if (hi->report->id == td->pen_report_id)
|
||||
mt_pen_input_configured(hdev, hi);
|
||||
}
|
||||
|
||||
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
|
@ -834,6 +942,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
int ret, i;
|
||||
struct mt_device *td;
|
||||
struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
|
||||
struct hid_input *hi;
|
||||
|
||||
for (i = 0; mt_classes[i].name ; i++) {
|
||||
if (id->driver_data == mt_classes[i].name) {
|
||||
|
@ -847,6 +956,14 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
*/
|
||||
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
|
||||
|
||||
/*
|
||||
* This allows the driver to handle different input sensors
|
||||
* that emits events through different reports on the same HID
|
||||
* device.
|
||||
*/
|
||||
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
|
||||
hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
|
||||
|
||||
td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
|
||||
if (!td) {
|
||||
dev_err(&hdev->dev, "cannot allocate multitouch data\n");
|
||||
|
@ -856,6 +973,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
td->inputmode = -1;
|
||||
td->maxcontact_report_id = -1;
|
||||
td->cc_index = -1;
|
||||
td->mt_report_id = -1;
|
||||
td->pen_report_id = -1;
|
||||
hid_set_drvdata(hdev, td);
|
||||
|
||||
td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
|
||||
|
@ -874,7 +993,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
|
||||
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
||||
if (ret)
|
||||
goto fail;
|
||||
goto hid_fail;
|
||||
|
||||
ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
|
||||
|
||||
|
@ -886,6 +1005,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
|
||||
return 0;
|
||||
|
||||
hid_fail:
|
||||
list_for_each_entry(hi, &hdev->inputs, list)
|
||||
mt_free_input_name(hi);
|
||||
fail:
|
||||
kfree(td->fields);
|
||||
kfree(td);
|
||||
|
@ -902,26 +1024,11 @@ static int mt_reset_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.
|
||||
* It should be safe to send it to other devices too.
|
||||
* Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
|
||||
|
||||
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
HID_REQ_SET_IDLE,
|
||||
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
0, interface->desc.bInterfaceNumber,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -930,8 +1037,14 @@ static int mt_resume(struct hid_device *hdev)
|
|||
static void mt_remove(struct hid_device *hdev)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
struct hid_input *hi;
|
||||
|
||||
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
|
||||
hid_hw_stop(hdev);
|
||||
|
||||
list_for_each_entry(hi, &hdev->inputs, list)
|
||||
mt_free_input_name(hi);
|
||||
|
||||
kfree(td);
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
}
|
||||
|
|
|
@ -118,8 +118,8 @@ static inline int ntrig_get_mode(struct hid_device *hdev)
|
|||
if (!report)
|
||||
return -EINVAL;
|
||||
|
||||
usbhid_submit_report(hdev, report, USB_DIR_IN);
|
||||
usbhid_wait_io(hdev);
|
||||
hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
|
||||
hid_hw_wait(hdev);
|
||||
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)
|
||||
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)
|
||||
|
@ -937,8 +937,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
if (report) {
|
||||
/* Let the device settle to ensure the wakeup message gets
|
||||
* through */
|
||||
usbhid_wait_io(hdev);
|
||||
usbhid_submit_report(hdev, report, USB_DIR_IN);
|
||||
hid_hw_wait(hdev);
|
||||
hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
|
||||
|
||||
/*
|
||||
* Sanity check: if the current mode is invalid reset it to
|
||||
|
|
|
@ -142,10 +142,10 @@ struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir);
|
|||
#ifdef CONFIG_DEBUG_FS
|
||||
void picolcd_debug_out_report(struct picolcd_data *data,
|
||||
struct hid_device *hdev, struct hid_report *report);
|
||||
#define usbhid_submit_report(a, b, c) \
|
||||
#define hid_hw_request(a, b, c) \
|
||||
do { \
|
||||
picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
|
||||
usbhid_submit_report(a, b, c); \
|
||||
hid_hw_request(a, b, c); \
|
||||
} while (0)
|
||||
|
||||
void picolcd_debug_raw_event(struct picolcd_data *data,
|
||||
|
@ -302,7 +302,7 @@ static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report
|
|||
static inline void picolcd_exit_cir(struct picolcd_data *data)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_HID_PICOLCD_LIRC */
|
||||
#endif /* CONFIG_HID_PICOLCD_CIR */
|
||||
|
||||
int picolcd_reset(struct hid_device *hdev);
|
||||
struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
***************************************************************************/
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/backlight.h>
|
||||
|
@ -46,7 +44,7 @@ static int picolcd_set_brightness(struct backlight_device *bdev)
|
|||
spin_lock_irqsave(&data->lock, flags);
|
||||
hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include <linux/hid-debug.h>
|
||||
#include <linux/input.h>
|
||||
#include "hid-ids.h"
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include <linux/hid-debug.h>
|
||||
#include <linux/input.h>
|
||||
#include "hid-ids.h"
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
@ -110,7 +108,7 @@ struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
|
|||
work = NULL;
|
||||
} else {
|
||||
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);
|
||||
wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
@ -244,7 +242,7 @@ int picolcd_reset(struct hid_device *hdev)
|
|||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
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);
|
||||
|
||||
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);
|
||||
hid_set_field(report->field[0], 0, timeout & 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);
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/hid-debug.h>
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -143,8 +141,8 @@ static int picolcd_fb_send_tile(struct picolcd_data *data, u8 *vbitmap,
|
|||
else
|
||||
hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
|
||||
|
||||
usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
|
||||
usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
|
||||
hid_hw_request(data->hdev, report1, HID_REQ_SET_REPORT);
|
||||
hid_hw_request(data->hdev, report2, HID_REQ_SET_REPORT);
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
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]);
|
||||
else
|
||||
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);
|
||||
|
||||
|
@ -270,7 +268,7 @@ static void picolcd_fb_update(struct fb_info *info)
|
|||
mutex_unlock(&info->lock);
|
||||
if (!data)
|
||||
return;
|
||||
usbhid_wait_io(data->hdev);
|
||||
hid_hw_wait(data->hdev);
|
||||
mutex_lock(&info->lock);
|
||||
n = 0;
|
||||
}
|
||||
|
@ -288,7 +286,7 @@ static void picolcd_fb_update(struct fb_info *info)
|
|||
spin_unlock_irqrestore(&fbdata->lock, flags);
|
||||
mutex_unlock(&info->lock);
|
||||
if (data)
|
||||
usbhid_wait_io(data->hdev);
|
||||
hid_hw_wait(data->hdev);
|
||||
return;
|
||||
}
|
||||
out:
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
***************************************************************************/
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.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);
|
||||
hid_set_field(report->field[0], 0, data->lcd_contrast);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include <linux/hid-debug.h>
|
||||
#include <linux/input.h>
|
||||
#include "hid-ids.h"
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
@ -55,7 +53,7 @@ void picolcd_leds_set(struct picolcd_data *data)
|
|||
spin_lock_irqsave(&data->lock, flags);
|
||||
hid_set_field(report->field[0], 0, data->led_state);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,13 +43,11 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
#ifdef CONFIG_PANTHERLORD_FF
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
struct plff_device {
|
||||
struct hid_report *report;
|
||||
|
@ -75,7 +73,7 @@ static int hid_plff_play(struct input_dev *dev, void *data,
|
|||
*plff->strong = left;
|
||||
*plff->weak = 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;
|
||||
}
|
||||
|
@ -169,7 +167,7 @@ static int plff_init(struct hid_device *hid)
|
|||
|
||||
*strong = 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");
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/rawmidi.h>
|
||||
#include "usbhid/usbhid.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[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)
|
||||
|
|
|
@ -130,14 +130,14 @@ static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj,
|
|||
if (off >= real_size)
|
||||
return 0;
|
||||
|
||||
if (off != 0 || count != real_size)
|
||||
if (off != 0 || count > real_size)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&isku->isku_lock);
|
||||
retval = isku_receive(usb_dev, command, buf, real_size);
|
||||
retval = isku_receive(usb_dev, command, buf, count);
|
||||
mutex_unlock(&isku->isku_lock);
|
||||
|
||||
return retval ? retval : real_size;
|
||||
return retval ? retval : count;
|
||||
}
|
||||
|
||||
static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
|
||||
|
@ -150,15 +150,15 @@ static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
|
|||
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
|
||||
int retval;
|
||||
|
||||
if (off != 0 || count != real_size)
|
||||
if (off != 0 || count > real_size)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&isku->isku_lock);
|
||||
retval = roccat_common2_send_with_status(usb_dev, command,
|
||||
(void *)buf, real_size);
|
||||
(void *)buf, count);
|
||||
mutex_unlock(&isku->isku_lock);
|
||||
|
||||
return retval ? retval : real_size;
|
||||
return retval ? retval : count;
|
||||
}
|
||||
|
||||
#define ISKU_SYSFS_W(thingy, THINGY) \
|
||||
|
@ -216,6 +216,7 @@ ISKU_SYSFS_RW(light, LIGHT)
|
|||
ISKU_SYSFS_RW(key_mask, KEY_MASK)
|
||||
ISKU_SYSFS_RW(last_set, LAST_SET)
|
||||
ISKU_SYSFS_W(talk, TALK)
|
||||
ISKU_SYSFS_W(talkfx, TALKFX)
|
||||
ISKU_SYSFS_R(info, INFO)
|
||||
ISKU_SYSFS_W(control, CONTROL)
|
||||
ISKU_SYSFS_W(reset, RESET)
|
||||
|
@ -232,6 +233,7 @@ static struct bin_attribute isku_bin_attributes[] = {
|
|||
ISKU_BIN_ATTR_RW(key_mask, KEY_MASK),
|
||||
ISKU_BIN_ATTR_RW(last_set, LAST_SET),
|
||||
ISKU_BIN_ATTR_W(talk, TALK),
|
||||
ISKU_BIN_ATTR_W(talkfx, TALKFX),
|
||||
ISKU_BIN_ATTR_R(info, INFO),
|
||||
ISKU_BIN_ATTR_W(control, CONTROL),
|
||||
ISKU_BIN_ATTR_W(reset, RESET),
|
||||
|
@ -405,6 +407,7 @@ static int isku_raw_event(struct hid_device *hdev,
|
|||
|
||||
static const struct hid_device_id isku_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKUFX) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -443,5 +446,5 @@ module_init(isku_init);
|
|||
module_exit(isku_exit);
|
||||
|
||||
MODULE_AUTHOR("Stefan Achatz");
|
||||
MODULE_DESCRIPTION("USB Roccat Isku driver");
|
||||
MODULE_DESCRIPTION("USB Roccat Isku/FX driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -25,10 +25,11 @@ enum {
|
|||
ISKU_SIZE_KEYS_MACRO = 0x23,
|
||||
ISKU_SIZE_KEYS_CAPSLOCK = 0x06,
|
||||
ISKU_SIZE_LAST_SET = 0x14,
|
||||
ISKU_SIZE_LIGHT = 0x0a,
|
||||
ISKU_SIZE_LIGHT = 0x10,
|
||||
ISKU_SIZE_MACRO = 0x823,
|
||||
ISKU_SIZE_RESET = 0x03,
|
||||
ISKU_SIZE_TALK = 0x10,
|
||||
ISKU_SIZE_TALKFX = 0x10,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -59,6 +60,7 @@ enum isku_commands {
|
|||
ISKU_COMMAND_LAST_SET = 0x14,
|
||||
ISKU_COMMAND_15 = 0x15,
|
||||
ISKU_COMMAND_TALK = 0x16,
|
||||
ISKU_COMMAND_TALKFX = 0x17,
|
||||
ISKU_COMMAND_FIRMWARE_WRITE = 0x1b,
|
||||
ISKU_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
|
||||
};
|
||||
|
|
|
@ -818,8 +818,9 @@ static void kone_report_to_chrdev(struct kone_device const *kone,
|
|||
(uint8_t *)&roccat_report);
|
||||
break;
|
||||
case kone_mouse_event_call_overlong_macro:
|
||||
case kone_mouse_event_multimedia:
|
||||
if (event->value == kone_keystroke_action_press) {
|
||||
roccat_report.event = kone_mouse_event_call_overlong_macro;
|
||||
roccat_report.event = event->event;
|
||||
roccat_report.value = kone->actual_profile;
|
||||
roccat_report.key = event->macro_key;
|
||||
roccat_report_event(kone->chrdev_minor,
|
||||
|
|
|
@ -169,6 +169,7 @@ enum kone_mouse_events {
|
|||
/* TODO clarify meaning and occurence of kone_mouse_event_calibration */
|
||||
kone_mouse_event_calibration = 0xc0,
|
||||
kone_mouse_event_call_overlong_macro = 0xe0,
|
||||
kone_mouse_event_multimedia = 0xe1,
|
||||
/* switch events notify if user changed values with mousebutton click */
|
||||
kone_mouse_event_switch_dpi = 0xf0,
|
||||
kone_mouse_event_switch_profile = 0xf1
|
||||
|
|
304
drivers/hid/hid-roccat-konepure.c
Normal file
304
drivers/hid/hid-roccat-konepure.c
Normal file
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
* Roccat KonePure driver for Linux
|
||||
*
|
||||
* Copyright (c) 2012 Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Roccat KonePure is a smaller version of KoneXTD with less buttons and lights.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/hid-roccat.h>
|
||||
#include "hid-ids.h"
|
||||
#include "hid-roccat-common.h"
|
||||
#include "hid-roccat-konepure.h"
|
||||
|
||||
static struct class *konepure_class;
|
||||
|
||||
static ssize_t konepure_sysfs_read(struct file *fp, struct kobject *kobj,
|
||||
char *buf, loff_t off, size_t count,
|
||||
size_t real_size, uint command)
|
||||
{
|
||||
struct device *dev =
|
||||
container_of(kobj, struct device, kobj)->parent->parent;
|
||||
struct konepure_device *konepure = hid_get_drvdata(dev_get_drvdata(dev));
|
||||
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
|
||||
int retval;
|
||||
|
||||
if (off >= real_size)
|
||||
return 0;
|
||||
|
||||
if (off != 0 || count != real_size)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&konepure->konepure_lock);
|
||||
retval = roccat_common2_receive(usb_dev, command, buf, real_size);
|
||||
mutex_unlock(&konepure->konepure_lock);
|
||||
|
||||
return retval ? retval : real_size;
|
||||
}
|
||||
|
||||
static ssize_t konepure_sysfs_write(struct file *fp, struct kobject *kobj,
|
||||
void const *buf, loff_t off, size_t count,
|
||||
size_t real_size, uint command)
|
||||
{
|
||||
struct device *dev =
|
||||
container_of(kobj, struct device, kobj)->parent->parent;
|
||||
struct konepure_device *konepure = hid_get_drvdata(dev_get_drvdata(dev));
|
||||
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
|
||||
int retval;
|
||||
|
||||
if (off != 0 || count != real_size)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&konepure->konepure_lock);
|
||||
retval = roccat_common2_send_with_status(usb_dev, command,
|
||||
(void *)buf, real_size);
|
||||
mutex_unlock(&konepure->konepure_lock);
|
||||
|
||||
return retval ? retval : real_size;
|
||||
}
|
||||
|
||||
#define KONEPURE_SYSFS_W(thingy, THINGY) \
|
||||
static ssize_t konepure_sysfs_write_ ## thingy(struct file *fp, \
|
||||
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
|
||||
loff_t off, size_t count) \
|
||||
{ \
|
||||
return konepure_sysfs_write(fp, kobj, buf, off, count, \
|
||||
KONEPURE_SIZE_ ## THINGY, KONEPURE_COMMAND_ ## THINGY); \
|
||||
}
|
||||
|
||||
#define KONEPURE_SYSFS_R(thingy, THINGY) \
|
||||
static ssize_t konepure_sysfs_read_ ## thingy(struct file *fp, \
|
||||
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
|
||||
loff_t off, size_t count) \
|
||||
{ \
|
||||
return konepure_sysfs_read(fp, kobj, buf, off, count, \
|
||||
KONEPURE_SIZE_ ## THINGY, KONEPURE_COMMAND_ ## THINGY); \
|
||||
}
|
||||
|
||||
#define KONEPURE_SYSFS_RW(thingy, THINGY) \
|
||||
KONEPURE_SYSFS_W(thingy, THINGY) \
|
||||
KONEPURE_SYSFS_R(thingy, THINGY)
|
||||
|
||||
#define KONEPURE_BIN_ATTRIBUTE_RW(thingy, THINGY) \
|
||||
{ \
|
||||
.attr = { .name = #thingy, .mode = 0660 }, \
|
||||
.size = KONEPURE_SIZE_ ## THINGY, \
|
||||
.read = konepure_sysfs_read_ ## thingy, \
|
||||
.write = konepure_sysfs_write_ ## thingy \
|
||||
}
|
||||
|
||||
#define KONEPURE_BIN_ATTRIBUTE_R(thingy, THINGY) \
|
||||
{ \
|
||||
.attr = { .name = #thingy, .mode = 0440 }, \
|
||||
.size = KONEPURE_SIZE_ ## THINGY, \
|
||||
.read = konepure_sysfs_read_ ## thingy, \
|
||||
}
|
||||
|
||||
#define KONEPURE_BIN_ATTRIBUTE_W(thingy, THINGY) \
|
||||
{ \
|
||||
.attr = { .name = #thingy, .mode = 0220 }, \
|
||||
.size = KONEPURE_SIZE_ ## THINGY, \
|
||||
.write = konepure_sysfs_write_ ## thingy \
|
||||
}
|
||||
|
||||
KONEPURE_SYSFS_RW(actual_profile, ACTUAL_PROFILE)
|
||||
KONEPURE_SYSFS_W(control, CONTROL)
|
||||
KONEPURE_SYSFS_RW(info, INFO)
|
||||
KONEPURE_SYSFS_W(talk, TALK)
|
||||
KONEPURE_SYSFS_W(macro, MACRO)
|
||||
KONEPURE_SYSFS_RW(sensor, SENSOR)
|
||||
KONEPURE_SYSFS_RW(tcu, TCU)
|
||||
KONEPURE_SYSFS_R(tcu_image, TCU_IMAGE)
|
||||
KONEPURE_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
|
||||
KONEPURE_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
|
||||
|
||||
static struct bin_attribute konepure_bin_attributes[] = {
|
||||
KONEPURE_BIN_ATTRIBUTE_RW(actual_profile, ACTUAL_PROFILE),
|
||||
KONEPURE_BIN_ATTRIBUTE_W(control, CONTROL),
|
||||
KONEPURE_BIN_ATTRIBUTE_RW(info, INFO),
|
||||
KONEPURE_BIN_ATTRIBUTE_W(talk, TALK),
|
||||
KONEPURE_BIN_ATTRIBUTE_W(macro, MACRO),
|
||||
KONEPURE_BIN_ATTRIBUTE_RW(sensor, SENSOR),
|
||||
KONEPURE_BIN_ATTRIBUTE_RW(tcu, TCU),
|
||||
KONEPURE_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE),
|
||||
KONEPURE_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
|
||||
KONEPURE_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
static int konepure_init_konepure_device_struct(struct usb_device *usb_dev,
|
||||
struct konepure_device *konepure)
|
||||
{
|
||||
mutex_init(&konepure->konepure_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int konepure_init_specials(struct hid_device *hdev)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
||||
struct usb_device *usb_dev = interface_to_usbdev(intf);
|
||||
struct konepure_device *konepure;
|
||||
int retval;
|
||||
|
||||
if (intf->cur_altsetting->desc.bInterfaceProtocol
|
||||
!= USB_INTERFACE_PROTOCOL_MOUSE) {
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
konepure = kzalloc(sizeof(*konepure), GFP_KERNEL);
|
||||
if (!konepure) {
|
||||
hid_err(hdev, "can't alloc device descriptor\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
hid_set_drvdata(hdev, konepure);
|
||||
|
||||
retval = konepure_init_konepure_device_struct(usb_dev, konepure);
|
||||
if (retval) {
|
||||
hid_err(hdev, "couldn't init struct konepure_device\n");
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
retval = roccat_connect(konepure_class, hdev,
|
||||
sizeof(struct konepure_mouse_report_button));
|
||||
if (retval < 0) {
|
||||
hid_err(hdev, "couldn't init char dev\n");
|
||||
} else {
|
||||
konepure->chrdev_minor = retval;
|
||||
konepure->roccat_claimed = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
exit_free:
|
||||
kfree(konepure);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void konepure_remove_specials(struct hid_device *hdev)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
||||
struct konepure_device *konepure;
|
||||
|
||||
if (intf->cur_altsetting->desc.bInterfaceProtocol
|
||||
!= USB_INTERFACE_PROTOCOL_MOUSE)
|
||||
return;
|
||||
|
||||
konepure = hid_get_drvdata(hdev);
|
||||
if (konepure->roccat_claimed)
|
||||
roccat_disconnect(konepure->chrdev_minor);
|
||||
kfree(konepure);
|
||||
}
|
||||
|
||||
static int konepure_probe(struct hid_device *hdev,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = hid_parse(hdev);
|
||||
if (retval) {
|
||||
hid_err(hdev, "parse failed\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
||||
if (retval) {
|
||||
hid_err(hdev, "hw start failed\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
retval = konepure_init_specials(hdev);
|
||||
if (retval) {
|
||||
hid_err(hdev, "couldn't install mouse\n");
|
||||
goto exit_stop;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_stop:
|
||||
hid_hw_stop(hdev);
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void konepure_remove(struct hid_device *hdev)
|
||||
{
|
||||
konepure_remove_specials(hdev);
|
||||
hid_hw_stop(hdev);
|
||||
}
|
||||
|
||||
static int konepure_raw_event(struct hid_device *hdev,
|
||||
struct hid_report *report, u8 *data, int size)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
|
||||
struct konepure_device *konepure = hid_get_drvdata(hdev);
|
||||
|
||||
if (intf->cur_altsetting->desc.bInterfaceProtocol
|
||||
!= USB_INTERFACE_PROTOCOL_MOUSE)
|
||||
return 0;
|
||||
|
||||
if (data[0] != KONEPURE_MOUSE_REPORT_NUMBER_BUTTON)
|
||||
return 0;
|
||||
|
||||
if (konepure != NULL && konepure->roccat_claimed)
|
||||
roccat_report_event(konepure->chrdev_minor, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hid_device_id konepure_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(hid, konepure_devices);
|
||||
|
||||
static struct hid_driver konepure_driver = {
|
||||
.name = "konepure",
|
||||
.id_table = konepure_devices,
|
||||
.probe = konepure_probe,
|
||||
.remove = konepure_remove,
|
||||
.raw_event = konepure_raw_event
|
||||
};
|
||||
|
||||
static int __init konepure_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
konepure_class = class_create(THIS_MODULE, "konepure");
|
||||
if (IS_ERR(konepure_class))
|
||||
return PTR_ERR(konepure_class);
|
||||
konepure_class->dev_bin_attrs = konepure_bin_attributes;
|
||||
|
||||
retval = hid_register_driver(&konepure_driver);
|
||||
if (retval)
|
||||
class_destroy(konepure_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit konepure_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&konepure_driver);
|
||||
class_destroy(konepure_class);
|
||||
}
|
||||
|
||||
module_init(konepure_init);
|
||||
module_exit(konepure_exit);
|
||||
|
||||
MODULE_AUTHOR("Stefan Achatz");
|
||||
MODULE_DESCRIPTION("USB Roccat KonePure driver");
|
||||
MODULE_LICENSE("GPL v2");
|
72
drivers/hid/hid-roccat-konepure.h
Normal file
72
drivers/hid/hid-roccat-konepure.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
#ifndef __HID_ROCCAT_KONEPURE_H
|
||||
#define __HID_ROCCAT_KONEPURE_H
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum {
|
||||
KONEPURE_SIZE_ACTUAL_PROFILE = 0x03,
|
||||
KONEPURE_SIZE_CONTROL = 0x03,
|
||||
KONEPURE_SIZE_FIRMWARE_WRITE = 0x0402,
|
||||
KONEPURE_SIZE_INFO = 0x06,
|
||||
KONEPURE_SIZE_MACRO = 0x0822,
|
||||
KONEPURE_SIZE_PROFILE_SETTINGS = 0x1f,
|
||||
KONEPURE_SIZE_PROFILE_BUTTONS = 0x3b,
|
||||
KONEPURE_SIZE_SENSOR = 0x06,
|
||||
KONEPURE_SIZE_TALK = 0x10,
|
||||
KONEPURE_SIZE_TCU = 0x04,
|
||||
KONEPURE_SIZE_TCU_IMAGE = 0x0404,
|
||||
};
|
||||
|
||||
enum konepure_control_requests {
|
||||
KONEPURE_CONTROL_REQUEST_GENERAL = 0x80,
|
||||
KONEPURE_CONTROL_REQUEST_BUTTONS = 0x90,
|
||||
};
|
||||
|
||||
enum konepure_commands {
|
||||
KONEPURE_COMMAND_CONTROL = 0x04,
|
||||
KONEPURE_COMMAND_ACTUAL_PROFILE = 0x05,
|
||||
KONEPURE_COMMAND_PROFILE_SETTINGS = 0x06,
|
||||
KONEPURE_COMMAND_PROFILE_BUTTONS = 0x07,
|
||||
KONEPURE_COMMAND_MACRO = 0x08,
|
||||
KONEPURE_COMMAND_INFO = 0x09,
|
||||
KONEPURE_COMMAND_TCU = 0x0c,
|
||||
KONEPURE_COMMAND_TCU_IMAGE = 0x0c,
|
||||
KONEPURE_COMMAND_E = 0x0e,
|
||||
KONEPURE_COMMAND_SENSOR = 0x0f,
|
||||
KONEPURE_COMMAND_TALK = 0x10,
|
||||
KONEPURE_COMMAND_FIRMWARE_WRITE = 0x1b,
|
||||
KONEPURE_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
|
||||
};
|
||||
|
||||
enum {
|
||||
KONEPURE_MOUSE_REPORT_NUMBER_BUTTON = 3,
|
||||
};
|
||||
|
||||
struct konepure_mouse_report_button {
|
||||
uint8_t report_number; /* always KONEPURE_MOUSE_REPORT_NUMBER_BUTTON */
|
||||
uint8_t zero;
|
||||
uint8_t type;
|
||||
uint8_t data1;
|
||||
uint8_t data2;
|
||||
uint8_t zero2;
|
||||
uint8_t unknown[2];
|
||||
} __packed;
|
||||
|
||||
struct konepure_device {
|
||||
int roccat_claimed;
|
||||
int chrdev_minor;
|
||||
struct mutex konepure_lock;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -242,7 +242,6 @@ static int roccat_release(struct inode *inode, struct file *file)
|
|||
* roccat_report_event() - output data to readers
|
||||
* @minor: minor device number returned by roccat_connect()
|
||||
* @data: pointer to data
|
||||
* @len: size of data
|
||||
*
|
||||
* Return value is zero on success, a negative error code on failure.
|
||||
*
|
||||
|
@ -290,6 +289,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
|
|||
* @class: the class thats used to create the device. Meant to hold device
|
||||
* specific sysfs attributes.
|
||||
* @hid: the hid device the char device should be connected to.
|
||||
* @report_size: size of reports
|
||||
*
|
||||
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
|
||||
* success, a negative error code on failure.
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/usb.h>
|
||||
#include "usbhid/usbhid.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.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;
|
||||
}
|
||||
hid_set_field(report->field[field_index], 0, value);
|
||||
usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT);
|
||||
usbhid_wait_io(hsdev->hdev);
|
||||
hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT);
|
||||
hid_hw_wait(hsdev->hdev);
|
||||
|
||||
done_proc:
|
||||
mutex_unlock(&data->mutex);
|
||||
|
@ -227,8 +225,8 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
|||
ret = -EINVAL;
|
||||
goto done_proc;
|
||||
}
|
||||
usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
|
||||
usbhid_wait_io(hsdev->hdev);
|
||||
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
|
||||
hid_hw_wait(hsdev->hdev);
|
||||
*value = report->field[field_index]->value[0];
|
||||
|
||||
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);
|
||||
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);
|
||||
wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
|
||||
switch (data->pending.raw_size) {
|
||||
|
|
|
@ -28,13 +28,11 @@
|
|||
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include "hid-ids.h"
|
||||
|
||||
#ifdef CONFIG_SMARTJOYPLUS_FF
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
struct sjoyff_device {
|
||||
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[2] = left;
|
||||
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;
|
||||
}
|
||||
|
@ -115,7 +113,7 @@ static int sjoyff_init(struct hid_device *hid)
|
|||
sjoyff->report->field[0]->value[0] = 0x01;
|
||||
sjoyff->report->field[0]->value[1] = 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");
|
||||
|
|
|
@ -16,10 +16,8 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
static const struct hid_device_id speedlink_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE)},
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "usbhid/usbhid.h"
|
||||
#include "hid-ids.h"
|
||||
|
||||
#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[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 */
|
||||
}
|
||||
|
@ -378,16 +377,5 @@ static struct hid_driver steelseries_srws1_driver = {
|
|||
.report_fixup = steelseries_srws1_report_fixup
|
||||
};
|
||||
|
||||
static int __init steelseries_srws1_init(void)
|
||||
{
|
||||
return hid_register_driver(&steelseries_srws1_driver);
|
||||
}
|
||||
|
||||
static void __exit steelseries_srws1_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&steelseries_srws1_driver);
|
||||
}
|
||||
|
||||
module_init(steelseries_srws1_init);
|
||||
module_exit(steelseries_srws1_exit);
|
||||
module_hid_driver(steelseries_srws1_driver);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
@ -46,7 +45,6 @@ static const signed short ff_joystick[] = {
|
|||
};
|
||||
|
||||
#ifdef CONFIG_THRUSTMASTER_FF
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
/* Usages for thrustmaster devices I know about */
|
||||
#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);
|
||||
ff_field->value[0] = x;
|
||||
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;
|
||||
|
||||
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);
|
||||
ff_field->value[0] = left;
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -789,12 +789,20 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
|
|||
input_report_abs(wdata->ir, yid, y);
|
||||
}
|
||||
|
||||
static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
|
||||
/* reduced status report with "BB BB" key data only */
|
||||
static void handler_status_K(struct wiimote_data *wdata,
|
||||
const __u8 *payload)
|
||||
{
|
||||
handler_keys(wdata, payload);
|
||||
|
||||
/* on status reports the drm is reset so we need to resend the drm */
|
||||
wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
|
||||
}
|
||||
|
||||
/* extended status report with "BB BB LF 00 00 VV" data */
|
||||
static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
|
||||
{
|
||||
handler_status_K(wdata, payload);
|
||||
|
||||
wiiext_event(wdata, payload[2] & 0x02);
|
||||
|
||||
|
@ -804,6 +812,12 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
|
|||
}
|
||||
}
|
||||
|
||||
/* reduced generic report with "BB BB" key data only */
|
||||
static void handler_generic_K(struct wiimote_data *wdata, const __u8 *payload)
|
||||
{
|
||||
handler_keys(wdata, payload);
|
||||
}
|
||||
|
||||
static void handler_data(struct wiimote_data *wdata, const __u8 *payload)
|
||||
{
|
||||
__u16 offset = payload[3] << 8 | payload[4];
|
||||
|
@ -947,16 +961,26 @@ struct wiiproto_handler {
|
|||
|
||||
static struct wiiproto_handler handlers[] = {
|
||||
{ .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
|
||||
{ .id = WIIPROTO_REQ_STATUS, .size = 2, .func = handler_status_K },
|
||||
{ .id = WIIPROTO_REQ_DATA, .size = 21, .func = handler_data },
|
||||
{ .id = WIIPROTO_REQ_DATA, .size = 2, .func = handler_generic_K },
|
||||
{ .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
|
||||
{ .id = WIIPROTO_REQ_RETURN, .size = 2, .func = handler_generic_K },
|
||||
{ .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
|
||||
{ .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA },
|
||||
{ .id = WIIPROTO_REQ_DRM_KA, .size = 2, .func = handler_generic_K },
|
||||
{ .id = WIIPROTO_REQ_DRM_KE, .size = 10, .func = handler_drm_KE },
|
||||
{ .id = WIIPROTO_REQ_DRM_KE, .size = 2, .func = handler_generic_K },
|
||||
{ .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI },
|
||||
{ .id = WIIPROTO_REQ_DRM_KAI, .size = 2, .func = handler_generic_K },
|
||||
{ .id = WIIPROTO_REQ_DRM_KEE, .size = 21, .func = handler_drm_KEE },
|
||||
{ .id = WIIPROTO_REQ_DRM_KEE, .size = 2, .func = handler_generic_K },
|
||||
{ .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE },
|
||||
{ .id = WIIPROTO_REQ_DRM_KAE, .size = 2, .func = handler_generic_K },
|
||||
{ .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE },
|
||||
{ .id = WIIPROTO_REQ_DRM_KIE, .size = 2, .func = handler_generic_K },
|
||||
{ .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE },
|
||||
{ .id = WIIPROTO_REQ_DRM_KAIE, .size = 2, .func = handler_generic_K },
|
||||
{ .id = WIIPROTO_REQ_DRM_E, .size = 21, .func = handler_drm_E },
|
||||
{ .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 },
|
||||
{ .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 },
|
||||
|
@ -970,7 +994,6 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
|
|||
struct wiiproto_handler *h;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
bool handled = false;
|
||||
|
||||
if (size < 1)
|
||||
return -EINVAL;
|
||||
|
@ -981,11 +1004,11 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
|
|||
h = &handlers[i];
|
||||
if (h->id == raw_data[0] && h->size < size) {
|
||||
h->func(wdata, &raw_data[1]);
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
if (!handlers[i].id)
|
||||
hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0],
|
||||
size);
|
||||
|
||||
|
@ -1160,6 +1183,7 @@ static void wiimote_destroy(struct wiimote_data *wdata)
|
|||
wiimote_leds_destroy(wdata);
|
||||
|
||||
power_supply_unregister(&wdata->battery);
|
||||
kfree(wdata->battery.name);
|
||||
input_unregister_device(wdata->accel);
|
||||
input_unregister_device(wdata->ir);
|
||||
input_unregister_device(wdata->input);
|
||||
|
@ -1216,9 +1240,14 @@ static int wiimote_hid_probe(struct hid_device *hdev,
|
|||
wdata->battery.properties = wiimote_battery_props;
|
||||
wdata->battery.num_properties = ARRAY_SIZE(wiimote_battery_props);
|
||||
wdata->battery.get_property = wiimote_battery_get_property;
|
||||
wdata->battery.name = "wiimote_battery";
|
||||
wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
wdata->battery.use_for_apm = 0;
|
||||
wdata->battery.name = kasprintf(GFP_KERNEL, "wiimote_battery_%s",
|
||||
wdata->hdev->uniq);
|
||||
if (!wdata->battery.name) {
|
||||
ret = -ENOMEM;
|
||||
goto err_battery_name;
|
||||
}
|
||||
|
||||
ret = power_supply_register(&wdata->hdev->dev, &wdata->battery);
|
||||
if (ret) {
|
||||
|
@ -1254,6 +1283,8 @@ static int wiimote_hid_probe(struct hid_device *hdev,
|
|||
return ret;
|
||||
|
||||
err_battery:
|
||||
kfree(wdata->battery.name);
|
||||
err_battery_name:
|
||||
input_unregister_device(wdata->input);
|
||||
wdata->input = NULL;
|
||||
err_input:
|
||||
|
@ -1283,6 +1314,8 @@ static void wiimote_hid_remove(struct hid_device *hdev)
|
|||
static const struct hid_device_id wiimote_hid_devices[] = {
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
|
||||
USB_DEVICE_ID_NINTENDO_WIIMOTE) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
|
||||
USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, wiimote_hid_devices);
|
||||
|
|
|
@ -24,13 +24,11 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
#ifdef CONFIG_ZEROPLUS_FF
|
||||
#include "usbhid/usbhid.h"
|
||||
|
||||
struct zpff_device {
|
||||
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[3]->value[0] = 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;
|
||||
}
|
||||
|
@ -104,7 +102,7 @@ static int zpff_init(struct hid_device *hid)
|
|||
zpff->report->field[1]->value[0] = 0x02;
|
||||
zpff->report->field[2]->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");
|
||||
|
||||
|
|
|
@ -563,6 +563,36 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
|
|||
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)
|
||||
{
|
||||
struct i2c_client *client = hid->driver_data;
|
||||
|
@ -742,6 +772,7 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
|
|||
.open = i2c_hid_open,
|
||||
.close = i2c_hid_close,
|
||||
.power = i2c_hid_power,
|
||||
.request = i2c_hid_request,
|
||||
.hidinput_input_event = i2c_hid_hidinput_input_event,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
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);
|
||||
spin_unlock_irqrestore(&usbhid->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usbhid_submit_report);
|
||||
|
||||
/* Workqueue routine to send requests to change LEDs */
|
||||
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;
|
||||
}
|
||||
|
||||
int usbhid_wait_io(struct hid_device *hid)
|
||||
static int usbhid_wait_io(struct hid_device *hid)
|
||||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
|
||||
|
@ -720,7 +719,6 @@ int usbhid_wait_io(struct hid_device *hid)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usbhid_wait_io);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = {
|
||||
.parse = usbhid_parse,
|
||||
.start = usbhid_start,
|
||||
|
@ -1251,6 +1275,9 @@ static struct hid_ll_driver usb_hid_driver = {
|
|||
.close = usbhid_close,
|
||||
.power = usbhid_power,
|
||||
.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)
|
||||
|
|
|
@ -263,8 +263,8 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
|
|||
envelope->attack_level,
|
||||
pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
|
||||
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
|
||||
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],
|
||||
effect->u.constant.level);
|
||||
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONSTANT],
|
||||
HID_REQ_SET_REPORT);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -325,8 +325,8 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
|
|||
pidff->effect_direction);
|
||||
pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
|
||||
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
|
||||
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_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
|
||||
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC],
|
||||
HID_REQ_SET_REPORT);
|
||||
|
||||
}
|
||||
|
||||
|
@ -399,8 +399,8 @@ static void pidff_set_condition_report(struct pidff_device *pidff,
|
|||
effect->u.condition[i].left_saturation);
|
||||
pidff_set(&pidff->set_condition[PID_DEAD_BAND],
|
||||
effect->u.condition[i].deadband);
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONDITION],
|
||||
HID_REQ_SET_REPORT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -440,8 +440,8 @@ static void pidff_set_ramp_force_report(struct pidff_device *pidff,
|
|||
effect->u.ramp.start_level);
|
||||
pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
|
||||
effect->u.ramp.end_level);
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_SET_RAMP],
|
||||
HID_REQ_SET_REPORT);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -465,19 +465,19 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
|
|||
int j;
|
||||
|
||||
pidff->create_new_effect_type->value[0] = efnum;
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
|
||||
HID_REQ_SET_REPORT);
|
||||
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_status->value[0] = 0;
|
||||
usbhid_wait_io(pidff->hid);
|
||||
hid_hw_wait(pidff->hid);
|
||||
|
||||
for (j = 0; j < 60; j++) {
|
||||
hid_dbg(pidff->hid, "pid_block_load requested\n");
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
|
||||
USB_DIR_IN);
|
||||
usbhid_wait_io(pidff->hid);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
|
||||
HID_REQ_GET_REPORT);
|
||||
hid_hw_wait(pidff->hid);
|
||||
if (pidff->block_load_status->value[0] ==
|
||||
pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
|
||||
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;
|
||||
}
|
||||
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
|
||||
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)
|
||||
{
|
||||
pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_FREE],
|
||||
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]);
|
||||
/* Wait for the queue to clear. We do not want a full fifo to
|
||||
prevent the effect removal. */
|
||||
usbhid_wait_io(pidff->hid);
|
||||
hid_hw_wait(pidff->hid);
|
||||
pidff_playback_pid(pidff, pid_id, 0);
|
||||
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;
|
||||
|
||||
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
|
||||
HID_REQ_SET_REPORT);
|
||||
}
|
||||
|
||||
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_START_DELAY].value[0] = 0;
|
||||
|
||||
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
|
||||
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];
|
||||
/* 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);
|
||||
usbhid_wait_io(hid);
|
||||
usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
|
||||
usbhid_wait_io(hid);
|
||||
hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
|
||||
hid_hw_wait(hid);
|
||||
hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
|
||||
hid_hw_wait(hid);
|
||||
|
||||
pidff->device_control->value[0] =
|
||||
pidff->control_id[PID_ENABLE_ACTUATORS];
|
||||
usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
|
||||
usbhid_wait_io(hid);
|
||||
hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
|
||||
hid_hw_wait(hid);
|
||||
|
||||
/* pool report is sometimes messed up, refetch it */
|
||||
usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
|
||||
usbhid_wait_io(hid);
|
||||
hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT);
|
||||
hid_hw_wait(hid);
|
||||
|
||||
if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
|
||||
while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) {
|
||||
|
@ -1181,9 +1181,9 @@ static void pidff_reset(struct pidff_device *pidff)
|
|||
break;
|
||||
}
|
||||
hid_dbg(pidff->hid, "pid_pool requested again\n");
|
||||
usbhid_submit_report(hid, pidff->reports[PID_POOL],
|
||||
USB_DIR_IN);
|
||||
usbhid_wait_io(hid);
|
||||
hid_hw_request(hid, pidff->reports[PID_POOL],
|
||||
HID_REQ_GET_REPORT);
|
||||
hid_hw_wait(hid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1269,8 +1269,8 @@ int hid_pidff_init(struct hid_device *hid)
|
|||
|
||||
if (test_bit(FF_GAIN, dev->ffbit)) {
|
||||
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
|
||||
usbhid_submit_report(hid, pidff->reports[PID_DEVICE_GAIN],
|
||||
USB_DIR_OUT);
|
||||
hid_hw_request(hid, pidff->reports[PID_DEVICE_GAIN],
|
||||
HID_REQ_SET_REPORT);
|
||||
}
|
||||
|
||||
error = pidff_check_autocenter(pidff, dev);
|
||||
|
|
|
@ -705,8 +705,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
if (report == NULL)
|
||||
break;
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_IN);
|
||||
usbhid_wait_io(hid);
|
||||
hid_hw_request(hid, report, HID_REQ_GET_REPORT);
|
||||
hid_hw_wait(hid);
|
||||
|
||||
r = 0;
|
||||
break;
|
||||
|
@ -724,8 +724,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
if (report == NULL)
|
||||
break;
|
||||
|
||||
usbhid_submit_report(hid, report, USB_DIR_OUT);
|
||||
usbhid_wait_io(hid);
|
||||
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
|
||||
hid_hw_wait(hid);
|
||||
|
||||
r = 0;
|
||||
break;
|
||||
|
|
|
@ -34,12 +34,9 @@
|
|||
#include <linux/input.h>
|
||||
|
||||
/* 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);
|
||||
int usbhid_open(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);
|
||||
void usbhid_put_power(struct hid_device *hid);
|
||||
struct usb_interface *usbhid_find_interface(int minor);
|
||||
|
|
|
@ -22,11 +22,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define HID_DEBUG_BUFSIZE 512
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
#define HID_DEBUG_BUFSIZE 512
|
||||
|
||||
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_field(struct hid_field *, int, struct seq_file *);
|
||||
char *hid_resolv_usage(unsigned, struct seq_file *);
|
||||
|
@ -50,6 +51,7 @@ struct hid_debug_list {
|
|||
#else
|
||||
|
||||
#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_field(a,b,c) do { } while (0)
|
||||
#define hid_resolv_usage(a,b) do { } while (0)
|
||||
|
|
|
@ -282,6 +282,7 @@ struct hid_item {
|
|||
#define HID_QUIRK_BADPAD 0x00000020
|
||||
#define HID_QUIRK_MULTI_INPUT 0x00000040
|
||||
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080
|
||||
#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
|
||||
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
|
||||
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
|
||||
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
|
||||
|
@ -456,7 +457,8 @@ struct hid_device { /* device report descriptor */
|
|||
unsigned country; /* HID country */
|
||||
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 hid_driver *driver;
|
||||
struct hid_ll_driver *ll_driver;
|
||||
|
@ -477,6 +479,7 @@ struct hid_device { /* device report descriptor */
|
|||
unsigned int status; /* see STAT flags above */
|
||||
unsigned claimed; /* Claimed by hidinput, hiddev? */
|
||||
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 */
|
||||
void *hiddev; /* The hiddev structure */
|
||||
|
@ -512,6 +515,7 @@ struct hid_device { /* device report descriptor */
|
|||
struct dentry *debug_rdesc;
|
||||
struct dentry *debug_events;
|
||||
struct list_head debug_list;
|
||||
struct mutex debug_list_lock;
|
||||
wait_queue_head_t debug_wait;
|
||||
};
|
||||
|
||||
|
@ -599,6 +603,10 @@ struct hid_usage_id {
|
|||
* @resume: invoked on resume if device was not 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
|
||||
* further processing should be done and negative on error
|
||||
*
|
||||
|
@ -662,6 +670,9 @@ struct hid_driver {
|
|||
* @hidinput_input_event: event input event (e.g. ff or leds)
|
||||
* @parse: this method is called only once to parse the device data,
|
||||
* 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 {
|
||||
int (*start)(struct hid_device *hdev);
|
||||
|
@ -676,6 +687,13 @@ struct hid_ll_driver {
|
|||
unsigned int code, int value);
|
||||
|
||||
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
|
||||
|
@ -737,6 +755,44 @@ const struct hid_device_id *hid_match_id(struct hid_device *hdev,
|
|||
const struct hid_device_id *id);
|
||||
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
|
||||
*
|
||||
|
@ -883,6 +939,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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 interrupt);
|
||||
|
||||
|
|
|
@ -17,10 +17,9 @@
|
|||
/*
|
||||
* Ugly hack to work around failing compilation on systems that don't
|
||||
* yet populate new version of hidraw.h to userspace.
|
||||
*
|
||||
* If you need this, please have your distro update the kernel headers.
|
||||
*/
|
||||
#ifndef HIDIOCSFEATURE
|
||||
#warning Please have your distro update the userspace kernel headers
|
||||
#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
|
||||
#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue