From 765a1077c85e5f2efcc43582f80caf43a052e903 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Wed, 8 Feb 2017 13:58:43 -0500 Subject: HID: sony: Use LED_CORE_SUSPENDRESUME The LED subsystem provides the LED_CORE_SUSPENDRESUME flag to handle automatically turning off and restoring the state of device LEDs during suspend/resume. Use this flag instead of saving and restoring the state locally. Signed-off-by: Frank Praznik Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index f405b07d0381..7e2bae309671 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1095,7 +1095,6 @@ struct sony_sc { u8 battery_charging; u8 battery_capacity; u8 led_state[MAX_LEDS]; - u8 resume_led_state[MAX_LEDS]; u8 led_delay_on[MAX_LEDS]; u8 led_delay_off[MAX_LEDS]; u8 led_count; @@ -1964,6 +1963,7 @@ static int sony_leds_init(struct sony_sc *sc) led->name = name; led->brightness = sc->led_state[n]; led->max_brightness = max_brightness[n]; + led->flags = LED_CORE_SUSPENDRESUME; led->brightness_get = sony_led_get_brightness; led->brightness_set = sony_led_set_brightness; @@ -2734,47 +2734,32 @@ static void sony_remove(struct hid_device *hdev) static int sony_suspend(struct hid_device *hdev, pm_message_t message) { - /* - * On suspend save the current LED state, - * stop running force-feedback and blank the LEDS. - */ - if (SONY_LED_SUPPORT || SONY_FF_SUPPORT) { - struct sony_sc *sc = hid_get_drvdata(hdev); - #ifdef CONFIG_SONY_FF - sc->left = sc->right = 0; -#endif - memcpy(sc->resume_led_state, sc->led_state, - sizeof(sc->resume_led_state)); - memset(sc->led_state, 0, sizeof(sc->led_state)); + /* On suspend stop any running force-feedback events */ + if (SONY_FF_SUPPORT) { + struct sony_sc *sc = hid_get_drvdata(hdev); + sc->left = sc->right = 0; sony_send_output_report(sc); } +#endif return 0; } static int sony_resume(struct hid_device *hdev) { - /* Restore the state of controller LEDs on resume */ - if (SONY_LED_SUPPORT) { - struct sony_sc *sc = hid_get_drvdata(hdev); - - memcpy(sc->led_state, sc->resume_led_state, - sizeof(sc->led_state)); - - /* - * The Sixaxis and navigation controllers on USB need to be - * reinitialized on resume or they won't behave properly. - */ - if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || - (sc->quirks & NAVIGATION_CONTROLLER_USB)) { - sixaxis_set_operational_usb(sc->hdev); - sc->defer_initialization = 1; - } + struct sony_sc *sc = hid_get_drvdata(hdev); - sony_set_leds(sc); + /* + * The Sixaxis and navigation controllers on USB need to be + * reinitialized on resume or they won't behave properly. + */ + if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || + (sc->quirks & NAVIGATION_CONTROLLER_USB)) { + sixaxis_set_operational_usb(sc->hdev); + sc->defer_initialization = 1; } return 0; -- cgit v1.2.3 From 227c011b2e046dd4d36d9e00e3d9c88097b2a4c3 Mon Sep 17 00:00:00 2001 From: Roderick Colenbrander Date: Tue, 7 Mar 2017 15:45:00 -0800 Subject: HID: sony: Report DS4 motion sensors through a separate device The DS4 motion sensors are currently mapped by the hid-core driver to non-existing axes in between ABS_MISC and ABS_MT_SLOT, because the device already exhausted ABS_X-ABS_RZ. For a part the mapping by hid-core is accomplished by a fixup in hid-sony as the motion axes actually use vendor specific usage pages. This patch makes the DS4 use a separate input device for the motion sensors and reports acceleration data through ABS_X-ABS_Z and gyroscope data through ABS_RX-ABS_RZ. In addition it extends the event spec to allow gyroscope data through ABS_RX-ABS_RZ when INPUT_PROP_ACCELEROMETER is set. This change was suggested by Peter Hutterer during a discussion on linux-input. [jkosina@suse.cz: rebase onto slightly newer codebase] Signed-off-by: Roderick Colenbrander Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 397 +++++++++++++------------------------------------ 1 file changed, 105 insertions(+), 292 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 7e2bae309671..17df165133ab 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -344,265 +344,6 @@ static u8 navigation_rdesc[] = { 0xC0 /* End Collection */ }; -/* - * 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, 0x0D, /* Usage Maximum (0Dh), */ - 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, 0x3F, /* Logical Maximum (63), */ - 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, 0xFF, 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, 0x00, 0x80, /* Logical Minimum (-32768), */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x09, 0x21, /* Usage (21h), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* 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 */ -}; /* * The default behavior of the Dualshock 4 is to send reports using report @@ -706,31 +447,10 @@ static u8 dualshock4_bt_rdesc[] = { 0x75, 0x08, /* Report Size (8), */ 0x95, 0x02, /* Report Count (2), */ 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x09, 0x20, /* Usage (20h), */ - 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, 0xFF, 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, 0x00, 0x80, /* Logical Minimum (-32768), */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */ - 0x95, 0x03, /* Report Count (3), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x09, 0x20, /* Usage (20h), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x31, /* Report Count (51), */ - 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h) */ + 0x09, 0x21, /* Usage (0x21) */ + 0x95, 0x42, /* Report Count (66) */ + 0x81, 0x02, /* Input (Variable) */ 0x09, 0x21, /* Usage (21h), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x4D, /* Report Count (77), */ @@ -1060,9 +780,11 @@ struct motion_output_report_02 { * additional +2. */ #define DS4_INPUT_REPORT_BUTTON_OFFSET 5 +#define DS4_INPUT_REPORT_GYRO_X_OFFSET 13 #define DS4_INPUT_REPORT_BATTERY_OFFSET 30 #define DS4_INPUT_REPORT_TOUCHPAD_OFFSET 33 +#define DS4_SENSOR_SUFFIX " Motion Sensors" #define DS4_TOUCHPAD_SUFFIX " Touchpad" static DEFINE_SPINLOCK(sony_dev_list_lock); @@ -1074,6 +796,7 @@ struct sony_sc { struct list_head list_node; struct hid_device *hdev; struct input_dev *touchpad; + struct input_dev *sensor_dev; struct led_classdev *leds[MAX_LEDS]; unsigned long quirks; struct work_struct state_worker; @@ -1227,15 +950,11 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc, } /* - * The default Dualshock 4 USB descriptor doesn't assign - * the gyroscope values to corresponding axes so we need a - * modified one. + * The default Dualshock 4 BT descriptor doesn't describe report ID 17 + * which is most often used for input data. Add this mapping, so we + * use the generic hid code for parsing the buttons and axes. */ - if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { - hid_info(hdev, "Using modified Dualshock 4 report descriptor with gyroscope axes\n"); - rdesc = dualshock4_usb_rdesc; - *rsize = sizeof(dualshock4_usb_rdesc); - } else if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) { + if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) { hid_info(hdev, "Using modified Dualshock 4 Bluetooth report descriptor\n"); rdesc = dualshock4_bt_rdesc; *rsize = sizeof(dualshock4_bt_rdesc); @@ -1295,6 +1014,9 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) int n, m, offset, num_touch_data, max_touch_data; u8 cable_state, battery_capacity, battery_charging; + /* Order of hw axes is gyro first, then accelerometer. */ + int axes[6] = {ABS_RX, ABS_RY, ABS_RZ, ABS_X, ABS_Y, ABS_Z}; + /* When using Bluetooth the header is 2 bytes longer, so skip these. */ int data_offset = (sc->quirks & DUALSHOCK4_CONTROLLER_USB) ? 0 : 2; @@ -1302,6 +1024,14 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) offset = data_offset + DS4_INPUT_REPORT_BUTTON_OFFSET; input_report_key(sc->touchpad, BTN_LEFT, rd[offset+2] & 0x2); + offset = data_offset + DS4_INPUT_REPORT_GYRO_X_OFFSET; + for (n = 0; n < 6; n++, offset += 2) { + short value = get_unaligned_le16(&rd[offset]); + + input_report_abs(sc->sensor_dev, axes[n], value); + } + input_sync(sc->sensor_dev); + /* * The lower 4 bits of byte 30 (or 32 for BT) contain the battery level * and the 5th bit contains the USB cable state. @@ -1580,6 +1310,76 @@ static void sony_unregister_touchpad(struct sony_sc *sc) sc->touchpad = NULL; } +static int sony_register_sensors(struct sony_sc *sc) +{ + size_t name_sz; + char *name; + int ret; + + sc->sensor_dev = input_allocate_device(); + if (!sc->sensor_dev) + return -ENOMEM; + + input_set_drvdata(sc->sensor_dev, sc); + sc->sensor_dev->dev.parent = &sc->hdev->dev; + sc->sensor_dev->phys = sc->hdev->phys; + sc->sensor_dev->uniq = sc->hdev->uniq; + sc->sensor_dev->id.bustype = sc->hdev->bus; + sc->sensor_dev->id.vendor = sc->hdev->vendor; + sc->sensor_dev->id.product = sc->hdev->product; + sc->sensor_dev->id.version = sc->hdev->version; + + /* Append a suffix to the controller name as there are various + * DS4 compatible non-Sony devices with different names. + */ + name_sz = strlen(sc->hdev->name) + sizeof(DS4_SENSOR_SUFFIX); + name = kzalloc(name_sz, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto err; + } + snprintf(name, name_sz, "%s" DS4_SENSOR_SUFFIX, sc->hdev->name); + sc->sensor_dev->name = name; + + input_set_abs_params(sc->sensor_dev, ABS_X, -32768, 32767, 0, 0); + input_set_abs_params(sc->sensor_dev, ABS_Y, -32768, 32767, 0, 0); + input_set_abs_params(sc->sensor_dev, ABS_Z, -32768, 32767, 0, 0); + + input_set_abs_params(sc->sensor_dev, ABS_RX, -32768, 32767, 0, 0); + input_set_abs_params(sc->sensor_dev, ABS_RY, -32768, 32767, 0, 0); + input_set_abs_params(sc->sensor_dev, ABS_RZ, -32768, 32767, 0, 0); + + __set_bit(INPUT_PROP_ACCELEROMETER, sc->sensor_dev->propbit); + + ret = input_register_device(sc->sensor_dev); + if (ret < 0) + goto err; + + return 0; + +err: + kfree(sc->sensor_dev->name); + sc->sensor_dev->name = NULL; + + input_free_device(sc->sensor_dev); + sc->sensor_dev = NULL; + + return ret; +} + +static void sony_unregister_sensors(struct sony_sc *sc) +{ + if (!sc->sensor_dev) + return; + + kfree(sc->sensor_dev->name); + sc->sensor_dev->name = NULL; + + input_unregister_device(sc->sensor_dev); + sc->sensor_dev = NULL; +} + + /* * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller * to "operational". Without this, the ps3 controller will not report any @@ -2585,6 +2385,13 @@ static int sony_input_configured(struct hid_device *hdev, goto err_stop; } + ret = sony_register_sensors(sc); + if (ret) { + hid_err(sc->hdev, + "Unable to initialize motion sensors: %d\n", ret); + goto err_stop; + } + sony_init_output_report(sc, dualshock4_send_output_report); } else if (sc->quirks & MOTION_CONTROLLER) { sony_init_output_report(sc, motion_send_output_report); @@ -2719,6 +2526,12 @@ static void sony_remove(struct hid_device *hdev) if (sc->touchpad) sony_unregister_touchpad(sc); + if (sc->sensor_dev) + sony_unregister_sensors(sc); + + if (sc->sensor_dev) + sony_unregister_sensors(sc); + sony_cancel_work_sync(sc); kfree(sc->output_report_dmabuf); -- cgit v1.2.3 From 55a07d62db0feda2e37f6962a1b2799e2a8b42ba Mon Sep 17 00:00:00 2001 From: Roderick Colenbrander Date: Tue, 7 Mar 2017 15:45:01 -0800 Subject: HID: sony: Calibrate DS4 motion sensors The DS4 motion sensors require calibration for accurate operation. This patch adds calibration for both the accelerometer and the gyroscope. Calibration requires reading device specific scaling factors and offsets. For precision reasons we store these values as a numerator and denominator and apply the values when processing the data. Signed-off-by: Roderick Colenbrander Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 212 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 184 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 17df165133ab..fedaebe0363f 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -768,6 +768,7 @@ struct motion_output_report_02 { }; #define DS4_FEATURE_REPORT_0x02_SIZE 37 +#define DS4_FEATURE_REPORT_0x05_SIZE 41 #define DS4_FEATURE_REPORT_0x81_SIZE 7 #define DS4_INPUT_REPORT_0x11_SIZE 78 #define DS4_OUTPUT_REPORT_0x05_SIZE 32 @@ -787,10 +788,25 @@ struct motion_output_report_02 { #define DS4_SENSOR_SUFFIX " Motion Sensors" #define DS4_TOUCHPAD_SUFFIX " Touchpad" +#define DS4_GYRO_RES_PER_DEG_S 1024 +#define DS4_ACC_RES_PER_G 8192 + static DEFINE_SPINLOCK(sony_dev_list_lock); static LIST_HEAD(sony_device_list); static DEFINE_IDA(sony_device_id_allocator); +/* Used for calibration of DS4 accelerometer and gyro. */ +struct ds4_calibration_data { + int abs_code; + short bias; + /* Calibration requires scaling against a sensitivity value, which is a + * float. Store sensitivity as a fraction to limit floating point + * calculations until final calibration. + */ + int sens_numer; + int sens_denom; +}; + struct sony_sc { spinlock_t lock; struct list_head list_node; @@ -822,6 +838,8 @@ struct sony_sc { u8 led_delay_off[MAX_LEDS]; u8 led_count; bool ds4_dongle_connected; + /* DS4 calibration data */ + struct ds4_calibration_data ds4_calib_data[6]; }; static void sony_set_leds(struct sony_sc *sc); @@ -1014,9 +1032,6 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) int n, m, offset, num_touch_data, max_touch_data; u8 cable_state, battery_capacity, battery_charging; - /* Order of hw axes is gyro first, then accelerometer. */ - int axes[6] = {ABS_RX, ABS_RY, ABS_RZ, ABS_X, ABS_Y, ABS_Z}; - /* When using Bluetooth the header is 2 bytes longer, so skip these. */ int data_offset = (sc->quirks & DUALSHOCK4_CONTROLLER_USB) ? 0 : 2; @@ -1025,10 +1040,22 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) input_report_key(sc->touchpad, BTN_LEFT, rd[offset+2] & 0x2); offset = data_offset + DS4_INPUT_REPORT_GYRO_X_OFFSET; - for (n = 0; n < 6; n++, offset += 2) { - short value = get_unaligned_le16(&rd[offset]); + for (n = 0; n < 6; n++) { + /* Store data in int for more precision during mult_frac. */ + int raw_data = (short)((rd[offset+1] << 8) | rd[offset]); + struct ds4_calibration_data *calib = &sc->ds4_calib_data[n]; + + /* High precision is needed during calibration, but the + * calibrated values are within 32-bit. + * Note: we swap numerator 'x' and 'numer' in mult_frac for + * precision reasons so we don't need 64-bit. + */ + int calib_data = mult_frac(calib->sens_numer, + raw_data - calib->bias, + calib->sens_denom); - input_report_abs(sc->sensor_dev, axes[n], value); + input_report_abs(sc->sensor_dev, calib->abs_code, calib_data); + offset += 2; } input_sync(sc->sensor_dev); @@ -1315,6 +1342,7 @@ static int sony_register_sensors(struct sony_sc *sc) size_t name_sz; char *name; int ret; + int range; sc->sensor_dev = input_allocate_device(); if (!sc->sensor_dev) @@ -1341,13 +1369,21 @@ static int sony_register_sensors(struct sony_sc *sc) snprintf(name, name_sz, "%s" DS4_SENSOR_SUFFIX, sc->hdev->name); sc->sensor_dev->name = name; - input_set_abs_params(sc->sensor_dev, ABS_X, -32768, 32767, 0, 0); - input_set_abs_params(sc->sensor_dev, ABS_Y, -32768, 32767, 0, 0); - input_set_abs_params(sc->sensor_dev, ABS_Z, -32768, 32767, 0, 0); - - input_set_abs_params(sc->sensor_dev, ABS_RX, -32768, 32767, 0, 0); - input_set_abs_params(sc->sensor_dev, ABS_RY, -32768, 32767, 0, 0); - input_set_abs_params(sc->sensor_dev, ABS_RZ, -32768, 32767, 0, 0); + range = DS4_ACC_RES_PER_G*4; + input_set_abs_params(sc->sensor_dev, ABS_X, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_Y, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_Z, -range, range, 16, 0); + input_abs_set_res(sc->sensor_dev, ABS_X, DS4_ACC_RES_PER_G); + input_abs_set_res(sc->sensor_dev, ABS_Y, DS4_ACC_RES_PER_G); + input_abs_set_res(sc->sensor_dev, ABS_Z, DS4_ACC_RES_PER_G); + + range = DS4_GYRO_RES_PER_DEG_S*2048; + input_set_abs_params(sc->sensor_dev, ABS_RX, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_RY, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_RZ, -range, range, 16, 0); + input_abs_set_res(sc->sensor_dev, ABS_RX, DS4_GYRO_RES_PER_DEG_S); + input_abs_set_res(sc->sensor_dev, ABS_RY, DS4_GYRO_RES_PER_DEG_S); + input_abs_set_res(sc->sensor_dev, ABS_RZ, DS4_GYRO_RES_PER_DEG_S); __set_bit(INPUT_PROP_ACCELEROMETER, sc->sensor_dev->propbit); @@ -1445,23 +1481,145 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev) } /* - * Requesting feature report 0x02 in Bluetooth mode changes the state of the - * controller so that it sends full input reports of type 0x11. + * Request DS4 calibration data for the motion sensors. + * For Bluetooth this also affects the operating mode (see below). */ -static int dualshock4_set_operational_bt(struct hid_device *hdev) +static int dualshock4_get_calibration_data(struct sony_sc *sc) { u8 *buf; int ret; + short gyro_pitch_bias, gyro_pitch_plus, gyro_pitch_minus; + short gyro_yaw_bias, gyro_yaw_plus, gyro_yaw_minus; + short gyro_roll_bias, gyro_roll_plus, gyro_roll_minus; + short gyro_speed_plus, gyro_speed_minus; + short acc_x_plus, acc_x_minus; + short acc_y_plus, acc_y_minus; + short acc_z_plus, acc_z_minus; + int speed_2x; + int range_2g; + + /* For Bluetooth we use a different request, which supports CRC. + * Note: in Bluetooth mode feature report 0x02 also changes the state + * of the controller, so that it sends input reports of type 0x11. + */ + if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { + buf = kmalloc(DS4_FEATURE_REPORT_0x02_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; - buf = kmalloc(DS4_FEATURE_REPORT_0x02_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; + ret = hid_hw_raw_request(sc->hdev, 0x02, buf, + DS4_FEATURE_REPORT_0x02_SIZE, + HID_FEATURE_REPORT, + HID_REQ_GET_REPORT); + if (ret < 0) + goto err_stop; + } else { + u8 bthdr = 0xA3; + u32 crc; + u32 report_crc; + int retries; - ret = hid_hw_raw_request(hdev, 0x02, buf, DS4_FEATURE_REPORT_0x02_SIZE, - HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + buf = kmalloc(DS4_FEATURE_REPORT_0x05_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; - kfree(buf); + for (retries = 0; retries < 3; retries++) { + ret = hid_hw_raw_request(sc->hdev, 0x05, buf, + DS4_FEATURE_REPORT_0x05_SIZE, + HID_FEATURE_REPORT, + HID_REQ_GET_REPORT); + if (ret < 0) + goto err_stop; + /* CRC check */ + crc = crc32_le(0xFFFFFFFF, &bthdr, 1); + crc = ~crc32_le(crc, buf, DS4_FEATURE_REPORT_0x05_SIZE-4); + report_crc = get_unaligned_le32(&buf[DS4_FEATURE_REPORT_0x05_SIZE-4]); + if (crc != report_crc) { + hid_warn(sc->hdev, "DualShock 4 calibration report's CRC check failed, received crc 0x%0x != 0x%0x\n", + report_crc, crc); + if (retries < 2) { + hid_warn(sc->hdev, "Retrying DualShock 4 get calibration report request\n"); + continue; + } else { + ret = -EILSEQ; + goto err_stop; + } + } else { + break; + } + } + } + + gyro_pitch_bias = get_unaligned_le16(&buf[1]); + gyro_yaw_bias = get_unaligned_le16(&buf[3]); + gyro_roll_bias = get_unaligned_le16(&buf[5]); + if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { + gyro_pitch_plus = get_unaligned_le16(&buf[7]); + gyro_pitch_minus = get_unaligned_le16(&buf[9]); + gyro_yaw_plus = get_unaligned_le16(&buf[11]); + gyro_yaw_minus = get_unaligned_le16(&buf[13]); + gyro_roll_plus = get_unaligned_le16(&buf[15]); + gyro_roll_minus = get_unaligned_le16(&buf[17]); + } else { + gyro_pitch_plus = get_unaligned_le16(&buf[7]); + gyro_yaw_plus = get_unaligned_le16(&buf[9]); + gyro_roll_plus = get_unaligned_le16(&buf[11]); + gyro_pitch_minus = get_unaligned_le16(&buf[13]); + gyro_yaw_minus = get_unaligned_le16(&buf[15]); + gyro_roll_minus = get_unaligned_le16(&buf[17]); + } + gyro_speed_plus = get_unaligned_le16(&buf[19]); + gyro_speed_minus = get_unaligned_le16(&buf[21]); + acc_x_plus = get_unaligned_le16(&buf[23]); + acc_x_minus = get_unaligned_le16(&buf[25]); + acc_y_plus = get_unaligned_le16(&buf[27]); + acc_y_minus = get_unaligned_le16(&buf[29]); + acc_z_plus = get_unaligned_le16(&buf[31]); + acc_z_minus = get_unaligned_le16(&buf[33]); + + /* Set gyroscope calibration and normalization parameters. + * Data values will be normalized to 1/DS4_GYRO_RES_PER_DEG_S degree/s. + */ + speed_2x = (gyro_speed_plus + gyro_speed_minus); + sc->ds4_calib_data[0].abs_code = ABS_RX; + sc->ds4_calib_data[0].bias = gyro_pitch_bias; + sc->ds4_calib_data[0].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + sc->ds4_calib_data[0].sens_denom = gyro_pitch_plus - gyro_pitch_minus; + + sc->ds4_calib_data[1].abs_code = ABS_RY; + sc->ds4_calib_data[1].bias = gyro_yaw_bias; + sc->ds4_calib_data[1].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + sc->ds4_calib_data[1].sens_denom = gyro_yaw_plus - gyro_yaw_minus; + + sc->ds4_calib_data[2].abs_code = ABS_RZ; + sc->ds4_calib_data[2].bias = gyro_roll_bias; + sc->ds4_calib_data[2].sens_numer = speed_2x*DS4_GYRO_RES_PER_DEG_S; + sc->ds4_calib_data[2].sens_denom = gyro_roll_plus - gyro_roll_minus; + + /* Set accelerometer calibration and normalization parameters. + * Data values will be normalized to 1/DS4_ACC_RES_PER_G G. + */ + range_2g = acc_x_plus - acc_x_minus; + sc->ds4_calib_data[3].abs_code = ABS_X; + sc->ds4_calib_data[3].bias = acc_x_plus - range_2g / 2; + sc->ds4_calib_data[3].sens_numer = 2*DS4_ACC_RES_PER_G; + sc->ds4_calib_data[3].sens_denom = range_2g; + + range_2g = acc_y_plus - acc_y_minus; + sc->ds4_calib_data[4].abs_code = ABS_Y; + sc->ds4_calib_data[4].bias = acc_y_plus - range_2g / 2; + sc->ds4_calib_data[4].sens_numer = 2*DS4_ACC_RES_PER_G; + sc->ds4_calib_data[4].sens_denom = range_2g; + + range_2g = acc_z_plus - acc_z_minus; + sc->ds4_calib_data[5].abs_code = ABS_Z; + sc->ds4_calib_data[5].bias = acc_z_plus - range_2g / 2; + sc->ds4_calib_data[5].sens_numer = 2*DS4_ACC_RES_PER_G; + sc->ds4_calib_data[5].sens_denom = range_2g; + +err_stop: + kfree(buf); return ret; } @@ -2365,12 +2523,10 @@ static int sony_input_configured(struct hid_device *hdev, ret = sixaxis_set_operational_bt(hdev); sony_init_output_report(sc, sixaxis_send_output_report); } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { - if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) { - ret = dualshock4_set_operational_bt(hdev); - if (ret < 0) { - hid_err(hdev, "failed to set the Dualshock 4 operational mode\n"); - goto err_stop; - } + ret = dualshock4_get_calibration_data(sc); + if (ret < 0) { + hid_err(hdev, "Failed to get calibration data from Dualshock 4\n"); + goto err_stop; } /* -- cgit v1.2.3 From 80786eb9abebce64ec471de12d8ab3072834b333 Mon Sep 17 00:00:00 2001 From: Roderick Colenbrander Date: Tue, 7 Mar 2017 15:45:02 -0800 Subject: HID: sony: Report hardware timestamp for DS4 sensor values Report the hardware timestamp inside each HID report through MSC_TIMESTAMP for motion sensor values. Signed-off-by: Roderick Colenbrander Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index fedaebe0363f..dab4aefd841e 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -781,6 +781,7 @@ struct motion_output_report_02 { * additional +2. */ #define DS4_INPUT_REPORT_BUTTON_OFFSET 5 +#define DS4_INPUT_REPORT_TIMESTAMP_OFFSET 10 #define DS4_INPUT_REPORT_GYRO_X_OFFSET 13 #define DS4_INPUT_REPORT_BATTERY_OFFSET 30 #define DS4_INPUT_REPORT_TOUCHPAD_OFFSET 33 @@ -837,6 +838,11 @@ struct sony_sc { u8 led_delay_on[MAX_LEDS]; u8 led_delay_off[MAX_LEDS]; u8 led_count; + + bool timestamp_initialized; + u16 prev_timestamp; + unsigned int timestamp_us; + bool ds4_dongle_connected; /* DS4 calibration data */ struct ds4_calibration_data ds4_calib_data[6]; @@ -1031,6 +1037,7 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) unsigned long flags; int n, m, offset, num_touch_data, max_touch_data; u8 cable_state, battery_capacity, battery_charging; + u16 timestamp; /* When using Bluetooth the header is 2 bytes longer, so skip these. */ int data_offset = (sc->quirks & DUALSHOCK4_CONTROLLER_USB) ? 0 : 2; @@ -1039,6 +1046,24 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) offset = data_offset + DS4_INPUT_REPORT_BUTTON_OFFSET; input_report_key(sc->touchpad, BTN_LEFT, rd[offset+2] & 0x2); + /* Convert timestamp (in 5.33us unit) to timestamp_us */ + offset = data_offset + DS4_INPUT_REPORT_TIMESTAMP_OFFSET; + timestamp = get_unaligned_le16(&rd[offset]); + if (!sc->timestamp_initialized) { + sc->timestamp_us = ((unsigned int)timestamp * 16) / 3; + sc->timestamp_initialized = true; + } else { + u16 delta; + + if (sc->prev_timestamp > timestamp) + delta = (U16_MAX - sc->prev_timestamp + timestamp + 1); + else + delta = timestamp - sc->prev_timestamp; + sc->timestamp_us += (delta * 16) / 3; + } + sc->prev_timestamp = timestamp; + input_event(sc->sensor_dev, EV_MSC, MSC_TIMESTAMP, sc->timestamp_us); + offset = data_offset + DS4_INPUT_REPORT_GYRO_X_OFFSET; for (n = 0; n < 6; n++) { /* Store data in int for more precision during mult_frac. */ @@ -1385,6 +1410,8 @@ static int sony_register_sensors(struct sony_sc *sc) input_abs_set_res(sc->sensor_dev, ABS_RY, DS4_GYRO_RES_PER_DEG_S); input_abs_set_res(sc->sensor_dev, ABS_RZ, DS4_GYRO_RES_PER_DEG_S); + __set_bit(EV_MSC, sc->sensor_dev->evbit); + __set_bit(MSC_TIMESTAMP, sc->sensor_dev->mscbit); __set_bit(INPUT_PROP_ACCELEROMETER, sc->sensor_dev->propbit); ret = input_register_device(sc->sensor_dev); -- cgit v1.2.3 From d03ae2e1080026951376d787b96109169926a15c Mon Sep 17 00:00:00 2001 From: Roderick Colenbrander Date: Tue, 7 Mar 2017 15:45:03 -0800 Subject: HID: sony: Remove report descriptor fixup for DS4 The DS4 in BT mode sends initial input reports through report 1, which is described in the HID report descriptors. When activated after sending a certain feature report, the device uses report 17. Currently the hid-sony driver fixes up the BT HID report descriptors, so the HID layer can manage input reports for report 17. We think it is best to eliminate this fixup and do the handling ourselves, which is what this patch does. The main motivation is that there are various users of DS4 through hidraw, including various cross-platform applications/games, which have their own HID parsing across Linux/Win/OSX. Due to the fixup the descriptors differ, which is causing pain for many developers including major game publishers (who reached out privately). Without the fixup, the Windows titles also have a fighting chance for working on Wine, which provides HID support now. Overall it felt best because of these reasons to remove the fixup. Signed-off-by: Roderick Colenbrander Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 261 +++++++++++-------------------------------------- 1 file changed, 59 insertions(+), 202 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index dab4aefd841e..f9ff10bbc1ac 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -344,197 +344,6 @@ static u8 navigation_rdesc[] = { 0xC0 /* End Collection */ }; - -/* - * The default behavior of the Dualshock 4 is to send reports using report - * type 1 when running over Bluetooth. However, when feature report 2 is - * requested during the controller initialization it starts sending input - * reports in report 17. Since report 17 is undefined in the default HID - * descriptor the button and axis definitions must be moved to report 17 or - * the HID layer won't process the received input. - */ -static u8 dualshock4_bt_rdesc[] = { - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x05, /* Usage (Gamepad), */ - 0xA1, 0x01, /* Collection (Application), */ - 0x85, 0x01, /* Report ID (1), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x0A, /* Report Count (9), */ - 0x81, 0x02, /* Input (Variable), */ - 0x06, 0x04, 0xFF, /* Usage Page (FF04h), */ - 0x85, 0x02, /* Report ID (2), */ - 0x09, 0x24, /* Usage (24h), */ - 0x95, 0x24, /* Report Count (36), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA3, /* Report ID (163), */ - 0x09, 0x25, /* Usage (25h), */ - 0x95, 0x30, /* Report Count (48), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x05, /* Report ID (5), */ - 0x09, 0x26, /* Usage (26h), */ - 0x95, 0x28, /* Report Count (40), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x06, /* Report ID (6), */ - 0x09, 0x27, /* Usage (27h), */ - 0x95, 0x34, /* Report Count (52), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x07, /* Report ID (7), */ - 0x09, 0x28, /* Usage (28h), */ - 0x95, 0x30, /* Report Count (48), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x08, /* Report ID (8), */ - 0x09, 0x29, /* Usage (29h), */ - 0x95, 0x2F, /* Report Count (47), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x06, 0x03, 0xFF, /* Usage Page (FF03h), */ - 0x85, 0x03, /* Report ID (3), */ - 0x09, 0x21, /* Usage (21h), */ - 0x95, 0x26, /* Report Count (38), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x04, /* Report ID (4), */ - 0x09, 0x22, /* Usage (22h), */ - 0x95, 0x2E, /* Report Count (46), */ - 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, 0x11, /* Report ID (17), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x09, 0x20, /* Usage (20h), */ - 0x95, 0x02, /* Report Count (2), */ - 0x81, 0x02, /* Input (Variable), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 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), */ - 0x75, 0x04, /* Report Size (4), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x42, /* Input (Variable, Null State), */ - 0x05, 0x09, /* Usage Page (Button), */ - 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x0D, /* Usage Maximum (0Dh), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x0E, /* Report Count (14), */ - 0x81, 0x02, /* Input (Variable), */ - 0x75, 0x06, /* Report Size (6), */ - 0x95, 0x01, /* Report Count (1), */ - 0x81, 0x01, /* Input (Constant), */ - 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 (0x21) */ - 0x95, 0x42, /* Report Count (66) */ - 0x81, 0x02, /* Input (Variable) */ - 0x09, 0x21, /* Usage (21h), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x4D, /* Report Count (77), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x12, /* Report ID (18), */ - 0x09, 0x22, /* Usage (22h), */ - 0x95, 0x8D, /* Report Count (141), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x23, /* Usage (23h), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x13, /* Report ID (19), */ - 0x09, 0x24, /* Usage (24h), */ - 0x95, 0xCD, /* Report Count (205), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x25, /* Usage (25h), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x14, /* Report ID (20), */ - 0x09, 0x26, /* Usage (26h), */ - 0x96, 0x0D, 0x01, /* Report Count (269), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x27, /* Usage (27h), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x15, /* Report ID (21), */ - 0x09, 0x28, /* Usage (28h), */ - 0x96, 0x4D, 0x01, /* Report Count (333), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x29, /* Usage (29h), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x16, /* Report ID (22), */ - 0x09, 0x2A, /* Usage (2Ah), */ - 0x96, 0x8D, 0x01, /* Report Count (397), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x2B, /* Usage (2Bh), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x17, /* Report ID (23), */ - 0x09, 0x2C, /* Usage (2Ch), */ - 0x96, 0xCD, 0x01, /* Report Count (461), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x2D, /* Usage (2Dh), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x18, /* Report ID (24), */ - 0x09, 0x2E, /* Usage (2Eh), */ - 0x96, 0x0D, 0x02, /* Report Count (525), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x2F, /* Usage (2Fh), */ - 0x91, 0x02, /* Output (Variable), */ - 0x85, 0x19, /* Report ID (25), */ - 0x09, 0x30, /* Usage (30h), */ - 0x96, 0x22, 0x02, /* Report Count (546), */ - 0x81, 0x02, /* Input (Variable), */ - 0x09, 0x31, /* Usage (31h), */ - 0x91, 0x02, /* Output (Variable), */ - 0x06, 0x80, 0xFF, /* Usage Page (FF80h), */ - 0x85, 0x82, /* Report ID (130), */ - 0x09, 0x22, /* Usage (22h), */ - 0x95, 0x3F, /* Report Count (63), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x83, /* Report ID (131), */ - 0x09, 0x23, /* Usage (23h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x84, /* Report ID (132), */ - 0x09, 0x24, /* Usage (24h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x90, /* Report ID (144), */ - 0x09, 0x30, /* Usage (30h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x91, /* Report ID (145), */ - 0x09, 0x31, /* Usage (31h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x92, /* Report ID (146), */ - 0x09, 0x32, /* Usage (32h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0x93, /* Report ID (147), */ - 0x09, 0x33, /* Usage (33h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA0, /* Report ID (160), */ - 0x09, 0x40, /* Usage (40h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0x85, 0xA4, /* Report ID (164), */ - 0x09, 0x44, /* Usage (44h), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0 /* End Collection */ -}; - static u8 ps3remote_rdesc[] = { 0x05, 0x01, /* GUsagePage Generic Desktop */ 0x09, 0x05, /* LUsage 0x05 [Game Pad] */ @@ -722,6 +531,10 @@ static const unsigned int ds4_keymap[] = { [0xd] = BTN_MODE, /* PS */ }; +static const struct {int x; int y; } ds4_hat_mapping[] = { + {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, + {0, 0} +}; static enum power_supply_property sony_battery_props[] = { POWER_SUPPLY_PROP_PRESENT, @@ -780,6 +593,7 @@ struct motion_output_report_02 { /* Offsets relative to USB input report (0x1). Bluetooth (0x11) requires an * additional +2. */ +#define DS4_INPUT_REPORT_AXIS_OFFSET 1 #define DS4_INPUT_REPORT_BUTTON_OFFSET 5 #define DS4_INPUT_REPORT_TIMESTAMP_OFFSET 10 #define DS4_INPUT_REPORT_GYRO_X_OFFSET 13 @@ -973,17 +787,6 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc, rdesc[55] = 0x06; } - /* - * The default Dualshock 4 BT descriptor doesn't describe report ID 17 - * which is most often used for input data. Add this mapping, so we - * use the generic hid code for parsing the buttons and axes. - */ - if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) { - hid_info(hdev, "Using modified Dualshock 4 Bluetooth report descriptor\n"); - rdesc = dualshock4_bt_rdesc; - *rsize = sizeof(dualshock4_bt_rdesc); - } - if (sc->quirks & SIXAXIS_CONTROLLER) return sixaxis_fixup(hdev, rdesc, rsize); @@ -1034,6 +837,9 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size) static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) { + struct hid_input *hidinput = list_entry(sc->hdev->inputs.next, + struct hid_input, list); + struct input_dev *input_dev = hidinput->input; unsigned long flags; int n, m, offset, num_touch_data, max_touch_data; u8 cable_state, battery_capacity, battery_charging; @@ -1046,6 +852,57 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) offset = data_offset + DS4_INPUT_REPORT_BUTTON_OFFSET; input_report_key(sc->touchpad, BTN_LEFT, rd[offset+2] & 0x2); + /* + * The default behavior of the Dualshock 4 is to send reports using + * report type 1 when running over Bluetooth. However, when feature + * report 2 is requested during the controller initialization it starts + * sending input reports in report 17. Since report 17 is undefined + * in the default HID descriptor, the HID layer won't generate events. + * While it is possible (and this was done before) to fixup the HID + * descriptor to add this mapping, it was better to do this manually. + * The reason is there were various pieces software both open and closed + * source, relying on the descriptors to be the same across various + * operating systems. If the descriptors wouldn't match some + * applications e.g. games on Wine would not be able to function due + * to different descriptors, which such applications are not parsing. + */ + if (rd[0] == 17) { + int value; + + offset = data_offset + DS4_INPUT_REPORT_AXIS_OFFSET; + input_report_abs(input_dev, ABS_X, rd[offset]); + input_report_abs(input_dev, ABS_Y, rd[offset+1]); + input_report_abs(input_dev, ABS_RX, rd[offset+2]); + input_report_abs(input_dev, ABS_RY, rd[offset+3]); + + value = rd[offset+4] & 0xf; + if (value > 7) + value = 8; /* Center 0, 0 */ + input_report_abs(input_dev, ABS_HAT0X, ds4_hat_mapping[value].x); + input_report_abs(input_dev, ABS_HAT0Y, ds4_hat_mapping[value].y); + + input_report_key(input_dev, BTN_WEST, rd[offset+4] & 0x10); + input_report_key(input_dev, BTN_SOUTH, rd[offset+4] & 0x20); + input_report_key(input_dev, BTN_EAST, rd[offset+4] & 0x40); + input_report_key(input_dev, BTN_NORTH, rd[offset+4] & 0x80); + + input_report_key(input_dev, BTN_TL, rd[offset+5] & 0x1); + input_report_key(input_dev, BTN_TR, rd[offset+5] & 0x2); + input_report_key(input_dev, BTN_TL2, rd[offset+5] & 0x4); + input_report_key(input_dev, BTN_TR2, rd[offset+5] & 0x8); + input_report_key(input_dev, BTN_SELECT, rd[offset+5] & 0x10); + input_report_key(input_dev, BTN_START, rd[offset+5] & 0x20); + input_report_key(input_dev, BTN_THUMBL, rd[offset+5] & 0x40); + input_report_key(input_dev, BTN_THUMBR, rd[offset+5] & 0x80); + + input_report_key(input_dev, BTN_MODE, rd[offset+6] & 0x1); + + input_report_abs(input_dev, ABS_Z, rd[offset+7]); + input_report_abs(input_dev, ABS_RZ, rd[offset+8]); + + input_sync(input_dev); + } + /* Convert timestamp (in 5.33us unit) to timestamp_us */ offset = data_offset + DS4_INPUT_REPORT_TIMESTAMP_OFFSET; timestamp = get_unaligned_le16(&rd[offset]); -- cgit v1.2.3 From 35f436c31ea81d240ed53fe3467946e2a53032bb Mon Sep 17 00:00:00 2001 From: Roderick Colenbrander Date: Tue, 7 Mar 2017 15:45:04 -0800 Subject: HID: sony: Treat the ds4 dongle as a separate device This patch adds a new quirk, which allows us to differentiate between the DualShock 4 USB and the dongle. So far they have been treated the same, but handling of calibration data differs as the dongle behaves like Bluetooth, for other requests it behaves like USB. In addition this patches changes usb/dongle/bt handling in sony_raw_event, which makes the code cleaner to read. In addition another patch in this series will add more dongle logic, so this change paves the road for that. Signed-off-by: Roderick Colenbrander Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 99 ++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index f9ff10bbc1ac..98b1b7550745 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -48,19 +48,21 @@ #define PS3REMOTE BIT(4) #define DUALSHOCK4_CONTROLLER_USB BIT(5) #define DUALSHOCK4_CONTROLLER_BT BIT(6) -#define MOTION_CONTROLLER_USB BIT(7) -#define MOTION_CONTROLLER_BT BIT(8) -#define NAVIGATION_CONTROLLER_USB BIT(9) -#define NAVIGATION_CONTROLLER_BT BIT(10) -#define SINO_LITE_CONTROLLER BIT(11) -#define FUTUREMAX_DANCE_MAT BIT(12) +#define DUALSHOCK4_DONGLE BIT(7) +#define MOTION_CONTROLLER_USB BIT(8) +#define MOTION_CONTROLLER_BT BIT(9) +#define NAVIGATION_CONTROLLER_USB BIT(10) +#define NAVIGATION_CONTROLLER_BT BIT(11) +#define SINO_LITE_CONTROLLER BIT(12) +#define FUTUREMAX_DANCE_MAT BIT(13) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) #define NAVIGATION_CONTROLLER (NAVIGATION_CONTROLLER_USB |\ NAVIGATION_CONTROLLER_BT) #define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\ - DUALSHOCK4_CONTROLLER_BT) + DUALSHOCK4_CONTROLLER_BT | \ + DUALSHOCK4_DONGLE) #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\ DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER |\ NAVIGATION_CONTROLLER) @@ -846,7 +848,7 @@ static void dualshock4_parse_report(struct so