diff options
Diffstat (limited to 'drivers/hid/hid-sony.c')
| -rw-r--r-- | drivers/hid/hid-sony.c | 1232 |
1 files changed, 262 insertions, 970 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 9671a4bad643..b966e4044238 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * HID driver for Sony / PS2 / PS3 / PS4 BD devices. * @@ -10,13 +11,12 @@ * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com> * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com> * Copyright (c) 2018 Todd Kelner + * Copyright (c) 2020-2021 Pascal Giard <pascal.giard@etsmtl.ca> + * Copyright (c) 2020 Sanjay Govind <sanjay.govind9@gmail.com> + * Copyright (c) 2021 Daniel Nguyen <daniel.nguyen.1@ens.etsmtl.ca> */ /* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. */ /* @@ -38,7 +38,9 @@ #include <linux/idr.h> #include <linux/input/mt.h> #include <linux/crc32.h> -#include <asm/unaligned.h> +#include <linux/usb.h> +#include <linux/timer.h> +#include <linux/unaligned.h> #include "hid-ids.h" @@ -47,43 +49,57 @@ #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 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 NSG_MR5U_REMOTE_BT BIT(14) -#define NSG_MR7U_REMOTE_BT BIT(15) +#define MOTION_CONTROLLER_USB BIT(5) +#define MOTION_CONTROLLER_BT BIT(6) +#define NAVIGATION_CONTROLLER_USB BIT(7) +#define NAVIGATION_CONTROLLER_BT BIT(8) +#define SINO_LITE_CONTROLLER BIT(9) +#define FUTUREMAX_DANCE_MAT BIT(10) +#define NSG_MR5U_REMOTE_BT BIT(11) +#define NSG_MR7U_REMOTE_BT BIT(12) +#define SHANWAN_GAMEPAD BIT(13) +#define GH_GUITAR_CONTROLLER BIT(14) +#define GHL_GUITAR_PS3WIIU BIT(15) +#define GHL_GUITAR_PS4 BIT(16) #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_DONGLE) #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\ - DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER |\ - NAVIGATION_CONTROLLER) -#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\ - MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER) -#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\ - MOTION_CONTROLLER) -#define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_BT |\ - MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT) + MOTION_CONTROLLER | NAVIGATION_CONTROLLER) +#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER) +#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | MOTION_CONTROLLER) +#define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT) #define NSG_MRXU_REMOTE (NSG_MR5U_REMOTE_BT | NSG_MR7U_REMOTE_BT) #define MAX_LEDS 4 #define NSG_MRXU_MAX_X 1667 #define NSG_MRXU_MAX_Y 1868 +/* The PS3/Wii U dongles require a poke every 10 seconds, but the PS4 + * requires one every 8 seconds. Using 8 seconds for all for simplicity. + */ +#define GHL_GUITAR_POKE_INTERVAL 8 /* In seconds */ +#define GUITAR_TILT_USAGE 44 + +/* Magic data taken from GHLtarUtility: + * https://github.com/ghlre/GHLtarUtility/blob/master/PS3Guitar.cs + * Note: The Wii U and PS3 dongles happen to share the same! + */ +static const char ghl_ps3wiiu_magic_data[] = { + 0x02, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Magic data for the PS4 dongles sniffed with a USB protocol + * analyzer. + */ +static const char ghl_ps4_magic_data[] = { + 0x30, 0x02, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00 +}; /* PS/3 Motion controller */ -static u8 motion_rdesc[] = { +static const u8 motion_rdesc[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x04, /* Usage (Joystick), */ 0xA1, 0x01, /* Collection (Application), */ @@ -179,7 +195,7 @@ static u8 motion_rdesc[] = { 0xC0 /* End Collection */ }; -static u8 ps3remote_rdesc[] = { +static const u8 ps3remote_rdesc[] = { 0x05, 0x01, /* GUsagePage Generic Desktop */ 0x09, 0x05, /* LUsage 0x05 [Game Pad] */ 0xA1, 0x01, /* MCollection Application (mouse, keyboard) */ @@ -342,7 +358,7 @@ static const unsigned int buzz_keymap[] = { }; /* The Navigation controller is a partial DS3 and uses the same HID report - * and hence the same keymap indices, however not not all axes/buttons + * and hence the same keymap indices, however not all axes/buttons * are physically present. We use the same axis and button mapping as * the DS3, which uses the Linux gamepad spec. */ @@ -402,36 +418,6 @@ static const unsigned int sixaxis_keymap[] = { [0x11] = BTN_MODE, /* PS */ }; -static const unsigned int ds4_absmap[] = { - [0x30] = ABS_X, - [0x31] = ABS_Y, - [0x32] = ABS_RX, /* right stick X */ - [0x33] = ABS_Z, /* L2 */ - [0x34] = ABS_RZ, /* R2 */ - [0x35] = ABS_RY, /* right stick Y */ -}; - -static const unsigned int ds4_keymap[] = { - [0x1] = BTN_WEST, /* Square */ - [0x2] = BTN_SOUTH, /* Cross */ - [0x3] = BTN_EAST, /* Circle */ - [0x4] = BTN_NORTH, /* Triangle */ - [0x5] = BTN_TL, /* L1 */ - [0x6] = BTN_TR, /* R1 */ - [0x7] = BTN_TL2, /* L2 */ - [0x8] = BTN_TR2, /* R2 */ - [0x9] = BTN_SELECT, /* Share */ - [0xa] = BTN_START, /* Options */ - [0xb] = BTN_THUMBL, /* L3 */ - [0xc] = BTN_THUMBR, /* R3 */ - [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, POWER_SUPPLY_PROP_CAPACITY, @@ -476,35 +462,12 @@ struct motion_output_report_02 { u8 rumble; }; -#define DS4_FEATURE_REPORT_0x02_SIZE 37 -#define DS4_FEATURE_REPORT_0x05_SIZE 41 -#define DS4_FEATURE_REPORT_0x81_SIZE 7 -#define DS4_FEATURE_REPORT_0xA3_SIZE 49 -#define DS4_INPUT_REPORT_0x11_SIZE 78 -#define DS4_OUTPUT_REPORT_0x05_SIZE 32 -#define DS4_OUTPUT_REPORT_0x11_SIZE 78 #define SIXAXIS_REPORT_0xF2_SIZE 17 #define SIXAXIS_REPORT_0xF5_SIZE 8 #define MOTION_REPORT_0x02_SIZE 49 -/* 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 -#define DS4_INPUT_REPORT_BATTERY_OFFSET 30 -#define DS4_INPUT_REPORT_TOUCHPAD_OFFSET 33 - #define SENSOR_SUFFIX " Motion Sensors" -#define DS4_TOUCHPAD_SUFFIX " Touchpad" - -/* Default to 4ms poll interval, which is same as USB (not adjustable). */ -#define DS4_BT_DEFAULT_POLL_INTERVAL_MS 4 -#define DS4_BT_MAX_POLL_INTERVAL_MS 62 -#define DS4_GYRO_RES_PER_DEG_S 1024 -#define DS4_ACC_RES_PER_G 8192 +#define TOUCHPAD_SUFFIX " Touchpad" #define SIXAXIS_INPUT_REPORT_ACC_X_OFFSET 41 #define SIXAXIS_ACC_RES_PER_G 113 @@ -513,28 +476,8 @@ 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; -}; - -enum ds4_dongle_state { - DONGLE_DISCONNECTED, - DONGLE_CALIBRATING, - DONGLE_CONNECTED, - DONGLE_DISABLED -}; - enum sony_worker { - SONY_WORKER_STATE, - SONY_WORKER_HOTPLUG + SONY_WORKER_STATE }; struct sony_sc { @@ -545,14 +488,11 @@ struct sony_sc { struct input_dev *sensor_dev; struct led_classdev *leds[MAX_LEDS]; unsigned long quirks; - struct work_struct hotplug_worker; struct work_struct state_worker; void (*send_output_report)(struct sony_sc *); struct power_supply *battery; struct power_supply_desc battery_desc; int device_id; - unsigned fw_version; - unsigned hw_version; u8 *output_report_dmabuf; #ifdef CONFIG_SONY_FF @@ -561,25 +501,18 @@ struct sony_sc { #endif u8 mac_address[6]; - u8 hotplug_worker_initialized; u8 state_worker_initialized; u8 defer_initialization; - u8 cable_state; - u8 battery_charging; u8 battery_capacity; + int battery_status; u8 led_state[MAX_LEDS]; 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; - - u8 ds4_bt_poll_interval; - enum ds4_dongle_state ds4_dongle_state; - /* DS4 calibration data */ - struct ds4_calibration_data ds4_calib_data[6]; + /* GH Live */ + struct urb *ghl_urb; + struct timer_list ghl_poke_timer; }; static void sony_set_leds(struct sony_sc *sc); @@ -587,88 +520,94 @@ static void sony_set_leds(struct sony_sc *sc); static inline void sony_schedule_work(struct sony_sc *sc, enum sony_worker which) { + unsigned long flags; + switch (which) { case SONY_WORKER_STATE: - if (!sc->defer_initialization) + spin_lock_irqsave(&sc->lock, flags); + if (!sc->defer_initialization && sc->state_worker_initialized) schedule_work(&sc->state_worker); - break; - case SONY_WORKER_HOTPLUG: - if (sc->hotplug_worker_initialized) - schedule_work(&sc->hotplug_worker); + spin_unlock_irqrestore(&sc->lock, flags); break; } } -static ssize_t ds4_show_poll_interval(struct device *dev, - struct device_attribute - *attr, char *buf) +static void ghl_magic_poke_cb(struct urb *urb) { - struct hid_device *hdev = to_hid_device(dev); - struct sony_sc *sc = hid_get_drvdata(hdev); + struct sony_sc *sc = urb->context; + + if (urb->status < 0) + hid_err(sc->hdev, "URB transfer failed : %d", urb->status); - return snprintf(buf, PAGE_SIZE, "%i\n", sc->ds4_bt_poll_interval); + mod_timer(&sc->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ); } -static ssize_t ds4_store_poll_interval(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static void ghl_magic_poke(struct timer_list *t) { - struct hid_device *hdev = to_hid_device(dev); - struct sony_sc *sc = hid_get_drvdata(hdev); - unsigned long flags; - u8 interval; - - if (kstrtou8(buf, 0, &interval)) - return -EINVAL; - - if (interval > DS4_BT_MAX_POLL_INTERVAL_MS) - return -EINVAL; + int ret; + struct sony_sc *sc = timer_container_of(sc, t, ghl_poke_timer); - spin_lock_irqsave(&sc->lock, flags); - sc->ds4_bt_poll_interval = interval; - spin_unlock_irqrestore(&sc->lock, flags); + ret = usb_submit_urb(sc->ghl_urb, GFP_ATOMIC); + if (ret < 0) + hid_err(sc->hdev, "usb_submit_urb failed: %d", ret); +} - sony_schedule_work(sc, SONY_WORKER_STATE); +static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev, + const char ghl_magic_data[], u16 poke_size) +{ + struct usb_ctrlrequest *cr; + u8 *databuf; + unsigned int pipe; + u16 ghl_magic_value = (((HID_OUTPUT_REPORT + 1) << 8) | ghl_magic_data[0]); - return count; -} + pipe = usb_sndctrlpipe(usbdev, 0); -static DEVICE_ATTR(bt_poll_interval, 0644, ds4_show_poll_interval, - ds4_store_poll_interval); + cr = devm_kzalloc(&sc->hdev->dev, sizeof(*cr), GFP_ATOMIC); + if (cr == NULL) + return -ENOMEM; -static ssize_t sony_show_firmware_version(struct device *dev, - struct device_attribute - *attr, char *buf) -{ - struct hid_device *hdev = to_hid_device(dev); - struct sony_sc *sc = hid_get_drvdata(hdev); + databuf = devm_kzalloc(&sc->hdev->dev, poke_size, GFP_ATOMIC); + if (databuf == NULL) + return -ENOMEM; - return snprintf(buf, PAGE_SIZE, "0x%04x\n", sc->fw_version); + cr->bRequestType = + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT; + cr->bRequest = USB_REQ_SET_CONFIGURATION; + cr->wValue = cpu_to_le16(ghl_magic_value); + cr->wIndex = 0; + cr->wLength = cpu_to_le16(poke_size); + memcpy(databuf, ghl_magic_data, poke_size); + usb_fill_control_urb( + sc->ghl_urb, usbdev, pipe, + (unsigned char *) cr, databuf, poke_size, + ghl_magic_poke_cb, sc); + return 0; } -static DEVICE_ATTR(firmware_version, 0444, sony_show_firmware_version, NULL); - -static ssize_t sony_show_hardware_version(struct device *dev, - struct device_attribute - *attr, char *buf) +static int guitar_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) { - struct hid_device *hdev = to_hid_device(dev); - struct sony_sc *sc = hid_get_drvdata(hdev); + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) { + unsigned int abs = usage->hid & HID_USAGE; - return snprintf(buf, PAGE_SIZE, "0x%04x\n", sc->hw_version); + if (abs == GUITAR_TILT_USAGE) { + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, ABS_RY); + return 1; + } + } + return 0; } -static DEVICE_ATTR(hardware_version, 0444, sony_show_hardware_version, NULL); - -static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc, - unsigned int *rsize) +static const u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc, + unsigned int *rsize) { *rsize = sizeof(motion_rdesc); return motion_rdesc; } -static u8 *ps3remote_fixup(struct hid_device *hdev, u8 *rdesc, - unsigned int *rsize) +static const u8 *ps3remote_fixup(struct hid_device *hdev, u8 *rdesc, + unsigned int *rsize) { *rsize = sizeof(ps3remote_rdesc); return ps3remote_rdesc; @@ -804,38 +743,7 @@ static int sixaxis_mapping(struct hid_device *hdev, struct hid_input *hi, return -1; } -static int ds4_mapping(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { - unsigned int key = usage->hid & HID_USAGE; - - if (key >= ARRAY_SIZE(ds4_keymap)) - return -1; - - key = ds4_keymap[key]; - hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key); - return 1; - } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) { - unsigned int abs = usage->hid & HID_USAGE; - - /* Let the HID parser deal with the HAT. */ - if (usage->hid == HID_GD_HATSWITCH) - return 0; - - if (abs >= ARRAY_SIZE(ds4_absmap)) - return -1; - - abs = ds4_absmap[abs]; - hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs); - return 1; - } - - return 0; -} - -static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc, +static const u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *rsize) { struct sony_sc *sc = hid_get_drvdata(hdev); @@ -865,6 +773,23 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc, if (sc->quirks & PS3REMOTE) return ps3remote_fixup(hdev, rdesc, rsize); + /* + * Some knock-off USB dongles incorrectly report their button count + * as 13 instead of 16 causing three non-functional buttons. + */ + if ((sc->quirks & SIXAXIS_CONTROLLER_USB) && *rsize >= 45 && + /* Report Count (13) */ + rdesc[23] == 0x95 && rdesc[24] == 0x0D && + /* Usage Maximum (13) */ + rdesc[37] == 0x29 && rdesc[38] == 0x0D && + /* Report Count (3) */ + rdesc[43] == 0x95 && rdesc[44] == 0x03) { + hid_info(hdev, "Fixing up USB dongle report descriptor\n"); + rdesc[24] = 0x10; + rdesc[38] = 0x10; + rdesc[44] = 0x00; + } + return rdesc; } @@ -873,7 +798,8 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size) static const u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 }; unsigned long flags; int offset; - u8 cable_state, battery_capacity, battery_charging; + u8 battery_capacity; + int battery_status; /* * The sixaxis is charging if the battery value is 0xee @@ -885,19 +811,16 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size) if (rd[offset] >= 0xee) { battery_capacity = 100; - battery_charging = !(rd[offset] & 0x01); - cable_state = 1; + battery_status = (rd[offset] & 0x01) ? POWER_SUPPLY_STATUS_FULL : POWER_SUPPLY_STATUS_CHARGING; } else { u8 index = rd[offset] <= 5 ? rd[offset] : 5; battery_capacity = sixaxis_battery_capacity[index]; - battery_charging = 0; - cable_state = 0; + battery_status = POWER_SUPPLY_STATUS_DISCHARGING; } spin_lock_irqsave(&sc->lock, flags); - sc->cable_state = cable_state; sc->battery_capacity = battery_capacity; - sc->battery_charging = battery_charging; + sc->battery_status = battery_status; spin_unlock_irqrestore(&sc->lock, flags); if (sc->quirks & SIXAXIS_CONTROLLER) { @@ -918,192 +841,6 @@ 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; - u16 timestamp; - - /* When using Bluetooth the header is 2 bytes longer, so skip these. */ - int data_offset = (sc->quirks & DUALSHOCK4_CONTROLLER_BT) ? 2 : 0; - - /* Second bit of third button byte is for the touchpad button. */ - 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]); - 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. */ - 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, calib->abs_code, calib_data); - offset += 2; - } - 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. - */ - offset = data_offset + DS4_INPUT_REPORT_BATTERY_OFFSET; - cable_state = (rd[offset] >> 4) & 0x01; - battery_capacity = rd[offset] & 0x0F; - - /* - * When a USB power source is connected the battery level ranges from - * 0 to 10, and when running on battery power it ranges from 0 to 9. - * A battery level above 10 when plugged in means charge completed. - */ - if (!cable_state || battery_capacity > 10) - battery_charging = 0; - else - battery_charging = 1; - - if (!cable_state) - battery_capacity++; - if (battery_capacity > 10) - battery_capacity = 10; - - battery_capacity *= 10; - - spin_lock_irqsave(&sc->lock, flags); - sc->cable_state = cable_state; - sc->battery_capacity = battery_capacity; - sc->battery_charging = battery_charging; - spin_unlock_irqrestore(&sc->lock, flags); - - /* - * The Dualshock 4 multi-touch trackpad data starts at offset 33 on USB - * and 35 on Bluetooth. - * The first byte indicates the number of touch data in the report. - * Trackpad data starts 2 bytes later (e.g. 35 for USB). - */ - offset = data_offset + DS4_INPUT_REPORT_TOUCHPAD_OFFSET; - max_touch_data = (sc->quirks & DUALSHOCK4_CONTROLLER_BT) ? 4 : 3; - if (rd[offset] > 0 && rd[offset] <= max_touch_data) - num_touch_data = rd[offset]; - else - num_touch_data = 1; - offset += 1; - - for (m = 0; m < num_touch_data; m++) { - /* Skip past timestamp */ - offset += 1; - - /* - * The first 7 bits of the first byte is a counter and bit 8 is - * a touch indicator that is 0 when pressed and 1 when not - * pressed. - * The next 3 bytes are two 12 bit touch coordinates, X and Y. - * The data for the second touch is in the same format and - * immediately follows the data for the first. - */ - for (n = 0; n < 2; n++) { - u16 x, y; - bool active; - - x = rd[offset+1] | ((rd[offset+2] & 0xF) << 8); - y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4); - - active = !(rd[offset] >> 7); - input_mt_slot(sc->touchpad, n); - input_mt_report_slot_state(sc->touchpad, MT_TOOL_FINGER, active); - - if (active) { - input_report_abs(sc->touchpad, ABS_MT_POSITION_X, x); - input_report_abs(sc->touchpad, ABS_MT_POSITION_Y, y); - } - - offset += 4; - } - input_mt_sync_frame(sc->touchpad); - input_sync(sc->touchpad); - } -} - static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size) { int n, offset, relx, rely; @@ -1210,83 +947,6 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, } else if ((sc->quirks & NAVIGATION_CONTROLLER) && rd[0] == 0x01 && size == 49) { sixaxis_parse_report(sc, rd, size); - } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 && - size == 64) { - dualshock4_parse_report(sc, rd, size); - } else if (((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && rd[0] == 0x11 && - size == 78)) { - /* CRC check */ - u8 bthdr = 0xA1; - u32 crc; - u32 report_crc; - - crc = crc32_le(0xFFFFFFFF, &bthdr, 1); - crc = ~crc32_le(crc, rd, DS4_INPUT_REPORT_0x11_SIZE-4); - report_crc = get_unaligned_le32(&rd[DS4_INPUT_REPORT_0x11_SIZE-4]); - if (crc != report_crc) { - hid_dbg(sc->hdev, "DualShock 4 input report's CRC check failed, received crc 0x%0x != 0x%0x\n", - report_crc, crc); - return -EILSEQ; - } - - dualshock4_parse_report(sc, rd, size); - } else if ((sc->quirks & DUALSHOCK4_DONGLE) && rd[0] == 0x01 && - size == 64) { - unsigned long flags; - enum ds4_dongle_state dongle_state; - - /* - * In the case of a DS4 USB dongle, bit[2] of byte 31 indicates - * if a DS4 is actually connected (indicated by '0'). - * For non-dongle, this bit is always 0 (connected). - */ - bool connected = (rd[31] & 0x04) ? false : true; - - spin_lock_irqsave(&sc->lock, flags); - dongle_state = sc->ds4_dongle_state; - spin_unlock_irqrestore(&sc->lock, flags); - - /* - * The dongle always sends input reports even when no - * DS4 is attached. When a DS4 is connected, we need to - * obtain calibration data before we can use it. - * The code below tracks dongle state and kicks of - * calibration when needed and only allows us to process - * input if a DS4 is actually connected. - */ - if (dongle_state == DONGLE_DISCONNECTED && connected) { - hid_info(sc->hdev, "DualShock 4 USB dongle: controller connected\n"); - sony_set_leds(sc); - - spin_lock_irqsave(&sc->lock, flags); - sc->ds4_dongle_state = DONGLE_CALIBRATING; - spin_unlock_irqrestore(&sc->lock, flags); - - sony_schedule_work(sc, SONY_WORKER_HOTPLUG); - - /* Don't process the report since we don't have - * calibration data, but let hidraw have it anyway. - */ - return 0; - } else if ((dongle_state == DONGLE_CONNECTED || - dongle_state == DONGLE_DISABLED) && !connected) { - hid_info(sc->hdev, "DualShock 4 USB dongle: controller disconnected\n"); - - spin_lock_irqsave(&sc->lock, flags); - sc->ds4_dongle_state = DONGLE_DISCONNECTED; - spin_unlock_irqrestore(&sc->lock, flags); - - /* Return 0, so hidraw can get the report. */ - return 0; - } else if (dongle_state == DONGLE_CALIBRATING || - dongle_state == DONGLE_DISABLED || - dongle_state == DONGLE_DISCONNECTED) { - /* Return 0, so hidraw can get the report. */ - return 0; - } - - dualshock4_parse_report(sc, rd, size); - } else if ((sc->quirks & NSG_MRXU_REMOTE) && rd[0] == 0x02) { nsg_mrxu_parse_report(sc, rd, size); return 1; @@ -1338,9 +998,8 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, if (sc->quirks & SIXAXIS_CONTROLLER) return sixaxis_mapping(hdev, hi, field, usage, bit, max); - if (sc->quirks & DUALSHOCK4_CONTROLLER) - return ds4_mapping(hdev, hi, field, usage, bit, max); - + if (sc->quirks & GH_GUITAR_CONTROLLER) + return guitar_mapping(hdev, hi, field, usage, bit, max); /* Let hid-core decide for the others */ return 0; @@ -1366,14 +1025,17 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count, sc->touchpad->id.product = sc->hdev->product; sc->touchpad->id.version = sc->hdev->version; - /* Append a suffix to the controller name as there are various - * DS4 compatible non-Sony devices with different names. + /* This suffix was originally apended when hid-sony also + * supported DS4 devices. The DS4 was implemented using multiple + * evdev nodes and hence had the need to separete them out using + * a suffix. Other devices which were added later like Sony TV remotes + * inhirited this suffix. */ - name_sz = strlen(sc->hdev->name) + sizeof(DS4_TOUCHPAD_SUFFIX); + name_sz = strlen(sc->hdev->name) + sizeof(TOUCHPAD_SUFFIX); name = devm_kzalloc(&sc->hdev->dev, name_sz, GFP_KERNEL); if (!name) return -ENOMEM; - snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name); + snprintf(name, name_sz, "%s" TOUCHPAD_SUFFIX, sc->hdev->name); sc->touchpad->name = name; /* We map the button underneath the touchpad to BTN_LEFT. */ @@ -1415,7 +1077,6 @@ static int sony_register_sensors(struct sony_sc *sc) size_t name_sz; char *name; int ret; - int range; sc->sensor_dev = devm_input_allocate_device(&sc->hdev->dev); if (!sc->sensor_dev) @@ -1453,25 +1114,6 @@ static int sony_register_sensors(struct sony_sc *sc) input_abs_set_res(sc->sensor_dev, ABS_X, SIXAXIS_ACC_RES_PER_G); input_abs_set_res(sc->sensor_dev, ABS_Y, SIXAXIS_ACC_RES_PER_G); input_abs_set_res(sc->sensor_dev, ABS_Z, SIXAXIS_ACC_RES_PER_G); - } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { - 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(EV_MSC, sc->sensor_dev->evbit); - __set_bit(MSC_TIMESTAMP, sc->sensor_dev->mscbit); } __set_bit(INPUT_PROP_ACCELEROMETER, sc->sensor_dev->propbit); @@ -1490,6 +1132,7 @@ static int sony_register_sensors(struct sony_sc *sc) */ static int sixaxis_set_operational_usb(struct hid_device *hdev) { + struct sony_sc *sc = hid_get_drvdata(hdev); const int buf_size = max(SIXAXIS_REPORT_0xF2_SIZE, SIXAXIS_REPORT_0xF5_SIZE); u8 *buf; @@ -1519,14 +1162,15 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev) /* * But the USB interrupt would cause SHANWAN controllers to - * start rumbling non-stop. + * start rumbling non-stop, so skip step 3 for these controllers. */ - if (strcmp(hdev->name, "SHANWAN PS3 GamePad")) { - ret = hid_hw_output_report(hdev, buf, 1); - if (ret < 0) { - hid_info(hdev, "can't set operational mode: step 3, ignoring\n"); - ret = 0; - } + if (sc->quirks & SHANWAN_GAMEPAD) + goto out; + + ret = hid_hw_output_report(hdev, buf, 1); + if (ret < 0) { + hid_info(hdev, "can't set operational mode: step 3, ignoring\n"); + ret = 0; } out: @@ -1553,202 +1197,6 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev) return ret; } -/* - * Request DS4 calibration data for the motion sensors. - * For Bluetooth this also affects the operating mode (see below). - */ -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 | DUALSHOCK4_DONGLE)) { - 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; - - buf = kmalloc(DS4_FEATURE_REPORT_0x05_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - 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 { - /* BT + Dongle */ - 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; -} - -static void dualshock4_calibration_work(struct work_struct *work) -{ - struct sony_sc *sc = container_of(work, struct sony_sc, hotplug_worker); - unsigned long flags; - enum ds4_dongle_state dongle_state; - int ret; - - ret = dualshock4_get_calibration_data(sc); - if (ret < 0) { - /* This call is very unlikely to fail for the dongle. When it - * fails we are probably in a very bad state, so mark the - * dongle as disabled. We will re-enable the dongle if a new - * DS4 hotplug is detect from sony_raw_event as any issues - * are likely resolved then (the dongle is quite stupid). - */ - hid_err(sc->hdev, "DualShock 4 USB dongle: calibration failed, disabling device\n"); - dongle_state = DONGLE_DISABLED; - } else { - hid_info(sc->hdev, "DualShock 4 USB dongle: calibration completed\n"); - dongle_state = DONGLE_CONNECTED; - } - - spin_lock_irqsave(&sc->lock, flags); - sc->ds4_dongle_state = dongle_state; - spin_unlock_irqrestore(&sc->lock, flags); -} - -static int dualshock4_get_version_info(struct sony_sc *sc) -{ - u8 *buf; - int ret; - - buf = kmalloc(DS4_FEATURE_REPORT_0xA3_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = hid_hw_raw_request(sc->hdev, 0xA3, buf, - DS4_FEATURE_REPORT_0xA3_SIZE, - HID_FEATURE_REPORT, - HID_REQ_GET_REPORT); - if (ret < 0) { - kfree(buf); - return ret; - } - - sc->hw_version = get_unaligned_le16(&buf[35]); - sc->fw_version = get_unaligned_le16(&buf[41]); - - kfree(buf); - return 0; -} - static void sixaxis_set_leds_from_id(struct sony_sc *sc) { static const u8 sixaxis_leds[10][4] = { @@ -1775,30 +1223,6 @@ static void sixaxis_set_leds_from_id(struct sony_sc *sc) memcpy(sc->led_state, sixaxis_leds[id], sizeof(sixaxis_leds[id])); } -static void dualshock4_set_leds_from_id(struct sony_sc *sc) -{ - /* The first 4 color/index entries match what the PS4 assigns */ - static const u8 color_code[7][3] = { - /* Blue */ { 0x00, 0x00, 0x40 }, - /* Red */ { 0x40, 0x00, 0x00 }, - /* Green */ { 0x00, 0x40, 0x00 }, - /* Pink */ { 0x20, 0x00, 0x20 }, - /* Orange */ { 0x02, 0x01, 0x00 }, - /* Teal */ { 0x00, 0x01, 0x01 }, - /* White */ { 0x01, 0x01, 0x01 } - }; - - int id = sc->device_id; - - BUILD_BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0])); - - if (id < 0) - return; - - id %= 7; - memcpy(sc->led_state, color_code[id], sizeof(color_code[id])); -} - static void buzz_set_leds(struct sony_sc *sc) { struct hid_device *hdev = sc->hdev; @@ -1944,40 +1368,32 @@ static int sony_leds_init(struct sony_sc *sc) { struct hid_device *hdev = sc->hdev; int n, ret = 0; - int use_ds4_names; + int use_color_names; struct led_classdev *led; size_t name_sz; char *name; size_t name_len; const char *name_fmt; - static const char * const ds4_name_str[] = { "red", "green", "blue", + static const char * const color_name_str[] = { "red", "green", "blue", "global" }; u8 max_brightness[MAX_LEDS] = { [0 ... (MAX_LEDS - 1)] = 1 }; u8 use_hw_blink[MAX_LEDS] = { 0 }; - BUG_ON(!(sc->quirks & SONY_LED_SUPPORT)); + if (WARN_ON(!(sc->quirks & SONY_LED_SUPPORT))) + return -EINVAL; if (sc->quirks & BUZZ_CONTROLLER) { sc->led_count = 4; - use_ds4_names = 0; + use_color_names = 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 (sc->quirks & DUALSHOCK4_CONTROLLER) { - dualshock4_set_leds_from_id(sc); - sc->led_state[3] = 1; - sc->led_count = 4; - memset(max_brightness, 255, 3); - use_hw_blink[3] = 1; - use_ds4_names = 1; - name_len = 0; - name_fmt = "%s:%s"; } else if (sc->quirks & MOTION_CONTROLLER) { sc->led_count = 3; memset(max_brightness, 255, 3); - use_ds4_names = 1; + use_color_names = 1; name_len = 0; name_fmt = "%s:%s"; } else if (sc->quirks & NAVIGATION_CONTROLLER) { @@ -1986,14 +1402,14 @@ static int sony_leds_init(struct sony_sc *sc) memcpy(sc->led_state, navigation_leds, sizeof(navigation_leds)); sc->led_count = 1; memset(use_hw_blink, 1, 4); - use_ds4_names = 0; + use_color_names = 0; name_len = strlen("::sony#"); name_fmt = "%s::sony%d"; } else { sixaxis_set_leds_from_id(sc); sc->led_count = 4; memset(use_hw_blink, 1, 4); - use_ds4_names = 0; + use_color_names = 0; name_len = strlen("::sony#"); name_fmt = "%s::sony%d"; } @@ -2009,8 +1425,8 @@ static int sony_leds_init(struct sony_sc *sc) for (n = 0; n < sc->led_count; n++) { - if (use_ds4_names) - name_sz = strlen(dev_name(&hdev->dev)) + strlen(ds4_name_str[n]) + 2; + if (use_color_names) + name_sz = strlen(dev_name(&hdev->dev)) + strlen(color_name_str[n]) + 2; led = devm_kzalloc(&hdev->dev, sizeof(struct led_classdev) + name_sz, GFP_KERNEL); if (!led) { @@ -2019,9 +1435,9 @@ static int sony_leds_init(struct sony_sc *sc) } name = (void *)(&led[1]); - if (use_ds4_names) + if (use_color_names) snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), - ds4_name_str[n]); + color_name_str[n]); else snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1); led->name = name; @@ -2097,71 +1513,14 @@ static void sixaxis_send_output_report(struct sony_sc *sc) } } - hid_hw_raw_request(sc->hdev, report->report_id, (u8 *)report, - sizeof(struct sixaxis_output_report), - HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); -} - -static void dualshock4_send_output_report(struct sony_sc *sc) -{ - struct hid_device *hdev = sc->hdev; - u8 *buf = sc->output_report_dmabuf; - int offset; - - /* - * NOTE: The lower 6 bits of buf[1] field of the Bluetooth report - * control the interval at which Dualshock 4 reports data: - * 0x00 - 1ms - * 0x01 - 1ms - * 0x02 - 2ms - * 0x3E - 62ms - * 0x3F - disabled - */ - if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) { - memset(buf, 0, DS4_OUTPUT_REPORT_0x05_SIZE); - buf[0] = 0x05; - buf[1] = 0x07; /* blink + LEDs + motor */ - offset = 4; - } else { - memset(buf, 0, DS4_OUTPUT_REPORT_0x11_SIZE); - buf[0] = 0x11; - buf[1] = 0xC0 /* HID + CRC */ | sc->ds4_bt_poll_interval; - buf[3] = 0x07; /* blink + LEDs + motor */ - offset = 6; - } - -#ifdef CONFIG_SONY_FF - buf[offset++] = sc->right; - buf[offset++] = sc->left; -#else - offset += 2; -#endif - - /* LED 3 is the global control */ - if (sc->led_state[3]) { - buf[offset++] = sc->led_state[0]; - buf[offset++] = sc->led_state[1]; - buf[offset++] = sc->led_state[2]; - } else { - offset += 3; - } - - /* If both delay values are zero the DualShock 4 disables blinking. */ - buf[offset++] = sc->led_delay_on[3]; - buf[offset++] = sc->led_delay_off[3]; - - if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) - hid_hw_output_report(hdev, buf, DS4_OUTPUT_REPORT_0x05_SIZE); - else { - /* CRC generation */ - u8 bthdr = 0xA2; - u32 crc; - - crc = crc32_le(0xFFFFFFFF, &bthdr, 1); - crc = ~crc32_le(crc, buf, DS4_OUTPUT_REPORT_0x11_SIZE-4); - put_unaligned_le32(crc, &buf[74]); - hid_hw_output_report(hdev, buf, DS4_OUTPUT_REPORT_0x11_SIZE); - } + /* SHANWAN controllers require output reports via intr channel */ + if (sc->quirks & SHANWAN_GAMEPAD) + hid_hw_output_report(sc->hdev, (u8 *)report, + sizeof(struct sixaxis_output_report)); + else + hid_hw_raw_request(sc->hdev, report->report_id, (u8 *)report, + sizeof(struct sixaxis_output_report), + HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); } static void motion_send_output_report(struct sony_sc *sc) @@ -2184,11 +1543,13 @@ static void motion_send_output_report(struct sony_sc *sc) hid_hw_output_report(hdev, (u8 *)report, MOTION_REPORT_0x02_SIZE); } +#ifdef CONFIG_SONY_FF static inline void sony_send_output_report(struct sony_sc *sc) { if (sc->send_output_report) sc->send_output_report(sc); } +#endif static void sony_state_worker(struct work_struct *work) { @@ -2205,14 +1566,6 @@ static int sony_allocate_output_report(struct sony_sc *sc) devm_kmalloc(&sc->hdev->dev, sizeof(union sixaxis_output_report_01), GFP_KERNEL); - else if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) - sc->output_report_dmabuf = devm_kmalloc(&sc->hdev->dev, - DS4_OUTPUT_REPORT_0x11_SIZE, - GFP_KERNEL); - else if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) - sc->output_report_dmabuf = devm_kmalloc(&sc->hdev->dev, - DS4_OUTPUT_REPORT_0x05_SIZE, - GFP_KERNEL); else if (sc->quirks & MOTION_CONTROLLER) sc->output_report_dmabuf = devm_kmalloc(&sc->hdev->dev, MOTION_REPORT_0x02_SIZE, @@ -2245,9 +1598,15 @@ static int sony_play_effect(struct input_dev *dev, void *data, static int sony_init_ff(struct sony_sc *sc) { - struct hid_input *hidinput = list_entry(sc->hdev->inputs.next, - struct hid_input, list); - struct input_dev *input_dev = hidinput->input; + struct hid_input *hidinput; + struct input_dev *input_dev; + + if (list_empty(&sc->hdev->inputs)) { + hid_err(sc->hdev, "no inputs found\n"); + return -ENODEV; + } + hidinput = list_entry(sc->hdev->inputs.next, struct hid_input, list); + input_dev = hidinput->input; input_set_capability(input_dev, EV_FF, FF_RUMBLE); return input_ff_create_memless(input_dev, NULL, sony_play_effect); @@ -2268,12 +1627,12 @@ static int sony_battery_get_property(struct power_supply *psy, struct sony_sc *sc = power_supply_get_drvdata(psy); unsigned long flags; int ret = 0; - u8 battery_charging, battery_capacity, cable_state; + u8 battery_capacity; + int battery_status; spin_lock_irqsave(&sc->lock, flags); - battery_charging = sc->battery_charging; battery_capacity = sc->battery_capacity; - cable_state = sc->cable_state; + battery_status = sc->battery_status; spin_unlock_irqrestore(&sc->lock, flags); switch (psp) { @@ -2287,13 +1646,7 @@ static int sony_battery_get_property(struct power_supply *psy, val->intval = battery_capacity; break; case POWER_SUPPLY_PROP_STATUS: - if (battery_charging) - val->intval = POWER_SUPPLY_STATUS_CHARGING; - else - if (battery_capacity == 100 && cable_state) - val->intval = POWER_SUPPLY_STATUS_FULL; - else - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + val->intval = battery_status; break; default: ret = -EINVAL; @@ -2427,8 +1780,7 @@ static int sony_check_add(struct sony_sc *sc) u8 *buf = NULL; int n, ret; - if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) || - (sc->quirks & MOTION_CONTROLLER_BT) || + if ((sc->quirks & MOTION_CONTROLLER_BT) || (sc->quirks & NAVIGATION_CONTROLLER_BT) || (sc->quirks & SIXAXIS_CONTROLLER_BT)) { /* @@ -2441,30 +1793,6 @@ static int sony_check_add(struct sony_sc *sc) hid_warn(sc->hdev, "UNIQ does not contain a MAC address; duplicate check skipped\n"); return 0; } - } else if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) { - buf = kmalloc(DS4_FEATURE_REPORT_0x81_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* - * The MAC address of a DS4 controller connected via USB can be - * retrieved with feature report 0x81. The address begins at - * offset 1. - */ - ret = hid_hw_raw_request(sc->hdev, 0x81, buf, - DS4_FEATURE_REPORT_0x81_SIZE, HID_FEATURE_REPORT, - HID_REQ_GET_REPORT); - - if (ret != DS4_FEATURE_REPORT_0x81_SIZE) { - hid_err(sc->hdev, "failed to retrieve feature report 0x81 with the DualShock 4 MAC address\n"); - ret = ret < 0 ? ret : -EINVAL; - goto out_free; - } - - memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address)); - - snprintf(sc->hdev->uniq, sizeof(sc->hdev->uniq), - "%pMR", sc->mac_address); } else if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || (sc->quirks & NAVIGATION_CONTROLLER_USB)) { buf = kmalloc(SIXAXIS_REPORT_0xF2_SIZE, GFP_KERNEL); @@ -2513,13 +1841,11 @@ static int sony_set_device_id(struct sony_sc *sc) int ret; /* - * Only DualShock 4 or Sixaxis controllers get an id. + * Only Sixaxis controllers get an id. * All others are set to -1. */ - if ((sc->quirks & SIXAXIS_CONTROLLER) || - (sc->quirks & DUALSHOCK4_CONTROLLER)) { - ret = ida_simple_get(&sony_device_id_allocator, 0, 0, - GFP_KERNEL); + if (sc->quirks & SIXAXIS_CONTROLLER) { + ret = ida_alloc(&sony_device_id_allocator, GFP_KERNEL); if (ret < 0) { sc->device_id = -1; return ret; @@ -2535,7 +1861,7 @@ static int sony_set_device_id(struct sony_sc *sc) static void sony_release_device_id(struct sony_sc *sc) { if (sc->device_id >= 0) { - ida_simple_remove(&sony_device_id_allocator, sc->device_id); + ida_free(&sony_device_id_allocator, sc->device_id); sc->device_id = -1; } } @@ -2553,13 +1879,16 @@ static inline void sony_init_output_report(struct sony_sc *sc, static inline void sony_cancel_work_sync(struct sony_sc *sc) { - if (sc->hotplug_worker_initialized) - cancel_work_sync(&sc->hotplug_worker); - if (sc->state_worker_initialized) + unsigned long flags; + + if (sc->state_worker_initialized) { + spin_lock_irqsave(&sc->lock, flags); + sc->state_worker_initialized = 0; + spin_unlock_irqrestore(&sc->lock, flags); cancel_work_sync(&sc->state_worker); + } } - static int sony_input_configured(struct hid_device *hdev, struct hid_input *hidinput) { @@ -2671,70 +2000,6 @@ static int sony_input_configured(struct hid_device *hdev, } sony_init_output_report(sc, sixaxis_send_output_report); - } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { - ret = dualshock4_get_calibration_data(sc); - if (ret < 0) { - hid_err(hdev, "Failed to get calibration data from Dualshock 4\n"); - goto err_stop; - } - - ret = dualshock4_get_version_info(sc); - if (ret < 0) { - hid_err(sc->hdev, "Failed to get version data from Dualshock 4\n"); - goto err_stop; - } - - ret = device_create_file(&sc->hdev->dev, &dev_attr_firmware_version); - if (ret) { - /* Make zero for cleanup reasons of sysfs entries. */ - sc->fw_version = 0; - sc->hw_version = 0; - hid_err(sc->hdev, "can't create sysfs firmware_version attribute err: %d\n", ret); - goto err_stop; - } - - ret = device_create_file(&sc->hdev->dev, &dev_attr_hardware_version); - if (ret) { - sc->hw_version = 0; - hid_err(sc->hdev, "can't create sysfs hardware_version attribute err: %d\n", ret); - goto err_stop; - } - - /* - * The Dualshock 4 touchpad supports 2 touches and has a - * resolution of 1920x942 (44.86 dots/mm). - */ - ret = sony_register_touchpad(sc, 2, 1920, 942, 0, 0, 0); - if (ret) { - hid_err(sc->hdev, - "Unable to initialize multi-touch slots: %d\n", - ret); - 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; - } - - if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) { - sc->ds4_bt_poll_interval = DS4_BT_DEFAULT_POLL_INTERVAL_MS; - ret = device_create_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); - if (ret) - hid_warn(sc->hdev, - "can't create sysfs bt_poll_interval attribute err: %d\n", - ret); - } - - if (sc->quirks & DUALSHOCK4_DONGLE) { - INIT_WORK(&sc->hotplug_worker, dualshock4_calibration_work); - sc->hotplug_worker_initialized = 1; - sc->ds4_dongle_state = DONGLE_DISCONNECTED; - } - - sony_init_output_report(sc, dualshock4_send_output_report); } else if (sc->quirks & NSG_MRXU_REMOTE) { /* * The NSG-MRxU touchpad supports 2 touches and has a @@ -2751,8 +2016,6 @@ static int sony_input_configured(struct hid_device *hdev, } else if (sc->quirks & MOTION_CONTROLLER) { sony_init_output_report(sc, motion_send_output_report); - } else { - ret = 0; } if (sc->quirks & SONY_LED_SUPPORT) { @@ -2784,20 +2047,9 @@ static int sony_input_configured(struct hid_device *hdev, err_close: hid_hw_close(hdev); err_stop: - /* Piggy back on the default ds4_bt_ poll_interval to determine - * if we need to remove the file as we don't know for sure if we - * executed that logic. - */ - if (sc->ds4_bt_poll_interval) - device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); - if (sc->fw_version) - device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version); - if (sc->hw_version) - device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version); sony_cancel_work_sync(sc); sony_remove_dev_list(sc); sony_release_device_id(sc); - hid_hw_stop(hdev); return ret; } @@ -2806,11 +2058,16 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) int ret; unsigned long quirks = id->driver_data; struct sony_sc *sc; + struct usb_device *usbdev; unsigned int connect_mask = HID_CONNECT_DEFAULT; if (!strcmp(hdev->name, "FutureMax Dance Mat")) quirks |= FUTUREMAX_DANCE_MAT; + if (!strcmp(hdev->name, "SHANWAN PS3 GamePad") || + !strcmp(hdev->name, "ShanWan PS(R) Ga`epad")) + quirks |= SHANWAN_GAMEPAD; + sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL); if (sc == NULL) { hid_err(hdev, "can't alloc sony descriptor\n"); @@ -2834,13 +2091,13 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) else if (sc->quirks & SIXAXIS_CONTROLLER) connect_mask |= HID_CONNECT_HIDDEV_FORCE; - /* Patch the hw version on DS3/4 compatible devices, so applications can + /* Patch the hw version on DS3 compatible devices, so applications can * distinguish between the default HID mappings and the mappings defined * by the Linux game controller spec. This is important for the SDL2 * library, which has a game controller database, which uses device ids * in combination with version as a key. */ - if (sc->quirks & (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)) + if (sc->quirks & SIXAXIS_CONTROLLER) hdev->version |= 0x8000; ret = hid_hw_start(hdev, connect_mask); @@ -2859,26 +2116,59 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) */ if (!(hdev->claimed & HID_CLAIMED_INPUT)) { hid_err(hdev, "failed to claim input\n"); - return -ENODEV; + ret = -ENODEV; + goto err; + } + + if (sc->quirks & (GHL_GUITAR_PS3WIIU | GHL_GUITAR_PS4)) { + if (!hid_is_usb(hdev)) { + ret = -EINVAL; + goto err; + } + + usbdev = to_usb_device(sc->hdev->dev.parent->parent); + + sc->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!sc->ghl_urb) { + ret = -ENOMEM; + goto err; + } + + if (sc->quirks & GHL_GUITAR_PS3WIIU) + ret = ghl_init_urb(sc, usbdev, ghl_ps3wiiu_magic_data, + ARRAY_SIZE(ghl_ps3wiiu_magic_data)); + else if (sc->quirks & GHL_GUITAR_PS4) + ret = ghl_init_urb(sc, usbdev, ghl_ps4_magic_data, + ARRAY_SIZE(ghl_ps4_magic_data)); + if (ret) { + hid_err(hdev, "error preparing URB\n"); + goto err; + } + + timer_setup(&sc->ghl_poke_timer, ghl_magic_poke, 0); + mod_timer(&sc->ghl_poke_timer, + jiffies + GHL_GUITAR_POKE_INTERVAL*HZ); } return ret; + +err: + usb_free_urb(sc->ghl_urb); + + hid_hw_stop(hdev); + return ret; } static void sony_remove(struct hid_device *hdev) { struct sony_sc *sc = hid_get_drvdata(hdev); - hid_hw_close(hdev); - - if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) - device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); - - if (sc->fw_version) - device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version); + if (sc->quirks & (GHL_GUITAR_PS3WIIU | GHL_GUITAR_PS4)) { + timer_delete_sync(&sc->ghl_poke_timer); + usb_free_urb(sc->ghl_urb); + } - if (sc->hw_version) - device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version); + hid_hw_close(hdev); sony_cancel_work_sync(sc); @@ -2960,17 +2250,6 @@ static const struct hid_device_id sony_devices[] = { /* SMK-Link PS3 BD Remote Control */ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_PS3_BDREMOTE), .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 }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2), - .driver_data = DUALSHOCK4_CONTROLLER_USB }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2), - .driver_data = DUALSHOCK4_CONTROLLER_BT }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE), - .driver_data = DUALSHOCK4_DONGLE }, /* Nyko Core Controller for PS3 */ { HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB | SINO_LITE_CONTROLLER }, @@ -2980,6 +2259,18 @@ static const struct hid_device_id sony_devices[] = { /* SMK-Link NSG-MR7U Remote Control */ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE), .driver_data = NSG_MR7U_REMOTE_BT }, + /* Guitar Hero Live PS3 and Wii U guitar dongles */ + { HID_USB_DEVICE(USB_VENDOR_ID_SONY_RHYTHM, USB_DEVICE_ID_SONY_PS3WIIU_GHLIVE_DONGLE), + .driver_data = GHL_GUITAR_PS3WIIU | GH_GUITAR_CONTROLLER }, + /* Guitar Hero PC Guitar Dongle */ + { HID_USB_DEVICE(USB_VENDOR_ID_REDOCTANE, USB_DEVICE_ID_REDOCTANE_GUITAR_DONGLE), + .driver_data = GH_GUITAR_CONTROLLER }, + /* Guitar Hero PS3 World Tour Guitar Dongle */ + { HID_USB_DEVICE(USB_VENDOR_ID_SONY_RHYTHM, USB_DEVICE_ID_SONY_PS3_GUITAR_DONGLE), + .driver_data = GH_GUITAR_CONTROLLER }, + /* Guitar Hero Live PS4 guitar dongles */ + { HID_USB_DEVICE(USB_VENDOR_ID_REDOCTANE, USB_DEVICE_ID_REDOCTANE_PS4_GHLIVE_DONGLE), + .driver_data = GHL_GUITAR_PS4 | GH_GUITAR_CONTROLLER }, { } }; MODULE_DEVICE_TABLE(hid, sony_devices); @@ -3018,4 +2309,5 @@ static void __exit sony_exit(void) module_init(sony_init); module_exit(sony_exit); +MODULE_DESCRIPTION("HID driver for Sony / PS2 / PS3 / PS4 BD devices"); MODULE_LICENSE("GPL"); |
