Commit e0da5c9a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID updates from Jiri Kosina:
 - i2c-hid is not querying init reports any more, as it's not mandated
   by the spec, and annoys quite a few devices during enumeration, by
   Bibek Basu
 - a lot of fixes for Logitech devices, by Simon Wood
 - hid-apple now has an option to switch between Option and Command
   mode, by Nanno Langstraat
 - Some more workarounds for severely broken ELO devices, by Oliver
   Neukum
 - more devm conversions, by Benjamin Tissoires
 - wiimote correctness fixes, by David Herrmann
 - a lot of added support for various new device IDs and random small
   fixes here and there"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (34 commits)
  HID: enable Mayflash USB Gamecube Adapter
  HID: sony: Add force feedback support for Dualshock3 USB
  Input: usbtouchscreen: ignore eGalax/D-Wav/EETI HIDs
  HID: don't ignore eGalax/D-Wav/EETI HIDs
  HID: roccat: add missing special driver declarations
  HID:hid-lg4ff: Correct Auto-center strength for wheels other than MOMO and MOMO2
  HID:hid-lg4ff: Initialize device properties before we touch autocentering.
  HID:hid-lg4ff: ensure ConstantForce is disabled when set to 0
  HID:hid-lg4ff: Switch autocentering off when strength is set to zero.
  HID:hid-lg4ff: Scale autocentering force properly on Logitech wheel
  HID: roccat: fix Coverity CID 141438
  HID: multitouch: add manufacturer to Kconfig help text
  HID: logitech-dj: small cleanup in rdcat()
  HID: remove self-assignment from hid_input_report
  HID: hid-sensor-hub: fix report size
  HID: i2c-hid: Stop querying for init reports
  HID: roccat: add support for Ryos MK keyboards
  HID: roccat: generalize some common code
  HID: roccat: add new device return value
  HID: wiimote: add pro-controller analog stick calibration
  ...
parents 9073e1a8 7f9cc24a
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/control
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one select which data from which
profile will be read next. The data has to be 3 bytes long.
This file is writeonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/profile
Date: October 2013
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. profile holds index of actual profile.
This value is persistent, so its value determines the profile
that's active when the device is powered on next time.
When written, the device activates the set profile immediately.
The data has to be 3 bytes long.
The device 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>/ryos/roccatryos<minor>/keys_primary
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the default of all keys for
a specific profile. Profile index is included in written data.
The data has to be 125 bytes long.
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>/ryos/roccatryos<minor>/keys_function
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the
function keys for a specific profile. Profile index is included
in written data. The data has to be 95 bytes long.
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>/ryos/roccatryos<minor>/keys_macro
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the macro
keys for a specific profile. Profile index is included in
written data. The data has to be 35 bytes long.
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>/ryos/roccatryos<minor>/keys_thumbster
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the
thumbster keys for a specific profile. Profile index is included
in written data. The data has to be 23 bytes long.
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>/ryos/roccatryos<minor>/keys_extra
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the
capslock and function keys for a specific profile. Profile index
is included in written data. The data has to be 8 bytes long.
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>/ryos/roccatryos<minor>/keys_easyzone
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the
easyzone keys for a specific profile. Profile index is included
in written data. The data has to be 294 bytes long.
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>/ryos/roccatryos<minor>/key_mask
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one deactivate certain keys like
windows and application keys, to prevent accidental presses.
Profile index for which this settings occur is included in
written data. The data has to be 6 bytes long.
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>/ryos/roccatryos<minor>/light
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the backlight intensity for
a specific profile. Profile index is included in written data.
This attribute is only valid for the glow and pro variant.
The data has to be 16 bytes long.
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>/ryos/roccatryos<minor>/macro
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one store macros with max 480
keystrokes for a specific button for a specific profile.
Button and profile indexes are included in written data.
The data has to be 2002 bytes long.
Before reading this file, control has to be written to select
which profile and key 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>/ryos/roccatryos<minor>/info
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns general data like firmware version.
The data is 8 bytes long.
This file is readonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/reset
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one reset the device.
The data has to be 3 bytes long.
This file is writeonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/ryos/roccatryos<minor>/talk
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one trigger easyshift functionality
from the host.
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>/ryos/roccatryos<minor>/light_control
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one switch between stored and custom
light settings.
This attribute is only valid for the pro variant.
The data has to be 8 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>/ryos/roccatryos<minor>/stored_lights
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set per-key lighting for different
layers.
This attribute is only valid for the pro variant.
The data has to be 1382 bytes long.
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>/ryos/roccatryos<minor>/custom_lights
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the actual per-key lighting.
This attribute is only valid for the pro variant.
The data has to be 20 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>/ryos/roccatryos<minor>/light_macro
Date: October 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set a light macro that is looped
whenever the device gets in dimness mode.
This attribute is only valid for the pro variant.
The data has to be 2002 bytes long.
Before reading this file, control has to be written to select
which profile to read.
Users: http://roccat.sourceforge.net
...@@ -57,3 +57,21 @@ Description: This attribute is only provided if the device was detected as a ...@@ -57,3 +57,21 @@ Description: This attribute is only provided if the device was detected as a
Calibration data is already applied by the kernel to all input Calibration data is already applied by the kernel to all input
values but may be used by user-space to perform other values but may be used by user-space to perform other
transformations. transformations.
What: /sys/bus/hid/drivers/wiimote/<dev>/pro_calib
Date: October 2013
KernelVersion: 3.13
Contact: David Herrmann <dh.herrmann@gmail.com>
Description: This attribute is only provided if the device was detected as a
pro-controller. It provides a single line with 4 calibration
values for all 4 analog sticks. Format is: "x1:y1 x2:y2". Data
is prefixed with a +/-. Each value is a signed 16bit number.
Data is encoded as decimal numbers and specifies the offsets of
the analog sticks of the pro-controller.
Calibration data is already applied by the kernel to all input
values but may be used by user-space to perform other
transformations.
Calibration data is detected by the kernel during device setup.
You can write "scan\n" into this file to re-trigger calibration.
You can also write data directly in the form "x1:y1 x2:y2" to
set the calibration values manually.
...@@ -242,6 +242,7 @@ config HID_HOLTEK ...@@ -242,6 +242,7 @@ config HID_HOLTEK
- Tracer Sniper TRM-503 / NOVA Gaming Slider X200 / - Tracer Sniper TRM-503 / NOVA Gaming Slider X200 /
Zalman ZM-GM1 Zalman ZM-GM1
- SHARKOON DarkGlider Gaming mouse - SHARKOON DarkGlider Gaming mouse
- LEETGION Hellion Gaming Mouse
config HOLTEK_FF config HOLTEK_FF
bool "Holtek On Line Grip force feedback support" bool "Holtek On Line Grip force feedback support"
...@@ -323,7 +324,7 @@ config HID_LCPOWER ...@@ -323,7 +324,7 @@ config HID_LCPOWER
config HID_LENOVO_TPKBD config HID_LENOVO_TPKBD
tristate "Lenovo ThinkPad USB Keyboard with TrackPoint" tristate "Lenovo ThinkPad USB Keyboard with TrackPoint"
depends on USB_HID depends on HID
select NEW_LEDS select NEW_LEDS
select LEDS_CLASS select LEDS_CLASS
---help--- ---help---
...@@ -362,19 +363,20 @@ config LOGITECH_FF ...@@ -362,19 +363,20 @@ config LOGITECH_FF
- Logitech WingMan Force 3D - Logitech WingMan Force 3D
- Logitech Formula Force EX - Logitech Formula Force EX
- Logitech WingMan Formula Force GP - Logitech WingMan Formula Force GP
- Logitech MOMO Force wheel
and if you want to enable force feedback for them. and if you want to enable force feedback for them.
Note: if you say N here, this device will still be supported, but without Note: if you say N here, this device will still be supported, but without
force feedback. force feedback.
config LOGIRUMBLEPAD2_FF config LOGIRUMBLEPAD2_FF
bool "Logitech RumblePad/Rumblepad 2 force feedback support" bool "Logitech force feedback support (variant 2)"
depends on HID_LOGITECH depends on HID_LOGITECH
select INPUT_FF_MEMLESS select INPUT_FF_MEMLESS
help help
Say Y here if you want to enable force feedback support for Logitech Say Y here if you want to enable force feedback support for:
RumblePad and Rumblepad 2 devices. - Logitech RumblePad
- Logitech Rumblepad 2
- Logitech Formula Vibration Feedback Wheel
config LOGIG940_FF config LOGIG940_FF
bool "Logitech Flight System G940 force feedback support" bool "Logitech Flight System G940 force feedback support"
...@@ -437,6 +439,7 @@ config HID_MULTITOUCH ...@@ -437,6 +439,7 @@ config HID_MULTITOUCH
- Chunghwa panels - Chunghwa panels
- CVTouch panels - CVTouch panels
- Cypress TrueTouch panels - Cypress TrueTouch panels
- Elan Microelectronics touch panels
- Elo TouchSystems IntelliTouch Plus panels - Elo TouchSystems IntelliTouch Plus panels
- GeneralTouch 'Sensing Win7-TwoFinger' panels - GeneralTouch 'Sensing Win7-TwoFinger' panels
- GoodTouch panels - GoodTouch panels
...@@ -453,6 +456,7 @@ config HID_MULTITOUCH ...@@ -453,6 +456,7 @@ config HID_MULTITOUCH
- Pixcir dual touch panels - Pixcir dual touch panels
- Quanta panels - Quanta panels
- eGalax dual-touch panels, including the Joojoo and Wetab tablets - eGalax dual-touch panels, including the Joojoo and Wetab tablets
- SiS multitouch panels
- Stantum multitouch panels - Stantum multitouch panels
- Touch International Panels - Touch International Panels
- Unitec Panels - Unitec Panels
...@@ -614,6 +618,14 @@ config HID_SONY ...@@ -614,6 +618,14 @@ config HID_SONY
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth) * Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
* Logitech Harmony adapter for Sony Playstation 3 (Bluetooth) * Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
config SONY_FF
bool "Sony PS2/3 accessories force feedback support"
depends on HID_SONY
select INPUT_FF_MEMLESS
---help---
Say Y here if you have a Sony PS2/3 accessory and want to enable force
feedback support for it.
config HID_SPEEDLINK config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support" tristate "Speedlink VAD Cezanne mouse support"
depends on HID depends on HID
......
...@@ -95,7 +95,7 @@ obj-$(CONFIG_HID_PRIMAX) += hid-primax.o ...@@ -95,7 +95,7 @@ obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \ hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \ hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \
hid-roccat-lua.o hid-roccat-pyra.o hid-roccat-savu.o hid-roccat-lua.o hid-roccat-pyra.o hid-roccat-ryos.o hid-roccat-savu.o
obj-$(CONFIG_HID_SAITEK) += hid-saitek.o obj-$(CONFIG_HID_SAITEK) += hid-saitek.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
......
...@@ -46,6 +46,12 @@ module_param(iso_layout, uint, 0644); ...@@ -46,6 +46,12 @@ module_param(iso_layout, uint, 0644);
MODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. " MODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. "
"(0 = disabled, [1] = enabled)"); "(0 = disabled, [1] = enabled)");
static unsigned int swap_opt_cmd;
module_param(swap_opt_cmd, uint, 0644);
MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\") keys. "
"(For people who want to keep Windows PC keyboard muscle memory. "
"[0] = as-is, Mac layout. 1 = swapped, Windows layout.)");
struct apple_sc { struct apple_sc {
unsigned long quirks; unsigned long quirks;
unsigned int fn_on; unsigned int fn_on;
...@@ -150,6 +156,14 @@ static const struct apple_key_translation apple_iso_keyboard[] = { ...@@ -150,6 +156,14 @@ static const struct apple_key_translation apple_iso_keyboard[] = {
{ } { }
}; };
static const struct apple_key_translation swapped_option_cmd_keys[] = {
{ KEY_LEFTALT, KEY_LEFTMETA },
{ KEY_LEFTMETA, KEY_LEFTALT },
{ KEY_RIGHTALT, KEY_RIGHTMETA },
{ KEY_RIGHTMETA,KEY_RIGHTALT },
{ }
};
static const struct apple_key_translation *apple_find_translation( static const struct apple_key_translation *apple_find_translation(
const struct apple_key_translation *table, u16 from) const struct apple_key_translation *table, u16 from)
{ {
...@@ -242,6 +256,14 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, ...@@ -242,6 +256,14 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
} }
} }
if (swap_opt_cmd) {
trans = apple_find_translation(swapped_option_cmd_keys, usage->code);
if (trans) {
input_event(input, usage->type, trans->to, value);
return 1;
}
}
return 0; return 0;
} }
......
...@@ -95,7 +95,7 @@ static int axff_init(struct hid_device *hid) ...@@ -95,7 +95,7 @@ static int axff_init(struct hid_device *hid)
} }
} }
if (field_count < 4) { if (field_count < 4 && hid->product != 0xf705) {
hid_err(hid, "not enough fields in the report: %d\n", hid_err(hid, "not enough fields in the report: %d\n",
field_count); field_count);
return -ENODEV; return -ENODEV;
...@@ -180,6 +180,7 @@ static void ax_remove(struct hid_device *hdev) ...@@ -180,6 +180,7 @@ static void ax_remove(struct hid_device *hdev)
static const struct hid_device_id ax_devices[] = { static const struct hid_device_id ax_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), }, { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705), },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, ax_devices); MODULE_DEVICE_TABLE(hid, ax_devices);
......
...@@ -1418,10 +1418,8 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i ...@@ -1418,10 +1418,8 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
ret = hdrv->raw_event(hid, report, data, size); ret = hdrv->raw_event(hid, report, data, size);
if (ret < 0) { if (ret < 0)
ret = ret < 0 ? ret : 0;
goto unlock; goto unlock;
}
} }
ret = hid_report_raw_event(hid, type, data, size, interrupt); ret = hid_report_raw_event(hid, type, data, size, interrupt);
...@@ -1605,6 +1603,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1605,6 +1603,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
...@@ -1716,6 +1715,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1716,6 +1715,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) }, { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
{ HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
...@@ -1754,6 +1754,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1754,6 +1754,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
...@@ -1801,21 +1802,28 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1801,21 +1802,28 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
#if IS_ENABLED(CONFIG_HID_ROCCAT) #if IS_ENABLED(CONFIG_HID_ROCCAT)
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKUFX) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEXTD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_GLOW) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
#endif #endif
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, USB_DEVICE_ID_SIS817_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) },
...@@ -2376,15 +2384,6 @@ bool hid_ignore(struct hid_device *hdev) ...@@ -2376,15 +2384,6 @@ bool hid_ignore(struct hid_device *hdev)
hdev->type == HID_TYPE_USBNONE) hdev->type == HID_TYPE_USBNONE)
return true; return true;
break; break;
case USB_VENDOR_ID_DWAV:
/* These are handled by usbtouchscreen. hdev->type is probably
* HID_TYPE_USBNONE, but we say !HID_TYPE_USBMOUSE to match
* usbtouchscreen. */
if ((hdev->product == USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER ||
hdev->product == USB_DEVICE_ID_DWAV_TOUCHCONTROLLER) &&
hdev->type != HID_TYPE_USBMOUSE)
return true;
break;
case USB_VENDOR_ID_VELLEMAN: case USB_VENDOR_ID_VELLEMAN:
/* These are not HID devices. They are handled by comedi. */ /* These are not HID devices. They are handled by comedi. */
if ((hdev->product >= USB_DEVICE_ID_VELLEMAN_K8055_FIRST && if ((hdev->product >= USB_DEVICE_ID_VELLEMAN_K8055_FIRST &&
......
...@@ -181,7 +181,40 @@ static void elo_work(struct work_struct *work) ...@@ -181,7 +181,40 @@ static void elo_work(struct work_struct *work)
*/ */
static bool elo_broken_firmware(struct usb_device *dev) static bool elo_broken_firmware(struct usb_device *dev)
{ {
return use_fw_quirk && le16_to_cpu(dev->descriptor.bcdDevice) == 0x10d; struct usb_device *hub = dev->parent;
struct usb_device *child = NULL;
u16 fw_lvl = le16_to_cpu(dev->descriptor.bcdDevice);
u16 child_vid, child_pid;
int i;
if (!use_fw_quirk)
return false;
if (fw_lvl != 0x10d)
return false;
/* iterate sibling devices of the touch controller */
usb_hub_for_each_child(hub, i, child) {
child_vid = le16_to_cpu(child->descriptor.idVendor);
child_pid = le16_to_cpu(child->descriptor.idProduct);
/*
* If one of the devices below is present attached as a sibling of
* the touch controller then this is a newer IBM 4820 monitor that
* does not need the IBM-requested workaround if fw level is
* 0x010d - aka 'M'.
* No other HW can have this combination.
*/
if (child_vid==0x04b3) {
switch (child_pid) {
case 0x4676: /* 4820 21x Video */
case 0x4677: /* 4820 51x Video */
case 0x4678: /* 4820 2Lx Video */
case 0x4679: /* 4820 5Lx Video */
return false;
}
}
}
return true;
} }
static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id) static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
* - USB ID 04d9:a04a, sold as Tracer Sniper TRM-503, NOVA Gaming Slider X200 * - USB ID 04d9:a04a, sold as Tracer Sniper TRM-503, NOVA Gaming Slider X200
* and Zalman ZM-GM1 * and Zalman ZM-GM1
* - USB ID 04d9:a081, sold as SHARKOON DarkGlider Gaming mouse * - USB ID 04d9:a081, sold as SHARKOON DarkGlider Gaming mouse
* - USB ID 04d9:a072, sold as LEETGION Hellion Gaming Mouse
*/ */
static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
...@@ -40,6 +41,7 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -40,6 +41,7 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
* 0x2fff, so they don't exceed HID_MAX_USAGES */ * 0x2fff, so they don't exceed HID_MAX_USAGES */
switch (hdev->product) { switch (hdev->product) {
case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067: case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067:
case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072:
if (*rsize >= 122 && rdesc[115] == 0xff && rdesc[116] == 0x7f if (*rsize >= 122 && rdesc[115] == 0xff && rdesc[116] == 0x7f
&& rdesc[120] == 0xff && rdesc[121] == 0x7f) { && rdesc[120] == 0xff && rdesc[121] == 0x7f) {
hid_info(hdev, "Fixing up report descriptor\n"); hid_info(hdev, "Fixing up report descriptor\n");
...@@ -65,6 +67,8 @@ static const struct hid_device_id holtek_mouse_devices[] = { ...@@ -65,6 +67,8 @@ static const struct hid_device_id holtek_mouse_devices[] = {
USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) }, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) }, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) }, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
{ } { }
......
...@@ -332,6 +332,11 @@ ...@@ -332,6 +332,11 @@
#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc
#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003 #define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003
#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS 0x0100 #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS 0x0100
#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0101 0x0101
#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0102 0x0102
#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0106 0x0106
#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A 0x010a
#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100 0xe100
#define USB_VENDOR_ID_GLAB 0x06c2 #define USB_VENDOR_ID_GLAB 0x06c2
#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
...@@ -448,8 +453,9 @@ ...@@ -448,8 +453,9 @@
#define USB_VENDOR_ID_HOLTEK_ALT 0x04d9 #define USB_VENDOR_ID_HOLTEK_ALT 0x04d9
#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055 #define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067 0xa067
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A 0xa04a #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A 0xa04a
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067 0xa067
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072 0xa072
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081 0xa081 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081 0xa081
#define USB_VENDOR_ID_IMATION 0x0718 #define USB_VENDOR_ID_IMATION 0x0718
...@@ -571,6 +577,7 @@ ...@@ -571,6 +577,7 @@
#define USB_DEVICE_ID_DINOVO_EDGE 0xc714 #define USB_DEVICE_ID_DINOVO_EDGE 0xc714
#define USB_DEVICE_ID_DINOVO_MINI 0xc71f #define USB_DEVICE_ID_DINOVO_MINI 0xc71f
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03
#define USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL 0xca04
#define USB_VENDOR_ID_LUMIO 0x202e #define USB_VENDOR_ID_LUMIO 0x202e
#define USB_DEVICE_ID_CRYSTALTOUCH 0x0006 #define USB_DEVICE_ID_CRYSTALTOUCH 0x0006
...@@ -726,6 +733,9 @@ ...@@ -726,6 +733,9 @@
#define USB_DEVICE_ID_ROCCAT_LUA 0x2c2e #define USB_DEVICE_ID_ROCCAT_LUA 0x2c2e
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24 #define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6 #define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
#define USB_DEVICE_ID_ROCCAT_RYOS_MK 0x3138
#define USB_DEVICE_ID_ROCCAT_RYOS_MK_GLOW 0x31ce
#define USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO 0x3232
#define USB_DEVICE_ID_ROCCAT_SAVU 0x2d5a #define USB_DEVICE_ID_ROCCAT_SAVU 0x2d5a
#define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_VENDOR_ID_SAITEK 0x06a3
...@@ -745,6 +755,10 @@ ...@@ -745,6 +755,10 @@
#define USB_VENDOR_ID_SIGMATEL 0x066F #define USB_VENDOR_ID_SIGMATEL 0x066F
#define USB_DEVICE_ID_SIGMATEL_STMP3780 0x3780 #define USB_DEVICE_ID_SIGMATEL_STMP3780 0x3780
#define USB_VENDOR_ID_SIS2_TOUCH 0x0457
#define USB_DEVICE_ID_SIS9200_TOUCH 0x9200
#define USB_DEVICE_ID_SIS817_TOUCH 0x0817
#define USB_VENDOR_ID_SKYCABLE 0x1223 #define USB_VENDOR_ID_SKYCABLE 0x1223
#define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07 #define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07
......
...@@ -14,11 +14,9 @@ ...@@ -14,11 +14,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/usb.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/leds.h> #include <linux/leds.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h" #include "hid-ids.h"
...@@ -41,10 +39,9 @@ static int tpkbd_input_mapping(struct hid_device *hdev, ...@@ -41,10 +39,9 @@ static int tpkbd_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field, struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max) struct hid_usage *usage, unsigned long **bit, int *max)
{ {
struct usbhid_device *uhdev; if (usage->hid == (HID_UP_BUTTON | 0x0010)) {
/* mark the device as pointer */
uhdev = (struct usbhid_device *) hdev->driver_data; hid_set_drvdata(hdev, (void *)1);
if (uhdev->ifnum == 1 && usage->hid == (HID_UP_BUTTON | 0x0010)) {
map_key_clear(KEY_MICMUTE); map_key_clear(KEY_MICMUTE);
return 1; return 1;
} }
...@@ -339,7 +336,7 @@ static int tpkbd_probe_tp(struct hid_device *hdev) ...@@ -339,7 +336,7 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
struct tpkbd_data_pointer *data_pointer; struct tpkbd_data_pointer *data_pointer;
size_t name_sz = strlen(dev_name(dev)) + 16; size_t name_sz = strlen(dev_name(dev)) + 16;
char *name_mute, *name_micmute; char *name_mute, *name_micmute;
int i, ret; int i;
/* Validate required reports. */ /* Validate required reports. */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
...@@ -354,7 +351,9 @@ static int tpkbd_probe_tp(struct hid_device *hdev) ...@@ -354,7 +351,9 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
hid_warn(hdev, "Could not create sysfs group\n"); hid_warn(hdev, "Could not create sysfs group\n");
} }
data_pointer = kzalloc(sizeof(struct tpkbd_data_pointer), GFP_KERNEL); data_pointer = devm_kzalloc(&hdev->dev,
sizeof(struct tpkbd_data_pointer),
GFP_KERNEL);
if (data_pointer == NULL) { if (data_pointer == NULL) {
hid_err(hdev, "Could not allocate memory for driver data\n"); hid_err(hdev, "Could not allocate memory for driver data\n");
return -ENOMEM; return -ENOMEM;
...@@ -364,20 +363,13 @@ static int tpkbd_probe_tp(struct hid_device *hdev) ...@@ -364,20 +363,13 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
data_pointer->sensitivity = 0xa0; data_pointer->sensitivity = 0xa0;
data_pointer->press_speed = 0x38; data_pointer->press_speed = 0x38;
name_mute = kzalloc(name_sz, GFP_KERNEL); name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
if (name_mute == NULL) { name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
if (name_mute == NULL || name_micmute == NULL) {
hid_err(hdev, "Could not allocate memory for led data\n"); hid_err(hdev, "Could not allocate memory for led data\n");
ret = -ENOMEM; return -ENOMEM;
goto err;
} }
snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev)); snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev));
name_micmute = kzalloc(name_sz, GFP_KERNEL);
if (name_micmute == NULL) {
hid_err(hdev, "Could not allocate memory for led data\n");
ret = -ENOMEM;
goto err2;
}
snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev)); snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev));
hid_set_drvdata(hdev, data_pointer); hid_set_drvdata(hdev, data_pointer);
...@@ -397,19 +389,12 @@ static int tpkbd_probe_tp(struct hid_device *hdev) ...@@ -397,19 +389,12 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
tpkbd_features_set(hdev); tpkbd_features_set(hdev);
return 0; return 0;
err2:
kfree(name_mute);
err:
kfree(data_pointer);
return ret;
} }
static int tpkbd_probe(struct hid_device *hdev, static int tpkbd_probe(struct hid_device *hdev,
const struct hid_device_id *id) const struct hid_device_id *id)
{ {
int ret; int ret;
struct usbhid_device *uhdev;
ret = hid_parse(hdev); ret = hid_parse(hdev);
if (ret) { if (ret) {
...@@ -423,9 +408,8 @@ static int tpkbd_probe(struct hid_device *hdev, ...@@ -423,9 +408,8 @@ static int tpkbd_probe(struct hid_device *hdev,
goto err; goto err;
} }
uhdev = (struct usbhid_device *) hdev->driver_data; if (hid_get_drvdata(hdev)) {
hid_set_drvdata(hdev, NULL);
if (uhdev->ifnum == 1) {
ret = tpkbd_probe_tp(hdev); ret = tpkbd_probe_tp(hdev);
if (ret) if (ret)
goto err_hid; goto err_hid;
...@@ -449,17 +433,11 @@ static void tpkbd_remove_tp(struct hid_device *hdev) ...@@ -449,17 +433,11 @@ static void tpkbd_remove_tp(struct hid_device *hdev)
led_classdev_unregister(&data_pointer->led_mute); led_classdev_unregister(&data_pointer->led_mute);
hid_set_drvdata(hdev, NULL); hid_set_drvdata(hdev, NULL);
kfree(data_pointer->led_micmute.name);
kfree(data_pointer->led_mute.name);
kfree(data_pointer);
} }
static void tpkbd_remove(struct hid_device *hdev) static void tpkbd_remove(struct hid_device *hdev)
{ {
struct usbhid_device *uhdev; if (hid_get_drvdata(hdev))
uhdev = (struct usbhid_device *) hdev->driver_data;
if (uhdev->ifnum == 1)
tpkbd_remove_tp(hdev); tpkbd_remove_tp(hdev);
hid_hw_stop(hdev); hid_hw_stop(hdev);
......
...@@ -45,7 +45,9 @@ ...@@ -45,7 +45,9 @@
/* Size of the original descriptors of the Driving Force (and Pro) wheels */ /* Size of the original descriptors of the Driving Force (and Pro) wheels */
#define DF_RDESC_ORIG_SIZE 130 #define DF_RDESC_ORIG_SIZE 130
#define DFP_RDESC_ORIG_SIZE 97 #define DFP_RDESC_ORIG_SIZE 97
#define FV_RDESC_ORIG_SIZE 130
#define MOMO_RDESC_ORIG_SIZE 87 #define MOMO_RDESC_ORIG_SIZE 87
#define MOMO2_RDESC_ORIG_SIZE 87
/* Fixed report descriptors for Logitech Driving Force (and Pro) /* Fixed report descriptors for Logitech Driving Force (and Pro)
* wheel controllers * wheel controllers
...@@ -170,6 +172,73 @@ static __u8 dfp_rdesc_fixed[] = { ...@@ -170,6 +172,73 @@ static __u8 dfp_rdesc_fixed[] = {
0xC0 /* End Collection */ 0xC0 /* End Collection */
}; };
static __u8 fv_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
0xA1, 0x01, /* Collection (Application), */
0xA1, 0x02, /* Collection (Logical), */
0x95, 0x01, /* Report Count (1), */
0x75, 0x0A, /* Report Size (10), */
0x15, 0x00, /* Logical Minimum (0), */
0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
0x35, 0x00, /* Physical Minimum (0), */
0x46, 0xFF, 0x03, /* Physical Maximum (1023), */
0x09, 0x30, /* Usage (X), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x0C, /* Report Count (12), */
0x75, 0x01, /* Report Size (1), */
0x25, 0x01, /* Logical Maximum (1), */
0x45, 0x01, /* Physical Maximum (1), */
0x05, 0x09, /* Usage Page (Button), */
0x19, 0x01, /* Usage Minimum (01h), */
0x29, 0x0C, /* Usage Maximum (0Ch), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x02, /* Report Count (2), */
0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
0x09, 0x01, /* Usage (01h), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x02, /* Usage (02h), */
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x46, 0xFF, 0x00, /* Physical Maximum (255), */
0x95, 0x01, /* Report Count (1), */
0x75, 0x08, /* Report Size (8), */
0x81, 0x02, /* Input (Variable), */
0x05, 0x01, /* Usage Page (Desktop), */
0x25, 0x07, /* Logical Maximum (7), */
0x46, 0x3B, 0x01, /* Physical Maximum (315), */
0x75, 0x04, /* Report Size (4), */
0x65, 0x14, /* Unit (Degrees), */
0x09, 0x39, /* Usage (Hat Switch), */
0x81, 0x42, /* Input (Variable, Null State), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x04, /* Report Count (4), */
0x65, 0x00, /* Unit, */
0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
0x09, 0x01, /* Usage (01h), */
0x25, 0x01, /* Logical Maximum (1), */
0x45, 0x01, /* Physical Maximum (1), */
0x81, 0x02, /* Input (Variable), */
0x05, 0x01, /* Usage Page (Desktop), */
0x95, 0x01, /* Report Count (1), */
0x75, 0x08, /* Report Size (8), */
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x46, 0xFF, 0x00, /* Physical Maximum (255), */
0x09, 0x31, /* Usage (Y), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x32, /* Usage (Z), */
0x81, 0x02, /* Input (Variable), */
0xC0, /* End Collection, */
0xA1, 0x02, /* Collection (Logical), */
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x46, 0xFF, 0x00, /* Physical Maximum (255), */
0x95, 0x07, /* Report Count (7), */
0x75, 0x08, /* Report Size (8), */
0x09, 0x03, /* Usage (03h), */
0x91, 0x02, /* Output (Variable), */
0xC0, /* End Collection, */
0xC0 /* End Collection */
};
static __u8 momo_rdesc_fixed[] = { static __u8 momo_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */ 0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */ 0x09, 0x04, /* Usage (Joystik), */
...@@ -216,6 +285,54 @@ static __u8 momo_rdesc_fixed[] = { ...@@ -216,6 +285,54 @@ static __u8 momo_rdesc_fixed[] = {
0xC0 /* End Collection */ 0xC0 /* End Collection */
}; };
static __u8 momo2_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
0xA1, 0x01, /* Collection (Application), */
0xA1, 0x02, /* Collection (Logical), */
0x95, 0x01, /* Report Count (1), */
0x75, 0x0A, /* Report Size (10), */
0x15, 0x00, /* Logical Minimum (0), */
0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
0x35, 0x00, /* Physical Minimum (0), */
0x46, 0xFF, 0x03, /* Physical Maximum (1023), */
0x09, 0x30, /* Usage (X), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x0A, /* Report Count (10), */
0x75, 0x01, /* Report Size (1), */
0x25, 0x01, /* Logical Maximum (1), */
0x45, 0x01, /* Physical Maximum (1), */
0x05, 0x09, /* Usage Page (Button), */
0x19, 0x01, /* Usage Minimum (01h), */
0x29, 0x0A, /* Usage Maximum (0Ah), */
0x81, 0x02, /* Input (Variable), */
0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
0x09, 0x00, /* Usage (00h), */
0x95, 0x04, /* Report Count (4), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x01, /* Report Count (1), */
0x75, 0x08, /* Report Size (8), */
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x46, 0xFF, 0x00, /* Physical Maximum (255), */
0x09, 0x01, /* Usage (01h), */
0x81, 0x02, /* Input (Variable), */
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x31, /* Usage (Y), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x32, /* Usage (Z), */
0x81, 0x02, /* Input (Variable), */
0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
0x09, 0x00, /* Usage (00h), */
0x81, 0x02, /* Input (Variable), */
0xC0, /* End Collection, */
0xA1, 0x02, /* Collection (Logical), */
0x09, 0x02, /* Usage (02h), */
0x95, 0x07, /* Report Count (7), */
0x91, 0x02, /* Output (Variable), */
0xC0, /* End Collection, */
0xC0 /* End Collection */
};
/* /*
* Certain Logitech keyboards send in report #3 keys which are far * Certain Logitech keyboards send in report #3 keys which are far
* above the logical maximum described in descriptor. This extends * above the logical maximum described in descriptor. This extends
...@@ -275,6 +392,24 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -275,6 +392,24 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
} }
break; break;
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
hid_info(hdev,
"fixing up Logitech Momo Racing Force (Black) report descriptor\n");
rdesc = momo2_rdesc_fixed;
*rsize = sizeof(momo2_rdesc_fixed);
}
break;
case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
if (*rsize == FV_RDESC_ORIG_SIZE) {
hid_info(hdev,
"fixing up Logitech Formula Vibration report descriptor\n");
rdesc = fv_rdesc_fixed;
*rsize = sizeof(fv_rdesc_fixed);
}
break;
case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
if (*rsize == DFP_RDESC_ORIG_SIZE) { if (*rsize == DFP_RDESC_ORIG_SIZE) {
hid_info(hdev, hid_info(hdev,
...@@ -492,6 +627,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, ...@@ -492,6 +627,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
case USB_DEVICE_ID_LOGITECH_G27_WHEEL: case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
case USB_DEVICE_ID_LOGITECH_WII_WHEEL: case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2: case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
field->application = HID_GD_MULTIAXIS; field->application = HID_GD_MULTIAXIS;
break; break;
default: default:
...@@ -639,6 +775,8 @@ static const struct hid_device_id lg_devices[] = { ...@@ -639,6 +775,8 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_NOGET | LG_FF4 }, .driver_data = LG_NOGET | LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
.driver_data = LG_FF4 }, .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
.driver_data = LG_FF2 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
.driver_data = LG_FF4 }, .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
......
...@@ -95,7 +95,7 @@ int lg2ff_init(struct hid_device *hid) ...@@ -95,7 +95,7 @@ int lg2ff_init(struct hid_device *hid)
hid_hw_request(hid, report, HID_REQ_SET_REPORT); hid_hw_request(hid, report, HID_REQ_SET_REPORT);
hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula <anssi.hannula@gmail.com>\n"); hid_info(hid, "Force feedback for Logitech variant 2 rumble devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0; return 0;
} }
...@@ -196,6 +196,21 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e ...@@ -196,6 +196,21 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e
case FF_CONSTANT: case FF_CONSTANT:
x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */
CLAMP(x); CLAMP(x);
if (x == 0x80) {
/* De-activate force in slot-1*/
value[0] = 0x13;
value[1] = 0x00;
value[2] = 0x00;
value[3] = 0x00;
value[4] = 0x00;
value[5] = 0x00;
value[6] = 0x00;
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
return 0;
}
value[0] = 0x11; /* Slot 1 */ value[0] = 0x11; /* Slot 1 */
value[1] = 0x08; value[1] = 0x08;
value[2] = x; value[2] = x;
...@@ -218,12 +233,70 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud ...@@ -218,12 +233,70 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct hid_report, list); struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
__s32 *value = report->field[0]->value; __s32 *value = report->field[0]->value;
__u32 expand_a, expand_b;
struct lg4ff_device_entry *entry;
struct lg_drv_data *drv_data;
drv_data = hid_get_drvdata(hid);
if (!drv_data) {
hid_err(hid, "Private driver data not found!\n");
return;
}
entry = drv_data->device_props;
if (!entry) {
hid_err(hid, "Device properties not found!\n");
return;
}
/* De-activate Auto-Center */
if (magnitude == 0) {
value[0] = 0xf5;
value[1] = 0x00;
value[2] = 0x00;
value[3] = 0x00;
value[4] = 0x00;
value[5] = 0x00;
value[6] = 0x00;
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
return;
}
if (magnitude <= 0xaaaa) {
expand_a = 0x0c * magnitude;
expand_b = 0x80 * magnitude;
} else {
expand_a = (0x0c * 0xaaaa) + 0x06 * (magnitude - 0xaaaa);
expand_b = (0x80 * 0xaaaa) + 0xff * (magnitude - 0xaaaa);
}
/* Adjust for non-MOMO wheels */
switch (entry->product_id) {
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
break;
default:
expand_a = expand_a >> 1;
break;
}
value[0] = 0xfe; value[0] = 0xfe;
value[1] = 0x0d; value[1] = 0x0d;
value[2] = magnitude >> 13; value[2] = expand_a / 0xaaaa;
value[3] = magnitude >> 13; value[3] = expand_a / 0xaaaa;
value[4] = magnitude >> 8; value[4] = expand_b / 0xaaaa;
value[5] = 0x00;
value[6] = 0x00;
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
/* Activate Auto-Center */
value[0] = 0x14;
value[1] = 0x00;
value[2] = 0x00;
value[3] = 0x00;
value[4] = 0x00;
value[5] = 0x00; value[5] = 0x00;
value[6] = 0x00; value[6] = 0x00;
...@@ -540,17 +613,6 @@ int lg4ff_init(struct hid_device *hid) ...@@ -540,17 +613,6 @@ int lg4ff_init(struct hid_device *hid)
if (error) if (error)
return error; return error;
/* Check if autocentering is available and
* set the centering force to zero by default */
if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
if (rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */
dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex;
else
dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default;
dev->ff->set_autocenter(dev, 0);
}
/* Get private driver data */ /* Get private driver data */
drv_data = hid_get_drvdata(hid); drv_data = hid_get_drvdata(hid);
if (!drv_data) { if (!drv_data) {
...@@ -571,6 +633,17 @@ int lg4ff_init(struct hid_device *hid) ...@@ -571,6 +633,17 @@ int lg4ff_init(struct hid_device *hid)
entry->max_range = lg4ff_devices[i].max_range; entry->max_range = lg4ff_devices[i].max_range;
entry->set_range = lg4ff_devices[i].set_range; entry->set_range = lg4ff_devices[i].set_range;
/* Check if autocentering is available and
* set the centering force to zero by default */
if (test_bit(FF_AUTOCENTER, dev->ffbit)) {
if (rev_maj == FFEX_REV_MAJ && rev_min == FFEX_REV_MIN) /* Formula Force EX expects different autocentering command */
dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex;
else
dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default;
dev->ff->set_autocenter(dev, 0);
}
/* Create sysfs interface */ /* Create sysfs interface */
error = device_create_file(&hid->dev, &dev_attr_range); error = device_create_file(&hid->dev, &dev_attr_range);
if (error) if (error)
......
...@@ -542,9 +542,9 @@ static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, ...@@ -542,9 +542,9 @@ static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
return 0; return 0;
} }
static void rdcat(char **rdesc, unsigned int *rsize, const char *data, unsigned int size) static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size)
{ {
memcpy(*rdesc + *rsize, data, size); memcpy(rdesc + *rsize, data, size);
*rsize += size; *rsize += size;
} }
...@@ -567,31 +567,31 @@ static int logi_dj_ll_parse(struct hid_device *hid) ...@@ -567,31 +567,31 @@ static int logi_dj_ll_parse(struct hid_device *hid)
if (djdev->reports_supported & STD_KEYBOARD) { if (djdev->reports_supported & STD_KEYBOARD) {
dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n", dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
__func__, djdev->reports_supported); __func__, djdev->reports_supported);
rdcat(&rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor)); rdcat(rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
} }
if (djdev->reports_supported & STD_MOUSE) { if (djdev->reports_supported & STD_MOUSE) {
dbg_hid("%s: sending a mouse descriptor, reports_supported: " dbg_hid("%s: sending a mouse descriptor, reports_supported: "
"%x\n", __func__, djdev->reports_supported); "%x\n", __func__, djdev->reports_supported);
rdcat(&rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor)); rdcat(rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));
} }
if (djdev->reports_supported & MULTIMEDIA) { if (djdev->reports_supported & MULTIMEDIA) {
dbg_hid("%s: sending a multimedia report descriptor: %x\n", dbg_hid("%s: sending a multimedia report descriptor: %x\n",
__func__, djdev->reports_supported); __func__, djdev->reports_supported);
rdcat(&rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor)); rdcat(rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
} }
if (djdev->reports_supported & POWER_KEYS) { if (djdev->reports_supported & POWER_KEYS) {
dbg_hid("%s: sending a power keys report descriptor: %x\n", dbg_hid("%s: sending a power keys report descriptor: %x\n",
__func__, djdev->reports_supported); __func__, djdev->reports_supported);
rdcat(&rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor)); rdcat(rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
} }
if (djdev->reports_supported & MEDIA_CENTER) { if (djdev->reports_supported & MEDIA_CENTER) {
dbg_hid("%s: sending a media center report descriptor: %x\n", dbg_hid("%s: sending a media center report descriptor: %x\n",
__func__, djdev->reports_supported); __func__, djdev->reports_supported);
rdcat(&rdesc, &rsize, media_descriptor, sizeof(media_descriptor)); rdcat(rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
} }
if (djdev->reports_supported & KBD_LEDS) { if (djdev->reports_supported & KBD_LEDS) {
......
...@@ -250,12 +250,12 @@ static struct mt_class mt_classes[] = { ...@@ -250,12 +250,12 @@ static struct mt_class mt_classes[] = {
{ .name = MT_CLS_GENERALTOUCH_TWOFINGERS, { .name = MT_CLS_GENERALTOUCH_TWOFINGERS,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
MT_QUIRK_VALID_IS_INRANGE | MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTNUMBER, MT_QUIRK_SLOT_IS_CONTACTID,
.maxcontacts = 2 .maxcontacts = 2
}, },
{ .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, { .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
MT_QUIRK_SLOT_IS_CONTACTNUMBER MT_QUIRK_SLOT_IS_CONTACTID
}, },
{ .name = MT_CLS_FLATFROG, { .name = MT_CLS_FLATFROG,
...@@ -1173,6 +1173,21 @@ static const struct hid_device_id mt_devices[] = { ...@@ -1173,6 +1173,21 @@ static const struct hid_device_id mt_devices[] = {
{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS, { .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) }, USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) },
{ .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS,
MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0101) },
{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0102) },
{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0106) },
{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A) },
{ .driver_data = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100) },
/* Gametel game controller */ /* Gametel game controller */
{ .driver_data = MT_CLS_NSMU, { .driver_data = MT_CLS_NSMU,
...@@ -1284,6 +1299,14 @@ static const struct hid_device_id mt_devices[] = { ...@@ -1284,6 +1299,14 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) }, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) },
/* SiS panels */
{ .driver_data = MT_CLS_DEFAULT,
HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH,
USB_DEVICE_ID_SIS9200_TOUCH) },
{ .driver_data = MT_CLS_DEFAULT,
HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH,
USB_DEVICE_ID_SIS817_TOUCH) },
/* Stantum panels */ /* Stantum panels */
{ .driver_data = MT_CLS_CONFIDENCE, { .driver_data = MT_CLS_CONFIDENCE,
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM, MT_USB_DEVICE(USB_VENDOR_ID_STANTUM,
......
...@@ -65,10 +65,11 @@ int roccat_common2_send(struct usb_device *usb_dev, uint report_id, ...@@ -65,10 +65,11 @@ int roccat_common2_send(struct usb_device *usb_dev, uint report_id,
EXPORT_SYMBOL_GPL(roccat_common2_send); EXPORT_SYMBOL_GPL(roccat_common2_send);
enum roccat_common2_control_states { enum roccat_common2_control_states {
ROCCAT_COMMON_CONTROL_STATUS_OVERLOAD = 0, ROCCAT_COMMON_CONTROL_STATUS_CRITICAL = 0,
ROCCAT_COMMON_CONTROL_STATUS_OK = 1, ROCCAT_COMMON_CONTROL_STATUS_OK = 1,
ROCCAT_COMMON_CONTROL_STATUS_INVALID = 2, ROCCAT_COMMON_CONTROL_STATUS_INVALID = 2,
ROCCAT_COMMON_CONTROL_STATUS_WAIT = 3, ROCCAT_COMMON_CONTROL_STATUS_BUSY = 3,
ROCCAT_COMMON_CONTROL_STATUS_CRITICAL_NEW = 4,
}; };
static int roccat_common2_receive_control_status(struct usb_device *usb_dev) static int roccat_common2_receive_control_status(struct usb_device *usb_dev)
...@@ -88,13 +89,12 @@ static int roccat_common2_receive_control_status(struct usb_device *usb_dev) ...@@ -88,13 +89,12 @@ static int roccat_common2_receive_control_status(struct usb_device *usb_dev)
switch (control.value) { switch (control.value) {
case ROCCAT_COMMON_CONTROL_STATUS_OK: case ROCCAT_COMMON_CONTROL_STATUS_OK:
return 0; return 0;
case ROCCAT_COMMON_CONTROL_STATUS_WAIT: case ROCCAT_COMMON_CONTROL_STATUS_BUSY:
msleep(500); msleep(500);
continue; continue;
case ROCCAT_COMMON_CONTROL_STATUS_INVALID: case ROCCAT_COMMON_CONTROL_STATUS_INVALID:
case ROCCAT_COMMON_CONTROL_STATUS_CRITICAL:
case ROCCAT_COMMON_CONTROL_STATUS_OVERLOAD: case ROCCAT_COMMON_CONTROL_STATUS_CRITICAL_NEW:
/* seems to be critical - replug necessary */
return -EINVAL; return -EINVAL;
default: default:
dev_err(&usb_dev->dev, dev_err(&usb_dev->dev,
...@@ -122,6 +122,59 @@ int roccat_common2_send_with_status(struct usb_device *usb_dev, ...@@ -122,6 +122,59 @@ int roccat_common2_send_with_status(struct usb_device *usb_dev,
} }
EXPORT_SYMBOL_GPL(roccat_common2_send_with_status); EXPORT_SYMBOL_GPL(roccat_common2_send_with_status);
int roccat_common2_device_init_struct(struct usb_device *usb_dev,
struct roccat_common2_device *dev)
{
mutex_init(&dev->lock);
return 0;
}
EXPORT_SYMBOL_GPL(roccat_common2_device_init_struct);
ssize_t roccat_common2_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent;
struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off >= real_size)
return 0;
if (off != 0 || count != real_size)
return -EINVAL;
mutex_lock(&roccat_dev->lock);
retval = roccat_common2_receive(usb_dev, command, buf, real_size);
mutex_unlock(&roccat_dev->lock);
return retval ? retval : real_size;
}
EXPORT_SYMBOL_GPL(roccat_common2_sysfs_read);
ssize_t roccat_common2_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent;
struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off != 0 || count != real_size)
return -EINVAL;
mutex_lock(&roccat_dev->lock);
retval = roccat_common2_send_with_status(usb_dev, command, buf, real_size);
mutex_unlock(&roccat_dev->lock);
return retval ? retval : real_size;
}
EXPORT_SYMBOL_GPL(roccat_common2_sysfs_write);
MODULE_AUTHOR("Stefan Achatz"); MODULE_AUTHOR("Stefan Achatz");
MODULE_DESCRIPTION("USB Roccat common driver"); MODULE_DESCRIPTION("USB Roccat common driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -32,4 +32,66 @@ int roccat_common2_send(struct usb_device *usb_dev, uint report_id, ...@@ -32,4 +32,66 @@ int roccat_common2_send(struct usb_device *usb_dev, uint report_id,
int roccat_common2_send_with_status(struct usb_device *usb_dev, int roccat_common2_send_with_status(struct usb_device *usb_dev,
uint command, void const *buf, uint size); uint command, void const *buf, uint size);
struct roccat_common2_device {
int roccat_claimed;
int chrdev_minor;
struct mutex lock;
};
int roccat_common2_device_init_struct(struct usb_device *usb_dev,
struct roccat_common2_device *dev);
ssize_t roccat_common2_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command);
ssize_t roccat_common2_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command);
#define ROCCAT_COMMON2_SYSFS_W(thingy, COMMAND, SIZE) \
static ssize_t roccat_common2_sysfs_write_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
return roccat_common2_sysfs_write(fp, kobj, buf, off, count, \
SIZE, COMMAND); \
}
#define ROCCAT_COMMON2_SYSFS_R(thingy, COMMAND, SIZE) \
static ssize_t roccat_common2_sysfs_read_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
return roccat_common2_sysfs_read(fp, kobj, buf, off, count, \
SIZE, COMMAND); \
}
#define ROCCAT_COMMON2_SYSFS_RW(thingy, COMMAND, SIZE) \
ROCCAT_COMMON2_SYSFS_W(thingy, COMMAND, SIZE) \
ROCCAT_COMMON2_SYSFS_R(thingy, COMMAND, SIZE)
#define ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(thingy, COMMAND, SIZE) \
ROCCAT_COMMON2_SYSFS_RW(thingy, COMMAND, SIZE); \
static struct bin_attribute bin_attr_ ## thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = SIZE, \
.read = roccat_common2_sysfs_read_ ## thingy, \
.write = roccat_common2_sysfs_write_ ## thingy \
}
#define ROCCAT_COMMON2_BIN_ATTRIBUTE_R(thingy, COMMAND, SIZE) \
ROCCAT_COMMON2_SYSFS_R(thingy, COMMAND, SIZE); \
static struct bin_attribute bin_attr_ ## thingy = { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = SIZE, \
.read = roccat_common2_sysfs_read_ ## thingy, \
}
#define ROCCAT_COMMON2_BIN_ATTRIBUTE_W(thingy, COMMAND, SIZE) \
ROCCAT_COMMON2_SYSFS_W(thingy, COMMAND, SIZE); \
static struct bin_attribute bin_attr_ ## thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = SIZE, \
.write = roccat_common2_sysfs_write_ ## thingy \
}
#endif #endif
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
* Roccat KonePure is a smaller version of KoneXTD with less buttons and lights. * Roccat KonePure is a smaller version of KoneXTD with less buttons and lights.
*/ */
#include <linux/types.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/hid.h> #include <linux/hid.h>
...@@ -23,128 +24,50 @@ ...@@ -23,128 +24,50 @@
#include <linux/hid-roccat.h> #include <linux/hid-roccat.h>
#include "hid-ids.h" #include "hid-ids.h"
#include "hid-roccat-common.h" #include "hid-roccat-common.h"
#include "hid-roccat-konepure.h"
static struct class *konepure_class; enum {
KONEPURE_MOUSE_REPORT_NUMBER_BUTTON = 3,
static ssize_t konepure_sysfs_read(struct file *fp, struct kobject *kobj, };
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent;
struct konepure_device *konepure = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off >= real_size)
return 0;
if (off != 0 || count != real_size)
return -EINVAL;
mutex_lock(&konepure->konepure_lock);
retval = roccat_common2_receive(usb_dev, command, buf, real_size);
mutex_unlock(&konepure->konepure_lock);
return retval ? retval : real_size;
}
static ssize_t konepure_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent;
struct konepure_device *konepure = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off != 0 || count != real_size)
return -EINVAL;
mutex_lock(&konepure->konepure_lock);
retval = roccat_common2_send_with_status(usb_dev, command,
(void *)buf, real_size);
mutex_unlock(&konepure->konepure_lock);
return retval ? retval : real_size;
}
#define KONEPURE_SYSFS_W(thingy, THINGY) \
static ssize_t konepure_sysfs_write_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
return konepure_sysfs_write(fp, kobj, buf, off, count, \
KONEPURE_SIZE_ ## THINGY, KONEPURE_COMMAND_ ## THINGY); \
}
#define KONEPURE_SYSFS_R(thingy, THINGY) \
static ssize_t konepure_sysfs_read_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
return konepure_sysfs_read(fp, kobj, buf, off, count, \
KONEPURE_SIZE_ ## THINGY, KONEPURE_COMMAND_ ## THINGY); \
}
#define KONEPURE_SYSFS_RW(thingy, THINGY) \ struct konepure_mouse_report_button {
KONEPURE_SYSFS_W(thingy, THINGY) \ uint8_t report_number; /* always KONEPURE_MOUSE_REPORT_NUMBER_BUTTON */
KONEPURE_SYSFS_R(thingy, THINGY) uint8_t zero;
uint8_t type;
#define KONEPURE_BIN_ATTRIBUTE_RW(thingy, THINGY) \ uint8_t data1;
KONEPURE_SYSFS_RW(thingy, THINGY); \ uint8_t data2;
static struct bin_attribute bin_attr_##thingy = { \ uint8_t zero2;
.attr = { .name = #thingy, .mode = 0660 }, \ uint8_t unknown[2];
.size = KONEPURE_SIZE_ ## THINGY, \ } __packed;
.read = konepure_sysfs_read_ ## thingy, \
.write = konepure_sysfs_write_ ## thingy \
}
#define KONEPURE_BIN_ATTRIBUTE_R(thingy, THINGY) \ static struct class *konepure_class;
KONEPURE_SYSFS_R(thingy, THINGY); \
static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = KONEPURE_SIZE_ ## THINGY, \
.read = konepure_sysfs_read_ ## thingy, \
}
#define KONEPURE_BIN_ATTRIBUTE_W(thingy, THINGY) \
KONEPURE_SYSFS_W(thingy, THINGY); \
static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = KONEPURE_SIZE_ ## THINGY, \
.write = konepure_sysfs_write_ ## thingy \
}
KONEPURE_BIN_ATTRIBUTE_RW(actual_profile, ACTUAL_PROFILE); ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
KONEPURE_BIN_ATTRIBUTE_RW(info, INFO); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(actual_profile, 0x05, 0x03);
KONEPURE_BIN_ATTRIBUTE_RW(sensor, SENSOR); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile_settings, 0x06, 0x1f);
KONEPURE_BIN_ATTRIBUTE_RW(tcu, TCU); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile_buttons, 0x07, 0x3b);
KONEPURE_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS); ROCCAT_COMMON2_BIN_ATTRIBUTE_W(macro, 0x08, 0x0822);
KONEPURE_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(info, 0x09, 0x06);
KONEPURE_BIN_ATTRIBUTE_W(control, CONTROL); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(tcu, 0x0c, 0x04);
KONEPURE_BIN_ATTRIBUTE_W(talk, TALK); ROCCAT_COMMON2_BIN_ATTRIBUTE_R(tcu_image, 0x0c, 0x0404);
KONEPURE_BIN_ATTRIBUTE_W(macro, MACRO); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(sensor, 0x0f, 0x06);
KONEPURE_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE); ROCCAT_COMMON2_BIN_ATTRIBUTE_W(talk, 0x10, 0x10);
static struct bin_attribute *konepure_bin_attributes[] = { static struct bin_attribute *konepure_bin_attrs[] = {
&bin_attr_actual_profile, &bin_attr_actual_profile,
&bin_attr_control,
&bin_attr_info, &bin_attr_info,
&bin_attr_talk,
&bin_attr_macro,
&bin_attr_sensor, &bin_attr_sensor,
&bin_attr_tcu, &bin_attr_tcu,
&bin_attr_tcu_image,
&bin_attr_profile_settings, &bin_attr_profile_settings,
&bin_attr_profile_buttons, &bin_attr_profile_buttons,
&bin_attr_control,
&bin_attr_talk,
&bin_attr_macro,
&bin_attr_tcu_image,
NULL, NULL,
}; };
static const struct attribute_group konepure_group = { static const struct attribute_group konepure_group = {
.bin_attrs = konepure_bin_attributes, .bin_attrs = konepure_bin_attrs,
}; };
static const struct attribute_group *konepure_groups[] = { static const struct attribute_group *konepure_groups[] = {
...@@ -152,20 +75,11 @@ static const struct attribute_group *konepure_groups[] = { ...@@ -152,20 +75,11 @@ static const struct attribute_group *konepure_groups[] = {
NULL, NULL,
}; };
static int konepure_init_konepure_device_struct(struct usb_device *usb_dev,
struct konepure_device *konepure)
{
mutex_init(&konepure->konepure_lock);
return 0;
}
static int konepure_init_specials(struct hid_device *hdev) static int konepure_init_specials(struct hid_device *hdev)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct usb_device *usb_dev = interface_to_usbdev(intf); struct usb_device *usb_dev = interface_to_usbdev(intf);
struct konepure_device *konepure; struct roccat_common2_device *konepure;
int retval; int retval;
if (intf->cur_altsetting->desc.bInterfaceProtocol if (intf->cur_altsetting->desc.bInterfaceProtocol
...@@ -181,9 +95,9 @@ static int konepure_init_specials(struct hid_device *hdev) ...@@ -181,9 +95,9 @@ static int konepure_init_specials(struct hid_device *hdev)
} }
hid_set_drvdata(hdev, konepure); hid_set_drvdata(hdev, konepure);
retval = konepure_init_konepure_device_struct(usb_dev, konepure); retval = roccat_common2_device_init_struct(usb_dev, konepure);
if (retval) { if (retval) {
hid_err(hdev, "couldn't init struct konepure_device\n"); hid_err(hdev, "couldn't init KonePure device\n");
goto exit_free; goto exit_free;
} }
...@@ -205,7 +119,7 @@ static int konepure_init_specials(struct hid_device *hdev) ...@@ -205,7 +119,7 @@ static int konepure_init_specials(struct hid_device *hdev)
static void konepure_remove_specials(struct hid_device *hdev) static void konepure_remove_specials(struct hid_device *hdev)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct konepure_device *konepure; struct roccat_common2_device *konepure;
if (intf->cur_altsetting->desc.bInterfaceProtocol if (intf->cur_altsetting->desc.bInterfaceProtocol
!= USB_INTERFACE_PROTOCOL_MOUSE) != USB_INTERFACE_PROTOCOL_MOUSE)
...@@ -258,7 +172,7 @@ static int konepure_raw_event(struct hid_device *hdev, ...@@ -258,7 +172,7 @@ static int konepure_raw_event(struct hid_device *hdev,
struct hid_report *report, u8 *data, int size) struct hid_report *report, u8 *data, int size)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct konepure_device *konepure = hid_get_drvdata(hdev); struct roccat_common2_device *konepure = hid_get_drvdata(hdev);
if (intf->cur_altsetting->desc.bInterfaceProtocol if (intf->cur_altsetting->desc.bInterfaceProtocol
!= USB_INTERFACE_PROTOCOL_MOUSE) != USB_INTERFACE_PROTOCOL_MOUSE)
......
#ifndef __HID_ROCCAT_KONEPURE_H
#define __HID_ROCCAT_KONEPURE_H
/*
* Copyright (c) 2012 Stefan Achatz <erazor_de@users.sourceforge.net>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/types.h>
enum {
KONEPURE_SIZE_ACTUAL_PROFILE = 0x03,
KONEPURE_SIZE_CONTROL = 0x03,
KONEPURE_SIZE_FIRMWARE_WRITE = 0x0402,
KONEPURE_SIZE_INFO = 0x06,
KONEPURE_SIZE_MACRO = 0x0822,
KONEPURE_SIZE_PROFILE_SETTINGS = 0x1f,
KONEPURE_SIZE_PROFILE_BUTTONS = 0x3b,
KONEPURE_SIZE_SENSOR = 0x06,
KONEPURE_SIZE_TALK = 0x10,
KONEPURE_SIZE_TCU = 0x04,
KONEPURE_SIZE_TCU_IMAGE = 0x0404,
};
enum konepure_control_requests {
KONEPURE_CONTROL_REQUEST_GENERAL = 0x80,
KONEPURE_CONTROL_REQUEST_BUTTONS = 0x90,
};
enum konepure_commands {
KONEPURE_COMMAND_CONTROL = 0x04,
KONEPURE_COMMAND_ACTUAL_PROFILE = 0x05,
KONEPURE_COMMAND_PROFILE_SETTINGS = 0x06,
KONEPURE_COMMAND_PROFILE_BUTTONS = 0x07,
KONEPURE_COMMAND_MACRO = 0x08,
KONEPURE_COMMAND_INFO = 0x09,
KONEPURE_COMMAND_TCU = 0x0c,
KONEPURE_COMMAND_TCU_IMAGE = 0x0c,
KONEPURE_COMMAND_E = 0x0e,
KONEPURE_COMMAND_SENSOR = 0x0f,
KONEPURE_COMMAND_TALK = 0x10,
KONEPURE_COMMAND_FIRMWARE_WRITE = 0x1b,
KONEPURE_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
};
enum {
KONEPURE_MOUSE_REPORT_NUMBER_BUTTON = 3,
};
struct konepure_mouse_report_button {
uint8_t report_number; /* always KONEPURE_MOUSE_REPORT_NUMBER_BUTTON */
uint8_t zero;
uint8_t type;
uint8_t data1;
uint8_t data2;
uint8_t zero2;
uint8_t unknown[2];
} __packed;
struct konepure_device {
int roccat_claimed;
int chrdev_minor;
struct mutex konepure_lock;
};
#endif
...@@ -554,9 +554,13 @@ static void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus, ...@@ -554,9 +554,13 @@ static void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus,
break; break;
case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI: case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI:
kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1); kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1);
break;
case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY: case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY:
kovaplus->actual_x_sensitivity = button_report->data1; kovaplus->actual_x_sensitivity = button_report->data1;
kovaplus->actual_y_sensitivity = button_report->data2; kovaplus->actual_y_sensitivity = button_report->data2;
break;
default:
break;
} }
} }
......
/*
* Roccat Ryos driver for Linux
*
* Copyright (c) 2013 Stefan Achatz <erazor_de@users.sourceforge.net>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/types.h>
#include <linux/device.h>
#include <linux/input.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/hid-roccat.h>
#include "hid-ids.h"
#include "hid-roccat-common.h"
enum {
RYOS_REPORT_NUMBER_SPECIAL = 3,
RYOS_USB_INTERFACE_PROTOCOL = 0,
};
struct ryos_report_special {
uint8_t number; /* RYOS_REPORT_NUMBER_SPECIAL */
uint8_t data[4];
} __packed;
static struct class *ryos_class;
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x04, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x05, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_primary, 0x06, 0x7d);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_function, 0x07, 0x5f);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_macro, 0x08, 0x23);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_thumbster, 0x09, 0x17);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_extra, 0x0a, 0x08);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(keys_easyzone, 0x0b, 0x126);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(key_mask, 0x0c, 0x06);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(light, 0x0d, 0x10);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(macro, 0x0e, 0x7d2);
ROCCAT_COMMON2_BIN_ATTRIBUTE_R(info, 0x0f, 0x08);
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(reset, 0x11, 0x03);
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(light_control, 0x13, 0x08);
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(talk, 0x16, 0x10);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(stored_lights, 0x17, 0x0566);
ROCCAT_COMMON2_BIN_ATTRIBUTE_W(custom_lights, 0x18, 0x14);
ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(light_macro, 0x19, 0x07d2);
static struct bin_attribute *ryos_bin_attrs[] = {
&bin_attr_control,
&bin_attr_profile,
&bin_attr_keys_primary,
&bin_attr_keys_function,
&bin_attr_keys_macro,
&bin_attr_keys_thumbster,
&bin_attr_keys_extra,
&bin_attr_keys_easyzone,
&bin_attr_key_mask,
&bin_attr_light,
&bin_attr_macro,
&bin_attr_info,
&bin_attr_reset,
&bin_attr_light_control,
&bin_attr_talk,
&bin_attr_stored_lights,
&bin_attr_custom_lights,
&bin_attr_light_macro,
NULL,
};
static const struct attribute_group ryos_group = {
.bin_attrs = ryos_bin_attrs,
};
static const struct attribute_group *ryos_groups[] = {
&ryos_group,
NULL,
};
static int ryos_init_specials(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct roccat_common2_device *ryos;
int retval;
if (intf->cur_altsetting->desc.bInterfaceProtocol
!= RYOS_USB_INTERFACE_PROTOCOL) {
hid_set_drvdata(hdev, NULL);
return 0;
}
ryos = kzalloc(sizeof(*ryos), GFP_KERNEL);
if (!ryos) {
hid_err(hdev, "can't alloc device descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, ryos);
retval = roccat_common2_device_init_struct(usb_dev, ryos);
if (retval) {
hid_err(hdev, "couldn't init Ryos device\n");
goto exit_free;
}
retval = roccat_connect(ryos_class, hdev,
sizeof(struct ryos_report_special));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
} else {
ryos->chrdev_minor = retval;
ryos->roccat_claimed = 1;
}
return 0;
exit_free:
kfree(ryos);
return retval;
}
static void ryos_remove_specials(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct roccat_common2_device *ryos;
if (intf->cur_altsetting->desc.bInterfaceProtocol
!= RYOS_USB_INTERFACE_PROTOCOL)
return;
ryos = hid_get_drvdata(hdev);
if (ryos->roccat_claimed)
roccat_disconnect(ryos->chrdev_minor);
kfree(ryos);
}
static int ryos_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int retval;
retval = hid_parse(hdev);
if (retval) {
hid_err(hdev, "parse failed\n");
goto exit;
}
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (retval) {
hid_err(hdev, "hw start failed\n");
goto exit;
}
retval = ryos_init_specials(hdev);
if (retval) {
hid_err(hdev, "couldn't install mouse\n");
goto exit_stop;
}
return 0;
exit_stop:
hid_hw_stop(hdev);
exit:
return retval;
}
static void ryos_remove(struct hid_device *hdev)
{
ryos_remove_specials(hdev);
hid_hw_stop(hdev);
}
static int ryos_raw_event(struct hid_device *hdev,
struct hid_report *report, u8 *data, int size)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct roccat_common2_device *ryos = hid_get_drvdata(hdev);
if (intf->cur_altsetting->desc.bInterfaceProtocol
!= RYOS_USB_INTERFACE_PROTOCOL)
return 0;
if (data[0] != RYOS_REPORT_NUMBER_SPECIAL)
return 0;
if (ryos != NULL && ryos->roccat_claimed)
roccat_report_event(ryos->chrdev_minor, data);
return 0;
}
static const struct hid_device_id ryos_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_GLOW) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO) },
{ }
};
MODULE_DEVICE_TABLE(hid, ryos_devices);
static struct hid_driver ryos_driver = {
.name = "ryos",
.id_table = ryos_devices,
.probe = ryos_probe,
.remove = ryos_remove,
.raw_event = ryos_raw_event
};
static int __init ryos_init(void)
{
int retval;
ryos_class = class_create(THIS_MODULE, "ryos");
if (IS_ERR(ryos_class))
return PTR_ERR(ryos_class);
ryos_class->dev_groups = ryos_groups;
retval = hid_register_driver(&ryos_driver);
if (retval)
class_destroy(ryos_class);
return retval;
}
static void __exit ryos_exit(void)
{
hid_unregister_driver(&ryos_driver);
class_destroy(ryos_class);
}
module_init(ryos_init);
module_exit(ryos_exit);
MODULE_AUTHOR("Stefan Achatz");
MODULE_DESCRIPTION("USB Roccat Ryos MK/Glow/Pro driver");
MODULE_LICENSE("GPL v2");
...@@ -27,98 +27,15 @@ ...@@ -27,98 +27,15 @@
static struct class *savu_class; static struct class *savu_class;
static ssize_t savu_sysfs_read(struct file *fp, struct kobject *kobj, ROCCAT_COMMON2_BIN_ATTRIBUTE_W(control, 0x4, 0x03);
char *buf, loff_t off, size_t count, ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(profile, 0x5, 0x03);
size_t real_size, uint command) ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(general, 0x6, 0x10);
{ ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(buttons, 0x7, 0x2f);
struct device *dev = ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(macro, 0x8, 0x0823);
container_of(kobj, struct device, kobj)->parent->parent; ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(info, 0x9, 0x08);
struct savu_device *savu = hid_get_drvdata(dev_get_drvdata(dev)); ROCCAT_COMMON2_BIN_ATTRIBUTE_RW(sensor, 0xc, 0x04);
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval; static struct bin_attribute *savu_bin_attrs[] = {
if (off >= real_size)
return 0;
if (off != 0 || count != real_size)
return -EINVAL;
mutex_lock(&savu->savu_lock);
retval = roccat_common2_receive(usb_dev, command, buf, real_size);
mutex_unlock(&savu->savu_lock);
return retval ? retval : real_size;
}
static ssize_t savu_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
struct device *dev =
container_of(kobj, struct device, kobj)->parent->parent;
struct savu_device *savu = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off != 0 || count != real_size)
return -EINVAL;
mutex_lock(&savu->savu_lock);
retval = roccat_common2_send_with_status(usb_dev, command,
(void *)buf, real_size);
mutex_unlock(&savu->savu_lock);
return retval ? retval : real_size;
}
#define SAVU_SYSFS_W(thingy, THINGY) \
static ssize_t savu_sysfs_write_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
return savu_sysfs_write(fp, kobj, buf, off, count, \
SAVU_SIZE_ ## THINGY, SAVU_COMMAND_ ## THINGY); \
}
#define SAVU_SYSFS_R(thingy, THINGY) \
static ssize_t savu_sysfs_read_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
return savu_sysfs_read(fp, kobj, buf, off, count, \
SAVU_SIZE_ ## THINGY, SAVU_COMMAND_ ## THINGY); \
}
#define SAVU_SYSFS_RW(thingy, THINGY) \
SAVU_SYSFS_W(thingy, THINGY) \
SAVU_SYSFS_R(thingy, THINGY)
#define SAVU_BIN_ATTRIBUTE_RW(thingy, THINGY) \
SAVU_SYSFS_RW(thingy, THINGY); \
static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = SAVU_SIZE_ ## THINGY, \
.read = savu_sysfs_read_ ## thingy, \
.write = savu_sysfs_write_ ## thingy \
}
#define SAVU_BIN_ATTRIBUTE_W(thingy, THINGY) \
SAVU_SYSFS_W(thingy, THINGY); \
static struct bin_attribute bin_attr_##thingy = { \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = SAVU_SIZE_ ## THINGY, \
.write = savu_sysfs_write_ ## thingy \
}
SAVU_BIN_ATTRIBUTE_W(control, CONTROL);
SAVU_BIN_ATTRIBUTE_RW(profile, PROFILE);
SAVU_BIN_ATTRIBUTE_RW(general, GENERAL);
SAVU_BIN_ATTRIBUTE_RW(buttons, BUTTONS);
SAVU_BIN_ATTRIBUTE_RW(macro, MACRO);
SAVU_BIN_ATTRIBUTE_RW(info, INFO);
SAVU_BIN_ATTRIBUTE_RW(sensor, SENSOR);
static struct bin_attribute *savu_bin_attributes[] = {
&bin_attr_control, &bin_attr_control,
&bin_attr_profile, &bin_attr_profile,
&bin_attr_general, &bin_attr_general,
...@@ -130,7 +47,7 @@ static struct bin_attribute *savu_bin_attributes[] = { ...@@ -130,7 +47,7 @@ static struct bin_attribute *savu_bin_attributes[] = {
}; };
static const struct attribute_group savu_group = { static const struct attribute_group savu_group = {
.bin_attrs = savu_bin_attributes, .bin_attrs = savu_bin_attrs,
}; };
static const struct attribute_group *savu_groups[] = { static const struct attribute_group *savu_groups[] = {
...@@ -138,19 +55,11 @@ static const struct attribute_group *savu_groups[] = { ...@@ -138,19 +55,11 @@ static const struct attribute_group *savu_groups[] = {
NULL, NULL,
}; };
static int savu_init_savu_device_struct(struct usb_device *usb_dev,
struct savu_device *savu)
{
mutex_init(&savu->savu_lock);
return 0;
}
static int savu_init_specials(struct hid_device *hdev) static int savu_init_specials(struct hid_device *hdev)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct usb_device *usb_dev = interface_to_usbdev(intf); struct usb_device *usb_dev = interface_to_usbdev(intf);
struct savu_device *savu; struct roccat_common2_device *savu;
int retval; int retval;
if (intf->cur_altsetting->desc.bInterfaceProtocol if (intf->cur_altsetting->desc.bInterfaceProtocol
...@@ -166,9 +75,9 @@ static int savu_init_specials(struct hid_device *hdev) ...@@ -166,9 +75,9 @@ static int savu_init_specials(struct hid_device *hdev)
} }
hid_set_drvdata(hdev, savu); hid_set_drvdata(hdev, savu);
retval = savu_init_savu_device_struct(usb_dev, savu); retval = roccat_common2_device_init_struct(usb_dev, savu);
if (retval) { if (retval) {
hid_err(hdev, "couldn't init struct savu_device\n"); hid_err(hdev, "couldn't init Savu device\n");
goto exit_free; goto exit_free;
} }
...@@ -190,7 +99,7 @@ static int savu_init_specials(struct hid_device *hdev) ...@@ -190,7 +99,7 @@ static int savu_init_specials(struct hid_device *hdev)
static void savu_remove_specials(struct hid_device *hdev) static void savu_remove_specials(struct hid_device *hdev)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct savu_device *savu; struct roccat_common2_device *savu;
if (intf->cur_altsetting->desc.bInterfaceProtocol if (intf->cur_altsetting->desc.bInterfaceProtocol
!= USB_INTERFACE_PROTOCOL_MOUSE) != USB_INTERFACE_PROTOCOL_MOUSE)
...@@ -239,7 +148,7 @@ static void savu_remove(struct hid_device *hdev) ...@@ -239,7 +148,7 @@ static void savu_remove(struct hid_device *hdev)
hid_hw_stop(hdev); hid_hw_stop(hdev);
} }
static void savu_report_to_chrdev(struct savu_device const *savu, static void savu_report_to_chrdev(struct roccat_common2_device const *savu,
u8 const *data) u8 const *data)
{ {
struct savu_roccat_report roccat_report; struct savu_roccat_report roccat_report;
...@@ -261,7 +170,7 @@ static int savu_raw_event(struct hid_device *hdev, ...@@ -261,7 +170,7 @@ static int savu_raw_event(struct hid_device *hdev,
struct hid_report *report, u8 *data, int size) struct hid_report *report, u8 *data, int size)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct savu_device *savu = hid_get_drvdata(hdev); struct roccat_common2_device *savu = hid_get_drvdata(hdev);
if (intf->cur_altsetting->desc.bInterfaceProtocol if (intf->cur_altsetting->desc.bInterfaceProtocol
!= USB_INTERFACE_PROTOCOL_MOUSE) != USB_INTERFACE_PROTOCOL_MOUSE)
......
...@@ -14,31 +14,6 @@ ...@@ -14,31 +14,6 @@
#include <linux/types.h> #include <linux/types.h>
enum {
SAVU_SIZE_CONTROL = 0x03,
SAVU_SIZE_PROFILE = 0x03,
SAVU_SIZE_GENERAL = 0x10,
SAVU_SIZE_BUTTONS = 0x2f,
SAVU_SIZE_MACRO = 0x0823,
SAVU_SIZE_INFO = 0x08,
SAVU_SIZE_SENSOR = 0x04,
};
enum savu_control_requests {
SAVU_CONTROL_REQUEST_GENERAL = 0x80,
SAVU_CONTROL_REQUEST_BUTTONS = 0x90,
};
enum savu_commands {
SAVU_COMMAND_CONTROL = 0x4,
SAVU_COMMAND_PROFILE = 0x5,
SAVU_COMMAND_GENERAL = 0x6,
SAVU_COMMAND_BUTTONS = 0x7,
SAVU_COMMAND_MACRO = 0x8,
SAVU_COMMAND_INFO = 0x9,
SAVU_COMMAND_SENSOR = 0xc,
};
struct savu_mouse_report_special { struct savu_mouse_report_special {
uint8_t report_number; /* always 3 */ uint8_t report_number; /* always 3 */
uint8_t zero; uint8_t zero;
...@@ -77,11 +52,4 @@ struct savu_roccat_report { ...@@ -77,11 +52,4 @@ struct savu_roccat_report {
uint8_t data[2]; uint8_t data[2];
} __packed; } __packed;
struct savu_device {
int roccat_claimed;
int chrdev_minor;
struct mutex savu_lock;
};
#endif #endif
...@@ -326,7 +326,8 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, ...@@ -326,7 +326,8 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
field->logical == attr_usage_id) { field->logical == attr_usage_id) {
sensor_hub_fill_attr_info(info, i, report->id, sensor_hub_fill_attr_info(info, i, report->id,
field->unit, field->unit_exponent, field->unit, field->unit_exponent,
field->report_size); field->report_size *
field->report_count);
ret = 0; ret = 0;
} else { } else {
for (j = 0; j < field->maxusage; ++j) { for (j = 0; j < field->maxusage; ++j) {
...@@ -338,7 +339,8 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, ...@@ -338,7 +339,8 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
i, report->id, i, report->id,
field->unit, field->unit,
field->unit_exponent, field->unit_exponent,
field->report_size); field->report_size *
field->report_count);
ret = 0; ret = 0;
break; break;
} }
...@@ -425,9 +427,10 @@ static int sensor_hub_raw_event(struct hid_device *hdev, ...@@ -425,9 +427,10 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n", hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n",
i, report->field[i]->usage->collection_index, i, report->field[i]->usage->collection_index,
report->field[i]->usage->hid, report->field[i]->usage->hid,
report->field[i]->report_size/8); (report->field[i]->report_size *
report->field[i]->report_count)/8);
sz = report->field[i]->report_size/8; sz = (report->field[i]->report_size *
report->field[i]->report_count)/8;
if (pdata->pending.status && pdata->pending.attr_usage_id == if (pdata->pending.status && pdata->pending.attr_usage_id ==
report->field[i]->usage->hid) { report->field[i]->usage->hid) {
hid_dbg(hdev, "data was pending ...\n"); hid_dbg(hdev, "data was pending ...\n");
......
...@@ -419,21 +419,14 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf, ...@@ -419,21 +419,14 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
*/ */
static int sixaxis_set_operational_usb(struct hid_device *hdev) static int sixaxis_set_operational_usb(struct hid_device *hdev)
{ {
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct usb_device *dev = interface_to_usbdev(intf);
__u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
int ret; int ret;
char *buf = kmalloc(18, GFP_KERNEL); char *buf = kmalloc(18, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ret = hdev->hid_get_raw_report(hdev, 0xf2, buf, 17, HID_FEATURE_REPORT);
HID_REQ_GET_REPORT,
USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE,
(3 << 8) | 0xf2, ifnum, buf, 17,
USB_CTRL_GET_TIMEOUT);
if (ret < 0) if (ret < 0)
hid_err(hdev, "can't set operational mode\n"); hid_err(hdev, "can't set operational mode\n");
...@@ -621,6 +614,54 @@ static void buzz_remove(struct hid_device *hdev) ...@@ -621,6 +614,54 @@ static void buzz_remove(struct hid_device *hdev)
drv_data->extra = NULL; drv_data->extra = NULL;
} }
#ifdef CONFIG_SONY_FF
static int sony_play_effect(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
unsigned char buf[] = {
0x01,
0x00, 0xff, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00
};
__u8 left;
__u8 right;
struct hid_device *hid = input_get_drvdata(dev);
if (effect->type != FF_RUMBLE)
return 0;
left = effect->u.rumble.strong_magnitude / 256;
right = effect->u.rumble.weak_magnitude ? 1 : 0;
buf[3] = right;
buf[5] = left;
return hid->hid_output_raw_report(hid, buf, sizeof(buf),
HID_OUTPUT_REPORT);
}
static int sony_init_ff(struct hid_device *hdev)
{
struct hid_input *hidinput = list_entry(hdev->inputs.next,
struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
return input_ff_create_memless(input_dev, NULL, sony_play_effect);
}
#else
static int sony_init_ff(struct hid_device *hdev)
{
return 0;
}
#endif
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{ {
int ret; int ret;
...@@ -670,6 +711,10 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -670,6 +711,10 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret < 0) if (ret < 0)
goto err_stop; goto err_stop;
ret = sony_init_ff(hdev);
if (ret < 0)
goto err_stop;
return 0; return 0;
err_stop: err_stop:
hid_hw_stop(hdev); hid_hw_stop(hdev);
......
...@@ -1655,10 +1655,39 @@ static void wiimod_pro_in_ext(struct wiimote_data *wdata, const __u8 *ext) ...@@ -1655,10 +1655,39 @@ static void wiimod_pro_in_ext(struct wiimote_data *wdata, const __u8 *ext)
ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8); ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8);
ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8); ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8);
input_report_abs(wdata->extension.input, ABS_X, lx - 0x800); /* zero-point offsets */
input_report_abs(wdata->extension.input, ABS_Y, ly - 0x800); lx -= 0x800;
input_report_abs(wdata->extension.input, ABS_RX, rx - 0x800); ly = 0x800 - ly;
input_report_abs(wdata->extension.input, ABS_RY, ry - 0x800); rx -= 0x800;
ry = 0x800 - ry;
/* Trivial automatic calibration. We don't know any calibration data
* in the EEPROM so we must use the first report to calibrate the
* null-position of the analog sticks. Users can retrigger calibration
* via sysfs, or set it explicitly. If data is off more than abs(500),
* we skip calibration as the sticks are likely to be moved already. */
if (!(wdata->state.flags & WIIPROTO_FLAG_PRO_CALIB_DONE)) {
wdata->state.flags |= WIIPROTO_FLAG_PRO_CALIB_DONE;
if (abs(lx) < 500)
wdata->state.calib_pro_sticks[0] = -lx;
if (abs(ly) < 500)
wdata->state.calib_pro_sticks[1] = -ly;
if (abs(rx) < 500)
wdata->state.calib_pro_sticks[2] = -rx;
if (abs(ry) < 500)
wdata->state.calib_pro_sticks[3] = -ry;
}
/* apply calibration data */
lx += wdata->state.calib_pro_sticks[0];
ly += wdata->state.calib_pro_sticks[1];
rx += wdata->state.calib_pro_sticks[2];
ry += wdata->state.calib_pro_sticks[3];
input_report_abs(wdata->extension.input, ABS_X, lx);
input_report_abs(wdata->extension.input, ABS_Y, ly);
input_report_abs(wdata->extension.input, ABS_RX, rx);
input_report_abs(wdata->extension.input, ABS_RY, ry);
input_report_key(wdata->extension.input, input_report_key(wdata->extension.input,
wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT], wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT],
...@@ -1766,12 +1795,70 @@ static int wiimod_pro_play(struct input_dev *dev, void *data, ...@@ -1766,12 +1795,70 @@ static int wiimod_pro_play(struct input_dev *dev, void *data,
return 0; return 0;
} }
static ssize_t wiimod_pro_calib_show(struct device *dev,
struct device_attribute *attr,
char *out)
{
struct wiimote_data *wdata = dev_to_wii(dev);
int r;
r = 0;
r += sprintf(&out[r], "%+06hd:", wdata->state.calib_pro_sticks[0]);
r += sprintf(&out[r], "%+06hd ", wdata->state.calib_pro_sticks[1]);
r += sprintf(&out[r], "%+06hd:", wdata->state.calib_pro_sticks[2]);
r += sprintf(&out[r], "%+06hd\n", wdata->state.calib_pro_sticks[3]);
return r;
}
static ssize_t wiimod_pro_calib_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct wiimote_data *wdata = dev_to_wii(dev);
int r;
s16 x1, y1, x2, y2;
if (!strncmp(buf, "scan\n", 5)) {
spin_lock_irq(&wdata->state.lock);
wdata->state.flags &= ~WIIPROTO_FLAG_PRO_CALIB_DONE;
spin_unlock_irq(&wdata->state.lock);
} else {
r = sscanf(buf, "%hd:%hd %hd:%hd", &x1, &y1, &x2, &y2);
if (r != 4)
return -EINVAL;
spin_lock_irq(&wdata->state.lock);
wdata->state.flags |= WIIPROTO_FLAG_PRO_CALIB_DONE;
spin_unlock_irq(&wdata->state.lock);
wdata->state.calib_pro_sticks[0] = x1;
wdata->state.calib_pro_sticks[1] = y1;
wdata->state.calib_pro_sticks[2] = x2;
wdata->state.calib_pro_sticks[3] = y2;
}
return strnlen(buf, PAGE_SIZE);
}
static DEVICE_ATTR(pro_calib, S_IRUGO|S_IWUSR|S_IWGRP, wiimod_pro_calib_show,
wiimod_pro_calib_store);
static int wiimod_pro_probe(const struct wiimod_ops *ops, static int wiimod_pro_probe(const struct wiimod_ops *ops,
struct wiimote_data *wdata) struct wiimote_data *wdata)
{ {
int ret, i; int ret, i;
unsigned long flags;
INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker); INIT_WORK(&wdata->rumble_worker, wiimod_rumble_worker);
wdata->state.calib_pro_sticks[0] = 0;
wdata->state.calib_pro_sticks[1] = 0;
wdata->state.calib_pro_sticks[2] = 0;
wdata->state.calib_pro_sticks[3] = 0;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->state.flags &= ~WIIPROTO_FLAG_PRO_CALIB_DONE;
spin_unlock_irqrestore(&wdata->state.lock, flags);
wdata->extension.input = input_allocate_device(); wdata->extension.input = input_allocate_device();
if (!wdata->extension.input) if (!wdata->extension.input)
...@@ -1786,6 +1873,13 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops, ...@@ -1786,6 +1873,13 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
goto err_free; goto err_free;
} }
ret = device_create_file(&wdata->hdev->dev,
&dev_attr_pro_calib);
if (ret) {
hid_err(wdata->hdev, "cannot create sysfs attribute\n");
goto err_free;
}
wdata->extension.input->open = wiimod_pro_open; wdata->extension.input->open = wiimod_pro_open;
wdata->extension.input->close = wiimod_pro_close; wdata->extension.input->close = wiimod_pro_close;
wdata->extension.input->dev.parent = &wdata->hdev->dev; wdata->extension.input->dev.parent = &wdata->hdev->dev;
...@@ -1806,20 +1900,23 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops, ...@@ -1806,20 +1900,23 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
set_bit(ABS_RX, wdata->extension.input->absbit); set_bit(ABS_RX, wdata->extension.input->absbit);
set_bit(ABS_RY, wdata->extension.input->absbit); set_bit(ABS_RY, wdata->extension.input->absbit);
input_set_abs_params(wdata->extension.input, input_set_abs_params(wdata->extension.input,
ABS_X, -0x800, 0x800, 2, 4); ABS_X, -0x400, 0x400, 4, 100);
input_set_abs_params(wdata->extension.input, input_set_abs_params(wdata->extension.input,
ABS_Y, -0x800, 0x800, 2, 4); ABS_Y, -0x400, 0x400, 4, 100);
input_set_abs_params(wdata->extension.input, input_set_abs_params(wdata->extension.input,
ABS_RX, -0x800, 0x800, 2, 4); ABS_RX, -0x400, 0x400, 4, 100);
input_set_abs_params(wdata->extension.input, input_set_abs_params(wdata->extension.input,
ABS_RY, -0x800, 0x800, 2, 4); ABS_RY, -0x400, 0x400, 4, 100);
ret = input_register_device(wdata->extension.input); ret = input_register_device(wdata->extension.input);
if (ret) if (ret)
goto err_free; goto err_file;
return 0; return 0;
err_file:
device_remove_file(&wdata->hdev->dev,
&dev_attr_pro_calib);
err_free: err_free:
input_free_device(wdata->extension.input); input_free_device(wdata->extension.input);
wdata->extension.input = NULL; wdata->extension.input = NULL;
...@@ -1837,6 +1934,8 @@ static void wiimod_pro_remove(const struct wiimod_ops *ops, ...@@ -1837,6 +1934,8 @@ static void wiimod_pro_remove(const struct wiimod_ops *ops,
input_unregister_device(wdata->extension.input); input_unregister_device(wdata->extension.input);
wdata->extension.input = NULL; wdata->extension.input = NULL;
cancel_work_sync(&wdata->rumble_worker); cancel_work_sync(&wdata->rumble_worker);
device_remove_file(&wdata->hdev->dev,
&dev_attr_pro_calib);
spin_lock_irqsave(&wdata->state.lock, flags); spin_lock_irqsave(&wdata->state.lock, flags);
wiiproto_req_rumble(wdata, 0); wiiproto_req_rumble(wdata, 0);
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#define WIIPROTO_FLAG_DRM_LOCKED 0x8000 #define WIIPROTO_FLAG_DRM_LOCKED 0x8000
#define WIIPROTO_FLAG_BUILTIN_MP 0x010000 #define WIIPROTO_FLAG_BUILTIN_MP 0x010000
#define WIIPROTO_FLAG_NO_MP 0x020000 #define WIIPROTO_FLAG_NO_MP 0x020000
#define WIIPROTO_FLAG_PRO_CALIB_DONE 0x040000
#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ #define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
...@@ -135,6 +136,7 @@ struct wiimote_state { ...@@ -135,6 +136,7 @@ struct wiimote_state {
/* calibration/cache data */ /* calibration/cache data */
__u16 calib_bboard[4][3]; __u16 calib_bboard[4][3];
__s16 calib_pro_sticks[4];
__u8 cache_rumble; __u8 cache_rumble;
}; };
......
...@@ -454,10 +454,6 @@ static void i2c_hid_init_reports(struct hid_device *hid) ...@@ -454,10 +454,6 @@ static void i2c_hid_init_reports(struct hid_device *hid)
return; return;
} }
list_for_each_entry(report,
&hid->report_enum[HID_INPUT_REPORT].report_list, list)
i2c_hid_init_report(report, inbuf, ihid->bufsize);
list_for_each_entry(report, list_for_each_entry(report,
&hid->report_enum[HID_FEATURE_REPORT].report_list, list) &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
i2c_hid_init_report(report, inbuf, ihid->bufsize); i2c_hid_init_report(report, inbuf, ihid->bufsize);
......
...@@ -84,6 +84,8 @@ static const struct hid_blacklist { ...@@ -84,6 +84,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SIS2_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SIS2_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET },
......
...@@ -146,12 +146,10 @@ enum { ...@@ -146,12 +146,10 @@ enum {
#define USB_DEVICE_HID_CLASS(vend, prod) \ #define USB_DEVICE_HID_CLASS(vend, prod) \
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \
| USB_DEVICE_ID_MATCH_INT_PROTOCOL \
| USB_DEVICE_ID_MATCH_DEVICE, \ | USB_DEVICE_ID_MATCH_DEVICE, \
.idVendor = (vend), \ .idVendor = (vend), \
.idProduct = (prod), \ .idProduct = (prod), \
.bInterfaceClass = USB_INTERFACE_CLASS_HID, \ .bInterfaceClass = USB_INTERFACE_CLASS_HID
.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
static const struct usb_device_id usbtouch_devices[] = { static const struct usb_device_id usbtouch_devices[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment