Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina: "Highlights: - Intel Skylake Win8 precision touchpads support fixes/improvements from Mika Westerberg - Lenovo Yoga 2 quirk from Ritesh Raj Sarraf - potential uninitialized buffer access fix in HID core from Richard Purdie - Wacom Intuos and Wacom Cintiq 2 support improvements from Jason Gerecke and Ping Cheng - initiation of sysfs deprecation process for most of the roccat drivers, from the roccat support maintiner Stefan Achatz - quite a few device ID / quirk additions and small fixes" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (30 commits) HID: logitech: Add support for G29 HID: logitech: Simplify wheel detection scheme HID: wacom: Call 'wacom_query_tablet_data' only after 'hid_hw_start' HID: wacom: Fix ABS_MISC reporting for Cintiq Companion 2 HID: wacom: Remove useless conditions from 'wacom_query_tablet_data' HID: wacom: fix Intuos wireless report id issue HID: fix some indenting issues HID: wacom: Expect 'touch_max' touches if HID_DG_CONTACTCOUNT not present HID: wacom: Tie cached HID_DG_CONTACTCOUNT indices to report ID HID: roccat: Fixed resubmit: Deprecating most Roccat sysfs attributes HID: wacom: Report full pressure range for Intuos, Cintiq 13HD Touch HID: wacom: Add support for Cintiq Companion 2 HID: multitouch: Fetch feature reports on demand for Win8 devices HID: sensor-hub: Add quirk for Lenovo Yoga 2 with ITE Chips HID: usbhid: Fix for the WiiU adapter from Mayflash HID: corsair: boolify struct k90_led.removed HID: corsair: Add Corsair Vengeance K90 driver HID: hid-input: allow input_configured callback return errors HID: multitouch: Add suffix for HID_DG_TOUCHPAD HID: i2c-hid: Fill in physical device providing HID functionality ...
This commit is contained in:
commit
6f1da317ac
34 changed files with 1492 additions and 323 deletions
|
@ -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
|
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/startup_profile
|
||||||
Date: October 2010
|
Date: October 2010
|
||||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
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.
|
Please read binary attribute info which contains firmware version.
|
||||||
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>/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
|
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_buttons
|
||||||
Date: August 2010
|
Date: August 2010
|
||||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
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.
|
Write control to select profile and read profile_buttons 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>/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
|
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/profile[1-5]_settings
|
||||||
Date: August 2010
|
Date: August 2010
|
||||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||||
|
@ -46,3 +107,39 @@ Description: The mouse can store 5 profiles which can be switched by the
|
||||||
This file is readonly.
|
This file is readonly.
|
||||||
Write control to select profile and read profile_settings instead.
|
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.
|
Has never been used. If bookkeeping is done, it's done in userland tools.
|
||||||
Users: http://roccat.sourceforge.net
|
Users: http://roccat.sourceforge.net
|
||||||
|
|
||||||
|
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/actual_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
|
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
|
Date: January 2011
|
||||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
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".
|
Obsoleted by binary sysfs attribute "info".
|
||||||
Users: http://roccat.sourceforge.net
|
Users: http://roccat.sourceforge.net
|
||||||
|
|
||||||
|
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/kovaplus/roccatkovaplus<minor>/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
|
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
|
Date: January 2011
|
||||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
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.
|
Write control to select profile and read profile_buttons 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>/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
|
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
|
Date: January 2011
|
||||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
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.
|
Please use binary attribute "info" which provides this information.
|
||||||
Users: http://roccat.sourceforge.net
|
Users: http://roccat.sourceforge.net
|
||||||
|
|
||||||
|
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/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
|
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_buttons
|
||||||
Date: August 2010
|
Date: August 2010
|
||||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
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.
|
Write control to select profile and read profile_buttons 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>/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
|
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/profile[1-5]_settings
|
||||||
Date: August 2010
|
Date: August 2010
|
||||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
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.
|
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>/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
|
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/pyra/roccatpyra<minor>/startup_profile
|
||||||
Date: August 2010
|
Date: August 2010
|
||||||
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
|
||||||
|
|
15
Documentation/ABI/testing/sysfs-driver-hid-corsair
Normal file
15
Documentation/ABI/testing/sysfs-driver-hid-corsair
Normal file
|
@ -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---
|
---help---
|
||||||
Support for Chicony Tactical pad.
|
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
|
config HID_PRODIKEYS
|
||||||
tristate "Prodikeys PC-MIDI Keyboard support"
|
tristate "Prodikeys PC-MIDI Keyboard support"
|
||||||
depends on HID && SND
|
depends on HID && SND
|
||||||
|
@ -678,9 +688,8 @@ config HID_SAITEK
|
||||||
|
|
||||||
Supported devices:
|
Supported devices:
|
||||||
- PS1000 Dual Analog Pad
|
- PS1000 Dual Analog Pad
|
||||||
- R.A.T.9 Gaming Mouse
|
- Saitek R.A.T.7, R.A.T.9, M.M.O.7 Gaming Mice
|
||||||
- R.A.T.7 Gaming Mouse
|
- Mad Catz R.A.T.5, R.A.T.9 Gaming Mice
|
||||||
- M.M.O.7 Gaming Mouse
|
|
||||||
|
|
||||||
config HID_SAMSUNG
|
config HID_SAMSUNG
|
||||||
tristate "Samsung InfraRed remote control or keyboards"
|
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_BETOP_FF) += hid-betopff.o
|
||||||
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
|
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
|
||||||
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
|
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
|
||||||
|
obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o
|
||||||
obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
|
obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
|
||||||
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
|
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
|
||||||
obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
|
obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
|
||||||
|
|
|
@ -23,7 +23,8 @@ static __u8 *aureal_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) {
|
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");
|
dev_info(&hdev->dev, "fixing Aureal Cy se W-01RN USB_V3.1 report descriptor.\n");
|
||||||
rdesc[53] = 0x65;
|
rdesc[53] = 0x65;
|
||||||
} return rdesc;
|
}
|
||||||
|
return rdesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct hid_device_id aureal_devices[] = {
|
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 &&
|
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 ||
|
||||||
|
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_PRO_3_JP ||
|
||||||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 ||
|
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 ||
|
||||||
hid->product == USB_DEVICE_ID_MS_POWER_COVER) &&
|
hid->product == USB_DEVICE_ID_MS_POWER_COVER) &&
|
||||||
|
@ -1611,7 +1612,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
|
||||||
"Multi-Axis Controller"
|
"Multi-Axis Controller"
|
||||||
};
|
};
|
||||||
const char *type, *bus;
|
const char *type, *bus;
|
||||||
char buf[64];
|
char buf[64] = "";
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int len;
|
int len;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1678,6 +1679,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
|
||||||
case BUS_BLUETOOTH:
|
case BUS_BLUETOOTH:
|
||||||
bus = "BLUETOOTH";
|
bus = "BLUETOOTH";
|
||||||
break;
|
break;
|
||||||
|
case BUS_I2C:
|
||||||
|
bus = "I2C";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
bus = "<UNKNOWN>";
|
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_WIRELESS2) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
|
{ 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_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_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
|
{ 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) },
|
{ 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_CORD) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
|
{ 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_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_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_WINGMAN_FFG ) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
|
{ 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_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_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) },
|
||||||
|
{ 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_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_TYPE_COVER_3) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) },
|
{ 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_OLD) },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
|
{ 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_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) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
|
||||||
#endif
|
#endif
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
|
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
|
||||||
|
|
673
drivers/hid/hid-corsair.c
Normal file
673
drivers/hid/hid-corsair.c
Normal file
|
@ -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 */
|
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,
|
static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
unsigned int *rsize)
|
unsigned int *rsize)
|
||||||
{
|
{
|
||||||
|
@ -244,6 +296,12 @@ static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
*rsize = sizeof(pid0011_rdesc_fixed);
|
*rsize = sizeof(pid0011_rdesc_fixed);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 0x0006:
|
||||||
|
if (*rsize == sizeof(pid0006_rdesc_fixed)) {
|
||||||
|
rdesc = pid0006_rdesc_fixed;
|
||||||
|
*rsize = sizeof(pid0006_rdesc_fixed);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return rdesc;
|
return rdesc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,6 +251,9 @@
|
||||||
#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
|
#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
|
||||||
#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
|
#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_VENDOR_ID_CREATIVELABS 0x041e
|
||||||
#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
|
#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
|
||||||
|
|
||||||
|
@ -288,6 +291,7 @@
|
||||||
#define USB_DEVICE_ID_DMI_ENC 0x5fab
|
#define USB_DEVICE_ID_DMI_ENC 0x5fab
|
||||||
|
|
||||||
#define USB_VENDOR_ID_DRAGONRISE 0x0079
|
#define USB_VENDOR_ID_DRAGONRISE 0x0079
|
||||||
|
#define USB_DEVICE_ID_DRAGONRISE_WIIU 0x1800
|
||||||
|
|
||||||
#define USB_VENDOR_ID_DWAV 0x0eef
|
#define USB_VENDOR_ID_DWAV 0x0eef
|
||||||
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
|
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
|
||||||
|
@ -510,6 +514,7 @@
|
||||||
|
|
||||||
#define USB_VENDOR_ID_ITE 0x048d
|
#define USB_VENDOR_ID_ITE 0x048d
|
||||||
#define USB_DEVICE_ID_ITE_LENOVO_YOGA 0x8386
|
#define USB_DEVICE_ID_ITE_LENOVO_YOGA 0x8386
|
||||||
|
#define USB_DEVICE_ID_ITE_LENOVO_YOGA2 0x8350
|
||||||
|
|
||||||
#define USB_VENDOR_ID_JABRA 0x0b0e
|
#define USB_VENDOR_ID_JABRA 0x0b0e
|
||||||
#define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412
|
#define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412
|
||||||
|
@ -646,6 +651,7 @@
|
||||||
|
|
||||||
#define USB_VENDOR_ID_MADCATZ 0x0738
|
#define USB_VENDOR_ID_MADCATZ 0x0738
|
||||||
#define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540
|
#define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540
|
||||||
|
#define USB_DEVICE_ID_MADCATZ_RAT5 0x1705
|
||||||
#define USB_DEVICE_ID_MADCATZ_RAT9 0x1709
|
#define USB_DEVICE_ID_MADCATZ_RAT9 0x1709
|
||||||
|
|
||||||
#define USB_VENDOR_ID_MCC 0x09db
|
#define USB_VENDOR_ID_MCC 0x09db
|
||||||
|
@ -679,6 +685,7 @@
|
||||||
#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
|
#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_2 0x07a9
|
||||||
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc
|
#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_PRO_3_JP 0x07dd
|
||||||
#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de
|
#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de
|
||||||
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
|
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
|
||||||
|
|
|
@ -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_Y || usage->code == ABS_Z ||
|
||||||
usage->code == ABS_RZ)) {
|
usage->code == ABS_RZ)) {
|
||||||
switch (hdev->product) {
|
switch (hdev->product) {
|
||||||
|
case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
|
||||||
case USB_DEVICE_ID_LOGITECH_WHEEL:
|
case USB_DEVICE_ID_LOGITECH_WHEEL:
|
||||||
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
|
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
|
||||||
case USB_DEVICE_ID_LOGITECH_DFP_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)
|
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;
|
unsigned int connect_mask = HID_CONNECT_DEFAULT;
|
||||||
struct lg_drv_data *drv_data;
|
struct lg_drv_data *drv_data;
|
||||||
int ret;
|
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);
|
drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
|
||||||
if (!drv_data) {
|
if (!drv_data) {
|
||||||
hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
|
hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
|
||||||
|
|
|
@ -45,7 +45,8 @@
|
||||||
#define LG4FF_MODE_G25_IDX 3
|
#define LG4FF_MODE_G25_IDX 3
|
||||||
#define LG4FF_MODE_DFGT_IDX 4
|
#define LG4FF_MODE_DFGT_IDX 4
|
||||||
#define LG4FF_MODE_G27_IDX 5
|
#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_NATIVE BIT(LG4FF_MODE_NATIVE_IDX)
|
||||||
#define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_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_G25 BIT(LG4FF_MODE_G25_IDX)
|
||||||
#define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX)
|
#define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX)
|
||||||
#define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_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_TAG "DF-EX"
|
||||||
#define LG4FF_DFEX_NAME "Driving Force / Formula EX"
|
#define LG4FF_DFEX_NAME "Driving Force / Formula EX"
|
||||||
|
@ -62,6 +64,8 @@
|
||||||
#define LG4FF_G25_NAME "G25 Racing Wheel"
|
#define LG4FF_G25_NAME "G25 Racing Wheel"
|
||||||
#define LG4FF_G27_TAG "G27"
|
#define LG4FF_G27_TAG "G27"
|
||||||
#define LG4FF_G27_NAME "G27 Racing Wheel"
|
#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_TAG "DFGT"
|
||||||
#define LG4FF_DFGT_NAME "Driving Force GT"
|
#define LG4FF_DFGT_NAME "Driving Force GT"
|
||||||
|
|
||||||
|
@ -114,16 +118,12 @@ struct lg4ff_compat_mode_switch {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lg4ff_wheel_ident_info {
|
struct lg4ff_wheel_ident_info {
|
||||||
|
const u32 modes;
|
||||||
const u16 mask;
|
const u16 mask;
|
||||||
const u16 result;
|
const u16 result;
|
||||||
const u16 real_product_id;
|
const u16 real_product_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lg4ff_wheel_ident_checklist {
|
|
||||||
const u32 count;
|
|
||||||
const struct lg4ff_wheel_ident_info *models[];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lg4ff_multimode_wheel {
|
struct lg4ff_multimode_wheel {
|
||||||
const u16 product_id;
|
const u16 product_id;
|
||||||
const u32 alternate_modes;
|
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_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_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_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_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL},
|
||||||
{USB_DEVICE_ID_LOGITECH_WII_WHEEL, 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,
|
{USB_DEVICE_ID_LOGITECH_G27_WHEEL,
|
||||||
LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||||
LG4FF_G27_TAG, LG4FF_G27_NAME},
|
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[] = {
|
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_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_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_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 */
|
/* Multimode wheel identificators */
|
||||||
static const struct lg4ff_wheel_ident_info lg4ff_dfp_ident_info = {
|
static const struct lg4ff_wheel_ident_info lg4ff_dfp_ident_info = {
|
||||||
|
LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||||
0xf000,
|
0xf000,
|
||||||
0x1000,
|
0x1000,
|
||||||
USB_DEVICE_ID_LOGITECH_DFP_WHEEL
|
USB_DEVICE_ID_LOGITECH_DFP_WHEEL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct lg4ff_wheel_ident_info lg4ff_g25_ident_info = {
|
static const struct lg4ff_wheel_ident_info lg4ff_g25_ident_info = {
|
||||||
|
LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||||
0xff00,
|
0xff00,
|
||||||
0x1200,
|
0x1200,
|
||||||
USB_DEVICE_ID_LOGITECH_G25_WHEEL
|
USB_DEVICE_ID_LOGITECH_G25_WHEEL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct lg4ff_wheel_ident_info lg4ff_g27_ident_info = {
|
static const struct lg4ff_wheel_ident_info lg4ff_g27_ident_info = {
|
||||||
|
LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||||
0xfff0,
|
0xfff0,
|
||||||
0x1230,
|
0x1230,
|
||||||
USB_DEVICE_ID_LOGITECH_G27_WHEEL
|
USB_DEVICE_ID_LOGITECH_G27_WHEEL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = {
|
static const struct lg4ff_wheel_ident_info lg4ff_dfgt_ident_info = {
|
||||||
|
LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX,
|
||||||
0xff00,
|
0xff00,
|
||||||
0x1300,
|
0x1300,
|
||||||
USB_DEVICE_ID_LOGITECH_DFGT_WHEEL
|
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 */
|
/* Multimode wheel identification checklists */
|
||||||
static const struct lg4ff_wheel_ident_checklist lg4ff_main_checklist = {
|
static const struct lg4ff_wheel_ident_info *lg4ff_main_checklist[] = {
|
||||||
4,
|
&lg4ff_g29_ident_info,
|
||||||
{&lg4ff_dfgt_ident_info,
|
&lg4ff_g29_ident_info2,
|
||||||
|
&lg4ff_dfgt_ident_info,
|
||||||
&lg4ff_g27_ident_info,
|
&lg4ff_g27_ident_info,
|
||||||
&lg4ff_g25_ident_info,
|
&lg4ff_g25_ident_info,
|
||||||
&lg4ff_dfp_ident_info}
|
&lg4ff_dfp_ident_info
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Compatibility mode switching commands */
|
/* 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 */
|
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 */
|
/* EXT_CMD1 - Understood by DFP, G25, G27 and DFGT */
|
||||||
static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = {
|
static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext01_dfp = {
|
||||||
1,
|
1,
|
||||||
|
@ -651,6 +681,23 @@ static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(cons
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
|
||||||
switch (target_product_id) {
|
switch (target_product_id) {
|
||||||
case USB_DEVICE_ID_LOGITECH_WHEEL:
|
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)
|
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;
|
u32 current_mode;
|
||||||
int i, from_idx, to_idx;
|
int i;
|
||||||
|
|
||||||
switch (reported_product_id) {
|
/* identify current mode from USB PID */
|
||||||
case USB_DEVICE_ID_LOGITECH_WHEEL:
|
for (i = 1; i < ARRAY_SIZE(lg4ff_alternate_modes); i++) {
|
||||||
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
|
dbg_hid("Testing whether PID is %X\n", lg4ff_alternate_modes[i].product_id);
|
||||||
checklist = &lg4ff_main_checklist;
|
if (reported_product_id == lg4ff_alternate_modes[i].product_id)
|
||||||
from_idx = 0;
|
|
||||||
to_idx = checklist->count - 1;
|
|
||||||
break;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = from_idx; i <= to_idx; i++) {
|
if (i == ARRAY_SIZE(lg4ff_alternate_modes))
|
||||||
const u16 mask = checklist->models[i]->mask;
|
return 0;
|
||||||
const u16 result = checklist->models[i]->result;
|
|
||||||
const u16 real_product_id = checklist->models[i]->real_product_id;
|
|
||||||
|
|
||||||
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);
|
dbg_hid("Found wheel with real PID %X whose reported PID is %X\n", real_product_id, reported_product_id);
|
||||||
return real_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);
|
entry->wdata.set_range(hid, entry->wdata.range);
|
||||||
|
|
||||||
#ifdef CONFIG_LEDS_CLASS
|
#ifdef CONFIG_LEDS_CLASS
|
||||||
/* register led subsystem - G27 only */
|
/* register led subsystem - G27/G29 only */
|
||||||
entry->wdata.led_state = 0;
|
entry->wdata.led_state = 0;
|
||||||
for (j = 0; j < 5; j++)
|
for (j = 0; j < 5; j++)
|
||||||
entry->wdata.led[j] = NULL;
|
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;
|
struct led_classdev *led;
|
||||||
size_t name_sz;
|
size_t name_sz;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
|
@ -33,6 +33,11 @@ module_param(disable_raw_mode, bool, 0644);
|
||||||
MODULE_PARM_DESC(disable_raw_mode,
|
MODULE_PARM_DESC(disable_raw_mode,
|
||||||
"Disable Raw mode reporting for touchpads and keep firmware gestures.");
|
"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_SHORT 0x10
|
||||||
#define REPORT_ID_HIDPP_LONG 0x11
|
#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_WTP BIT(0)
|
||||||
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
|
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
|
||||||
|
#define HIDPP_QUIRK_CLASS_K400 BIT(2)
|
||||||
|
|
||||||
/* bits 2..20 are reserved for classes */
|
/* 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_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
|
* 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;
|
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 */
|
/* 0x6100: TouchPadRawXY */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
@ -1132,6 +1188,75 @@ static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||||
return -1;
|
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 */
|
/* Generic HID++ devices */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
@ -1205,7 +1330,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
|
||||||
if (unlikely(hidpp_report_is_connect_event(report))) {
|
if (unlikely(hidpp_report_is_connect_event(report))) {
|
||||||
atomic_set(&hidpp->connected,
|
atomic_set(&hidpp->connected,
|
||||||
!(report->rap.params[0] & (1 << 6)));
|
!(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))
|
(schedule_work(&hidpp->work) == 0))
|
||||||
dbg_hid("%s: connect event already queued\n", __func__);
|
dbg_hid("%s: connect event already queued\n", __func__);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1330,23 +1455,30 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
||||||
ret = m560_send_config_command(hdev, connected);
|
ret = m560_send_config_command(hdev, connected);
|
||||||
if (ret)
|
if (ret)
|
||||||
return;
|
return;
|
||||||
|
} else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) {
|
||||||
|
ret = k400_connect(hdev, connected);
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connected || hidpp->delayed_input)
|
if (!connected || hidpp->delayed_input)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* the device is already connected, we can ask for its name and
|
||||||
|
* protocol */
|
||||||
if (!hidpp->protocol_major) {
|
if (!hidpp->protocol_major) {
|
||||||
ret = !hidpp_is_connected(hidpp);
|
ret = !hidpp_is_connected(hidpp);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
hid_err(hdev, "Can not get the protocol version.\n");
|
hid_err(hdev, "Can not get the protocol version.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* the device is already connected, we can ask for its name and
|
|
||||||
* protocol */
|
|
||||||
hid_info(hdev, "HID++ %u.%u device connected.\n",
|
hid_info(hdev, "HID++ %u.%u device connected.\n",
|
||||||
hidpp->protocol_major, hidpp->protocol_minor);
|
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) {
|
if (!hidpp->name || hidpp->name == hdev->name) {
|
||||||
name = hidpp_get_device_name(hidpp);
|
name = hidpp_get_device_name(hidpp);
|
||||||
|
@ -1399,7 +1531,8 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
|
|
||||||
if (disable_raw_mode) {
|
if (disable_raw_mode) {
|
||||||
hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP;
|
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) {
|
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
|
||||||
|
@ -1410,6 +1543,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
ret = m560_allocate(hdev);
|
ret = m560_allocate(hdev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto allocate_fail;
|
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);
|
INIT_WORK(&hidpp->work, delayed_work_cb);
|
||||||
|
@ -1450,7 +1587,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
/* Block incoming packets */
|
/* Block incoming packets */
|
||||||
hid_device_io_stop(hdev);
|
hid_device_io_stop(hdev);
|
||||||
|
|
||||||
if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
|
if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
|
||||||
connect_mask &= ~HID_CONNECT_HIDINPUT;
|
connect_mask &= ~HID_CONNECT_HIDINPUT;
|
||||||
|
|
||||||
ret = hid_hw_start(hdev, connect_mask);
|
ret = hid_hw_start(hdev, connect_mask);
|
||||||
|
@ -1459,7 +1596,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
goto hid_hw_start_fail;
|
goto hid_hw_start_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) {
|
if (hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) {
|
||||||
/* Allow incoming packets */
|
/* Allow incoming packets */
|
||||||
hid_device_io_start(hdev);
|
hid_device_io_start(hdev);
|
||||||
|
|
||||||
|
@ -1504,6 +1641,10 @@ static const struct hid_device_id hidpp_devices[] = {
|
||||||
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||||
USB_VENDOR_ID_LOGITECH, 0x402d),
|
USB_VENDOR_ID_LOGITECH, 0x402d),
|
||||||
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
|
.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,
|
{ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
||||||
USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
|
USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
|
||||||
|
|
|
@ -278,6 +278,8 @@ static const struct hid_device_id ms_devices[] = {
|
||||||
.driver_data = MS_DUPLICATE_USAGES },
|
.driver_data = MS_DUPLICATE_USAGES },
|
||||||
{ 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),
|
||||||
.driver_data = MS_HIDINPUT },
|
.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),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP),
|
||||||
.driver_data = MS_HIDINPUT },
|
.driver_data = MS_HIDINPUT },
|
||||||
{ 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_TYPE_COVER_3),
|
||||||
|
|
|
@ -309,6 +309,41 @@ static struct attribute_group mt_attribute_group = {
|
||||||
.attrs = sysfs_attrs
|
.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,
|
static void mt_feature_mapping(struct hid_device *hdev,
|
||||||
struct hid_field *field, struct hid_usage *usage)
|
struct hid_field *field, struct hid_usage *usage)
|
||||||
{
|
{
|
||||||
|
@ -327,6 +362,8 @@ static void mt_feature_mapping(struct hid_device *hdev,
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case HID_DG_CONTACTMAX:
|
case HID_DG_CONTACTMAX:
|
||||||
|
mt_get_feature(hdev, field->report);
|
||||||
|
|
||||||
td->maxcontact_report_id = field->report->id;
|
td->maxcontact_report_id = field->report->id;
|
||||||
td->maxcontacts = field->value[0];
|
td->maxcontacts = field->value[0];
|
||||||
if (!td->maxcontacts &&
|
if (!td->maxcontacts &&
|
||||||
|
@ -343,6 +380,7 @@ static void mt_feature_mapping(struct hid_device *hdev,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mt_get_feature(hdev, field->report);
|
||||||
if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD)
|
if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD)
|
||||||
td->is_buttonpad = true;
|
td->is_buttonpad = true;
|
||||||
|
|
||||||
|
@ -976,6 +1014,9 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||||
case HID_DG_TOUCHSCREEN:
|
case HID_DG_TOUCHSCREEN:
|
||||||
/* we do not set suffix = "Touchscreen" */
|
/* we do not set suffix = "Touchscreen" */
|
||||||
break;
|
break;
|
||||||
|
case HID_DG_TOUCHPAD:
|
||||||
|
suffix = "Touchpad";
|
||||||
|
break;
|
||||||
case HID_GD_SYSTEM_CONTROL:
|
case HID_GD_SYSTEM_CONTROL:
|
||||||
suffix = "System Control";
|
suffix = "System Control";
|
||||||
break;
|
break;
|
||||||
|
@ -1036,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
|
* reports. Fortunately, the Win8 spec says that all touches
|
||||||
* should be sent during each report, making the initialization
|
* should be sent during each report, making the initialization
|
||||||
* of input reports unnecessary.
|
* 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);
|
td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
|
||||||
if (!td) {
|
if (!td) {
|
||||||
|
|
|
@ -177,6 +177,8 @@ static int saitek_event(struct hid_device *hdev, struct hid_field *field,
|
||||||
static const struct hid_device_id saitek_devices[] = {
|
static const struct hid_device_id saitek_devices[] = {
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
|
||||||
.driver_data = SAITEK_FIX_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),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD),
|
||||||
.driver_data = SAITEK_RELEASE_MODE_RAT7 },
|
.driver_data = SAITEK_RELEASE_MODE_RAT7 },
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
|
||||||
|
|
|
@ -593,6 +593,20 @@ static __u8 *sensor_hub_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Checks if the report descriptor of Thinkpad Helix 2 has a logical
|
||||||
|
* minimum for magnetic flux axis greater than the maximum */
|
||||||
|
if (hdev->product == USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA &&
|
||||||
|
*rsize == 2558 && rdesc[913] == 0x17 && rdesc[914] == 0x40 &&
|
||||||
|
rdesc[915] == 0x81 && rdesc[916] == 0x08 &&
|
||||||
|
rdesc[917] == 0x00 && rdesc[918] == 0x27 &&
|
||||||
|
rdesc[921] == 0x07 && rdesc[922] == 0x00) {
|
||||||
|
/* Sets negative logical minimum for mag x, y and z */
|
||||||
|
rdesc[914] = rdesc[935] = rdesc[956] = 0xc0;
|
||||||
|
rdesc[915] = rdesc[936] = rdesc[957] = 0x7e;
|
||||||
|
rdesc[916] = rdesc[937] = rdesc[958] = 0xf7;
|
||||||
|
rdesc[917] = rdesc[938] = rdesc[959] = 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
return rdesc;
|
return rdesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,6 +791,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
|
||||||
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
|
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
|
||||||
USB_DEVICE_ID_ITE_LENOVO_YOGA),
|
USB_DEVICE_ID_ITE_LENOVO_YOGA),
|
||||||
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
|
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
|
||||||
|
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
|
||||||
|
USB_DEVICE_ID_ITE_LENOVO_YOGA2),
|
||||||
|
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
|
||||||
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
|
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
|
||||||
HID_ANY_ID) },
|
HID_ANY_ID) },
|
||||||
{ }
|
{ }
|
||||||
|
|
|
@ -1028,6 +1028,7 @@ static int i2c_hid_probe(struct i2c_client *client,
|
||||||
|
|
||||||
snprintf(hid->name, sizeof(hid->name), "%s %04hX:%04hX",
|
snprintf(hid->name, sizeof(hid->name), "%s %04hX:%04hX",
|
||||||
client->name, hid->vendor, hid->product);
|
client->name, hid->vendor, hid->product);
|
||||||
|
strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
|
||||||
|
|
||||||
ret = hid_add_device(hid);
|
ret = hid_add_device(hid);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -71,6 +71,7 @@ static const struct hid_blacklist {
|
||||||
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
|
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
|
||||||
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
|
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
|
||||||
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
|
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
|
||||||
|
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
|
||||||
{ USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL },
|
{ USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL },
|
||||||
{ USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B, HID_QUIRK_ALWAYS_POLL },
|
{ USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B, HID_QUIRK_ALWAYS_POLL },
|
||||||
{ USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_0103, HID_QUIRK_ALWAYS_POLL },
|
{ USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_0103, HID_QUIRK_ALWAYS_POLL },
|
||||||
|
@ -91,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_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_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, 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_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_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
|
||||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, 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.
|
* Bamboo models do not support HID_DG_CONTACTMAX.
|
||||||
* And, Bamboo Pen only descriptor contains touch.
|
* 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 */
|
/* ISDv4 touch devices at least supports one touch point */
|
||||||
if (finger && !features->touch_max)
|
if (finger && !features->touch_max)
|
||||||
features->touch_max = 1;
|
features->touch_max = 1;
|
||||||
|
@ -222,7 +222,8 @@ static void wacom_usage_mapping(struct hid_device *hdev,
|
||||||
features->x_max = field->logical_maximum;
|
features->x_max = field->logical_maximum;
|
||||||
if (finger) {
|
if (finger) {
|
||||||
features->x_phy = field->physical_maximum;
|
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->unit = field->unit;
|
||||||
features->unitExpo = field->unit_exponent;
|
features->unitExpo = field->unit_exponent;
|
||||||
}
|
}
|
||||||
|
@ -232,7 +233,8 @@ static void wacom_usage_mapping(struct hid_device *hdev,
|
||||||
features->y_max = field->logical_maximum;
|
features->y_max = field->logical_maximum;
|
||||||
if (finger) {
|
if (finger) {
|
||||||
features->y_phy = field->physical_maximum;
|
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->unit = field->unit;
|
||||||
features->unitExpo = field->unit_exponent;
|
features->unitExpo = field->unit_exponent;
|
||||||
}
|
}
|
||||||
|
@ -420,7 +422,7 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
|
||||||
/* MT Tablet PC touch */
|
/* MT Tablet PC touch */
|
||||||
return wacom_set_device_mode(hdev, 3, 4, 4);
|
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);
|
return wacom_set_device_mode(hdev, 18, 3, 2);
|
||||||
}
|
}
|
||||||
else if (features->type == WACOM_27QHDT) {
|
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);
|
return wacom_set_device_mode(hdev, 2, 2, 2);
|
||||||
}
|
}
|
||||||
} else if (features->device_type & WACOM_DEVICETYPE_PEN) {
|
} 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);
|
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 =
|
wacom_wac1->features =
|
||||||
*((struct wacom_features *)id->driver_data);
|
*((struct wacom_features *)id->driver_data);
|
||||||
wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PEN;
|
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_set_default_phy(&wacom_wac1->features);
|
||||||
wacom_calculate_res(&wacom_wac1->features);
|
wacom_calculate_res(&wacom_wac1->features);
|
||||||
snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen",
|
snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen",
|
||||||
wacom_wac1->features.name);
|
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",
|
snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",
|
||||||
wacom_wac1->features.name);
|
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->touch_max = wacom_wac1->features.touch_max;
|
||||||
wacom_wac1->shared->type = wacom_wac1->features.type;
|
wacom_wac1->shared->type = wacom_wac1->features.type;
|
||||||
wacom_wac1->pid = wacom_wac->pid;
|
wacom_wac1->pid = wacom_wac->pid;
|
||||||
|
@ -1566,7 +1569,8 @@ static void wacom_wireless_work(struct work_struct *work)
|
||||||
|
|
||||||
/* Touch interface */
|
/* Touch interface */
|
||||||
if (wacom_wac1->features.touch_max ||
|
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 =
|
wacom_wac2->features =
|
||||||
*((struct wacom_features *)id->driver_data);
|
*((struct wacom_features *)id->driver_data);
|
||||||
wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
|
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);
|
wacom_calculate_res(&wacom_wac2->features);
|
||||||
snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX,
|
snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX,
|
||||||
"%s (WL) Finger",wacom_wac2->features.name);
|
"%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)
|
if (wacom_wac1->features.touch_max)
|
||||||
wacom_wac2->features.device_type |= WACOM_DEVICETYPE_TOUCH;
|
wacom_wac2->features.device_type |= WACOM_DEVICETYPE_TOUCH;
|
||||||
if (wacom_wac1->features.type == INTUOSHT ||
|
if (wacom_wac1->features.type >= INTUOSHT &&
|
||||||
wacom_wac1->features.type == BAMBOO_PT)
|
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->features.device_type |= WACOM_DEVICETYPE_PAD;
|
||||||
|
}
|
||||||
wacom_wac2->pid = wacom_wac->pid;
|
wacom_wac2->pid = wacom_wac->pid;
|
||||||
error = wacom_allocate_inputs(wacom2) ||
|
error = wacom_allocate_inputs(wacom2) ||
|
||||||
wacom_register_inputs(wacom2);
|
wacom_register_inputs(wacom2);
|
||||||
if (error)
|
if (error)
|
||||||
goto fail;
|
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_wac1->features.touch_max)
|
||||||
wacom_wac->shared->touch_input = wacom_wac2->touch_input;
|
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 */
|
/* Note that if query fails it is not a hard failure */
|
||||||
wacom_query_tablet_data(hdev, features);
|
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)
|
if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
|
||||||
error = hid_hw_open(hdev);
|
error = hid_hw_open(hdev);
|
||||||
|
|
||||||
if (wacom_wac->features.type == INTUOSHT &&
|
if ((wacom_wac->features.type == INTUOSHT ||
|
||||||
wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) {
|
wacom_wac->features.type == INTUOSHT2) &&
|
||||||
|
(wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)) {
|
||||||
wacom_wac->shared->touch_input = wacom_wac->touch_input;
|
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 */
|
/* general pen packet */
|
||||||
if ((data[1] & 0xb8) == 0xa0) {
|
if ((data[1] & 0xb8) == 0xa0) {
|
||||||
t = (data[6] << 2) | ((data[7] >> 6) & 3);
|
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);
|
t = (t << 1) | (data[1] & 1);
|
||||||
}
|
}
|
||||||
input_report_abs(input, ABS_PRESSURE, t);
|
input_report_abs(input, ABS_PRESSURE, t);
|
||||||
|
if (features->type != INTUOSHT2) {
|
||||||
input_report_abs(input, ABS_TILT_X,
|
input_report_abs(input, ABS_TILT_X,
|
||||||
(((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
|
(((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_STYLUS, data[1] & 2);
|
||||||
input_report_key(input, BTN_STYLUS2, data[1] & 4);
|
input_report_key(input, BTN_STYLUS2, data[1] & 4);
|
||||||
input_report_key(input, BTN_TOUCH, t > 10);
|
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_INTUOSREAD &&
|
||||||
data[0] != WACOM_REPORT_INTUOSWRITE &&
|
data[0] != WACOM_REPORT_INTUOSWRITE &&
|
||||||
data[0] != WACOM_REPORT_INTUOSPAD &&
|
data[0] != WACOM_REPORT_INTUOSPAD &&
|
||||||
|
data[0] != WACOM_REPORT_INTUOS_PEN &&
|
||||||
data[0] != WACOM_REPORT_CINTIQ &&
|
data[0] != WACOM_REPORT_CINTIQ &&
|
||||||
data[0] != WACOM_REPORT_CINTIQPAD &&
|
data[0] != WACOM_REPORT_CINTIQPAD &&
|
||||||
data[0] != WACOM_REPORT_INTUOS5PAD) {
|
data[0] != WACOM_REPORT_INTUOS5PAD) {
|
||||||
|
@ -948,6 +951,27 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
||||||
} else {
|
} else {
|
||||||
input_report_abs(input, ABS_MISC, 0);
|
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) {
|
} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -1628,6 +1652,7 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
|
||||||
wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
|
wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
|
||||||
break;
|
break;
|
||||||
case HID_DG_CONTACTCOUNT:
|
case HID_DG_CONTACTCOUNT:
|
||||||
|
wacom_wac->hid_data.cc_report = field->report->id;
|
||||||
wacom_wac->hid_data.cc_index = field->index;
|
wacom_wac->hid_data.cc_index = field->index;
|
||||||
wacom_wac->hid_data.cc_value_index = usage->usage_index;
|
wacom_wac->hid_data.cc_value_index = usage->usage_index;
|
||||||
break;
|
break;
|
||||||
|
@ -1715,7 +1740,32 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
|
||||||
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
||||||
struct hid_data* hid_data = &wacom_wac->hid_data;
|
struct hid_data* hid_data = &wacom_wac->hid_data;
|
||||||
|
|
||||||
if (hid_data->cc_index >= 0) {
|
if (hid_data->cc_report != 0 &&
|
||||||
|
hid_data->cc_report != report->id) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
hid_data->cc_report = report->id;
|
||||||
|
hid_data->cc_index = -1;
|
||||||
|
hid_data->cc_value_index = -1;
|
||||||
|
|
||||||
|
for (i = 0; i < report->maxfield; i++) {
|
||||||
|
struct hid_field *field = report->field[i];
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < field->maxusage; j++) {
|
||||||
|
if (field->usage[j].hid == HID_DG_CONTACTCOUNT) {
|
||||||
|
hid_data->cc_index = i;
|
||||||
|
hid_data->cc_value_index = j;
|
||||||
|
|
||||||
|
/* break */
|
||||||
|
i = report->maxfield;
|
||||||
|
j = field->maxusage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hid_data->cc_report != 0 &&
|
||||||
|
hid_data->cc_index >= 0) {
|
||||||
struct hid_field *field = report->field[hid_data->cc_index];
|
struct hid_field *field = report->field[hid_data->cc_index];
|
||||||
int value = field->value[hid_data->cc_value_index];
|
int value = field->value[hid_data->cc_value_index];
|
||||||
if (value)
|
if (value)
|
||||||
|
@ -1896,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 y = (data[3] << 4) | (data[4] & 0x0f);
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
if (features->type >= INTUOSPS && features->type <= INTUOSHT) {
|
if (features->type >= INTUOSPS && features->type <= INTUOSHT2) {
|
||||||
width = data[5] * 100;
|
width = data[5] * 100;
|
||||||
height = data[6] * 100;
|
height = data[6] * 100;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1924,7 +1974,7 @@ static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
|
||||||
struct input_dev *input = wacom->pad_input;
|
struct input_dev *input = wacom->pad_input;
|
||||||
struct wacom_features *features = &wacom->features;
|
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_LEFT, (data[1] & 0x02) != 0);
|
||||||
input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0);
|
input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1939,7 +1989,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
|
||||||
{
|
{
|
||||||
unsigned char *data = wacom->data;
|
unsigned char *data = wacom->data;
|
||||||
int count = data[1] & 0x07;
|
int count = data[1] & 0x07;
|
||||||
int i;
|
int touch_changed = 0, i;
|
||||||
|
|
||||||
if (data[0] != 0x02)
|
if (data[0] != 0x02)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1949,15 +1999,16 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
|
||||||
int offset = (8 * i) + 2;
|
int offset = (8 * i) + 2;
|
||||||
int msg_id = data[offset];
|
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);
|
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);
|
wacom_bpt3_button_msg(wacom, data + offset);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only update the touch if we actually have a touchpad */
|
/* only update touch if we actually have a touchpad and touch data changed */
|
||||||
if (wacom->touch_registered) {
|
if (wacom->touch_registered && touch_changed) {
|
||||||
input_mt_sync_frame(wacom->touch_input);
|
input_mt_sync_frame(wacom->touch_input);
|
||||||
wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
|
wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
|
||||||
}
|
}
|
||||||
|
@ -2038,7 +2089,12 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
|
||||||
|
|
||||||
static int wacom_bpt_irq(struct wacom_wac *wacom, size_t len)
|
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);
|
return wacom_bpt_touch(wacom);
|
||||||
else if (len == WACOM_PKGLEN_BBTOUCH3)
|
else if (len == WACOM_PKGLEN_BBTOUCH3)
|
||||||
return wacom_bpt3_touch(wacom);
|
return wacom_bpt3_touch(wacom);
|
||||||
|
@ -2145,7 +2201,8 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
|
||||||
if (connected) {
|
if (connected) {
|
||||||
int pid, battery, charging;
|
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_input &&
|
||||||
wacom->shared->touch_max) {
|
wacom->shared->touch_max) {
|
||||||
input_report_switch(wacom->shared->touch_input,
|
input_report_switch(wacom->shared->touch_input,
|
||||||
|
@ -2183,7 +2240,8 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
|
||||||
if (data[0] != WACOM_REPORT_USB)
|
if (data[0] != WACOM_REPORT_USB)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (features->type == INTUOSHT &&
|
if ((features->type == INTUOSHT ||
|
||||||
|
features->type == INTUOSHT2) &&
|
||||||
wacom_wac->shared->touch_input &&
|
wacom_wac->shared->touch_input &&
|
||||||
features->touch_max) {
|
features->touch_max) {
|
||||||
input_report_switch(wacom_wac->shared->touch_input,
|
input_report_switch(wacom_wac->shared->touch_input,
|
||||||
|
@ -2264,6 +2322,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
||||||
case WACOM_27QHD:
|
case WACOM_27QHD:
|
||||||
case DTK:
|
case DTK:
|
||||||
case CINTIQ_HYBRID:
|
case CINTIQ_HYBRID:
|
||||||
|
case CINTIQ_COMPANION_2:
|
||||||
sync = wacom_intuos_irq(wacom_wac);
|
sync = wacom_intuos_irq(wacom_wac);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2300,7 +2359,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BAMBOO_PT:
|
case BAMBOO_PT:
|
||||||
|
case BAMBOO_PEN:
|
||||||
|
case BAMBOO_TOUCH:
|
||||||
case INTUOSHT:
|
case INTUOSHT:
|
||||||
|
case INTUOSHT2:
|
||||||
if (wacom_wac->data[0] == WACOM_REPORT_USB)
|
if (wacom_wac->data[0] == WACOM_REPORT_USB)
|
||||||
sync = wacom_status_irq(wacom_wac, len);
|
sync = wacom_status_irq(wacom_wac, len);
|
||||||
else
|
else
|
||||||
|
@ -2337,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;
|
struct input_dev *input_dev = wacom_wac->pen_input;
|
||||||
|
|
||||||
input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
|
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_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_STYLUS, input_dev->keybit);
|
||||||
__set_bit(BTN_STYLUS2, input_dev->keybit);
|
__set_bit(BTN_STYLUS2, input_dev->keybit);
|
||||||
|
|
||||||
input_set_abs_params(input_dev, ABS_DISTANCE,
|
input_set_abs_params(input_dev, ABS_DISTANCE,
|
||||||
0, wacom_wac->features.distance_max, 0, 0);
|
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_WHEEL, 0, 1023, 0, 0);
|
||||||
input_set_abs_params(input_dev, ABS_TILT_X, -64, 63, 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);
|
input_abs_set_res(input_dev, ABS_TILT_X, 57);
|
||||||
|
@ -2387,9 +2458,8 @@ void wacom_setup_device_quirks(struct wacom *wacom)
|
||||||
|
|
||||||
/* The pen and pad share the same interface on most devices */
|
/* The pen and pad share the same interface on most devices */
|
||||||
if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 ||
|
if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 ||
|
||||||
features->type == DTUS || features->type == WACOM_MO ||
|
features->type == DTUS ||
|
||||||
(features->type >= INTUOS3S && features->type <= WACOM_13HD &&
|
(features->type >= INTUOS3S && features->type <= WACOM_MO)) {
|
||||||
features->type != INTUOSHT)) {
|
|
||||||
if (features->device_type & WACOM_DEVICETYPE_PEN)
|
if (features->device_type & WACOM_DEVICETYPE_PEN)
|
||||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||||
}
|
}
|
||||||
|
@ -2406,12 +2476,12 @@ void wacom_setup_device_quirks(struct wacom *wacom)
|
||||||
* interface (PacketSize of WACOM_PKGLEN_BBTOUCH3), override the
|
* interface (PacketSize of WACOM_PKGLEN_BBTOUCH3), override the
|
||||||
* tablet values.
|
* tablet values.
|
||||||
*/
|
*/
|
||||||
if ((features->type >= INTUOS5S && features->type <= INTUOSHT) ||
|
if ((features->type >= INTUOS5S && features->type <= INTUOSPL) ||
|
||||||
(features->type == BAMBOO_PT)) {
|
(features->type >= INTUOSHT && features->type <= BAMBOO_PT)) {
|
||||||
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
|
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
|
||||||
if (features->touch_max)
|
if (features->touch_max)
|
||||||
features->device_type |= WACOM_DEVICETYPE_TOUCH;
|
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->device_type |= WACOM_DEVICETYPE_PAD;
|
||||||
|
|
||||||
features->x_max = 4096;
|
features->x_max = 4096;
|
||||||
|
@ -2520,6 +2590,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
|
||||||
case CINTIQ:
|
case CINTIQ:
|
||||||
case WACOM_13HD:
|
case WACOM_13HD:
|
||||||
case CINTIQ_HYBRID:
|
case CINTIQ_HYBRID:
|
||||||
|
case CINTIQ_COMPANION_2:
|
||||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||||
input_abs_set_res(input_dev, ABS_Z, 287);
|
input_abs_set_res(input_dev, ABS_Z, 287);
|
||||||
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
|
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
|
||||||
|
@ -2598,16 +2669,22 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
|
||||||
|
|
||||||
case INTUOSHT:
|
case INTUOSHT:
|
||||||
case BAMBOO_PT:
|
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(INPUT_PROP_POINTER, input_dev->propbit);
|
||||||
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
|
|
||||||
|
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_PEN, input_dev->keybit);
|
||||||
|
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
|
||||||
__set_bit(BTN_STYLUS, input_dev->keybit);
|
__set_bit(BTN_STYLUS, input_dev->keybit);
|
||||||
__set_bit(BTN_STYLUS2, input_dev->keybit);
|
__set_bit(BTN_STYLUS2, input_dev->keybit);
|
||||||
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
|
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
|
||||||
features->distance_max,
|
features->distance_max,
|
||||||
0, 0);
|
0, 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case BAMBOO_PAD:
|
case BAMBOO_PAD:
|
||||||
__clear_bit(ABS_MISC, input_dev->absbit);
|
__clear_bit(ABS_MISC, input_dev->absbit);
|
||||||
|
@ -2688,11 +2765,13 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INTUOSHT:
|
case INTUOSHT:
|
||||||
|
case INTUOSHT2:
|
||||||
input_dev->evbit[0] |= BIT_MASK(EV_SW);
|
input_dev->evbit[0] |= BIT_MASK(EV_SW);
|
||||||
__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
|
__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
|
||||||
case BAMBOO_PT:
|
case BAMBOO_PT:
|
||||||
|
case BAMBOO_TOUCH:
|
||||||
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
|
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
|
||||||
input_set_abs_params(input_dev,
|
input_set_abs_params(input_dev,
|
||||||
ABS_MT_TOUCH_MAJOR,
|
ABS_MT_TOUCH_MAJOR,
|
||||||
|
@ -2752,6 +2831,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
|
||||||
switch (features->type) {
|
switch (features->type) {
|
||||||
|
|
||||||
case CINTIQ_HYBRID:
|
case CINTIQ_HYBRID:
|
||||||
|
case CINTIQ_COMPANION_2:
|
||||||
case DTK:
|
case DTK:
|
||||||
case DTUS:
|
case DTUS:
|
||||||
case GRAPHIRE_BT:
|
case GRAPHIRE_BT:
|
||||||
|
@ -2845,6 +2925,8 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
|
||||||
|
|
||||||
case INTUOSHT:
|
case INTUOSHT:
|
||||||
case BAMBOO_PT:
|
case BAMBOO_PT:
|
||||||
|
case BAMBOO_TOUCH:
|
||||||
|
case INTUOSHT2:
|
||||||
__clear_bit(ABS_MISC, input_dev->absbit);
|
__clear_bit(ABS_MISC, input_dev->absbit);
|
||||||
|
|
||||||
__set_bit(BTN_LEFT, input_dev->keybit);
|
__set_bit(BTN_LEFT, input_dev->keybit);
|
||||||
|
@ -3235,11 +3317,10 @@ static const struct wacom_features wacom_features_0x47 =
|
||||||
{ "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
|
{ "Wacom Intuos2 6x8", 20320, 16240, 1023, 31,
|
||||||
INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||||
static const struct wacom_features wacom_features_0x84 =
|
static const struct wacom_features wacom_features_0x84 =
|
||||||
{ "Wacom Wireless Receiver", 0, 0, 0, 0,
|
{ "Wacom Wireless Receiver", .type = WIRELESS, .touch_max = 16 };
|
||||||
WIRELESS, 0, 0, .touch_max = 16 };
|
|
||||||
static const struct wacom_features wacom_features_0xD0 =
|
static const struct wacom_features wacom_features_0xD0 =
|
||||||
{ "Wacom Bamboo 2FG", 14720, 9200, 1023, 31,
|
{ "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 =
|
static const struct wacom_features wacom_features_0xD1 =
|
||||||
{ "Wacom Bamboo 2FG 4x5", 14720, 9200, 1023, 31,
|
{ "Wacom Bamboo 2FG 4x5", 14720, 9200, 1023, 31,
|
||||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
||||||
|
@ -3251,10 +3332,10 @@ static const struct wacom_features wacom_features_0xD3 =
|
||||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
||||||
static const struct wacom_features wacom_features_0xD4 =
|
static const struct wacom_features wacom_features_0xD4 =
|
||||||
{ "Wacom Bamboo Pen", 14720, 9200, 1023, 31,
|
{ "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 =
|
static const struct wacom_features wacom_features_0xD5 =
|
||||||
{ "Wacom Bamboo Pen 6x8", 21648, 13700, 1023, 31,
|
{ "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 =
|
static const struct wacom_features wacom_features_0xD6 =
|
||||||
{ "Wacom BambooPT 2FG 4x5", 14720, 9200, 1023, 31,
|
{ "Wacom BambooPT 2FG 4x5", 14720, 9200, 1023, 31,
|
||||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 2 };
|
||||||
|
@ -3281,7 +3362,7 @@ static const struct wacom_features wacom_features_0xDF =
|
||||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
|
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16 };
|
||||||
static const struct wacom_features wacom_features_0x300 =
|
static const struct wacom_features wacom_features_0x300 =
|
||||||
{ "Wacom Bamboo One S", 14720, 9225, 1023, 31,
|
{ "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 =
|
static const struct wacom_features wacom_features_0x301 =
|
||||||
{ "Wacom Bamboo One M", 21648, 13530, 1023, 31,
|
{ "Wacom Bamboo One M", 21648, 13530, 1023, 31,
|
||||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||||
|
@ -3324,14 +3405,38 @@ static const struct wacom_features wacom_features_0x318 =
|
||||||
static const struct wacom_features wacom_features_0x319 =
|
static const struct wacom_features wacom_features_0x319 =
|
||||||
{ "Wacom Wireless Bamboo PAD", 4095, 4095, /* Touch */
|
{ "Wacom Wireless Bamboo PAD", 4095, 4095, /* Touch */
|
||||||
.type = BAMBOO_PAD, 35, 48, .touch_max = 4 };
|
.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 =
|
static const struct wacom_features wacom_features_0x323 =
|
||||||
{ "Wacom Intuos P M", 21600, 13500, 1023, 31,
|
{ "Wacom Intuos P M", 21600, 13500, 1023, 31,
|
||||||
INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
|
INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
|
||||||
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
|
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
|
||||||
static const struct wacom_features wacom_features_0x331 =
|
static const struct wacom_features wacom_features_0x331 =
|
||||||
{ "Wacom Express Key Remote", 0, 0, 0, 0,
|
{ "Wacom Express Key Remote", .type = REMOTE,
|
||||||
REMOTE, 0, 0, 18, .check_for_hid_type = true,
|
.numbered_buttons = 18, .check_for_hid_type = true,
|
||||||
.hid_type = HID_TYPE_USBNONE };
|
.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 =
|
static const struct wacom_features wacom_features_HID_ANY_ID =
|
||||||
{ "Wacom HID", .type = HID_GENERIC };
|
{ "Wacom HID", .type = HID_GENERIC };
|
||||||
|
@ -3483,6 +3588,8 @@ const struct hid_device_id wacom_ids[] = {
|
||||||
{ USB_DEVICE_WACOM(0x318) },
|
{ USB_DEVICE_WACOM(0x318) },
|
||||||
{ USB_DEVICE_WACOM(0x319) },
|
{ USB_DEVICE_WACOM(0x319) },
|
||||||
{ USB_DEVICE_WACOM(0x323) },
|
{ USB_DEVICE_WACOM(0x323) },
|
||||||
|
{ USB_DEVICE_WACOM(0x325) },
|
||||||
|
{ USB_DEVICE_WACOM(0x326) },
|
||||||
{ USB_DEVICE_WACOM(0x32A) },
|
{ USB_DEVICE_WACOM(0x32A) },
|
||||||
{ USB_DEVICE_WACOM(0x32B) },
|
{ USB_DEVICE_WACOM(0x32B) },
|
||||||
{ USB_DEVICE_WACOM(0x32C) },
|
{ USB_DEVICE_WACOM(0x32C) },
|
||||||
|
@ -3491,6 +3598,10 @@ const struct hid_device_id wacom_ids[] = {
|
||||||
{ USB_DEVICE_WACOM(0x333) },
|
{ USB_DEVICE_WACOM(0x333) },
|
||||||
{ USB_DEVICE_WACOM(0x335) },
|
{ USB_DEVICE_WACOM(0x335) },
|
||||||
{ USB_DEVICE_WACOM(0x336) },
|
{ 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(0x4001) },
|
||||||
{ USB_DEVICE_WACOM(0x4004) },
|
{ USB_DEVICE_WACOM(0x4004) },
|
||||||
{ USB_DEVICE_WACOM(0x5000) },
|
{ USB_DEVICE_WACOM(0x5000) },
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
#define WACOM_REPORT_BPAD_PEN 3
|
#define WACOM_REPORT_BPAD_PEN 3
|
||||||
#define WACOM_REPORT_BPAD_TOUCH 16
|
#define WACOM_REPORT_BPAD_TOUCH 16
|
||||||
#define WACOM_REPORT_DEVICE_LIST 16
|
#define WACOM_REPORT_DEVICE_LIST 16
|
||||||
|
#define WACOM_REPORT_INTUOS_PEN 16
|
||||||
#define WACOM_REPORT_REMOTE 17
|
#define WACOM_REPORT_REMOTE 17
|
||||||
|
|
||||||
/* device quirks */
|
/* device quirks */
|
||||||
|
@ -117,22 +118,26 @@ enum {
|
||||||
INTUOSPS,
|
INTUOSPS,
|
||||||
INTUOSPM,
|
INTUOSPM,
|
||||||
INTUOSPL,
|
INTUOSPL,
|
||||||
INTUOSHT,
|
|
||||||
WACOM_21UX2,
|
WACOM_21UX2,
|
||||||
WACOM_22HD,
|
WACOM_22HD,
|
||||||
DTK,
|
DTK,
|
||||||
WACOM_24HD,
|
WACOM_24HD,
|
||||||
WACOM_27QHD,
|
WACOM_27QHD,
|
||||||
CINTIQ_HYBRID,
|
CINTIQ_HYBRID,
|
||||||
|
CINTIQ_COMPANION_2,
|
||||||
CINTIQ,
|
CINTIQ,
|
||||||
WACOM_BEE,
|
WACOM_BEE,
|
||||||
WACOM_13HD,
|
WACOM_13HD,
|
||||||
WACOM_MO,
|
WACOM_MO,
|
||||||
WIRELESS,
|
BAMBOO_PEN,
|
||||||
|
INTUOSHT,
|
||||||
|
INTUOSHT2,
|
||||||
|
BAMBOO_TOUCH,
|
||||||
BAMBOO_PT,
|
BAMBOO_PT,
|
||||||
WACOM_24HDT,
|
WACOM_24HDT,
|
||||||
WACOM_27QHDT,
|
WACOM_27QHDT,
|
||||||
BAMBOO_PAD,
|
BAMBOO_PAD,
|
||||||
|
WIRELESS,
|
||||||
REMOTE,
|
REMOTE,
|
||||||
TABLETPC, /* add new TPC below */
|
TABLETPC, /* add new TPC below */
|
||||||
TABLETPCE,
|
TABLETPCE,
|
||||||
|
@ -198,6 +203,7 @@ struct hid_data {
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int id;
|
int id;
|
||||||
|
int cc_report;
|
||||||
int cc_index;
|
int cc_index;
|
||||||
int cc_value_index;
|
int cc_value_index;
|
||||||
int num_expected;
|
int num_expected;
|
||||||
|
|
Loading…
Reference in a new issue