aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-sony.c
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2014-03-08 22:52:42 -0500
committerJiri Kosina <jkosina@suse.cz>2014-03-14 10:30:20 -0400
commite534a9352237e84263cecedff283387b144b3ed8 (patch)
tree59ef11db183e22e6192c7a5ab9587a62c0ad7dd1 /drivers/hid/hid-sony.c
parent65ab2fc479fa8554e26d6d1726a4ebe6f29a73be (diff)
HID: sony: do not rely on hid_output_raw_report
hid_out_raw_report is going to be obsoleted as it is not part of the unified HID low level transport documentation (Documentation/hid/hid-transport.txt) To do so, we need to introduce two new quirks: * HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP: this quirks prevents the transport driver to use the interrupt channel to send output report (and thus force to use HID_REQ_SET_REPORT command) * HID_QUIRK_SKIP_OUTPUT_REPORT_ID: this one forces usbhid to not include the report ID in the buffer it sends to the device through HID_REQ_SET_REPORT in case of an output report This also fixes a regression introduced in commit 3a75b24949a8 (HID: hidraw: replace hid_output_raw_report() calls by appropriates ones). The hidraw API was not able to communicate with the PS3 SixAxis controllers in USB mode. Reviewed-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Tested-by: Antonio Ospite <ao2@ao2.it> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-sony.c')
-rw-r--r--drivers/hid/hid-sony.c60
1 files changed, 14 insertions, 46 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index b5fe65e70dc4..4884bb567bf8 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -29,7 +29,6 @@
29#include <linux/hid.h> 29#include <linux/hid.h>
30#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/slab.h> 31#include <linux/slab.h>
32#include <linux/usb.h>
33#include <linux/leds.h> 32#include <linux/leds.h>
34#include <linux/power_supply.h> 33#include <linux/power_supply.h>
35#include <linux/spinlock.h> 34#include <linux/spinlock.h>
@@ -1007,45 +1006,6 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
1007} 1006}
1008 1007
1009/* 1008/*
1010 * The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
1011 * like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
1012 * so we need to override that forcing HID Output Reports on the Control EP.
1013 *
1014 * There is also another issue about HID Output Reports via USB, the Sixaxis
1015 * does not want the report_id as part of the data packet, so we have to
1016 * discard buf[0] when sending the actual control message, even for numbered
1017 * reports, humpf!
1018 */
1019static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
1020 size_t count, unsigned char report_type)
1021{
1022 struct usb_interface *intf = to_usb_interface(hid->dev.parent);
1023 struct usb_device *dev = interface_to_usbdev(intf);
1024 struct usb_host_interface *interface = intf->cur_altsetting;
1025 int report_id = buf[0];
1026 int ret;
1027
1028 if (report_type == HID_OUTPUT_REPORT) {
1029 /* Don't send the Report ID */
1030 buf++;
1031 count--;
1032 }
1033
1034 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
1035 HID_REQ_SET_REPORT,
1036 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
1037 ((report_type + 1) << 8) | report_id,
1038 interface->desc.bInterfaceNumber, buf, count,
1039 USB_CTRL_SET_TIMEOUT);
1040
1041 /* Count also the Report ID, in case of an Output report. */
1042 if (ret > 0 && report_type == HID_OUTPUT_REPORT)
1043 ret++;
1044
1045 return ret;
1046}
1047
1048/*
1049 * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller 1009 * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
1050 * to "operational". Without this, the ps3 controller will not report any 1010 * to "operational". Without this, the ps3 controller will not report any
1051 * events. 1011 * events.
@@ -1305,11 +1265,8 @@ static void sixaxis_state_worker(struct work_struct *work)
1305 buf[10] |= sc->led_state[2] << 3; 1265 buf[10] |= sc->led_state[2] << 3;
1306 buf[10] |= sc->led_state[3] << 4; 1266 buf[10] |= sc->led_state[3] << 4;
1307 1267
1308 if (sc->quirks & SIXAXIS_CONTROLLER_USB) 1268 hid_hw_raw_request(sc->hdev, 0x01, buf, sizeof(buf), HID_OUTPUT_REPORT,
1309 hid_output_raw_report(sc->hdev, buf, sizeof(buf), HID_OUTPUT_REPORT); 1269 HID_REQ_SET_REPORT);
1310 else
1311 hid_hw_raw_request(sc->hdev, 0x01, buf, sizeof(buf),
1312 HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
1313} 1270}
1314 1271
1315static void dualshock4_state_worker(struct work_struct *work) 1272static void dualshock4_state_worker(struct work_struct *work)
@@ -1659,7 +1616,18 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
1659 } 1616 }
1660 1617
1661 if (sc->quirks & SIXAXIS_CONTROLLER_USB) { 1618 if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
1662 hdev->hid_output_raw_report = sixaxis_usb_output_raw_report; 1619 /*
1620 * The Sony Sixaxis does not handle HID Output Reports on the
1621 * Interrupt EP like it could, so we need to force HID Output
1622 * Reports to use HID_REQ_SET_REPORT on the Control EP.
1623 *
1624 * There is also another issue about HID Output Reports via USB,
1625 * the Sixaxis does not want the report_id as part of the data
1626 * packet, so we have to discard buf[0] when sending the actual
1627 * control message, even for numbered reports, humpf!
1628 */
1629 hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
1630 hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
1663 ret = sixaxis_set_operational_usb(hdev); 1631 ret = sixaxis_set_operational_usb(hdev);
1664 sc->worker_initialized = 1; 1632 sc->worker_initialized = 1;
1665 INIT_WORK(&sc->state_worker, sixaxis_state_worker); 1633 INIT_WORK(&sc->state_worker, sixaxis_state_worker);