Commit fd62c545 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID subsystem updates from Jiri Kosina:

 1) Support for HID over I2C bus has been added by Benjamin Tissoires.
    ACPI device discovery is still in the works.

 2) Support for Win8 Multitiouch protocol is being added, most work done
    by Benjamin Tissoires as well

 3) EIO/ERESTARTSYS is fixed in hiddev/hidraw, fixes by Andrew Duggan
    and Jiri Kosina

 4) ION iCade driver added by Bastien Nocera

 5) Support for a couple new Roccat devices has been added by Stefan
    Achatz

 6) HID sensor hubs are now auto-detected instead of having to list all
    the VID/PID combinations in the blacklist array

 7) other random fixes and support for new device IDs

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (65 commits)
  HID: i2c-hid: add mutex protecting open/close race
  Revert "HID: sensors: add to special driver list"
  HID: sensors: autodetect USB HID sensor hubs
  HID: hidp: fallback to input session properly if hid is blacklisted
  HID: i2c-hid: fix ret_count check
  HID: i2c-hid: fix i2c_hid_get_raw_report count mismatches
  HID: i2c-hid: remove extra .irq field in struct i2c_hid
  HID: i2c-hid: reorder allocation/free of buffers
  HID: i2c-hid: fix memory corruption due to missing hid declaration
  HID: i2c-hid: remove superfluous include
  HID: i2c-hid: remove unneeded test in i2c_hid_remove
  HID: i2c-hid: i2c_hid_get_report may fail
  HID: i2c-hid: also call i2c_hid_free_buffers in i2c_hid_remove
  HID: i2c-hid: fix error messages
  HID: i2c-hid: fix return paths
  HID: i2c-hid: remove unused static declarations
  HID: i2c-hid: fix i2c_hid_dbg macro
  HID: i2c-hid: fix checkpatch.pl warning
  HID: i2c-hid: enhance Kconfig
  HID: i2c-hid: change I2C name
  ...
parents a2013a13 818b930b
...@@ -8,3 +8,41 @@ Description: The integer value of this attribute ranges from 0-4. ...@@ -8,3 +8,41 @@ Description: The integer value of this attribute ranges from 0-4.
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.
Please use actual_profile, it does the same thing. Please use actual_profile, it does the same thing.
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
Date: October 2010
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.
Please read binary attribute info which contains firmware version.
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
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_buttons holds information about button layout.
When read, these files return the respective profile buttons.
The returned data is 77 bytes in size.
This file is readonly.
Write control to select profile and read profile_buttons instead.
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
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_settings holds information like resolution, sensitivity
and light effects.
When read, these files return the respective profile settings.
The returned data is 43 bytes in size.
This file is readonly.
Write control to select profile and read profile_settings instead.
Users: http://roccat.sourceforge.net
\ No newline at end of file
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.
Has never been used. If bookkeeping is done, it's done in userland tools.
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.
Has never been used. If bookkeeping is done, it's done in userland tools.
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.
Has never been used. If bookkeeping is done, it's done in userland tools.
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.
Obsoleted by binary sysfs attribute "info".
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 information about button layout.
When read, these files return the respective profile buttons.
The returned data is 23 bytes in size.
This file is readonly.
Write control to select profile and read profile_buttons instead.
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 information 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.
Write control to select profile and read profile_settings instead.
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_cpi
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: It is possible to switch the cpi setting of the mouse with the
press of a button.
When read, this file returns the raw number of the actual cpi
setting reported by the mouse. This number has to be further
processed to receive the real dpi value.
VALUE DPI
1 400
2 800
4 1600
This file is readonly.
Has never been used. If bookkeeping is done, it's done in userland tools.
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
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the number of the actual profile in
range 0-4.
This file is readonly.
Please use binary attribute "settings" which provides this information.
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
Date: August 2010
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 138 means 1.38
This file is readonly.
Please use binary attribute "info" which provides this information.
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
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_buttons holds information about button layout.
When read, these files return the respective profile buttons.
The returned data is 19 bytes in size.
This file is readonly.
Write control to select profile and read profile_buttons instead.
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
Date: August 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_settings holds information like resolution, sensitivity
and light effects.
When read, these files return the respective profile settings.
The returned data is 13 bytes in size.
This file is readonly.
Write control to select profile and read profile_settings instead.
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
Date: August 2010
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 profile
that's active when the mouse is powered on.
This file is readonly.
Please use binary attribute "settings" which provides this information.
Users: http://roccat.sourceforge.net
...@@ -117,6 +117,14 @@ Description: When written, this file lets one store macros with max 500 ...@@ -117,6 +117,14 @@ Description: When written, this file lets one store macros with max 500
which profile and key to read. which profile and key to read.
Users: http://roccat.sourceforge.net Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/reset
Date: November 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one reset the device.
The data has to be 3 bytes long.
This file is writeonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/control What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/control
Date: June 2011 Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
......
...@@ -9,15 +9,12 @@ Description: The integer value of this attribute ranges from 0-4. ...@@ -9,15 +9,12 @@ Description: The integer value of this attribute ranges from 0-4.
and the mouse activates this profile immediately. and the mouse activates this profile immediately.
Users: http://roccat.sourceforge.net 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>/info
Date: October 2010 Date: November 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns the raw integer version number of the Description: When read, this file returns general data like firmware version.
firmware reported by the mouse. Using the integer value eases When written, the device can be reset.
further usage in other programs. To receive the real version The data is 8 bytes long.
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 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
...@@ -42,18 +39,8 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -42,18 +39,8 @@ Description: The mouse can store 5 profiles which can be switched by the
The mouse will reject invalid data. The mouse will reject invalid data.
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. Before reading this file, control has to be written to select
Users: http://roccat.sourceforge.net which profile to read.
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
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_buttons holds information about button layout.
When read, these files return the respective profile buttons.
The returned data is 77 bytes in size.
This file is readonly.
Users: http://roccat.sourceforge.net 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
...@@ -68,19 +55,8 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -68,19 +55,8 @@ Description: The mouse can store 5 profiles which can be switched by the
The mouse will reject invalid data. The mouse will reject invalid data.
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. Before reading this file, control has to be written to select
Users: http://roccat.sourceforge.net which profile to read.
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
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_settings holds information like resolution, sensitivity
and light effects.
When read, these files return the respective profile settings.
The returned data is 43 bytes in size.
This file is readonly.
Users: http://roccat.sourceforge.net 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
...@@ -104,9 +80,9 @@ What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid- ...@@ -104,9 +80,9 @@ What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-
Date: October 2010 Date: October 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written a calibration process for the tracking control unit Description: When written a calibration process for the tracking control unit
can be initiated/cancelled. can be initiated/cancelled. Also lets one read/write sensor
The data has to be 3 bytes long. registers.
This file is writeonly. The data has to be 4 bytes long.
Users: http://roccat.sourceforge.net 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
......
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 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 Date: January 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
...@@ -18,33 +9,12 @@ Description: The integer value of this attribute ranges from 0-4. ...@@ -18,33 +9,12 @@ Description: The integer value of this attribute ranges from 0-4.
active when the mouse is powered on. active when the mouse is powered on.
Users: http://roccat.sourceforge.net 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 What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/info
Date: January 2011 Date: November 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The integer value of this attribute ranges from 1-10. Description: When read, this file returns general data like firmware version.
When read, this attribute returns the number of the actual When written, the device can be reset.
sensitivity in x direction. The data is 6 bytes long.
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 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 What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_buttons
...@@ -58,18 +28,8 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -58,18 +28,8 @@ Description: The mouse can store 5 profiles which can be switched by the
The mouse will reject invalid data. The mouse will reject invalid data.
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. Before reading this file, control has to be written to select
Users: http://roccat.sourceforge.net which profile to read.
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 information 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 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 What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_settings
...@@ -84,17 +44,6 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -84,17 +44,6 @@ Description: The mouse can store 5 profiles which can be switched by the
The mouse will reject invalid data. The mouse will reject invalid data.
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. Before reading this file, control has to be written to select
Users: http://roccat.sourceforge.net which profile to read.
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 information 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 Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/control
Date: October 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, cpi, button and light settings can be configured.
When read, actual cpi setting and sensor data are returned.
The data has to be 8 bytes long.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/actual_cpi What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/info
Date: August 2010 Date: November 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: It is possible to switch the cpi setting of the mouse with the
press of a button.
When read, this file returns the raw number of the actual cpi
setting reported by the mouse. This number has to be further
processed to receive the real dpi value.
VALUE DPI
1 400
2 800
4 1600
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
Date: August 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 in Description: When read, this file returns general data like firmware version.
range 0-4. When written, the device can be reset.
This file is readonly. The data is 6 bytes long.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/firmware_version
Date: August 2010
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 138 means 1.38
This file is readonly.
Users: http://roccat.sourceforge.net 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
...@@ -46,19 +18,8 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -46,19 +18,8 @@ Description: The mouse can store 5 profiles which can be switched by the
The mouse will reject invalid data. The mouse will reject invalid data.
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. Before reading this file, control has to be written to select
Users: http://roccat.sourceforge.net which profile to read.
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
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_settings holds information like resolution, sensitivity
and light effects.
When read, these files return the respective profile settings.
The returned data is 13 bytes in size.
This file is readonly.
Users: http://roccat.sourceforge.net 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
...@@ -72,27 +33,8 @@ Description: The mouse can store 5 profiles which can be switched by the ...@@ -72,27 +33,8 @@ Description: The mouse can store 5 profiles which can be switched by the
The mouse will reject invalid data. The mouse will reject invalid data.
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. Before reading this file, control has to be written to select
Users: http://roccat.sourceforge.net which profile to read.
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
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_buttons holds information about button layout.
When read, these files return the respective profile buttons.
The returned data is 19 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>/pyra/roccatpyra<minor>/startup_profile
Date: August 2010
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 profile
that's active when the mouse is powered on.
This file is readonly.
Users: http://roccat.sourceforge.net 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
......
...@@ -40,8 +40,8 @@ What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid- ...@@ -40,8 +40,8 @@ What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-
Date: Mai 2012 Date: Mai 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns general data like firmware version. Description: When read, this file returns general data like firmware version.
When written, the device can be reset.
The data is 8 bytes long. The data is 8 bytes long.
This file is readonly.
Users: http://roccat.sourceforge.net Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/macro What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/macro
...@@ -74,4 +74,3 @@ Description: The mouse has a Avago ADNS-3090 sensor. ...@@ -74,4 +74,3 @@ Description: The mouse has a Avago ADNS-3090 sensor.
This file allows reading and writing of the mouse sensors registers. This file allows reading and writing of the mouse sensors registers.
The data has to be 4 bytes long. The data has to be 4 bytes long.
Users: http://roccat.sourceforge.net Users: http://roccat.sourceforge.net
...@@ -196,6 +196,17 @@ EV_MSC: ...@@ -196,6 +196,17 @@ EV_MSC:
EV_MSC events are used for input and output events that do not fall under other EV_MSC events are used for input and output events that do not fall under other
categories. categories.
A few EV_MSC codes have special meaning:
* MSC_TIMESTAMP:
- Used to report the number of microseconds since the last reset. This event
should be coded as an uint32 value, which is allowed to wrap around with
no special consequence. It is assumed that the time difference between two
consecutive events is reliable on a reasonable time scale (hours).
A reset to zero can happen, in which case the time since the last event is
unknown. If the device does not provide this information, the driver must
not provide it to user space.
EV_LED: EV_LED:
---------- ----------
EV_LED events are used for input and output to set and query the state of EV_LED events are used for input and output to set and query the state of
......
...@@ -265,6 +265,15 @@ config HID_GYRATION ...@@ -265,6 +265,15 @@ config HID_GYRATION
---help--- ---help---
Support for Gyration remote control. Support for Gyration remote control.
config HID_ICADE
tristate "ION iCade arcade controller"
depends on BT_HIDP
---help---
Support for the ION iCade arcade controller to work as a joystick.
To compile this driver as a module, choose M here: the
module will be called hid-icade.
config HID_TWINHAN config HID_TWINHAN
tristate "Twinhan IR remote control" tristate "Twinhan IR remote control"
depends on USB_HID depends on USB_HID
...@@ -728,4 +737,6 @@ endif # HID ...@@ -728,4 +737,6 @@ endif # HID
source "drivers/hid/usbhid/Kconfig" source "drivers/hid/usbhid/Kconfig"
source "drivers/hid/i2c-hid/Kconfig"
endmenu endmenu
...@@ -52,6 +52,7 @@ obj-$(CONFIG_HID_GYRATION) += hid-gyration.o ...@@ -52,6 +52,7 @@ obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o
obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o
obj-$(CONFIG_HID_ICADE) += hid-icade.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_KEYTOUCH) += hid-keytouch.o
obj-$(CONFIG_HID_KYE) += hid-kye.o obj-$(CONFIG_HID_KYE) += hid-kye.o
...@@ -93,8 +94,8 @@ obj-$(CONFIG_HID_PRIMAX) += hid-primax.o ...@@ -93,8 +94,8 @@ obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \ hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o \ hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-lua.o \
hid-roccat-savu.o hid-roccat-pyra.o hid-roccat-savu.o
obj-$(CONFIG_HID_SAITEK) += hid-saitek.o obj-$(CONFIG_HID_SAITEK) += hid-saitek.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
...@@ -118,3 +119,4 @@ obj-$(CONFIG_USB_HID) += usbhid/ ...@@ -118,3 +119,4 @@ obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/
obj-$(CONFIG_USB_KBD) += usbhid/ obj-$(CONFIG_USB_KBD) += usbhid/
obj-$(CONFIG_I2C_HID) += i2c-hid/
...@@ -439,7 +439,8 @@ static const struct hid_device_id apple_devices[] = { ...@@ -439,7 +439,8 @@ static const struct hid_device_id apple_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI), { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO), { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS), { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
APPLE_RDESC_JIS }, APPLE_RDESC_JIS },
......
...@@ -92,6 +92,7 @@ EXPORT_SYMBOL_GPL(hid_register_report); ...@@ -92,6 +92,7 @@ EXPORT_SYMBOL_GPL(hid_register_report);
static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
{ {
struct hid_field *field; struct hid_field *field;
int i;
if (report->maxfield == HID_MAX_FIELDS) { if (report->maxfield == HID_MAX_FIELDS) {
hid_err(report->device, "too many fields in report\n"); hid_err(report->device, "too many fields in report\n");
...@@ -110,6 +111,9 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned ...@@ -110,6 +111,9 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
field->value = (s32 *)(field->usage + usages); field->value = (s32 *)(field->usage + usages);
field->report = report; field->report = report;
for (i = 0; i < usages; i++)
field->usage[i].usage_index = i;
return field; return field;
} }
...@@ -315,6 +319,7 @@ static s32 item_sdata(struct hid_item *item) ...@@ -315,6 +319,7 @@ static s32 item_sdata(struct hid_item *item)
static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
{ {
__u32 raw_value;
switch (item->tag) { switch (item->tag) {
case HID_GLOBAL_ITEM_TAG_PUSH: case HID_GLOBAL_ITEM_TAG_PUSH:
...@@ -365,7 +370,14 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) ...@@ -365,7 +370,14 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
return 0; return 0;
case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
parser->global.unit_exponent = item_sdata(item); /* Units exponent negative numbers are given through a
* two's complement.
* See "6.2.2.7 Global Items" for more information. */
raw_value = item_udata(item);
if (!(raw_value & 0xfffffff0))
parser->global.unit_exponent = hid_snto32(raw_value, 4);
else
parser->global.unit_exponent = raw_value;
return 0; return 0;
case HID_GLOBAL_ITEM_TAG_UNIT: case HID_GLOBAL_ITEM_TAG_UNIT:
...@@ -713,7 +725,12 @@ static int hid_scan_report(struct hid_device *hid) ...@@ -713,7 +725,12 @@ static int hid_scan_report(struct hid_device *hid)
hid_scan_usage(hid, u); hid_scan_usage(hid, u);
break; break;
} }
} } else if (page == HID_UP_SENSOR &&
item.type == HID_ITEM_TYPE_MAIN &&
item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION &&
(item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL &&
hid->bus == BUS_USB)
hid->group = HID_GROUP_SENSOR_HUB;
} }
return 0; return 0;
...@@ -865,6 +882,12 @@ static s32 snto32(__u32 value, unsigned n) ...@@ -865,6 +882,12 @@ static s32 snto32(__u32 value, unsigned n)
return value & (1 << (n - 1)) ? value | (-1 << n) : value; return value & (1 << (n - 1)) ? value | (-1 << n) : value;
} }
s32 hid_snto32(__u32 value, unsigned n)
{
return snto32(value, n);
}
EXPORT_SYMBOL_GPL(hid_snto32);
/* /*
* Convert a signed 32-bit integer to a signed n-bit integer. * Convert a signed 32-bit integer to a signed n-bit integer.
*/ */
...@@ -1465,6 +1488,10 @@ EXPORT_SYMBOL_GPL(hid_disconnect); ...@@ -1465,6 +1488,10 @@ EXPORT_SYMBOL_GPL(hid_disconnect);
* there is a proper autodetection and autoloading in place (based on presence * there is a proper autodetection and autoloading in place (based on presence
* of HID_DG_CONTACTID), so those devices don't need to be added to this list, * of HID_DG_CONTACTID), so those devices don't need to be added to this list,
* as we are doing the right thing in hid_scan_usage(). * as we are doing the right thing in hid_scan_usage().
*
* Autodetection for (USB) HID sensor hubs exists too. If a collection of type
* physical is found inside a usage page of type sensor, hid-sensor-hub will be
* used as a driver. See hid_scan_report().
*/ */
static const struct hid_device_id hid_have_special_driver[] = { 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) },
...@@ -1538,6 +1565,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1538,6 +1565,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
...@@ -1571,10 +1599,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1571,10 +1599,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ 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_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_1020) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_09FA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_1020) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_09FA) },
{ 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_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) },
...@@ -1658,6 +1683,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1658,6 +1683,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, { 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_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
...@@ -1672,7 +1698,6 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1672,7 +1698,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_SENSOR_HUB_7014) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
...@@ -2150,8 +2175,13 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { ...@@ -2150,8 +2175,13 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ } { }
}; };
static bool hid_ignore(struct hid_device *hdev) bool hid_ignore(struct hid_device *hdev)
{ {
if (hdev->quirks & HID_QUIRK_NO_IGNORE)
return false;
if (hdev->quirks & HID_QUIRK_IGNORE)
return true;
switch (hdev->vendor) { switch (hdev->vendor) {
case USB_VENDOR_ID_CODEMERCS: case USB_VENDOR_ID_CODEMERCS:
/* ignore all Code Mercenaries IOWarrior devices */ /* ignore all Code Mercenaries IOWarrior devices */
...@@ -2189,6 +2219,15 @@ static bool hid_ignore(struct hid_device *hdev) ...@@ -2189,6 +2219,15 @@ static bool hid_ignore(struct hid_device *hdev)
hdev->type == HID_TYPE_USBNONE) hdev->type == HID_TYPE_USBNONE)
return true; return true;
break; break;
case USB_VENDOR_ID_DWAV:
/* These are handled by usbtouchscreen. hdev->type is probably
* HID_TYPE_USBNONE, but we say !HID_TYPE_USBMOUSE to match
* usbtouchscreen. */
if ((hdev->product == USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER ||
hdev->product == USB_DEVICE_ID_DWAV_TOUCHCONTROLLER) &&
hdev->type != HID_TYPE_USBMOUSE)
return true;
break;
} }
if (hdev->type == HID_TYPE_USBMOUSE && if (hdev->type == HID_TYPE_USBMOUSE &&
...@@ -2197,6 +2236,7 @@ static bool hid_ignore(struct hid_device *hdev) ...@@ -2197,6 +2236,7 @@ static bool hid_ignore(struct hid_device *hdev)
return !!hid_match_id(hdev, hid_ignore_list); return !!hid_match_id(hdev, hid_ignore_list);
} }
EXPORT_SYMBOL_GPL(hid_ignore);
int hid_add_device(struct hid_device *hdev) int hid_add_device(struct hid_device *hdev)
{ {
...@@ -2208,8 +2248,7 @@ int hid_add_device(struct hid_device *hdev) ...@@ -2208,8 +2248,7 @@ int hid_add_device(struct hid_device *hdev)
/* we need to kill them here, otherwise they will stay allocated to /* we need to kill them here, otherwise they will stay allocated to
* wait for coming driver */ * wait for coming driver */
if (!(hdev->quirks & HID_QUIRK_NO_IGNORE) if (hid_ignore(hdev))
&& (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE)))
return -ENODEV; return -ENODEV;
/* /*
......
/*
* ION iCade input driver
*
* Copyright (c) 2012 Bastien Nocera <hadess@hadess.net>
* Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
*/
/*
* 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"
/*
* ↑ A C Y L
* ← →
* ↓ B X Z R
*
*
* UP ON,OFF = w,e
* RT ON,OFF = d,c
* DN ON,OFF = x,z
* LT ON,OFF = a,q
* A ON,OFF = y,t
* B ON,OFF = h,r
* C ON,OFF = u,f
* X ON,OFF = j,n
* Y ON,OFF = i,m
* Z ON,OFF = k,p
* L ON,OFF = o,g
* R ON,OFF = l,v
*/
/* The translation code uses HID usage instead of input layer
* keys. This code generates a lookup table that makes
* translation quick.
*
* #include <linux/input.h>
* #include <stdio.h>
* #include <assert.h>
*
* #define unk KEY_UNKNOWN
*
* < copy of hid_keyboard[] from hid-input.c >
*
* struct icade_key_translation {
* int from;
* const char *to;
* int press;
* };
*
* static const struct icade_key_translation icade_keys[] = {
* { KEY_W, "KEY_UP", 1 },
* { KEY_E, "KEY_UP", 0 },
* { KEY_D, "KEY_RIGHT", 1 },
* { KEY_C, "KEY_RIGHT", 0 },
* { KEY_X, "KEY_DOWN", 1 },
* { KEY_Z, "KEY_DOWN", 0 },
* { KEY_A, "KEY_LEFT", 1 },
* { KEY_Q, "KEY_LEFT", 0 },
* { KEY_Y, "BTN_A", 1 },
* { KEY_T, "BTN_A", 0 },
* { KEY_H, "BTN_B", 1 },
* { KEY_R, "BTN_B", 0 },
* { KEY_U, "BTN_C", 1 },
* { KEY_F, "BTN_C", 0 },
* { KEY_J, "BTN_X", 1 },
* { KEY_N, "BTN_X", 0 },
* { KEY_I, "BTN_Y", 1 },
* { KEY_M, "BTN_Y", 0 },
* { KEY_K, "BTN_Z", 1 },
* { KEY_P, "BTN_Z", 0 },
* { KEY_O, "BTN_THUMBL", 1 },
* { KEY_G, "BTN_THUMBL", 0 },
* { KEY_L, "BTN_THUMBR", 1 },
* { KEY_V, "BTN_THUMBR", 0 },
*
* { }
* };
*
* static int
* usage_for_key (int key)
* {
* int i;
* for (i = 0; i < 256; i++) {
* if (hid_keyboard[i] == key)
* return i;
* }
* assert(0);
* }
*
* int main (int argc, char **argv)
* {
* const struct icade_key_translation *trans;
* int max_usage = 0;
*
* for (trans = icade_keys; trans->from; trans++) {
* int usage = usage_for_key (trans->from);
* max_usage = usage > max_usage ? usage : max_usage;
* }
*
* printf ("#define ICADE_MAX_USAGE %d\n\n", max_usage);
* printf ("struct icade_key {\n");
* printf ("\tu16 to;\n");
* printf ("\tu8 press:1;\n");
* printf ("};\n\n");
* printf ("static const struct icade_key "
* "icade_usage_table[%d] = {\n", max_usage + 1);
* for (trans = icade_keys; trans->from; trans++) {
* printf ("\t[%d] = { %s, %d },\n",
* usage_for_key (trans->from), trans->to, trans->press);
* }
* printf ("};\n");
*
* return 0;
* }
*/
#define ICADE_MAX_USAGE 29
struct icade_key {
u16 to;
u8 press:1;
};
static const struct icade_key icade_usage_table[30] = {
[26] = { KEY_UP, 1 },
[8] = { KEY_UP, 0 },
[7] = { KEY_RIGHT, 1 },
[6] = { KEY_RIGHT, 0 },
[27] = { KEY_DOWN, 1 },
[29] = { KEY_DOWN, 0 },
[4] = { KEY_LEFT, 1 },
[20] = { KEY_LEFT, 0 },
[28] = { BTN_A, 1 },
[23] = { BTN_A, 0 },
[11] = { BTN_B, 1 },
[21] = { BTN_B, 0 },
[24] = { BTN_C, 1 },
[9] = { BTN_C, 0 },
[13] = { BTN_X, 1 },
[17] = { BTN_X, 0 },
[12] = { BTN_Y, 1 },
[16] = { BTN_Y, 0 },
[14] = { BTN_Z, 1 },
[19] = { BTN_Z, 0 },
[18] = { BTN_THUMBL, 1 },
[10] = { BTN_THUMBL, 0 },
[15] = { BTN_THUMBR, 1 },
[25] = { BTN_THUMBR, 0 },
};
static const struct icade_key *icade_find_translation(u16 from)
{
if (from < 0 || from > ICADE_MAX_USAGE)
return NULL;
return &icade_usage_table[from];
}
static int icade_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
const struct icade_key *trans;
if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
!usage->type)
return 0;
/* We ignore the fake key up, and act only on key down */
if (!value)
return 1;
trans = icade_find_translation(usage->hid & HID_USAGE);
if (!trans)
return 1;
input_event(field->hidinput->input, usage->type,
trans->to, trans->press);
return 1;
}
static int icade_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
const struct icade_key *trans;
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_KEYBOARD) {
trans = icade_find_translation(usage->hid & HID_USAGE);
if (!trans)
return -1;
hid_map_usage(hi, usage, bit, max, EV_KEY, trans->to);
set_bit(trans->to, hi->input->keybit);
return 1;
}
/* ignore others */
return -1;
}
static int icade_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
if (usage->type == EV_KEY)
set_bit(usage->type, hi->input->evbit);
return -1;
}
static const struct hid_device_id icade_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
{ }
};
MODULE_DEVICE_TABLE(hid, icade_devices);
static struct hid_driver icade_driver = {
.name = "icade",
.id_table = icade_devices,
.event = icade_event,
.input_mapped = icade_input_mapped,
.input_mapping = icade_input_mapping,
};
static int __init icade_init(void)
{
int ret;
ret = hid_register_driver(&icade_driver);
if (ret)
pr_err("can't register icade driver\n");
return ret;
}
static void __exit icade_exit(void)
{
hid_unregister_driver(&icade_driver);
}
module_init(icade_init);
module_exit(icade_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
MODULE_DESCRIPTION("ION iCade input driver");
...@@ -257,6 +257,7 @@ ...@@ -257,6 +257,7 @@
#define USB_VENDOR_ID_DWAV 0x0eef #define USB_VENDOR_ID_DWAV 0x0eef
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
#define USB_DEVICE_ID_DWAV_TOUCHCONTROLLER 0x0002
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D 0x480d #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D 0x480d
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E 0x480e #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E 0x480e
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207 0x7207 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207 0x7207
...@@ -423,6 +424,9 @@ ...@@ -423,6 +424,9 @@
#define USB_VENDOR_ID_ILITEK 0x222a #define USB_VENDOR_ID_ILITEK 0x222a
#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001 #define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001
#define USB_VENDOR_ID_ION 0x15e4
#define USB_DEVICE_ID_ICADE 0x0132
#define USB_VENDOR_ID_HOLTEK 0x1241 #define USB_VENDOR_ID_HOLTEK 0x1241
#define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015 #define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015
...@@ -432,11 +436,6 @@ ...@@ -432,11 +436,6 @@
#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_INTEL_8086 0x8086
#define USB_VENDOR_ID_INTEL_8087 0x8087
#define USB_DEVICE_ID_SENSOR_HUB_1020 0x1020
#define USB_DEVICE_ID_SENSOR_HUB_09FA 0x09FA
#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615 #define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
...@@ -603,6 +602,7 @@ ...@@ -603,6 +602,7 @@
#define USB_VENDOR_ID_NOVATEK 0x0603 #define USB_VENDOR_ID_NOVATEK 0x0603
#define USB_DEVICE_ID_NOVATEK_PCT 0x0600 #define USB_DEVICE_ID_NOVATEK_PCT 0x0600
#define USB_DEVICE_ID_NOVATEK_MOUSE 0x1602
#define USB_VENDOR_ID_NTRIG 0x1b96 #define USB_VENDOR_ID_NTRIG 0x1b96
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
...@@ -677,7 +677,9 @@ ...@@ -677,7 +677,9 @@
#define USB_DEVICE_ID_ROCCAT_ISKU 0x319c #define USB_DEVICE_ID_ROCCAT_ISKU 0x319c
#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_KONEXTD 0x2e22
#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50 #define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
#define USB_DEVICE_ID_ROCCAT_LUA 0x2c2e
#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
#define USB_DEVICE_ID_ROCCAT_SAVU 0x2d5a #define USB_DEVICE_ID_ROCCAT_SAVU 0x2d5a
...@@ -696,6 +698,9 @@ ...@@ -696,6 +698,9 @@
#define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f #define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f
#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002 #define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002
#define USB_VENDOR_ID_SIGMATEL 0x066F
#define USB_DEVICE_ID_SIGMATEL_STMP3780 0x3780
#define USB_VENDOR_ID_SKYCABLE 0x1223 #define USB_VENDOR_ID_SKYCABLE 0x1223
#define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07 #define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07
...@@ -714,7 +719,6 @@ ...@@ -714,7 +719,6 @@
#define USB_VENDOR_ID_STANTUM_STM 0x0483 #define USB_VENDOR_ID_STANTUM_STM 0x0483
#define USB_DEVICE_ID_MTP_STM 0x3261 #define USB_DEVICE_ID_MTP_STM 0x3261
#define USB_DEVICE_ID_SENSOR_HUB_7014 0x7014
#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403 #define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403
#define USB_DEVICE_ID_MTP_SITRONIX 0x5001 #define USB_DEVICE_ID_MTP_SITRONIX 0x5001
...@@ -762,6 +766,9 @@ ...@@ -762,6 +766,9 @@
#define USB_VENDOR_ID_TOUCHPACK 0x1bfd #define USB_VENDOR_ID_TOUCHPACK 0x1bfd
#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688 #define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688
#define USB_VENDOR_ID_TPV 0x25aa
#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN 0x8883
#define USB_VENDOR_ID_TURBOX 0x062a #define USB_VENDOR_ID_TURBOX 0x062a
#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
#define USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART 0x7100 #define USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART 0x7100
......
...@@ -192,7 +192,6 @@ static int hidinput_setkeycode(struct input_dev *dev, ...@@ -192,7 +192,6 @@ static int hidinput_setkeycode(struct input_dev *dev,
return -EINVAL; return -EINVAL;
} }
/** /**
* hidinput_calc_abs_res - calculate an absolute axis resolution * hidinput_calc_abs_res - calculate an absolute axis resolution
* @field: the HID report field to calculate resolution for * @field: the HID report field to calculate resolution for
...@@ -208,7 +207,7 @@ static int hidinput_setkeycode(struct input_dev *dev, ...@@ -208,7 +207,7 @@ static int hidinput_setkeycode(struct input_dev *dev,
* Only exponent 1 length units are processed. Centimeters and inches are * Only exponent 1 length units are processed. Centimeters and inches are
* converted to millimeters. Degrees are converted to radians. * converted to millimeters. Degrees are converted to radians.
*/ */
static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
{ {
__s32 unit_exponent = field->unit_exponent; __s32 unit_exponent = field->unit_exponent;
__s32 logical_extents = field->logical_maximum - __s32 logical_extents = field->logical_maximum -
...@@ -229,17 +228,29 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) ...@@ -229,17 +228,29 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
case ABS_X: case ABS_X:
case ABS_Y: case ABS_Y:
case ABS_Z: case ABS_Z:
if (field->unit == 0x11) { /* If centimeters */ case ABS_MT_POSITION_X:
case ABS_MT_POSITION_Y:
case ABS_MT_TOOL_X:
case ABS_MT_TOOL_Y:
case ABS_MT_TOUCH_MAJOR:
case ABS_MT_TOUCH_MINOR:
if (field->unit & 0xffffff00) /* Not a length */
return 0;
unit_exponent += hid_snto32(field->unit >> 4, 4) - 1;
switch (field->unit & 0xf) {
case 0x1: /* If centimeters */
/* Convert to millimeters */ /* Convert to millimeters */
unit_exponent += 1; unit_exponent += 1;
} else if (field->unit == 0x13) { /* If inches */ break;
case 0x3: /* If inches */
/* Convert to millimeters */ /* Convert to millimeters */
prev = physical_extents; prev = physical_extents;
physical_extents *= 254; physical_extents *= 254;
if (physical_extents < prev) if (physical_extents < prev)
return 0; return 0;
unit_exponent -= 1; unit_exponent -= 1;
} else { break;
default:
return 0; return 0;
} }
break; break;
...@@ -281,8 +292,9 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) ...@@ -281,8 +292,9 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
} }
/* Calculate resolution */ /* Calculate resolution */
return logical_extents / physical_extents; return DIV_ROUND_CLOSEST(logical_extents, physical_extents);
} }
EXPORT_SYMBOL_GPL(hidinput_calc_abs_res);
#ifdef CONFIG_HID_BATTERY_STRENGTH #ifdef CONFIG_HID_BATTERY_STRENGTH
static enum power_supply_property hidinput_battery_props[] = { static enum power_supply_property hidinput_battery_props[] = {
...@@ -298,6 +310,9 @@ static enum power_supply_property hidinput_battery_props[] = { ...@@ -298,6 +310,9 @@ static enum power_supply_property hidinput_battery_props[] = {
#define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */ #define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */
static const struct hid_device_id hid_battery_quirks[] = { static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
...@@ -502,9 +517,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -502,9 +517,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
if (code <= 0xf) if (code <= 0xf)
code += BTN_JOYSTICK; code += BTN_JOYSTICK;
else else
code += BTN_TRIGGER_HAPPY; code += BTN_TRIGGER_HAPPY - 0x10;
break;
case HID_GD_GAMEPAD:
if (code <= 0xf)
code += BTN_GAMEPAD;
else
code += BTN_TRIGGER_HAPPY - 0x10;
break; break;
case HID_GD_GAMEPAD: code += BTN_GAMEPAD; break;
default: default:
switch (field->physical) { switch (field->physical) {
case HID_GD_MOUSE: case HID_GD_MOUSE:
...@@ -1146,6 +1166,38 @@ static void report_features(struct hid_device *hid) ...@@ -1146,6 +1166,38 @@ static void report_features(struct hid_device *hid)
} }
} }
static struct hid_input *hidinput_allocate(struct hid_device *hid)
{
struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
struct input_dev *input_dev = input_allocate_device();
if (!hidinput || !input_dev) {
kfree(hidinput);
input_free_device(input_dev);
hid_err(hid, "Out of memory during hid input probe\n");
return NULL;
}
input_set_drvdata(input_dev, hid);
input_dev->event = hid->ll_driver->hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
input_dev->setkeycode = hidinput_setkeycode;
input_dev->getkeycode = hidinput_getkeycode;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
input_dev->uniq = hid->uniq;
input_dev->id.bustype = hid->bus;
input_dev->id.vendor = hid->vendor;
input_dev->id.product = hid->product;
input_dev->id.version = hid->version;
input_dev->dev.parent = hid->dev.parent;
hidinput->input = input_dev;
list_add_tail(&hidinput->list, &hid->inputs);
return hidinput;
}
/* /*
* Register the input device; print a message. * Register the input device; print a message.
* Configure the input layer interface * Configure the input layer interface
...@@ -1157,7 +1209,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1157,7 +1209,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
struct hid_driver *drv = hid->driver; struct hid_driver *drv = hid->driver;
struct hid_report *report; struct hid_report *report;
struct hid_input *hidinput = NULL; struct hid_input *hidinput = NULL;
struct input_dev *input_dev;
int i, j, k; int i, j, k;
INIT_LIST_HEAD(&hid->inputs); INIT_LIST_HEAD(&hid->inputs);
...@@ -1188,35 +1239,11 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1188,35 +1239,11 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
continue; continue;
if (!hidinput) { if (!hidinput) {
hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); hidinput = hidinput_allocate(hid);
input_dev = input_allocate_device(); if (!hidinput)
if (!hidinput || !input_dev) {
kfree(hidinput);
input_free_device(input_dev);
hid_err(hid, "Out of memory during hid input probe\n");
goto out_unwind; goto out_unwind;
} }
input_set_drvdata(input_dev, hid);
input_dev->event =
hid->ll_driver->hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
input_dev->setkeycode = hidinput_setkeycode;
input_dev->getkeycode = hidinput_getkeycode;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
input_dev->uniq = hid->uniq;
input_dev->id.bustype = hid->bus;
input_dev->id.vendor = hid->vendor;
input_dev->id.product = hid->product;
input_dev->id.version = hid->version;
input_dev->dev.parent = hid->dev.parent;
hidinput->input = input_dev;
list_add_tail(&hidinput->list, &hid->inputs);
}
for (i = 0; i < report->maxfield; i++) for (i = 0; i < report->maxfield; i++)
for (j = 0; j < report->field[i]->maxusage; j++) for (j = 0; j < report->field[i]->maxusage; j++)
hidinput_configure_usage(hidinput, report->field[i], hidinput_configure_usage(hidinput, report->field[i],
......
...@@ -52,11 +52,14 @@ MODULE_LICENSE("GPL"); ...@@ -52,11 +52,14 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6) #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6)
#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8) #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8)
#define MT_QUIRK_NO_AREA (1 << 9) #define MT_QUIRK_NO_AREA (1 << 9)
#define MT_QUIRK_IGNORE_DUPLICATES (1 << 10)
#define MT_QUIRK_HOVERING (1 << 11)
struct mt_slot { struct mt_slot {
__s32 x, y, p, w, h; __s32 x, y, cx, cy, p, w, h;
__s32 contactid; /* the device ContactID assigned to this slot */ __s32 contactid; /* the device ContactID assigned to this slot */
bool touch_state; /* is the touch valid? */ bool touch_state; /* is the touch valid? */
bool inrange_state; /* is the finger in proximity of the sensor? */
}; };
struct mt_class { struct mt_class {
...@@ -121,6 +124,7 @@ struct mt_device { ...@@ -121,6 +124,7 @@ struct mt_device {
#define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 #define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109
#define MT_DEFAULT_MAXCONTACT 10 #define MT_DEFAULT_MAXCONTACT 10
#define MT_MAX_MAXCONTACT 250
#define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p) #define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p)
#define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p) #define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p)
...@@ -282,11 +286,26 @@ static void mt_feature_mapping(struct hid_device *hdev, ...@@ -282,11 +286,26 @@ static void mt_feature_mapping(struct hid_device *hdev,
case HID_DG_CONTACTMAX: case HID_DG_CONTACTMAX:
td->maxcontact_report_id = field->report->id; td->maxcontact_report_id = field->report->id;
td->maxcontacts = field->value[0]; td->maxcontacts = field->value[0];
if (!td->maxcontacts &&
field->logical_maximum <= MT_MAX_MAXCONTACT)
td->maxcontacts = field->logical_maximum;
if (td->mtclass.maxcontacts) if (td->mtclass.maxcontacts)
/* check if the maxcontacts is given by the class */ /* check if the maxcontacts is given by the class */
td->maxcontacts = td->mtclass.maxcontacts; td->maxcontacts = td->mtclass.maxcontacts;
break; break;
case 0xff0000c5:
if (field->report_count == 256 && field->report_size == 8) {
/* Win 8 devices need special quirks */
__s32 *quirks = &td->mtclass.quirks;
*quirks |= MT_QUIRK_ALWAYS_VALID;
*quirks |= MT_QUIRK_IGNORE_DUPLICATES;
*quirks |= MT_QUIRK_HOVERING;
*quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
*quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
*quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
}
break;
} }
} }
...@@ -297,6 +316,7 @@ static void set_abs(struct input_dev *input, unsigned int code, ...@@ -297,6 +316,7 @@ static void set_abs(struct input_dev *input, unsigned int code,
int fmax = field->logical_maximum; int fmax = field->logical_maximum;
int fuzz = snratio ? (fmax - fmin) / snratio : 0; int fuzz = snratio ? (fmax - fmin) / snratio : 0;
input_set_abs_params(input, code, fmin, fmax, fuzz, 0); input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
input_abs_set_res(input, code, hidinput_calc_abs_res(field, code));
} }
static void mt_store_field(struct hid_usage *usage, struct mt_device *td, static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
...@@ -317,6 +337,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -317,6 +337,7 @@ 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;
int code; int code;
struct hid_usage *prev_usage = NULL;
/* Only map fields from TouchScreen or TouchPad collections. /* Only map fields from TouchScreen or TouchPad collections.
* We need to ignore fields that belong to other collections * We need to ignore fields that belong to other collections
...@@ -339,23 +360,42 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -339,23 +360,42 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if (field->physical == HID_DG_STYLUS) if (field->physical == HID_DG_STYLUS)
return -1; return -1;
if (usage->usage_index)
prev_usage = &field->usage[usage->usage_index - 1];
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 (prev_usage && (prev_usage->hid == usage->hid)) {
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOOL_X);
set_abs(hi->input, ABS_MT_TOOL_X, field,
cls->sn_move);
} else {
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,
cls->sn_move); cls->sn_move);
}
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_GD_Y: case HID_GD_Y:
if (prev_usage && (prev_usage->hid == usage->hid)) {
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOOL_Y);
set_abs(hi->input, ABS_MT_TOOL_Y, field,
cls->sn_move);
} else {
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,
cls->sn_move); cls->sn_move);
}
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
...@@ -365,6 +405,12 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -365,6 +405,12 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_DIGITIZER: case HID_UP_DIGITIZER:
switch (usage->hid) { switch (usage->hid) {
case HID_DG_INRANGE: case HID_DG_INRANGE:
if (cls->quirks & MT_QUIRK_HOVERING) {
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_DISTANCE);
input_set_abs_params(hi->input,
ABS_MT_DISTANCE, 0, 1, 0, 0);
}
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
...@@ -477,18 +523,26 @@ static int mt_compute_slot(struct mt_device *td, struct input_dev *input) ...@@ -477,18 +523,26 @@ static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
*/ */
static void mt_complete_slot(struct mt_device *td, struct input_dev *input) static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
{ {
if (td->curvalid) { if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
int slotnum = mt_compute_slot(td, input); int slotnum = mt_compute_slot(td, input);
struct mt_slot *s = &td->curdata; struct mt_slot *s = &td->curdata;
struct input_mt *mt = input->mt;
if (slotnum < 0 || slotnum >= td->maxcontacts) if (slotnum < 0 || slotnum >= td->maxcontacts)
return; return;
if ((td->mtclass.quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
struct input_mt_slot *slot = &mt->slots[slotnum];
if (input_mt_is_active(slot) &&
input_mt_is_used(mt, slot))
return;
}
input_mt_slot(input, slotnum); input_mt_slot(input, slotnum);
input_mt_report_slot_state(input, MT_TOOL_FINGER, input_mt_report_slot_state(input, MT_TOOL_FINGER,
s->touch_state); s->touch_state || s->inrange_state);
if (s->touch_state) { if (s->touch_state || s->inrange_state) {
/* this finger is on the screen */ /* this finger is in proximity of the sensor */
int wide = (s->w > s->h); int wide = (s->w > s->h);
/* divided by two to match visual scale of touch */ /* divided by two to match visual scale of touch */
int major = max(s->w, s->h) >> 1; int major = max(s->w, s->h) >> 1;
...@@ -496,6 +550,10 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) ...@@ -496,6 +550,10 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
input_event(input, EV_ABS, ABS_MT_TOOL_X, s->cx);
input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy);
input_event(input, EV_ABS, ABS_MT_DISTANCE,
!s->touch_state);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
...@@ -526,10 +584,10 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, ...@@ -526,10 +584,10 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
if (hid->claimed & HID_CLAIMED_INPUT) { if (hid->claimed & HID_CLAIMED_INPUT) {
switch (usage->hid) { switch (usage->hid) {
case HID_DG_INRANGE: case HID_DG_INRANGE:
if (quirks & MT_QUIRK_ALWAYS_VALID) if (quirks & MT_QUIRK_VALID_IS_INRANGE)
td->curvalid = true;
else if (quirks & MT_QUIRK_VALID_IS_INRANGE)
td->curvalid = value; td->curvalid = value;
if (quirks & MT_QUIRK_HOVERING)
td->curdata.inrange_state = value;
break; break;
case HID_DG_TIPSWITCH: case HID_DG_TIPSWITCH:
if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
...@@ -547,9 +605,15 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, ...@@ -547,9 +605,15 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
td->curdata.p = value; td->curdata.p = value;
break; break;
case HID_GD_X: case HID_GD_X:
if (usage->code == ABS_MT_TOOL_X)
td->curdata.cx = value;
else
td->curdata.x = value; td->curdata.x = value;
break; break;
case HID_GD_Y: case HID_GD_Y:
if (usage->code == ABS_MT_TOOL_Y)
td->curdata.cy = value;
else
td->curdata.y = value; td->curdata.y = value;
break; break;
case HID_DG_WIDTH: case HID_DG_WIDTH:
...@@ -575,12 +639,15 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, ...@@ -575,12 +639,15 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
return 0; return 0;
} }
if (usage->usage_index + 1 == field->report_count) {
/* we only take into account the last report. */
if (usage->hid == td->last_slot_field) if (usage->hid == td->last_slot_field)
mt_complete_slot(td, field->hidinput->input); mt_complete_slot(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)
mt_sync_frame(td, field->hidinput->input); mt_sync_frame(td, field->hidinput->input);
}
} }
......
...@@ -167,7 +167,7 @@ static ssize_t isku_sysfs_write_ ## thingy(struct file *fp, struct kobject *kobj ...@@ -167,7 +167,7 @@ static ssize_t isku_sysfs_write_ ## thingy(struct file *fp, struct kobject *kobj
loff_t off, size_t count) \ loff_t off, size_t count) \
{ \ { \
return isku_sysfs_write(fp, kobj, buf, off, count, \ return isku_sysfs_write(fp, kobj, buf, off, count, \
sizeof(struct isku_ ## thingy), ISKU_COMMAND_ ## THINGY); \ ISKU_SIZE_ ## THINGY, ISKU_COMMAND_ ## THINGY); \
} }
#define ISKU_SYSFS_R(thingy, THINGY) \ #define ISKU_SYSFS_R(thingy, THINGY) \
...@@ -176,32 +176,32 @@ static ssize_t isku_sysfs_read_ ## thingy(struct file *fp, struct kobject *kobj, ...@@ -176,32 +176,32 @@ static ssize_t isku_sysfs_read_ ## thingy(struct file *fp, struct kobject *kobj,
loff_t off, size_t count) \ loff_t off, size_t count) \
{ \ { \
return isku_sysfs_read(fp, kobj, buf, off, count, \ return isku_sysfs_read(fp, kobj, buf, off, count, \
sizeof(struct isku_ ## thingy), ISKU_COMMAND_ ## THINGY); \ ISKU_SIZE_ ## THINGY, ISKU_COMMAND_ ## THINGY); \
} }
#define ISKU_SYSFS_RW(thingy, THINGY) \ #define ISKU_SYSFS_RW(thingy, THINGY) \
ISKU_SYSFS_R(thingy, THINGY) \ ISKU_SYSFS_R(thingy, THINGY) \
ISKU_SYSFS_W(thingy, THINGY) ISKU_SYSFS_W(thingy, THINGY)
#define ISKU_BIN_ATTR_RW(thingy) \ #define ISKU_BIN_ATTR_RW(thingy, THINGY) \
{ \ { \
.attr = { .name = #thingy, .mode = 0660 }, \ .attr = { .name = #thingy, .mode = 0660 }, \
.size = sizeof(struct isku_ ## thingy), \ .size = ISKU_SIZE_ ## THINGY, \
.read = isku_sysfs_read_ ## thingy, \ .read = isku_sysfs_read_ ## thingy, \
.write = isku_sysfs_write_ ## thingy \ .write = isku_sysfs_write_ ## thingy \
} }
#define ISKU_BIN_ATTR_R(thingy) \ #define ISKU_BIN_ATTR_R(thingy, THINGY) \
{ \ { \
.attr = { .name = #thingy, .mode = 0440 }, \ .attr = { .name = #thingy, .mode = 0440 }, \
.size = sizeof(struct isku_ ## thingy), \ .size = ISKU_SIZE_ ## THINGY, \
.read = isku_sysfs_read_ ## thingy, \ .read = isku_sysfs_read_ ## thingy, \
} }
#define ISKU_BIN_ATTR_W(thingy) \ #define ISKU_BIN_ATTR_W(thingy, THINGY) \
{ \ { \
.attr = { .name = #thingy, .mode = 0220 }, \ .attr = { .name = #thingy, .mode = 0220 }, \
.size = sizeof(struct isku_ ## thingy), \ .size = ISKU_SIZE_ ## THINGY, \
.write = isku_sysfs_write_ ## thingy \ .write = isku_sysfs_write_ ## thingy \
} }
...@@ -218,21 +218,23 @@ ISKU_SYSFS_RW(last_set, LAST_SET) ...@@ -218,21 +218,23 @@ ISKU_SYSFS_RW(last_set, LAST_SET)
ISKU_SYSFS_W(talk, TALK) ISKU_SYSFS_W(talk, TALK)
ISKU_SYSFS_R(info, INFO) ISKU_SYSFS_R(info, INFO)
ISKU_SYSFS_W(control, CONTROL) ISKU_SYSFS_W(control, CONTROL)
ISKU_SYSFS_W(reset, RESET)
static struct bin_attribute isku_bin_attributes[] = { static struct bin_attribute isku_bin_attributes[] = {
ISKU_BIN_ATTR_RW(macro), ISKU_BIN_ATTR_RW(macro, MACRO),
ISKU_BIN_ATTR_RW(keys_function), ISKU_BIN_ATTR_RW(keys_function, KEYS_FUNCTION),
ISKU_BIN_ATTR_RW(keys_easyzone), ISKU_BIN_ATTR_RW(keys_easyzone, KEYS_EASYZONE),
ISKU_BIN_ATTR_RW(keys_media), ISKU_BIN_ATTR_RW(keys_media, KEYS_MEDIA),
ISKU_BIN_ATTR_RW(keys_thumbster), ISKU_BIN_ATTR_RW(keys_thumbster, KEYS_THUMBSTER),
ISKU_BIN_ATTR_RW(keys_macro), ISKU_BIN_ATTR_RW(keys_macro, KEYS_MACRO),
ISKU_BIN_ATTR_RW(keys_capslock), ISKU_BIN_ATTR_RW(keys_capslock, KEYS_CAPSLOCK),
ISKU_BIN_ATTR_RW(light), ISKU_BIN_ATTR_RW(light, LIGHT),
ISKU_BIN_ATTR_RW(key_mask), ISKU_BIN_ATTR_RW(key_mask, KEY_MASK),
ISKU_BIN_ATTR_RW(last_set), ISKU_BIN_ATTR_RW(last_set, LAST_SET),
ISKU_BIN_ATTR_W(talk), ISKU_BIN_ATTR_W(talk, TALK),
ISKU_BIN_ATTR_R(info), ISKU_BIN_ATTR_R(info, INFO),
ISKU_BIN_ATTR_W(control), ISKU_BIN_ATTR_W(control, CONTROL),
ISKU_BIN_ATTR_W(reset, RESET),
__ATTR_NULL __ATTR_NULL
}; };
......
...@@ -14,77 +14,34 @@ ...@@ -14,77 +14,34 @@
#include <linux/types.h> #include <linux/types.h>
enum {
ISKU_SIZE_CONTROL = 0x03,
ISKU_SIZE_INFO = 0x06,
ISKU_SIZE_KEY_MASK = 0x06,
ISKU_SIZE_KEYS_FUNCTION = 0x29,
ISKU_SIZE_KEYS_EASYZONE = 0x41,
ISKU_SIZE_KEYS_MEDIA = 0x1d,
ISKU_SIZE_KEYS_THUMBSTER = 0x17,
ISKU_SIZE_KEYS_MACRO = 0x23,
ISKU_SIZE_KEYS_CAPSLOCK = 0x06,
ISKU_SIZE_LAST_SET = 0x14,
ISKU_SIZE_LIGHT = 0x0a,
ISKU_SIZE_MACRO = 0x823,
ISKU_SIZE_RESET = 0x03,
ISKU_SIZE_TALK = 0x10,
};
enum { enum {
ISKU_PROFILE_NUM = 5, ISKU_PROFILE_NUM = 5,
ISKU_USB_INTERFACE_PROTOCOL = 0, ISKU_USB_INTERFACE_PROTOCOL = 0,
}; };
struct isku_control {
uint8_t command; /* ISKU_COMMAND_CONTROL */
uint8_t value;
uint8_t request;
} __packed;
struct isku_actual_profile { struct isku_actual_profile {
uint8_t command; /* ISKU_COMMAND_ACTUAL_PROFILE */ uint8_t command; /* ISKU_COMMAND_ACTUAL_PROFILE */
uint8_t size; /* always 3 */ uint8_t size; /* always 3 */
uint8_t actual_profile; uint8_t actual_profile;
} __packed; } __packed;
struct isku_key_mask {
uint8_t command; /* ISKU_COMMAND_KEY_MASK */
uint8_t size; /* 6 */
uint8_t profile_number; /* 0-4 */
uint8_t mask;
uint16_t checksum;
} __packed;
struct isku_keys_function {
uint8_t data[0x29];
} __packed;
struct isku_keys_easyzone {
uint8_t data[0x41];
} __packed;
struct isku_keys_media {
uint8_t data[0x1d];
} __packed;
struct isku_keys_thumbster {
uint8_t data[0x17];
} __packed;
struct isku_keys_macro {
uint8_t data[0x23];
} __packed;
struct isku_keys_capslock {
uint8_t data[0x6];
} __packed;
struct isku_macro {
uint8_t data[0x823];
} __packed;
struct isku_light {
uint8_t data[0xa];
} __packed;
struct isku_info {
uint8_t data[2];
uint8_t firmware_version;
uint8_t unknown[3];
} __packed;
struct isku_talk {
uint8_t data[0x10];
} __packed;
struct isku_last_set {
uint8_t data[0x14];
} __packed;
enum isku_commands { enum isku_commands {
ISKU_COMMAND_CONTROL = 0x4, ISKU_COMMAND_CONTROL = 0x4,
ISKU_COMMAND_ACTUAL_PROFILE = 0x5, ISKU_COMMAND_ACTUAL_PROFILE = 0x5,
...@@ -97,6 +54,7 @@ enum isku_commands { ...@@ -97,6 +54,7 @@ enum isku_commands {
ISKU_COMMAND_MACRO = 0xe, ISKU_COMMAND_MACRO = 0xe,
ISKU_COMMAND_INFO = 0xf, ISKU_COMMAND_INFO = 0xf,
ISKU_COMMAND_LIGHT = 0x10, ISKU_COMMAND_LIGHT = 0x10,
ISKU_COMMAND_RESET = 0x11,
ISKU_COMMAND_KEYS_CAPSLOCK = 0x13, ISKU_COMMAND_KEYS_CAPSLOCK = 0x13,
ISKU_COMMAND_LAST_SET = 0x14, ISKU_COMMAND_LAST_SET = 0x14,
ISKU_COMMAND_15 = 0x15, ISKU_COMMAND_15 = 0x15,
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
/* /*
* Roccat Kone[+] is an updated/improved version of the Kone with more memory * Roccat Kone[+] is an updated/improved version of the Kone with more memory
* and functionality and without the non-standard behaviours the Kone had. * and functionality and without the non-standard behaviours the Kone had.
* KoneXTD has same capabilities but updated sensor.
*/ */
#include <linux/device.h> #include <linux/device.h>
...@@ -55,56 +56,6 @@ static int koneplus_send_control(struct usb_device *usb_dev, uint value, ...@@ -55,56 +56,6 @@ static int koneplus_send_control(struct usb_device *usb_dev, uint value,
&control, sizeof(struct roccat_common2_control)); &control, sizeof(struct roccat_common2_control));
} }
static int koneplus_get_info(struct usb_device *usb_dev,
struct koneplus_info *buf)
{
return roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_INFO,
buf, sizeof(struct koneplus_info));
}
static int koneplus_get_profile_settings(struct usb_device *usb_dev,
struct koneplus_profile_settings *buf, uint number)
{
int retval;
retval = koneplus_send_control(usb_dev, number,
KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
if (retval)
return retval;
return roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS,
buf, sizeof(struct koneplus_profile_settings));
}
static int koneplus_set_profile_settings(struct usb_device *usb_dev,
struct koneplus_profile_settings const *settings)
{
return roccat_common2_send_with_status(usb_dev,
KONEPLUS_COMMAND_PROFILE_SETTINGS,
settings, sizeof(struct koneplus_profile_settings));
}
static int koneplus_get_profile_buttons(struct usb_device *usb_dev,
struct koneplus_profile_buttons *buf, int number)
{
int retval;
retval = koneplus_send_control(usb_dev, number,
KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
if (retval)
return retval;
return roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS,
buf, sizeof(struct koneplus_profile_buttons));
}
static int koneplus_set_profile_buttons(struct usb_device *usb_dev,
struct koneplus_profile_buttons const *buttons)
{
return roccat_common2_send_with_status(usb_dev,
KONEPLUS_COMMAND_PROFILE_BUTTONS,
buttons, sizeof(struct koneplus_profile_buttons));
}
/* retval is 0-4 on success, < 0 on error */ /* retval is 0-4 on success, < 0 on error */
static int koneplus_get_actual_profile(struct usb_device *usb_dev) static int koneplus_get_actual_profile(struct usb_device *usb_dev)
...@@ -113,7 +64,7 @@ static int koneplus_get_actual_profile(struct usb_device *usb_dev) ...@@ -113,7 +64,7 @@ static int koneplus_get_actual_profile(struct usb_device *usb_dev)
int retval; int retval;
retval = roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE, retval = roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE,
&buf, sizeof(struct koneplus_actual_profile)); &buf, KONEPLUS_SIZE_ACTUAL_PROFILE);
return retval ? retval : buf.actual_profile; return retval ? retval : buf.actual_profile;
} }
...@@ -124,12 +75,12 @@ static int koneplus_set_actual_profile(struct usb_device *usb_dev, ...@@ -124,12 +75,12 @@ static int koneplus_set_actual_profile(struct usb_device *usb_dev,
struct koneplus_actual_profile buf; struct koneplus_actual_profile buf;
buf.command = KONEPLUS_COMMAND_ACTUAL_PROFILE; buf.command = KONEPLUS_COMMAND_ACTUAL_PROFILE;
buf.size = sizeof(struct koneplus_actual_profile); buf.size = KONEPLUS_SIZE_ACTUAL_PROFILE;
buf.actual_profile = new_profile; buf.actual_profile = new_profile;
return roccat_common2_send_with_status(usb_dev, return roccat_common2_send_with_status(usb_dev,
KONEPLUS_COMMAND_ACTUAL_PROFILE, KONEPLUS_COMMAND_ACTUAL_PROFILE,
&buf, sizeof(struct koneplus_actual_profile)); &buf, KONEPLUS_SIZE_ACTUAL_PROFILE);
} }
static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj, static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
...@@ -182,111 +133,77 @@ static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj, ...@@ -182,111 +133,77 @@ static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
return real_size; return real_size;
} }
static ssize_t koneplus_sysfs_write_talk(struct file *fp, #define KONEPLUS_SYSFS_W(thingy, THINGY) \
struct kobject *kobj, struct bin_attribute *attr, char *buf, static ssize_t koneplus_sysfs_write_ ## thingy(struct file *fp, \
loff_t off, size_t count) struct kobject *kobj, struct bin_attribute *attr, char *buf, \
{ loff_t off, size_t count) \
return koneplus_sysfs_write(fp, kobj, buf, off, count, { \
sizeof(struct koneplus_talk), KONEPLUS_COMMAND_TALK); return koneplus_sysfs_write(fp, kobj, buf, off, count, \
KONEPLUS_SIZE_ ## THINGY, KONEPLUS_COMMAND_ ## THINGY); \
} }
static ssize_t koneplus_sysfs_write_macro(struct file *fp, #define KONEPLUS_SYSFS_R(thingy, THINGY) \
struct kobject *kobj, struct bin_attribute *attr, char *buf, static ssize_t koneplus_sysfs_read_ ## thingy(struct file *fp, \
loff_t off, size_t count) struct kobject *kobj, struct bin_attribute *attr, char *buf, \
{ loff_t off, size_t count) \
return koneplus_sysfs_write(fp, kobj, buf, off, count, { \
sizeof(struct koneplus_macro), KONEPLUS_COMMAND_MACRO); return koneplus_sysfs_read(fp, kobj, buf, off, count, \
KONEPLUS_SIZE_ ## THINGY, KONEPLUS_COMMAND_ ## THINGY); \
} }
static ssize_t koneplus_sysfs_read_sensor(struct file *fp, #define KONEPLUS_SYSFS_RW(thingy, THINGY) \
struct kobject *kobj, struct bin_attribute *attr, char *buf, KONEPLUS_SYSFS_W(thingy, THINGY) \
loff_t off, size_t count) KONEPLUS_SYSFS_R(thingy, THINGY)
{
return koneplus_sysfs_read(fp, kobj, buf, off, count,
sizeof(struct koneplus_sensor), KONEPLUS_COMMAND_SENSOR);
}
static ssize_t koneplus_sysfs_write_sensor(struct file *fp, #define KONEPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \
struct kobject *kobj, struct bin_attribute *attr, char *buf, { \
loff_t off, size_t count) .attr = { .name = #thingy, .mode = 0660 }, \
{ .size = KONEPLUS_SIZE_ ## THINGY, \
return koneplus_sysfs_write(fp, kobj, buf, off, count, .read = koneplus_sysfs_read_ ## thingy, \
sizeof(struct koneplus_sensor), KONEPLUS_COMMAND_SENSOR); .write = koneplus_sysfs_write_ ## thingy \
} }
static ssize_t koneplus_sysfs_write_tcu(struct file *fp, #define KONEPLUS_BIN_ATTRIBUTE_R(thingy, THINGY) \
struct kobject *kobj, struct bin_attribute *attr, char *buf, { \
loff_t off, size_t count) .attr = { .name = #thingy, .mode = 0440 }, \
{ .size = KONEPLUS_SIZE_ ## THINGY, \
return koneplus_sysfs_write(fp, kobj, buf, off, count, .read = koneplus_sysfs_read_ ## thingy, \
sizeof(struct koneplus_tcu), KONEPLUS_COMMAND_TCU);
} }
static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp, #define KONEPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
struct kobject *kobj, struct bin_attribute *attr, char *buf, { \
loff_t off, size_t count) .attr = { .name = #thingy, .mode = 0220 }, \
{ .size = KONEPLUS_SIZE_ ## THINGY, \
return koneplus_sysfs_read(fp, kobj, buf, off, count, .write = koneplus_sysfs_write_ ## thingy \
sizeof(struct koneplus_tcu_image), KONEPLUS_COMMAND_TCU);
} }
static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp, KONEPLUS_SYSFS_W(control, CONTROL)
struct kobject *kobj, struct bin_attribute *attr, char *buf, KONEPLUS_SYSFS_RW(info, INFO)
loff_t off, size_t count) KONEPLUS_SYSFS_W(talk, TALK)
{ KONEPLUS_SYSFS_W(macro, MACRO)
struct device *dev = KONEPLUS_SYSFS_RW(sensor, SENSOR)
container_of(kobj, struct device, kobj)->parent->parent; KONEPLUS_SYSFS_RW(tcu, TCU)
struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev)); KONEPLUS_SYSFS_R(tcu_image, TCU_IMAGE)
KONEPLUS_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
if (off >= sizeof(struct koneplus_profile_settings)) KONEPLUS_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
return 0;
if (off + count > sizeof(struct koneplus_profile_settings))
count = sizeof(struct koneplus_profile_settings) - off;
mutex_lock(&koneplus->koneplus_lock); static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
memcpy(buf, ((char const *)&koneplus->profile_settings[*(uint *)(attr->private)]) + off,
count);
mutex_unlock(&koneplus->koneplus_lock);
return count;
}
static ssize_t koneplus_sysfs_write_profile_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf, struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count) loff_t off, size_t count)
{ {
struct device *dev = struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent; container_of(kobj, struct device, kobj)->parent->parent;
struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0; ssize_t retval;
int difference;
int profile_number;
struct koneplus_profile_settings *profile_settings;
if (off != 0 || count != sizeof(struct koneplus_profile_settings))
return -EINVAL;
profile_number = ((struct koneplus_profile_settings const *)buf)->number;
profile_settings = &koneplus->profile_settings[profile_number];
mutex_lock(&koneplus->koneplus_lock);
difference = memcmp(buf, profile_settings,
sizeof(struct koneplus_profile_settings));
if (difference) {
retval = koneplus_set_profile_settings(usb_dev,
(struct koneplus_profile_settings const *)buf);
if (!retval)
memcpy(profile_settings, buf,
sizeof(struct koneplus_profile_settings));
}
mutex_unlock(&koneplus->koneplus_lock);
retval = koneplus_send_control(usb_dev, *(uint *)(attr->private),
KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
if (retval) if (retval)
return retval; return retval;
return sizeof(struct koneplus_profile_settings); return koneplus_sysfs_read(fp, kobj, buf, off, count,
KONEPLUS_SIZE_PROFILE_SETTINGS,
KONEPLUS_COMMAND_PROFILE_SETTINGS);
} }
static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp, static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
...@@ -295,57 +212,17 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp, ...@@ -295,57 +212,17 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
{ {
struct device *dev = struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent; container_of(kobj, struct device, kobj)->parent->parent;
struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct koneplus_profile_buttons))
return 0;
if (off + count > sizeof(struct koneplus_profile_buttons))
count = sizeof(struct koneplus_profile_buttons) - off;
mutex_lock(&koneplus->koneplus_lock);
memcpy(buf, ((char const *)&koneplus->profile_buttons[*(uint *)(attr->private)]) + off,
count);
mutex_unlock(&koneplus->koneplus_lock);
return count;
}
static ssize_t koneplus_sysfs_write_profile_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent;
struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0; ssize_t retval;
int difference;
uint profile_number;
struct koneplus_profile_buttons *profile_buttons;
if (off != 0 || count != sizeof(struct koneplus_profile_buttons))
return -EINVAL;
profile_number = ((struct koneplus_profile_buttons const *)buf)->number;
profile_buttons = &koneplus->profile_buttons[profile_number];
mutex_lock(&koneplus->koneplus_lock);
difference = memcmp(buf, profile_buttons,
sizeof(struct koneplus_profile_buttons));
if (difference) {
retval = koneplus_set_profile_buttons(usb_dev,
(struct koneplus_profile_buttons const *)buf);
if (!retval)
memcpy(profile_buttons, buf,
sizeof(struct koneplus_profile_buttons));
}
mutex_unlock(&koneplus->koneplus_lock);
retval = koneplus_send_control(usb_dev, *(uint *)(attr->private),
KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
if (retval) if (retval)
return retval; return retval;
return sizeof(struct koneplus_profile_buttons); return koneplus_sysfs_read(fp, kobj, buf, off, count,
KONEPLUS_SIZE_PROFILE_BUTTONS,
KONEPLUS_COMMAND_PROFILE_BUTTONS);
} }
static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev, static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
...@@ -401,9 +278,20 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev, ...@@ -401,9 +278,20 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev, static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct koneplus_device *koneplus = struct koneplus_device *koneplus;
hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); struct usb_device *usb_dev;
return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->info.firmware_version); struct koneplus_info info;
dev = dev->parent->parent;
koneplus = hid_get_drvdata(dev_get_drvdata(dev));
usb_dev = interface_to_usbdev(to_usb_interface(dev));
mutex_lock(&koneplus->koneplus_lock);
roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_INFO,
&info, KONEPLUS_SIZE_INFO);
mutex_unlock(&koneplus->koneplus_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
} }
static struct device_attribute koneplus_attributes[] = { static struct device_attribute koneplus_attributes[] = {
...@@ -419,132 +307,85 @@ static struct device_attribute koneplus_attributes[] = { ...@@ -419,132 +307,85 @@ static struct device_attribute koneplus_attributes[] = {
}; };
static struct bin_attribute koneplus_bin_attributes[] = { static struct bin_attribute koneplus_bin_attributes[] = {
{ KONEPLUS_BIN_ATTRIBUTE_W(control, CONTROL),
.attr = { .name = "sensor", .mode = 0660 }, KONEPLUS_BIN_ATTRIBUTE_RW(info, INFO),
.size = sizeof(struct koneplus_sensor), KONEPLUS_BIN_ATTRIBUTE_W(talk, TALK),
.read = koneplus_sysfs_read_sensor, KONEPLUS_BIN_ATTRIBUTE_W(macro, MACRO),
.write = koneplus_sysfs_write_sensor KONEPLUS_BIN_ATTRIBUTE_RW(sensor, SENSOR),
}, KONEPLUS_BIN_ATTRIBUTE_RW(tcu, TCU),
{ KONEPLUS_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE),
.attr = { .name = "tcu", .mode = 0220 }, KONEPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
.size = sizeof(struct koneplus_tcu), KONEPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
.write = koneplus_sysfs_write_tcu
},
{
.attr = { .name = "tcu_image", .mode = 0440 },
.size = sizeof(struct koneplus_tcu_image),
.read = koneplus_sysfs_read_tcu_image
},
{
.attr = { .name = "profile_settings", .mode = 0220 },
.size = sizeof(struct koneplus_profile_settings),
.write = koneplus_sysfs_write_profile_settings
},
{ {
.attr = { .name = "profile1_settings", .mode = 0440 }, .attr = { .name = "profile1_settings", .mode = 0440 },
.size = sizeof(struct koneplus_profile_settings), .size = KONEPLUS_SIZE_PROFILE_SETTINGS,
.read = koneplus_sysfs_read_profilex_settings, .read = koneplus_sysfs_read_profilex_settings,
.private = &profile_numbers[0] .private = &profile_numbers[0]
}, },
{ {
.attr = { .name = "profile2_settings", .mode = 0440 }, .attr = { .name = "profile2_settings", .mode = 0440 },
.size = sizeof(struct koneplus_profile_settings), .size = KONEPLUS_SIZE_PROFILE_SETTINGS,
.read = koneplus_sysfs_read_profilex_settings, .read = koneplus_sysfs_read_profilex_settings,
.private = &profile_numbers[1] .private = &profile_numbers[1]
}, },
{ {
.attr = { .name = "profile3_settings", .mode = 0440 }, .attr = { .name = "profile3_settings", .mode = 0440 },
.size = sizeof(struct koneplus_profile_settings), .size = KONEPLUS_SIZE_PROFILE_SETTINGS,
.read = koneplus_sysfs_read_profilex_settings, .read = koneplus_sysfs_read_profilex_settings,
.private = &profile_numbers[2] .private = &profile_numbers[2]
}, },
{ {
.attr = { .name = "profile4_settings", .mode = 0440 }, .attr = { .name = "profile4_settings", .mode = 0440 },
.size = sizeof(struct koneplus_profile_settings), .size = KONEPLUS_SIZE_PROFILE_SETTINGS,
.read = koneplus_sysfs_read_profilex_settings, .read = koneplus_sysfs_read_profilex_settings,
.private = &profile_numbers[3] .private = &profile_numbers[3]
}, },
{ {
.attr = { .name = "profile5_settings", .mode = 0440 }, .attr = { .name = "profile5_settings", .mode = 0440 },
.size = sizeof(struct koneplus_profile_settings), .size = KONEPLUS_SIZE_PROFILE_SETTINGS,
.read = koneplus_sysfs_read_profilex_settings, .read = koneplus_sysfs_read_profilex_settings,
.private = &profile_numbers[4] .private = &profile_numbers[4]
}, },
{
.attr = { .name = "profile_buttons", .mode = 0220 },
.size = sizeof(struct koneplus_profile_buttons),
.write = koneplus_sysfs_write_profile_buttons
},
{ {
.attr = { .name = "profile1_buttons", .mode = 0440 }, .attr = { .name = "profile1_buttons", .mode = 0440 },
.size = sizeof(struct koneplus_profile_buttons), .size = KONEPLUS_SIZE_PROFILE_BUTTONS,
.read = koneplus_sysfs_read_profilex_buttons, .read = koneplus_sysfs_read_profilex_buttons,
.private = &profile_numbers[0] .private = &profile_numbers[0]
}, },
{ {
.attr = { .name = "profile2_buttons", .mode = 0440 }, .attr = { .name = "profile2_buttons", .mode = 0440 },
.size = sizeof(struct koneplus_profile_buttons), .size = KONEPLUS_SIZE_PROFILE_BUTTONS,
.read = koneplus_sysfs_read_profilex_buttons, .read = koneplus_sysfs_read_profilex_buttons,
.private = &profile_numbers[1] .private = &profile_numbers[1]
}, },
{ {
.attr = { .name = "profile3_buttons", .mode = 0440 }, .attr = { .name = "profile3_buttons", .mode = 0440 },
.size = sizeof(struct koneplus_profile_buttons), .size = KONEPLUS_SIZE_PROFILE_BUTTONS,
.read = koneplus_sysfs_read_profilex_buttons, .read = koneplus_sysfs_read_profilex_buttons,
.private = &profile_numbers[2] .private = &profile_numbers[2]
}, },
{ {
.attr = { .name = "profile4_buttons", .mode = 0440 }, .attr = { .name = "profile4_buttons", .mode = 0440 },
.size = sizeof(struct koneplus_profile_buttons), .size = KONEPLUS_SIZE_PROFILE_BUTTONS,
.read = koneplus_sysfs_read_profilex_buttons, .read = koneplus_sysfs_read_profilex_buttons,
.private = &profile_numbers[3] .private = &profile_numbers[3]
}, },
{ {
.attr = { .name = "profile5_buttons", .mode = 0440 }, .attr = { .name = "profile5_buttons", .mode = 0440 },
.size = sizeof(struct koneplus_profile_buttons), .size = KONEPLUS_SIZE_PROFILE_BUTTONS,
.read = koneplus_sysfs_read_profilex_buttons, .read = koneplus_sysfs_read_profilex_buttons,
.private = &profile_numbers[4] .private = &profile_numbers[4]
}, },
{
.attr = { .name = "macro", .mode = 0220 },
.size = sizeof(struct koneplus_macro),
.write = koneplus_sysfs_write_macro
},
{
.attr = { .name = "talk", .mode = 0220 },
.size = sizeof(struct koneplus_talk),
.write = koneplus_sysfs_write_talk
},
__ATTR_NULL __ATTR_NULL
}; };
static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev, static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
struct koneplus_device *koneplus) struct koneplus_device *koneplus)
{ {
int retval, i; int retval;
static uint wait = 200;
mutex_init(&koneplus->koneplus_lock); mutex_init(&koneplus->koneplus_lock);
retval = koneplus_get_info(usb_dev, &koneplus->info);
if (retval)
return retval;
for (i = 0; i < 5; ++i) {
msleep(wait);
retval = koneplus_get_profile_settings(usb_dev,
&koneplus->profile_settings[i], i);
if (retval)
return retval;
msleep(wait);
retval = koneplus_get_profile_buttons(usb_dev,
&koneplus->profile_buttons[i], i);
if (retval)
return retval;
}
msleep(wait);
retval = koneplus_get_actual_profile(usb_dev); retval = koneplus_get_actual_profile(usb_dev);
if (retval < 0) if (retval < 0)
return retval; return retval;
...@@ -709,6 +550,7 @@ static int koneplus_raw_event(struct hid_device *hdev, ...@@ -709,6 +550,7 @@ static int koneplus_raw_event(struct hid_device *hdev,
static const struct hid_device_id koneplus_devices[] = { static const struct hid_device_id koneplus_devices[] = {
{ 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_KONEXTD) },
{ } { }
}; };
...@@ -749,5 +591,5 @@ module_init(koneplus_init); ...@@ -749,5 +591,5 @@ module_init(koneplus_init);
module_exit(koneplus_exit); module_exit(koneplus_exit);
MODULE_AUTHOR("Stefan Achatz"); MODULE_AUTHOR("Stefan Achatz");
MODULE_DESCRIPTION("USB Roccat Kone[+] driver"); MODULE_DESCRIPTION("USB Roccat Kone[+]/XTD driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -14,11 +14,19 @@ ...@@ -14,11 +14,19 @@
#include <linux/types.h> #include <linux/types.h>
struct koneplus_talk { enum {
uint8_t command; /* KONEPLUS_COMMAND_TALK */ KONEPLUS_SIZE_ACTUAL_PROFILE = 0x03,
uint8_t size; /* always 0x10 */ KONEPLUS_SIZE_CONTROL = 0x03,
uint8_t data[14]; KONEPLUS_SIZE_FIRMWARE_WRITE = 0x0402,
} __packed; KONEPLUS_SIZE_INFO = 0x06,
KONEPLUS_SIZE_MACRO = 0x0822,
KONEPLUS_SIZE_PROFILE_SETTINGS = 0x2b,
KONEPLUS_SIZE_PROFILE_BUTTONS = 0x4d,
KONEPLUS_SIZE_SENSOR = 0x06,
KONEPLUS_SIZE_TALK = 0x10,
KONEPLUS_SIZE_TCU = 0x04,
KONEPLUS_SIZE_TCU_IMAGE = 0x0404,
};
enum koneplus_control_requests { enum koneplus_control_requests {
KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x80, KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x80,
...@@ -31,45 +39,6 @@ struct koneplus_actual_profile { ...@@ -31,45 +39,6 @@ struct koneplus_actual_profile {
uint8_t actual_profile; /* Range 0-4! */ uint8_t actual_profile; /* Range 0-4! */
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
struct koneplus_profile_settings {
uint8_t command; /* KONEPLUS_COMMAND_PROFILE_SETTINGS */
uint8_t size; /* always 43 */
uint8_t number; /* range 0-4 */
uint8_t advanced_sensitivity;
uint8_t sensitivity_x;
uint8_t sensitivity_y;
uint8_t cpi_levels_enabled;
uint8_t cpi_levels_x[5];
uint8_t cpi_startup_level; /* range 0-4 */
uint8_t cpi_levels_y[5]; /* range 1-60 means 100-6000 cpi */
uint8_t unknown1;
uint8_t polling_rate;
uint8_t lights_enabled;
uint8_t light_effect_mode;
uint8_t color_flow_effect;
uint8_t light_effect_type;
uint8_t light_effect_speed;
uint8_t lights[16];
uint16_t checksum;
} __attribute__ ((__packed__));
struct koneplus_profile_buttons {
uint8_t command; /* KONEPLUS_COMMAND_PROFILE_BUTTONS */
uint8_t size; /* always 77 */
uint8_t number; /* range 0-4 */
uint8_t data[72];
uint16_t checksum;
} __attribute__ ((__packed__));
struct koneplus_macro {
uint8_t command; /* KONEPLUS_COMMAND_MACRO */
uint16_t size; /* always 0x822 little endian */
uint8_t profile; /* range 0-4 */
uint8_t button; /* range 0-23 */
uint8_t data[2075];
uint16_t checksum;
} __attribute__ ((__packed__));
struct koneplus_info { struct koneplus_info {
uint8_t command; /* KONEPLUS_COMMAND_INFO */ uint8_t command; /* KONEPLUS_COMMAND_INFO */
uint8_t size; /* always 6 */ uint8_t size; /* always 6 */
...@@ -77,51 +46,15 @@ struct koneplus_info { ...@@ -77,51 +46,15 @@ struct koneplus_info {
uint8_t unknown[3]; uint8_t unknown[3];
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
struct koneplus_e {
uint8_t command; /* KONEPLUS_COMMAND_E */
uint8_t size; /* always 3 */
uint8_t unknown; /* TODO 1; 0 before firmware update */
} __attribute__ ((__packed__));
struct koneplus_sensor {
uint8_t command; /* KONEPLUS_COMMAND_SENSOR */
uint8_t size; /* always 6 */
uint8_t data[4];
} __attribute__ ((__packed__));
struct koneplus_firmware_write {
uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE */
uint8_t unknown[1025];
} __attribute__ ((__packed__));
struct koneplus_firmware_write_control {
uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL */
/*
* value is 1 on success
* 3 means "not finished yet"
*/
uint8_t value;
uint8_t unknown; /* always 0x75 */
} __attribute__ ((__packed__));
struct koneplus_tcu {
uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */
uint8_t data[2];
} __attribute__ ((__packed__));
struct koneplus_tcu_image {
uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */
uint8_t data[1024];
uint16_t checksum;
} __attribute__ ((__packed__));
enum koneplus_commands { enum koneplus_commands {
KONEPLUS_COMMAND_ACTUAL_PROFILE = 0x5, KONEPLUS_COMMAND_ACTUAL_PROFILE = 0x5,
KONEPLUS_COMMAND_CONTROL = 0x4,
KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6, KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7, KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
KONEPLUS_COMMAND_MACRO = 0x8, KONEPLUS_COMMAND_MACRO = 0x8,
KONEPLUS_COMMAND_INFO = 0x9, KONEPLUS_COMMAND_INFO = 0x9,
KONEPLUS_COMMAND_TCU = 0xc, KONEPLUS_COMMAND_TCU = 0xc,
KONEPLUS_COMMAND_TCU_IMAGE = 0xc,
KONEPLUS_COMMAND_E = 0xe, KONEPLUS_COMMAND_E = 0xe,
KONEPLUS_COMMAND_SENSOR = 0xf, KONEPLUS_COMMAND_SENSOR = 0xf,
KONEPLUS_COMMAND_TALK = 0x10, KONEPLUS_COMMAND_TALK = 0x10,
...@@ -187,10 +120,6 @@ struct koneplus_device { ...@@ -187,10 +120,6 @@ struct koneplus_device {
int chrdev_minor; int chrdev_minor;
struct mutex koneplus_lock; struct mutex koneplus_lock;
struct koneplus_info info;
struct koneplus_profile_settings profile_settings[5];
struct koneplus_profile_buttons profile_buttons[5];
}; };
#endif #endif
...@@ -70,13 +70,6 @@ static int kovaplus_select_profile(struct usb_device *usb_dev, uint number, ...@@ -70,13 +70,6 @@ static int kovaplus_select_profile(struct usb_device *usb_dev, uint number,
return kovaplus_send_control(usb_dev, number, request); return kovaplus_send_control(usb_dev, number, request);
} }
static int kovaplus_get_info(struct usb_device *usb_dev,
struct kovaplus_info *buf)
{
return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_INFO,
buf, sizeof(struct kovaplus_info));
}
static int kovaplus_get_profile_settings(struct usb_device *usb_dev, static int kovaplus_get_profile_settings(struct usb_device *usb_dev,
struct kovaplus_profile_settings *buf, uint number) struct kovaplus_profile_settings *buf, uint number)
{ {
...@@ -88,15 +81,7 @@ static int kovaplus_get_profile_settings(struct usb_device *usb_dev, ...@@ -88,15 +81,7 @@ static int kovaplus_get_profile_settings(struct usb_device *usb_dev,
return retval; return retval;
return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS,
buf, sizeof(struct kovaplus_profile_settings)); buf, KOVAPLUS_SIZE_PROFILE_SETTINGS);
}
static int kovaplus_set_profile_settings(struct usb_device *usb_dev,
struct kovaplus_profile_settings const *settings)
{
return roccat_common2_send_with_status(usb_dev,
KOVAPLUS_COMMAND_PROFILE_SETTINGS,
settings, sizeof(struct kovaplus_profile_settings));
} }
static int kovaplus_get_profile_buttons(struct usb_device *usb_dev, static int kovaplus_get_profile_buttons(struct usb_device *usb_dev,
...@@ -110,15 +95,7 @@ static int kovaplus_get_profile_buttons(struct usb_device *usb_dev, ...@@ -110,15 +95,7 @@ static int kovaplus_get_profile_buttons(struct usb_device *usb_dev,
return retval; return retval;
return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS,
buf, sizeof(struct kovaplus_profile_buttons)); buf, KOVAPLUS_SIZE_PROFILE_BUTTONS);
}
static int kovaplus_set_profile_buttons(struct usb_device *usb_dev,
struct kovaplus_profile_buttons const *buttons)
{
return roccat_common2_send_with_status(usb_dev,
KOVAPLUS_COMMAND_PROFILE_BUTTONS,
buttons, sizeof(struct kovaplus_profile_buttons));
} }
/* retval is 0-4 on success, < 0 on error */ /* retval is 0-4 on success, < 0 on error */
...@@ -147,122 +124,141 @@ static int kovaplus_set_actual_profile(struct usb_device *usb_dev, ...@@ -147,122 +124,141 @@ static int kovaplus_set_actual_profile(struct usb_device *usb_dev,
&buf, sizeof(struct kovaplus_actual_profile)); &buf, sizeof(struct kovaplus_actual_profile));
} }
static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp, static ssize_t kovaplus_sysfs_read(struct file *fp, struct kobject *kobj,
struct kobject *kobj, struct bin_attribute *attr, char *buf, char *buf, loff_t off, size_t count,
loff_t off, size_t count) size_t real_size, uint command)
{ {
struct device *dev = struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent; container_of(kobj, struct device, kobj)->parent->parent;
struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off >= sizeof(struct kovaplus_profile_settings)) if (off >= real_size)
return 0; return 0;
if (off + count > sizeof(struct kovaplus_profile_settings)) if (off != 0 || count != real_size)
count = sizeof(struct kovaplus_profile_settings) - off; return -EINVAL;
mutex_lock(&kovaplus->kovaplus_lock); mutex_lock(&kovaplus->kovaplus_lock);
memcpy(buf, ((char const *)&kovaplus->profile_settings[*(uint *)(attr->private)]) + off, retval = roccat_common2_receive(usb_dev, command, buf, real_size);
count);
mutex_unlock(&kovaplus->kovaplus_lock); mutex_unlock(&kovaplus->kovaplus_lock);
return count; if (retval)
return retval;
return real_size;
} }
static ssize_t kovaplus_sysfs_write_profile_settings(struct file *fp, static ssize_t kovaplus_sysfs_write(struct file *fp, struct kobject *kobj,
struct kobject *kobj, struct bin_attribute *attr, char *buf, void const *buf, loff_t off, size_t count,
loff_t off, size_t count) size_t real_size, uint command)
{ {
struct device *dev = struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent; container_of(kobj, struct device, kobj)->parent->parent;
struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0; int retval;
int difference;
int profile_index;
struct kovaplus_profile_settings *profile_settings;
if (off != 0 || count != sizeof(struct kovaplus_profile_settings)) if (off != 0 || count != real_size)
return -EINVAL; return -EINVAL;
profile_index = ((struct kovaplus_profile_settings const *)buf)->profile_index;
profile_settings = &kovaplus->profile_settings[profile_index];
mutex_lock(&kovaplus->kovaplus_lock); mutex_lock(&kovaplus->kovaplus_lock);
difference = memcmp(buf, profile_settings, retval = roccat_common2_send_with_status(usb_dev, command,
sizeof(struct kovaplus_profile_settings)); buf, real_size);
if (difference) {
retval = kovaplus_set_profile_settings(usb_dev,
(struct kovaplus_profile_settings const *)buf);
if (!retval)
memcpy(profile_settings, buf,
sizeof(struct kovaplus_profile_settings));
}
mutex_unlock(&kovaplus->kovaplus_lock); mutex_unlock(&kovaplus->kovaplus_lock);
if (retval) if (retval)
return retval; return retval;
return sizeof(struct kovaplus_profile_settings); return real_size;
} }
static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp, #define KOVAPLUS_SYSFS_W(thingy, THINGY) \
struct kobject *kobj, struct bin_attribute *attr, char *buf, static ssize_t kovaplus_sysfs_write_ ## thingy(struct file *fp, \
loff_t off, size_t count) struct kobject *kobj, struct bin_attribute *attr, char *buf, \
{ loff_t off, size_t count) \
struct device *dev = { \
container_of(kobj, struct device, kobj)->parent->parent; return kovaplus_sysfs_write(fp, kobj, buf, off, count, \
struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); KOVAPLUS_SIZE_ ## THINGY, KOVAPLUS_COMMAND_ ## THINGY); \
}
if (off >= sizeof(struct kovaplus_profile_buttons)) #define KOVAPLUS_SYSFS_R(thingy, THINGY) \
return 0; static ssize_t kovaplus_sysfs_read_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
return kovaplus_sysfs_read(fp, kobj, buf, off, count, \
KOVAPLUS_SIZE_ ## THINGY, KOVAPLUS_COMMAND_ ## THINGY); \
}
if (off + count > sizeof(struct kovaplus_profile_buttons)) #define KOVAPLUS_SYSFS_RW(thingy, THINGY) \
count = sizeof(struct kovaplus_profile_buttons) - off; KOVAPLUS_SYSFS_W(thingy, THINGY) \
KOVAPLUS_SYSFS_R(thingy, THINGY)
mutex_lock(&kovaplus->kovaplus_lock); #define KOVAPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \
memcpy(buf, ((char const *)&kovaplus->profile_buttons[*(uint *)(attr->private)]) + off, { \
count); .attr = { .name = #thingy, .mode = 0660 }, \
mutex_unlock(&kovaplus->kovaplus_lock); .size = KOVAPLUS_SIZE_ ## THINGY, \
.read = kovaplus_sysfs_read_ ## thingy, \
.write = kovaplus_sysfs_write_ ## thingy \
}
#define KOVAPLUS_BIN_ATTRIBUTE_R(thingy, THINGY) \
{ \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = KOVAPLUS_SIZE_ ## THINGY, \
.read = kovaplus_sysfs_read_ ## thingy, \
}
return count; #define KOVAPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
{ \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = KOVAPLUS_SIZE_ ## THINGY, \
.write = kovaplus_sysfs_write_ ## thingy \
} }
static ssize_t kovaplus_sysfs_write_profile_buttons(struct file *fp, KOVAPLUS_SYSFS_W(control, CONTROL)
KOVAPLUS_SYSFS_RW(info, INFO)
KOVAPLUS_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
KOVAPLUS_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf, struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count) loff_t off, size_t count)
{ {
struct device *dev = struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent; container_of(kobj, struct device, kobj)->parent->parent;
struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0; ssize_t retval;
int difference;
uint profile_index;
struct kovaplus_profile_buttons *profile_buttons;
if (off != 0 || count != sizeof(struct kovaplus_profile_buttons)) retval = kovaplus_select_profile(usb_dev, *(uint *)(attr->private),
return -EINVAL; KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
if (retval)
return retval;
profile_index = ((struct kovaplus_profile_buttons const *)buf)->profile_index; return kovaplus_sysfs_read(fp, kobj, buf, off, count,
profile_buttons = &kovaplus->profile_buttons[profile_index]; KOVAPLUS_SIZE_PROFILE_SETTINGS,
KOVAPLUS_COMMAND_PROFILE_SETTINGS);
}
mutex_lock(&kovaplus->kovaplus_lock); static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
difference = memcmp(buf, profile_buttons, struct kobject *kobj, struct bin_attribute *attr, char *buf,
sizeof(struct kovaplus_profile_buttons)); loff_t off, size_t count)
if (difference) { {
retval = kovaplus_set_profile_buttons(usb_dev, struct device *dev =
(struct kovaplus_profile_buttons const *)buf); container_of(kobj, struct device, kobj)->parent->parent;
if (!retval) struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
memcpy(profile_buttons, buf, ssize_t retval;
sizeof(struct kovaplus_profile_buttons));
}
mutex_unlock(&kovaplus->kovaplus_lock);
retval = kovaplus_select_profile(usb_dev, *(uint *)(attr->private),
KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
if (retval) if (retval)
return retval; return retval;
return sizeof(struct kovaplus_profile_buttons); return kovaplus_sysfs_read(fp, kobj, buf, off, count,
KOVAPLUS_SIZE_PROFILE_BUTTONS,
KOVAPLUS_COMMAND_PROFILE_BUTTONS);
} }
static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev, static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev,
...@@ -342,9 +338,20 @@ static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev, ...@@ -342,9 +338,20 @@ static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev,
static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev, static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct kovaplus_device *kovaplus = struct kovaplus_device *kovaplus;
hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); struct usb_device *usb_dev;
return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->info.firmware_version); struct kovaplus_info info;
dev = dev->parent->parent;
kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
usb_dev = interface_to_usbdev(to_usb_interface(dev));
mutex_lock(&kovaplus->kovaplus_lock);
roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_INFO,
&info, KOVAPLUS_SIZE_INFO);
mutex_unlock(&kovaplus->kovaplus_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
} }
static struct device_attribute kovaplus_attributes[] = { static struct device_attribute kovaplus_attributes[] = {
...@@ -363,73 +370,67 @@ static struct device_attribute kovaplus_attributes[] = { ...@@ -363,73 +370,67 @@ static struct device_attribute kovaplus_attributes[] = {
}; };
static struct bin_attribute kovaplus_bin_attributes[] = { static struct bin_attribute kovaplus_bin_attributes[] = {
{ KOVAPLUS_BIN_ATTRIBUTE_W(control, CONTROL),
.attr = { .name = "profile_settings", .mode = 0220 }, KOVAPLUS_BIN_ATTRIBUTE_RW(info, INFO),
.size = sizeof(struct kovaplus_profile_settings), KOVAPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
.write = kovaplus_sysfs_write_profile_settings KOVAPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
},
{ {
.attr = { .name = "profile1_settings", .mode = 0440 }, .attr = { .name = "profile1_settings", .mode = 0440 },
.size = sizeof(struct kovaplus_profile_settings), .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
.read = kovaplus_sysfs_read_profilex_settings, .read = kovaplus_sysfs_read_profilex_settings,
.private = &profile_numbers[0] .private = &profile_numbers[0]
}, },
{ {
.attr = { .name = "profile2_settings", .mode = 0440 }, .attr = { .name = "profile2_settings", .mode = 0440 },
.size = sizeof(struct kovaplus_profile_settings), .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
.read = kovaplus_sysfs_read_profilex_settings, .read = kovaplus_sysfs_read_profilex_settings,
.private = &profile_numbers[1] .private = &profile_numbers[1]
}, },
{ {
.attr = { .name = "profile3_settings", .mode = 0440 }, .attr = { .name = "profile3_settings", .mode = 0440 },
.size = sizeof(struct kovaplus_profile_settings), .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
.read = kovaplus_sysfs_read_profilex_settings, .read = kovaplus_sysfs_read_profilex_settings,
.private = &profile_numbers[2] .private = &profile_numbers[2]
}, },
{ {
.attr = { .name = "profile4_settings", .mode = 0440 }, .attr = { .name = "profile4_settings", .mode = 0440 },
.size = sizeof(struct kovaplus_profile_settings), .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
.read = kovaplus_sysfs_read_profilex_settings, .read = kovaplus_sysfs_read_profilex_settings,
.private = &profile_numbers[3] .private = &profile_numbers[3]
}, },
{ {
.attr = { .name = "profile5_settings", .mode = 0440 }, .attr = { .name = "profile5_settings", .mode = 0440 },
.size = sizeof(struct kovaplus_profile_settings), .size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
.read = kovaplus_sysfs_read_profilex_settings, .read = kovaplus_sysfs_read_profilex_settings,
.private = &profile_numbers[4] .private = &profile_numbers[4]
}, },
{
.attr = { .name = "profile_buttons", .mode = 0220 },
.size = sizeof(struct kovaplus_profile_buttons),
.write = kovaplus_sysfs_write_profile_buttons
},
{ {
.attr = { .name = "profile1_buttons", .mode = 0440 }, .attr = { .name = "profile1_buttons", .mode = 0440 },
.size = sizeof(struct kovaplus_profile_buttons), .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
.read = kovaplus_sysfs_read_profilex_buttons, .read = kovaplus_sysfs_read_profilex_buttons,
.private = &profile_numbers[0] .private = &profile_numbers[0]
}, },
{ {
.attr = { .name = "profile2_buttons", .mode = 0440 }, .attr = { .name = "profile2_buttons", .mode = 0440 },
.size = sizeof(struct kovaplus_profile_buttons), .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
.read = kovaplus_sysfs_read_profilex_buttons, .read = kovaplus_sysfs_read_profilex_buttons,
.private = &profile_numbers[1] .private = &profile_numbers[1]
}, },
{ {
.attr = { .name = "profile3_buttons", .mode = 0440 }, .attr = { .name = "profile3_buttons", .mode = 0440 },
.size = sizeof(struct kovaplus_profile_buttons), .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
.read = kovaplus_sysfs_read_profilex_buttons, .read = kovaplus_sysfs_read_profilex_buttons,
.private = &profile_numbers[2] .private = &profile_numbers[2]
}, },
{ {
.attr = { .name = "profile4_buttons", .mode = 0440 }, .attr = { .name = "profile4_buttons", .mode = 0440 },
.size = sizeof(struct kovaplus_profile_buttons), .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
.read = kovaplus_sysfs_read_profilex_buttons, .read = kovaplus_sysfs_read_profilex_buttons,
.private = &profile_numbers[3] .private = &profile_numbers[3]
}, },
{ {
.attr = { .name = "profile5_buttons", .mode = 0440 }, .attr = { .name = "profile5_buttons", .mode = 0440 },
.size = sizeof(struct kovaplus_profile_buttons), .size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
.read = kovaplus_sysfs_read_profilex_buttons, .read = kovaplus_sysfs_read_profilex_buttons,
.private = &profile_numbers[4] .private = &profile_numbers[4]
}, },
...@@ -444,10 +445,6 @@ static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev, ...@@ -444,10 +445,6 @@ static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
mutex_init(&kovaplus->kovaplus_lock); mutex_init(&kovaplus->kovaplus_lock);
retval = kovaplus_get_info(usb_dev, &kovaplus->info);
if (retval)
return retval;
for (i = 0; i < 5; ++i) { for (i = 0; i < 5; ++i) {
msleep(wait); msleep(wait);
retval = kovaplus_get_profile_settings(usb_dev, retval = kovaplus_get_profile_settings(usb_dev,
......
...@@ -14,6 +14,13 @@ ...@@ -14,6 +14,13 @@
#include <linux/types.h> #include <linux/types.h>
enum {
KOVAPLUS_SIZE_CONTROL = 0x03,
KOVAPLUS_SIZE_INFO = 0x06,
KOVAPLUS_SIZE_PROFILE_SETTINGS = 0x10,
KOVAPLUS_SIZE_PROFILE_BUTTONS = 0x17,
};
enum kovaplus_control_requests { enum kovaplus_control_requests {
/* write; value = profile number range 0-4 */ /* write; value = profile number range 0-4 */
KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10, KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10,
...@@ -53,15 +60,9 @@ struct kovaplus_info { ...@@ -53,15 +60,9 @@ struct kovaplus_info {
uint8_t unknown[3]; uint8_t unknown[3];
} __packed; } __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 { enum kovaplus_commands {
KOVAPLUS_COMMAND_ACTUAL_PROFILE = 0x5, KOVAPLUS_COMMAND_ACTUAL_PROFILE = 0x5,
KOVAPLUS_COMMAND_CONTROL = 0x4,
KOVAPLUS_COMMAND_PROFILE_SETTINGS = 0x6, KOVAPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
KOVAPLUS_COMMAND_PROFILE_BUTTONS = 0x7, KOVAPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
KOVAPLUS_COMMAND_INFO = 0x9, KOVAPLUS_COMMAND_INFO = 0x9,
...@@ -125,7 +126,6 @@ struct kovaplus_device { ...@@ -125,7 +126,6 @@ struct kovaplus_device {
int roccat_claimed; int roccat_claimed;
int chrdev_minor; int chrdev_minor;
struct mutex kovaplus_lock; struct mutex kovaplus_lock;
struct kovaplus_info info;
struct kovaplus_profile_settings profile_settings[5]; struct kovaplus_profile_settings profile_settings[5];
struct kovaplus_profile_buttons profile_buttons[5]; struct kovaplus_profile_buttons profile_buttons[5];
}; };
......
/*
* Roccat Lua driver for Linux
*
* Copyright (c) 2012 Stefan Achatz <erazor_de@users.sourceforge.net>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
/*
* Roccat Lua is a gamer mouse which cpi, button and light settings can be
* configured.
*/
#include <linux/device.h>
#include <linux/input.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/hid-roccat.h>
#include "hid-ids.h"
#include "hid-roccat-common.h"
#include "hid-roccat-lua.h"
static ssize_t lua_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off >= real_size)
return 0;
if (off != 0 || count != real_size)
return -EINVAL;
mutex_lock(&lua->lua_lock);
retval = roccat_common2_receive(usb_dev, command, buf, real_size);
mutex_unlock(&lua->lua_lock);
return retval ? retval : real_size;
}
static ssize_t lua_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off != 0 || count != real_size)
return -EINVAL;
mutex_lock(&lua->lua_lock);
retval = roccat_common2_send(usb_dev, command, (void *)buf, real_size);
mutex_unlock(&lua->lua_lock);
return retval ? retval : real_size;
}
#define LUA_SYSFS_W(thingy, THINGY) \
static ssize_t lua_sysfs_write_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, \
char *buf, loff_t off, size_t count) \
{ \
return lua_sysfs_write(fp, kobj, buf, off, count, \
LUA_SIZE_ ## THINGY, LUA_COMMAND_ ## THINGY); \
}
#define LUA_SYSFS_R(thingy, THINGY) \
static ssize_t lua_sysfs_read_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, \
char *buf, loff_t off, size_t count) \
{ \
return lua_sysfs_read(fp, kobj, buf, off, count, \
LUA_SIZE_ ## THINGY, LUA_COMMAND_ ## THINGY); \
}
#define LUA_BIN_ATTRIBUTE_RW(thingy, THINGY) \
LUA_SYSFS_W(thingy, THINGY) \
LUA_SYSFS_R(thingy, THINGY) \
static struct bin_attribute lua_ ## thingy ## _attr = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = LUA_SIZE_ ## THINGY, \
.read = lua_sysfs_read_ ## thingy, \
.write = lua_sysfs_write_ ## thingy \
};
LUA_BIN_ATTRIBUTE_RW(control, CONTROL)
static int lua_create_sysfs_attributes(struct usb_interface *intf)
{
return sysfs_create_bin_file(&intf->dev.kobj, &lua_control_attr);
}
static void lua_remove_sysfs_attributes(struct usb_interface *intf)
{
sysfs_remove_bin_file(&intf->dev.kobj, &lua_control_attr);
}
static int lua_init_lua_device_struct(struct usb_device *usb_dev,
struct lua_device *lua)
{
mutex_init(&lua->lua_lock);
return 0;
}
static int lua_init_specials(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct lua_device *lua;
int retval;
lua = kzalloc(sizeof(*lua), GFP_KERNEL);
if (!lua) {
hid_err(hdev, "can't alloc device descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, lua);
retval = lua_init_lua_device_struct(usb_dev, lua);
if (retval) {
hid_err(hdev, "couldn't init struct lua_device\n");
goto exit;
}
retval = lua_create_sysfs_attributes(intf);
if (retval) {
hid_err(hdev, "cannot create sysfs files\n");
goto exit;
}
return 0;
exit:
kfree(lua);
return retval;
}
static void lua_remove_specials(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct lua_device *lua;
lua_remove_sysfs_attributes(intf);
lua = hid_get_drvdata(hdev);
kfree(lua);
}
static int lua_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int retval;
retval = hid_parse(hdev);
if (retval) {
hid_err(hdev, "parse failed\n");
goto exit;
}
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (retval) {
hid_err(hdev, "hw start failed\n");
goto exit;
}
retval = lua_init_specials(hdev);
if (retval) {
hid_err(hdev, "couldn't install mouse\n");
goto exit_stop;
}
return 0;
exit_stop:
hid_hw_stop(hdev);
exit:
return retval;
}
static void lua_remove(struct hid_device *hdev)
{
lua_remove_specials(hdev);
hid_hw_stop(hdev);
}
static const struct hid_device_id lua_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },
{ }
};
MODULE_DEVICE_TABLE(hid, lua_devices);
static struct hid_driver lua_driver = {
.name = "lua",
.id_table = lua_devices,
.probe = lua_probe,
.remove = lua_remove
};
static int __init lua_init(void)
{
return hid_register_driver(&lua_driver);
}
static void __exit lua_exit(void)
{
hid_unregister_driver(&lua_driver);
}
module_init(lua_init);
module_exit(lua_exit);
MODULE_AUTHOR("Stefan Achatz");
MODULE_DESCRIPTION("USB Roccat Lua driver");
MODULE_LICENSE("GPL v2");
#ifndef __HID_ROCCAT_LUA_H
#define __HID_ROCCAT_LUA_H
/*
* Copyright (c) 2012 Stefan Achatz <erazor_de@users.sourceforge.net>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/types.h>
enum {
LUA_SIZE_CONTROL = 8,
};
enum lua_commands {
LUA_COMMAND_CONTROL = 3,
};
struct lua_device {
struct mutex lua_lock;
};
#endif
...@@ -66,48 +66,14 @@ static int pyra_get_profile_settings(struct usb_device *usb_dev, ...@@ -66,48 +66,14 @@ static int pyra_get_profile_settings(struct usb_device *usb_dev,
if (retval) if (retval)
return retval; return retval;
return roccat_common2_receive(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS, return roccat_common2_receive(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS,
buf, sizeof(struct pyra_profile_settings)); buf, PYRA_SIZE_PROFILE_SETTINGS);
}
static int pyra_get_profile_buttons(struct usb_device *usb_dev,
struct pyra_profile_buttons *buf, int number)
{
int retval;
retval = pyra_send_control(usb_dev, number,
PYRA_CONTROL_REQUEST_PROFILE_BUTTONS);
if (retval)
return retval;
return roccat_common2_receive(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS,
buf, sizeof(struct pyra_profile_buttons));
} }
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)
{ {
return roccat_common2_receive(usb_dev, PYRA_COMMAND_SETTINGS, return roccat_common2_receive(usb_dev, PYRA_COMMAND_SETTINGS,
buf, sizeof(struct pyra_settings)); buf, PYRA_SIZE_SETTINGS);
}
static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf)
{
return roccat_common2_receive(usb_dev, PYRA_COMMAND_INFO,
buf, sizeof(struct pyra_info));
}
static int pyra_set_profile_settings(struct usb_device *usb_dev,
struct pyra_profile_settings const *settings)
{
return roccat_common2_send_with_status(usb_dev,
PYRA_COMMAND_PROFILE_SETTINGS, settings,
sizeof(struct pyra_profile_settings));
}
static int pyra_set_profile_buttons(struct usb_device *usb_dev,
struct pyra_profile_buttons const *buttons)
{
return roccat_common2_send_with_status(usb_dev,
PYRA_COMMAND_PROFILE_BUTTONS, buttons,
sizeof(struct pyra_profile_buttons));
} }
static int pyra_set_settings(struct usb_device *usb_dev, static int pyra_set_settings(struct usb_device *usb_dev,
...@@ -115,146 +81,144 @@ static int pyra_set_settings(struct usb_device *usb_dev, ...@@ -115,146 +81,144 @@ static int pyra_set_settings(struct usb_device *usb_dev,
{ {
return roccat_common2_send_with_status(usb_dev, return roccat_common2_send_with_status(usb_dev,
PYRA_COMMAND_SETTINGS, settings, PYRA_COMMAND_SETTINGS, settings,
sizeof(struct pyra_settings)); PYRA_SIZE_SETTINGS);
} }
static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp, static ssize_t pyra_sysfs_read(struct file *fp, struct kobject *kobj,
struct kobject *kobj, struct bin_attribute *attr, char *buf, char *buf, loff_t off, size_t count,
loff_t off, size_t count) size_t real_size, uint command)
{ {
struct device *dev = struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent; container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off >= sizeof(struct pyra_profile_settings)) if (off >= real_size)
return 0; return 0;
if (off + count > sizeof(struct pyra_profile_settings)) if (off != 0 || count != real_size)
count = sizeof(struct pyra_profile_settings) - off; return -EINVAL;
mutex_lock(&pyra->pyra_lock); mutex_lock(&pyra->pyra_lock);
memcpy(buf, ((char const *)&pyra->profile_settings[*(uint *)(attr->private)]) + off, retval = roccat_common2_receive(usb_dev, command, buf, real_size);
count);
mutex_unlock(&pyra->pyra_lock); mutex_unlock(&pyra->pyra_lock);
return count; if (retval)
return retval;
return real_size;
} }
static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp, static ssize_t pyra_sysfs_write(struct file *fp, struct kobject *kobj,
struct kobject *kobj, struct bin_attribute *attr, char *buf, void const *buf, loff_t off, size_t count,
loff_t off, size_t count) size_t real_size, uint command)
{ {
struct device *dev = struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent; container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off >= sizeof(struct pyra_profile_buttons)) if (off != 0 || count != real_size)
return 0; return -EINVAL;
if (off + count > sizeof(struct pyra_profile_buttons))
count = sizeof(struct pyra_profile_buttons) - off;
mutex_lock(&pyra->pyra_lock); mutex_lock(&pyra->pyra_lock);
memcpy(buf, ((char const *)&pyra->profile_buttons[*(uint *)(attr->private)]) + off, retval = roccat_common2_send_with_status(usb_dev, command, (void *)buf, real_size);
count);
mutex_unlock(&pyra->pyra_lock); mutex_unlock(&pyra->pyra_lock);
return count; if (retval)
return retval;
return real_size;
} }
static ssize_t pyra_sysfs_write_profile_settings(struct file *fp, #define PYRA_SYSFS_W(thingy, THINGY) \
struct kobject *kobj, struct bin_attribute *attr, char *buf, static ssize_t pyra_sysfs_write_ ## thingy(struct file *fp, \
loff_t off, size_t count) struct kobject *kobj, struct bin_attribute *attr, char *buf, \
{ loff_t off, size_t count) \
struct device *dev = { \
container_of(kobj, struct device, kobj)->parent->parent; return pyra_sysfs_write(fp, kobj, buf, off, count, \
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); PYRA_SIZE_ ## THINGY, PYRA_COMMAND_ ## THINGY); \
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); }
int retval = 0;
int difference;
int profile_number;
struct pyra_profile_settings *profile_settings;
if (off != 0 || count != sizeof(struct pyra_profile_settings)) #define PYRA_SYSFS_R(thingy, THINGY) \
return -EINVAL; static ssize_t pyra_sysfs_read_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
return pyra_sysfs_read(fp, kobj, buf, off, count, \
PYRA_SIZE_ ## THINGY, PYRA_COMMAND_ ## THINGY); \
}
profile_number = ((struct pyra_profile_settings const *)buf)->number; #define PYRA_SYSFS_RW(thingy, THINGY) \
profile_settings = &pyra->profile_settings[profile_number]; PYRA_SYSFS_W(thingy, THINGY) \
PYRA_SYSFS_R(thingy, THINGY)
mutex_lock(&pyra->pyra_lock); #define PYRA_BIN_ATTRIBUTE_RW(thingy, THINGY) \
difference = memcmp(buf, profile_settings, { \
sizeof(struct pyra_profile_settings)); .attr = { .name = #thingy, .mode = 0660 }, \
if (difference) { .size = PYRA_SIZE_ ## THINGY, \
retval = pyra_set_profile_settings(usb_dev, .read = pyra_sysfs_read_ ## thingy, \
(struct pyra_profile_settings const *)buf); .write = pyra_sysfs_write_ ## thingy \
if (!retval) }
memcpy(profile_settings, buf,
sizeof(struct pyra_profile_settings));
}
mutex_unlock(&pyra->pyra_lock);
if (retval) #define PYRA_BIN_ATTRIBUTE_R(thingy, THINGY) \
return retval; { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = PYRA_SIZE_ ## THINGY, \
.read = pyra_sysfs_read_ ## thingy, \
}
return sizeof(struct pyra_profile_settings); #define PYRA_BIN_ATTRIBUTE_W(thingy, THINGY) \
{ \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = PYRA_SIZE_ ## THINGY, \
.write = pyra_sysfs_write_ ## thingy \
} }
static ssize_t pyra_sysfs_write_profile_buttons(struct file *fp, PYRA_SYSFS_W(control, CONTROL)
PYRA_SYSFS_RW(info, INFO)
PYRA_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
PYRA_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
PYRA_SYSFS_R(settings, SETTINGS)
static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf, struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count) loff_t off, size_t count)
{ {
struct device *dev = struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent; container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0; ssize_t retval;
int difference;
int profile_number;
struct pyra_profile_buttons *profile_buttons;
if (off != 0 || count != sizeof(struct pyra_profile_buttons))
return -EINVAL;
profile_number = ((struct pyra_profile_buttons const *)buf)->number;
profile_buttons = &pyra->profile_buttons[profile_number];
mutex_lock(&pyra->pyra_lock);
difference = memcmp(buf, profile_buttons,
sizeof(struct pyra_profile_buttons));
if (difference) {
retval = pyra_set_profile_buttons(usb_dev,
(struct pyra_profile_buttons const *)buf);
if (!retval)
memcpy(profile_buttons, buf,
sizeof(struct pyra_profile_buttons));
}
mutex_unlock(&pyra->pyra_lock);
retval = pyra_send_control(usb_dev, *(uint *)(attr->private),
PYRA_CONTROL_REQUEST_PROFILE_SETTINGS);
if (retval) if (retval)
return retval; return retval;
return sizeof(struct pyra_profile_buttons); return pyra_sysfs_read(fp, kobj, buf, off, count,
PYRA_SIZE_PROFILE_SETTINGS,
PYRA_COMMAND_PROFILE_SETTINGS);
} }
static ssize_t pyra_sysfs_read_settings(struct file *fp, static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf, struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count) loff_t off, size_t count)
{ {
struct device *dev = struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent; container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
if (off >= sizeof(struct pyra_settings))
return 0;
if (off + count > sizeof(struct pyra_settings))
count = sizeof(struct pyra_settings) - off;
mutex_lock(&pyra->pyra_lock); retval = pyra_send_control(usb_dev, *(uint *)(attr->private),
memcpy(buf, ((char const *)&pyra->settings) + off, count); PYRA_CONTROL_REQUEST_PROFILE_BUTTONS);
mutex_unlock(&pyra->pyra_lock); if (retval)
return retval;
return count; return pyra_sysfs_read(fp, kobj, buf, off, count,
PYRA_SIZE_PROFILE_BUTTONS,
PYRA_COMMAND_PROFILE_BUTTONS);
} }
static ssize_t pyra_sysfs_write_settings(struct file *fp, static ssize_t pyra_sysfs_write_settings(struct file *fp,
...@@ -266,35 +230,32 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp, ...@@ -266,35 +230,32 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0; int retval = 0;
int difference;
struct pyra_roccat_report roccat_report; struct pyra_roccat_report roccat_report;
struct pyra_settings const *settings;
if (off != 0 || count != sizeof(struct pyra_settings)) if (off != 0 || count != PYRA_SIZE_SETTINGS)
return -EINVAL; return -EINVAL;
mutex_lock(&pyra->pyra_lock); mutex_lock(&pyra->pyra_lock);
difference = memcmp(buf, &pyra->settings, sizeof(struct pyra_settings));
if (difference) { settings = (struct pyra_settings const *)buf;
retval = pyra_set_settings(usb_dev,
(struct pyra_settings const *)buf); retval = pyra_set_settings(usb_dev, settings);
if (retval) { if (retval) {
mutex_unlock(&pyra->pyra_lock); mutex_unlock(&pyra->pyra_lock);
return retval; return retval;
} }
memcpy(&pyra->settings, buf, profile_activated(pyra, settings->startup_profile);
sizeof(struct pyra_settings));
profile_activated(pyra, pyra->settings.startup_profile);
roccat_report.type = PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2; roccat_report.type = PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2;
roccat_report.value = pyra->settings.startup_profile + 1; roccat_report.value = settings->startup_profile + 1;
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);
}
mutex_unlock(&pyra->pyra_lock); mutex_unlock(&pyra->pyra_lock);
return sizeof(struct pyra_settings); return PYRA_SIZE_SETTINGS;
} }
...@@ -311,23 +272,34 @@ static ssize_t pyra_sysfs_show_actual_profile(struct device *dev, ...@@ -311,23 +272,34 @@ static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
{ {
struct pyra_device *pyra = struct pyra_device *pyra =
hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
struct pyra_settings settings;
mutex_lock(&pyra->pyra_lock);
roccat_common2_receive(usb_dev, PYRA_COMMAND_SETTINGS,
&settings, PYRA_SIZE_SETTINGS);
mutex_unlock(&pyra->pyra_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", settings.startup_profile);
} }
static ssize_t pyra_sysfs_show_firmware_version(struct device *dev, static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct pyra_device *pyra = struct pyra_device *pyra;
hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); struct usb_device *usb_dev;
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version); struct pyra_info info;
}
static ssize_t pyra_sysfs_show_startup_profile(struct device *dev, dev = dev->parent->parent;
struct device_attribute *attr, char *buf) pyra = hid_get_drvdata(dev_get_drvdata(dev));
{ usb_dev = interface_to_usbdev(to_usb_interface(dev));
struct pyra_device *pyra =
hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); mutex_lock(&pyra->pyra_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile); roccat_common2_receive(usb_dev, PYRA_COMMAND_INFO,
&info, PYRA_SIZE_INFO);
mutex_unlock(&pyra->pyra_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
} }
static struct device_attribute pyra_attributes[] = { static struct device_attribute pyra_attributes[] = {
...@@ -336,105 +308,88 @@ static struct device_attribute pyra_attributes[] = { ...@@ -336,105 +308,88 @@ static struct device_attribute pyra_attributes[] = {
__ATTR(firmware_version, 0440, __ATTR(firmware_version, 0440,
pyra_sysfs_show_firmware_version, NULL), pyra_sysfs_show_firmware_version, NULL),
__ATTR(startup_profile, 0440, __ATTR(startup_profile, 0440,
pyra_sysfs_show_startup_profile, NULL), pyra_sysfs_show_actual_profile, NULL),
__ATTR_NULL __ATTR_NULL
}; };
static struct bin_attribute pyra_bin_attributes[] = { static struct bin_attribute pyra_bin_attributes[] = {
{ PYRA_BIN_ATTRIBUTE_W(control, CONTROL),
.attr = { .name = "profile_settings", .mode = 0220 }, PYRA_BIN_ATTRIBUTE_RW(info, INFO),
.size = sizeof(struct pyra_profile_settings), PYRA_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
.write = pyra_sysfs_write_profile_settings PYRA_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
}, PYRA_BIN_ATTRIBUTE_RW(settings, SETTINGS),
{ {
.attr = { .name = "profile1_settings", .mode = 0440 }, .attr = { .name = "profile1_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings), .size = PYRA_SIZE_PROFILE_SETTINGS,
.read = pyra_sysfs_read_profilex_settings, .read = pyra_sysfs_read_profilex_settings,
.private = &profile_numbers[0] .private = &profile_numbers[0]
}, },
{ {
.attr = { .name = "profile2_settings", .mode = 0440 }, .attr = { .name = "profile2_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings), .size = PYRA_SIZE_PROFILE_SETTINGS,
.read = pyra_sysfs_read_profilex_settings, .read = pyra_sysfs_read_profilex_settings,
.private = &profile_numbers[1] .private = &profile_numbers[1]
}, },
{ {
.attr = { .name = "profile3_settings", .mode = 0440 }, .attr = { .name = "profile3_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings), .size = PYRA_SIZE_PROFILE_SETTINGS,
.read = pyra_sysfs_read_profilex_settings, .read = pyra_sysfs_read_profilex_settings,
.private = &profile_numbers[2] .private = &profile_numbers[2]
}, },
{ {
.attr = { .name = "profile4_settings", .mode = 0440 }, .attr = { .name = "profile4_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings), .size = PYRA_SIZE_PROFILE_SETTINGS,
.read = pyra_sysfs_read_profilex_settings, .read = pyra_sysfs_read_profilex_settings,
.private = &profile_numbers[3] .private = &profile_numbers[3]
}, },
{ {
.attr = { .name = "profile5_settings", .mode = 0440 }, .attr = { .name = "profile5_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings), .size = PYRA_SIZE_PROFILE_SETTINGS,
.read = pyra_sysfs_read_profilex_settings, .read = pyra_sysfs_read_profilex_settings,
.private = &profile_numbers[4] .private = &profile_numbers[4]
}, },
{
.attr = { .name = "profile_buttons", .mode = 0220 },
.size = sizeof(struct pyra_profile_buttons),
.write = pyra_sysfs_write_profile_buttons
},
{ {
.attr = { .name = "profile1_buttons", .mode = 0440 }, .attr = { .name = "profile1_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons), .size = PYRA_SIZE_PROFILE_BUTTONS,
.read = pyra_sysfs_read_profilex_buttons, .read = pyra_sysfs_read_profilex_buttons,
.private = &profile_numbers[0] .private = &profile_numbers[0]
}, },
{ {
.attr = { .name = "profile2_buttons", .mode = 0440 }, .attr = { .name = "profile2_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons), .size = PYRA_SIZE_PROFILE_BUTTONS,
.read = pyra_sysfs_read_profilex_buttons, .read = pyra_sysfs_read_profilex_buttons,
.private = &profile_numbers[1] .private = &profile_numbers[1]
}, },
{ {
.attr = { .name = "profile3_buttons", .mode = 0440 }, .attr = { .name = "profile3_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons), .size = PYRA_SIZE_PROFILE_BUTTONS,
.read = pyra_sysfs_read_profilex_buttons, .read = pyra_sysfs_read_profilex_buttons,
.private = &profile_numbers[2] .private = &profile_numbers[2]
}, },
{ {
.attr = { .name = "profile4_buttons", .mode = 0440 }, .attr = { .name = "profile4_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons), .size = PYRA_SIZE_PROFILE_BUTTONS,
.read = pyra_sysfs_read_profilex_buttons, .read = pyra_sysfs_read_profilex_buttons,
.private = &profile_numbers[3] .private = &profile_numbers[3]
}, },
{ {
.attr = { .name = "profile5_buttons", .mode = 0440 }, .attr = { .name = "profile5_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons), .size = PYRA_SIZE_PROFILE_BUTTONS,
.read = pyra_sysfs_read_profilex_buttons, .read = pyra_sysfs_read_profilex_buttons,
.private = &profile_numbers[4] .private = &profile_numbers[4]
}, },
{
.attr = { .name = "settings", .mode = 0660 },
.size = sizeof(struct pyra_settings),
.read = pyra_sysfs_read_settings,
.write = pyra_sysfs_write_settings
},
__ATTR_NULL __ATTR_NULL
}; };
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_settings settings;
int retval, i; int retval, i;
mutex_init(&pyra->pyra_lock); mutex_init(&pyra->pyra_lock);
retval = pyra_get_info(usb_dev, &info); retval = pyra_get_settings(usb_dev, &settings);
if (retval)
return retval;
pyra->firmware_version = info.firmware_version;
retval = pyra_get_settings(usb_dev, &pyra->settings);
if (retval) if (retval)
return retval; return retval;
...@@ -443,14 +398,9 @@ static int pyra_init_pyra_device_struct(struct usb_device *usb_dev, ...@@ -443,14 +398,9 @@ static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
&pyra->profile_settings[i], i); &pyra->profile_settings[i], i);
if (retval) if (retval)
return retval; return retval;
retval = pyra_get_profile_buttons(usb_dev,
&pyra->profile_buttons[i], i);
if (retval)
return retval;
} }
profile_activated(pyra, pyra->settings.startup_profile); profile_activated(pyra, settings.startup_profile);
return 0; return 0;
} }
......
...@@ -14,11 +14,13 @@ ...@@ -14,11 +14,13 @@
#include <linux/types.h> #include <linux/types.h>
struct pyra_b { enum {
uint8_t command; /* PYRA_COMMAND_B */ PYRA_SIZE_CONTROL = 0x03,
uint8_t size; /* always 3 */ PYRA_SIZE_INFO = 0x06,
uint8_t unknown; /* 1 */ PYRA_SIZE_PROFILE_SETTINGS = 0x0d,
} __attribute__ ((__packed__)); PYRA_SIZE_PROFILE_BUTTONS = 0x13,
PYRA_SIZE_SETTINGS = 0x03,
};
enum pyra_control_requests { enum pyra_control_requests {
PYRA_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10, PYRA_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10,
...@@ -46,14 +48,6 @@ struct pyra_profile_settings { ...@@ -46,14 +48,6 @@ struct pyra_profile_settings {
uint16_t checksum; /* byte sum */ uint16_t checksum; /* byte sum */
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
struct pyra_profile_buttons {
uint8_t command; /* PYRA_COMMAND_PROFILE_BUTTONS */
uint8_t size; /* always 0x13 */
uint8_t number; /* Range 0-4 */
uint8_t buttons[14];
uint16_t checksum; /* byte sum */
} __attribute__ ((__packed__));
struct pyra_info { struct pyra_info {
uint8_t command; /* PYRA_COMMAND_INFO */ uint8_t command; /* PYRA_COMMAND_INFO */
uint8_t size; /* always 6 */ uint8_t size; /* always 6 */
...@@ -64,6 +58,7 @@ struct pyra_info { ...@@ -64,6 +58,7 @@ struct pyra_info {
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
enum pyra_commands { enum pyra_commands {
PYRA_COMMAND_CONTROL = 0x4,
PYRA_COMMAND_SETTINGS = 0x5, PYRA_COMMAND_SETTINGS = 0x5,
PYRA_COMMAND_PROFILE_SETTINGS = 0x6, PYRA_COMMAND_PROFILE_SETTINGS = 0x6,
PYRA_COMMAND_PROFILE_BUTTONS = 0x7, PYRA_COMMAND_PROFILE_BUTTONS = 0x7,
...@@ -148,13 +143,10 @@ struct pyra_roccat_report { ...@@ -148,13 +143,10 @@ struct pyra_roccat_report {
struct pyra_device { struct pyra_device {
int actual_profile; int actual_profile;
int actual_cpi; int actual_cpi;
int firmware_version;
int roccat_claimed; int roccat_claimed;
int chrdev_minor; int chrdev_minor;
struct mutex pyra_lock; struct mutex pyra_lock;
struct pyra_settings settings;
struct pyra_profile_settings profile_settings[5]; struct pyra_profile_settings profile_settings[5];
struct pyra_profile_buttons profile_buttons[5];
}; };
#endif #endif
...@@ -120,7 +120,7 @@ SAVU_SYSFS_RW(profile, PROFILE) ...@@ -120,7 +120,7 @@ SAVU_SYSFS_RW(profile, PROFILE)
SAVU_SYSFS_RW(general, GENERAL) SAVU_SYSFS_RW(general, GENERAL)
SAVU_SYSFS_RW(buttons, BUTTONS) SAVU_SYSFS_RW(buttons, BUTTONS)
SAVU_SYSFS_RW(macro, MACRO) SAVU_SYSFS_RW(macro, MACRO)
SAVU_SYSFS_R(info, INFO) SAVU_SYSFS_RW(info, INFO)
SAVU_SYSFS_RW(sensor, SENSOR) SAVU_SYSFS_RW(sensor, SENSOR)
static struct bin_attribute savu_bin_attributes[] = { static struct bin_attribute savu_bin_attributes[] = {
...@@ -129,7 +129,7 @@ static struct bin_attribute savu_bin_attributes[] = { ...@@ -129,7 +129,7 @@ static struct bin_attribute savu_bin_attributes[] = {
SAVU_BIN_ATTRIBUTE_RW(general, GENERAL), SAVU_BIN_ATTRIBUTE_RW(general, GENERAL),
SAVU_BIN_ATTRIBUTE_RW(buttons, BUTTONS), SAVU_BIN_ATTRIBUTE_RW(buttons, BUTTONS),
SAVU_BIN_ATTRIBUTE_RW(macro, MACRO), SAVU_BIN_ATTRIBUTE_RW(macro, MACRO),
SAVU_BIN_ATTRIBUTE_R(info, INFO), SAVU_BIN_ATTRIBUTE_RW(info, INFO),
SAVU_BIN_ATTRIBUTE_RW(sensor, SENSOR), SAVU_BIN_ATTRIBUTE_RW(sensor, SENSOR),
__ATTR_NULL __ATTR_NULL
}; };
......
...@@ -82,23 +82,6 @@ struct hid_sensor_hub_callbacks_list { ...@@ -82,23 +82,6 @@ struct hid_sensor_hub_callbacks_list {
void *priv; void *priv;
}; };
static int sensor_hub_check_for_sensor_page(struct hid_device *hdev)
{
int i;
int ret = -EINVAL;
for (i = 0; i < hdev->maxcollection; i++) {
struct hid_collection *col = &hdev->collection[i];
if (col->type == HID_COLLECTION_PHYSICAL &&
(col->usage & HID_USAGE_PAGE) == HID_UP_SENSOR) {
ret = 0;
break;
}
}
return ret;
}
static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev, static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev,
int dir) int dir)
{ {
...@@ -437,9 +420,6 @@ static int sensor_hub_raw_event(struct hid_device *hdev, ...@@ -437,9 +420,6 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
ptr = raw_data; ptr = raw_data;
ptr++; /*Skip report id*/ ptr++; /*Skip report id*/
if (!report)
goto err_report;
spin_lock_irqsave(&pdata->lock, flags); spin_lock_irqsave(&pdata->lock, flags);
for (i = 0; i < report->maxfield; ++i) { for (i = 0; i < report->maxfield; ++i) {
...@@ -485,7 +465,6 @@ static int sensor_hub_raw_event(struct hid_device *hdev, ...@@ -485,7 +465,6 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
callback->pdev); callback->pdev);
spin_unlock_irqrestore(&pdata->lock, flags); spin_unlock_irqrestore(&pdata->lock, flags);
err_report:
return 1; return 1;
} }
...@@ -524,10 +503,6 @@ static int sensor_hub_probe(struct hid_device *hdev, ...@@ -524,10 +503,6 @@ static int sensor_hub_probe(struct hid_device *hdev,
hid_err(hdev, "parse failed\n"); hid_err(hdev, "parse failed\n");
goto err_free; goto err_free;
} }
if (sensor_hub_check_for_sensor_page(hdev) < 0) {
hid_err(hdev, "sensor page not found\n");
goto err_free;
}
INIT_LIST_HEAD(&hdev->inputs); INIT_LIST_HEAD(&hdev->inputs);
ret = hid_hw_start(hdev, 0); ret = hid_hw_start(hdev, 0);
...@@ -630,16 +605,7 @@ static void sensor_hub_remove(struct hid_device *hdev) ...@@ -630,16 +605,7 @@ static void sensor_hub_remove(struct hid_device *hdev)
} }
static const struct hid_device_id sensor_hub_devices[] = { static const struct hid_device_id sensor_hub_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, { HID_DEVICE(BUS_USB, HID_GROUP_SENSOR_HUB, HID_ANY_ID, HID_ANY_ID) },
USB_DEVICE_ID_SENSOR_HUB_1020) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
USB_DEVICE_ID_SENSOR_HUB_1020) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
USB_DEVICE_ID_SENSOR_HUB_09FA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
USB_DEVICE_ID_SENSOR_HUB_09FA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
USB_DEVICE_ID_SENSOR_HUB_7014) },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, sensor_hub_devices); MODULE_DEVICE_TABLE(hid, sensor_hub_devices);
......
...@@ -57,10 +57,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, ...@@ -57,10 +57,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
while (list->head == list->tail) { while (list->head == list->tail) {
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
break;
}
if (signal_pending(current)) { if (signal_pending(current)) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
break; break;
...@@ -69,6 +65,10 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, ...@@ -69,6 +65,10 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
ret = -EIO; ret = -EIO;
break; break;
} }
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
break;
}
/* allow O_NONBLOCK to work well from other threads */ /* allow O_NONBLOCK to work well from other threads */
mutex_unlock(&list->read_mutex); mutex_unlock(&list->read_mutex);
...@@ -295,6 +295,13 @@ static int hidraw_open(struct inode *inode, struct file *file) ...@@ -295,6 +295,13 @@ static int hidraw_open(struct inode *inode, struct file *file)
} }
static int hidraw_fasync(int fd, struct file *file, int on)
{
struct hidraw_list *list = file->private_data;
return fasync_helper(fd, file, on, &list->fasync);
}
static int hidraw_release(struct inode * inode, struct file * file) static int hidraw_release(struct inode * inode, struct file * file)
{ {
unsigned int minor = iminor(inode); unsigned int minor = iminor(inode);
...@@ -438,6 +445,7 @@ static const struct file_operations hidraw_ops = { ...@@ -438,6 +445,7 @@ static const struct file_operations hidraw_ops = {
.open = hidraw_open, .open = hidraw_open,
.release = hidraw_release, .release = hidraw_release,
.unlocked_ioctl = hidraw_ioctl, .unlocked_ioctl = hidraw_ioctl,
.fasync = hidraw_fasync,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = hidraw_ioctl, .compat_ioctl = hidraw_ioctl,
#endif #endif
......
menu "I2C HID support"
depends on I2C
config I2C_HID
tristate "HID over I2C transport layer"
default n
depends on I2C && INPUT
select HID
---help---
Say Y here if you use a keyboard, a touchpad, a touchscreen, or any
other HID based devices which is connected to your computer via I2C.
If unsure, say N.
This support is also available as a module. If so, the module
will be called i2c-hid.
endmenu
#
# Makefile for the I2C input drivers
#
obj-$(CONFIG_I2C_HID) += i2c-hid.o
/*
* HID over I2C protocol implementation
*
* Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France
* Copyright (c) 2012 Red Hat, Inc
*
* This code is partly based on "USB HID support for Linux":
*
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
* Copyright (c) 2007-2008 Oliver Neukum
* Copyright (c) 2006-2010 Jiri Kosina
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/err.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/hid.h>
#include <linux/mutex.h>
#include <linux/i2c/i2c-hid.h>
/* flags */
#define I2C_HID_STARTED (1 << 0)
#define I2C_HID_RESET_PENDING (1 << 1)
#define I2C_HID_READ_PENDING (1 << 2)
#define I2C_HID_PWR_ON 0x00
#define I2C_HID_PWR_SLEEP 0x01
/* debug option */
static bool debug;
module_param(debug, bool, 0444);
MODULE_PARM_DESC(debug, "print a lot of debug information");
#define i2c_hid_dbg(ihid, fmt, arg...) \
do { \
if (debug) \
dev_printk(KERN_DEBUG, &(ihid)->client->dev, fmt, ##arg); \
} while (0)
struct i2c_hid_desc {
__le16 wHIDDescLength;
__le16 bcdVersion;
__le16 wReportDescLength;
__le16 wReportDescRegister;
__le16 wInputRegister;
__le16 wMaxInputLength;
__le16 wOutputRegister;
__le16 wMaxOutputLength;
__le16 wCommandRegister;
__le16 wDataRegister;
__le16 wVendorID;
__le16 wProductID;
__le16 wVersionID;
__le32 reserved;
} __packed;
struct i2c_hid_cmd {
unsigned int registerIndex;
__u8 opcode;
unsigned int length;
bool wait;
};
union command {
u8 data[0];
struct cmd {
__le16 reg;
__u8 reportTypeID;
__u8 opcode;
} __packed c;
};
#define I2C_HID_CMD(opcode_) \
.opcode = opcode_, .length = 4, \
.registerIndex = offsetof(struct i2c_hid_desc, wCommandRegister)
/* fetch HID descriptor */
static const struct i2c_hid_cmd hid_descr_cmd = { .length = 2 };
/* fetch report descriptors */
static const struct i2c_hid_cmd hid_report_descr_cmd = {
.registerIndex = offsetof(struct i2c_hid_desc,
wReportDescRegister),
.opcode = 0x00,
.length = 2 };
/* commands */
static const struct i2c_hid_cmd hid_reset_cmd = { I2C_HID_CMD(0x01),
.wait = true };
static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) };
static const struct i2c_hid_cmd hid_set_report_cmd = { I2C_HID_CMD(0x03) };
static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) };
/*
* These definitions are not used here, but are defined by the spec.
* Keeping them here for documentation purposes.
*
* static const struct i2c_hid_cmd hid_get_idle_cmd = { I2C_HID_CMD(0x04) };
* static const struct i2c_hid_cmd hid_set_idle_cmd = { I2C_HID_CMD(0x05) };
* static const struct i2c_hid_cmd hid_get_protocol_cmd = { I2C_HID_CMD(0x06) };
* static const struct i2c_hid_cmd hid_set_protocol_cmd = { I2C_HID_CMD(0x07) };
*/
static DEFINE_MUTEX(i2c_hid_open_mut);
/* The main device structure */
struct i2c_hid {
struct i2c_client *client; /* i2c client */
struct hid_device *hid; /* pointer to corresponding HID dev */
union {
__u8 hdesc_buffer[sizeof(struct i2c_hid_desc)];
struct i2c_hid_desc hdesc; /* the HID Descriptor */
};
__le16 wHIDDescRegister; /* location of the i2c
* register of the HID
* descriptor. */
unsigned int bufsize; /* i2c buffer size */
char *inbuf; /* Input buffer */
char *cmdbuf; /* Command buffer */
char *argsbuf; /* Command arguments buffer */
unsigned long flags; /* device flags */
wait_queue_head_t wait; /* For waiting the interrupt */
};
static int __i2c_hid_command(struct i2c_client *client,
const struct i2c_hid_cmd *command, u8 reportID,
u8 reportType, u8 *args, int args_len,
unsigned char *buf_recv, int data_len)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
union command *cmd = (union command *)ihid->cmdbuf;
int ret;
struct i2c_msg msg[2];
int msg_num = 1;
int length = command->length;
bool wait = command->wait;
unsigned int registerIndex = command->registerIndex;
/* special case for hid_descr_cmd */
if (command == &hid_descr_cmd) {
cmd->c.reg = ihid->wHIDDescRegister;
} else {
cmd->data[0] = ihid->hdesc_buffer[registerIndex];
cmd->data[1] = ihid->hdesc_buffer[registerIndex + 1];
}
if (length > 2) {
cmd->c.opcode = command->opcode;
cmd->c.reportTypeID = reportID | reportType << 4;
}
memcpy(cmd->data + length, args, args_len);
length += args_len;
i2c_hid_dbg(ihid, "%s: cmd=%*ph\n", __func__, length, cmd->data);
msg[0].addr = client->addr;
msg[0].flags = client->flags & I2C_M_TEN;
msg[0].len = length;
msg[0].buf = cmd->data;
if (data_len > 0) {
msg[1].addr = client->addr;
msg[1].flags = client->flags & I2C_M_TEN;
msg[1].flags |= I2C_M_RD;
msg[1].len = data_len;
msg[1].buf = buf_recv;
msg_num = 2;
set_bit(I2C_HID_READ_PENDING, &ihid->flags);
}
if (wait)
set_bit(I2C_HID_RESET_PENDING, &ihid->flags);
ret = i2c_transfer(client->adapter, msg, msg_num);
if (data_len > 0)
clear_bit(I2C_HID_READ_PENDING, &ihid->flags);
if (ret != msg_num)
return ret < 0 ? ret : -EIO;
ret = 0;
if (wait) {
i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
if (!wait_event_timeout(ihid->wait,
!test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
msecs_to_jiffies(5000)))
ret = -ENODATA;
i2c_hid_dbg(ihid, "%s: finished.\n", __func__);
}
return ret;
}
static int i2c_hid_command(struct i2c_client *client,
const struct i2c_hid_cmd *command,
unsigned char *buf_recv, int data_len)
{
return __i2c_hid_command(client, command, 0, 0, NULL, 0,
buf_recv, data_len);
}
static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
u8 reportID, unsigned char *buf_recv, int data_len)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
u8 args[3];
int ret;
int args_len = 0;
u16 readRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
i2c_hid_dbg(ihid, "%s\n", __func__);
if (reportID >= 0x0F) {
args[args_len++] = reportID;
reportID = 0x0F;
}
args[args_len++] = readRegister & 0xFF;
args[args_len++] = readRegister >> 8;
ret = __i2c_hid_command(client, &hid_get_report_cmd, reportID,
reportType, args, args_len, buf_recv, data_len);
if (ret) {
dev_err(&client->dev,
"failed to retrieve report from device.\n");
return ret;
}
return 0;
}
static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
u8 reportID, unsigned char *buf, size_t data_len)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
u8 *args = ihid->argsbuf;
int ret;
u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
/* hidraw already checked that data_len < HID_MAX_BUFFER_SIZE */
u16 size = 2 /* size */ +
(reportID ? 1 : 0) /* reportID */ +
data_len /* buf */;
int args_len = (reportID >= 0x0F ? 1 : 0) /* optional third byte */ +
2 /* dataRegister */ +
size /* args */;
int index = 0;
i2c_hid_dbg(ihid, "%s\n", __func__);
if (reportID >= 0x0F) {
args[index++] = reportID;
reportID = 0x0F;
}
args[index++] = dataRegister & 0xFF;
args[index++] = dataRegister >> 8;
args[index++] = size & 0xFF;
args[index++] = size >> 8;
if (reportID)
args[index++] = reportID;
memcpy(&args[index], buf, data_len);
ret = __i2c_hid_command(client, &hid_set_report_cmd, reportID,
reportType, args, args_len, NULL, 0);
if (ret) {
dev_err(&client->dev, "failed to set a report to device.\n");
return ret;
}
return data_len;
}
static int i2c_hid_set_power(struct i2c_client *client, int power_state)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret;
i2c_hid_dbg(ihid, "%s\n", __func__);
ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state,
0, NULL, 0, NULL, 0);
if (ret)
dev_err(&client->dev, "failed to change power setting.\n");
return ret;
}
static int i2c_hid_hwreset(struct i2c_client *client)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret;
i2c_hid_dbg(ihid, "%s\n", __func__);
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
if (ret)
return ret;
i2c_hid_dbg(ihid, "resetting...\n");
ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0);
if (ret) {
dev_err(&client->dev, "failed to reset device.\n");
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
return ret;
}
return 0;
}
static void i2c_hid_get_input(struct i2c_hid *ihid)
{
int ret, ret_size;
int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
ret = i2c_master_recv(ihid->client, ihid->inbuf, size);
if (ret != size) {
if (ret < 0)
return;
dev_err(&ihid->client->dev, "%s: got %d data instead of %d\n",
__func__, ret, size);
return;
}
ret_size = ihid->inbuf[0] | ihid->inbuf[1] << 8;
if (!ret_size) {
/* host or device initiated RESET completed */
if (test_and_clear_bit(I2C_HID_RESET_PENDING, &ihid->flags))
wake_up(&ihid->wait);
return;
}
if (ret_size > size) {
dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
__func__, size, ret_size);
return;
}
i2c_hid_dbg(ihid, "input: %*ph\n", ret_size, ihid->inbuf);
if (test_bit(I2C_HID_STARTED, &ihid->flags))
hid_input_report(ihid->hid, HID_INPUT_REPORT, ihid->inbuf + 2,
ret_size - 2, 1);
return;
}
static irqreturn_t i2c_hid_irq(int irq, void *dev_id)
{
struct i2c_hid *ihid = dev_id;
if (test_bit(I2C_HID_READ_PENDING, &ihid->flags))
return IRQ_HANDLED;
i2c_hid_get_input(ihid);
return IRQ_HANDLED;
}
static int i2c_hid_get_report_length(struct hid_report *report)
{
return ((report->size - 1) >> 3) + 1 +
report->device->report_enum[report->type].numbered + 2;
}
static void i2c_hid_init_report(struct hid_report *report, u8 *buffer,
size_t bufsize)
{
struct hid_device *hid = report->device;
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
unsigned int size, ret_size;
size = i2c_hid_get_report_length(report);
if (i2c_hid_get_report(client,
report->type == HID_FEATURE_REPORT ? 0x03 : 0x01,
report->id, buffer, size))
return;
i2c_hid_dbg(ihid, "report (len=%d): %*ph\n", size, size, ihid->inbuf);
ret_size = buffer[0] | (buffer[1] << 8);
if (ret_size != size) {
dev_err(&client->dev, "error in %s size:%d / ret_size:%d\n",
__func__, size, ret_size);
return;
}
/* hid->driver_lock is held as we are in probe function,
* we just need to setup the input fields, so using
* hid_report_raw_event is safe. */
hid_report_raw_event(hid, report->type, buffer + 2, size - 2, 1);
}
/*
* Initialize all reports
*/
static void i2c_hid_init_reports(struct hid_device *hid)
{
struct hid_report *report;
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
u8 *inbuf = kzalloc(ihid->bufsize, GFP_KERNEL);
if (!inbuf) {
dev_err(&client->dev, "can not retrieve initial reports\n");
return;
}
list_for_each_entry(report,
&hid->report_enum[HID_INPUT_REPORT].report_list, list)
i2c_hid_init_report(report, inbuf, ihid->bufsize);
list_for_each_entry(report,
&hid->report_enum[HID_FEATURE_REPORT].report_list, list)
i2c_hid_init_report(report, inbuf, ihid->bufsize);
kfree(inbuf);
}
/*
* Traverse the supplied list of reports and find the longest
*/
static void i2c_hid_find_max_report(struct hid_device *hid, unsigned int type,
unsigned int *max)
{
struct hid_report *report;
unsigned int size;
/* We should not rely on wMaxInputLength, as some devices may set it to
* a wrong length. */
list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
size = i2c_hid_get_report_length(report);
if (*max < size)
*max = size;
}
}
static void i2c_hid_free_buffers(struct i2c_hid *ihid)
{
kfree(ihid->inbuf);
kfree(ihid->argsbuf);
kfree(ihid->cmdbuf);
ihid->inbuf = NULL;
ihid->cmdbuf = NULL;
ihid->argsbuf = NULL;
ihid->bufsize = 0;
}
static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size)
{
/* the worst case is computed from the set_report command with a
* reportID > 15 and the maximum report length */
int args_len = sizeof(__u8) + /* optional ReportID byte */
sizeof(__u16) + /* data register */
sizeof(__u16) + /* size of the report */
report_size; /* report */
ihid->inbuf = kzalloc(report_size, GFP_KERNEL);
ihid->argsbuf = kzalloc(args_len, GFP_KERNEL);
ihid->cmdbuf = kzalloc(sizeof(union command) + args_len, GFP_KERNEL);
if (!ihid->inbuf || !ihid->argsbuf || !ihid->cmdbuf) {
i2c_hid_free_buffers(ihid);
return -ENOMEM;
}
ihid->bufsize = report_size;
return 0;
}
static int i2c_hid_get_raw_report(struct hid_device *hid,
unsigned char report_number, __u8 *buf, size_t count,
unsigned char report_type)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
size_t ret_count, ask_count;
int ret;
if (report_type == HID_OUTPUT_REPORT)
return -EINVAL;
/* +2 bytes to include the size of the reply in the query buffer */
ask_count = min(count + 2, (size_t)ihid->bufsize);
ret = i2c_hid_get_report(client,
report_type == HID_FEATURE_REPORT ? 0x03 : 0x01,
report_number, ihid->inbuf, ask_count);
if (ret < 0)
return ret;
ret_count = ihid->inbuf[0] | (ihid->inbuf[1] << 8);
if (ret_count <= 2)
return 0;
ret_count = min(ret_count, ask_count);
/* The query buffer contains the size, dropping it in the reply */
count = min(count, ret_count - 2);
memcpy(buf, ihid->inbuf + 2, count);
return count;
}
static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
size_t count, unsigned char report_type)
{
struct i2c_client *client = hid->driver_data;
int report_id = buf[0];
if (report_type == HID_INPUT_REPORT)
return -EINVAL;
return i2c_hid_set_report(client,
report_type == HID_FEATURE_REPORT ? 0x03 : 0x02,
report_id, buf, count);
}
static int i2c_hid_parse(struct hid_device *hid)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
struct i2c_hid_desc *hdesc = &ihid->hdesc;
unsigned int rsize;
char *rdesc;
int ret;
int tries = 3;
i2c_hid_dbg(ihid, "entering %s\n", __func__);
rsize = le16_to_cpu(hdesc->wReportDescLength);
if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
dbg_hid("weird size of report descriptor (%u)\n", rsize);
return -EINVAL;
}
do {
ret = i2c_hid_hwreset(client);
if (ret)
msleep(1000);
} while (tries-- > 0 && ret);
if (ret)
return ret;
rdesc = kzalloc(rsize, GFP_KERNEL);
if (!rdesc) {
dbg_hid("couldn't allocate rdesc memory\n");
return -ENOMEM;
}
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
if (ret) {
hid_err(hid, "reading report descriptor failed\n");
kfree(rdesc);
return -EIO;
}
i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
ret = hid_parse_report(hid, rdesc, rsize);
kfree(rdesc);
if (ret) {
dbg_hid("parsing report descriptor failed\n");
return ret;
}
return 0;
}
static int i2c_hid_start(struct hid_device *hid)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret;
unsigned int bufsize = HID_MIN_BUFFER_SIZE;
i2c_hid_find_max_report(hid, HID_INPUT_REPORT, &bufsize);
i2c_hid_find_max_report(hid, HID_OUTPUT_REPORT, &bufsize);
i2c_hid_find_max_report(hid, HID_FEATURE_REPORT, &bufsize);
if (bufsize > ihid->bufsize) {
i2c_hid_free_buffers(ihid);
ret = i2c_hid_alloc_buffers(ihid, bufsize);
if (ret)
return ret;
}
if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
i2c_hid_init_reports(hid);
return 0;
}
static void i2c_hid_stop(struct hid_device *hid)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
hid->claimed = 0;
i2c_hid_free_buffers(ihid);
}
static int i2c_hid_open(struct hid_device *hid)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret = 0;
mutex_lock(&i2c_hid_open_mut);
if (!hid->open++) {
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
if (ret) {
hid->open--;
goto done;
}
set_bit(I2C_HID_STARTED, &ihid->flags);
}
done:
mutex_unlock(&i2c_hid_open_mut);
return ret;
}
static void i2c_hid_close(struct hid_device *hid)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
/* protecting hid->open to make sure we don't restart
* data acquistion due to a resumption we no longer
* care about
*/
mutex_lock(&i2c_hid_open_mut);
if (!--hid->open) {
clear_bit(I2C_HID_STARTED, &ihid->flags);
/* Save some power */
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
}
mutex_unlock(&i2c_hid_open_mut);
}
static int i2c_hid_power(struct hid_device *hid, int lvl)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret = 0;
i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl);
switch (lvl) {
case PM_HINT_FULLON:
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
break;
case PM_HINT_NORMAL:
ret = i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
break;
}
return ret;
}
static int i2c_hid_hidinput_input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hid_field *field;
int offset;
if (type == EV_FF)
return input_ff_event(dev, type, code, value);
if (type != EV_LED)
return -1;
offset = hidinput_find_field(hid, type, code, &field);
if (offset == -1) {
hid_warn(dev, "event field not found\n");
return -1;
}
return hid_set_field(field, offset, value);
}
static struct hid_ll_driver i2c_hid_ll_driver = {
.parse = i2c_hid_parse,
.start = i2c_hid_start,
.stop = i2c_hid_stop,
.open = i2c_hid_open,
.close = i2c_hid_close,
.power = i2c_hid_power,
.hidinput_input_event = i2c_hid_hidinput_input_event,
};
static int __devinit i2c_hid_init_irq(struct i2c_client *client)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret;
dev_dbg(&client->dev, "Requesting IRQ: %d\n", client->irq);
ret = request_threaded_irq(client->irq, NULL, i2c_hid_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, ihid);
if (ret < 0) {
dev_warn(&client->dev,
"Could not register for %s interrupt, irq = %d,"
" ret = %d\n",
client->name, client->irq, ret);
return ret;
}
return 0;
}
static int __devinit i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
{
struct i2c_client *client = ihid->client;
struct i2c_hid_desc *hdesc = &ihid->hdesc;
unsigned int dsize;
int ret;
/* Fetch the length of HID description, retrieve the 4 first bytes:
* bytes 0-1 -> length
* bytes 2-3 -> bcdVersion (has to be 1.00) */
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, 4);
i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %*ph\n",
__func__, 4, ihid->hdesc_buffer);
if (ret) {
dev_err(&client->dev,
"unable to fetch the size of HID descriptor (ret=%d)\n",
ret);
return -ENODEV;
}
dsize = le16_to_cpu(hdesc->wHIDDescLength);
/*
* the size of the HID descriptor should at least contain
* its size and the bcdVersion (4 bytes), and should not be greater
* than sizeof(struct i2c_hid_desc) as we directly fill this struct
* through i2c_hid_command.
*/
if (dsize < 4 || dsize > sizeof(struct i2c_hid_desc)) {
dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
dsize);
return -ENODEV;
}
/* check bcdVersion == 1.0 */
if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) {
dev_err(&client->dev,
"unexpected HID descriptor bcdVersion (0x%04hx)\n",
le16_to_cpu(hdesc->bcdVersion));
return -ENODEV;
}
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
dsize);
if (ret) {
dev_err(&client->dev, "hid_descr_cmd Fail\n");
return -ENODEV;
}
i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer);
return 0;
}
static int __devinit i2c_hid_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
int ret;
struct i2c_hid *ihid;
struct hid_device *hid;
__u16 hidRegister;
struct i2c_hid_platform_data *platform_data = client->dev.platform_data;
dbg_hid("HID probe called for i2c 0x%02x\n", client->addr);
if (!platform_data) {
dev_err(&client->dev, "HID register address not provided\n");
return -EINVAL;
}
if (!client->irq) {
dev_err(&client->dev,
"HID over i2c has not been provided an Int IRQ\n");
return -EINVAL;
}
ihid = kzalloc(sizeof(struct i2c_hid), GFP_KERNEL);
if (!ihid)
return -ENOMEM;
i2c_set_clientdata(client, ihid);
ihid->client = client;
hidRegister = platform_data->hid_descriptor_address;
ihid->wHIDDescRegister = cpu_to_le16(hidRegister);
init_waitqueue_head(&ihid->wait);
/* we need to allocate the command buffer without knowing the maximum
* size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the
* real computation later. */
ret = i2c_hid_alloc_buffers(ihid, HID_MIN_BUFFER_SIZE);
if (ret < 0)
goto err;
ret = i2c_hid_fetch_hid_descriptor(ihid);
if (ret < 0)
goto err;
ret = i2c_hid_init_irq(client);
if (ret < 0)
goto err;
hid = hid_allocate_device();
if (IS_ERR(hid)) {
ret = PTR_ERR(hid);
goto err_irq;
}
ihid->hid = hid;
hid->driver_data = client;
hid->ll_driver = &i2c_hid_ll_driver;
hid->hid_get_raw_report = i2c_hid_get_raw_report;
hid->hid_output_raw_report = i2c_hid_output_raw_report;
hid->dev.parent = &client->dev;
hid->bus = BUS_I2C;
hid->version = le16_to_cpu(ihid->hdesc.bcdVersion);
hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID);
hid->product = le16_to_cpu(ihid->hdesc.wProductID);
snprintf(hid->name, sizeof(hid->name), "%s %04hX:%04hX",
client->name, hid->vendor, hid->product);
ret = hid_add_device(hid);
if (ret) {
if (ret != -ENODEV)
hid_err(client, "can't add hid device: %d\n", ret);
goto err_mem_free;
}
return 0;
err_mem_free:
hid_destroy_device(hid);
err_irq:
free_irq(client->irq, ihid);
err:
i2c_hid_free_buffers(ihid);
kfree(ihid);
return ret;
}
static int __devexit i2c_hid_remove(struct i2c_client *client)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
struct hid_device *hid;
hid = ihid->hid;
hid_destroy_device(hid);
free_irq(client->irq, ihid);
if (ihid->bufsize)
i2c_hid_free_buffers(ihid);
kfree(ihid);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int i2c_hid_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
/* Save some power */
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
return 0;
}
static int i2c_hid_resume(struct device *dev)
{
int ret;
struct i2c_client *client = to_i2c_client(dev);
ret = i2c_hid_hwreset(client);
if (ret)
return ret;
if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(i2c_hid_pm, i2c_hid_suspend, i2c_hid_resume);
static const struct i2c_device_id i2c_hid_id_table[] = {
{ "hid", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, i2c_hid_id_table);
static struct i2c_driver i2c_hid_driver = {
.driver = {
.name = "i2c_hid",
.owner = THIS_MODULE,
.pm = &i2c_hid_pm,
},
.probe = i2c_hid_probe,
.remove = __devexit_p(i2c_hid_remove),
.id_table = i2c_hid_id_table,
};
module_i2c_driver(i2c_hid_driver);
MODULE_DESCRIPTION("HID over I2C core driver");
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
MODULE_LICENSE("GPL");
...@@ -72,6 +72,7 @@ static const struct hid_blacklist { ...@@ -72,6 +72,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS },
...@@ -79,9 +80,11 @@ static const struct hid_blacklist { ...@@ -79,9 +80,11 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
......
...@@ -361,10 +361,6 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun ...@@ -361,10 +361,6 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
prepare_to_wait(&list->hiddev->wait, &wait, TASK_INTERRUPTIBLE); prepare_to_wait(&list->hiddev->wait, &wait, TASK_INTERRUPTIBLE);
while (list->head == list->tail) { while (list->head == list->tail) {
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
}
if (signal_pending(current)) { if (signal_pending(current)) {
retval = -ERESTARTSYS; retval = -ERESTARTSYS;
break; break;
...@@ -373,6 +369,10 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun ...@@ -373,6 +369,10 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
retval = -EIO; retval = -EIO;
break; break;
} }
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
}
/* let O_NONBLOCK tasks run */ /* let O_NONBLOCK tasks run */
mutex_unlock(&list->thread_lock); mutex_unlock(&list->thread_lock);
...@@ -625,7 +625,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -625,7 +625,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break; break;
case HIDIOCAPPLICATION: case HIDIOCAPPLICATION:
if (arg < 0 || arg >= hid->maxapplication) if (arg >= hid->maxapplication)
break; break;
for (i = 0; i < hid->maxcollection; i++) for (i = 0; i < hid->maxcollection; i++)
......
...@@ -251,7 +251,7 @@ void input_mt_sync_frame(struct input_dev *dev) ...@@ -251,7 +251,7 @@ void input_mt_sync_frame(struct input_dev *dev)
if (mt->flags & INPUT_MT_DROP_UNUSED) { if (mt->flags & INPUT_MT_DROP_UNUSED) {
for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
if (s->frame == mt->frame) if (input_mt_is_used(mt, s))
continue; continue;
input_mt_slot(dev, s - mt->slots); input_mt_slot(dev, s - mt->slots);
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#ifndef _HID_SENSORS_IDS_H #ifndef _HID_SENSORS_IDS_H
#define _HID_SENSORS_IDS_H #define _HID_SENSORS_IDS_H
#define HID_UP_SENSOR 0x00200000
#define HID_MAX_PHY_DEVICES 0xFF #define HID_MAX_PHY_DEVICES 0xFF
/* Accel 3D (200073) */ /* Accel 3D (200073) */
......
...@@ -167,6 +167,7 @@ struct hid_item { ...@@ -167,6 +167,7 @@ struct hid_item {
#define HID_UP_MSVENDOR 0xff000000 #define HID_UP_MSVENDOR 0xff000000
#define HID_UP_CUSTOM 0x00ff0000 #define HID_UP_CUSTOM 0x00ff0000
#define HID_UP_LOGIVENDOR 0xffbc0000 #define HID_UP_LOGIVENDOR 0xffbc0000
#define HID_UP_SENSOR 0x00200000
#define HID_USAGE 0x0000ffff #define HID_USAGE 0x0000ffff
...@@ -292,6 +293,7 @@ struct hid_item { ...@@ -292,6 +293,7 @@ struct hid_item {
*/ */
#define HID_GROUP_GENERIC 0x0001 #define HID_GROUP_GENERIC 0x0001
#define HID_GROUP_MULTITOUCH 0x0002 #define HID_GROUP_MULTITOUCH 0x0002
#define HID_GROUP_SENSOR_HUB 0x0003
/* /*
* This is the global environment of the parser. This information is * This is the global environment of the parser. This information is
...@@ -342,6 +344,7 @@ struct hid_collection { ...@@ -342,6 +344,7 @@ struct hid_collection {
struct hid_usage { struct hid_usage {
unsigned hid; /* hid usage code */ unsigned hid; /* hid usage code */
unsigned collection_index; /* index into collection array */ unsigned collection_index; /* index into collection array */
unsigned usage_index; /* index into usage array */
/* hidinput data */ /* hidinput data */
__u16 code; /* input driver code */ __u16 code; /* input driver code */
__u8 type; /* input driver type */ __u8 type; /* input driver type */
...@@ -684,6 +687,7 @@ struct hid_ll_driver { ...@@ -684,6 +687,7 @@ struct hid_ll_driver {
extern int hid_debug; extern int hid_debug;
extern bool hid_ignore(struct hid_device *);
extern int hid_add_device(struct hid_device *); extern int hid_add_device(struct hid_device *);
extern void hid_destroy_device(struct hid_device *); extern void hid_destroy_device(struct hid_device *);
...@@ -706,6 +710,7 @@ int hid_input_report(struct hid_device *, int type, u8 *, int, int); ...@@ -706,6 +710,7 @@ int hid_input_report(struct hid_device *, int type, u8 *, int, int);
int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
struct hid_field *hidinput_get_led_field(struct hid_device *hid); struct hid_field *hidinput_get_led_field(struct hid_device *hid);
unsigned int hidinput_count_leds(struct hid_device *hid); unsigned int hidinput_count_leds(struct hid_device *hid);
__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
void hid_output_report(struct hid_report *report, __u8 *data); void hid_output_report(struct hid_report *report, __u8 *data);
struct hid_device *hid_allocate_device(void); struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
...@@ -716,6 +721,7 @@ int hid_connect(struct hid_device *hid, unsigned int connect_mask); ...@@ -716,6 +721,7 @@ int hid_connect(struct hid_device *hid, unsigned int connect_mask);
void hid_disconnect(struct hid_device *hid); void hid_disconnect(struct hid_device *hid);
const struct hid_device_id *hid_match_id(struct hid_device *hdev, const struct hid_device_id *hid_match_id(struct hid_device *hdev,
const struct hid_device_id *id); const struct hid_device_id *id);
s32 hid_snto32(__u32 value, unsigned n);
/** /**
* hid_map_usage - map usage input bits * hid_map_usage - map usage input bits
......
/*
* HID over I2C protocol implementation
*
* Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2012 Ecole Nationale de l'Aviation Civile, France
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#ifndef __LINUX_I2C_HID_H
#define __LINUX_I2C_HID_H
#include <linux/types.h>
/**
* struct i2chid_platform_data - used by hid over i2c implementation.
* @hid_descriptor_address: i2c register where the HID descriptor is stored.
*
* Note that it is the responsibility of the platform driver (or the acpi 5.0
* driver) to setup the irq related to the gpio in the struct i2c_board_info.
* The platform driver should also setup the gpio according to the device:
*
* A typical example is the following:
* irq = gpio_to_irq(intr_gpio);
* hkdk4412_i2c_devs5[0].irq = irq; // store the irq in i2c_board_info
* gpio_request(intr_gpio, "elan-irq");
* s3c_gpio_setpull(intr_gpio, S3C_GPIO_PULL_UP);
*/
struct i2c_hid_platform_data {
u16 hid_descriptor_address;
};
#endif /* __LINUX_I2C_HID_H */
...@@ -69,6 +69,12 @@ static inline bool input_mt_is_active(const struct input_mt_slot *slot) ...@@ -69,6 +69,12 @@ static inline bool input_mt_is_active(const struct input_mt_slot *slot)
return input_mt_get_value(slot, ABS_MT_TRACKING_ID) >= 0; return input_mt_get_value(slot, ABS_MT_TRACKING_ID) >= 0;
} }
static inline bool input_mt_is_used(const struct input_mt *mt,
const struct input_mt_slot *slot)
{
return slot->frame == mt->frame;
}
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots, int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
unsigned int flags); unsigned int flags);
void input_mt_destroy_slots(struct input_dev *dev); void input_mt_destroy_slots(struct input_dev *dev);
......
...@@ -851,6 +851,7 @@ struct input_keymap_entry { ...@@ -851,6 +851,7 @@ struct input_keymap_entry {
#define MSC_GESTURE 0x02 #define MSC_GESTURE 0x02
#define MSC_RAW 0x03 #define MSC_RAW 0x03
#define MSC_SCAN 0x04 #define MSC_SCAN 0x04
#define MSC_TIMESTAMP 0x05
#define MSC_MAX 0x07 #define MSC_MAX 0x07
#define MSC_CNT (MSC_MAX+1) #define MSC_CNT (MSC_MAX+1)
......
...@@ -945,6 +945,13 @@ static int hidp_setup_hid(struct hidp_session *session, ...@@ -945,6 +945,13 @@ static int hidp_setup_hid(struct hidp_session *session,
hid->hid_get_raw_report = hidp_get_raw_report; hid->hid_get_raw_report = hidp_get_raw_report;
hid->hid_output_raw_report = hidp_output_raw_report; hid->hid_output_raw_report = hidp_output_raw_report;
/* True if device is blacklisted in drivers/hid/hid-core.c */
if (hid_ignore(hid)) {
hid_destroy_device(session->hid);
session->hid = NULL;
return -ENODEV;
}
return 0; return 0;
fault: fault:
...@@ -1017,7 +1024,7 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, ...@@ -1017,7 +1024,7 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
if (req->rd_size > 0) { if (req->rd_size > 0) {
err = hidp_setup_hid(session, req); err = hidp_setup_hid(session, req);
if (err) if (err && err != -ENODEV)
goto purge; goto purge;
} }
......
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