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 ...
This commit is contained in:
commit
4988abf174
|
@ -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));
|
||||
|
||||
/* 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;
|
||||
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)
|
||||
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,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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue