Commit 7fd23a24 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (48 commits)
  HID: add support for Logitech Driving Force Pro wheel
  HID: hid-ortek: remove spurious reference
  HID: add support for Ortek PKB-1700
  HID: roccat-koneplus: vorrect mode of sysfs attr 'sensor'
  HID: hid-ntrig: init settle and mode check
  HID: merge hid-egalax into hid-multitouch
  HID: hid-multitouch: Send events per slot if CONTACTCOUNT is missing
  HID: ntrig remove if and drop an indent
  HID: ACRUX - activate the device immediately after binding
  HID: ntrig: apply NO_INIT_REPORTS quirk
  HID: hid-magicmouse: Correct touch orientation direction
  HID: ntrig don't dereference unclaimed hidinput
  HID: Do not create input devices for feature reports
  HID: bt hidp: send Output reports using SET_REPORT on the Control channel
  HID: hid-sony.c: Fix sending Output reports to the Sixaxis
  HID: add support for Keytouch IEC 60945
  HID: Add HID Report Descriptor to sysfs
  HID: add IRTOUCH infrared USB to hid_have_special_driver
  HID: kernel oops in out_cleanup in function hidinput_connect
  HID: Add teletext/color keys - gyration remote - EU version (GYAR3101CKDE)
  ...
parents 0a95d92c 65b06194
What: For USB devices : /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
For BT devices : /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
Symlink : /sys/class/hidraw/hidraw<num>/device/report_descriptor
Date: Jan 2011
KernelVersion: 2.0.39
Contact: Alan Ott <alan@signal11.us>
Description: When read, this file returns the device's raw binary HID
report descriptor.
This file cannot be written.
Users: HIDAPI library (http://www.signal11.us/oss/hidapi)
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/actual_profile
Date: Januar 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The integer value of this attribute ranges from 1-5.
When read, this attribute returns the number of the actual
profile which is also the profile that's active on device startup.
When written this attribute activates the selected profile
immediately.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/button
Date: Januar 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The keyboard can store short macros with consist of 1 button with
several modifier keys 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 24 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>/arvo/roccatarvo<minor>/info
Date: Januar 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns some info about the device like the
installed firmware version.
The size of the data is 8 bytes in size.
This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/key_mask
Date: Januar 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The keyboard lets the user deactivate 5 certain keys like the
windows and application keys, to protect the user from the outcome
of accidentally pressing them.
The integer value of this attribute has bits 0-4 set depending
on the state of the corresponding key.
When read, this file returns the current state of the buttons.
When written, the given buttons are activated/deactivated
immediately.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/arvo/roccatarvo<minor>/mode_key
Date: Januar 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The keyboard has a condensed layout without num-lock key.
Instead it uses a mode-key which activates a gaming mode where
the assignment of the number block changes.
The integer value of this attribute ranges from 0 (OFF) to 1 (ON).
When read, this file returns the actual state of the key.
When written, the key is activated/deactivated immediately.
Users: http://roccat.sourceforge.net
...@@ -16,12 +16,14 @@ Description: It is possible to switch the dpi setting of the mouse with the ...@@ -16,12 +16,14 @@ Description: It is possible to switch the dpi setting of the mouse with the
6 3200 6 3200
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/actual_profile What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/actual_profile
Date: March 2010 Date: March 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the number of the actual profile. Description: When read, this file returns the number of the actual profile.
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/firmware_version What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/firmware_version
Date: March 2010 Date: March 2010
...@@ -32,6 +34,7 @@ Description: When read, this file returns the raw integer version number of the ...@@ -32,6 +34,7 @@ Description: When read, this file returns the raw integer version number of the
number the decimal point has to be shifted 2 positions to the number the decimal point has to be shifted 2 positions to the
left. E.g. a returned value of 138 means 1.38 left. E.g. a returned value of 138 means 1.38
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/profile[1-5] What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/profile[1-5]
Date: March 2010 Date: March 2010
...@@ -47,6 +50,7 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -47,6 +50,7 @@ Description: The mouse can store 5 profiles which can be switched by the
The mouse will reject invalid data, whereas the profile number The mouse will reject invalid data, whereas the profile number
stored in the profile doesn't need to fit the number of the stored in the profile doesn't need to fit the number of the
store. store.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/settings What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/settings
Date: March 2010 Date: March 2010
...@@ -57,6 +61,7 @@ Description: When read, this file returns the settings stored in the mouse. ...@@ -57,6 +61,7 @@ Description: When read, this file returns the settings stored in the mouse.
When written, this file lets write settings back to the mouse. When written, this file lets write settings back to the mouse.
The data has to be 36 bytes long. The mouse will reject invalid The data has to be 36 bytes long. The mouse will reject invalid
data. data.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/startup_profile What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/startup_profile
Date: March 2010 Date: March 2010
...@@ -66,6 +71,7 @@ Description: The integer value of this attribute ranges from 1 to 5. ...@@ -66,6 +71,7 @@ Description: The integer value of this attribute ranges from 1 to 5.
that's active when the mouse is powered on. that's active when the mouse is powered on.
When written, this file sets the number of the startup profile When written, this file sets the number of the startup profile
and the mouse activates this profile immediately. and the mouse activates this profile immediately.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/tcu What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/tcu
Date: March 2010 Date: March 2010
...@@ -77,6 +83,7 @@ Description: The mouse has a "Tracking Control Unit" which lets the user ...@@ -77,6 +83,7 @@ Description: The mouse has a "Tracking Control Unit" which lets the user
Writing 0 in this file will switch the TCU off. Writing 0 in this file will switch the TCU off.
Writing 1 in this file will start the calibration which takes Writing 1 in this file will start the calibration which takes
around 6 seconds to complete and activates the TCU. around 6 seconds to complete and activates the TCU.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/weight What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kone/roccatkone<minor>/weight
Date: March 2010 Date: March 2010
...@@ -96,3 +103,4 @@ Description: The mouse can be equipped with one of four supplied weights ...@@ -96,3 +103,4 @@ Description: The mouse can be equipped with one of four supplied weights
4 20g 4 20g
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
...@@ -4,6 +4,7 @@ Contact: Stefan Achatz <erazor_de@users.sourceforge.net> ...@@ -4,6 +4,7 @@ Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the number of the actual profile in Description: When read, this file returns the number of the actual profile in
range 0-4. range 0-4.
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/firmware_version What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/firmware_version
Date: October 2010 Date: October 2010
...@@ -14,6 +15,7 @@ Description: When read, this file returns the raw integer version number of the ...@@ -14,6 +15,7 @@ Description: When read, this file returns the raw integer version number of the
number the decimal point has to be shifted 2 positions to the number the decimal point has to be shifted 2 positions to the
left. E.g. a returned value of 121 means 1.21 left. E.g. a returned value of 121 means 1.21
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/macro What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/macro
Date: October 2010 Date: October 2010
...@@ -24,6 +26,7 @@ Description: The mouse can store a macro with max 500 key/button strokes ...@@ -24,6 +26,7 @@ Description: The mouse can store a macro with max 500 key/button strokes
button for a specific profile. Button and profile numbers are button for a specific profile. Button and profile numbers are
included in written data. The data has to be 2082 bytes long. included in written data. The data has to be 2082 bytes long.
This file is writeonly. 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>/koneplus/roccatkoneplus<minor>/profile_buttons What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_buttons
Date: August 2010 Date: August 2010
...@@ -37,6 +40,7 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -37,6 +40,7 @@ Description: The mouse can store 5 profiles which can be switched by the
Which profile to write is determined by the profile number Which profile to write is determined by the profile number
contained in the data. contained in the data.
This file is writeonly. 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>/koneplus/roccatkoneplus<minor>/profile[1-5]_buttons What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_buttons
Date: August 2010 Date: August 2010
...@@ -47,6 +51,7 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -47,6 +51,7 @@ Description: The mouse can store 5 profiles which can be switched by the
When read, these files return the respective profile buttons. When read, these files return the respective profile buttons.
The returned data is 77 bytes in size. The returned data is 77 bytes in size.
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_settings What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_settings
Date: October 2010 Date: October 2010
...@@ -61,6 +66,7 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -61,6 +66,7 @@ Description: The mouse can store 5 profiles which can be switched by the
Which profile to write is determined by the profile number Which profile to write is determined by the profile number
contained in the data. contained in the data.
This file is writeonly. 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>/koneplus/roccatkoneplus<minor>/profile[1-5]_settings What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_settings
Date: August 2010 Date: August 2010
...@@ -72,6 +78,7 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -72,6 +78,7 @@ Description: The mouse can store 5 profiles which can be switched by the
When read, these files return the respective profile settings. When read, these files return the respective profile settings.
The returned data is 43 bytes in size. The returned data is 43 bytes in size.
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/sensor What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/sensor
Date: October 2010 Date: October 2010
...@@ -80,6 +87,7 @@ Description: The mouse has a tracking- and a distance-control-unit. These ...@@ -80,6 +87,7 @@ Description: The mouse has a tracking- and a distance-control-unit. These
can be activated/deactivated and the lift-off distance can be can be activated/deactivated and the lift-off distance can be
set. The data has to be 6 bytes long. set. The data has to be 6 bytes long.
This file is writeonly. 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>/koneplus/roccatkoneplus<minor>/startup_profile What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/startup_profile
Date: October 2010 Date: October 2010
...@@ -89,6 +97,7 @@ Description: The integer value of this attribute ranges from 0-4. ...@@ -89,6 +97,7 @@ Description: The integer value of this attribute ranges from 0-4.
that's active when the mouse is powered on. that's active when the mouse is powered on.
When written, this file sets the number of the startup profile When written, this file sets the number of the startup profile
and the mouse activates this profile immediately. and the mouse activates this profile immediately.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu
Date: October 2010 Date: October 2010
...@@ -97,6 +106,7 @@ Description: When written a calibration process for the tracking control unit ...@@ -97,6 +106,7 @@ Description: When written a calibration process for the tracking control unit
can be initiated/cancelled. can be initiated/cancelled.
The data has to be 3 bytes long. The data has to be 3 bytes long.
This file is writeonly. 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>/koneplus/roccatkoneplus<minor>/tcu_image What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu_image
Date: October 2010 Date: October 2010
...@@ -106,3 +116,4 @@ Description: When read the mouse returns a 30x30 pixel image of the ...@@ -106,3 +116,4 @@ Description: When read the mouse returns a 30x30 pixel image of the
calibration process initiated with tcu. calibration process initiated with tcu.
The returned data is 1028 bytes in size. The returned data is 1028 bytes in size.
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_cpi
Date: January 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The integer value of this attribute ranges from 1-4.
When read, this attribute returns the number of the active
cpi level.
This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_profile
Date: January 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The integer value of this attribute ranges from 0-4.
When read, this attribute returns the number of the active
profile.
When written, the mouse activates this profile immediately.
The profile that's active when powered down is the same that's
active when the mouse is powered on.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_sensitivity_x
Date: January 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The integer value of this attribute ranges from 1-10.
When read, this attribute returns the number of the actual
sensitivity in x direction.
This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_sensitivity_y
Date: January 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The integer value of this attribute ranges from 1-10.
When read, this attribute returns the number of the actual
sensitivity in y direction.
This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/firmware_version
Date: January 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the raw integer version number of the
firmware reported by the mouse. Using the integer value eases
further usage in other programs. To receive the real version
number the decimal point has to be shifted 2 positions to the
left. E.g. a returned value of 121 means 1.21
This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_buttons
Date: January 2011
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 informations about button layout.
When written, this file lets one write the respective profile
buttons back to the mouse. The data has to be 23 bytes long.
The mouse will reject invalid data.
Which profile to write is determined by the profile number
contained in the data.
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>/kovaplus/roccatkovaplus<minor>/profile[1-5]_buttons
Date: January 2011
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 informations about button layout.
When read, these files return the respective profile buttons.
The returned data is 23 bytes in size.
This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_settings
Date: January 2011
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 informations 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 16 bytes long.
The mouse will reject invalid data.
Which profile to write is determined by the profile number
contained in the data.
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>/kovaplus/roccatkovaplus<minor>/profile[1-5]_settings
Date: January 2011
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 informations like resolution, sensitivity
and light effects.
When read, these files return the respective profile settings.
The returned data is 16 bytes in size.
This file is readonly.
Users: http://roccat.sourceforge.net
...@@ -13,6 +13,7 @@ Description: It is possible to switch the cpi setting of the mouse with the ...@@ -13,6 +13,7 @@ Description: It is possible to switch the cpi setting of the mouse with the
4 1600 4 1600
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/actual_profile What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/actual_profile
Date: August 2010 Date: August 2010
...@@ -20,6 +21,7 @@ Contact: Stefan Achatz <erazor_de@users.sourceforge.net> ...@@ -20,6 +21,7 @@ Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the number of the actual profile in Description: When read, this file returns the number of the actual profile in
range 0-4. range 0-4.
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/firmware_version What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/firmware_version
Date: August 2010 Date: August 2010
...@@ -30,6 +32,7 @@ Description: When read, this file returns the raw integer version number of the ...@@ -30,6 +32,7 @@ Description: When read, this file returns the raw integer version number of the
number the decimal point has to be shifted 2 positions to the number the decimal point has to be shifted 2 positions to the
left. E.g. a returned value of 138 means 1.38 left. E.g. a returned value of 138 means 1.38
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_settings What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_settings
Date: August 2010 Date: August 2010
...@@ -44,6 +47,7 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -44,6 +47,7 @@ Description: The mouse can store 5 profiles which can be switched by the
Which profile to write is determined by the profile number Which profile to write is determined by the profile number
contained in the data. contained in the data.
This file is writeonly. 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>/pyra/roccatpyra<minor>/profile[1-5]_settings What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_settings
Date: August 2010 Date: August 2010
...@@ -55,6 +59,7 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -55,6 +59,7 @@ Description: The mouse can store 5 profiles which can be switched by the
When read, these files return the respective profile settings. When read, these files return the respective profile settings.
The returned data is 13 bytes in size. The returned data is 13 bytes in size.
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_buttons What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_buttons
Date: August 2010 Date: August 2010
...@@ -68,6 +73,7 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -68,6 +73,7 @@ Description: The mouse can store 5 profiles which can be switched by the
Which profile to write is determined by the profile number Which profile to write is determined by the profile number
contained in the data. contained in the data.
This file is writeonly. 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>/pyra/roccatpyra<minor>/profile[1-5]_buttons What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_buttons
Date: August 2010 Date: August 2010
...@@ -78,6 +84,7 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -78,6 +84,7 @@ Description: The mouse can store 5 profiles which can be switched by the
When read, these files return the respective profile buttons. When read, these files return the respective profile buttons.
The returned data is 19 bytes in size. The returned data is 19 bytes in size.
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/startup_profile What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/startup_profile
Date: August 2010 Date: August 2010
...@@ -86,6 +93,7 @@ Description: The integer value of this attribute ranges from 0-4. ...@@ -86,6 +93,7 @@ Description: The integer value of this attribute ranges from 0-4.
When read, this attribute returns the number of the profile When read, this attribute returns the number of the profile
that's active when the mouse is powered on. that's active when the mouse is powered on.
This file is readonly. This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/settings What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/settings
Date: August 2010 Date: August 2010
...@@ -96,3 +104,4 @@ Description: When read, this file returns the settings stored in the mouse. ...@@ -96,3 +104,4 @@ Description: When read, this file returns the settings stored in the mouse.
When written, this file lets write settings back to the mouse. When written, this file lets write settings back to the mouse.
The data has to be 3 bytes long. The mouse will reject invalid The data has to be 3 bytes long. The mouse will reject invalid
data. data.
Users: http://roccat.sourceforge.net
...@@ -133,6 +133,7 @@ Code Seq#(hex) Include File Comments ...@@ -133,6 +133,7 @@ Code Seq#(hex) Include File Comments
'H' C0-DF net/bluetooth/hidp/hidp.h conflict! 'H' C0-DF net/bluetooth/hidp/hidp.h conflict!
'H' C0-DF net/bluetooth/cmtp/cmtp.h conflict! 'H' C0-DF net/bluetooth/cmtp/cmtp.h conflict!
'H' C0-DF net/bluetooth/bnep/bnep.h conflict! 'H' C0-DF net/bluetooth/bnep/bnep.h conflict!
'H' F1 linux/hid-roccat.h <mailto:erazor_de@users.sourceforge.net>
'I' all linux/isdn.h conflict! 'I' all linux/isdn.h conflict!
'I' 00-0F drivers/isdn/divert/isdn_divert.h conflict! 'I' 00-0F drivers/isdn/divert/isdn_divert.h conflict!
'I' 40-4F linux/mISDNif.h conflict! 'I' 40-4F linux/mISDNif.h conflict!
......
...@@ -68,9 +68,15 @@ config HID_A4TECH ...@@ -68,9 +68,15 @@ config HID_A4TECH
---help--- ---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice. Support for A4 tech X5 and WOP-35 / Trust 450L mice.
config HID_ACRUX_FF config HID_ACRUX
tristate "ACRUX force feedback" tristate "ACRUX game controller support"
depends on USB_HID depends on USB_HID
---help---
Say Y here if you want to enable support for ACRUX game controllers.
config HID_ACRUX_FF
tristate "ACRUX force feedback support"
depends on HID_ACRUX
select INPUT_FF_MEMLESS select INPUT_FF_MEMLESS
---help--- ---help---
Say Y here if you want to enable force feedback support for ACRUX Say Y here if you want to enable force feedback support for ACRUX
...@@ -140,7 +146,12 @@ config HID_DRAGONRISE ...@@ -140,7 +146,12 @@ config HID_DRAGONRISE
tristate "DragonRise Inc. game controller" tristate "DragonRise Inc. game controller"
depends on USB_HID depends on USB_HID
---help--- ---help---
Say Y here if you have DragonRise Inc.game controllers. Say Y here if you have DragonRise Inc. game controllers.
These might be branded as:
- Tesun USB-703
- Media-tech MT1504 "Rogue"
- DVTech JS19 "Gear"
- Defender Game Master
config DRAGONRISE_FF config DRAGONRISE_FF
bool "DragonRise Inc. force feedback" bool "DragonRise Inc. force feedback"
...@@ -160,13 +171,6 @@ config HID_EMS_FF ...@@ -160,13 +171,6 @@ config HID_EMS_FF
Currently the following devices are known to be supported: Currently the following devices are known to be supported:
- Trio Linker Plus II - Trio Linker Plus II
config HID_EGALAX
tristate "eGalax multi-touch panel"
depends on USB_HID
---help---
Support for the eGalax dual-touch panels, including the
Joojoo and Wetab tablets.
config HID_ELECOM config HID_ELECOM
tristate "ELECOM BM084 bluetooth mouse" tristate "ELECOM BM084 bluetooth mouse"
depends on BT_HIDP depends on BT_HIDP
...@@ -180,6 +184,14 @@ config HID_EZKEY ...@@ -180,6 +184,14 @@ config HID_EZKEY
---help--- ---help---
Support for Ezkey BTC 8193 keyboard. Support for Ezkey BTC 8193 keyboard.
config HID_KEYTOUCH
tristate "Keyoutch HID devices"
depends on USB_HID
---help---
Support for Keytouch HID devices not fully compliant with
the specification. Currently supported:
- Keytouch IEC 60945
config HID_KYE config HID_KYE
tristate "Kye/Genius Ergo Mouse" if EXPERT tristate "Kye/Genius Ergo Mouse" if EXPERT
depends on USB_HID depends on USB_HID
...@@ -218,6 +230,12 @@ config HID_KENSINGTON ...@@ -218,6 +230,12 @@ config HID_KENSINGTON
---help--- ---help---
Support for Kensington Slimblade Trackball. Support for Kensington Slimblade Trackball.
config HID_LCPOWER
tristate "LC-Power"
depends on USB_HID
---help---
Support for LC-Power RC1000MCE RF remote control.
config HID_LOGITECH config HID_LOGITECH
tristate "Logitech devices" if EXPERT tristate "Logitech devices" if EXPERT
depends on USB_HID depends on USB_HID
...@@ -304,8 +322,11 @@ config HID_MULTITOUCH ...@@ -304,8 +322,11 @@ config HID_MULTITOUCH
Say Y here if you have one of the following devices: Say Y here if you have one of the following devices:
- Cypress TrueTouch panels - Cypress TrueTouch panels
- Hanvon dual touch panels - Hanvon dual touch panels
- IrTouch Infrared USB panels
- Pixcir dual touch panels - Pixcir dual touch panels
- 'Sensing Win7-TwoFinger' panel by GeneralTouch - 'Sensing Win7-TwoFinger' panel by GeneralTouch
- eGalax dual-touch panels, including the
Joojoo and Wetab tablets
If unsure, say N. If unsure, say N.
...@@ -319,10 +340,10 @@ config HID_NTRIG ...@@ -319,10 +340,10 @@ config HID_NTRIG
Support for N-Trig touch screen. Support for N-Trig touch screen.
config HID_ORTEK config HID_ORTEK
tristate "Ortek WKB-2000 wireless keyboard and mouse trackpad" tristate "Ortek PKB-1700/WKB-2000 wireless keyboard and mouse trackpad"
depends on USB_HID depends on USB_HID
---help--- ---help---
Support for Ortek WKB-2000 wireless keyboard + mouse trackpad. Support for Ortek PKB-1700/WKB-2000 wireless keyboard + mouse trackpad.
config HID_PANTHERLORD config HID_PANTHERLORD
tristate "Pantherlord/GreenAsia game controller" tristate "Pantherlord/GreenAsia game controller"
...@@ -417,10 +438,22 @@ config HID_ROCCAT ...@@ -417,10 +438,22 @@ config HID_ROCCAT
Say Y here if you have a Roccat mouse or keyboard and want OSD or Say Y here if you have a Roccat mouse or keyboard and want OSD or
macro execution support. macro execution support.
config HID_ROCCAT_COMMON
tristate
config HID_ROCCAT_ARVO
tristate "Roccat Arvo keyboard support"
depends on USB_HID
select HID_ROCCAT
select HID_ROCCAT_COMMON
---help---
Support for Roccat Arvo keyboard.
config HID_ROCCAT_KONE config HID_ROCCAT_KONE
tristate "Roccat Kone Mouse support" tristate "Roccat Kone Mouse support"
depends on USB_HID depends on USB_HID
select HID_ROCCAT select HID_ROCCAT
select HID_ROCCAT_COMMON
---help--- ---help---
Support for Roccat Kone mouse. Support for Roccat Kone mouse.
...@@ -428,13 +461,23 @@ config HID_ROCCAT_KONEPLUS ...@@ -428,13 +461,23 @@ config HID_ROCCAT_KONEPLUS
tristate "Roccat Kone[+] mouse support" tristate "Roccat Kone[+] mouse support"
depends on USB_HID depends on USB_HID
select HID_ROCCAT select HID_ROCCAT
select HID_ROCCAT_COMMON
---help--- ---help---
Support for Roccat Kone[+] mouse. Support for Roccat Kone[+] mouse.
config HID_ROCCAT_KOVAPLUS
tristate "Roccat Kova[+] mouse support"
depends on USB_HID
select HID_ROCCAT
select HID_ROCCAT_COMMON
---help---
Support for Roccat Kova[+] mouse.
config HID_ROCCAT_PYRA config HID_ROCCAT_PYRA
tristate "Roccat Pyra mouse support" tristate "Roccat Pyra mouse support"
depends on USB_HID depends on USB_HID
select HID_ROCCAT select HID_ROCCAT
select HID_ROCCAT_COMMON
---help--- ---help---
Support for Roccat Pyra mouse. Support for Roccat Pyra mouse.
......
...@@ -27,21 +27,22 @@ endif ...@@ -27,21 +27,22 @@ endif
obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX_FF) += hid-axff.o obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CANDO) += hid-cando.o obj-$(CONFIG_HID_CANDO) += hid-cando.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
obj-$(CONFIG_HID_DRAGONRISE) += hid-drff.o obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
obj-$(CONFIG_HID_EGALAX) += hid-egalax.o
obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
obj-$(CONFIG_HID_KYE) += hid-kye.o obj-$(CONFIG_HID_KYE) += hid-kye.o
obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
...@@ -56,8 +57,11 @@ obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o ...@@ -56,8 +57,11 @@ obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o
obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o
obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o
obj-$(CONFIG_HID_ROCCAT_KOVAPLUS) += hid-roccat-kovaplus.o
obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <linux/hid.h> #include <linux/hid.h>
#include "hid-ids.h" #include "hid-ids.h"
#ifdef CONFIG_HID_ACRUX_FF
#include "usbhid/usbhid.h" #include "usbhid/usbhid.h"
struct axff_device { struct axff_device {
...@@ -109,6 +111,12 @@ static int axff_init(struct hid_device *hid) ...@@ -109,6 +111,12 @@ static int axff_init(struct hid_device *hid)
kfree(axff); kfree(axff);
return error; return error;
} }
#else
static inline int axff_init(struct hid_device *hid)
{
return 0;
}
#endif
static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id) static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
{ {
...@@ -139,9 +147,25 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -139,9 +147,25 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
error); error);
} }
/*
* We need to start polling device right away, otherwise
* it will go into a coma.
*/
error = hid_hw_open(hdev);
if (error) {
dev_err(&hdev->dev, "hw open failed\n");
return error;
}
return 0; return 0;
} }
static void ax_remove(struct hid_device *hdev)
{
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
static const struct hid_device_id ax_devices[] = { static const struct hid_device_id ax_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), }, { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), },
{ } { }
...@@ -149,9 +173,10 @@ static const struct hid_device_id ax_devices[] = { ...@@ -149,9 +173,10 @@ static const struct hid_device_id ax_devices[] = {
MODULE_DEVICE_TABLE(hid, ax_devices); MODULE_DEVICE_TABLE(hid, ax_devices);
static struct hid_driver ax_driver = { static struct hid_driver ax_driver = {
.name = "acrux", .name = "acrux",
.id_table = ax_devices, .id_table = ax_devices,
.probe = ax_probe, .probe = ax_probe,
.remove = ax_remove,
}; };
static int __init ax_init(void) static int __init ax_init(void)
......
...@@ -1159,6 +1159,32 @@ static bool hid_hiddev(struct hid_device *hdev) ...@@ -1159,6 +1159,32 @@ static bool hid_hiddev(struct hid_device *hdev)
return !!hid_match_id(hdev, hid_hiddev_list); return !!hid_match_id(hdev, hid_hiddev_list);
} }
static ssize_t
read_report_descriptor(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
if (off >= hdev->rsize)
return 0;
if (off + count > hdev->rsize)
count = hdev->rsize - off;
memcpy(buf, hdev->rdesc + off, count);
return count;
}
static struct bin_attribute dev_bin_attr_report_desc = {
.attr = { .name = "report_descriptor", .mode = 0444 },
.read = read_report_descriptor,
.size = HID_MAX_DESCRIPTOR_SIZE,
};
int hid_connect(struct hid_device *hdev, unsigned int connect_mask) int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
{ {
static const char *types[] = { "Device", "Pointer", "Mouse", "Device", static const char *types[] = { "Device", "Pointer", "Mouse", "Device",
...@@ -1169,6 +1195,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) ...@@ -1169,6 +1195,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
char buf[64]; char buf[64];
unsigned int i; unsigned int i;
int len; int len;
int ret;
if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE) if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV); connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
...@@ -1230,6 +1257,11 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) ...@@ -1230,6 +1257,11 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
bus = "<UNKNOWN>"; bus = "<UNKNOWN>";
} }
ret = device_create_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
if (ret)
hid_warn(hdev,
"can't create sysfs report descriptor attribute err: %d\n", ret);
hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n", hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
buf, bus, hdev->version >> 8, hdev->version & 0xff, buf, bus, hdev->version >> 8, hdev->version & 0xff,
type, hdev->name, hdev->phys); type, hdev->name, hdev->phys);
...@@ -1240,6 +1272,7 @@ EXPORT_SYMBOL_GPL(hid_connect); ...@@ -1240,6 +1272,7 @@ EXPORT_SYMBOL_GPL(hid_connect);
void hid_disconnect(struct hid_device *hdev) void hid_disconnect(struct hid_device *hdev)
{ {
device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
if (hdev->claimed & HID_CLAIMED_INPUT) if (hdev->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hdev); hidinput_disconnect(hdev);
if (hdev->claimed & HID_CLAIMED_HIDDEV) if (hdev->claimed & HID_CLAIMED_HIDDEV)
...@@ -1256,9 +1289,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1256,9 +1289,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, { 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_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
#if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE)
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
#endif
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, { 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_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
...@@ -1328,6 +1359,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1328,6 +1359,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
...@@ -1345,9 +1377,12 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1345,9 +1377,12 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
...@@ -1368,6 +1403,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1368,6 +1403,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
...@@ -1400,12 +1436,15 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1400,12 +1436,15 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
......
...@@ -145,6 +145,110 @@ static inline int drff_init(struct hid_device *hid) ...@@ -145,6 +145,110 @@ static inline int drff_init(struct hid_device *hid)
} }
#endif #endif
/*
* The original descriptor of joystick with PID 0x0011, represented by DVTech PC
* JS19. It seems both copied from another device and a result of confusion
* either about the specification or about the program used to create the
* descriptor. In any case, it's a wonder it works on Windows.
*
* Usage Page (Desktop), ; Generic desktop controls (01h)
* Usage (Joystik), ; Joystik (04h, application collection)
* Collection (Application),
* Collection (Logical),
* Report Size (8),
* Report Count (5),
* Logical Minimum (0),
* Logical Maximum (255),
* Physical Minimum (0),
* Physical Maximum (255),
* Usage (X), ; X (30h, dynamic value)
* Usage (X), ; X (30h, dynamic value)
* Usage (X), ; X (30h, dynamic value)
* Usage (X), ; X (30h, dynamic value)
* Usage (Y), ; Y (31h, dynamic value)
* Input (Variable),
* Report Size (4),
* Report Count (1),
* Logical Maximum (7),
* Physical Maximum (315),
* Unit (Degrees),
* Usage (00h),
* Input (Variable, Null State),
* Unit,
* Report Size (1),
* Report Count (10),
* Logical Maximum (1),
* Physical Maximum (1),
* Usage Page (Button), ; Button (09h)
* Usage Minimum (01h),
* Usage Maximum (0Ah),
* Input (Variable),
* Usage Page (FF00h), ; FF00h, vendor-defined
* Report Size (1),
* Report Count (10),
* Logical Maximum (1),
* Physical Maximum (1),
* Usage (01h),
* Input (Variable),
* End Collection,
* Collection (Logical),
* Report Size (8),
* Report Count (4),
* Physical Maximum (255),
* Logical Maximum (255),
* Usage (02h),
* Output (Variable),
* End Collection,
* End Collection
*/
/* Size of the original descriptor of the PID 0x0011 joystick */
#define PID0011_RDESC_ORIG_SIZE 101
/* Fixed report descriptor for PID 0x011 joystick */
static __u8 pid0011_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
0xA1, 0x01, /* Collection (Application), */
0xA1, 0x02, /* Collection (Logical), */
0x14, /* Logical Minimum (0), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x03, /* Report Count (3), */
0x81, 0x01, /* Input (Constant), */
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x95, 0x02, /* Report Count (2), */
0x09, 0x30, /* Usage (X), */
0x09, 0x31, /* Usage (Y), */
0x81, 0x02, /* Input (Variable), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x04, /* Report Count (4), */
0x81, 0x01, /* Input (Constant), */
0x25, 0x01, /* Logical Maximum (1), */
0x95, 0x0A, /* Report Count (10), */
0x05, 0x09, /* Usage Page (Button), */
0x19, 0x01, /* Usage Minimum (01h), */
0x29, 0x0A, /* Usage Maximum (0Ah), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x0A, /* Report Count (10), */
0x81, 0x01, /* Input (Constant), */
0xC0, /* End Collection, */
0xC0 /* End Collection */
};
static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
switch (hdev->product) {
case 0x0011:
if (*rsize == PID0011_RDESC_ORIG_SIZE) {
rdesc = pid0011_rdesc_fixed;
*rsize = sizeof(pid0011_rdesc_fixed);
}
break;
}
return rdesc;
}
static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id) static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
{ {
int ret; int ret;
...@@ -163,7 +267,16 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -163,7 +267,16 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err; goto err;
} }
drff_init(hdev); switch (hdev->product) {
case 0x0006:
ret = drff_init(hdev);
if (ret) {
dev_err(&hdev->dev, "force feedback init failed\n");
hid_hw_stop(hdev);
goto err;
}
break;
}
return 0; return 0;
err: err:
...@@ -172,6 +285,7 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -172,6 +285,7 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
static const struct hid_device_id dr_devices[] = { static const struct hid_device_id dr_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006), }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006), },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011), },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, dr_devices); MODULE_DEVICE_TABLE(hid, dr_devices);
...@@ -179,6 +293,7 @@ MODULE_DEVICE_TABLE(hid, dr_devices); ...@@ -179,6 +293,7 @@ MODULE_DEVICE_TABLE(hid, dr_devices);
static struct hid_driver dr_driver = { static struct hid_driver dr_driver = {
.name = "dragonrise", .name = "dragonrise",
.id_table = dr_devices, .id_table = dr_devices,
.report_fixup = dr_report_fixup,
.probe = dr_probe, .probe = dr_probe,
}; };
......
/*
* HID driver for eGalax dual-touch panels
*
* Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
* Copyright (c) 2010 Canonical, Ltd.
*
*/
/*
* 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/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/input/mt.h>
#include <linux/slab.h>
#include "usbhid/usbhid.h"
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_DESCRIPTION("eGalax dual-touch panel");
MODULE_LICENSE("GPL");
#include "hid-ids.h"
#define MAX_SLOTS 2
/* estimated signal-to-noise ratios */
#define SN_MOVE 4096
#define SN_PRESSURE 32
struct egalax_data {
int valid;
int slot;
int touch;
int x, y, z;
};
static void set_abs(struct input_dev *input, unsigned int code,
struct hid_field *field, int snratio)
{
int fmin = field->logical_minimum;
int fmax = field->logical_maximum;
int fuzz = snratio ? (fmax - fmin) / snratio : 0;
input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
}
static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
struct input_dev *input = hi->input;
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
set_abs(input, ABS_MT_POSITION_X, field, SN_MOVE);
/* touchscreen emulation */
set_abs(input, ABS_X, field, SN_MOVE);
return 1;
case HID_GD_Y:
field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
set_abs(input, ABS_MT_POSITION_Y, field, SN_MOVE);
/* touchscreen emulation */
set_abs(input, ABS_Y, field, SN_MOVE);
return 1;
}
return 0;
case HID_UP_DIGITIZER:
switch (usage->hid) {
case HID_DG_TIPSWITCH:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(input, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_INRANGE:
case HID_DG_CONFIDENCE:
case HID_DG_CONTACTCOUNT:
case HID_DG_CONTACTMAX:
return -1;
case HID_DG_CONTACTID:
input_mt_init_slots(input, MAX_SLOTS);
return 1;
case HID_DG_TIPPRESSURE:
field->logical_minimum = 0;
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_PRESSURE);
set_abs(input, ABS_MT_PRESSURE, field, SN_PRESSURE);
/* touchscreen emulation */
set_abs(input, ABS_PRESSURE, field, SN_PRESSURE);
return 1;
}
return 0;
}
/* ignore others (from other reports we won't get anyway) */
return -1;
}
static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
/* tell hid-input to skip setup of these event types */
if (usage->type == EV_KEY || usage->type == EV_ABS)
set_bit(usage->type, hi->input->evbit);
return -1;
}
/*
* this function is called when a whole finger has been parsed,
* so that it can decide what to send to the input layer.
*/
static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
{
input_mt_slot(input, td->slot);
input_mt_report_slot_state(input, MT_TOOL_FINGER, td->touch);
if (td->touch) {
input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z);
}
input_mt_report_pointer_emulation(input, true);
}
static int egalax_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct egalax_data *td = hid_get_drvdata(hid);
/* Note, eGalax has two product lines: the first is resistive and
* uses a standard parallel multitouch protocol (product ID ==
* 48xx). The second is capacitive and uses an unusual "serial"
* protocol with a different message for each multitouch finger
* (product ID == 72xx).
*/
if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input;
switch (usage->hid) {
case HID_DG_INRANGE:
td->valid = value;
break;
case HID_DG_CONFIDENCE:
/* avoid interference from generic hidinput handling */
break;
case HID_DG_TIPSWITCH:
td->touch = value;
break;
case HID_DG_TIPPRESSURE:
td->z = value;
break;
case HID_DG_CONTACTID:
td->slot = clamp_val(value, 0, MAX_SLOTS - 1);
break;
case HID_GD_X:
td->x = value;
break;
case HID_GD_Y:
td->y = value;
/* this is the last field in a finger */
if (td->valid)
egalax_filter_event(td, input);
break;
case HID_DG_CONTACTCOUNT:
/* touch emulation: this is the last field in a frame */
break;
default:
/* fallback to the generic hidinput handling */
return 0;
}
}
/* we have handled the hidinput part, now remains hiddev */
if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
hid->hiddev_hid_event(hid, field, usage, value);
return 1;
}
static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
struct egalax_data *td;
struct hid_report *report;
td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL);
if (!td) {
hid_err(hdev, "cannot allocate eGalax data\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, td);
ret = hid_parse(hdev);
if (ret)
goto end;
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
goto end;
report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[5];
if (report) {
report->field[0]->value[0] = 2;
usbhid_submit_report(hdev, report, USB_DIR_OUT);
}
end:
if (ret)
kfree(td);
return ret;
}
static void egalax_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
kfree(hid_get_drvdata(hdev));
hid_set_drvdata(hdev, NULL);
}
static const struct hid_device_id egalax_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
{ }
};
MODULE_DEVICE_TABLE(hid, egalax_devices);
static const struct hid_usage_id egalax_grabbed_usages[] = {
{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
};
static struct hid_driver egalax_driver = {
.name = "egalax-touch",
.id_table = egalax_devices,
.probe = egalax_probe,
.remove = egalax_remove,
.input_mapping = egalax_input_mapping,
.input_mapped = egalax_input_mapped,
.usage_table = egalax_grabbed_usages,
.event = egalax_event,
};
static int __init egalax_init(void)
{
return hid_register_driver(&egalax_driver);
}
static void __exit egalax_exit(void)
{
hid_unregister_driver(&egalax_driver);
}
module_init(egalax_init);
module_exit(egalax_exit);
...@@ -43,6 +43,11 @@ static int gyration_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -43,6 +43,11 @@ static int gyration_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case 0x048: gy_map_key_clear(KEY_MEDIA); break; case 0x048: gy_map_key_clear(KEY_MEDIA); break;
case 0x049: gy_map_key_clear(KEY_CAMERA); break; case 0x049: gy_map_key_clear(KEY_CAMERA); break;
case 0x04a: gy_map_key_clear(KEY_VIDEO); break; case 0x04a: gy_map_key_clear(KEY_VIDEO); break;
case 0x05a: gy_map_key_clear(KEY_TEXT); break;
case 0x05b: gy_map_key_clear(KEY_RED); break;
case 0x05c: gy_map_key_clear(KEY_GREEN); break;
case 0x05d: gy_map_key_clear(KEY_YELLOW); break;
case 0x05e: gy_map_key_clear(KEY_BLUE); break;
default: default:
return 0; return 0;
......
...@@ -333,6 +333,9 @@ ...@@ -333,6 +333,9 @@
#define USB_VENDOR_ID_IMATION 0x0718 #define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000 #define USB_DEVICE_ID_DISC_STAKKA 0xd000
#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
#define USB_VENDOR_ID_JESS 0x0c45 #define USB_VENDOR_ID_JESS 0x0c45
#define USB_DEVICE_ID_JESS_YUREX 0x1010 #define USB_DEVICE_ID_JESS_YUREX 0x1010
...@@ -345,6 +348,9 @@ ...@@ -345,6 +348,9 @@
#define USB_VENDOR_ID_KWORLD 0x1b80 #define USB_VENDOR_ID_KWORLD 0x1b80
#define USB_DEVICE_ID_KWORLD_RADIO_FM700 0xd700 #define USB_DEVICE_ID_KWORLD_RADIO_FM700 0xd700
#define USB_VENDOR_ID_KEYTOUCH 0x0926
#define USB_DEVICE_ID_KEYTOUCH_IEC 0x3333
#define USB_VENDOR_ID_KYE 0x0458 #define USB_VENDOR_ID_KYE 0x0458
#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087 #define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
#define USB_DEVICE_ID_KYE_GPEN_560 0x5003 #define USB_DEVICE_ID_KYE_GPEN_560 0x5003
...@@ -352,6 +358,9 @@ ...@@ -352,6 +358,9 @@
#define USB_VENDOR_ID_LABTEC 0x1020 #define USB_VENDOR_ID_LABTEC 0x1020
#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006 #define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
#define USB_VENDOR_ID_LCPOWER 0x1241
#define USB_DEVICE_ID_LCPOWER_LC1000 0xf767
#define USB_VENDOR_ID_LD 0x0f11 #define USB_VENDOR_ID_LD 0x0f11
#define USB_DEVICE_ID_LD_CASSY 0x1000 #define USB_DEVICE_ID_LD_CASSY 0x1000
#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010 #define USB_DEVICE_ID_LD_POCKETCASSY 0x1010
...@@ -383,6 +392,7 @@ ...@@ -383,6 +392,7 @@
#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293 #define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299 #define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c #define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a #define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
...@@ -466,6 +476,7 @@ ...@@ -466,6 +476,7 @@
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 #define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
#define USB_VENDOR_ID_ORTEK 0x05a4 #define USB_VENDOR_ID_ORTEK 0x05a4
#define USB_DEVICE_ID_ORTEK_PKB1700 0x1700
#define USB_DEVICE_ID_ORTEK_WKB2000 0x2000 #define USB_DEVICE_ID_ORTEK_WKB2000 0x2000
#define USB_VENDOR_ID_PANJIT 0x134c #define USB_VENDOR_ID_PANJIT 0x134c
...@@ -496,8 +507,10 @@ ...@@ -496,8 +507,10 @@
#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001 #define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001
#define USB_VENDOR_ID_ROCCAT 0x1e7d #define USB_VENDOR_ID_ROCCAT 0x1e7d
#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced #define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51 #define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24 #define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6 #define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
......
...@@ -290,14 +290,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -290,14 +290,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
goto ignore; goto ignore;
} }
if (field->report_type == HID_FEATURE_REPORT) {
if (device->driver->feature_mapping) {
device->driver->feature_mapping(device, hidinput, field,
usage);
}
goto ignore;
}
if (device->driver->input_mapping) { if (device->driver->input_mapping) {
int ret = device->driver->input_mapping(device, hidinput, field, int ret = device->driver->input_mapping(device, hidinput, field,
usage, &bit, &max); usage, &bit, &max);
...@@ -835,6 +827,24 @@ static void hidinput_close(struct input_dev *dev) ...@@ -835,6 +827,24 @@ static void hidinput_close(struct input_dev *dev)
hid_hw_close(hid); hid_hw_close(hid);
} }
static void report_features(struct hid_device *hid)
{
struct hid_driver *drv = hid->driver;
struct hid_report_enum *rep_enum;
struct hid_report *rep;
int i, j;
if (!drv->feature_mapping)
return;
rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(rep, &rep_enum->report_list, list)
for (i = 0; i < rep->maxfield; i++)
for (j = 0; j < rep->field[i]->maxusage; j++)
drv->feature_mapping(hid, rep->field[i],
rep->field[i]->usage + j);
}
/* /*
* Register the input device; print a message. * Register the input device; print a message.
* Configure the input layer interface * Configure the input layer interface
...@@ -863,7 +873,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -863,7 +873,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
return -1; return -1;
} }
for (k = HID_INPUT_REPORT; k <= HID_FEATURE_REPORT; k++) { report_features(hid);
for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
if (k == HID_OUTPUT_REPORT && if (k == HID_OUTPUT_REPORT &&
hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
continue; continue;
...@@ -928,6 +940,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -928,6 +940,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
return 0; return 0;
out_cleanup: out_cleanup:
list_del(&hidinput->list);
input_free_device(hidinput->input); input_free_device(hidinput->input);
kfree(hidinput); kfree(hidinput);
out_unwind: out_unwind:
......
/*
* HID driver for Keytouch devices not fully compliant with HID standard
*
* Copyright (c) 2011 Jiri Kosina
*/
/*
* 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/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
/* Replace the broken report descriptor of this device with rather
* a default one */
static __u8 keytouch_fixed_rdesc[] = {
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15,
0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08,
0x81, 0x01, 0x95, 0x03, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91,
0x02, 0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00,
0x26, 0xff, 0x00, 0x05, 0x07, 0x19, 0x00, 0x2a, 0xff, 0x00, 0x81, 0x00, 0xc0
};
static __u8 *keytouch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
hid_info(hdev, "fixing up Keytouch IEC report descriptor\n");
rdesc = keytouch_fixed_rdesc;
*rsize = sizeof(keytouch_fixed_rdesc);
return rdesc;
}
static const struct hid_device_id keytouch_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ }
};
MODULE_DEVICE_TABLE(hid, keytouch_devices);
static struct hid_driver keytouch_driver = {
.name = "keytouch",
.id_table = keytouch_devices,
.report_fixup = keytouch_report_fixup,
};
static int __init keytouch_init(void)
{
return hid_register_driver(&keytouch_driver);
}
static void __exit keytouch_exit(void)
{
hid_unregister_driver(&keytouch_driver);
}
module_init(keytouch_init);
module_exit(keytouch_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jiri Kosina");
/*
* HID driver for LC Power Model RC1000MCE
*
* Copyright (c) 2011 Chris Schlund
* based on hid-topseed module
*/
/*
* 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/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
#define ts_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
EV_KEY, (c))
static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
if ((usage->hid & HID_USAGE_PAGE) != 0x0ffbc0000)
return 0;
switch (usage->hid & HID_USAGE) {
case 0x046: ts_map_key_clear(KEY_YELLOW); break;
case 0x047: ts_map_key_clear(KEY_GREEN); break;
case 0x049: ts_map_key_clear(KEY_BLUE); break;
case 0x04a: ts_map_key_clear(KEY_RED); break;
case 0x00d: ts_map_key_clear(KEY_HOME); break;
case 0x025: ts_map_key_clear(KEY_TV); break;
case 0x048: ts_map_key_clear(KEY_VCR); break;
case 0x024: ts_map_key_clear(KEY_MENU); break;
default:
return 0;
}
return 1;
}
static const struct hid_device_id ts_devices[] = {
{ HID_USB_DEVICE( USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000) },
{ }
};
MODULE_DEVICE_TABLE(hid, ts_devices);
static struct hid_driver ts_driver = {
.name = "LC RC1000MCE",
.id_table = ts_devices,
.input_mapping = ts_input_mapping,
};
static int __init ts_init(void)
{
return hid_register_driver(&ts_driver);
}
static void __exit ts_exit(void)
{
hid_unregister_driver(&ts_driver);
}
module_init(ts_init);
module_exit(ts_exit);
MODULE_LICENSE("GPL");
...@@ -377,6 +377,8 @@ static const struct hid_device_id lg_devices[] = { ...@@ -377,6 +377,8 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_FF }, .driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
.driver_data = LG_FF }, .driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
.driver_data = LG_FF4 }, .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
......
...@@ -258,7 +258,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda ...@@ -258,7 +258,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
input_report_abs(input, ABS_MT_TRACKING_ID, id); input_report_abs(input, ABS_MT_TRACKING_ID, id);
input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2); input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2);
input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2); input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2);
input_report_abs(input, ABS_MT_ORIENTATION, orientation); input_report_abs(input, ABS_MT_ORIENTATION, -orientation);
input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y); input_report_abs(input, ABS_MT_POSITION_Y, y);
...@@ -397,7 +397,7 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h ...@@ -397,7 +397,7 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0); input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0); input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0); input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0);
input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0); input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
/* Note: Touch Y position from the device is inverted relative /* Note: Touch Y position from the device is inverted relative
* to how pointer motion is reported (and relative to how USB * to how pointer motion is reported (and relative to how USB
......
...@@ -5,6 +5,12 @@ ...@@ -5,6 +5,12 @@
* Copyright (c) 2010-2011 Benjamin Tissoires <benjamin.tissoires@gmail.com> * Copyright (c) 2010-2011 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2010-2011 Ecole Nationale de l'Aviation Civile, France * Copyright (c) 2010-2011 Ecole Nationale de l'Aviation Civile, France
* *
* This code is partly based on hid-egalax.c:
*
* Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
* Copyright (c) 2010 Canonical, Ltd.
*
*/ */
/* /*
...@@ -24,6 +30,7 @@ ...@@ -24,6 +30,7 @@
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
MODULE_DESCRIPTION("HID multitouch panels"); MODULE_DESCRIPTION("HID multitouch panels");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -36,6 +43,7 @@ MODULE_LICENSE("GPL"); ...@@ -36,6 +43,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3) #define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
#define MT_QUIRK_VALID_IS_INRANGE (1 << 4) #define MT_QUIRK_VALID_IS_INRANGE (1 << 4)
#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5) #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5)
#define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 6)
struct mt_slot { struct mt_slot {
__s32 x, y, p, w, h; __s32 x, y, p, w, h;
...@@ -65,10 +73,11 @@ struct mt_class { ...@@ -65,10 +73,11 @@ struct mt_class {
}; };
/* classes of device behavior */ /* classes of device behavior */
#define MT_CLS_DEFAULT 1 #define MT_CLS_DEFAULT 1
#define MT_CLS_DUAL1 2 #define MT_CLS_DUAL_INRANGE_CONTACTID 2
#define MT_CLS_DUAL2 3 #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 3
#define MT_CLS_CYPRESS 4 #define MT_CLS_CYPRESS 4
#define MT_CLS_EGALAX 5
/* /*
* these device-dependent functions determine what slot corresponds * these device-dependent functions determine what slot corresponds
...@@ -104,13 +113,13 @@ static int find_slot_from_contactid(struct mt_device *td) ...@@ -104,13 +113,13 @@ static int find_slot_from_contactid(struct mt_device *td)
struct mt_class mt_classes[] = { struct mt_class mt_classes[] = {
{ .name = MT_CLS_DEFAULT, { .name = MT_CLS_DEFAULT,
.quirks = MT_QUIRK_VALID_IS_INRANGE, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
.maxcontacts = 10 }, .maxcontacts = 10 },
{ .name = MT_CLS_DUAL1, { .name = MT_CLS_DUAL_INRANGE_CONTACTID,
.quirks = MT_QUIRK_VALID_IS_INRANGE | .quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTID, MT_QUIRK_SLOT_IS_CONTACTID,
.maxcontacts = 2 }, .maxcontacts = 2 },
{ .name = MT_CLS_DUAL2, { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
.quirks = MT_QUIRK_VALID_IS_INRANGE | .quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTNUMBER, MT_QUIRK_SLOT_IS_CONTACTNUMBER,
.maxcontacts = 2 }, .maxcontacts = 2 },
...@@ -119,10 +128,18 @@ struct mt_class mt_classes[] = { ...@@ -119,10 +128,18 @@ struct mt_class mt_classes[] = {
MT_QUIRK_CYPRESS, MT_QUIRK_CYPRESS,
.maxcontacts = 10 }, .maxcontacts = 10 },
{ .name = MT_CLS_EGALAX,
.quirks = MT_QUIRK_SLOT_IS_CONTACTID |
MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_EGALAX_XYZ_FIXUP,
.maxcontacts = 2,
.sn_move = 4096,
.sn_pressure = 32,
},
{ } { }
}; };
static void mt_feature_mapping(struct hid_device *hdev, struct hid_input *hi, static void mt_feature_mapping(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage) struct hid_field *field, struct hid_usage *usage)
{ {
if (usage->hid == HID_DG_INPUTMODE) { if (usage->hid == HID_DG_INPUTMODE) {
...@@ -146,11 +163,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -146,11 +163,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
{ {
struct mt_device *td = hid_get_drvdata(hdev); struct mt_device *td = hid_get_drvdata(hdev);
struct mt_class *cls = td->mtclass; struct mt_class *cls = td->mtclass;
__s32 quirks = cls->quirks;
switch (usage->hid & HID_USAGE_PAGE) { switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK: case HID_UP_GENDESK:
switch (usage->hid) { switch (usage->hid) {
case HID_GD_X: case HID_GD_X:
if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X); EV_ABS, ABS_MT_POSITION_X);
set_abs(hi->input, ABS_MT_POSITION_X, field, set_abs(hi->input, ABS_MT_POSITION_X, field,
...@@ -160,6 +181,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -160,6 +181,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
return 1; return 1;
case HID_GD_Y: case HID_GD_Y:
if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
field->logical_maximum = 32760;
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y); EV_ABS, ABS_MT_POSITION_Y);
set_abs(hi->input, ABS_MT_POSITION_Y, field, set_abs(hi->input, ABS_MT_POSITION_Y, field,
...@@ -203,6 +226,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -203,6 +226,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
return 1; return 1;
case HID_DG_TIPPRESSURE: case HID_DG_TIPPRESSURE:
if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
field->logical_minimum = 0;
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_PRESSURE); EV_ABS, ABS_MT_PRESSURE);
set_abs(hi->input, ABS_MT_PRESSURE, field, set_abs(hi->input, ABS_MT_PRESSURE, field,
...@@ -363,8 +388,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, ...@@ -363,8 +388,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
return 0; return 0;
} }
if (usage->hid == td->last_slot_field) if (usage->hid == td->last_slot_field) {
mt_complete_slot(td); mt_complete_slot(td);
if (!td->last_field_index)
mt_emit_event(td, field->hidinput->input);
}
if (field->index == td->last_field_index if (field->index == td->last_field_index
&& td->num_received >= td->num_expected) && td->num_received >= td->num_expected)
...@@ -466,18 +494,42 @@ static const struct hid_device_id mt_devices[] = { ...@@ -466,18 +494,42 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
/* GeneralTouch panel */ /* GeneralTouch panel */
{ .driver_data = MT_CLS_DUAL2, { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
/* IRTOUCH panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
/* PixCir-based panels */ /* PixCir-based panels */
{ .driver_data = MT_CLS_DUAL1, { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
HID_USB_DEVICE(USB_VENDOR_ID_HANVON, HID_USB_DEVICE(USB_VENDOR_ID_HANVON,
USB_DEVICE_ID_HANVON_MULTITOUCH) }, USB_DEVICE_ID_HANVON_MULTITOUCH) },
{ .driver_data = MT_CLS_DUAL1, { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
HID_USB_DEVICE(USB_VENDOR_ID_CANDO, HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
/* Resistive eGalax devices */
{ .driver_data = MT_CLS_EGALAX,
HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
{ .driver_data = MT_CLS_EGALAX,
HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
/* Capacitive eGalax devices */
{ .driver_data = MT_CLS_EGALAX,
HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
{ .driver_data = MT_CLS_EGALAX,
HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
{ .driver_data = MT_CLS_EGALAX,
HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, mt_devices); MODULE_DEVICE_TABLE(hid, mt_devices);
......
This diff is collapsed.
/* /*
* HID driver for Ortek WKB-2000 (wireless keyboard + mouse trackpad). * HID driver for Ortek PKB-1700/WKB-2000 (wireless keyboard + mouse trackpad).
* Fixes LogicalMaximum error in USB report description, see * Fixes LogicalMaximum error in HID report description.
* http://bugzilla.kernel.org/show_bug.cgi?id=14787
* *
* Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com> * Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
*/ */
...@@ -30,6 +29,7 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -30,6 +29,7 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
} }
static const struct hid_device_id ortek_devices[] = { static const struct hid_device_id ortek_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ } { }
}; };
......
This diff is collapsed.
#ifndef __HID_ROCCAT_ARVO_H
#define __HID_ROCCAT_ARVO_H
/*
* Copyright (c) 2011 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>
struct arvo_mode_key { /* 2 bytes */
uint8_t command; /* ARVO_COMMAND_MODE_KEY */
uint8_t state;
} __packed;
struct arvo_button {
uint8_t unknown[24];
} __packed;
struct arvo_info {
uint8_t unknown[8];
} __packed;
struct arvo_key_mask { /* 2 bytes */
uint8_t command; /* ARVO_COMMAND_KEY_MASK */
uint8_t key_mask;
} __packed;
/* selected profile is persistent */
struct arvo_actual_profile { /* 2 bytes */
uint8_t command; /* ARVO_COMMAND_ACTUAL_PROFILE */
uint8_t actual_profile;
} __packed;
enum arvo_commands {
ARVO_COMMAND_MODE_KEY = 0x3,
ARVO_COMMAND_BUTTON = 0x4,
ARVO_COMMAND_INFO = 0x5,
ARVO_COMMAND_KEY_MASK = 0x6,
ARVO_COMMAND_ACTUAL_PROFILE = 0x7,
};
enum arvo_usb_commands {
ARVO_USB_COMMAND_MODE_KEY = 0x303,
/*
* read/write
* Read uses both index bytes as profile/key indexes
* Write has index 0, profile/key is determined by payload
*/
ARVO_USB_COMMAND_BUTTON = 0x304,
ARVO_USB_COMMAND_INFO = 0x305,
ARVO_USB_COMMAND_KEY_MASK = 0x306,
ARVO_USB_COMMAND_ACTUAL_PROFILE = 0x307,
};
struct arvo_special_report {
uint8_t unknown1; /* always 0x01 */
uint8_t event;
uint8_t unknown2; /* always 0x70 */
} __packed;
enum arvo_special_report_events {
ARVO_SPECIAL_REPORT_EVENT_ACTION_PRESS = 0x10,
ARVO_SPECIAL_REPORT_EVENT_ACTION_RELEASE = 0x0,
};
enum arvo_special_report_event_masks {
ARVO_SPECIAL_REPORT_EVENT_MASK_ACTION = 0xf0,
ARVO_SPECIAL_REPORT_EVENT_MASK_BUTTON = 0x0f,
};
struct arvo_roccat_report {
uint8_t profile;
uint8_t button;
uint8_t action;
} __packed;
enum arvo_roccat_report_action {
ARVO_ROCCAT_REPORT_ACTION_RELEASE = 0,
ARVO_ROCCAT_REPORT_ACTION_PRESS = 1,
};
struct arvo_device {
int roccat_claimed;
int chrdev_minor;
struct mutex arvo_lock;
int actual_profile;
};
#endif
/*
* Roccat common functions for device specific drivers
*
* Copyright (c) 2011 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/slab.h>
#include "hid-roccat-common.h"
int roccat_common_receive(struct usb_device *usb_dev, uint usb_command,
void *data, uint size)
{
char *buf;
int len;
buf = kmalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
USB_REQ_CLEAR_FEATURE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
memcpy(data, buf, size);
kfree(buf);
return ((len < 0) ? len : ((len != size) ? -EIO : 0));
}
EXPORT_SYMBOL_GPL(roccat_common_receive);
int roccat_common_send(struct usb_device *usb_dev, uint usb_command,
void const *data, uint size)
{
char *buf;
int len;
buf = kmalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
memcpy(buf, data, size);
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
USB_REQ_SET_CONFIGURATION,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
kfree(buf);
return ((len < 0) ? len : ((len != size) ? -EIO : 0));
}
EXPORT_SYMBOL_GPL(roccat_common_send);
MODULE_AUTHOR("Stefan Achatz");
MODULE_DESCRIPTION("USB Roccat common driver");
MODULE_LICENSE("GPL v2");
#ifndef __HID_ROCCAT_COMMON_H
#define __HID_ROCCAT_COMMON_H
/*
* Copyright (c) 2011 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/usb.h>
#include <linux/types.h>
int roccat_common_receive(struct usb_device *usb_dev, uint usb_command,
void *data, uint size);
int roccat_common_send(struct usb_device *usb_dev, uint usb_command,
void const *data, uint size);
#endif
...@@ -28,11 +28,11 @@ ...@@ -28,11 +28,11 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/hid-roccat.h>
#include "hid-ids.h" #include "hid-ids.h"
#include "hid-roccat.h" #include "hid-roccat-common.h"
#include "hid-roccat-kone.h" #include "hid-roccat-kone.h"
static uint profile_numbers[5] = {0, 1, 2, 3, 4}; static uint profile_numbers[5] = {0, 1, 2, 3, 4};
...@@ -58,12 +58,8 @@ static void kone_set_settings_checksum(struct kone_settings *settings) ...@@ -58,12 +58,8 @@ static void kone_set_settings_checksum(struct kone_settings *settings)
*/ */
static int kone_check_write(struct usb_device *usb_dev) static int kone_check_write(struct usb_device *usb_dev)
{ {
int len; int retval;
unsigned char *data; uint8_t data;
data = kmalloc(1, GFP_KERNEL);
if (!data)
return -ENOMEM;
do { do {
/* /*
...@@ -72,56 +68,36 @@ static int kone_check_write(struct usb_device *usb_dev) ...@@ -72,56 +68,36 @@ static int kone_check_write(struct usb_device *usb_dev)
*/ */
msleep(80); msleep(80);
len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), retval = roccat_common_receive(usb_dev,
USB_REQ_CLEAR_FEATURE, kone_command_confirm_write, &data, 1);
USB_TYPE_CLASS | USB_RECIP_INTERFACE | if (retval)
USB_DIR_IN, return retval;
kone_command_confirm_write, 0, data, 1,
USB_CTRL_SET_TIMEOUT);
if (len != 1) {
kfree(data);
return -EIO;
}
/* /*
* value of 3 seems to mean something like * value of 3 seems to mean something like
* "not finished yet, but it looks good" * "not finished yet, but it looks good"
* So check again after a moment. * So check again after a moment.
*/ */
} while (*data == 3); } while (data == 3);
if (*data == 1) { /* everything alright */ if (data == 1) /* everything alright */
kfree(data);
return 0; return 0;
} else { /* unknown answer */
hid_err(usb_dev, "got retval %d when checking write\n", *data); /* unknown answer */
kfree(data); hid_err(usb_dev, "got retval %d when checking write\n", data);
return -EIO; return -EIO;
}
} }
/* /*
* Reads settings from mouse and stores it in @buf * Reads settings from mouse and stores it in @buf
* @buf has to be alloced with GFP_KERNEL
* On success returns 0 * On success returns 0
* On failure returns errno * On failure returns errno
*/ */
static int kone_get_settings(struct usb_device *usb_dev, static int kone_get_settings(struct usb_device *usb_dev,
struct kone_settings *buf) struct kone_settings *buf)
{ {
int len; return roccat_common_receive(usb_dev, kone_command_settings, buf,
sizeof(struct kone_settings));
len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
USB_REQ_CLEAR_FEATURE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
kone_command_settings, 0, buf,
sizeof(struct kone_settings), USB_CTRL_SET_TIMEOUT);
if (len != sizeof(struct kone_settings))
return -EIO;
return 0;
} }
/* /*
...@@ -132,22 +108,12 @@ static int kone_get_settings(struct usb_device *usb_dev, ...@@ -132,22 +108,12 @@ static int kone_get_settings(struct usb_device *usb_dev,
static int kone_set_settings(struct usb_device *usb_dev, static int kone_set_settings(struct usb_device *usb_dev,
struct kone_settings const *settings) struct kone_settings const *settings)
{ {
int len; int retval;
retval = roccat_common_send(usb_dev, kone_command_settings,
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), settings, sizeof(struct kone_settings));
USB_REQ_SET_CONFIGURATION, if (retval)
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, return retval;
kone_command_settings, 0, (char *)settings, return kone_check_write(usb_dev);
sizeof(struct kone_settings),
USB_CTRL_SET_TIMEOUT);
if (len != sizeof(struct kone_settings))
return -EIO;
if (kone_check_write(usb_dev))
return -EIO;
return 0;
} }
/* /*
...@@ -193,7 +159,7 @@ static int kone_set_profile(struct usb_device *usb_dev, ...@@ -193,7 +159,7 @@ static int kone_set_profile(struct usb_device *usb_dev,
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
USB_REQ_SET_CONFIGURATION, USB_REQ_SET_CONFIGURATION,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
kone_command_profile, number, (char *)profile, kone_command_profile, number, (void *)profile,
sizeof(struct kone_profile), sizeof(struct kone_profile),
USB_CTRL_SET_TIMEOUT); USB_CTRL_SET_TIMEOUT);
...@@ -213,24 +179,15 @@ static int kone_set_profile(struct usb_device *usb_dev, ...@@ -213,24 +179,15 @@ static int kone_set_profile(struct usb_device *usb_dev,
*/ */
static int kone_get_weight(struct usb_device *usb_dev, int *result) static int kone_get_weight(struct usb_device *usb_dev, int *result)
{ {
int len; int retval;
uint8_t *data; uint8_t data;
data = kmalloc(1, GFP_KERNEL); retval = roccat_common_receive(usb_dev, kone_command_weight, &data, 1);
if (!data)
return -ENOMEM;
len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), if (retval)
USB_REQ_CLEAR_FEATURE, return retval;
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
kone_command_weight, 0, data, 1, USB_CTRL_SET_TIMEOUT);
if (len != 1) { *result = (int)data;
kfree(data);
return -EIO;
}
*result = (int)*data;
kfree(data);
return 0; return 0;
} }
...@@ -241,25 +198,15 @@ static int kone_get_weight(struct usb_device *usb_dev, int *result) ...@@ -241,25 +198,15 @@ static int kone_get_weight(struct usb_device *usb_dev, int *result)
*/ */
static int kone_get_firmware_version(struct usb_device *usb_dev, int *result) static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
{ {
int len; int retval;
unsigned char *data; uint16_t data;
data = kmalloc(2, GFP_KERNEL);
if (!data)
return -ENOMEM;
len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), retval = roccat_common_receive(usb_dev, kone_command_firmware_version,
USB_REQ_CLEAR_FEATURE, &data, 2);
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, if (retval)
kone_command_firmware_version, 0, data, 2, return retval;
USB_CTRL_SET_TIMEOUT);
if (len != 2) { *result = le16_to_cpu(data);
kfree(data);
return -EIO;
}
*result = le16_to_cpu(*data);
kfree(data);
return 0; return 0;
} }
...@@ -435,23 +382,9 @@ static ssize_t kone_sysfs_show_tcu(struct device *dev, ...@@ -435,23 +382,9 @@ static ssize_t kone_sysfs_show_tcu(struct device *dev,
static int kone_tcu_command(struct usb_device *usb_dev, int number) static int kone_tcu_command(struct usb_device *usb_dev, int number)
{ {
int len; unsigned char value;
char *value; value = number;
return roccat_common_send(usb_dev, kone_command_calibrate, &value, 1);
value = kmalloc(1, GFP_KERNEL);
if (!value)
return -ENOMEM;
*value = number;
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
USB_REQ_SET_CONFIGURATION,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
kone_command_calibrate, 0, value, 1,
USB_CTRL_SET_TIMEOUT);
kfree(value);
return ((len != 1) ? -EIO : 0);
} }
/* /*
...@@ -727,7 +660,8 @@ static int kone_init_specials(struct hid_device *hdev) ...@@ -727,7 +660,8 @@ static int kone_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(kone_class, hdev); retval = roccat_connect(kone_class, hdev,
sizeof(struct kone_roccat_report));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
/* be tolerant about not getting chrdev */ /* be tolerant about not getting chrdev */
...@@ -827,8 +761,7 @@ static void kone_report_to_chrdev(struct kone_device const *kone, ...@@ -827,8 +761,7 @@ static void kone_report_to_chrdev(struct kone_device const *kone,
roccat_report.value = event->value; roccat_report.value = event->value;
roccat_report.key = 0; roccat_report.key = 0;
roccat_report_event(kone->chrdev_minor, roccat_report_event(kone->chrdev_minor,
(uint8_t *)&roccat_report, (uint8_t *)&roccat_report);
sizeof(struct kone_roccat_report));
break; break;
case kone_mouse_event_call_overlong_macro: case kone_mouse_event_call_overlong_macro:
if (event->value == kone_keystroke_action_press) { if (event->value == kone_keystroke_action_press) {
...@@ -836,8 +769,7 @@ static void kone_report_to_chrdev(struct kone_device const *kone, ...@@ -836,8 +769,7 @@ static void kone_report_to_chrdev(struct kone_device const *kone,
roccat_report.value = kone->actual_profile; roccat_report.value = kone->actual_profile;
roccat_report.key = event->macro_key; roccat_report.key = event->macro_key;
roccat_report_event(kone->chrdev_minor, roccat_report_event(kone->chrdev_minor,
(uint8_t *)&roccat_report, (uint8_t *)&roccat_report);
sizeof(struct kone_roccat_report));
} }
break; break;
} }
...@@ -912,8 +844,8 @@ static int __init kone_init(void) ...@@ -912,8 +844,8 @@ static int __init kone_init(void)
static void __exit kone_exit(void) static void __exit kone_exit(void)
{ {
class_destroy(kone_class);
hid_unregister_driver(&kone_driver); hid_unregister_driver(&kone_driver);
class_destroy(kone_class);
} }
module_init(kone_init); module_init(kone_init);
......
This diff is collapsed.
This diff is collapsed.
#ifndef __HID_ROCCAT_KOVAPLUS_H
#define __HID_ROCCAT_KOVAPLUS_H
/*
* Copyright (c) 2010 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>
struct kovaplus_control {
uint8_t command; /* KOVAPLUS_COMMAND_CONTROL */
uint8_t value;
uint8_t request;
} __packed;
enum kovaplus_control_requests {
/* read after write; value = 1 */
KOVAPLUS_CONTROL_REQUEST_STATUS = 0x0,
/* write; value = profile number range 0-4 */
KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10,
/* write; value = profile number range 0-4 */
KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x20,
};
enum kovaplus_control_values {
KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD = 0, /* supposed */
KOVAPLUS_CONTROL_REQUEST_STATUS_OK = 1,
KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT = 3, /* supposed */
};
struct kovaplus_actual_profile {
uint8_t command; /* KOVAPLUS_COMMAND_ACTUAL_PROFILE */
uint8_t size; /* always 3 */
uint8_t actual_profile; /* Range 0-4! */
} __packed;
struct kovaplus_profile_settings {
uint8_t command; /* KOVAPLUS_COMMAND_PROFILE_SETTINGS */
uint8_t size; /* 16 */
uint8_t profile_index; /* range 0-4 */
uint8_t unknown1;
uint8_t sensitivity_x; /* range 1-10 */
uint8_t sensitivity_y; /* range 1-10 */
uint8_t cpi_levels_enabled;
uint8_t cpi_startup_level; /* range 1-4 */
uint8_t data[8];
} __packed;
struct kovaplus_profile_buttons {
uint8_t command; /* KOVAPLUS_COMMAND_PROFILE_BUTTONS */
uint8_t size; /* 23 */
uint8_t profile_index; /* range 0-4 */
uint8_t data[20];
} __packed;
struct kovaplus_info {
uint8_t command; /* KOVAPLUS_COMMAND_INFO */
uint8_t size; /* 6 */
uint8_t firmware_version;
uint8_t unknown[3];
} __packed;
/* writes 1 on plugin */
struct kovaplus_a {
uint8_t command; /* KOVAPLUS_COMMAND_A */
uint8_t size; /* 3 */
uint8_t unknown;
} __packed;
enum kovaplus_commands {
KOVAPLUS_COMMAND_CONTROL = 0x4,
KOVAPLUS_COMMAND_ACTUAL_PROFILE = 0x5,
KOVAPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
KOVAPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
KOVAPLUS_COMMAND_INFO = 0x9,
KOVAPLUS_COMMAND_A = 0xa,
};
enum kovaplus_usb_commands {
KOVAPLUS_USB_COMMAND_CONTROL = 0x304,
KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305,
KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
KOVAPLUS_USB_COMMAND_INFO = 0x309,
KOVAPLUS_USB_COMMAND_A = 0x30a,
};
enum kovaplus_mouse_report_numbers {
KOVAPLUS_MOUSE_REPORT_NUMBER_MOUSE = 1,
KOVAPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2,
KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON = 3,
KOVAPLUS_MOUSE_REPORT_NUMBER_KBD = 4,
};
struct kovaplus_mouse_report_button {
uint8_t report_number; /* KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON */
uint8_t unknown1;
uint8_t type;
uint8_t data1;
uint8_t data2;
} __packed;
enum kovaplus_mouse_report_button_types {
/* data1 = profile_number range 1-5; no release event */
KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1 = 0x20,
/* data1 = profile_number range 1-5; no release event */
KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2 = 0x30,
/* data1 = button_number range 1-18; data2 = action */
KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO = 0x40,
/* data1 = button_number range 1-18; data2 = action */
KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT = 0x50,
/* data1 = button_number range 1-18; data2 = action */
KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH = 0x60,
/* data1 = button_number range 1-18; data2 = action */
KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER = 0x80,
/* data1 = 1 = 400, 2 = 800, 4 = 1600, 7 = 3200; no release event */
KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI = 0xb0,
/* data1 + data2 = sense range 1-10; no release event */
KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY = 0xc0,
/* data1 = type as in profile_buttons; data2 = action */
KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
};
enum kovaplus_mouse_report_button_actions {
KOVAPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS = 0,
KOVAPLUS_MOUSE_REPORT_BUTTON_ACTION_RELEASE = 1,
};
struct kovaplus_roccat_report {
uint8_t type;
uint8_t profile;
uint8_t button;
uint8_t data1;
uint8_t data2;
} __packed;
struct kovaplus_device {
int actual_profile;
int actual_cpi;
int actual_x_sensitivity;
int actual_y_sensitivity;
int roccat_claimed;
int chrdev_minor;
struct mutex kovaplus_lock;
struct kovaplus_info info;
struct kovaplus_profile_settings profile_settings[5];
struct kovaplus_profile_buttons profile_buttons[5];
};
#endif
...@@ -20,11 +20,11 @@ ...@@ -20,11 +20,11 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/hid-roccat.h>
#include "hid-ids.h" #include "hid-ids.h"
#include "hid-roccat.h" #include "hid-roccat-common.h"
#include "hid-roccat-pyra.h" #include "hid-roccat-pyra.h"
static uint profile_numbers[5] = {0, 1, 2, 3, 4}; static uint profile_numbers[5] = {0, 1, 2, 3, 4};
...@@ -42,7 +42,6 @@ static void profile_activated(struct pyra_device *pyra, ...@@ -42,7 +42,6 @@ static void profile_activated(struct pyra_device *pyra,
static int pyra_send_control(struct usb_device *usb_dev, int value, static int pyra_send_control(struct usb_device *usb_dev, int value,
enum pyra_control_requests request) enum pyra_control_requests request)
{ {
int len;
struct pyra_control control; struct pyra_control control;
if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS || if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS ||
...@@ -54,47 +53,31 @@ static int pyra_send_control(struct usb_device *usb_dev, int value, ...@@ -54,47 +53,31 @@ static int pyra_send_control(struct usb_device *usb_dev, int value,
control.value = value; control.value = value;
control.request = request; control.request = request;
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), return roccat_common_send(usb_dev, PYRA_USB_COMMAND_CONTROL,
USB_REQ_SET_CONFIGURATION, &control, sizeof(struct pyra_control));
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
PYRA_USB_COMMAND_CONTROL, 0, (char *)&control,
sizeof(struct pyra_control),
USB_CTRL_SET_TIMEOUT);
if (len != sizeof(struct pyra_control))
return len;
return 0;
} }
static int pyra_receive_control_status(struct usb_device *usb_dev) static int pyra_receive_control_status(struct usb_device *usb_dev)
{ {
int len; int retval;
struct pyra_control control; struct pyra_control control;
do { do {
msleep(10); msleep(10);
retval = roccat_common_receive(usb_dev, PYRA_USB_COMMAND_CONTROL,
len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), &control, sizeof(struct pyra_control));
USB_REQ_CLEAR_FEATURE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE |
USB_DIR_IN,
PYRA_USB_COMMAND_CONTROL, 0, (char *)&control,
sizeof(struct pyra_control),
USB_CTRL_SET_TIMEOUT);
/* requested too early, try again */ /* requested too early, try again */
} while (len == -EPROTO); } while (retval == -EPROTO);
if (len == sizeof(struct pyra_control) && if (!retval && control.command == PYRA_COMMAND_CONTROL &&
control.command == PYRA_COMMAND_CONTROL &&
control.request == PYRA_CONTROL_REQUEST_STATUS && control.request == PYRA_CONTROL_REQUEST_STATUS &&
control.value == 1) control.value == 1)
return 0; return 0;
else { else {
hid_err(usb_dev, "receive control status: unknown response 0x%x 0x%x\n", hid_err(usb_dev, "receive control status: unknown response 0x%x 0x%x\n",
control.request, control.value); control.request, control.value);
return -EINVAL; return retval ? retval : -EINVAL;
} }
} }
...@@ -102,125 +85,72 @@ static int pyra_get_profile_settings(struct usb_device *usb_dev, ...@@ -102,125 +85,72 @@ static int pyra_get_profile_settings(struct usb_device *usb_dev,
struct pyra_profile_settings *buf, int number) struct pyra_profile_settings *buf, int number)
{ {
int retval; int retval;
retval = pyra_send_control(usb_dev, number, retval = pyra_send_control(usb_dev, number,
PYRA_CONTROL_REQUEST_PROFILE_SETTINGS); PYRA_CONTROL_REQUEST_PROFILE_SETTINGS);
if (retval) if (retval)
return retval; return retval;
return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS,
retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), buf, sizeof(struct pyra_profile_settings));
USB_REQ_CLEAR_FEATURE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)buf,
sizeof(struct pyra_profile_settings),
USB_CTRL_SET_TIMEOUT);
if (retval != sizeof(struct pyra_profile_settings))
return retval;
return 0;
} }
static int pyra_get_profile_buttons(struct usb_device *usb_dev, static int pyra_get_profile_buttons(struct usb_device *usb_dev,
struct pyra_profile_buttons *buf, int number) struct pyra_profile_buttons *buf, int number)
{ {
int retval; int retval;
retval = pyra_send_control(usb_dev, number, retval = pyra_send_control(usb_dev, number,
PYRA_CONTROL_REQUEST_PROFILE_BUTTONS); PYRA_CONTROL_REQUEST_PROFILE_BUTTONS);
if (retval) if (retval)
return retval; return retval;
return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS,
retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), buf, sizeof(struct pyra_profile_buttons));
USB_REQ_CLEAR_FEATURE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buf,
sizeof(struct pyra_profile_buttons),
USB_CTRL_SET_TIMEOUT);
if (retval != sizeof(struct pyra_profile_buttons))
return retval;
return 0;
} }
static int pyra_get_settings(struct usb_device *usb_dev, static int pyra_get_settings(struct usb_device *usb_dev,
struct pyra_settings *buf) struct pyra_settings *buf)
{ {
int len; return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_SETTINGS,
len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), buf, sizeof(struct pyra_settings));
USB_REQ_CLEAR_FEATURE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
PYRA_USB_COMMAND_SETTINGS, 0, buf,
sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT);
if (len != sizeof(struct pyra_settings))
return -EIO;
return 0;
} }
static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf) static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf)
{ {
int len; return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_INFO,
len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), buf, sizeof(struct pyra_info));
USB_REQ_CLEAR_FEATURE, }
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
PYRA_USB_COMMAND_INFO, 0, buf, static int pyra_send(struct usb_device *usb_dev, uint command,
sizeof(struct pyra_info), USB_CTRL_SET_TIMEOUT); void const *buf, uint size)
if (len != sizeof(struct pyra_info)) {
return -EIO; int retval;
return 0; retval = roccat_common_send(usb_dev, command, buf, size);
if (retval)
return retval;
return pyra_receive_control_status(usb_dev);
} }
static int pyra_set_profile_settings(struct usb_device *usb_dev, static int pyra_set_profile_settings(struct usb_device *usb_dev,
struct pyra_profile_settings const *settings) struct pyra_profile_settings const *settings)
{ {
int len; return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS, settings,
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), sizeof(struct pyra_profile_settings));
USB_REQ_SET_CONFIGURATION,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)settings,
sizeof(struct pyra_profile_settings),
USB_CTRL_SET_TIMEOUT);
if (len != sizeof(struct pyra_profile_settings))
return -EIO;
if (pyra_receive_control_status(usb_dev))
return -EIO;
return 0;
} }
static int pyra_set_profile_buttons(struct usb_device *usb_dev, static int pyra_set_profile_buttons(struct usb_device *usb_dev,
struct pyra_profile_buttons const *buttons) struct pyra_profile_buttons const *buttons)
{ {
int len; return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS, buttons,
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), sizeof(struct pyra_profile_buttons));
USB_REQ_SET_CONFIGURATION,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buttons,
sizeof(struct pyra_profile_buttons),
USB_CTRL_SET_TIMEOUT);
if (len != sizeof(struct pyra_profile_buttons))
return -EIO;
if (pyra_receive_control_status(usb_dev))
return -EIO;
return 0;
} }
static int pyra_set_settings(struct usb_device *usb_dev, static int pyra_set_settings(struct usb_device *usb_dev,
struct pyra_settings const *settings) struct pyra_settings const *settings)
{ {
int len; int retval;
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), retval = roccat_common_send(usb_dev, PYRA_USB_COMMAND_SETTINGS, settings,
USB_REQ_SET_CONFIGURATION, sizeof(struct pyra_settings));
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, if (retval)
PYRA_USB_COMMAND_SETTINGS, 0, (char *)settings, return retval;
sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT); return pyra_receive_control_status(usb_dev);
if (len != sizeof(struct pyra_settings))
return -EIO;
if (pyra_receive_control_status(usb_dev))
return -EIO;
return 0;
} }
static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp, static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
...@@ -521,21 +451,16 @@ static struct bin_attribute pyra_bin_attributes[] = { ...@@ -521,21 +451,16 @@ static struct bin_attribute pyra_bin_attributes[] = {
static int pyra_init_pyra_device_struct(struct usb_device *usb_dev, static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
struct pyra_device *pyra) struct pyra_device *pyra)
{ {
struct pyra_info *info; struct pyra_info info;
int retval, i; int retval, i;
mutex_init(&pyra->pyra_lock); mutex_init(&pyra->pyra_lock);
info = kmalloc(sizeof(struct pyra_info), GFP_KERNEL); retval = pyra_get_info(usb_dev, &info);
if (!info) if (retval)
return -ENOMEM;
retval = pyra_get_info(usb_dev, info);
if (retval) {
kfree(info);
return retval; return retval;
}
pyra->firmware_version = info->firmware_version; pyra->firmware_version = info.firmware_version;
kfree(info);
retval = pyra_get_settings(usb_dev, &pyra->settings); retval = pyra_get_settings(usb_dev, &pyra->settings);
if (retval) if (retval)
...@@ -581,7 +506,8 @@ static int pyra_init_specials(struct hid_device *hdev) ...@@ -581,7 +506,8 @@ static int pyra_init_specials(struct hid_device *hdev)
goto exit_free; goto exit_free;
} }
retval = roccat_connect(pyra_class, hdev); retval = roccat_connect(pyra_class, hdev,
sizeof(struct pyra_roccat_report));
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n"); hid_err(hdev, "couldn't init char dev\n");
} else { } else {
...@@ -685,8 +611,7 @@ static void pyra_report_to_chrdev(struct pyra_device const *pyra, ...@@ -685,8 +611,7 @@ static void pyra_report_to_chrdev(struct pyra_device const *pyra,
roccat_report.value = button_event->data1; roccat_report.value = button_event->data1;
roccat_report.key = 0; roccat_report.key = 0;
roccat_report_event(pyra->chrdev_minor, roccat_report_event(pyra->chrdev_minor,
(uint8_t const *)&roccat_report, (uint8_t const *)&roccat_report);
sizeof(struct pyra_roccat_report));
break; break;
case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO: case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO:
case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT: case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT:
...@@ -700,8 +625,7 @@ static void pyra_report_to_chrdev(struct pyra_device const *pyra, ...@@ -700,8 +625,7 @@ static void pyra_report_to_chrdev(struct pyra_device const *pyra,
*/ */
roccat_report.value = pyra->actual_profile + 1; roccat_report.value = pyra->actual_profile + 1;
roccat_report_event(pyra->chrdev_minor, roccat_report_event(pyra->chrdev_minor,
(uint8_t const *)&roccat_report, (uint8_t const *)&roccat_report);
sizeof(struct pyra_roccat_report));
} }
break; break;
} }
...@@ -761,8 +685,8 @@ static int __init pyra_init(void) ...@@ -761,8 +685,8 @@ static int __init pyra_init(void)
static void __exit pyra_exit(void) static void __exit pyra_exit(void)
{ {
class_destroy(pyra_class);
hid_unregister_driver(&pyra_driver); hid_unregister_driver(&pyra_driver);
class_destroy(pyra_class);
} }
module_init(pyra_init); module_init(pyra_init);
......
...@@ -26,8 +26,7 @@ ...@@ -26,8 +26,7 @@
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/hid-roccat.h>
#include "hid-roccat.h"
#define ROCCAT_FIRST_MINOR 0 #define ROCCAT_FIRST_MINOR 0
#define ROCCAT_MAX_DEVICES 8 #define ROCCAT_MAX_DEVICES 8
...@@ -37,11 +36,11 @@ ...@@ -37,11 +36,11 @@
struct roccat_report { struct roccat_report {
uint8_t *value; uint8_t *value;
int len;
}; };
struct roccat_device { struct roccat_device {
unsigned int minor; unsigned int minor;
int report_size;
int open; int open;
int exist; int exist;
wait_queue_head_t wait; wait_queue_head_t wait;
...@@ -123,7 +122,7 @@ static ssize_t roccat_read(struct file *file, char __user *buffer, ...@@ -123,7 +122,7 @@ static ssize_t roccat_read(struct file *file, char __user *buffer,
* If report is larger than requested amount of data, rest of report * If report is larger than requested amount of data, rest of report
* is lost! * is lost!
*/ */
len = report->len > count ? count : report->len; len = device->report_size > count ? count : device->report_size;
if (copy_to_user(buffer, report->value, len)) { if (copy_to_user(buffer, report->value, len)) {
retval = -EFAULT; retval = -EFAULT;
...@@ -248,26 +247,25 @@ static int roccat_release(struct inode *inode, struct file *file) ...@@ -248,26 +247,25 @@ static int roccat_release(struct inode *inode, struct file *file)
* *
* This is called from interrupt handler. * This is called from interrupt handler.
*/ */
int roccat_report_event(int minor, u8 const *data, int len) int roccat_report_event(int minor, u8 const *data)
{ {
struct roccat_device *device; struct roccat_device *device;
struct roccat_reader *reader; struct roccat_reader *reader;
struct roccat_report *report; struct roccat_report *report;
uint8_t *new_value; uint8_t *new_value;
new_value = kmemdup(data, len, GFP_ATOMIC); device = devices[minor];
new_value = kmemdup(data, device->report_size, GFP_ATOMIC);
if (!new_value) if (!new_value)
return -ENOMEM; return -ENOMEM;
device = devices[minor];
report = &device->cbuf[device->cbuf_end]; report = &device->cbuf[device->cbuf_end];
/* passing NULL is safe */ /* passing NULL is safe */
kfree(report->value); kfree(report->value);
report->value = new_value; report->value = new_value;
report->len = len;
device->cbuf_end = (device->cbuf_end + 1) % ROCCAT_CBUF_SIZE; device->cbuf_end = (device->cbuf_end + 1) % ROCCAT_CBUF_SIZE;
list_for_each_entry(reader, &device->readers, node) { list_for_each_entry(reader, &device->readers, node) {
...@@ -295,7 +293,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event); ...@@ -295,7 +293,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on * Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
* success, a negative error code on failure. * success, a negative error code on failure.
*/ */
int roccat_connect(struct class *klass, struct hid_device *hid) int roccat_connect(struct class *klass, struct hid_device *hid, int report_size)
{ {
unsigned int minor; unsigned int minor;
struct roccat_device *device; struct roccat_device *device;
...@@ -343,6 +341,7 @@ int roccat_connect(struct class *klass, struct hid_device *hid) ...@@ -343,6 +341,7 @@ int roccat_connect(struct class *klass, struct hid_device *hid)
device->hid = hid; device->hid = hid;
device->exist = 1; device->exist = 1;
device->cbuf_end = 0; device->cbuf_end = 0;
device->report_size = report_size;
return minor; return minor;
} }
...@@ -357,13 +356,16 @@ void roccat_disconnect(int minor) ...@@ -357,13 +356,16 @@ void roccat_disconnect(int minor)
mutex_lock(&devices_lock); mutex_lock(&devices_lock);
device = devices[minor]; device = devices[minor];
devices[minor] = NULL;
mutex_unlock(&devices_lock); mutex_unlock(&devices_lock);
device->exist = 0; /* TODO exist maybe not needed */ device->exist = 0; /* TODO exist maybe not needed */
device_destroy(device->dev->class, MKDEV(roccat_major, minor)); device_destroy(device->dev->class, MKDEV(roccat_major, minor));
mutex_lock(&devices_lock);
devices[minor] = NULL;
mutex_unlock(&devices_lock);
if (device->open) { if (device->open) {
hid_hw_close(device->hid); hid_hw_close(device->hid);
wake_up_interruptible(&device->wait); wake_up_interruptible(&device->wait);
...@@ -373,6 +375,34 @@ void roccat_disconnect(int minor) ...@@ -373,6 +375,34 @@ void roccat_disconnect(int minor)
} }
EXPORT_SYMBOL_GPL(roccat_disconnect); EXPORT_SYMBOL_GPL(roccat_disconnect);
static long roccat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct inode *inode = file->f_path.dentry->d_inode;
struct roccat_device *device;
unsigned int minor = iminor(inode);
long retval = 0;
mutex_lock(&devices_lock);
device = devices[minor];
if (!device) {
retval = -ENODEV;
goto out;
}
switch (cmd) {
case ROCCATIOCGREPSIZE:
if (put_user(device->report_size, (int __user *)arg))
retval = -EFAULT;
break;
default:
retval = -ENOTTY;
}
out:
mutex_unlock(&devices_lock);
return retval;
}
static const struct file_operations roccat_ops = { static const struct file_operations roccat_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = roccat_read, .read = roccat_read,
...@@ -380,6 +410,7 @@ static const struct file_operations roccat_ops = { ...@@ -380,6 +410,7 @@ static const struct file_operations roccat_ops = {
.open = roccat_open, .open = roccat_open,
.release = roccat_release, .release = roccat_release,
.llseek = noop_llseek, .llseek = noop_llseek,
.unlocked_ioctl = roccat_ioctl,
}; };
static int __init roccat_init(void) static int __init roccat_init(void)
......
...@@ -46,6 +46,16 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -46,6 +46,16 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc; return rdesc;
} }
/*
* The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
* like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
* so we need to override that forcing HID Output Reports on the Control EP.
*
* There is also another issue about HID Output Reports via USB, the Sixaxis
* does not want the report_id as part of the data packet, so we have to
* discard buf[0] when sending the actual control message, even for numbered
* reports, humpf!
*/
static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf, static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
size_t count, unsigned char report_type) size_t count, unsigned char report_type)
{ {
...@@ -55,6 +65,12 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf, ...@@ -55,6 +65,12 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
int report_id = buf[0]; int report_id = buf[0];
int ret; int ret;
if (report_type == HID_OUTPUT_REPORT) {
/* Don't send the Report ID */
buf++;
count--;
}
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT, HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
...@@ -62,6 +78,10 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf, ...@@ -62,6 +78,10 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
interface->desc.bInterfaceNumber, buf, count, interface->desc.bInterfaceNumber, buf, count,
USB_CTRL_SET_TIMEOUT); USB_CTRL_SET_TIMEOUT);
/* Count also the Report ID, in case of an Output report. */
if (ret > 0 && report_type == HID_OUTPUT_REPORT)
ret++;
return ret; return ret;
} }
......
...@@ -91,7 +91,7 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, ...@@ -91,7 +91,7 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
ret = -EFAULT; ret = -EFAULT;
goto out; goto out;
} }
ret += len; ret = len;
kfree(list->buffer[list->tail].value); kfree(list->buffer[list->tail].value);
list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
...@@ -102,15 +102,14 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, ...@@ -102,15 +102,14 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
} }
/* the first byte is expected to be a report number */ /* the first byte is expected to be a report number */
static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) /* This function is to be called with the minors_lock mutex held */
static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
{ {
unsigned int minor = iminor(file->f_path.dentry->d_inode); unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct hid_device *dev; struct hid_device *dev;
__u8 *buf; __u8 *buf;
int ret = 0; int ret = 0;
mutex_lock(&minors_lock);
if (!hidraw_table[minor]) { if (!hidraw_table[minor]) {
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
...@@ -148,14 +147,92 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t ...@@ -148,14 +147,92 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
goto out_free; goto out_free;
} }
ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); ret = dev->hid_output_raw_report(dev, buf, count, report_type);
out_free: out_free:
kfree(buf); kfree(buf);
out: out:
return ret;
}
/* the first byte is expected to be a report number */
static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
ssize_t ret;
mutex_lock(&minors_lock);
ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
mutex_unlock(&minors_lock); mutex_unlock(&minors_lock);
return ret; return ret;
} }
/* This function performs a Get_Report transfer over the control endpoint
per section 7.2.1 of the HID specification, version 1.1. The first byte
of buffer is the report number to request, or 0x0 if the defice does not
use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
or HID_INPUT_REPORT. This function is to be called with the minors_lock
mutex held. */
static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
{
unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct hid_device *dev;
__u8 *buf;
int ret = 0, len;
unsigned char report_number;
dev = hidraw_table[minor]->hid;
if (!dev->hid_get_raw_report) {
ret = -ENODEV;
goto out;
}
if (count > HID_MAX_BUFFER_SIZE) {
printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
task_pid_nr(current));
ret = -EINVAL;
goto out;
}
if (count < 2) {
printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
task_pid_nr(current));
ret = -EINVAL;
goto out;
}
buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
if (!buf) {
ret = -ENOMEM;
goto out;
}
/* Read the first byte from the user. This is the report number,
which is passed to dev->hid_get_raw_report(). */
if (copy_from_user(&report_number, buffer, 1)) {
ret = -EFAULT;
goto out_free;
}
ret = dev->hid_get_raw_report(dev, report_number, buf, count, report_type);
if (ret < 0)
goto out_free;
len = (ret < count) ? ret : count;
if (copy_to_user(buffer, buf, len)) {
ret = -EFAULT;
goto out_free;
}
ret = len;
out_free:
kfree(buf);
out:
return ret;
}
static unsigned int hidraw_poll(struct file *file, poll_table *wait) static unsigned int hidraw_poll(struct file *file, poll_table *wait)
{ {
struct hidraw_list *list = file->private_data; struct hidraw_list *list = file->private_data;
...@@ -295,7 +372,24 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, ...@@ -295,7 +372,24 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
default: default:
{ {
struct hid_device *hid = dev->hid; struct hid_device *hid = dev->hid;
if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) { if (_IOC_TYPE(cmd) != 'H') {
ret = -EINVAL;
break;
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {
int len = _IOC_SIZE(cmd);
ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
break;
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {
int len = _IOC_SIZE(cmd);
ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
break;
}
/* Begin Read-only ioctls. */
if (_IOC_DIR(cmd) != _IOC_READ) {
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
...@@ -327,7 +421,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, ...@@ -327,7 +421,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
-EFAULT : len; -EFAULT : len;
break; break;
} }
} }
ret = -ENOTTY; ret = -ENOTTY;
} }
...@@ -428,12 +522,12 @@ void hidraw_disconnect(struct hid_device *hid) ...@@ -428,12 +522,12 @@ void hidraw_disconnect(struct hid_device *hid)
hidraw->exist = 0; hidraw->exist = 0;
device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
mutex_lock(&minors_lock); mutex_lock(&minors_lock);
hidraw_table[hidraw->minor] = NULL; hidraw_table[hidraw->minor] = NULL;
mutex_unlock(&minors_lock); mutex_unlock(&minors_lock);
device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
if (hidraw->open) { if (hidraw->open) {
hid_hw_close(hid); hid_hw_close(hid);
wake_up_interruptible(&hidraw->wait); wake_up_interruptible(&hidraw->wait);
......
...@@ -799,6 +799,40 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) ...@@ -799,6 +799,40 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
return 0; return 0;
} }
static int usbhid_get_raw_report(struct hid_device *hid,
unsigned char report_number, __u8 *buf, size_t count,
unsigned char report_type)
{
struct usbhid_device *usbhid = hid->driver_data;
struct usb_device *dev = hid_to_usb_dev(hid);
struct usb_interface *intf = usbhid->intf;
struct usb_host_interface *interface = intf->cur_altsetting;
int skipped_report_id = 0;
int ret;
/* Byte 0 is the report number. Report data starts at byte 1.*/
buf[0] = report_number;
if (report_number == 0x0) {
/* Offset the return buffer by 1, so that the report ID
will remain in byte 0. */
buf++;
count--;
skipped_report_id = 1;
}
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
HID_REQ_GET_REPORT,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
((report_type + 1) << 8) | report_number,
interface->desc.bInterfaceNumber, buf, count,
USB_CTRL_SET_TIMEOUT);
/* count also the report id */
if (ret > 0 && skipped_report_id)
ret++;
return ret;
}
static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count, static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count,
unsigned char report_type) unsigned char report_type)
{ {
...@@ -1139,6 +1173,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * ...@@ -1139,6 +1173,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
usb_set_intfdata(intf, hid); usb_set_intfdata(intf, hid);
hid->ll_driver = &usb_hid_driver; hid->ll_driver = &usb_hid_driver;
hid->hid_get_raw_report = usbhid_get_raw_report;
hid->hid_output_raw_report = usbhid_output_raw_report; hid->hid_output_raw_report = usbhid_output_raw_report;
hid->ff_init = hid_pidff_init; hid->ff_init = hid_pidff_init;
#ifdef CONFIG_USB_HIDDEV #ifdef CONFIG_USB_HIDDEV
......
...@@ -15,18 +15,15 @@ ...@@ -15,18 +15,15 @@
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/types.h> #include <linux/types.h>
#if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE) #define ROCCATIOCGREPSIZE _IOR('H', 0xf1, int)
int roccat_connect(struct class *klass, struct hid_device *hid);
#ifdef __KERNEL__
int roccat_connect(struct class *klass, struct hid_device *hid,
int report_size);
void roccat_disconnect(int minor); void roccat_disconnect(int minor);
int roccat_report_event(int minor, u8 const *data, int len); int roccat_report_event(int minor, u8 const *data);
#else
static inline int roccat_connect(struct class *klass,
struct hid_device *hid) { return -1; }
static inline void roccat_disconnect(int minor) {}
static inline int roccat_report_event(int minor, u8 const *data, int len)
{
return 0;
}
#endif #endif
#endif #endif
...@@ -504,6 +504,9 @@ struct hid_device { /* device report descriptor */ ...@@ -504,6 +504,9 @@ struct hid_device { /* device report descriptor */
struct hid_usage *, __s32); struct hid_usage *, __s32);
void (*hiddev_report_event) (struct hid_device *, struct hid_report *); void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
/* handler for raw input (Get_Report) data, used by hidraw */
int (*hid_get_raw_report) (struct hid_device *, unsigned char, __u8 *, size_t, unsigned char);
/* handler for raw output data, used by hidraw */ /* handler for raw output data, used by hidraw */
int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char); int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char);
...@@ -638,7 +641,7 @@ struct hid_driver { ...@@ -638,7 +641,7 @@ struct hid_driver {
struct hid_input *hidinput, struct hid_field *field, struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max); struct hid_usage *usage, unsigned long **bit, int *max);
void (*feature_mapping)(struct hid_device *hdev, void (*feature_mapping)(struct hid_device *hdev,
struct hid_input *hidinput, struct hid_field *field, struct hid_field *field,
struct hid_usage *usage); struct hid_usage *usage);
#ifdef CONFIG_PM #ifdef CONFIG_PM
int (*suspend)(struct hid_device *hdev, pm_message_t message); int (*suspend)(struct hid_device *hdev, pm_message_t message);
......
...@@ -35,6 +35,9 @@ struct hidraw_devinfo { ...@@ -35,6 +35,9 @@ struct hidraw_devinfo {
#define HIDIOCGRAWINFO _IOR('H', 0x03, struct hidraw_devinfo) #define HIDIOCGRAWINFO _IOR('H', 0x03, struct hidraw_devinfo)
#define HIDIOCGRAWNAME(len) _IOC(_IOC_READ, 'H', 0x04, len) #define HIDIOCGRAWNAME(len) _IOC(_IOC_READ, 'H', 0x04, len)
#define HIDIOCGRAWPHYS(len) _IOC(_IOC_READ, 'H', 0x05, len) #define HIDIOCGRAWPHYS(len) _IOC(_IOC_READ, 'H', 0x05, len)
/* The first byte of SFEATURE and GFEATURE is the report number */
#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
#define HIDRAW_FIRST_MINOR 0 #define HIDRAW_FIRST_MINOR 0
#define HIDRAW_MAX_DEVICES 64 #define HIDRAW_MAX_DEVICES 64
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment