Merge branches 'for-4.3/upstream-fixes', 'for-4.4/corsair', 'for-4.4/dragonrise', 'for-4.4/i2c-hid', 'for-4.4/logitech', 'for-4.4/microsoft', 'for-4.4/multitouch', 'for-4.4/roccat-sysfs-deprecation', 'for-4.4/upstream' and 'for-4.4/wacom' into for-linus
This commit is contained in:
parent
df70793805
937804f3c7
18339f59c3
f3984edc17
29fae1c851
c6956eb70e
6d4f5440a3
8d2f8479da
636a89d43e
86e88f0e70
commit
d64e19db03
|
@ -1,3 +1,14 @@
|
|||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/actual_profile
|
||||
Date: October 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 actual
|
||||
profile. This value is persistent, so its equivalent to the
|
||||
profile that's active when the mouse is powered on next time.
|
||||
When written, this file sets the number of the startup profile
|
||||
and the mouse activates this profile immediately.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/startup_profile
|
||||
Date: October 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
|
@ -22,6 +33,40 @@ Description: When read, this file returns the raw integer version number of the
|
|||
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>/info
|
||||
Date: November 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read, this file returns general data like firmware version.
|
||||
When written, the device can be reset.
|
||||
The data is 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>/koneplus/roccatkoneplus<minor>/macro
|
||||
Date: October 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse can store a macro with max 500 key/button strokes
|
||||
internally.
|
||||
When written, this file lets one set the sequence for a specific
|
||||
button for a specific profile. Button and profile numbers are
|
||||
included in written data. The data has to be 2082 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_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 written, this file lets one write the respective profile
|
||||
buttons back to the mouse. The data has to be 77 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_buttons
|
||||
Date: August 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
|
@ -34,6 +79,22 @@ Description: The mouse can store 5 profiles which can be switched by the
|
|||
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_settings
|
||||
Date: October 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 written, this file lets one write the respective profile
|
||||
settings back to the mouse. The data has to be 43 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_settings
|
||||
Date: August 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
|
@ -45,4 +106,40 @@ Description: The mouse can store 5 profiles which can be switched by the
|
|||
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
|
||||
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
|
||||
Date: October 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse has a tracking- and a distance-control-unit. These
|
||||
can be activated/deactivated and the lift-off distance can be
|
||||
set. The data has to be 6 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/talk
|
||||
Date: May 2011
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: Used to active some easy* functions of the mouse from outside.
|
||||
The data has to be 16 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu
|
||||
Date: October 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When written a calibration process for the tracking control unit
|
||||
can be initiated/cancelled. Also lets one read/write sensor
|
||||
registers.
|
||||
The data has to be 4 bytes long.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu_image
|
||||
Date: October 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read the mouse returns a 30x30 pixel image of the
|
||||
sampled underground. This works only in the course of a
|
||||
calibration process initiated with tcu.
|
||||
The returned data is 1028 bytes in size.
|
||||
This file is readonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
|
|
@ -8,6 +8,17 @@ Description: The integer value of this attribute ranges from 1-4.
|
|||
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_profile
|
||||
Date: January 2011
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The integer value of this attribute ranges from 0-4.
|
||||
When read, this attribute returns the number of the active
|
||||
profile.
|
||||
When written, the mouse activates this profile immediately.
|
||||
The profile that's active when powered down is the same that's
|
||||
active when the mouse is powered on.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_sensitivity_x
|
||||
Date: January 2011
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
|
@ -40,6 +51,29 @@ Description: When read, this file returns the raw integer version number of the
|
|||
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>/info
|
||||
Date: November 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read, this file returns general data like firmware version.
|
||||
When written, the device can be reset.
|
||||
The data is 6 bytes long.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_buttons
|
||||
Date: January 2011
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse can store 5 profiles which can be switched by the
|
||||
press of a button. A profile is split in settings and buttons.
|
||||
profile_buttons holds information about button layout.
|
||||
When written, this file lets one write the respective profile
|
||||
buttons back to the mouse. The data has to be 23 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile[1-5]_buttons
|
||||
Date: January 2011
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
|
@ -52,6 +86,22 @@ Description: The mouse can store 5 profiles which can be switched by the
|
|||
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_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 written, this file lets one write the respective profile
|
||||
settings back to the mouse. The data has to be 16 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile[1-5]_settings
|
||||
Date: January 2011
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
|
|
|
@ -37,6 +37,29 @@ Description: When read, this file returns the raw integer version number of the
|
|||
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>/info
|
||||
Date: November 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read, this file returns general data like firmware version.
|
||||
When written, the device can be reset.
|
||||
The data is 6 bytes long.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_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 written, this file lets one write the respective profile
|
||||
buttons back to the mouse. The data has to be 19 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_buttons
|
||||
Date: August 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
|
@ -49,6 +72,22 @@ Description: The mouse can store 5 profiles which can be switched by the
|
|||
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_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 written, this file lets one write the respective profile
|
||||
settings back to the mouse. The data has to be 13 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_settings
|
||||
Date: August 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
|
@ -62,6 +101,17 @@ Description: The mouse can store 5 profiles which can be switched by the
|
|||
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>/settings
|
||||
Date: August 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read, this file returns the settings stored in the mouse.
|
||||
The size of the data is 3 bytes and holds information on the
|
||||
startup_profile.
|
||||
When written, this file lets write settings back to the mouse.
|
||||
The data has to be 3 bytes long. The mouse will reject invalid
|
||||
data.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/startup_profile
|
||||
Date: August 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
What: /sys/bus/drivers/corsair/<dev>/macro_mode
|
||||
Date: August 2015
|
||||
KernelVersion: 4.2
|
||||
Contact: Clement Vuchener <clement.vuchener@gmail.com>
|
||||
Description: Get/set the current playback mode. "SW" for software mode
|
||||
where G-keys triggers their regular key codes. "HW" for
|
||||
hardware playback mode where the G-keys play their macro
|
||||
from the on-board memory.
|
||||
|
||||
|
||||
What: /sys/bus/drivers/corsair/<dev>/current_profile
|
||||
Date: August 2015
|
||||
KernelVersion: 4.2
|
||||
Contact: Clement Vuchener <clement.vuchener@gmail.com>
|
||||
Description: Get/set the current selected profile. Values are from 1 to 3.
|
|
@ -1,96 +0,0 @@
|
|||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/actual_profile
|
||||
Date: October 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 actual
|
||||
profile. This value is persistent, so its equivalent to the
|
||||
profile that's active when the mouse is powered on next time.
|
||||
When written, this file sets the number of the startup profile
|
||||
and the mouse activates this profile immediately.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/info
|
||||
Date: November 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read, this file returns general data like firmware version.
|
||||
When written, the device can be reset.
|
||||
The data is 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>/koneplus/roccatkoneplus<minor>/macro
|
||||
Date: October 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse can store a macro with max 500 key/button strokes
|
||||
internally.
|
||||
When written, this file lets one set the sequence for a specific
|
||||
button for a specific profile. Button and profile numbers are
|
||||
included in written data. The data has to be 2082 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_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 written, this file lets one write the respective profile
|
||||
buttons back to the mouse. The data has to be 77 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile_settings
|
||||
Date: October 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 written, this file lets one write the respective profile
|
||||
settings back to the mouse. The data has to be 43 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/sensor
|
||||
Date: October 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse has a tracking- and a distance-control-unit. These
|
||||
can be activated/deactivated and the lift-off distance can be
|
||||
set. The data has to be 6 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/talk
|
||||
Date: May 2011
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: Used to active some easy* functions of the mouse from outside.
|
||||
The data has to be 16 bytes long.
|
||||
This file is writeonly.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu
|
||||
Date: October 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When written a calibration process for the tracking control unit
|
||||
can be initiated/cancelled. Also lets one read/write sensor
|
||||
registers.
|
||||
The data has to be 4 bytes long.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu_image
|
||||
Date: October 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read the mouse returns a 30x30 pixel image of the
|
||||
sampled underground. This works only in the course of a
|
||||
calibration process initiated with tcu.
|
||||
The returned data is 1028 bytes in size.
|
||||
This file is readonly.
|
||||
Users: http://roccat.sourceforge.net
|
|
@ -1,49 +0,0 @@
|
|||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_profile
|
||||
Date: January 2011
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The integer value of this attribute ranges from 0-4.
|
||||
When read, this attribute returns the number of the active
|
||||
profile.
|
||||
When written, the mouse activates this profile immediately.
|
||||
The profile that's active when powered down is the same that's
|
||||
active when the mouse is powered on.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/info
|
||||
Date: November 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read, this file returns general data like firmware version.
|
||||
When written, the device can be reset.
|
||||
The data is 6 bytes long.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_buttons
|
||||
Date: January 2011
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse can store 5 profiles which can be switched by the
|
||||
press of a button. A profile is split in settings and buttons.
|
||||
profile_buttons holds information about button layout.
|
||||
When written, this file lets one write the respective profile
|
||||
buttons back to the mouse. The data has to be 23 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/profile_settings
|
||||
Date: January 2011
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: The mouse can store 5 profiles which can be switched by the
|
||||
press of a button. A profile is split in settings and buttons.
|
||||
profile_settings holds information like resolution, sensitivity
|
||||
and light effects.
|
||||
When written, this file lets one write the respective profile
|
||||
settings back to the mouse. The data has to be 16 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
|
@ -1,49 +0,0 @@
|
|||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/info
|
||||
Date: November 2012
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read, this file returns general data like firmware version.
|
||||
When written, the device can be reset.
|
||||
The data is 6 bytes long.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_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 written, this file lets one write the respective profile
|
||||
settings back to the mouse. The data has to be 13 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile_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 written, this file lets one write the respective profile
|
||||
buttons back to the mouse. The data has to be 19 bytes long.
|
||||
The mouse will reject invalid data.
|
||||
Which profile to write is determined by the profile number
|
||||
contained in the data.
|
||||
Before reading this file, control has to be written to select
|
||||
which profile to read.
|
||||
Users: http://roccat.sourceforge.net
|
||||
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/settings
|
||||
Date: August 2010
|
||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||
Description: When read, this file returns the settings stored in the mouse.
|
||||
The size of the data is 3 bytes and holds information on the
|
||||
startup_profile.
|
||||
When written, this file lets write settings back to the mouse.
|
||||
The data has to be 3 bytes long. The mouse will reject invalid
|
||||
data.
|
||||
Users: http://roccat.sourceforge.net
|
|
@ -171,6 +171,16 @@ config HID_CHICONY
|
|||
---help---
|
||||
Support for Chicony Tactical pad.
|
||||
|
||||
config HID_CORSAIR
|
||||
tristate "Corsair devices"
|
||||
depends on HID && USB && LEDS_CLASS
|
||||
---help---
|
||||
Support for Corsair devices that are not fully compliant with the
|
||||
HID standard.
|
||||
|
||||
Supported devices:
|
||||
- Vengeance K90
|
||||
|
||||
config HID_PRODIKEYS
|
||||
tristate "Prodikeys PC-MIDI Keyboard support"
|
||||
depends on HID && SND
|
||||
|
@ -672,9 +682,8 @@ config HID_SAITEK
|
|||
|
||||
Supported devices:
|
||||
- PS1000 Dual Analog Pad
|
||||
- R.A.T.9 Gaming Mouse
|
||||
- R.A.T.7 Gaming Mouse
|
||||
- M.M.O.7 Gaming Mouse
|
||||
- Saitek R.A.T.7, R.A.T.9, M.M.O.7 Gaming Mice
|
||||
- Mad Catz R.A.T.5, R.A.T.9 Gaming Mice
|
||||
|
||||
config HID_SAMSUNG
|
||||
tristate "Samsung InfraRed remote control or keyboards"
|
||||
|
|
|
@ -29,6 +29,7 @@ obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
|
|||
obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o
|
||||
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
|
||||
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
|
||||
obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o
|
||||
obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
|
||||
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
|
||||
obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
|
||||
|
|
|
@ -256,7 +256,7 @@ static int appleir_raw_event(struct hid_device *hid, struct hid_report *report,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void appleir_input_configured(struct hid_device *hid,
|
||||
static int appleir_input_configured(struct hid_device *hid,
|
||||
struct hid_input *hidinput)
|
||||
{
|
||||
struct input_dev *input_dev = hidinput->input;
|
||||
|
@ -275,6 +275,8 @@ static void appleir_input_configured(struct hid_device *hid,
|
|||
for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++)
|
||||
set_bit(appleir->keymap[i], input_dev->keybit);
|
||||
clear_bit(KEY_RESERVED, input_dev->keybit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int appleir_input_mapping(struct hid_device *hid,
|
||||
|
|
|
@ -23,7 +23,8 @@ static __u8 *aureal_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|||
if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) {
|
||||
dev_info(&hdev->dev, "fixing Aureal Cy se W-01RN USB_V3.1 report descriptor.\n");
|
||||
rdesc[53] = 0x65;
|
||||
} return rdesc;
|
||||
}
|
||||
return rdesc;
|
||||
}
|
||||
|
||||
static const struct hid_device_id aureal_devices[] = {
|
||||
|
|
|
@ -725,6 +725,7 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
|
|||
|
||||
if (hid->vendor == USB_VENDOR_ID_MICROSOFT &&
|
||||
(hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 ||
|
||||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 ||
|
||||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP ||
|
||||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 ||
|
||||
hid->product == USB_DEVICE_ID_MS_POWER_COVER) &&
|
||||
|
@ -1678,6 +1679,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
|
|||
case BUS_BLUETOOTH:
|
||||
bus = "BLUETOOTH";
|
||||
break;
|
||||
case BUS_I2C:
|
||||
bus = "I2C";
|
||||
break;
|
||||
default:
|
||||
bus = "<UNKNOWN>";
|
||||
}
|
||||
|
@ -1828,6 +1832,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
|
||||
|
@ -1896,6 +1901,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
|
||||
|
@ -1928,6 +1934,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) },
|
||||
|
@ -1981,6 +1988,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT5) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
|
||||
#endif
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
|
||||
|
|
|
@ -0,0 +1,673 @@
|
|||
/*
|
||||
* HID driver for Corsair devices
|
||||
*
|
||||
* Supported devices:
|
||||
* - Vengeance K90 Keyboard
|
||||
*
|
||||
* Copyright (c) 2015 Clement Vuchener
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
#define CORSAIR_USE_K90_MACRO (1<<0)
|
||||
#define CORSAIR_USE_K90_BACKLIGHT (1<<1)
|
||||
|
||||
struct k90_led {
|
||||
struct led_classdev cdev;
|
||||
int brightness;
|
||||
struct work_struct work;
|
||||
bool removed;
|
||||
};
|
||||
|
||||
struct k90_drvdata {
|
||||
struct k90_led record_led;
|
||||
};
|
||||
|
||||
struct corsair_drvdata {
|
||||
unsigned long quirks;
|
||||
struct k90_drvdata *k90;
|
||||
struct k90_led *backlight;
|
||||
};
|
||||
|
||||
#define K90_GKEY_COUNT 18
|
||||
|
||||
static int corsair_usage_to_gkey(unsigned int usage)
|
||||
{
|
||||
/* G1 (0xd0) to G16 (0xdf) */
|
||||
if (usage >= 0xd0 && usage <= 0xdf)
|
||||
return usage - 0xd0 + 1;
|
||||
/* G17 (0xe8) to G18 (0xe9) */
|
||||
if (usage >= 0xe8 && usage <= 0xe9)
|
||||
return usage - 0xe8 + 17;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned short corsair_gkey_map[K90_GKEY_COUNT] = {
|
||||
BTN_TRIGGER_HAPPY1,
|
||||
BTN_TRIGGER_HAPPY2,
|
||||
BTN_TRIGGER_HAPPY3,
|
||||
BTN_TRIGGER_HAPPY4,
|
||||
BTN_TRIGGER_HAPPY5,
|
||||
BTN_TRIGGER_HAPPY6,
|
||||
BTN_TRIGGER_HAPPY7,
|
||||
BTN_TRIGGER_HAPPY8,
|
||||
BTN_TRIGGER_HAPPY9,
|
||||
BTN_TRIGGER_HAPPY10,
|
||||
BTN_TRIGGER_HAPPY11,
|
||||
BTN_TRIGGER_HAPPY12,
|
||||
BTN_TRIGGER_HAPPY13,
|
||||
BTN_TRIGGER_HAPPY14,
|
||||
BTN_TRIGGER_HAPPY15,
|
||||
BTN_TRIGGER_HAPPY16,
|
||||
BTN_TRIGGER_HAPPY17,
|
||||
BTN_TRIGGER_HAPPY18,
|
||||
};
|
||||
|
||||
module_param_array_named(gkey_codes, corsair_gkey_map, ushort, NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(gkey_codes, "Key codes for the G-keys");
|
||||
|
||||
static unsigned short corsair_record_keycodes[2] = {
|
||||
BTN_TRIGGER_HAPPY19,
|
||||
BTN_TRIGGER_HAPPY20
|
||||
};
|
||||
|
||||
module_param_array_named(recordkey_codes, corsair_record_keycodes, ushort,
|
||||
NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(recordkey_codes, "Key codes for the MR (start and stop record) button");
|
||||
|
||||
static unsigned short corsair_profile_keycodes[3] = {
|
||||
BTN_TRIGGER_HAPPY21,
|
||||
BTN_TRIGGER_HAPPY22,
|
||||
BTN_TRIGGER_HAPPY23
|
||||
};
|
||||
|
||||
module_param_array_named(profilekey_codes, corsair_profile_keycodes, ushort,
|
||||
NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(profilekey_codes, "Key codes for the profile buttons");
|
||||
|
||||
#define CORSAIR_USAGE_SPECIAL_MIN 0xf0
|
||||
#define CORSAIR_USAGE_SPECIAL_MAX 0xff
|
||||
|
||||
#define CORSAIR_USAGE_MACRO_RECORD_START 0xf6
|
||||
#define CORSAIR_USAGE_MACRO_RECORD_STOP 0xf7
|
||||
|
||||
#define CORSAIR_USAGE_PROFILE 0xf1
|
||||
#define CORSAIR_USAGE_M1 0xf1
|
||||
#define CORSAIR_USAGE_M2 0xf2
|
||||
#define CORSAIR_USAGE_M3 0xf3
|
||||
#define CORSAIR_USAGE_PROFILE_MAX 0xf3
|
||||
|
||||
#define CORSAIR_USAGE_META_OFF 0xf4
|
||||
#define CORSAIR_USAGE_META_ON 0xf5
|
||||
|
||||
#define CORSAIR_USAGE_LIGHT 0xfa
|
||||
#define CORSAIR_USAGE_LIGHT_OFF 0xfa
|
||||
#define CORSAIR_USAGE_LIGHT_DIM 0xfb
|
||||
#define CORSAIR_USAGE_LIGHT_MEDIUM 0xfc
|
||||
#define CORSAIR_USAGE_LIGHT_BRIGHT 0xfd
|
||||
#define CORSAIR_USAGE_LIGHT_MAX 0xfd
|
||||
|
||||
/* USB control protocol */
|
||||
|
||||
#define K90_REQUEST_BRIGHTNESS 49
|
||||
#define K90_REQUEST_MACRO_MODE 2
|
||||
#define K90_REQUEST_STATUS 4
|
||||
#define K90_REQUEST_GET_MODE 5
|
||||
#define K90_REQUEST_PROFILE 20
|
||||
|
||||
#define K90_MACRO_MODE_SW 0x0030
|
||||
#define K90_MACRO_MODE_HW 0x0001
|
||||
|
||||
#define K90_MACRO_LED_ON 0x0020
|
||||
#define K90_MACRO_LED_OFF 0x0040
|
||||
|
||||
/*
|
||||
* LED class devices
|
||||
*/
|
||||
|
||||
#define K90_BACKLIGHT_LED_SUFFIX "::backlight"
|
||||
#define K90_RECORD_LED_SUFFIX "::record"
|
||||
|
||||
static enum led_brightness k90_backlight_get(struct led_classdev *led_cdev)
|
||||
{
|
||||
int ret;
|
||||
struct k90_led *led = container_of(led_cdev, struct k90_led, cdev);
|
||||
struct device *dev = led->cdev.dev->parent;
|
||||
struct usb_interface *usbif = to_usb_interface(dev->parent);
|
||||
struct usb_device *usbdev = interface_to_usbdev(usbif);
|
||||
int brightness;
|
||||
char data[8];
|
||||
|
||||
ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
|
||||
K90_REQUEST_STATUS,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, 0, 0, data, 8,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
dev_warn(dev, "Failed to get K90 initial state (error %d).\n",
|
||||
ret);
|
||||
return -EIO;
|
||||
}
|
||||
brightness = data[4];
|
||||
if (brightness < 0 || brightness > 3) {
|
||||
dev_warn(dev,
|
||||
"Read invalid backlight brightness: %02hhx.\n",
|
||||
data[4]);
|
||||
return -EIO;
|
||||
}
|
||||
return brightness;
|
||||
}
|
||||
|
||||
static enum led_brightness k90_record_led_get(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct k90_led *led = container_of(led_cdev, struct k90_led, cdev);
|
||||
|
||||
return led->brightness;
|
||||
}
|
||||
|
||||
static void k90_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct k90_led *led = container_of(led_cdev, struct k90_led, cdev);
|
||||
|
||||
led->brightness = brightness;
|
||||
schedule_work(&led->work);
|
||||
}
|
||||
|
||||
static void k90_backlight_work(struct work_struct *work)
|
||||
{
|
||||
int ret;
|
||||
struct k90_led *led = container_of(work, struct k90_led, work);
|
||||
struct device *dev;
|
||||
struct usb_interface *usbif;
|
||||
struct usb_device *usbdev;
|
||||
|
||||
if (led->removed)
|
||||
return;
|
||||
|
||||
dev = led->cdev.dev->parent;
|
||||
usbif = to_usb_interface(dev->parent);
|
||||
usbdev = interface_to_usbdev(usbif);
|
||||
|
||||
ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
|
||||
K90_REQUEST_BRIGHTNESS,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, led->brightness, 0,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (ret != 0)
|
||||
dev_warn(dev, "Failed to set backlight brightness (error: %d).\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
static void k90_record_led_work(struct work_struct *work)
|
||||
{
|
||||
int ret;
|
||||
struct k90_led *led = container_of(work, struct k90_led, work);
|
||||
struct device *dev;
|
||||
struct usb_interface *usbif;
|
||||
struct usb_device *usbdev;
|
||||
int value;
|
||||
|
||||
if (led->removed)
|
||||
return;
|
||||
|
||||
dev = led->cdev.dev->parent;
|
||||
usbif = to_usb_interface(dev->parent);
|
||||
usbdev = interface_to_usbdev(usbif);
|
||||
|
||||
if (led->brightness > 0)
|
||||
value = K90_MACRO_LED_ON;
|
||||
else
|
||||
value = K90_MACRO_LED_OFF;
|
||||
|
||||
ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
|
||||
K90_REQUEST_MACRO_MODE,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, value, 0, NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (ret != 0)
|
||||
dev_warn(dev, "Failed to set record LED state (error: %d).\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Keyboard attributes
|
||||
*/
|
||||
|
||||
static ssize_t k90_show_macro_mode(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int ret;
|
||||
struct usb_interface *usbif = to_usb_interface(dev->parent);
|
||||
struct usb_device *usbdev = interface_to_usbdev(usbif);
|
||||
const char *macro_mode;
|
||||
char data[8];
|
||||
|
||||
ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
|
||||
K90_REQUEST_GET_MODE,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, 0, 0, data, 2,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
dev_warn(dev, "Failed to get K90 initial mode (error %d).\n",
|
||||
ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
switch (data[0]) {
|
||||
case K90_MACRO_MODE_HW:
|
||||
macro_mode = "HW";
|
||||
break;
|
||||
|
||||
case K90_MACRO_MODE_SW:
|
||||
macro_mode = "SW";
|
||||
break;
|
||||
default:
|
||||
dev_warn(dev, "K90 in unknown mode: %02hhx.\n",
|
||||
data[0]);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", macro_mode);
|
||||
}
|
||||
|
||||
static ssize_t k90_store_macro_mode(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
struct usb_interface *usbif = to_usb_interface(dev->parent);
|
||||
struct usb_device *usbdev = interface_to_usbdev(usbif);
|
||||
__u16 value;
|
||||
|
||||
if (strncmp(buf, "SW", 2) == 0)
|
||||
value = K90_MACRO_MODE_SW;
|
||||
else if (strncmp(buf, "HW", 2) == 0)
|
||||
value = K90_MACRO_MODE_HW;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
|
||||
K90_REQUEST_MACRO_MODE,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, value, 0, NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (ret != 0) {
|
||||
dev_warn(dev, "Failed to set macro mode.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t k90_show_current_profile(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int ret;
|
||||
struct usb_interface *usbif = to_usb_interface(dev->parent);
|
||||
struct usb_device *usbdev = interface_to_usbdev(usbif);
|
||||
int current_profile;
|
||||
char data[8];
|
||||
|
||||
ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
|
||||
K90_REQUEST_STATUS,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, 0, 0, data, 8,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
dev_warn(dev, "Failed to get K90 initial state (error %d).\n",
|
||||
ret);
|
||||
return -EIO;
|
||||
}
|
||||
current_profile = data[7];
|
||||
if (current_profile < 1 || current_profile > 3) {
|
||||
dev_warn(dev, "Read invalid current profile: %02hhx.\n",
|
||||
data[7]);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", current_profile);
|
||||
}
|
||||
|
||||
static ssize_t k90_store_current_profile(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
struct usb_interface *usbif = to_usb_interface(dev->parent);
|
||||
struct usb_device *usbdev = interface_to_usbdev(usbif);
|
||||
int profile;
|
||||
|
||||
if (kstrtoint(buf, 10, &profile))
|
||||
return -EINVAL;
|
||||
if (profile < 1 || profile > 3)
|
||||
return -EINVAL;
|
||||
|
||||
ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
|
||||
K90_REQUEST_PROFILE,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR |
|
||||
USB_RECIP_DEVICE, profile, 0, NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (ret != 0) {
|
||||
dev_warn(dev, "Failed to change current profile (error %d).\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(macro_mode, 0644, k90_show_macro_mode, k90_store_macro_mode);
|
||||
static DEVICE_ATTR(current_profile, 0644, k90_show_current_profile,
|
||||
k90_store_current_profile);
|
||||
|
||||
static struct attribute *k90_attrs[] = {
|
||||
&dev_attr_macro_mode.attr,
|
||||
&dev_attr_current_profile.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group k90_attr_group = {
|
||||
.attrs = k90_attrs,
|
||||
};
|
||||
|
||||
/*
|
||||
* Driver functions
|
||||
*/
|
||||
|
||||
static int k90_init_backlight(struct hid_device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct corsair_drvdata *drvdata = hid_get_drvdata(dev);
|
||||
size_t name_sz;
|
||||
char *name;
|
||||
|
||||
drvdata->backlight = kzalloc(sizeof(struct k90_led), GFP_KERNEL);
|
||||
if (!drvdata->backlight) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_backlight_alloc;
|
||||
}
|
||||
|
||||
name_sz =
|
||||
strlen(dev_name(&dev->dev)) + sizeof(K90_BACKLIGHT_LED_SUFFIX);
|
||||
name = kzalloc(name_sz, GFP_KERNEL);
|
||||
if (!name) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_name_alloc;
|
||||
}
|
||||
snprintf(name, name_sz, "%s" K90_BACKLIGHT_LED_SUFFIX,
|
||||
dev_name(&dev->dev));
|
||||
drvdata->backlight->removed = false;
|
||||
drvdata->backlight->cdev.name = name;
|
||||
drvdata->backlight->cdev.max_brightness = 3;
|
||||
drvdata->backlight->cdev.brightness_set = k90_brightness_set;
|
||||
drvdata->backlight->cdev.brightness_get = k90_backlight_get;
|
||||
INIT_WORK(&drvdata->backlight->work, k90_backlight_work);
|
||||
ret = led_classdev_register(&dev->dev, &drvdata->backlight->cdev);
|
||||
if (ret != 0)
|
||||
goto fail_register_cdev;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_register_cdev:
|
||||
kfree(drvdata->backlight->cdev.name);
|
||||
fail_name_alloc:
|
||||
kfree(drvdata->backlight);
|
||||
drvdata->backlight = NULL;
|
||||
fail_backlight_alloc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int k90_init_macro_functions(struct hid_device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct corsair_drvdata *drvdata = hid_get_drvdata(dev);
|
||||
struct k90_drvdata *k90;
|
||||
size_t name_sz;
|
||||
char *name;
|
||||
|
||||
k90 = kzalloc(sizeof(struct k90_drvdata), GFP_KERNEL);
|
||||
if (!k90) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_drvdata;
|
||||
}
|
||||
drvdata->k90 = k90;
|
||||
|
||||
/* Init LED device for record LED */
|
||||
name_sz = strlen(dev_name(&dev->dev)) + sizeof(K90_RECORD_LED_SUFFIX);
|
||||
name = kzalloc(name_sz, GFP_KERNEL);
|
||||
if (!name) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_record_led_alloc;
|
||||
}
|
||||
snprintf(name, name_sz, "%s" K90_RECORD_LED_SUFFIX,
|
||||
dev_name(&dev->dev));
|
||||
k90->record_led.removed = false;
|
||||
k90->record_led.cdev.name = name;
|
||||
k90->record_led.cdev.max_brightness = 1;
|
||||
k90->record_led.cdev.brightness_set = k90_brightness_set;
|
||||
k90->record_led.cdev.brightness_get = k90_record_led_get;
|
||||
INIT_WORK(&k90->record_led.work, k90_record_led_work);
|
||||
k90->record_led.brightness = 0;
|
||||
ret = led_classdev_register(&dev->dev, &k90->record_led.cdev);
|
||||
if (ret != 0)
|
||||
goto fail_record_led;
|
||||
|
||||
/* Init attributes */
|
||||
ret = sysfs_create_group(&dev->dev.kobj, &k90_attr_group);
|
||||
if (ret != 0)
|
||||
goto fail_sysfs;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_sysfs:
|
||||
k90->record_led.removed = true;
|
||||
led_classdev_unregister(&k90->record_led.cdev);
|
||||
cancel_work_sync(&k90->record_led.work);
|
||||
fail_record_led:
|
||||
kfree(k90->record_led.cdev.name);
|
||||
fail_record_led_alloc:
|
||||
kfree(k90);
|
||||
fail_drvdata:
|
||||
drvdata->k90 = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void k90_cleanup_backlight(struct hid_device *dev)
|
||||
{
|
||||
struct corsair_drvdata *drvdata = hid_get_drvdata(dev);
|
||||
|
||||
if (drvdata->backlight) {
|
||||
drvdata->backlight->removed = true;
|
||||
led_classdev_unregister(&drvdata->backlight->cdev);
|
||||
cancel_work_sync(&drvdata->backlight->work);
|
||||
kfree(drvdata->backlight->cdev.name);
|
||||
kfree(drvdata->backlight);
|
||||
}
|
||||
}
|
||||
|
||||
static void k90_cleanup_macro_functions(struct hid_device *dev)
|
||||
{
|
||||
struct corsair_drvdata *drvdata = hid_get_drvdata(dev);
|
||||
struct k90_drvdata *k90 = drvdata->k90;
|
||||
|
||||
if (k90) {
|
||||
sysfs_remove_group(&dev->dev.kobj, &k90_attr_group);
|
||||
|
||||
k90->record_led.removed = true;
|
||||
led_classdev_unregister(&k90->record_led.cdev);
|
||||
cancel_work_sync(&k90->record_led.work);
|
||||
kfree(k90->record_led.cdev.name);
|
||||
|
||||
kfree(k90);
|
||||
}
|
||||
}
|
||||
|
||||
static int corsair_probe(struct hid_device *dev, const struct hid_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
unsigned long quirks = id->driver_data;
|
||||
struct corsair_drvdata *drvdata;
|
||||
struct usb_interface *usbif = to_usb_interface(dev->dev.parent);
|
||||
|
||||
drvdata = devm_kzalloc(&dev->dev, sizeof(struct corsair_drvdata),
|
||||
GFP_KERNEL);
|
||||
if (drvdata == NULL)
|
||||
return -ENOMEM;
|
||||
drvdata->quirks = quirks;
|
||||
hid_set_drvdata(dev, drvdata);
|
||||
|
||||
ret = hid_parse(dev);
|
||||
if (ret != 0) {
|
||||
hid_err(dev, "parse failed\n");
|
||||
return ret;
|
||||
}
|
||||
ret = hid_hw_start(dev, HID_CONNECT_DEFAULT);
|
||||
if (ret != 0) {
|
||||
hid_err(dev, "hw start failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (usbif->cur_altsetting->desc.bInterfaceNumber == 0) {
|
||||
if (quirks & CORSAIR_USE_K90_MACRO) {
|
||||
ret = k90_init_macro_functions(dev);
|
||||
if (ret != 0)
|
||||
hid_warn(dev, "Failed to initialize K90 macro functions.\n");
|
||||
}
|
||||
if (quirks & CORSAIR_USE_K90_BACKLIGHT) {
|
||||
ret = k90_init_backlight(dev);
|
||||
if (ret != 0)
|
||||
hid_warn(dev, "Failed to initialize K90 backlight.\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void corsair_remove(struct hid_device *dev)
|
||||
{
|
||||
k90_cleanup_macro_functions(dev);
|
||||
k90_cleanup_backlight(dev);
|
||||
|
||||
hid_hw_stop(dev);
|
||||
}
|
||||
|
||||
static int corsair_event(struct hid_device *dev, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
struct corsair_drvdata *drvdata = hid_get_drvdata(dev);
|
||||
|
||||
if (!drvdata->k90)
|
||||
return 0;
|
||||
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
case CORSAIR_USAGE_MACRO_RECORD_START:
|
||||
drvdata->k90->record_led.brightness = 1;
|
||||
break;
|
||||
case CORSAIR_USAGE_MACRO_RECORD_STOP:
|
||||
drvdata->k90->record_led.brightness = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int corsair_input_mapping(struct hid_device *dev,
|
||||
struct hid_input *input,
|
||||
struct hid_field *field,
|
||||
struct hid_usage *usage, unsigned long **bit,
|
||||
int *max)
|
||||
{
|
||||
int gkey;
|
||||
|
||||
gkey = corsair_usage_to_gkey(usage->hid & HID_USAGE);
|
||||
if (gkey != 0) {
|
||||
hid_map_usage_clear(input, usage, bit, max, EV_KEY,
|
||||
corsair_gkey_map[gkey - 1]);
|
||||
return 1;
|
||||
}
|
||||
if ((usage->hid & HID_USAGE) >= CORSAIR_USAGE_SPECIAL_MIN &&
|
||||
(usage->hid & HID_USAGE) <= CORSAIR_USAGE_SPECIAL_MAX) {
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
case CORSAIR_USAGE_MACRO_RECORD_START:
|
||||
hid_map_usage_clear(input, usage, bit, max, EV_KEY,
|
||||
corsair_record_keycodes[0]);
|
||||
return 1;
|
||||
|
||||
case CORSAIR_USAGE_MACRO_RECORD_STOP:
|
||||
hid_map_usage_clear(input, usage, bit, max, EV_KEY,
|
||||
corsair_record_keycodes[1]);
|
||||
return 1;
|
||||
|
||||
case CORSAIR_USAGE_M1:
|
||||
hid_map_usage_clear(input, usage, bit, max, EV_KEY,
|
||||
corsair_profile_keycodes[0]);
|
||||
return 1;
|
||||
|
||||
case CORSAIR_USAGE_M2:
|
||||
hid_map_usage_clear(input, usage, bit, max, EV_KEY,
|
||||
corsair_profile_keycodes[1]);
|
||||
return 1;
|
||||
|
||||
case CORSAIR_USAGE_M3:
|
||||
hid_map_usage_clear(input, usage, bit, max, EV_KEY,
|
||||
corsair_profile_keycodes[2]);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hid_device_id corsair_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90),
|
||||
.driver_data = CORSAIR_USE_K90_MACRO |
|
||||
CORSAIR_USE_K90_BACKLIGHT },
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(hid, corsair_devices);
|
||||
|
||||
static struct hid_driver corsair_driver = {
|
||||
.name = "corsair",
|
||||
.id_table = corsair_devices,
|
||||
.probe = corsair_probe,
|
||||
.event = corsair_event,
|
||||
.remove = corsair_remove,
|
||||
.input_mapping = corsair_input_mapping,
|
||||
};
|
||||
|
||||
static int __init corsair_init(void)
|
||||
{
|
||||
return hid_register_driver(&corsair_driver);
|
||||
}
|
||||
|
||||
static void corsair_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&corsair_driver);
|
||||
}
|
||||
|
||||
module_init(corsair_init);
|
||||
module_exit(corsair_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Clement Vuchener");
|
||||
MODULE_DESCRIPTION("HID driver for Corsair devices");
|
|
@ -234,6 +234,58 @@ static __u8 pid0011_rdesc_fixed[] = {
|
|||
0xC0 /* End Collection */
|
||||
};
|
||||
|
||||
static __u8 pid0006_rdesc_fixed[] = {
|
||||
0x05, 0x01, /* Usage Page (Generic Desktop) */
|
||||
0x09, 0x04, /* Usage (Joystick) */
|
||||
0xA1, 0x01, /* Collection (Application) */
|
||||
0xA1, 0x02, /* Collection (Logical) */
|
||||
0x75, 0x08, /* Report Size (8) */
|
||||
0x95, 0x05, /* Report Count (5) */
|
||||
0x15, 0x00, /* Logical Minimum (0) */
|
||||
0x26, 0xFF, 0x00, /* Logical Maximum (255) */
|
||||
0x35, 0x00, /* Physical Minimum (0) */
|
||||
0x46, 0xFF, 0x00, /* Physical Maximum (255) */
|
||||
0x09, 0x30, /* Usage (X) */
|
||||
0x09, 0x33, /* Usage (Ry) */
|
||||
0x09, 0x32, /* Usage (Z) */
|
||||
0x09, 0x31, /* Usage (Y) */
|
||||
0x09, 0x34, /* Usage (Ry) */
|
||||
0x81, 0x02, /* Input (Variable) */
|
||||
0x75, 0x04, /* Report Size (4) */
|
||||
0x95, 0x01, /* Report Count (1) */
|
||||
0x25, 0x07, /* Logical Maximum (7) */
|
||||
0x46, 0x3B, 0x01, /* Physical Maximum (315) */
|
||||
0x65, 0x14, /* Unit (Centimeter) */
|
||||
0x09, 0x39, /* Usage (Hat switch) */
|
||||
0x81, 0x42, /* Input (Variable) */
|
||||
0x65, 0x00, /* Unit (None) */
|
||||
0x75, 0x01, /* Report Size (1) */
|
||||
0x95, 0x0C, /* Report Count (12) */
|
||||
0x25, 0x01, /* Logical Maximum (1) */
|
||||
0x45, 0x01, /* Physical Maximum (1) */
|
||||
0x05, 0x09, /* Usage Page (Button) */
|
||||
0x19, 0x01, /* Usage Minimum (0x01) */
|
||||
0x29, 0x0C, /* Usage Maximum (0x0C) */
|
||||
0x81, 0x02, /* Input (Variable) */
|
||||
0x06, 0x00, 0xFF, /* Usage Page (Vendor Defined) */
|
||||
0x75, 0x01, /* Report Size (1) */
|
||||
0x95, 0x08, /* Report Count (8) */
|
||||
0x25, 0x01, /* Logical Maximum (1) */
|
||||
0x45, 0x01, /* Physical Maximum (1) */
|
||||
0x09, 0x01, /* Usage (0x01) */
|
||||
0x81, 0x02, /* Input (Variable) */
|
||||
0xC0, /* End Collection */
|
||||
0xA1, 0x02, /* Collection (Logical) */
|
||||
0x75, 0x08, /* Report Size (8) */
|
||||
0x95, 0x07, /* Report Count (7) */
|
||||
0x46, 0xFF, 0x00, /* Physical Maximum (255) */
|
||||
0x26, 0xFF, 0x00, /* Logical Maximum (255) */
|
||||
0x09, 0x02, /* Usage (0x02) */
|
||||
0x91, 0x02, /* Output (Variable) */
|
||||
0xC0, /* End Collection */
|
||||
0xC0 /* End Collection */
|
||||
};
|
||||
|
||||
static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
|
@ -244,6 +296,12 @@ static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|||
*rsize = sizeof(pid0011_rdesc_fixed);
|
||||
}
|
||||
break;
|
||||
case 0x0006:
|
||||
if (*rsize == sizeof(pid0006_rdesc_fixed)) {
|
||||
rdesc = pid0006_rdesc_fixed;
|
||||
*rsize = sizeof(pid0006_rdesc_fixed);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return rdesc;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|||
hid_info(hdev, "Fixing up Elecom BM084 report descriptor\n");
|
||||
rdesc[47] = 0x00;
|
||||
}
|
||||
return rdesc;
|
||||
return rdesc;
|
||||
}
|
||||
|
||||
static const struct hid_device_id elecom_devices[] = {
|
||||
|
|
|
@ -37,7 +37,7 @@ static bool use_fw_quirk = true;
|
|||
module_param(use_fw_quirk, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(use_fw_quirk, "Do periodic pokes for broken M firmwares (default = true)");
|
||||
|
||||
static void elo_input_configured(struct hid_device *hdev,
|
||||
static int elo_input_configured(struct hid_device *hdev,
|
||||
struct hid_input *hidinput)
|
||||
{
|
||||
struct input_dev *input = hidinput->input;
|
||||
|
@ -45,6 +45,8 @@ static void elo_input_configured(struct hid_device *hdev,
|
|||
set_bit(BTN_TOUCH, input->keybit);
|
||||
set_bit(ABS_PRESSURE, input->absbit);
|
||||
input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void elo_process_data(struct input_dev *input, const u8 *data, int size)
|
||||
|
|
|
@ -251,6 +251,9 @@
|
|||
#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
|
||||
#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
|
||||
|
||||
#define USB_VENDOR_ID_CORSAIR 0x1b1c
|
||||
#define USB_DEVICE_ID_CORSAIR_K90 0x1b02
|
||||
|
||||
#define USB_VENDOR_ID_CREATIVELABS 0x041e
|
||||
#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
|
||||
|
||||
|
@ -648,6 +651,7 @@
|
|||
|
||||
#define USB_VENDOR_ID_MADCATZ 0x0738
|
||||
#define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540
|
||||
#define USB_DEVICE_ID_MADCATZ_RAT5 0x1705
|
||||
#define USB_DEVICE_ID_MADCATZ_RAT9 0x1709
|
||||
|
||||
#define USB_VENDOR_ID_MCC 0x09db
|
||||
|
@ -681,6 +685,7 @@
|
|||
#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
|
||||
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
|
||||
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc
|
||||
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2
|
||||
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd
|
||||
#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de
|
||||
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
|
||||
|
|
|
@ -1510,8 +1510,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
|||
* UGCI) cram a lot of unrelated inputs into the
|
||||
* same interface. */
|
||||
hidinput->report = report;
|
||||
if (drv->input_configured)
|
||||
drv->input_configured(hid, hidinput);
|
||||
if (drv->input_configured &&
|
||||
drv->input_configured(hid, hidinput))
|
||||
goto out_cleanup;
|
||||
if (input_register_device(hidinput->input))
|
||||
goto out_cleanup;
|
||||
hidinput = NULL;
|
||||
|
@ -1532,8 +1533,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
|||
}
|
||||
|
||||
if (hidinput) {
|
||||
if (drv->input_configured)
|
||||
drv->input_configured(hid, hidinput);
|
||||
if (drv->input_configured &&
|
||||
drv->input_configured(hid, hidinput))
|
||||
goto out_cleanup;
|
||||
if (input_register_device(hidinput->input))
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
|
|
@ -848,7 +848,7 @@ static void lenovo_remove(struct hid_device *hdev)
|
|||
hid_hw_stop(hdev);
|
||||
}
|
||||
|
||||
static void lenovo_input_configured(struct hid_device *hdev,
|
||||
static int lenovo_input_configured(struct hid_device *hdev,
|
||||
struct hid_input *hi)
|
||||
{
|
||||
switch (hdev->product) {
|
||||
|
@ -863,6 +863,8 @@ static void lenovo_input_configured(struct hid_device *hdev,
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -620,6 +620,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
|||
usage->code == ABS_Y || usage->code == ABS_Z ||
|
||||
usage->code == ABS_RZ)) {
|
||||
switch (hdev->product) {
|
||||
case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
|
||||
case USB_DEVICE_ID_LOGITECH_WHEEL:
|
||||
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
|
||||
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
|
||||
|
@ -658,10 +659,18 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
|
|||
|
||||
static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
{
|
||||
struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
|
||||
__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
|
||||
unsigned int connect_mask = HID_CONNECT_DEFAULT;
|
||||
struct lg_drv_data *drv_data;
|
||||
int ret;
|
||||
|
||||
/* Only work with the 1st interface (G29 presents multiple) */
|
||||
if (iface_num != 0) {
|
||||
dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
|
||||
if (!drv_data) {
|
||||
hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
|
||||
|
|
|
@ -45,7 +45,8 @@
|
|||
#define LG4FF_MODE_G25_IDX 3
|
||||
#define LG4FF_MODE_DFGT_IDX 4
|
||||
#define LG4FF_MODE_G27_IDX 5
|
||||
#define LG4FF_MODE_MAX_IDX 6
|
||||
#define LG4FF_MODE_G29_IDX 6
|
||||
#define LG4FF_MODE_MAX_IDX 7
|
||||
|
||||
#define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX)
|
||||
#define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX)
|
||||
|
@ -53,6 +54,7 @@
|
|||
#define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX)
|
||||
#define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX)
|
||||
#define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX)
|
||||
#define LG4FF_MODE_G29 BIT(LG4FF_MODE_G29_IDX)
|
||||
|
||||
#define LG4FF_DFEX_TAG "DF-EX"
|
||||
#define LG4FF_DFEX_NAME "Driving Force / Formula EX"
|
||||
|
@ -62,6 +64,8 @@
|
|||
#define LG4FF_G25_NAME "G25 Racing Wheel"
|
||||
#define LG4FF_G27_TAG "G27"
|
||||
#define LG4FF_G27_NAME "G27 Racing Wheel"
|
||||
#define LG4FF_G29_TAG "G29"
|
||||
#define LG4FF_G29_NAME "G29 Racing Wheel"
|
||||
#define LG4FF_DFGT_TAG "DFGT"
|
||||
#define LG4FF_DFGT_NAME "Driving Force GT"
|
||||
|
||||
|
@ -114,16 +118,12 @@ struct lg4ff_compat_mode_switch {
|
|||
};
|
||||
|
||||
struct lg4ff_wheel_ident_info {
|
||||
const u32 modes;
|
||||
const u16 mask;
|
||||
const u16 result;
|
||||
const u16 real_product_id;
|
||||
};
|
||||
|
||||
struct lg4ff_wheel_ident_checklist {
|
||||
const u32 count;
|
||||
const struct lg4ff_wheel_ident_info *models[];
|
||||
};
|
||||
|
||||
struct lg4ff_multimode_wheel {
|
||||
const u16 product_id;
|
||||
const u32 alternate_modes;
|
||||
|
@ -144,6 +144,7 @@ static const struct lg4ff_wheel lg4ff_devices[] = {
|
|||
{USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
|
||||
{USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
|
||||
{USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
|
||||
{USB_DEVICE_ID_LOGITECH_G29_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25},
|
||||
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL},
|
||||
{USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}
|
||||
};
|
||||
|
@ -161,6 +162,9 @@ static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = {
|
|||
{USB_DEVICE_ID_LOGITECH_G27_WHEEL,
|
||||
LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||
LG4FF_G27_TAG, LG4FF_G27_NAME},
|
||||
{USB_DEVICE_ID_LOGITECH_G29_WHEEL,
|
||||
LG4FF_MODE_NATIVE | LG4FF_MODE_G29 | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||
LG4FF_G29_TAG, LG4FF_G29_NAME},
|
||||
};
|
||||
|
||||
static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = {
|
||||
|
@ -169,41 +173,61 @@ static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = {
|
|||
[LG4FF_MODE_DFP_IDX] = {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, LG4FF_DFP_TAG, LG4FF_DFP_NAME},
|
||||
[LG4FF_MODE_G25_IDX] = {USB_DEVICE_ID_LOGITECH_G25_WHEEL, LG4FF_G25_TAG, LG4FF_G25_NAME},
|
||||
[LG4FF_MODE_DFGT_IDX] = {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, LG4FF_DFGT_TAG, LG4FF_DFGT_NAME},
|
||||
[LG4FF_MODE_G27_IDX] = {USB_DEVICE_ID_LOGITECH_G27_WHEEL, LG4FF_G27_TAG, LG4FF_G27_NAME}
|
||||
[LG4FF_MODE_G27_IDX] = {USB_DEVICE_ID_LOGITECH_G27_WHEEL, LG4FF_G27_TAG, LG4FF_G27_NAME},
|
||||
[LG4FF_MODE_G29_IDX] = {USB_DEVICE_ID_LOGITECH_G29_WHEEL, LG4FF_G29_TAG, LG4FF_G29_NAME},
|
||||
};
|
||||
|
||||
/* Multimode wheel identificators */
|
||||
static const struct lg4ff_wheel_ident_info lg4ff_dfp_ident_info = {
|
||||
LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||
0xf000,
|
||||
0x1000,
|
||||
USB_DEVICE_ID_LOGITECH_DFP_WHEEL
|
||||
};
|
||||
|
||||
static const struct lg4ff_wheel_ident_info lg4ff_g25_ident_info = {
|
||||
LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||
0xff00,
|
||||
0x1200,
|
||||
USB_DEVICE_ID_LOGITECH_G25_WHEEL
|
||||
};
|
||||
|
||||
static const struct lg4ff_wheel_ident_info lg4ff_g27_ident_info = {
|
||||
LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||
0xfff0,
|
||||
0x1230,
|
||||
USB_DEVICE_ID_LOGITECH_G27_WHEEL
|
||||
};
|
||||
|
||||
static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = {
|
||||
LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||
0xff00,
|
||||
0x1300,
|
||||
USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
|
||||
};
|
||||
|
||||
static const struct lg4ff_wheel_ident_info lg4ff_g29_ident_info = {
|
||||
LG4FF_MODE_G29 | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||
0xfff8,
|
||||
0x1350,
|
||||
USB_DEVICE_ID_LOGITECH_G29_WHEEL
|
||||
};
|
||||
|
||||
static const struct lg4ff_wheel_ident_info lg4ff_g29_ident_info2 = {
|
||||
LG4FF_MODE_G29 | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||
0xff00,
|
||||
0x8900,
|
||||
USB_DEVICE_ID_LOGITECH_G29_WHEEL
|
||||
};
|
||||
|
||||
/* Multimode wheel identification checklists */
|
||||
static const struct lg4ff_wheel_ident_checklist lg4ff_main_checklist = {
|
||||
4,
|
||||
{&lg4ff_dfgt_ident_info,
|
||||
&lg4ff_g27_ident_info,
|
||||
&lg4ff_g25_ident_info,
|
||||
&lg4ff_dfp_ident_info}
|
||||
static const struct lg4ff_wheel_ident_info *lg4ff_main_checklist[] = {
|
||||
&lg4ff_g29_ident_info,
|
||||
&lg4ff_g29_ident_info2,
|
||||
&lg4ff_dfgt_ident_info,
|
||||
&lg4ff_g27_ident_info,
|
||||
&lg4ff_g25_ident_info,
|
||||
&lg4ff_dfp_ident_info
|
||||
};
|
||||
|
||||
/* Compatibility mode switching commands */
|
||||
|
@ -238,6 +262,12 @@ static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g27 = {
|
|||
0xf8, 0x09, 0x04, 0x01, 0x00, 0x00, 0x00} /* Switch mode to G27 with detach */
|
||||
};
|
||||
|
||||
static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext09_g29 = {
|
||||
2,
|
||||
{0xf8, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, /* Revert mode upon USB reset */
|
||||
0xf8, 0x09, 0x05, 0x01, 0x01, 0x00, 0x00} /* Switch mode to G29 with detach */
|
||||
};
|
||||
|
||||
/* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */
|
||||
static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = {
|
||||
1,
|
||||
|
@ -651,6 +681,23 @@ static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(cons
|
|||
return NULL;
|
||||
}
|
||||
break;
|
||||
case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
|
||||
switch (target_product_id) {
|
||||
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
|
||||
return &lg4ff_mode_switch_ext09_dfp;
|
||||
case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
|
||||
return &lg4ff_mode_switch_ext09_dfgt;
|
||||
case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
|
||||
return &lg4ff_mode_switch_ext09_g25;
|
||||
case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
|
||||
return &lg4ff_mode_switch_ext09_g27;
|
||||
case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
|
||||
return &lg4ff_mode_switch_ext09_g29;
|
||||
/* G29 can only be switched to DF-EX, DFP, DFGT, G25, G27 or its native mode */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
|
||||
switch (target_product_id) {
|
||||
case USB_DEVICE_ID_LOGITECH_WHEEL:
|
||||
|
@ -1037,41 +1084,28 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde
|
|||
|
||||
static u16 lg4ff_identify_multimode_wheel(struct hid_device *hid, const u16 reported_product_id, const u16 bcdDevice)
|
||||
{
|
||||
const struct lg4ff_wheel_ident_checklist *checklist;
|
||||
int i, from_idx, to_idx;
|
||||
u32 current_mode;
|
||||
int i;
|
||||
|
||||
switch (reported_product_id) {
|
||||
case USB_DEVICE_ID_LOGITECH_WHEEL:
|
||||
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
|
||||
checklist = &lg4ff_main_checklist;
|
||||
from_idx = 0;
|
||||
to_idx = checklist->count - 1;
|
||||
break;
|
||||
case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
|
||||
checklist = &lg4ff_main_checklist;
|
||||
from_idx = 0;
|
||||
to_idx = checklist->count - 2; /* End identity check at G25 */
|
||||
break;
|
||||
case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
|
||||
checklist = &lg4ff_main_checklist;
|
||||
from_idx = 1; /* Start identity check at G27 */
|
||||
to_idx = checklist->count - 3; /* End identity check at G27 */
|
||||
break;
|
||||
case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
|
||||
checklist = &lg4ff_main_checklist;
|
||||
from_idx = 0;
|
||||
to_idx = checklist->count - 4; /* End identity check at DFGT */
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
/* identify current mode from USB PID */
|
||||
for (i = 1; i < ARRAY_SIZE(lg4ff_alternate_modes); i++) {
|
||||
dbg_hid("Testing whether PID is %X\n", lg4ff_alternate_modes[i].product_id);
|
||||
if (reported_product_id == lg4ff_alternate_modes[i].product_id)
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = from_idx; i <= to_idx; i++) {
|
||||
const u16 mask = checklist->models[i]->mask;
|
||||
const u16 result = checklist->models[i]->result;
|
||||
const u16 real_product_id = checklist->models[i]->real_product_id;
|
||||
if (i == ARRAY_SIZE(lg4ff_alternate_modes))
|
||||
return 0;
|
||||
|
||||
if ((bcdDevice & mask) == result) {
|
||||
current_mode = BIT(i);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lg4ff_main_checklist); i++) {
|
||||
const u16 mask = lg4ff_main_checklist[i]->mask;
|
||||
const u16 result = lg4ff_main_checklist[i]->result;
|
||||
const u16 real_product_id = lg4ff_main_checklist[i]->real_product_id;
|
||||
|
||||
if ((current_mode & lg4ff_main_checklist[i]->modes) && \
|
||||
(bcdDevice & mask) == result) {
|
||||
dbg_hid("Found wheel with real PID %X whose reported PID is %X\n", real_product_id, reported_product_id);
|
||||
return real_product_id;
|
||||
}
|
||||
|
@ -1246,12 +1280,13 @@ int lg4ff_init(struct hid_device *hid)
|
|||
entry->wdata.set_range(hid, entry->wdata.range);
|
||||
|
||||
#ifdef CONFIG_LEDS_CLASS
|
||||
/* register led subsystem - G27 only */
|
||||
/* register led subsystem - G27/G29 only */
|
||||
entry->wdata.led_state = 0;
|
||||
for (j = 0; j < 5; j++)
|
||||
entry->wdata.led[j] = NULL;
|
||||
|
||||
if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) {
|
||||
if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL ||
|
||||
lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G29_WHEEL) {
|
||||
struct led_classdev *led;
|
||||
size_t name_sz;
|
||||
char *name;
|
||||
|
|
|
@ -33,6 +33,11 @@ module_param(disable_raw_mode, bool, 0644);
|
|||
MODULE_PARM_DESC(disable_raw_mode,
|
||||
"Disable Raw mode reporting for touchpads and keep firmware gestures.");
|
||||
|
||||
static bool disable_tap_to_click;
|
||||
module_param(disable_tap_to_click, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_tap_to_click,
|
||||
"Disable Tap-To-Click mode reporting for touchpads (only on the K400 currently).");
|
||||
|
||||
#define REPORT_ID_HIDPP_SHORT 0x10
|
||||
#define REPORT_ID_HIDPP_LONG 0x11
|
||||
|
||||
|
@ -41,10 +46,15 @@ MODULE_PARM_DESC(disable_raw_mode,
|
|||
|
||||
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
|
||||
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
|
||||
#define HIDPP_QUIRK_CLASS_K400 BIT(2)
|
||||
|
||||
/* bits 2..20 are reserved for classes */
|
||||
#define HIDPP_QUIRK_DELAYED_INIT BIT(21)
|
||||
#define HIDPP_QUIRK_CONNECT_EVENTS BIT(21)
|
||||
#define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22)
|
||||
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
|
||||
|
||||
#define HIDPP_QUIRK_DELAYED_INIT (HIDPP_QUIRK_NO_HIDINPUT | \
|
||||
HIDPP_QUIRK_CONNECT_EVENTS)
|
||||
|
||||
/*
|
||||
* There are two hidpp protocols in use, the first version hidpp10 is known
|
||||
|
@ -552,6 +562,52 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp)
|
|||
return name;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x6010: Touchpad FW items */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define HIDPP_PAGE_TOUCHPAD_FW_ITEMS 0x6010
|
||||
|
||||
#define CMD_TOUCHPAD_FW_ITEMS_SET 0x10
|
||||
|
||||
struct hidpp_touchpad_fw_items {
|
||||
uint8_t presence;
|
||||
uint8_t desired_state;
|
||||
uint8_t state;
|
||||
uint8_t persistent;
|
||||
};
|
||||
|
||||
/**
|
||||
* send a set state command to the device by reading the current items->state
|
||||
* field. items is then filled with the current state.
|
||||
*/
|
||||
static int hidpp_touchpad_fw_items_set(struct hidpp_device *hidpp,
|
||||
u8 feature_index,
|
||||
struct hidpp_touchpad_fw_items *items)
|
||||
{
|
||||
struct hidpp_report response;
|
||||
int ret;
|
||||
u8 *params = (u8 *)response.fap.params;
|
||||
|
||||
ret = hidpp_send_fap_command_sync(hidpp, feature_index,
|
||||
CMD_TOUCHPAD_FW_ITEMS_SET, &items->state, 1, &response);
|
||||
|
||||
if (ret > 0) {
|
||||
hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
|
||||
__func__, ret);
|
||||
return -EPROTO;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
items->presence = params[0];
|
||||
items->desired_state = params[1];
|
||||
items->state = params[2];
|
||||
items->persistent = params[3];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x6100: TouchPadRawXY */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -1132,6 +1188,75 @@ static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Logitech K400 devices */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* The Logitech K400 keyboard has an embedded touchpad which is seen
|
||||
* as a mouse from the OS point of view. There is a hardware shortcut to disable
|
||||
* tap-to-click but the setting is not remembered accross reset, annoying some
|
||||
* users.
|
||||
*
|
||||
* We can toggle this feature from the host by using the feature 0x6010:
|
||||
* Touchpad FW items
|
||||
*/
|
||||
|
||||
struct k400_private_data {
|
||||
u8 feature_index;
|
||||
};
|
||||
|
||||
static int k400_disable_tap_to_click(struct hidpp_device *hidpp)
|
||||
{
|
||||
struct k400_private_data *k400 = hidpp->private_data;
|
||||
struct hidpp_touchpad_fw_items items = {};
|
||||
int ret;
|
||||
u8 feature_type;
|
||||
|
||||
if (!k400->feature_index) {
|
||||
ret = hidpp_root_get_feature(hidpp,
|
||||
HIDPP_PAGE_TOUCHPAD_FW_ITEMS,
|
||||
&k400->feature_index, &feature_type);
|
||||
if (ret)
|
||||
/* means that the device is not powered up */
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hidpp_touchpad_fw_items_set(hidpp, k400->feature_index, &items);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int k400_allocate(struct hid_device *hdev)
|
||||
{
|
||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||
struct k400_private_data *k400;
|
||||
|
||||
k400 = devm_kzalloc(&hdev->dev, sizeof(struct k400_private_data),
|
||||
GFP_KERNEL);
|
||||
if (!k400)
|
||||
return -ENOMEM;
|
||||
|
||||
hidpp->private_data = k400;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int k400_connect(struct hid_device *hdev, bool connected)
|
||||
{
|
||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||
|
||||
if (!connected)
|
||||
return 0;
|
||||
|
||||
if (!disable_tap_to_click)
|
||||
return 0;
|
||||
|
||||
return k400_disable_tap_to_click(hidpp);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Generic HID++ devices */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -1160,13 +1285,15 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
|
|||
m560_populate_input(hidpp, input, origin_is_hid_core);
|
||||
}
|
||||
|
||||
static void hidpp_input_configured(struct hid_device *hdev,
|
||||
static int hidpp_input_configured(struct hid_device *hdev,
|
||||
struct hid_input *hidinput)
|
||||
{
|
||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||
struct input_dev *input = hidinput->input;
|
||||
|
||||
hidpp_populate_input(hidpp, input, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
|
||||
|
@ -1203,7 +1330,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
|
|||
if (unlikely(hidpp_report_is_connect_event(report))) {
|
||||
atomic_set(&hidpp->connected,
|
||||
!(report->rap.params[0] & (1 << 6)));
|
||||
if ((hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) &&
|
||||
if ((hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) &&
|
||||
(schedule_work(&hidpp->work) == 0))
|
||||
dbg_hid("%s: connect event already queued\n", __func__);
|
||||
return 1;
|
||||
|
@ -1328,23 +1455,30 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
|||
ret = m560_send_config_command(hdev, connected);
|
||||
if (ret)
|
||||
return;
|
||||
} else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) {
|
||||
ret = k400_connect(hdev, connected);
|
||||
if (ret)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!connected || hidpp->delayed_input)
|
||||
return;
|
||||
|
||||
/* the device is already connected, we can ask for its name and
|
||||
* protocol */
|
||||
if (!hidpp->protocol_major) {
|
||||
ret = !hidpp_is_connected(hidpp);
|
||||
if (ret) {
|
||||
hid_err(hdev, "Can not get the protocol version.\n");
|
||||
return;
|
||||
}
|
||||
hid_info(hdev, "HID++ %u.%u device connected.\n",
|
||||
hidpp->protocol_major, hidpp->protocol_minor);
|
||||
}
|
||||
|
||||
/* the device is already connected, we can ask for its name and
|
||||
* protocol */
|
||||
hid_info(hdev, "HID++ %u.%u device connected.\n",
|
||||
hidpp->protocol_major, hidpp->protocol_minor);
|
||||
if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT))
|
||||
/* if HID created the input nodes for us, we can stop now */
|
||||
return;
|
||||
|
||||
if (!hidpp->name || hidpp->name == hdev->name) {
|
||||
name = hidpp_get_device_name(hidpp);
|
||||
|
@ -1397,7 +1531,8 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
|
||||
if (disable_raw_mode) {
|
||||
hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP;
|
||||
hidpp->quirks &= ~HIDPP_QUIRK_DELAYED_INIT;
|
||||
hidpp->quirks &= ~HIDPP_QUIRK_CONNECT_EVENTS;
|
||||
hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT;
|
||||
}
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
|
||||
|
@ -1408,6 +1543,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
ret = m560_allocate(hdev);
|
||||
if (ret)
|
||||
goto allocate_fail;
|
||||
} else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) {
|
||||
ret = k400_allocate(hdev);
|
||||
if (ret)
|
||||
goto allocate_fail;
|
||||
}
|
||||
|
||||
INIT_WORK(&hidpp->work, delayed_work_cb);
|
||||
|
@ -1448,7 +1587,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
/* Block incoming packets */
|
||||
hid_device_io_stop(hdev);
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
|
||||
if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
|
||||
connect_mask &= ~HID_CONNECT_HIDINPUT;
|
||||
|
||||
ret = hid_hw_start(hdev, connect_mask);
|
||||
|
@ -1457,7 +1596,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
goto hid_hw_start_fail;
|
||||
}
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) {
|
||||
if (hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) {
|
||||
/* Allow incoming packets */
|
||||
hid_device_io_start(hdev);
|
||||
|
||||
|
@ -1502,6 +1641,10 @@ static const struct hid_device_id hidpp_devices[] = {
|
|||
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||
USB_VENDOR_ID_LOGITECH, 0x402d),
|
||||
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
|
||||
{ /* Keyboard logitech K400 */
|
||||
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||
USB_VENDOR_ID_LOGITECH, 0x4024),
|
||||
.driver_data = HIDPP_QUIRK_CONNECT_EVENTS | HIDPP_QUIRK_CLASS_K400 },
|
||||
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||
USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
|
||||
|
|
|
@ -471,18 +471,22 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void magicmouse_input_configured(struct hid_device *hdev,
|
||||
static int magicmouse_input_configured(struct hid_device *hdev,
|
||||
struct hid_input *hi)
|
||||
|
||||
{
|
||||
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
|
||||
int ret;
|
||||
|
||||
int ret = magicmouse_setup_input(msc->input, hdev);
|
||||
ret = magicmouse_setup_input(msc->input, hdev);
|
||||
if (ret) {
|
||||
hid_err(hdev, "magicmouse setup input failed (%d)\n", ret);
|
||||
/* clean msc->input to notify probe() of the failure */
|
||||
msc->input = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -278,6 +278,8 @@ static const struct hid_device_id ms_devices[] = {
|
|||
.driver_data = MS_DUPLICATE_USAGES },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3),
|
||||
.driver_data = MS_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2),
|
||||
.driver_data = MS_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP),
|
||||
.driver_data = MS_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
|
||||
|
|
|
@ -309,6 +309,41 @@ static struct attribute_group mt_attribute_group = {
|
|||
.attrs = sysfs_attrs
|
||||
};
|
||||
|
||||
static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
int ret, size = hid_report_len(report);
|
||||
u8 *buf;
|
||||
|
||||
/*
|
||||
* Only fetch the feature report if initial reports are not already
|
||||
* been retrieved. Currently this is only done for Windows 8 touch
|
||||
* devices.
|
||||
*/
|
||||
if (!(hdev->quirks & HID_QUIRK_NO_INIT_REPORTS))
|
||||
return;
|
||||
if (td->mtclass.name != MT_CLS_WIN_8)
|
||||
return;
|
||||
|
||||
buf = hid_alloc_report_buf(report, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
ret = hid_hw_raw_request(hdev, report->id, buf, size,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
if (ret < 0) {
|
||||
dev_warn(&hdev->dev, "failed to fetch feature %d\n",
|
||||
report->id);
|
||||
} else {
|
||||
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
|
||||
size, 0);
|
||||
if (ret)
|
||||
dev_warn(&hdev->dev, "failed to report feature\n");
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
static void mt_feature_mapping(struct hid_device *hdev,
|
||||
struct hid_field *field, struct hid_usage *usage)
|
||||
{
|
||||
|
@ -327,6 +362,8 @@ static void mt_feature_mapping(struct hid_device *hdev,
|
|||
|
||||
break;
|
||||
case HID_DG_CONTACTMAX:
|
||||
mt_get_feature(hdev, field->report);
|
||||
|
||||
td->maxcontact_report_id = field->report->id;
|
||||
td->maxcontacts = field->value[0];
|
||||
if (!td->maxcontacts &&
|
||||
|
@ -343,6 +380,7 @@ static void mt_feature_mapping(struct hid_device *hdev,
|
|||
break;
|
||||
}
|
||||
|
||||
mt_get_feature(hdev, field->report);
|
||||
if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD)
|
||||
td->is_buttonpad = true;
|
||||
|
||||
|
@ -725,12 +763,13 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
|
|||
mt_sync_frame(td, report->field[0]->hidinput->input);
|
||||
}
|
||||
|
||||
static void mt_touch_input_configured(struct hid_device *hdev,
|
||||
static int mt_touch_input_configured(struct hid_device *hdev,
|
||||
struct hid_input *hi)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
struct mt_class *cls = &td->mtclass;
|
||||
struct input_dev *input = hi->input;
|
||||
int ret;
|
||||
|
||||
if (!td->maxcontacts)
|
||||
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
|
||||
|
@ -752,9 +791,12 @@ static void mt_touch_input_configured(struct hid_device *hdev,
|
|||
if (td->is_buttonpad)
|
||||
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
|
||||
|
||||
input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
|
||||
ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
td->mt_flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
|
@ -930,15 +972,19 @@ static void mt_post_parse(struct mt_device *td)
|
|||
cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
|
||||
}
|
||||
|
||||
static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||
static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
char *name;
|
||||
const char *suffix = NULL;
|
||||
struct hid_field *field = hi->report->field[0];
|
||||
int ret;
|
||||
|
||||
if (hi->report->id == td->mt_report_id)
|
||||
mt_touch_input_configured(hdev, hi);
|
||||
if (hi->report->id == td->mt_report_id) {
|
||||
ret = mt_touch_input_configured(hdev, hi);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
|
||||
|
@ -968,6 +1014,9 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|||
case HID_DG_TOUCHSCREEN:
|
||||
/* we do not set suffix = "Touchscreen" */
|
||||
break;
|
||||
case HID_DG_TOUCHPAD:
|
||||
suffix = "Touchpad";
|
||||
break;
|
||||
case HID_GD_SYSTEM_CONTROL:
|
||||
suffix = "System Control";
|
||||
break;
|
||||
|
@ -989,6 +1038,8 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|||
hi->input->name = name;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
|
@ -1026,8 +1077,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
* reports. Fortunately, the Win8 spec says that all touches
|
||||
* should be sent during each report, making the initialization
|
||||
* of input reports unnecessary.
|
||||
*
|
||||
* In addition some touchpads do not behave well if we read
|
||||
* all feature reports from them. Instead we prevent
|
||||
* initial report fetching and then selectively fetch each
|
||||
* report we are interested in.
|
||||
*/
|
||||
hdev->quirks |= HID_QUIRK_NO_INIT_INPUT_REPORTS;
|
||||
hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
|
||||
|
||||
td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
|
||||
if (!td) {
|
||||
|
|
|
@ -859,14 +859,14 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void ntrig_input_configured(struct hid_device *hid,
|
||||
static int ntrig_input_configured(struct hid_device *hid,
|
||||
struct hid_input *hidinput)
|
||||
|
||||
{
|
||||
struct input_dev *input = hidinput->input;
|
||||
|
||||
if (hidinput->report->maxfield < 1)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
switch (hidinput->report->field[0]->application) {
|
||||
case HID_DG_PEN:
|
||||
|
@ -890,6 +890,8 @@ static void ntrig_input_configured(struct hid_device *hid,
|
|||
"N-Trig MultiTouch";
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
|
|
|
@ -427,7 +427,7 @@ static int pcmidi_handle_report4(struct pcmidi_snd *pm, u8 *data)
|
|||
pm->midi_octave = 2;
|
||||
dbg_hid("pcmidi mode: %d octave: %d\n",
|
||||
pm->midi_mode, pm->midi_octave);
|
||||
continue;
|
||||
continue;
|
||||
} else
|
||||
key = KEY_MESSENGER;
|
||||
break;
|
||||
|
@ -695,7 +695,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
|
|||
if (err < 0) {
|
||||
pk_error("failed to register pc-midi sound card: error %d\n",
|
||||
err);
|
||||
goto fail_register;
|
||||
goto fail_register;
|
||||
}
|
||||
|
||||
dbg_hid("pcmidi_snd_initialise finished ok\n");
|
||||
|
|
|
@ -1173,7 +1173,7 @@ static int rmi_populate(struct hid_device *hdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||
static int rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||
{
|
||||
struct rmi_data *data = hid_get_drvdata(hdev);
|
||||
struct input_dev *input = hi->input;
|
||||
|
@ -1185,10 +1185,10 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|||
hid_dbg(hdev, "Opening low level driver\n");
|
||||
ret = hid_hw_open(hdev);
|
||||
if (ret)
|
||||
return;
|
||||
return ret;
|
||||
|
||||
if (!(data->device_flags & RMI_DEVICE))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
/* Allow incoming hid reports */
|
||||
hid_device_io_start(hdev);
|
||||
|
@ -1228,7 +1228,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|||
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
|
||||
|
||||
input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER);
|
||||
ret = input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if (data->button_count) {
|
||||
__set_bit(EV_KEY, input->evbit);
|
||||
|
@ -1244,6 +1246,7 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|||
exit:
|
||||
hid_device_io_stop(hdev);
|
||||
hid_hw_close(hdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rmi_input_mapping(struct hid_device *hdev,
|
||||
|
|
|
@ -177,6 +177,8 @@ static int saitek_event(struct hid_device *hdev, struct hid_field *field,
|
|||
static const struct hid_device_id saitek_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
|
||||
.driver_data = SAITEK_FIX_PS1000 },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT5),
|
||||
.driver_data = SAITEK_RELEASE_MODE_RAT7 },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD),
|
||||
.driver_data = SAITEK_RELEASE_MODE_RAT7 },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
|
||||
|
|
|
@ -660,8 +660,8 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
|||
GFP_KERNEL);
|
||||
if (sd->hid_sensor_hub_client_devs == NULL) {
|
||||
hid_err(hdev, "Failed to allocate memory for mfd cells\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_stop_hw;
|
||||
ret = -ENOMEM;
|
||||
goto err_stop_hw;
|
||||
}
|
||||
|
||||
for (i = 0; i < hdev->maxcollection; ++i) {
|
||||
|
@ -698,8 +698,8 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
|||
collection->usage);
|
||||
if (name == NULL) {
|
||||
hid_err(hdev, "Failed MFD device name\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_stop_hw;
|
||||
ret = -ENOMEM;
|
||||
goto err_stop_hw;
|
||||
}
|
||||
sd->hid_sensor_hub_client_devs[
|
||||
sd->hid_sensor_client_cnt].name = name;
|
||||
|
|
|
@ -1360,20 +1360,27 @@ static int sony_register_touchpad(struct hid_input *hi, int touch_count,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void sony_input_configured(struct hid_device *hdev,
|
||||
static int sony_input_configured(struct hid_device *hdev,
|
||||
struct hid_input *hidinput)
|
||||
{
|
||||
struct sony_sc *sc = hid_get_drvdata(hdev);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The Dualshock 4 touchpad supports 2 touches and has a
|
||||
* resolution of 1920x942 (44.86 dots/mm).
|
||||
*/
|
||||
if (sc->quirks & DUALSHOCK4_CONTROLLER) {
|
||||
if (sony_register_touchpad(hidinput, 2, 1920, 942) != 0)
|
||||
ret = sony_register_touchpad(hidinput, 2, 1920, 942);
|
||||
if (ret) {
|
||||
hid_err(sc->hdev,
|
||||
"Unable to initialize multi-touch slots\n");
|
||||
"Unable to initialize multi-touch slots: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -731,7 +731,7 @@ static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void uclogic_input_configured(struct hid_device *hdev,
|
||||
static int uclogic_input_configured(struct hid_device *hdev,
|
||||
struct hid_input *hi)
|
||||
{
|
||||
char *name;
|
||||
|
@ -741,7 +741,7 @@ static void uclogic_input_configured(struct hid_device *hdev,
|
|||
|
||||
/* no report associated (HID_QUIRK_MULTI_INPUT not set) */
|
||||
if (!hi->report)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
field = hi->report->field[0];
|
||||
|
||||
|
@ -774,6 +774,8 @@ static void uclogic_input_configured(struct hid_device *hdev,
|
|||
hi->input->name = name;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1028,6 +1028,7 @@ static int i2c_hid_probe(struct i2c_client *client,
|
|||
|
||||
snprintf(hid->name, sizeof(hid->name), "%s %04hX:%04hX",
|
||||
client->name, hid->vendor, hid->product);
|
||||
strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
|
||||
|
||||
ret = hid_add_device(hid);
|
||||
if (ret) {
|
||||
|
|
|
@ -92,6 +92,7 @@ static const struct hid_blacklist {
|
|||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS },
|
||||
|
|
|
@ -211,7 +211,7 @@ static void wacom_usage_mapping(struct hid_device *hdev,
|
|||
* Bamboo models do not support HID_DG_CONTACTMAX.
|
||||
* And, Bamboo Pen only descriptor contains touch.
|
||||
*/
|
||||
if (features->type != BAMBOO_PT) {
|
||||
if (features->type > BAMBOO_PT) {
|
||||
/* ISDv4 touch devices at least supports one touch point */
|
||||
if (finger && !features->touch_max)
|
||||
features->touch_max = 1;
|
||||
|
@ -222,7 +222,8 @@ static void wacom_usage_mapping(struct hid_device *hdev,
|
|||
features->x_max = field->logical_maximum;
|
||||
if (finger) {
|
||||
features->x_phy = field->physical_maximum;
|
||||
if (features->type != BAMBOO_PT) {
|
||||
if ((features->type != BAMBOO_PT) &&
|
||||
(features->type != BAMBOO_TOUCH)) {
|
||||
features->unit = field->unit;
|
||||
features->unitExpo = field->unit_exponent;
|
||||
}
|
||||
|
@ -232,7 +233,8 @@ static void wacom_usage_mapping(struct hid_device *hdev,
|
|||
features->y_max = field->logical_maximum;
|
||||
if (finger) {
|
||||
features->y_phy = field->physical_maximum;
|
||||
if (features->type != BAMBOO_PT) {
|
||||
if ((features->type != BAMBOO_PT) &&
|
||||
(features->type != BAMBOO_TOUCH)) {
|
||||
features->unit = field->unit;
|
||||
features->unitExpo = field->unit_exponent;
|
||||
}
|
||||
|
@ -420,7 +422,7 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
|
|||
/* MT Tablet PC touch */
|
||||
return wacom_set_device_mode(hdev, 3, 4, 4);
|
||||
}
|
||||
else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
|
||||
else if (features->type == WACOM_24HDT) {
|
||||
return wacom_set_device_mode(hdev, 18, 3, 2);
|
||||
}
|
||||
else if (features->type == WACOM_27QHDT) {
|
||||
|
@ -430,7 +432,7 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
|
|||
return wacom_set_device_mode(hdev, 2, 2, 2);
|
||||
}
|
||||
} else if (features->device_type & WACOM_DEVICETYPE_PEN) {
|
||||
if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
|
||||
if (features->type <= BAMBOO_PT) {
|
||||
return wacom_set_device_mode(hdev, 2, 2, 2);
|
||||
}
|
||||
}
|
||||
|
@ -1547,15 +1549,16 @@ static void wacom_wireless_work(struct work_struct *work)
|
|||
wacom_wac1->features =
|
||||
*((struct wacom_features *)id->driver_data);
|
||||
wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PEN;
|
||||
if (wacom_wac1->features.type != INTUOSHT &&
|
||||
wacom_wac1->features.type != BAMBOO_PT)
|
||||
wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD;
|
||||
wacom_set_default_phy(&wacom_wac1->features);
|
||||
wacom_calculate_res(&wacom_wac1->features);
|
||||
snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen",
|
||||
wacom_wac1->features.name);
|
||||
snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
|
||||
wacom_wac1->features.name);
|
||||
if (wacom_wac1->features.type < BAMBOO_PEN ||
|
||||
wacom_wac1->features.type > BAMBOO_PT) {
|
||||
snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
|
||||
wacom_wac1->features.name);
|
||||
wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD;
|
||||
}
|
||||
wacom_wac1->shared->touch_max = wacom_wac1->features.touch_max;
|
||||
wacom_wac1->shared->type = wacom_wac1->features.type;
|
||||
wacom_wac1->pid = wacom_wac->pid;
|
||||
|
@ -1566,7 +1569,8 @@ static void wacom_wireless_work(struct work_struct *work)
|
|||
|
||||
/* Touch interface */
|
||||
if (wacom_wac1->features.touch_max ||
|
||||
wacom_wac1->features.type == INTUOSHT) {
|
||||
(wacom_wac1->features.type >= INTUOSHT &&
|
||||
wacom_wac1->features.type <= BAMBOO_PT)) {
|
||||
wacom_wac2->features =
|
||||
*((struct wacom_features *)id->driver_data);
|
||||
wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
|
||||
|
@ -1575,20 +1579,22 @@ static void wacom_wireless_work(struct work_struct *work)
|
|||
wacom_calculate_res(&wacom_wac2->features);
|
||||
snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX,
|
||||
"%s (WL) Finger",wacom_wac2->features.name);
|
||||
snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
|
||||
"%s (WL) Pad",wacom_wac2->features.name);
|
||||
if (wacom_wac1->features.touch_max)
|
||||
wacom_wac2->features.device_type |= WACOM_DEVICETYPE_TOUCH;
|
||||
if (wacom_wac1->features.type == INTUOSHT ||
|
||||
wacom_wac1->features.type == BAMBOO_PT)
|
||||
if (wacom_wac1->features.type >= INTUOSHT &&
|
||||
wacom_wac1->features.type <= BAMBOO_PT) {
|
||||
snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX,
|
||||
"%s (WL) Pad",wacom_wac2->features.name);
|
||||
wacom_wac2->features.device_type |= WACOM_DEVICETYPE_PAD;
|
||||
}
|
||||
wacom_wac2->pid = wacom_wac->pid;
|
||||
error = wacom_allocate_inputs(wacom2) ||
|
||||
wacom_register_inputs(wacom2);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
if (wacom_wac1->features.type == INTUOSHT &&
|
||||
if ((wacom_wac1->features.type == INTUOSHT ||
|
||||
wacom_wac1->features.type == INTUOSHT2) &&
|
||||
wacom_wac1->features.touch_max)
|
||||
wacom_wac->shared->touch_input = wacom_wac2->touch_input;
|
||||
}
|
||||
|
@ -1812,11 +1818,27 @@ static int wacom_probe(struct hid_device *hdev,
|
|||
/* Note that if query fails it is not a hard failure */
|
||||
wacom_query_tablet_data(hdev, features);
|
||||
|
||||
/* touch only Bamboo doesn't support pen */
|
||||
if ((features->type == BAMBOO_TOUCH) &&
|
||||
(features->device_type & WACOM_DEVICETYPE_PEN)) {
|
||||
error = -ENODEV;
|
||||
goto fail_hw_start;
|
||||
}
|
||||
|
||||
/* pen only Bamboo neither support touch nor pad */
|
||||
if ((features->type == BAMBOO_PEN) &&
|
||||
((features->device_type & WACOM_DEVICETYPE_TOUCH) ||
|
||||
(features->device_type & WACOM_DEVICETYPE_PAD))) {
|
||||
error = -ENODEV;
|
||||
goto fail_hw_start;
|
||||
}
|
||||
|
||||
if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
|
||||
error = hid_hw_open(hdev);
|
||||
|
||||
if (wacom_wac->features.type == INTUOSHT &&
|
||||
wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) {
|
||||
if ((wacom_wac->features.type == INTUOSHT ||
|
||||
wacom_wac->features.type == INTUOSHT2) &&
|
||||
(wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)) {
|
||||
wacom_wac->shared->touch_input = wacom_wac->touch_input;
|
||||
}
|
||||
|
||||
|
|
|
@ -765,13 +765,15 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
|
|||
/* general pen packet */
|
||||
if ((data[1] & 0xb8) == 0xa0) {
|
||||
t = (data[6] << 2) | ((data[7] >> 6) & 3);
|
||||
if (features->type >= INTUOS4S && features->type <= CINTIQ_HYBRID) {
|
||||
if (features->pressure_max == 2047) {
|
||||
t = (t << 1) | (data[1] & 1);
|
||||
}
|
||||
input_report_abs(input, ABS_PRESSURE, t);
|
||||
input_report_abs(input, ABS_TILT_X,
|
||||
if (features->type != INTUOSHT2) {
|
||||
input_report_abs(input, ABS_TILT_X,
|
||||
(((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
|
||||
input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
|
||||
input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
|
||||
}
|
||||
input_report_key(input, BTN_STYLUS, data[1] & 2);
|
||||
input_report_key(input, BTN_STYLUS2, data[1] & 4);
|
||||
input_report_key(input, BTN_TOUCH, t > 10);
|
||||
|
@ -799,6 +801,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
|||
data[0] != WACOM_REPORT_INTUOSREAD &&
|
||||
data[0] != WACOM_REPORT_INTUOSWRITE &&
|
||||
data[0] != WACOM_REPORT_INTUOSPAD &&
|
||||
data[0] != WACOM_REPORT_INTUOS_PEN &&
|
||||
data[0] != WACOM_REPORT_CINTIQ &&
|
||||
data[0] != WACOM_REPORT_CINTIQPAD &&
|
||||
data[0] != WACOM_REPORT_INTUOS5PAD) {
|
||||
|
@ -948,6 +951,27 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
|||
} else {
|
||||
input_report_abs(input, ABS_MISC, 0);
|
||||
}
|
||||
|
||||
} else if (features->type == CINTIQ_COMPANION_2) {
|
||||
input_report_key(input, BTN_1, (data[1] & 0x02));
|
||||
input_report_key(input, BTN_2, (data[2] & 0x01));
|
||||
input_report_key(input, BTN_3, (data[2] & 0x02));
|
||||
input_report_key(input, BTN_4, (data[2] & 0x04));
|
||||
input_report_key(input, BTN_5, (data[2] & 0x08));
|
||||
input_report_key(input, BTN_6, (data[1] & 0x04));
|
||||
|
||||
input_report_key(input, BTN_7, (data[2] & 0x10)); /* Right */
|
||||
input_report_key(input, BTN_8, (data[2] & 0x20)); /* Up */
|
||||
input_report_key(input, BTN_9, (data[2] & 0x40)); /* Left */
|
||||
input_report_key(input, BTN_A, (data[2] & 0x80)); /* Down */
|
||||
input_report_key(input, BTN_0, (data[1] & 0x01)); /* Center */
|
||||
|
||||
if (data[2] | (data[1] & 0x07)) {
|
||||
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
|
||||
} else {
|
||||
input_report_abs(input, ABS_MISC, 0);
|
||||
}
|
||||
|
||||
} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
|
||||
int i;
|
||||
|
||||
|
@ -1922,7 +1946,7 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
|
|||
int y = (data[3] << 4) | (data[4] & 0x0f);
|
||||
int width, height;
|
||||
|
||||
if (features->type >= INTUOSPS && features->type <= INTUOSHT) {
|
||||
if (features->type >= INTUOSPS && features->type <= INTUOSHT2) {
|
||||
width = data[5] * 100;
|
||||
height = data[6] * 100;
|
||||
} else {
|
||||
|
@ -1950,7 +1974,7 @@ static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
|
|||
struct input_dev *input = wacom->pad_input;
|
||||
struct wacom_features *features = &wacom->features;
|
||||
|
||||
if (features->type == INTUOSHT) {
|
||||
if (features->type == INTUOSHT || features->type == INTUOSHT2) {
|
||||
input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0);
|
||||
input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0);
|
||||
} else {
|
||||
|
@ -1965,7 +1989,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
|
|||
{
|
||||
unsigned char *data = wacom->data;
|
||||
int count = data[1] & 0x07;
|
||||
int i;
|
||||
int touch_changed = 0, i;
|
||||
|
||||
if (data[0] != 0x02)
|
||||
return 0;
|
||||
|
@ -1975,15 +1999,16 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
|
|||
int offset = (8 * i) + 2;
|
||||
int msg_id = data[offset];
|
||||
|
||||
if (msg_id >= 2 && msg_id <= 17)
|
||||
if (msg_id >= 2 && msg_id <= 17) {
|
||||
wacom_bpt3_touch_msg(wacom, data + offset);
|
||||
else if (msg_id == 128)
|
||||
touch_changed++;
|
||||
} else if (msg_id == 128)
|
||||
wacom_bpt3_button_msg(wacom, data + offset);
|
||||
|
||||
}
|
||||
|
||||
/* only update the touch if we actually have a touchpad */
|
||||
if (wacom->touch_registered) {
|
||||
/* only update touch if we actually have a touchpad and touch data changed */
|
||||
if (wacom->touch_registered && touch_changed) {
|
||||
input_mt_sync_frame(wacom->touch_input);
|
||||
wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
|
||||
}
|
||||
|
@ -2064,7 +2089,12 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
|
|||
|
||||
static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
|
||||
{
|
||||
if (len == WACOM_PKGLEN_BBTOUCH)
|
||||
struct wacom_features *features = &wacom->features;
|
||||
|
||||
if ((features->type == INTUOSHT2) &&
|
||||
(features->device_type & WACOM_DEVICETYPE_PEN))
|
||||
return wacom_intuos_irq(wacom);
|
||||
else if (len == WACOM_PKGLEN_BBTOUCH)
|
||||
return wacom_bpt_touch(wacom);
|
||||
else if (len == WACOM_PKGLEN_BBTOUCH3)
|
||||
return wacom_bpt3_touch(wacom);
|
||||
|
@ -2171,7 +2201,8 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
|
|||
if (connected) {
|
||||
int pid, battery, charging;
|
||||
|
||||
if ((wacom->shared->type == INTUOSHT) &&
|
||||
if ((wacom->shared->type == INTUOSHT ||
|
||||
wacom->shared->type == INTUOSHT2) &&
|
||||
wacom->shared->touch_input &&
|
||||
wacom->shared->touch_max) {
|
||||
input_report_switch(wacom->shared->touch_input,
|
||||
|
@ -2209,7 +2240,8 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
|
|||
if (data[0] != WACOM_REPORT_USB)
|
||||
return 0;
|
||||
|
||||
if (features->type == INTUOSHT &&
|
||||
if ((features->type == INTUOSHT ||
|
||||
features->type == INTUOSHT2) &&
|
||||
wacom_wac->shared->touch_input &&
|
||||
features->touch_max) {
|
||||
input_report_switch(wacom_wac->shared->touch_input,
|
||||
|
@ -2290,6 +2322,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
|||
case WACOM_27QHD:
|
||||
case DTK:
|
||||
case CINTIQ_HYBRID:
|
||||
case CINTIQ_COMPANION_2:
|
||||
sync = wacom_intuos_irq(wacom_wac);
|
||||
break;
|
||||
|
||||
|
@ -2326,7 +2359,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
|||
break;
|
||||
|
||||
case BAMBOO_PT:
|
||||
case BAMBOO_PEN:
|
||||
case BAMBOO_TOUCH:
|
||||
case INTUOSHT:
|
||||
case INTUOSHT2:
|
||||
if (wacom_wac->data[0] == WACOM_REPORT_USB)
|
||||
sync = wacom_status_irq(wacom_wac, len);
|
||||
else
|
||||
|
@ -2363,22 +2399,31 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
|
||||
static void wacom_setup_basic_pro_pen(struct wacom_wac *wacom_wac)
|
||||
{
|
||||
struct input_dev *input_dev = wacom_wac->pen_input;
|
||||
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
|
||||
|
||||
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS2, input_dev->keybit);
|
||||
|
||||
input_set_abs_params(input_dev, ABS_DISTANCE,
|
||||
0, wacom_wac->features.distance_max, 0, 0);
|
||||
}
|
||||
|
||||
static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
|
||||
{
|
||||
struct input_dev *input_dev = wacom_wac->pen_input;
|
||||
|
||||
wacom_setup_basic_pro_pen(wacom_wac);
|
||||
|
||||
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_BRUSH, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_PENCIL, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_AIRBRUSH, input_dev->keybit);
|
||||
|
||||
input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_TILT_X, -64, 63, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_TILT_X, 57);
|
||||
|
@ -2413,9 +2458,8 @@ void wacom_setup_device_quirks(struct wacom *wacom)
|
|||
|
||||
/* The pen and pad share the same interface on most devices */
|
||||
if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 ||
|
||||
features->type == DTUS || features->type == WACOM_MO ||
|
||||
(features->type >= INTUOS3S && features->type <= WACOM_13HD &&
|
||||
features->type != INTUOSHT)) {
|
||||
features->type == DTUS ||
|
||||
(features->type >= INTUOS3S && features->type <= WACOM_MO)) {
|
||||
if (features->device_type & WACOM_DEVICETYPE_PEN)
|
||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||
}
|
||||
|
@ -2432,12 +2476,12 @@ void wacom_setup_device_quirks(struct wacom *wacom)
|
|||
* interface (PacketSize of WACOM_PKGLEN_BBTOUCH3), override the
|
||||
* tablet values.
|
||||
*/
|
||||
if ((features->type >= INTUOS5S && features->type <= INTUOSHT) ||
|
||||
(features->type == BAMBOO_PT)) {
|
||||
if ((features->type >= INTUOS5S && features->type <= INTUOSPL) ||
|
||||
(features->type >= INTUOSHT && features->type <= BAMBOO_PT)) {
|
||||
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
|
||||
if (features->touch_max)
|
||||
features->device_type |= WACOM_DEVICETYPE_TOUCH;
|
||||
if (features->type == BAMBOO_PT || features->type == INTUOSHT)
|
||||
if (features->type >= INTUOSHT || features->type <= BAMBOO_PT)
|
||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||
|
||||
features->x_max = 4096;
|
||||
|
@ -2546,6 +2590,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
|
|||
case CINTIQ:
|
||||
case WACOM_13HD:
|
||||
case CINTIQ_HYBRID:
|
||||
case CINTIQ_COMPANION_2:
|
||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_Z, 287);
|
||||
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
|
||||
|
@ -2624,16 +2669,22 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
|
|||
|
||||
case INTUOSHT:
|
||||
case BAMBOO_PT:
|
||||
__clear_bit(ABS_MISC, input_dev->absbit);
|
||||
|
||||
case BAMBOO_PEN:
|
||||
case INTUOSHT2:
|
||||
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
|
||||
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS2, input_dev->keybit);
|
||||
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
|
||||
|
||||
if (features->type == INTUOSHT2) {
|
||||
wacom_setup_basic_pro_pen(wacom_wac);
|
||||
} else {
|
||||
__clear_bit(ABS_MISC, input_dev->absbit);
|
||||
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS2, input_dev->keybit);
|
||||
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
|
||||
features->distance_max,
|
||||
0, 0);
|
||||
}
|
||||
break;
|
||||
case BAMBOO_PAD:
|
||||
__clear_bit(ABS_MISC, input_dev->absbit);
|
||||
|
@ -2714,11 +2765,13 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
|
|||
break;
|
||||
|
||||
case INTUOSHT:
|
||||
case INTUOSHT2:
|
||||
input_dev->evbit[0] |= BIT_MASK(EV_SW);
|
||||
__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
|
||||
/* fall through */
|
||||
|
||||
case BAMBOO_PT:
|
||||
case BAMBOO_TOUCH:
|
||||
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
|
||||
input_set_abs_params(input_dev,
|
||||
ABS_MT_TOUCH_MAJOR,
|
||||
|
@ -2778,6 +2831,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
|
|||
switch (features->type) {
|
||||
|
||||
case CINTIQ_HYBRID:
|
||||
case CINTIQ_COMPANION_2:
|
||||
case DTK:
|
||||
case DTUS:
|
||||
case GRAPHIRE_BT:
|
||||
|
@ -2871,6 +2925,8 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
|
|||
|
||||
case INTUOSHT:
|
||||
case BAMBOO_PT:
|
||||
case BAMBOO_TOUCH:
|
||||
case INTUOSHT2:
|
||||
__clear_bit(ABS_MISC, input_dev->absbit);
|
||||
|
||||
__set_bit(BTN_LEFT, input_dev->keybit);
|
||||
|
@ -3261,11 +3317,10 @@ static const struct wacom_features wacom_features_0x47 =
|
|||
{ "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
|
||||
INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x84 =
|
||||
{ "Wacom Wireless Receiver", 0, 0, 0, 0,
|
||||
WIRELESS, 0, 0, .touch_max = 16 };
|
||||
{ "Wacom Wireless Receiver", .type = WIRELESS, .touch_max = 16 };
|
||||
static const struct wacom_features wacom_features_0xD0 =
|
||||
{ "Wacom Bamboo 2FG", 14720, 9200, 1023, 31,
|
||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
||||
BAMBOO_TOUCH, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
||||
static const struct wacom_features wacom_features_0xD1 =
|
||||
{ "Wacom Bamboo 2FG 4x5", 14720, 9200, 1023, 31,
|
||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
||||
|
@ -3277,10 +3332,10 @@ static const struct wacom_features wacom_features_0xD3 =
|
|||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
||||
static const struct wacom_features wacom_features_0xD4 =
|
||||
{ "Wacom Bamboo Pen", 14720, 9200, 1023, 31,
|
||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD5 =
|
||||
{ "Wacom Bamboo Pen 6x8", 21648, 13700, 1023, 31,
|
||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD6 =
|
||||
{ "Wacom BambooPT 2FG 4x5", 14720, 9200, 1023, 31,
|
||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
||||
|
@ -3307,7 +3362,7 @@ static const struct wacom_features wacom_features_0xDF =
|
|||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
|
||||
static const struct wacom_features wacom_features_0x300 =
|
||||
{ "Wacom Bamboo One S", 14720, 9225, 1023, 31,
|
||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x301 =
|
||||
{ "Wacom Bamboo One M", 21648, 13530, 1023, 31,
|
||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
|
@ -3350,14 +3405,38 @@ static const struct wacom_features wacom_features_0x318 =
|
|||
static const struct wacom_features wacom_features_0x319 =
|
||||
{ "Wacom Wireless Bamboo PAD", 4095, 4095, /* Touch */
|
||||
.type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
|
||||
static const struct wacom_features wacom_features_0x325 =
|
||||
{ "Wacom ISDv5 325", 59552, 33848, 2047, 63,
|
||||
CINTIQ_COMPANION_2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 11,
|
||||
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
|
||||
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x326 };
|
||||
static const struct wacom_features wacom_features_0x326 = /* Touch */
|
||||
{ "Wacom ISDv5 326", .type = HID_GENERIC, .oVid = USB_VENDOR_ID_WACOM,
|
||||
.oPid = 0x325 };
|
||||
static const struct wacom_features wacom_features_0x323 =
|
||||
{ "Wacom Intuos P M", 21600, 13500, 1023, 31,
|
||||
INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
|
||||
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
|
||||
static const struct wacom_features wacom_features_0x331 =
|
||||
{ "Wacom Express Key Remote", 0, 0, 0, 0,
|
||||
REMOTE, 0, 0, 18, .check_for_hid_type = true,
|
||||
{ "Wacom Express Key Remote", .type = REMOTE,
|
||||
.numbered_buttons = 18, .check_for_hid_type = true,
|
||||
.hid_type = HID_TYPE_USBNONE };
|
||||
static const struct wacom_features wacom_features_0x33B =
|
||||
{ "Wacom Intuos S 2", 15200, 9500, 2047, 63,
|
||||
INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
|
||||
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
|
||||
static const struct wacom_features wacom_features_0x33C =
|
||||
{ "Wacom Intuos PT S 2", 15200, 9500, 2047, 63,
|
||||
INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
|
||||
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
|
||||
static const struct wacom_features wacom_features_0x33D =
|
||||
{ "Wacom Intuos P M 2", 21600, 13500, 2047, 63,
|
||||
INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
|
||||
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
|
||||
static const struct wacom_features wacom_features_0x33E =
|
||||
{ "Wacom Intuos PT M 2", 21600, 13500, 2047, 63,
|
||||
INTUOSHT2, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
|
||||
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
|
||||
|
||||
static const struct wacom_features wacom_features_HID_ANY_ID =
|
||||
{ "Wacom HID", .type = HID_GENERIC };
|
||||
|
@ -3509,6 +3588,8 @@ const struct hid_device_id wacom_ids[] = {
|
|||
{ USB_DEVICE_WACOM(0x318) },
|
||||
{ USB_DEVICE_WACOM(0x319) },
|
||||
{ USB_DEVICE_WACOM(0x323) },
|
||||
{ USB_DEVICE_WACOM(0x325) },
|
||||
{ USB_DEVICE_WACOM(0x326) },
|
||||
{ USB_DEVICE_WACOM(0x32A) },
|
||||
{ USB_DEVICE_WACOM(0x32B) },
|
||||
{ USB_DEVICE_WACOM(0x32C) },
|
||||
|
@ -3517,6 +3598,10 @@ const struct hid_device_id wacom_ids[] = {
|
|||
{ USB_DEVICE_WACOM(0x333) },
|
||||
{ USB_DEVICE_WACOM(0x335) },
|
||||
{ USB_DEVICE_WACOM(0x336) },
|
||||
{ USB_DEVICE_WACOM(0x33B) },
|
||||
{ USB_DEVICE_WACOM(0x33C) },
|
||||
{ USB_DEVICE_WACOM(0x33D) },
|
||||
{ USB_DEVICE_WACOM(0x33E) },
|
||||
{ USB_DEVICE_WACOM(0x4001) },
|
||||
{ USB_DEVICE_WACOM(0x4004) },
|
||||
{ USB_DEVICE_WACOM(0x5000) },
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#define WACOM_REPORT_BPAD_PEN 3
|
||||
#define WACOM_REPORT_BPAD_TOUCH 16
|
||||
#define WACOM_REPORT_DEVICE_LIST 16
|
||||
#define WACOM_REPORT_INTUOS_PEN 16
|
||||
#define WACOM_REPORT_REMOTE 17
|
||||
|
||||
/* device quirks */
|
||||
|
@ -117,22 +118,26 @@ enum {
|
|||
INTUOSPS,
|
||||
INTUOSPM,
|
||||
INTUOSPL,
|
||||
INTUOSHT,
|
||||
WACOM_21UX2,
|
||||
WACOM_22HD,
|
||||
DTK,
|
||||
WACOM_24HD,
|
||||
WACOM_27QHD,
|
||||
CINTIQ_HYBRID,
|
||||
CINTIQ_COMPANION_2,
|
||||
CINTIQ,
|
||||
WACOM_BEE,
|
||||
WACOM_13HD,
|
||||
WACOM_MO,
|
||||
WIRELESS,
|
||||
BAMBOO_PEN,
|
||||
INTUOSHT,
|
||||
INTUOSHT2,
|
||||
BAMBOO_TOUCH,
|
||||
BAMBOO_PT,
|
||||
WACOM_24HDT,
|
||||
WACOM_27QHDT,
|
||||
BAMBOO_PAD,
|
||||
WIRELESS,
|
||||
REMOTE,
|
||||
TABLETPC, /* add new TPC below */
|
||||
TABLETPCE,
|
||||
|
|
|
@ -698,8 +698,8 @@ struct hid_driver {
|
|||
int (*input_mapped)(struct hid_device *hdev,
|
||||
struct hid_input *hidinput, struct hid_field *field,
|
||||
struct hid_usage *usage, unsigned long **bit, int *max);
|
||||
void (*input_configured)(struct hid_device *hdev,
|
||||
struct hid_input *hidinput);
|
||||
int (*input_configured)(struct hid_device *hdev,
|
||||
struct hid_input *hidinput);
|
||||
void (*feature_mapping)(struct hid_device *hdev,
|
||||
struct hid_field *field,
|
||||
struct hid_usage *usage);
|
||||
|
|
Loading…
Reference in New Issue