diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 11:58:38 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-07 11:58:38 -0700 |
commit | bc75450cc3db3485db1e289fef8c1028ba38296a (patch) | |
tree | cd7dca62f9f60524ed5241a9e2fbdce1c8ab0bb7 /drivers/hid/hid-sony.c | |
parent | e6e3d8f8f4f06caf25004c749bb2ba84f18c7d39 (diff) | |
parent | 179023e6af0c608ffb505821223f5580853ef6b8 (diff) | |
download | lwn-bc75450cc3db3485db1e289fef8c1028ba38296a.tar.gz lwn-bc75450cc3db3485db1e289fef8c1028ba38296a.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina:
- Integrated Sensor Hub support (Cherrytrail+) from Srinivas Pandruvada
- Big cleanup of Wacom driver; namely it's now using devres, and the
standardized LED API so that libinput doesn't need to have root
access any more, with substantial amount of other cleanups
piggy-backing on top. All this from Benjamin Tissoires
- Report descriptor parsing would now ignore and out-of-range System
controls in case of the application actually being System Control.
This fixes quite some issues with several devices, and allows us to
remove a few ->report_fixup callbacks. From Benjamin Tissoires
- ... a lot of other assorted small fixes and device ID additions
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (76 commits)
HID: add missing \n to end of dev_warn messages
HID: alps: fix multitouch cursor issue
HID: hid-logitech: Documentation updates/corrections
HID: hid-logitech: Improve Wingman Formula Force GP support
HID: hid-logitech: Rewrite of descriptor for all DF wheels
HID: hid-logitech: Compute combined pedals value
HID: hid-logitech: Add combined pedal support Logitech wheels
HID: hid-logitech: Introduce control for combined pedals feature
HID: sony: Update copyright and add Dualshock 4 rate control note
HID: sony: Defer the initial USB Sixaxis output report
HID: sony: Relax duplicate checking for USB-only devices
Revert "HID: microsoft: fix invalid rdesc for 3k kbd"
HID: alps: fix error return code in alps_input_configured()
HID: alps: fix stick device not working after resume
HID: support for keyboard - Corsair STRAFE
HID: alps: Fix memory leak
HID: uclogic: Add support for UC-Logic TWHA60 v3
HID: uclogic: Override constant descriptors
HID: uclogic: Support UGTizer GP0610 partially
HID: uclogic: Add support for several more tablets
...
Diffstat (limited to 'drivers/hid/hid-sony.c')
-rw-r--r-- | drivers/hid/hid-sony.c | 88 |
1 files changed, 74 insertions, 14 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 310436a54a3f..b0bb99a821bd 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -8,7 +8,7 @@ * Copyright (c) 2012 David Dillow <dave@thedillows.org> * Copyright (c) 2006-2013 Jiri Kosina * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com> - * Copyright (c) 2014 Frank Praznik <frank.praznik@gmail.com> + * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com> */ /* @@ -51,6 +51,7 @@ #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 SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) @@ -65,6 +66,8 @@ 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) #define MAX_LEDS 4 @@ -1048,6 +1051,7 @@ struct sony_sc { u8 mac_address[6]; u8 worker_initialized; + u8 defer_initialization; u8 cable_state; u8 battery_charging; u8 battery_capacity; @@ -1058,6 +1062,12 @@ struct sony_sc { u8 led_count; }; +static inline void sony_schedule_work(struct sony_sc *sc) +{ + if (!sc->defer_initialization) + schedule_work(&sc->state_worker); +} + static u8 *sixaxis_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *rsize) { @@ -1125,7 +1135,7 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc, { struct sony_sc *sc = hid_get_drvdata(hdev); - if (sc->quirks & SINO_LITE_CONTROLLER) + if (sc->quirks & (SINO_LITE_CONTROLLER | FUTUREMAX_DANCE_MAT)) return rdesc; /* @@ -1317,6 +1327,11 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, dualshock4_parse_report(sc, rd, size); } + if (sc->defer_initialization) { + sc->defer_initialization = 0; + sony_schedule_work(sc); + } + return 0; } @@ -1554,7 +1569,7 @@ static void buzz_set_leds(struct sony_sc *sc) static void sony_set_leds(struct sony_sc *sc) { if (!(sc->quirks & BUZZ_CONTROLLER)) - schedule_work(&sc->state_worker); + sony_schedule_work(sc); else buzz_set_leds(sc); } @@ -1665,7 +1680,7 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on, new_off != drv_data->led_delay_off[n]) { drv_data->led_delay_on[n] = new_on; drv_data->led_delay_off[n] = new_off; - schedule_work(&drv_data->state_worker); + sony_schedule_work(drv_data); } return 0; @@ -1865,6 +1880,17 @@ static void dualshock4_send_output_report(struct sony_sc *sc) u8 *buf = sc->output_report_dmabuf; int offset; + /* + * NOTE: The buf[1] field of the Bluetooth report controls + * the Dualshock 4 reporting rate. + * + * Known values include: + * + * 0x80 - 1000hz (full speed) + * 0xA0 - 31hz + * 0xB0 - 20hz + * 0xD0 - 66hz + */ if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { memset(buf, 0, DS4_REPORT_0x05_SIZE); buf[0] = 0x05; @@ -1976,7 +2002,7 @@ static int sony_play_effect(struct input_dev *dev, void *data, sc->left = effect->u.rumble.strong_magnitude / 256; sc->right = effect->u.rumble.weak_magnitude / 256; - schedule_work(&sc->state_worker); + sony_schedule_work(sc); return 0; } @@ -2039,8 +2065,11 @@ static int sony_battery_get_property(struct power_supply *psy, return ret; } -static int sony_battery_probe(struct sony_sc *sc) +static int sony_battery_probe(struct sony_sc *sc, int append_dev_id) { + const char *battery_str_fmt = append_dev_id ? + "sony_controller_battery_%pMR_%i" : + "sony_controller_battery_%pMR"; struct power_supply_config psy_cfg = { .drv_data = sc, }; struct hid_device *hdev = sc->hdev; int ret; @@ -2056,9 +2085,8 @@ static int sony_battery_probe(struct sony_sc *sc) 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); + sc->battery_desc.name = kasprintf(GFP_KERNEL, battery_str_fmt, + sc->mac_address, sc->device_id); if (!sc->battery_desc.name) return -ENOMEM; @@ -2094,7 +2122,21 @@ static void sony_battery_remove(struct sony_sc *sc) * it will show up as two devices. A global list of connected controllers and * their MAC addresses is maintained to ensure that a device is only connected * once. + * + * Some USB-only devices masquerade as Sixaxis controllers and all have the + * same dummy Bluetooth address, so a comparison of the connection type is + * required. Devices are only rejected in the case where two devices have + * matching Bluetooth addresses on different bus types. */ +static inline int sony_compare_connection_type(struct sony_sc *sc0, + struct sony_sc *sc1) +{ + const int sc0_not_bt = !(sc0->quirks & SONY_BT_DEVICE); + const int sc1_not_bt = !(sc1->quirks & SONY_BT_DEVICE); + + return sc0_not_bt == sc1_not_bt; +} + static int sony_check_add_dev_list(struct sony_sc *sc) { struct sony_sc *entry; @@ -2107,9 +2149,14 @@ static int sony_check_add_dev_list(struct sony_sc *sc) ret = memcmp(sc->mac_address, entry->mac_address, sizeof(sc->mac_address)); if (!ret) { - ret = -EEXIST; - hid_info(sc->hdev, "controller with MAC address %pMR already connected\n", + if (sony_compare_connection_type(sc, entry)) { + ret = 1; + } else { + ret = -EEXIST; + hid_info(sc->hdev, + "controller with MAC address %pMR already connected\n", sc->mac_address); + } goto unlock; } } @@ -2285,10 +2332,14 @@ static inline void sony_cancel_work_sync(struct sony_sc *sc) static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret; + int append_dev_id; unsigned long quirks = id->driver_data; struct sony_sc *sc; unsigned int connect_mask = HID_CONNECT_DEFAULT; + if (!strcmp(hdev->name, "FutureMax Dance Mat")) + quirks |= FUTUREMAX_DANCE_MAT; + sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL); if (sc == NULL) { hid_err(hdev, "can't alloc sony descriptor\n"); @@ -2341,9 +2392,16 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) * the Sixaxis does not want the report_id as part of the data * packet, so we have to discard buf[0] when sending the actual * control message, even for numbered reports, humpf! + * + * Additionally, the Sixaxis on USB isn't properly initialized + * until the PS logo button is pressed and as such won't retain + * any state set by an output report, so the initial + * configuration report is deferred until the first input + * report arrives. */ hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID; + sc->defer_initialization = 1; ret = sixaxis_set_operational_usb(hdev); sony_init_output_report(sc, sixaxis_send_output_report); } else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) || @@ -2379,7 +2437,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret < 0) goto err_stop; - ret = sony_check_add(sc); + ret = append_dev_id = sony_check_add(sc); if (ret < 0) goto err_stop; @@ -2390,7 +2448,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) } if (sc->quirks & SONY_BATTERY_SUPPORT) { - ret = sony_battery_probe(sc); + ret = sony_battery_probe(sc, append_dev_id); if (ret < 0) goto err_stop; @@ -2486,8 +2544,10 @@ static int sony_resume(struct hid_device *hdev) * reinitialized on resume or they won't behave properly. */ if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || - (sc->quirks & NAVIGATION_CONTROLLER_USB)) + (sc->quirks & NAVIGATION_CONTROLLER_USB)) { sixaxis_set_operational_usb(sc->hdev); + sc->defer_initialization = 1; + } sony_set_leds(sc); } |