Commit 4988abf1 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:

 - 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
  ...
parents fe41c2c0 62813858
......@@ -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.
......
......@@ -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) },
......
......@@ -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",
......
......@@ -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,
......
......@@ -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
......@@ -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);
......
......@@ -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 },
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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,
......
......@@ -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,
......
......@@ -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));
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;
buzz = kzalloc(sizeof(*buzz), GFP_KERNEL);
if (!buzz) {
hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
return -ENOMEM;
} 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)) + name_len + 1;
name_sz = strlen(dev_name(&hdev->dev)) + strlen("::buzz#") + 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)
static void sixaxis_state_worker(struct work_struct *work)
{
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)
{
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,16 +1077,29 @@ 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)
......@@ -746,6 +1107,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
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);
......
......@@ -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 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
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 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
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)
......
......@@ -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;
......
......@@ -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 }
};
......
......@@ -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]);
}
}
......
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