summaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-sony.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/hid-sony.c')
-rw-r--r--drivers/hid/hid-sony.c37
1 files changed, 30 insertions, 7 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 31e9d2561106..27f67e7ebf10 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -802,9 +802,10 @@ union sixaxis_output_report_01 {
#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
-static spinlock_t sony_dev_list_lock;
+static DEFINE_SPINLOCK(sony_dev_list_lock);
static LIST_HEAD(sony_device_list);
static DEFINE_IDA(sony_device_id_allocator);
@@ -1130,18 +1131,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;
@@ -1944,6 +1965,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
return -ENOMEM;
}
+ spin_lock_init(&sc->lock);
+
sc->quirks = quirks;
hid_set_drvdata(hdev, sc);
sc->hdev = hdev;
@@ -2147,8 +2170,8 @@ static void __exit sony_exit(void)
{
dbg_hid("Sony:%s\n", __func__);
- ida_destroy(&sony_device_id_allocator);
hid_unregister_driver(&sony_driver);
+ ida_destroy(&sony_device_id_allocator);
}
module_init(sony_init);
module_exit(sony_exit);