aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-sony.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/hid/hid-sony.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'drivers/hid/hid-sony.c')
-rw-r--r--drivers/hid/hid-sony.c89
1 files changed, 66 insertions, 23 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 402d5574b574..936c911fdca6 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -24,24 +24,65 @@
24 24
25#include "hid-ids.h" 25#include "hid-ids.h"
26 26
27#define VAIO_RDESC_CONSTANT 0x0001 27#define VAIO_RDESC_CONSTANT (1 << 0)
28#define SIXAXIS_CONTROLLER_USB (1 << 1)
29#define SIXAXIS_CONTROLLER_BT (1 << 2)
28 30
29struct sony_sc { 31struct sony_sc {
30 unsigned long quirks; 32 unsigned long quirks;
31}; 33};
32 34
33/* Sony Vaio VGX has wrongly mouse pointer declared as constant */ 35/* Sony Vaio VGX has wrongly mouse pointer declared as constant */
34static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, 36static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
35 unsigned int rsize) 37 unsigned int *rsize)
36{ 38{
37 struct sony_sc *sc = hid_get_drvdata(hdev); 39 struct sony_sc *sc = hid_get_drvdata(hdev);
38 40
39 if ((sc->quirks & VAIO_RDESC_CONSTANT) && 41 if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
40 rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) { 42 *rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
41 dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report " 43 hid_info(hdev, "Fixing up Sony Vaio VGX report descriptor\n");
42 "descriptor\n");
43 rdesc[55] = 0x06; 44 rdesc[55] = 0x06;
44 } 45 }
46 return rdesc;
47}
48
49/*
50 * The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
51 * like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
52 * so we need to override that forcing HID Output Reports on the Control EP.
53 *
54 * There is also another issue about HID Output Reports via USB, the Sixaxis
55 * does not want the report_id as part of the data packet, so we have to
56 * discard buf[0] when sending the actual control message, even for numbered
57 * reports, humpf!
58 */
59static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
60 size_t count, unsigned char report_type)
61{
62 struct usb_interface *intf = to_usb_interface(hid->dev.parent);
63 struct usb_device *dev = interface_to_usbdev(intf);
64 struct usb_host_interface *interface = intf->cur_altsetting;
65 int report_id = buf[0];
66 int ret;
67
68 if (report_type == HID_OUTPUT_REPORT) {
69 /* Don't send the Report ID */
70 buf++;
71 count--;
72 }
73
74 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
75 HID_REQ_SET_REPORT,
76 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
77 ((report_type + 1) << 8) | report_id,
78 interface->desc.bInterfaceNumber, buf, count,
79 USB_CTRL_SET_TIMEOUT);
80
81 /* Count also the Report ID, in case of an Output report. */
82 if (ret > 0 && report_type == HID_OUTPUT_REPORT)
83 ret++;
84
85 return ret;
45} 86}
46 87
47/* 88/*
@@ -49,7 +90,7 @@ static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
49 * to "operational". Without this, the ps3 controller will not report any 90 * to "operational". Without this, the ps3 controller will not report any
50 * events. 91 * events.
51 */ 92 */
52static int sony_set_operational_usb(struct hid_device *hdev) 93static int sixaxis_set_operational_usb(struct hid_device *hdev)
53{ 94{
54 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 95 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
55 struct usb_device *dev = interface_to_usbdev(intf); 96 struct usb_device *dev = interface_to_usbdev(intf);
@@ -67,14 +108,14 @@ static int sony_set_operational_usb(struct hid_device *hdev)
67 (3 << 8) | 0xf2, ifnum, buf, 17, 108 (3 << 8) | 0xf2, ifnum, buf, 17,
68 USB_CTRL_GET_TIMEOUT); 109 USB_CTRL_GET_TIMEOUT);
69 if (ret < 0) 110 if (ret < 0)
70 dev_err(&hdev->dev, "can't set operational mode\n"); 111 hid_err(hdev, "can't set operational mode\n");
71 112
72 kfree(buf); 113 kfree(buf);
73 114
74 return ret; 115 return ret;
75} 116}
76 117
77static int sony_set_operational_bt(struct hid_device *hdev) 118static int sixaxis_set_operational_bt(struct hid_device *hdev)
78{ 119{
79 unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; 120 unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
80 return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); 121 return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
@@ -88,7 +129,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
88 129
89 sc = kzalloc(sizeof(*sc), GFP_KERNEL); 130 sc = kzalloc(sizeof(*sc), GFP_KERNEL);
90 if (sc == NULL) { 131 if (sc == NULL) {
91 dev_err(&hdev->dev, "can't alloc sony descriptor\n"); 132 hid_err(hdev, "can't alloc sony descriptor\n");
92 return -ENOMEM; 133 return -ENOMEM;
93 } 134 }
94 135
@@ -97,27 +138,25 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
97 138
98 ret = hid_parse(hdev); 139 ret = hid_parse(hdev);
99 if (ret) { 140 if (ret) {
100 dev_err(&hdev->dev, "parse failed\n"); 141 hid_err(hdev, "parse failed\n");
101 goto err_free; 142 goto err_free;
102 } 143 }
103 144
104 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | 145 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
105 HID_CONNECT_HIDDEV_FORCE); 146 HID_CONNECT_HIDDEV_FORCE);
106 if (ret) { 147 if (ret) {
107 dev_err(&hdev->dev, "hw start failed\n"); 148 hid_err(hdev, "hw start failed\n");
108 goto err_free; 149 goto err_free;
109 } 150 }
110 151
111 switch (hdev->bus) { 152 if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
112 case BUS_USB: 153 hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
113 ret = sony_set_operational_usb(hdev); 154 ret = sixaxis_set_operational_usb(hdev);
114 break;
115 case BUS_BLUETOOTH:
116 ret = sony_set_operational_bt(hdev);
117 break;
118 default:
119 ret = 0;
120 } 155 }
156 else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
157 ret = sixaxis_set_operational_bt(hdev);
158 else
159 ret = 0;
121 160
122 if (ret < 0) 161 if (ret < 0)
123 goto err_stop; 162 goto err_stop;
@@ -137,8 +176,12 @@ static void sony_remove(struct hid_device *hdev)
137} 176}
138 177
139static const struct hid_device_id sony_devices[] = { 178static const struct hid_device_id sony_devices[] = {
140 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, 179 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
141 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, 180 .driver_data = SIXAXIS_CONTROLLER_USB },
181 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER),
182 .driver_data = SIXAXIS_CONTROLLER_USB },
183 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
184 .driver_data = SIXAXIS_CONTROLLER_BT },
142 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), 185 { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
143 .driver_data = VAIO_RDESC_CONSTANT }, 186 .driver_data = VAIO_RDESC_CONSTANT },
144 { } 187 { }