diff options
Diffstat (limited to 'drivers/hid/hid-sony.c')
-rw-r--r-- | drivers/hid/hid-sony.c | 450 |
1 files changed, 380 insertions, 70 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 1896c019e302..ed2f008f8403 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -46,20 +46,37 @@ #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 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) #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\ - DUALSHOCK4_CONTROLLER) -#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER) -#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_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 MAX_LEDS 4 +/* + * The Sixaxis reports both digital and analog values for each button on the + * controller except for Start, Select and the PS button. The controller ends + * up reporting 27 axes which causes them to spill over into the multi-touch + * axis values. Additionally, the controller only has 20 actual, physical axes + * so there are several unused axes in between the used ones. + */ static __u8 sixaxis_rdesc[] = { 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x04, /* Usage (Joystik), */ + 0x09, 0x04, /* Usage (Joystick), */ 0xA1, 0x01, /* Collection (Application), */ 0xA1, 0x02, /* Collection (Logical), */ 0x85, 0x01, /* Report ID (1), */ @@ -134,6 +151,186 @@ static __u8 sixaxis_rdesc[] = { 0xC0 /* End Collection */ }; +/* PS/3 Motion controller */ +static __u8 motion_rdesc[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x04, /* Usage (Joystick), */ + 0xA1, 0x01, /* Collection (Application), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0x01, /* Report ID (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x15, /* Report Count (21), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x35, 0x00, /* Physical Minimum (0), */ + 0x45, 0x01, /* Physical Maximum (1), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x15, /* Usage Maximum (15h), */ + 0x81, 0x02, /* Input (Variable), * Buttons */ + 0x95, 0x0B, /* Report Count (11), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x81, 0x03, /* Input (Constant, Variable), * Padding */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0xA1, 0x00, /* Collection (Physical), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x01, /* Report Count (1), */ + 0x35, 0x00, /* Physical Minimum (0), */ + 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ + 0x09, 0x30, /* Usage (X), */ + 0x81, 0x02, /* Input (Variable), * Trigger */ + 0xC0, /* End Collection, */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x07, /* Report Count (7), * skip 7 bytes */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x75, 0x10, /* Report Size (16), */ + 0x46, 0xFF, 0xFF, /* Physical Maximum (65535), */ + 0x27, 0xFF, 0xFF, 0x00, 0x00, /* Logical Maximum (65535), */ + 0x95, 0x03, /* Report Count (3), * 3x Accels */ + 0x09, 0x33, /* Usage (rX), */ + 0x09, 0x34, /* Usage (rY), */ + 0x09, 0x35, /* Usage (rZ), */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x03, /* Report Count (3), * Skip Accels 2nd frame */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x95, 0x03, /* Report Count (3), * 3x Gyros */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x03, /* Report Count (3), * Skip Gyros 2nd frame */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x0C, /* Report Size (12), */ + 0x46, 0xFF, 0x0F, /* Physical Maximum (4095), */ + 0x26, 0xFF, 0x0F, /* Logical Maximum (4095), */ + 0x95, 0x04, /* Report Count (4), * Skip Temp and Magnetometers */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x08, /* Report Size (8), */ + 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x95, 0x06, /* Report Count (6), * Skip Timestamp and Extension Bytes */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x91, 0x02, /* Output (Variable), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0x02, /* Report ID (2), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0xEE, /* Report ID (238), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0xEF, /* Report ID (239), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; + +/* PS/3 Navigation controller */ +static __u8 navigation_rdesc[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x04, /* Usage (Joystik), */ + 0xA1, 0x01, /* Collection (Application), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0x01, /* Report ID (1), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x13, /* Report Count (19), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x35, 0x00, /* Physical Minimum (0), */ + 0x45, 0x01, /* Physical Maximum (1), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x13, /* Usage Maximum (13h), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x0D, /* Report Count (13), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xA1, 0x00, /* Collection (Physical), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0x35, 0x00, /* Physical Minimum (0), */ + 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x06, /* Report Count (6), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x05, /* Report Count (5), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x20, /* Report Count (26), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x91, 0x02, /* Output (Variable), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0x02, /* Report ID (2), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0xEE, /* Report ID (238), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0xEF, /* Report ID (239), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; + /* * The default descriptor doesn't provide mapping for the accelerometers * or orientation sensors. This fixed descriptor maps the accelerometers @@ -798,11 +995,20 @@ union sixaxis_output_report_01 { __u8 buf[36]; }; +struct motion_output_report_02 { + u8 type, zero; + u8 r, g, b; + u8 zero2; + u8 rumble; +}; + #define DS4_REPORT_0x02_SIZE 37 #define DS4_REPORT_0x05_SIZE 32 #define DS4_REPORT_0x11_SIZE 78 #define DS4_REPORT_0x81_SIZE 7 -#define SIXAXIS_REPORT_0xF2_SIZE 18 +#define SIXAXIS_REPORT_0xF2_SIZE 17 +#define SIXAXIS_REPORT_0xF5_SIZE 8 +#define MOTION_REPORT_0x02_SIZE 49 static DEFINE_SPINLOCK(sony_dev_list_lock); static LIST_HEAD(sony_device_list); @@ -815,7 +1021,8 @@ struct sony_sc { struct led_classdev *leds[MAX_LEDS]; unsigned long quirks; struct work_struct state_worker; - struct power_supply battery; + struct power_supply *battery; + struct power_supply_desc battery_desc; int device_id; __u8 *output_report_dmabuf; @@ -842,6 +1049,20 @@ static __u8 *sixaxis_fixup(struct hid_device *hdev, __u8 *rdesc, return sixaxis_rdesc; } +static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc, + unsigned int *rsize) +{ + *rsize = sizeof(motion_rdesc); + return motion_rdesc; +} + +static u8 *navigation_fixup(struct hid_device *hdev, u8 *rdesc, + unsigned int *rsize) +{ + *rsize = sizeof(navigation_rdesc); + return navigation_rdesc; +} + static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { @@ -922,6 +1143,12 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, if (sc->quirks & SIXAXIS_CONTROLLER) return sixaxis_fixup(hdev, rdesc, rsize); + if (sc->quirks & MOTION_CONTROLLER) + return motion_fixup(hdev, rdesc, rsize); + + if (sc->quirks & NAVIGATION_CONTROLLER) + return navigation_fixup(hdev, rdesc, rsize); + if (sc->quirks & PS3REMOTE) return ps3remote_fixup(hdev, rdesc, rsize); @@ -932,6 +1159,7 @@ 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; /* @@ -940,12 +1168,14 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size) * It does not report the actual level while charging so it * is set to 100% while charging is in progress. */ - if (rd[30] >= 0xee) { + offset = (sc->quirks & MOTION_CONTROLLER) ? 12 : 30; + + if (rd[offset] >= 0xee) { battery_capacity = 100; - battery_charging = !(rd[30] & 0x01); + battery_charging = !(rd[offset] & 0x01); cable_state = 1; } else { - __u8 index = rd[30] <= 5 ? rd[30] : 5; + __u8 index = rd[offset] <= 5 ? rd[offset] : 5; battery_capacity = sixaxis_battery_capacity[index]; battery_charging = 0; cable_state = 0; @@ -1046,6 +1276,11 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, swap(rd[47], rd[48]); sixaxis_parse_report(sc, rd, size); + } else if ((sc->quirks & MOTION_CONTROLLER_BT) && rd[0] == 0x01 && size == 49) { + sixaxis_parse_report(sc, rd, size); + } 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) || ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && rd[0] == 0x11 && size == 78)) { @@ -1130,18 +1365,38 @@ static void sony_input_configured(struct hid_device *hdev, */ static int sixaxis_set_operational_usb(struct hid_device *hdev) { + const int buf_size = + max(SIXAXIS_REPORT_0xF2_SIZE, SIXAXIS_REPORT_0xF5_SIZE); + __u8 *buf; int ret; - char *buf = kmalloc(18, GFP_KERNEL); + buf = kmalloc(buf_size, GFP_KERNEL); if (!buf) return -ENOMEM; - ret = hid_hw_raw_request(hdev, 0xf2, buf, 17, HID_FEATURE_REPORT, - HID_REQ_GET_REPORT); + ret = hid_hw_raw_request(hdev, 0xf2, buf, SIXAXIS_REPORT_0xF2_SIZE, + HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + if (ret < 0) { + hid_err(hdev, "can't set operational mode: step 1\n"); + goto out; + } + + /* + * Some compatible controllers like the Speedlink Strike FX and + * Gasia need another query plus an USB interrupt to get operational. + */ + ret = hid_hw_raw_request(hdev, 0xf5, buf, SIXAXIS_REPORT_0xF5_SIZE, + HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + if (ret < 0) { + hid_err(hdev, "can't set operational mode: step 2\n"); + goto out; + } + ret = hid_hw_output_report(hdev, buf, 1); if (ret < 0) - hid_err(hdev, "can't set operational mode\n"); + hid_err(hdev, "can't set operational mode: step 3\n"); +out: kfree(buf); return ret; @@ -1186,7 +1441,7 @@ static int dualshock4_set_operational_bt(struct hid_device *hdev) return ret; } -static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS]) +static void sixaxis_set_leds_from_id(struct sony_sc *sc) { static const __u8 sixaxis_leds[10][4] = { { 0x01, 0x00, 0x00, 0x00 }, @@ -1201,16 +1456,18 @@ static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS]) { 0x01, 0x01, 0x01, 0x01 } }; - BUG_ON(MAX_LEDS < ARRAY_SIZE(sixaxis_leds[0])); + int id = sc->device_id; + + BUILD_BUG_ON(MAX_LEDS < ARRAY_SIZE(sixaxis_leds[0])); if (id < 0) return; id %= 10; - memcpy(values, sixaxis_leds[id], sizeof(sixaxis_leds[id])); + memcpy(sc->led_state, sixaxis_leds[id], sizeof(sixaxis_leds[id])); } -static void dualshock4_set_leds_from_id(int id, __u8 values[MAX_LEDS]) +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] = { @@ -1223,46 +1480,44 @@ static void dualshock4_set_leds_from_id(int id, __u8 values[MAX_LEDS]) /* White */ { 0x01, 0x01, 0x01 } }; - BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0])); + int id = sc->device_id; + + BUILD_BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0])); if (id < 0) return; id %= 7; - memcpy(values, color_code[id], sizeof(color_code[id])); + memcpy(sc->led_state, color_code[id], sizeof(color_code[id])); } -static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds) +static void buzz_set_leds(struct sony_sc *sc) { + struct hid_device *hdev = sc->hdev; struct list_head *report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); __s32 *value = report->field[0]->value; + BUILD_BUG_ON(MAX_LEDS < 4); + value[0] = 0x00; - value[1] = leds[0] ? 0xff : 0x00; - value[2] = leds[1] ? 0xff : 0x00; - value[3] = leds[2] ? 0xff : 0x00; - value[4] = leds[3] ? 0xff : 0x00; + value[1] = sc->led_state[0] ? 0xff : 0x00; + value[2] = sc->led_state[1] ? 0xff : 0x00; + value[3] = sc->led_state[2] ? 0xff : 0x00; + value[4] = sc->led_state[3] ? 0xff : 0x00; value[5] = 0x00; value[6] = 0x00; hid_hw_request(hdev, report, HID_REQ_SET_REPORT); } -static void sony_set_leds(struct sony_sc *sc, const __u8 *leds, int count) +static void sony_set_leds(struct sony_sc *sc) { - int n; - - BUG_ON(count > MAX_LEDS); - - if (sc->quirks & BUZZ_CONTROLLER && count == 4) { - buzz_set_leds(sc->hdev, leds); - } else { - for (n = 0; n < count; n++) - sc->led_state[n] = leds[n]; + if (!(sc->quirks & BUZZ_CONTROLLER)) schedule_work(&sc->state_worker); - } + else + buzz_set_leds(sc); } static void sony_led_set_brightness(struct led_classdev *led, @@ -1302,8 +1557,7 @@ static void sony_led_set_brightness(struct led_classdev *led, drv_data->led_delay_on[n] = 0; drv_data->led_delay_off[n] = 0; - sony_set_leds(drv_data, drv_data->led_state, - drv_data->led_count); + sony_set_leds(drv_data); break; } } @@ -1409,7 +1663,6 @@ static int sony_leds_init(struct sony_sc *sc) const char *name_fmt; static const char * const ds4_name_str[] = { "red", "green", "blue", "global" }; - __u8 initial_values[MAX_LEDS] = { 0 }; __u8 max_brightness[MAX_LEDS] = { [0 ... (MAX_LEDS - 1)] = 1 }; __u8 use_hw_blink[MAX_LEDS] = { 0 }; @@ -1424,16 +1677,31 @@ static int sony_leds_init(struct sony_sc *sc) 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->device_id, initial_values); - initial_values[3] = 1; + 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; + name_len = 0; + name_fmt = "%s:%s"; + } else if (sc->quirks & NAVIGATION_CONTROLLER) { + static const __u8 navigation_leds[4] = {0x01, 0x00, 0x00, 0x00}; + + memcpy(sc->led_state, navigation_leds, sizeof(navigation_leds)); + sc->led_count = 1; + memset(use_hw_blink, 1, 4); + use_ds4_names = 0; + name_len = strlen("::sony#"); + name_fmt = "%s::sony%d"; } else { - sixaxis_set_leds_from_id(sc->device_id, initial_values); + sixaxis_set_leds_from_id(sc); sc->led_count = 4; memset(use_hw_blink, 1, 4); use_ds4_names = 0; @@ -1446,7 +1714,7 @@ static int sony_leds_init(struct sony_sc *sc) * only relevant if the driver is loaded after somebody actively set the * LEDs to on */ - sony_set_leds(sc, initial_values, sc->led_count); + sony_set_leds(sc); name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1; @@ -1469,7 +1737,7 @@ static int sony_leds_init(struct sony_sc *sc) else snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1); led->name = name; - led->brightness = initial_values[n]; + led->brightness = sc->led_state[n]; led->max_brightness = max_brightness[n]; led->brightness_get = sony_led_get_brightness; led->brightness_set = sony_led_set_brightness; @@ -1600,9 +1868,31 @@ static void dualshock4_state_worker(struct work_struct *work) HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); } +static void motion_state_worker(struct work_struct *work) +{ + struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); + struct hid_device *hdev = sc->hdev; + struct motion_output_report_02 *report = + (struct motion_output_report_02 *)sc->output_report_dmabuf; + + memset(report, 0, MOTION_REPORT_0x02_SIZE); + + report->type = 0x02; /* set leds */ + report->r = sc->led_state[0]; + report->g = sc->led_state[1]; + report->b = sc->led_state[2]; + +#ifdef CONFIG_SONY_FF + report->rumble = max(sc->right, sc->left); +#endif + + hid_hw_output_report(hdev, (__u8 *)report, MOTION_REPORT_0x02_SIZE); +} + static int sony_allocate_output_report(struct sony_sc *sc) { - if (sc->quirks & SIXAXIS_CONTROLLER) + if ((sc->quirks & SIXAXIS_CONTROLLER) || + (sc->quirks & NAVIGATION_CONTROLLER)) sc->output_report_dmabuf = kmalloc(sizeof(union sixaxis_output_report_01), GFP_KERNEL); @@ -1612,6 +1902,9 @@ static int sony_allocate_output_report(struct sony_sc *sc) else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) sc->output_report_dmabuf = kmalloc(DS4_REPORT_0x05_SIZE, GFP_KERNEL); + else if (sc->quirks & MOTION_CONTROLLER) + sc->output_report_dmabuf = kmalloc(MOTION_REPORT_0x02_SIZE, + GFP_KERNEL); else return 0; @@ -1660,7 +1953,7 @@ static int sony_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { - struct sony_sc *sc = container_of(psy, struct sony_sc, battery); + struct sony_sc *sc = power_supply_get_drvdata(psy); unsigned long flags; int ret = 0; u8 battery_charging, battery_capacity, cable_state; @@ -1699,6 +1992,7 @@ static int sony_battery_get_property(struct power_supply *psy, static int sony_battery_probe(struct sony_sc *sc) { + struct power_supply_config psy_cfg = { .drv_data = sc, }; struct hid_device *hdev = sc->hdev; int ret; @@ -1708,39 +2002,42 @@ static int sony_battery_probe(struct sony_sc *sc) */ sc->battery_capacity = 100; - sc->battery.properties = sony_battery_props; - sc->battery.num_properties = ARRAY_SIZE(sony_battery_props); - sc->battery.get_property = sony_battery_get_property; - sc->battery.type = POWER_SUPPLY_TYPE_BATTERY; - sc->battery.use_for_apm = 0; - sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%pMR", - sc->mac_address); - if (!sc->battery.name) + sc->battery_desc.properties = sony_battery_props; + sc->battery_desc.num_properties = ARRAY_SIZE(sony_battery_props); + sc->battery_desc.get_property = sony_battery_get_property; + sc->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; + sc->battery_desc.use_for_apm = 0; + sc->battery_desc.name = kasprintf(GFP_KERNEL, + "sony_controller_battery_%pMR", + sc->mac_address); + if (!sc->battery_desc.name) return -ENOMEM; - ret = power_supply_register(&hdev->dev, &sc->battery); - if (ret) { + sc->battery = power_supply_register(&hdev->dev, &sc->battery_desc, + &psy_cfg); + if (IS_ERR(sc->battery)) { + ret = PTR_ERR(sc->battery); hid_err(hdev, "Unable to register battery device\n"); goto err_free; } - power_supply_powers(&sc->battery, &hdev->dev); + power_supply_powers(sc->battery, &hdev->dev); return 0; err_free: - kfree(sc->battery.name); - sc->battery.name = NULL; + kfree(sc->battery_desc.name); + sc->battery_desc.name = NULL; return ret; } static void sony_battery_remove(struct sony_sc *sc) { - if (!sc->battery.name) + if (!sc->battery_desc.name) return; - power_supply_unregister(&sc->battery); - kfree(sc->battery.name); - sc->battery.name = NULL; + power_supply_unregister(sc->battery); + kfree(sc->battery_desc.name); + sc->battery_desc.name = NULL; } /* @@ -1813,6 +2110,8 @@ static int sony_check_add(struct sony_sc *sc) int n, ret; if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) || + (sc->quirks & MOTION_CONTROLLER_BT) || + (sc->quirks & NAVIGATION_CONTROLLER_BT) || (sc->quirks & SIXAXIS_CONTROLLER_BT)) { /* * sony_get_bt_devaddr() attempts to parse the Bluetooth MAC @@ -1845,7 +2144,8 @@ static int sony_check_add(struct sony_sc *sc) } memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address)); - } else if (sc->quirks & SIXAXIS_CONTROLLER_USB) { + } else if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || + (sc->quirks & NAVIGATION_CONTROLLER_USB)) { buf = kmalloc(SIXAXIS_REPORT_0xF2_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1967,19 +2267,20 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } - ret = sony_allocate_output_report(sc); + ret = sony_set_device_id(sc); if (ret < 0) { - hid_err(hdev, "failed to allocate the output report buffer\n"); + hid_err(hdev, "failed to allocate the device id\n"); goto err_stop; } - ret = sony_set_device_id(sc); + ret = sony_allocate_output_report(sc); if (ret < 0) { - hid_err(hdev, "failed to allocate the device id\n"); + hid_err(hdev, "failed to allocate the output report buffer\n"); goto err_stop; } - if (sc->quirks & SIXAXIS_CONTROLLER_USB) { + if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || + (sc->quirks & NAVIGATION_CONTROLLER_USB)) { /* * The Sony Sixaxis does not handle HID Output Reports on the * Interrupt EP like it could, so we need to force HID Output @@ -1994,7 +2295,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID; ret = sixaxis_set_operational_usb(hdev); sony_init_work(sc, sixaxis_state_worker); - } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) { + } else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) || + (sc->quirks & NAVIGATION_CONTROLLER_BT)) { /* * The Sixaxis wants output reports sent on the ctrl endpoint * when connected via Bluetooth. @@ -2017,6 +2319,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) } sony_init_work(sc, dualshock4_state_worker); + } else if (sc->quirks & MOTION_CONTROLLER) { + sony_init_work(sc, motion_state_worker); } else { ret = 0; } @@ -2096,7 +2400,13 @@ static const struct hid_device_id sony_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER), - .driver_data = SIXAXIS_CONTROLLER_USB }, + .driver_data = NAVIGATION_CONTROLLER_USB }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER), + .driver_data = NAVIGATION_CONTROLLER_BT }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), + .driver_data = MOTION_CONTROLLER_USB }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), + .driver_data = MOTION_CONTROLLER_BT }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_BT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), |