diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-22 20:58:23 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-22 20:58:23 -0800 |
commit | 4988abf1749241bc80600a6b3283d03898d2717c (patch) | |
tree | 9660d892d024b8df5b685f3724ed50afdeed77b2 /drivers | |
parent | fe41c2c018b8af9b370a40845f547e22894ff68a (diff) | |
parent | 62813858fb5d1fb661433d7884668aa111115a35 (diff) | |
download | op-kernel-dev-4988abf1749241bc80600a6b3283d03898d2717c.zip op-kernel-dev-4988abf1749241bc80600a6b3283d03898d2717c.tar.gz |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina:
- quite some work on hid-sony driver in order to have DualShock 4
device properly supported, from Frank Praznik
- fixed support for suspending I2C conntected devices, from Mika
Westerberg
- regression fix for 0xff05 usage on Microsoft Ergonomy, from Jiri
Kosina
- support for Synaptics HD touchscreen, from AceLan Kao
- workaround for USB 3.0 problem for logitech-dj connected devices,
from Benjamin Tisssoires
- support for Logitech Dual Action pads, from Vitaly Katraew
- quite a few other assorted fixes and device ID additions
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (33 commits)
HID: sony: Use colors for the Dualshock 4 LED names
HID: sony: Add annotated HID descriptor for the Dualshock 4
HID: sony: Cache the output report for the Dualshock 4
HID: sony: Map gyroscopes and accelerometers to axes
HID: sony: Fix spacing in the device definitions.
HID: sony: Use standard output reports instead of raw reports to send data to the Dualshock 4.
HID: sony: Use separate identifiers for USB and Bluetooth connected Dualshock 4 controllers.
HID: hid-holtek-mouse: add new a070 mouse
HID: hid-sensor-hub: Fix buggy report descriptors
HID: logitech-dj: Fix USB 3.0 issue
HID: sony: Rename worker function
HID: sony: Add LED controls for the Dualshock 4
HID: sony: Add force-feedback support for the Dualshock 4
HID: hidraw: make comment more accurate and nicer
HID: sony: fix error return code
HID: input: fix input sysfs path for hid devices
HID: debug: add labels for some new buttons
HID: remove SIS entries from hid_have_special_driver[]
HID: microsoft: no fallthrough in MS ergonomy 0xff05 usage
HID: add support for SiS multitouch panel in the touch monitor LG 23ET83V
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hid/Kconfig | 1 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 5 | ||||
-rw-r--r-- | drivers/hid/hid-debug.c | 5 | ||||
-rw-r--r-- | drivers/hid/hid-holtek-mouse.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 15 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-lg.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-logitech-dj.c | 8 | ||||
-rw-r--r-- | drivers/hid/hid-microsoft.c | 1 | ||||
-rw-r--r-- | drivers/hid/hid-multitouch.c | 7 | ||||
-rw-r--r-- | drivers/hid/hid-sensor-hub.c | 45 | ||||
-rw-r--r-- | drivers/hid/hid-sony.c | 594 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 27 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 2 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 9 | ||||
-rw-r--r-- | drivers/hid/usbhid/usbkbd.c | 2 |
16 files changed, 592 insertions, 136 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 34e2d39..f722001 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -344,6 +344,7 @@ config HID_LOGITECH config HID_LOGITECH_DJ tristate "Logitech Unifying receivers full support" + depends on HIDRAW depends on HID_LOGITECH ---help--- Say Y if you want support for Logitech Unifying receivers and devices. diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 253fe23..026ab0f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1715,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_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_A070) }, { 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_HUION, USB_DEVICE_ID_HUION_580) }, @@ -1823,8 +1824,6 @@ static const struct hid_device_id hid_have_special_driver[] = { { 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_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_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) }, @@ -1832,6 +1831,8 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 8453214..53b771d 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -768,6 +768,8 @@ static const char *keys[KEY_MAX + 1] = { [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel", [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp", [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", + [BTN_DPAD_UP] = "BtnDPadUp", [BTN_DPAD_DOWN] = "BtnDPadDown", + [BTN_DPAD_LEFT] = "BtnDPadLeft", [BTN_DPAD_RIGHT] = "BtnDPadRight", [BTN_0] = "Btn0", [BTN_1] = "Btn1", [BTN_2] = "Btn2", [BTN_3] = "Btn3", [BTN_4] = "Btn4", [BTN_5] = "Btn5", @@ -797,7 +799,8 @@ static const char *keys[KEY_MAX + 1] = { [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", - [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn", + [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_TOOL_QUADTAP] = "ToolQuadrupleTap", + [BTN_GEAR_DOWN] = "WheelBtn", [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", diff --git a/drivers/hid/hid-holtek-mouse.c b/drivers/hid/hid-holtek-mouse.c index 0caa676..d60fbd0 100644 --- a/drivers/hid/hid-holtek-mouse.c +++ b/drivers/hid/hid-holtek-mouse.c @@ -49,6 +49,7 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, } break; case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A: + case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070: case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081: if (*rsize >= 113 && rdesc[106] == 0xff && rdesc[107] == 0x7f && rdesc[111] == 0xff && rdesc[112] == 0x7f) { @@ -65,6 +66,8 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, static const struct hid_device_id holtek_mouse_devices[] = { { 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_A070) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f9304cb..92b40c0 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -445,6 +445,10 @@ #define USB_VENDOR_ID_ILITEK 0x222a #define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001 +#define USB_VENDOR_ID_INTEL_0 0x8086 +#define USB_VENDOR_ID_INTEL_1 0x8087 +#define USB_DEVICE_ID_INTEL_HID_SENSOR 0x09fa + #define USB_VENDOR_ID_ION 0x15e4 #define USB_DEVICE_ID_ICADE 0x0132 @@ -455,6 +459,7 @@ #define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055 #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_A070 0xa070 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072 0xa072 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081 0xa081 @@ -552,6 +557,7 @@ #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211 #define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215 +#define USB_DEVICE_ID_LOGITECH_DUAL_ACTION 0xc216 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219 #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 @@ -755,9 +761,11 @@ #define USB_VENDOR_ID_SIGMATEL 0x066F #define USB_DEVICE_ID_SIGMATEL_STMP3780 0x3780 -#define USB_VENDOR_ID_SIS2_TOUCH 0x0457 +#define USB_VENDOR_ID_SIS_TOUCH 0x0457 #define USB_DEVICE_ID_SIS9200_TOUCH 0x9200 #define USB_DEVICE_ID_SIS817_TOUCH 0x0817 +#define USB_DEVICE_ID_SIS_TS 0x1013 +#define USB_DEVICE_ID_SIS1030_TOUCH 0x1030 #define USB_VENDOR_ID_SKYCABLE 0x1223 #define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07 @@ -767,6 +775,7 @@ #define USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE 0x0374 #define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 +#define USB_DEVICE_ID_SONY_PS4_CONTROLLER 0x05c4 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 #define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000 @@ -809,6 +818,8 @@ #define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013 #define USB_DEVICE_ID_SYNAPTICS_LTS1 0x0af8 #define USB_DEVICE_ID_SYNAPTICS_LTS2 0x1d10 +#define USB_DEVICE_ID_SYNAPTICS_HD 0x0ac3 +#define USB_DEVICE_ID_SYNAPTICS_QUAD_HD 0x1ac3 #define USB_VENDOR_ID_THINGM 0x27b8 #define USB_DEVICE_ID_BLINK1 0x01ed @@ -939,7 +950,5 @@ #define USB_VENDOR_ID_PRIMAX 0x0461 #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 -#define USB_VENDOR_ID_SIS 0x0457 -#define USB_DEVICE_ID_SIS_TS 0x1013 #endif diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d97f232..d50e731 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1279,7 +1279,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid) input_dev->id.vendor = hid->vendor; input_dev->id.product = hid->product; input_dev->id.version = hid->version; - input_dev->dev.parent = hid->dev.parent; + input_dev->dev.parent = &hid->dev; hidinput->input = input_dev; list_add_tail(&hidinput->list, &hid->inputs); diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 06eb45f..9fe9d4a 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -758,6 +758,8 @@ static const struct hid_device_id lg_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D), .driver_data = LG_NOGET }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION), + .driver_data = LG_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL), .driver_data = LG_NOGET | LG_FF4 }, diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index a7947d8..f45279c 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -516,6 +516,14 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, dj_report->report_params[CMD_SWITCH_PARAM_TIMEOUT_SECONDS] = (u8)timeout; retval = logi_dj_recv_send_report(djrcv_dev, dj_report); kfree(dj_report); + + /* + * Ugly sleep to work around a USB 3.0 bug when the receiver is still + * processing the "switch-to-dj" command while we send an other command. + * 50 msec should gives enough time to the receiver to be ready. + */ + msleep(50); + return retval; } diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 551795b..c6ef6ee 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -73,6 +73,7 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage, set_bit(KEY_F16, input->keybit); set_bit(KEY_F17, input->keybit); set_bit(KEY_F18, input->keybit); + break; default: return 0; } diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index d83b1e8b..f134d73 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1301,11 +1301,14 @@ static const struct hid_device_id mt_devices[] = { /* SiS panels */ { .driver_data = MT_CLS_DEFAULT, - HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, + HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH) }, { .driver_data = MT_CLS_DEFAULT, - HID_USB_DEVICE(USB_VENDOR_ID_SIS2_TOUCH, + HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH) }, + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, + USB_DEVICE_ID_SIS1030_TOUCH) }, /* Stantum panels */ { .driver_data = MT_CLS_CONFIDENCE, diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 8fab828..46f4480 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -26,6 +26,8 @@ #include <linux/hid-sensor-hub.h> #include "hid-ids.h" +#define HID_SENSOR_HUB_ENUM_QUIRK 0x01 + /** * struct sensor_hub_pending - Synchronous read pending information * @status: Pending status true/false. @@ -64,6 +66,7 @@ struct sensor_hub_data { spinlock_t dyn_callback_lock; struct mfd_cell *hid_sensor_hub_client_devs; int hid_sensor_client_cnt; + unsigned long quirks; }; /** @@ -497,6 +500,40 @@ void sensor_hub_device_close(struct hid_sensor_hub_device *hsdev) } EXPORT_SYMBOL_GPL(sensor_hub_device_close); +static __u8 *sensor_hub_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + int index; + struct sensor_hub_data *sd = hid_get_drvdata(hdev); + unsigned char report_block[] = { + 0x0a, 0x16, 0x03, 0x15, 0x00, 0x25, 0x05}; + unsigned char power_block[] = { + 0x0a, 0x19, 0x03, 0x15, 0x00, 0x25, 0x05}; + + if (!(sd->quirks & HID_SENSOR_HUB_ENUM_QUIRK)) { + hid_dbg(hdev, "No Enum quirks\n"); + return rdesc; + } + + /* Looks for power and report state usage id and force to 1 */ + for (index = 0; index < *rsize; ++index) { + if (((*rsize - index) > sizeof(report_block)) && + !memcmp(&rdesc[index], report_block, + sizeof(report_block))) { + rdesc[index + 4] = 0x01; + index += sizeof(report_block); + } + if (((*rsize - index) > sizeof(power_block)) && + !memcmp(&rdesc[index], power_block, + sizeof(power_block))) { + rdesc[index + 4] = 0x01; + index += sizeof(power_block); + } + } + + return rdesc; +} + static int sensor_hub_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -520,6 +557,7 @@ static int sensor_hub_probe(struct hid_device *hdev, return -ENOMEM; } hid_set_drvdata(hdev, sd); + sd->quirks = id->driver_data; sd->hsdev->hdev = hdev; sd->hsdev->vendor_id = hdev->vendor; sd->hsdev->product_id = hdev->product; @@ -621,6 +659,12 @@ static void sensor_hub_remove(struct hid_device *hdev) } static const struct hid_device_id sensor_hub_devices[] = { + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_0, + USB_DEVICE_ID_INTEL_HID_SENSOR), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1, + USB_DEVICE_ID_INTEL_HID_SENSOR), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, HID_ANY_ID) }, { } @@ -633,6 +677,7 @@ static struct hid_driver sensor_hub_driver = { .probe = sensor_hub_probe, .remove = sensor_hub_remove, .raw_event = sensor_hub_raw_event, + .report_fixup = sensor_hub_report_fixup, #ifdef CONFIG_PM .suspend = sensor_hub_suspend, .resume = sensor_hub_resume, diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 098af2f8..1235405 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -33,11 +33,17 @@ #include "hid-ids.h" -#define VAIO_RDESC_CONSTANT (1 << 0) -#define SIXAXIS_CONTROLLER_USB (1 << 1) -#define SIXAXIS_CONTROLLER_BT (1 << 2) -#define BUZZ_CONTROLLER (1 << 3) -#define PS3REMOTE (1 << 4) +#define VAIO_RDESC_CONSTANT BIT(0) +#define SIXAXIS_CONTROLLER_USB BIT(1) +#define SIXAXIS_CONTROLLER_BT BIT(2) +#define BUZZ_CONTROLLER BIT(3) +#define PS3REMOTE BIT(4) +#define DUALSHOCK4_CONTROLLER_USB BIT(5) +#define DUALSHOCK4_CONTROLLER_BT BIT(6) + +#define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER_USB) + +#define MAX_LEDS 4 static const u8 sixaxis_rdesc_fixup[] = { 0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x95, 0x0C, @@ -67,6 +73,265 @@ static const u8 sixaxis_rdesc_fixup2[] = { 0xb1, 0x02, 0xc0, 0xc0, }; +/* The default descriptor doesn't provide mapping for the accelerometers + * or orientation sensors. This fixed descriptor maps the accelerometers + * to usage values 0x40, 0x41 and 0x42 and maps the orientation sensors + * to usage values 0x43, 0x44 and 0x45. + */ +static u8 dualshock4_usb_rdesc[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x05, /* Usage (Gamepad), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x01, /* Report ID (1), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x09, 0x32, /* Usage (Z), */ + 0x09, 0x35, /* Usage (Rz), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x04, /* Report Count (4), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0x39, /* Usage (Hat Switch), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x07, /* Logical Maximum (7), */ + 0x35, 0x00, /* Physical Minimum (0), */ + 0x46, 0x3B, 0x01, /* Physical Maximum (315), */ + 0x65, 0x14, /* Unit (Degrees), */ + 0x75, 0x04, /* Report Size (4), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x42, /* Input (Variable, Null State), */ + 0x65, 0x00, /* Unit, */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x0E, /* Usage Maximum (0Eh), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x0E, /* Report Count (14), */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x09, 0x20, /* Usage (20h), */ + 0x75, 0x06, /* Report Size (6), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x7F, /* Logical Maximum (127), */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x33, /* Usage (Rx), */ + 0x09, 0x34, /* Usage (Ry), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x09, 0x21, /* Usage (21h), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x19, 0x40, /* Usage Minimum (40h), */ + 0x29, 0x42, /* Usage Maximum (42h), */ + 0x16, 0x00, 0x80, /* Logical Minimum (-32768), */ + 0x26, 0x00, 0x7F, /* Logical Maximum (32767), */ + 0x75, 0x10, /* Report Size (16), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x02, /* Input (Variable), */ + 0x19, 0x43, /* Usage Minimum (43h), */ + 0x29, 0x45, /* Usage Maximum (45h), */ + 0x16, 0xFF, 0xBF, /* Logical Minimum (-16385), */ + 0x26, 0x00, 0x40, /* Logical Maximum (16384), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x09, 0x21, /* Usage (21h), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0xFF, /* Logical Maximum (255), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x27, /* Report Count (39), */ + 0x81, 0x02, /* Input (Variable), */ + 0x85, 0x05, /* Report ID (5), */ + 0x09, 0x22, /* Usage (22h), */ + 0x95, 0x1F, /* Report Count (31), */ + 0x91, 0x02, /* Output (Variable), */ + 0x85, 0x04, /* Report ID (4), */ + 0x09, 0x23, /* Usage (23h), */ + 0x95, 0x24, /* Report Count (36), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x02, /* Report ID (2), */ + 0x09, 0x24, /* Usage (24h), */ + 0x95, 0x24, /* Report Count (36), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x08, /* Report ID (8), */ + 0x09, 0x25, /* Usage (25h), */ + 0x95, 0x03, /* Report Count (3), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x10, /* Report ID (16), */ + 0x09, 0x26, /* Usage (26h), */ + 0x95, 0x04, /* Report Count (4), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x11, /* Report ID (17), */ + 0x09, 0x27, /* Usage (27h), */ + 0x95, 0x02, /* Report Count (2), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x12, /* Report ID (18), */ + 0x06, 0x02, 0xFF, /* Usage Page (FF02h), */ + 0x09, 0x21, /* Usage (21h), */ + 0x95, 0x0F, /* Report Count (15), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x13, /* Report ID (19), */ + 0x09, 0x22, /* Usage (22h), */ + 0x95, 0x16, /* Report Count (22), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x14, /* Report ID (20), */ + 0x06, 0x05, 0xFF, /* Usage Page (FF05h), */ + 0x09, 0x20, /* Usage (20h), */ + 0x95, 0x10, /* Report Count (16), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x15, /* Report ID (21), */ + 0x09, 0x21, /* Usage (21h), */ + 0x95, 0x2C, /* Report Count (44), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x06, 0x80, 0xFF, /* Usage Page (FF80h), */ + 0x85, 0x80, /* Report ID (128), */ + 0x09, 0x20, /* Usage (20h), */ + 0x95, 0x06, /* Report Count (6), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x81, /* Report ID (129), */ + 0x09, 0x21, /* Usage (21h), */ + 0x95, 0x06, /* Report Count (6), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x82, /* Report ID (130), */ + 0x09, 0x22, /* Usage (22h), */ + 0x95, 0x05, /* Report Count (5), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x83, /* Report ID (131), */ + 0x09, 0x23, /* Usage (23h), */ + 0x95, 0x01, /* Report Count (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x84, /* Report ID (132), */ + 0x09, 0x24, /* Usage (24h), */ + 0x95, 0x04, /* Report Count (4), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x85, /* Report ID (133), */ + 0x09, 0x25, /* Usage (25h), */ + 0x95, 0x06, /* Report Count (6), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x86, /* Report ID (134), */ + 0x09, 0x26, /* Usage (26h), */ + 0x95, 0x06, /* Report Count (6), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x87, /* Report ID (135), */ + 0x09, 0x27, /* Usage (27h), */ + 0x95, 0x23, /* Report Count (35), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x88, /* Report ID (136), */ + 0x09, 0x28, /* Usage (28h), */ + 0x95, 0x22, /* Report Count (34), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x89, /* Report ID (137), */ + 0x09, 0x29, /* Usage (29h), */ + 0x95, 0x02, /* Report Count (2), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x90, /* Report ID (144), */ + 0x09, 0x30, /* Usage (30h), */ + 0x95, 0x05, /* Report Count (5), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x91, /* Report ID (145), */ + 0x09, 0x31, /* Usage (31h), */ + 0x95, 0x03, /* Report Count (3), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x92, /* Report ID (146), */ + 0x09, 0x32, /* Usage (32h), */ + 0x95, 0x03, /* Report Count (3), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0x93, /* Report ID (147), */ + 0x09, 0x33, /* Usage (33h), */ + 0x95, 0x0C, /* Report Count (12), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xA0, /* Report ID (160), */ + 0x09, 0x40, /* Usage (40h), */ + 0x95, 0x06, /* Report Count (6), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xA1, /* Report ID (161), */ + 0x09, 0x41, /* Usage (41h), */ + 0x95, 0x01, /* Report Count (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xA2, /* Report ID (162), */ + 0x09, 0x42, /* Usage (42h), */ + 0x95, 0x01, /* Report Count (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xA3, /* Report ID (163), */ + 0x09, 0x43, /* Usage (43h), */ + 0x95, 0x30, /* Report Count (48), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xA4, /* Report ID (164), */ + 0x09, 0x44, /* Usage (44h), */ + 0x95, 0x0D, /* Report Count (13), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xA5, /* Report ID (165), */ + 0x09, 0x45, /* Usage (45h), */ + 0x95, 0x15, /* Report Count (21), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xA6, /* Report ID (166), */ + 0x09, 0x46, /* Usage (46h), */ + 0x95, 0x15, /* Report Count (21), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xF0, /* Report ID (240), */ + 0x09, 0x47, /* Usage (47h), */ + 0x95, 0x3F, /* Report Count (63), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xF1, /* Report ID (241), */ + 0x09, 0x48, /* Usage (48h), */ + 0x95, 0x3F, /* Report Count (63), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xF2, /* Report ID (242), */ + 0x09, 0x49, /* Usage (49h), */ + 0x95, 0x0F, /* Report Count (15), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xA7, /* Report ID (167), */ + 0x09, 0x4A, /* Usage (4Ah), */ + 0x95, 0x01, /* Report Count (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xA8, /* Report ID (168), */ + 0x09, 0x4B, /* Usage (4Bh), */ + 0x95, 0x01, /* Report Count (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xA9, /* Report ID (169), */ + 0x09, 0x4C, /* Usage (4Ch), */ + 0x95, 0x08, /* Report Count (8), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xAA, /* Report ID (170), */ + 0x09, 0x4E, /* Usage (4Eh), */ + 0x95, 0x01, /* Report Count (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xAB, /* Report ID (171), */ + 0x09, 0x4F, /* Usage (4Fh), */ + 0x95, 0x39, /* Report Count (57), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xAC, /* Report ID (172), */ + 0x09, 0x50, /* Usage (50h), */ + 0x95, 0x39, /* Report Count (57), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xAD, /* Report ID (173), */ + 0x09, 0x51, /* Usage (51h), */ + 0x95, 0x0B, /* Report Count (11), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xAE, /* Report ID (174), */ + 0x09, 0x52, /* Usage (52h), */ + 0x95, 0x01, /* Report Count (1), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xAF, /* Report ID (175), */ + 0x09, 0x53, /* Usage (53h), */ + 0x95, 0x02, /* Report Count (2), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0x85, 0xB0, /* Report ID (176), */ + 0x09, 0x54, /* Usage (54h), */ + 0x95, 0x3F, /* Report Count (63), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0 /* End Collection */ +}; + static __u8 ps3remote_rdesc[] = { 0x05, 0x01, /* GUsagePage Generic Desktop */ 0x09, 0x05, /* LUsage 0x05 [Game Pad] */ @@ -223,21 +488,19 @@ static const unsigned int buzz_keymap[] = { }; struct sony_sc { + struct hid_device *hdev; + struct led_classdev *leds[MAX_LEDS]; + struct hid_report *output_report; unsigned long quirks; + struct work_struct state_worker; #ifdef CONFIG_SONY_FF - struct work_struct rumble_worker; - struct hid_device *hdev; __u8 left; __u8 right; #endif - void *extra; -}; - -struct buzz_extra { - int led_state; - struct led_classdev *leds[4]; + __u8 led_state[MAX_LEDS]; + __u8 led_count; }; static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc, @@ -304,6 +567,17 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[55] = 0x06; } + /* + * The default Dualshock 4 USB descriptor doesn't assign + * the gyroscope values to corresponding axes so we need a + * modified one. + */ + if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && *rsize == 467) { + hid_info(hdev, "Using modified Dualshock 4 report descriptor with gyroscope axes\n"); + rdesc = dualshock4_usb_rdesc; + *rsize = sizeof(dualshock4_usb_rdesc); + } + /* The HID descriptor exposed over BT has a trailing zero byte */ if ((((sc->quirks & SIXAXIS_CONTROLLER_USB) && *rsize == 148) || ((sc->quirks & SIXAXIS_CONTROLLER_BT) && *rsize == 149)) && @@ -448,7 +722,7 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev) return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); } -static void buzz_set_leds(struct hid_device *hdev, int leds) +static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds) { struct list_head *report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list; @@ -457,67 +731,76 @@ static void buzz_set_leds(struct hid_device *hdev, int leds) __s32 *value = report->field[0]->value; value[0] = 0x00; - value[1] = (leds & 1) ? 0xff : 0x00; - value[2] = (leds & 2) ? 0xff : 0x00; - value[3] = (leds & 4) ? 0xff : 0x00; - value[4] = (leds & 8) ? 0xff : 0x00; + value[1] = leds[0] ? 0xff : 0x00; + value[2] = leds[1] ? 0xff : 0x00; + value[3] = leds[2] ? 0xff : 0x00; + value[4] = leds[3] ? 0xff : 0x00; value[5] = 0x00; value[6] = 0x00; hid_hw_request(hdev, report, HID_REQ_SET_REPORT); } -static void buzz_led_set_brightness(struct led_classdev *led, +static void sony_set_leds(struct hid_device *hdev, const __u8 *leds, int count) +{ + struct sony_sc *drv_data = hid_get_drvdata(hdev); + int n; + + BUG_ON(count > MAX_LEDS); + + if (drv_data->quirks & BUZZ_CONTROLLER && count == 4) { + buzz_set_leds(hdev, leds); + } else if ((drv_data->quirks & SIXAXIS_CONTROLLER_USB) || + (drv_data->quirks & DUALSHOCK4_CONTROLLER_USB)) { + for (n = 0; n < count; n++) + drv_data->led_state[n] = leds[n]; + schedule_work(&drv_data->state_worker); + } +} + +static void sony_led_set_brightness(struct led_classdev *led, enum led_brightness value) { struct device *dev = led->dev->parent; struct hid_device *hdev = container_of(dev, struct hid_device, dev); struct sony_sc *drv_data; - struct buzz_extra *buzz; int n; drv_data = hid_get_drvdata(hdev); - if (!drv_data || !drv_data->extra) { + if (!drv_data) { hid_err(hdev, "No device data\n"); return; } - buzz = drv_data->extra; - - for (n = 0; n < 4; n++) { - if (led == buzz->leds[n]) { - int on = !! (buzz->led_state & (1 << n)); - if (value == LED_OFF && on) { - buzz->led_state &= ~(1 << n); - buzz_set_leds(hdev, buzz->led_state); - } else if (value != LED_OFF && !on) { - buzz->led_state |= (1 << n); - buzz_set_leds(hdev, buzz->led_state); + + for (n = 0; n < drv_data->led_count; n++) { + if (led == drv_data->leds[n]) { + if (value != drv_data->led_state[n]) { + drv_data->led_state[n] = value; + sony_set_leds(hdev, drv_data->led_state, drv_data->led_count); } break; } } } -static enum led_brightness buzz_led_get_brightness(struct led_classdev *led) +static enum led_brightness sony_led_get_brightness(struct led_classdev *led) { struct device *dev = led->dev->parent; struct hid_device *hdev = container_of(dev, struct hid_device, dev); struct sony_sc *drv_data; - struct buzz_extra *buzz; int n; int on = 0; drv_data = hid_get_drvdata(hdev); - if (!drv_data || !drv_data->extra) { + if (!drv_data) { hid_err(hdev, "No device data\n"); return LED_OFF; } - buzz = drv_data->extra; - for (n = 0; n < 4; n++) { - if (led == buzz->leds[n]) { - on = !! (buzz->led_state & (1 << n)); + for (n = 0; n < drv_data->led_count; n++) { + if (led == drv_data->leds[n]) { + on = !!(drv_data->led_state[n]); break; } } @@ -525,110 +808,122 @@ static enum led_brightness buzz_led_get_brightness(struct led_classdev *led) return on ? LED_FULL : LED_OFF; } -static int buzz_init(struct hid_device *hdev) +static void sony_leds_remove(struct hid_device *hdev) +{ + struct sony_sc *drv_data; + struct led_classdev *led; + int n; + + drv_data = hid_get_drvdata(hdev); + BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT)); + + for (n = 0; n < drv_data->led_count; n++) { + led = drv_data->leds[n]; + drv_data->leds[n] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + + drv_data->led_count = 0; +} + +static int sony_leds_init(struct hid_device *hdev) { struct sony_sc *drv_data; - struct buzz_extra *buzz; int n, ret = 0; + int max_brightness; + int use_colors; struct led_classdev *led; size_t name_sz; char *name; + size_t name_len; + const char *name_fmt; + static const char * const color_str[] = { "red", "green", "blue" }; + static const __u8 initial_values[MAX_LEDS] = { 0x00, 0x00, 0x00, 0x00 }; drv_data = hid_get_drvdata(hdev); - BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER)); - - /* Validate expected report characteristics. */ - if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7)) - return -ENODEV; - - buzz = kzalloc(sizeof(*buzz), GFP_KERNEL); - if (!buzz) { - hid_err(hdev, "Insufficient memory, cannot allocate driver data\n"); - return -ENOMEM; + BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT)); + + if (drv_data->quirks & BUZZ_CONTROLLER) { + drv_data->led_count = 4; + max_brightness = 1; + use_colors = 0; + name_len = strlen("::buzz#"); + name_fmt = "%s::buzz%d"; + /* Validate expected report characteristics. */ + if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7)) + return -ENODEV; + } else if (drv_data->quirks & DUALSHOCK4_CONTROLLER_USB) { + drv_data->led_count = 3; + max_brightness = 255; + use_colors = 1; + name_len = 0; + name_fmt = "%s:%s"; + } else { + drv_data->led_count = 4; + max_brightness = 1; + use_colors = 0; + name_len = strlen("::sony#"); + name_fmt = "%s::sony%d"; } - drv_data->extra = buzz; /* Clear LEDs as we have no way of reading their initial state. This is * only relevant if the driver is loaded after somebody actively set the * LEDs to on */ - buzz_set_leds(hdev, 0x00); + sony_set_leds(hdev, initial_values, drv_data->led_count); - name_sz = strlen(dev_name(&hdev->dev)) + strlen("::buzz#") + 1; + name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1; + + for (n = 0; n < drv_data->led_count; n++) { + + if (use_colors) + name_sz = strlen(dev_name(&hdev->dev)) + strlen(color_str[n]) + 2; - for (n = 0; n < 4; n++) { led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL); if (!led) { hid_err(hdev, "Couldn't allocate memory for LED %d\n", n); + ret = -ENOMEM; goto error_leds; } name = (void *)(&led[1]); - snprintf(name, name_sz, "%s::buzz%d", dev_name(&hdev->dev), n + 1); + if (use_colors) + snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), color_str[n]); + else + snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1); led->name = name; led->brightness = 0; - led->max_brightness = 1; - led->brightness_get = buzz_led_get_brightness; - led->brightness_set = buzz_led_set_brightness; + led->max_brightness = max_brightness; + led->brightness_get = sony_led_get_brightness; + led->brightness_set = sony_led_set_brightness; - if (led_classdev_register(&hdev->dev, led)) { + ret = led_classdev_register(&hdev->dev, led); + if (ret) { hid_err(hdev, "Failed to register LED %d\n", n); kfree(led); goto error_leds; } - buzz->leds[n] = led; + drv_data->leds[n] = led; } return ret; error_leds: - for (n = 0; n < 4; n++) { - led = buzz->leds[n]; - buzz->leds[n] = NULL; - if (!led) - continue; - led_classdev_unregister(led); - kfree(led); - } + sony_leds_remove(hdev); - kfree(drv_data->extra); - drv_data->extra = NULL; return ret; } -static void buzz_remove(struct hid_device *hdev) -{ - struct sony_sc *drv_data; - struct buzz_extra *buzz; - struct led_classdev *led; - int n; - - drv_data = hid_get_drvdata(hdev); - BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER)); - - buzz = drv_data->extra; - - for (n = 0; n < 4; n++) { - led = buzz->leds[n]; - buzz->leds[n] = NULL; - if (!led) - continue; - led_classdev_unregister(led); - kfree(led); - } - - kfree(drv_data->extra); - drv_data->extra = NULL; -} - -#ifdef CONFIG_SONY_FF -static void sony_rumble_worker(struct work_struct *work) +static void sixaxis_state_worker(struct work_struct *work) { - struct sony_sc *sc = container_of(work, struct sony_sc, rumble_worker); + struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); unsigned char buf[] = { 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, @@ -636,13 +931,42 @@ static void sony_rumble_worker(struct work_struct *work) 0x00, 0x00, 0x00, 0x00, 0x00 }; - buf[3] = sc->right; +#ifdef CONFIG_SONY_FF + buf[3] = sc->right ? 1 : 0; buf[5] = sc->left; +#endif + + buf[10] |= sc->led_state[0] << 1; + buf[10] |= sc->led_state[1] << 2; + buf[10] |= sc->led_state[2] << 3; + buf[10] |= sc->led_state[3] << 4; sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf), HID_OUTPUT_REPORT); } +static void dualshock4_state_worker(struct work_struct *work) +{ + struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); + struct hid_device *hdev = sc->hdev; + struct hid_report *report = sc->output_report; + __s32 *value = report->field[0]->value; + + value[0] = 0x03; + +#ifdef CONFIG_SONY_FF + value[3] = sc->right; + value[4] = sc->left; +#endif + + value[5] = sc->led_state[0]; + value[6] = sc->led_state[1]; + value[7] = sc->led_state[2]; + + hid_hw_request(hdev, report, HID_REQ_SET_REPORT); +} + +#ifdef CONFIG_SONY_FF static int sony_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect) { @@ -653,9 +977,9 @@ static int sony_play_effect(struct input_dev *dev, void *data, return 0; sc->left = effect->u.rumble.strong_magnitude / 256; - sc->right = effect->u.rumble.weak_magnitude ? 1 : 0; + sc->right = effect->u.rumble.weak_magnitude / 256; - schedule_work(&sc->rumble_worker); + schedule_work(&sc->state_worker); return 0; } @@ -664,10 +988,6 @@ 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; - struct sony_sc *sc = hid_get_drvdata(hdev); - - sc->hdev = hdev; - INIT_WORK(&sc->rumble_worker, sony_rumble_worker); input_set_capability(input_dev, EV_FF, FF_RUMBLE); return input_ff_create_memless(input_dev, NULL, sony_play_effect); @@ -677,7 +997,7 @@ static void sony_destroy_ff(struct hid_device *hdev) { struct sony_sc *sc = hid_get_drvdata(hdev); - cancel_work_sync(&sc->rumble_worker); + cancel_work_sync(&sc->state_worker); } #else @@ -691,6 +1011,33 @@ static void sony_destroy_ff(struct hid_device *hdev) } #endif +static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size) +{ + struct list_head *head, *list; + struct hid_report *report; + struct hid_device *hdev = sc->hdev; + + list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list; + + list_for_each(head, list) { + report = list_entry(head, struct hid_report, list); + + if (report->id == req_id) { + if (report->size < req_size) { + hid_err(hdev, "Output report 0x%02x (%i bits) is smaller than requested size (%i bits)\n", + req_id, report->size, req_size); + return -EINVAL; + } + sc->output_report = report; + return 0; + } + } + + hid_err(hdev, "Unable to locate output report 0x%02x\n", req_id); + + return -EINVAL; +} + static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; @@ -706,6 +1053,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) sc->quirks = quirks; hid_set_drvdata(hdev, sc); + sc->hdev = hdev; ret = hid_parse(hdev); if (ret) { @@ -729,23 +1077,38 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) if (sc->quirks & SIXAXIS_CONTROLLER_USB) { hdev->hid_output_raw_report = sixaxis_usb_output_raw_report; ret = sixaxis_set_operational_usb(hdev); + INIT_WORK(&sc->state_worker, sixaxis_state_worker); } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) ret = sixaxis_set_operational_bt(hdev); - else if (sc->quirks & BUZZ_CONTROLLER) - ret = buzz_init(hdev); - else + else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { + /* Report 5 (31 bytes) is used to send data to the controller via USB */ + ret = sony_set_output_report(sc, 0x05, 248); + if (ret < 0) + goto err_stop; + + INIT_WORK(&sc->state_worker, dualshock4_state_worker); + } else { ret = 0; + } if (ret < 0) goto err_stop; + if (sc->quirks & SONY_LED_SUPPORT) { + ret = sony_leds_init(hdev); + if (ret < 0) + goto err_stop; + } + ret = sony_init_ff(hdev); if (ret < 0) goto err_stop; return 0; err_stop: + if (sc->quirks & SONY_LED_SUPPORT) + sony_leds_remove(hdev); hid_hw_stop(hdev); return ret; } @@ -754,8 +1117,8 @@ static void sony_remove(struct hid_device *hdev) { struct sony_sc *sc = hid_get_drvdata(hdev); - if (sc->quirks & BUZZ_CONTROLLER) - buzz_remove(hdev); + if (sc->quirks & SONY_LED_SUPPORT) + sony_leds_remove(hdev); sony_destroy_ff(hdev); @@ -785,6 +1148,11 @@ static const struct hid_device_id sony_devices[] = { /* Logitech Harmony Adapter for PS3 */ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3), .driver_data = PS3REMOTE }, + /* Sony Dualshock 4 controllers for PS4 */ + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER), + .driver_data = DUALSHOCK4_CONTROLLER_USB }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER), + .driver_data = DUALSHOCK4_CONTROLLER_BT }, { } }; MODULE_DEVICE_TABLE(hid, sony_devices); diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 6a6dd5c..cb0137b 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -6,7 +6,7 @@ * to work on raw hid events as they want to, and avoids a need to * use a transport-specific userspace libhid/libusb libraries. * - * Copyright (c) 2007 Jiri Kosina + * Copyright (c) 2007-2014 Jiri Kosina */ /* @@ -104,8 +104,11 @@ out: return ret; } -/* The first byte is expected to be a report number. - * This function is to be called with the minors_lock mutex held */ +/* + * The first byte of the report buffer is expected to be a report number. + * + * This function is to be called with the minors_lock mutex held. + */ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type) { unsigned int minor = iminor(file_inode(file)); @@ -157,7 +160,6 @@ out: return ret; } -/* the first byte is expected to be a report number */ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { ssize_t ret; @@ -168,12 +170,15 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t } -/* This function performs a Get_Report transfer over the control endpoint +/* + * This function performs a Get_Report transfer over the control endpoint * per section 7.2.1 of the HID specification, version 1.1. The first byte * of buffer is the report number to request, or 0x0 if the defice does not * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT - * or HID_INPUT_REPORT. This function is to be called with the minors_lock - * mutex held. */ + * or HID_INPUT_REPORT. + * + * This function is to be called with the minors_lock mutex held. + */ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type) { unsigned int minor = iminor(file_inode(file)); @@ -209,8 +214,10 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t goto out; } - /* Read the first byte from the user. This is the report number, - * which is passed to dev->hid_get_raw_report(). */ + /* + * Read the first byte from the user. This is the report number, + * which is passed to dev->hid_get_raw_report(). + */ if (copy_from_user(&report_number, buffer, 1)) { ret = -EFAULT; goto out_free; @@ -498,7 +505,7 @@ int hidraw_connect(struct hid_device *hid) int minor, result; struct hidraw *dev; - /* we accept any HID device, no matter the applications */ + /* we accept any HID device, all applications */ dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL); if (!dev) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 5f7e55f..e914f27 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -1061,6 +1061,7 @@ static int i2c_hid_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); + disable_irq(client->irq); if (device_may_wakeup(&client->dev)) enable_irq_wake(client->irq); @@ -1075,6 +1076,7 @@ static int i2c_hid_resume(struct device *dev) int ret; struct i2c_client *client = to_i2c_client(dev); + enable_irq(client->irq); ret = i2c_hid_hwreset(client); if (ret) return ret; diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 0db9a67..175ec0a 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -84,8 +84,10 @@ static const struct hid_blacklist { { 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_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_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH, 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_2, HID_QUIRK_NOGET }, @@ -114,7 +116,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_SIS, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD, HID_QUIRK_NO_INIT_REPORTS }, { 0, 0 } }; diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index 7960869..9a332e6 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c @@ -146,7 +146,7 @@ static void usb_kbd_irq(struct urb *urb) input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1); else hid_info(urb->dev, - "Unknown key (scancode %#x) released.\n", + "Unknown key (scancode %#x) pressed.\n", kbd->new[i]); } } |