xref: /linux/drivers/hid/hid-sony.c (revision a464918419f94a0043d2f549d6defb4c3f69f68a)
1bd28ce00SJiri Slaby /*
2bd28ce00SJiri Slaby  *  HID driver for some sony "special" devices
3bd28ce00SJiri Slaby  *
4bd28ce00SJiri Slaby  *  Copyright (c) 1999 Andreas Gal
5bd28ce00SJiri Slaby  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
6bd28ce00SJiri Slaby  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
7bd28ce00SJiri Slaby  *  Copyright (c) 2008 Jiri Slaby
8cc6e0bbbSJiri Kosina  *  Copyright (c) 2006-2008 Jiri Kosina
9bd28ce00SJiri Slaby  */
10bd28ce00SJiri Slaby 
11bd28ce00SJiri Slaby /*
12bd28ce00SJiri Slaby  * This program is free software; you can redistribute it and/or modify it
13bd28ce00SJiri Slaby  * under the terms of the GNU General Public License as published by the Free
14bd28ce00SJiri Slaby  * Software Foundation; either version 2 of the License, or (at your option)
15bd28ce00SJiri Slaby  * any later version.
16bd28ce00SJiri Slaby  */
17bd28ce00SJiri Slaby 
18bd28ce00SJiri Slaby #include <linux/device.h>
19bd28ce00SJiri Slaby #include <linux/hid.h>
20bd28ce00SJiri Slaby #include <linux/module.h>
215a0e3ad6STejun Heo #include <linux/slab.h>
22bd28ce00SJiri Slaby #include <linux/usb.h>
23bd28ce00SJiri Slaby 
24bd28ce00SJiri Slaby #include "hid-ids.h"
25bd28ce00SJiri Slaby 
26816651a7SAntonio Ospite #define VAIO_RDESC_CONSTANT     (1 << 0)
27816651a7SAntonio Ospite #define SIXAXIS_CONTROLLER_USB  (1 << 1)
28816651a7SAntonio Ospite #define SIXAXIS_CONTROLLER_BT   (1 << 2)
29cc6e0bbbSJiri Kosina 
3061ab44beSSimon Wood static const u8 sixaxis_rdesc_fixup[] = {
3161ab44beSSimon Wood 	0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x95, 0x0C,
3261ab44beSSimon Wood 	0x81, 0x01, 0x75, 0x10, 0x95, 0x04, 0x26, 0xFF,
3361ab44beSSimon Wood 	0x03, 0x46, 0xFF, 0x03, 0x09, 0x01, 0x81, 0x02
3461ab44beSSimon Wood };
3561ab44beSSimon Wood 
36e57a67daSMauro Carvalho Chehab static const u8 sixaxis_rdesc_fixup2[] = {
37e57a67daSMauro Carvalho Chehab 	0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0xa1, 0x02,
38e57a67daSMauro Carvalho Chehab 	0x85, 0x01, 0x75, 0x08, 0x95, 0x01, 0x15, 0x00,
39e57a67daSMauro Carvalho Chehab 	0x26, 0xff, 0x00, 0x81, 0x03, 0x75, 0x01, 0x95,
40e57a67daSMauro Carvalho Chehab 	0x13, 0x15, 0x00, 0x25, 0x01, 0x35, 0x00, 0x45,
41e57a67daSMauro Carvalho Chehab 	0x01, 0x05, 0x09, 0x19, 0x01, 0x29, 0x13, 0x81,
42e57a67daSMauro Carvalho Chehab 	0x02, 0x75, 0x01, 0x95, 0x0d, 0x06, 0x00, 0xff,
43e57a67daSMauro Carvalho Chehab 	0x81, 0x03, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05,
44e57a67daSMauro Carvalho Chehab 	0x01, 0x09, 0x01, 0xa1, 0x00, 0x75, 0x08, 0x95,
45e57a67daSMauro Carvalho Chehab 	0x04, 0x35, 0x00, 0x46, 0xff, 0x00, 0x09, 0x30,
46e57a67daSMauro Carvalho Chehab 	0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x81, 0x02,
47e57a67daSMauro Carvalho Chehab 	0xc0, 0x05, 0x01, 0x95, 0x13, 0x09, 0x01, 0x81,
48e57a67daSMauro Carvalho Chehab 	0x02, 0x95, 0x0c, 0x81, 0x01, 0x75, 0x10, 0x95,
49e57a67daSMauro Carvalho Chehab 	0x04, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x09,
50e57a67daSMauro Carvalho Chehab 	0x01, 0x81, 0x02, 0xc0, 0xa1, 0x02, 0x85, 0x02,
51e57a67daSMauro Carvalho Chehab 	0x75, 0x08, 0x95, 0x30, 0x09, 0x01, 0xb1, 0x02,
52e57a67daSMauro Carvalho Chehab 	0xc0, 0xa1, 0x02, 0x85, 0xee, 0x75, 0x08, 0x95,
53e57a67daSMauro Carvalho Chehab 	0x30, 0x09, 0x01, 0xb1, 0x02, 0xc0, 0xa1, 0x02,
54e57a67daSMauro Carvalho Chehab 	0x85, 0xef, 0x75, 0x08, 0x95, 0x30, 0x09, 0x01,
55e57a67daSMauro Carvalho Chehab 	0xb1, 0x02, 0xc0, 0xc0,
56e57a67daSMauro Carvalho Chehab };
57e57a67daSMauro Carvalho Chehab 
58cc6e0bbbSJiri Kosina struct sony_sc {
59cc6e0bbbSJiri Kosina 	unsigned long quirks;
60cc6e0bbbSJiri Kosina };
61cc6e0bbbSJiri Kosina 
62cc6e0bbbSJiri Kosina /* Sony Vaio VGX has wrongly mouse pointer declared as constant */
6373e4008dSNikolai Kondrashov static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
6473e4008dSNikolai Kondrashov 		unsigned int *rsize)
65cc6e0bbbSJiri Kosina {
66cc6e0bbbSJiri Kosina 	struct sony_sc *sc = hid_get_drvdata(hdev);
67cc6e0bbbSJiri Kosina 
68cc6e0bbbSJiri Kosina 	if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
6973e4008dSNikolai Kondrashov 			*rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
70*a4649184SFernando Luis Vázquez Cao 		hid_info(hdev, "Fixing up Sony RF Receiver report descriptor\n");
71cc6e0bbbSJiri Kosina 		rdesc[55] = 0x06;
72cc6e0bbbSJiri Kosina 	}
7361ab44beSSimon Wood 
7461ab44beSSimon Wood 	/* The HID descriptor exposed over BT has a trailing zero byte */
7561ab44beSSimon Wood 	if ((((sc->quirks & SIXAXIS_CONTROLLER_USB) && *rsize == 148) ||
7661ab44beSSimon Wood 			((sc->quirks & SIXAXIS_CONTROLLER_BT) && *rsize == 149)) &&
7761ab44beSSimon Wood 			rdesc[83] == 0x75) {
7861ab44beSSimon Wood 		hid_info(hdev, "Fixing up Sony Sixaxis report descriptor\n");
7961ab44beSSimon Wood 		memcpy((void *)&rdesc[83], (void *)&sixaxis_rdesc_fixup,
8061ab44beSSimon Wood 			sizeof(sixaxis_rdesc_fixup));
81e57a67daSMauro Carvalho Chehab 	} else if (sc->quirks & SIXAXIS_CONTROLLER_USB &&
82e57a67daSMauro Carvalho Chehab 		   *rsize > sizeof(sixaxis_rdesc_fixup2)) {
83e57a67daSMauro Carvalho Chehab 		hid_info(hdev, "Sony Sixaxis clone detected. Using original report descriptor (size: %d clone; %d new)\n",
84e57a67daSMauro Carvalho Chehab 			 *rsize, (int)sizeof(sixaxis_rdesc_fixup2));
85e57a67daSMauro Carvalho Chehab 		*rsize = sizeof(sixaxis_rdesc_fixup2);
86e57a67daSMauro Carvalho Chehab 		memcpy(rdesc, &sixaxis_rdesc_fixup2, *rsize);
8761ab44beSSimon Wood 	}
8873e4008dSNikolai Kondrashov 	return rdesc;
89cc6e0bbbSJiri Kosina }
90cc6e0bbbSJiri Kosina 
91c9e4d877SSimon Wood static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
92c9e4d877SSimon Wood 		__u8 *rd, int size)
93c9e4d877SSimon Wood {
94c9e4d877SSimon Wood 	struct sony_sc *sc = hid_get_drvdata(hdev);
95c9e4d877SSimon Wood 
96c9e4d877SSimon Wood 	/* Sixaxis HID report has acclerometers/gyro with MSByte first, this
97c9e4d877SSimon Wood 	 * has to be BYTE_SWAPPED before passing up to joystick interface
98c9e4d877SSimon Wood 	 */
99c9e4d877SSimon Wood 	if ((sc->quirks & (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)) &&
100c9e4d877SSimon Wood 			rd[0] == 0x01 && size == 49) {
101c9e4d877SSimon Wood 		swap(rd[41], rd[42]);
102c9e4d877SSimon Wood 		swap(rd[43], rd[44]);
103c9e4d877SSimon Wood 		swap(rd[45], rd[46]);
104c9e4d877SSimon Wood 		swap(rd[47], rd[48]);
105c9e4d877SSimon Wood 	}
106c9e4d877SSimon Wood 
107c9e4d877SSimon Wood 	return 0;
108c9e4d877SSimon Wood }
109c9e4d877SSimon Wood 
1105710fabfSAntonio Ospite /*
1115710fabfSAntonio Ospite  * The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
1125710fabfSAntonio Ospite  * like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
1135710fabfSAntonio Ospite  * so we need to override that forcing HID Output Reports on the Control EP.
1145710fabfSAntonio Ospite  *
1155710fabfSAntonio Ospite  * There is also another issue about HID Output Reports via USB, the Sixaxis
1165710fabfSAntonio Ospite  * does not want the report_id as part of the data packet, so we have to
1175710fabfSAntonio Ospite  * discard buf[0] when sending the actual control message, even for numbered
1185710fabfSAntonio Ospite  * reports, humpf!
1195710fabfSAntonio Ospite  */
120569b10a5SAntonio Ospite static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
121569b10a5SAntonio Ospite 		size_t count, unsigned char report_type)
122569b10a5SAntonio Ospite {
123569b10a5SAntonio Ospite 	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
124569b10a5SAntonio Ospite 	struct usb_device *dev = interface_to_usbdev(intf);
125569b10a5SAntonio Ospite 	struct usb_host_interface *interface = intf->cur_altsetting;
126569b10a5SAntonio Ospite 	int report_id = buf[0];
127569b10a5SAntonio Ospite 	int ret;
128569b10a5SAntonio Ospite 
1295710fabfSAntonio Ospite 	if (report_type == HID_OUTPUT_REPORT) {
1305710fabfSAntonio Ospite 		/* Don't send the Report ID */
1315710fabfSAntonio Ospite 		buf++;
1325710fabfSAntonio Ospite 		count--;
1335710fabfSAntonio Ospite 	}
1345710fabfSAntonio Ospite 
135569b10a5SAntonio Ospite 	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
136569b10a5SAntonio Ospite 		HID_REQ_SET_REPORT,
137569b10a5SAntonio Ospite 		USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
138569b10a5SAntonio Ospite 		((report_type + 1) << 8) | report_id,
139569b10a5SAntonio Ospite 		interface->desc.bInterfaceNumber, buf, count,
140569b10a5SAntonio Ospite 		USB_CTRL_SET_TIMEOUT);
141569b10a5SAntonio Ospite 
1425710fabfSAntonio Ospite 	/* Count also the Report ID, in case of an Output report. */
1435710fabfSAntonio Ospite 	if (ret > 0 && report_type == HID_OUTPUT_REPORT)
1445710fabfSAntonio Ospite 		ret++;
1455710fabfSAntonio Ospite 
146569b10a5SAntonio Ospite 	return ret;
147569b10a5SAntonio Ospite }
148569b10a5SAntonio Ospite 
149bd28ce00SJiri Slaby /*
150bd28ce00SJiri Slaby  * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
151bd28ce00SJiri Slaby  * to "operational".  Without this, the ps3 controller will not report any
152bd28ce00SJiri Slaby  * events.
153bd28ce00SJiri Slaby  */
154816651a7SAntonio Ospite static int sixaxis_set_operational_usb(struct hid_device *hdev)
155bd28ce00SJiri Slaby {
156bd28ce00SJiri Slaby 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
157bd28ce00SJiri Slaby 	struct usb_device *dev = interface_to_usbdev(intf);
158bd28ce00SJiri Slaby 	__u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
159bd28ce00SJiri Slaby 	int ret;
160bd28ce00SJiri Slaby 	char *buf = kmalloc(18, GFP_KERNEL);
161bd28ce00SJiri Slaby 
162bd28ce00SJiri Slaby 	if (!buf)
163bd28ce00SJiri Slaby 		return -ENOMEM;
164bd28ce00SJiri Slaby 
165bd28ce00SJiri Slaby 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
166bd28ce00SJiri Slaby 				 HID_REQ_GET_REPORT,
167bd28ce00SJiri Slaby 				 USB_DIR_IN | USB_TYPE_CLASS |
168bd28ce00SJiri Slaby 				 USB_RECIP_INTERFACE,
169bd28ce00SJiri Slaby 				 (3 << 8) | 0xf2, ifnum, buf, 17,
170bd28ce00SJiri Slaby 				 USB_CTRL_GET_TIMEOUT);
171bd28ce00SJiri Slaby 	if (ret < 0)
1724291ee30SJoe Perches 		hid_err(hdev, "can't set operational mode\n");
173bd28ce00SJiri Slaby 
174bd28ce00SJiri Slaby 	kfree(buf);
175bd28ce00SJiri Slaby 
176bd28ce00SJiri Slaby 	return ret;
177bd28ce00SJiri Slaby }
178bd28ce00SJiri Slaby 
179816651a7SAntonio Ospite static int sixaxis_set_operational_bt(struct hid_device *hdev)
180f9ce7c28SBastien Nocera {
181fddb33f2SAntonio Ospite 	unsigned char buf[] = { 0xf4,  0x42, 0x03, 0x00, 0x00 };
182f9ce7c28SBastien Nocera 	return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
183f9ce7c28SBastien Nocera }
184f9ce7c28SBastien Nocera 
185bd28ce00SJiri Slaby static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
186bd28ce00SJiri Slaby {
187bd28ce00SJiri Slaby 	int ret;
188cc6e0bbbSJiri Kosina 	unsigned long quirks = id->driver_data;
189cc6e0bbbSJiri Kosina 	struct sony_sc *sc;
190cc6e0bbbSJiri Kosina 
191cc6e0bbbSJiri Kosina 	sc = kzalloc(sizeof(*sc), GFP_KERNEL);
192cc6e0bbbSJiri Kosina 	if (sc == NULL) {
1934291ee30SJoe Perches 		hid_err(hdev, "can't alloc sony descriptor\n");
194cc6e0bbbSJiri Kosina 		return -ENOMEM;
195cc6e0bbbSJiri Kosina 	}
196cc6e0bbbSJiri Kosina 
197cc6e0bbbSJiri Kosina 	sc->quirks = quirks;
198cc6e0bbbSJiri Kosina 	hid_set_drvdata(hdev, sc);
199bd28ce00SJiri Slaby 
200bd28ce00SJiri Slaby 	ret = hid_parse(hdev);
201bd28ce00SJiri Slaby 	if (ret) {
2024291ee30SJoe Perches 		hid_err(hdev, "parse failed\n");
203bd28ce00SJiri Slaby 		goto err_free;
204bd28ce00SJiri Slaby 	}
205bd28ce00SJiri Slaby 
20693c10132SJiri Slaby 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
20793c10132SJiri Slaby 			HID_CONNECT_HIDDEV_FORCE);
208bd28ce00SJiri Slaby 	if (ret) {
2094291ee30SJoe Perches 		hid_err(hdev, "hw start failed\n");
210bd28ce00SJiri Slaby 		goto err_free;
211bd28ce00SJiri Slaby 	}
212bd28ce00SJiri Slaby 
213569b10a5SAntonio Ospite 	if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
214569b10a5SAntonio Ospite 		hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
215816651a7SAntonio Ospite 		ret = sixaxis_set_operational_usb(hdev);
216569b10a5SAntonio Ospite 	}
217816651a7SAntonio Ospite 	else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
218816651a7SAntonio Ospite 		ret = sixaxis_set_operational_bt(hdev);
219816651a7SAntonio Ospite 	else
220f9ce7c28SBastien Nocera 		ret = 0;
221f9ce7c28SBastien Nocera 
2224dfdc464SJiri Kosina 	if (ret < 0)
223bd28ce00SJiri Slaby 		goto err_stop;
224bd28ce00SJiri Slaby 
225bd28ce00SJiri Slaby 	return 0;
226bd28ce00SJiri Slaby err_stop:
227bd28ce00SJiri Slaby 	hid_hw_stop(hdev);
228bd28ce00SJiri Slaby err_free:
229cc6e0bbbSJiri Kosina 	kfree(sc);
230bd28ce00SJiri Slaby 	return ret;
231bd28ce00SJiri Slaby }
232bd28ce00SJiri Slaby 
233cc6e0bbbSJiri Kosina static void sony_remove(struct hid_device *hdev)
234cc6e0bbbSJiri Kosina {
235cc6e0bbbSJiri Kosina 	hid_hw_stop(hdev);
236cc6e0bbbSJiri Kosina 	kfree(hid_get_drvdata(hdev));
237cc6e0bbbSJiri Kosina }
238cc6e0bbbSJiri Kosina 
239bd28ce00SJiri Slaby static const struct hid_device_id sony_devices[] = {
240816651a7SAntonio Ospite 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
241816651a7SAntonio Ospite 		.driver_data = SIXAXIS_CONTROLLER_USB },
24235dca5b4SJiri Kosina 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER),
24335dca5b4SJiri Kosina 		.driver_data = SIXAXIS_CONTROLLER_USB },
244816651a7SAntonio Ospite 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
245816651a7SAntonio Ospite 		.driver_data = SIXAXIS_CONTROLLER_BT },
246cc6e0bbbSJiri Kosina 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
247cc6e0bbbSJiri Kosina 		.driver_data = VAIO_RDESC_CONSTANT },
248*a4649184SFernando Luis Vázquez Cao 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE),
249*a4649184SFernando Luis Vázquez Cao 		.driver_data = VAIO_RDESC_CONSTANT },
250bd28ce00SJiri Slaby 	{ }
251bd28ce00SJiri Slaby };
252bd28ce00SJiri Slaby MODULE_DEVICE_TABLE(hid, sony_devices);
253bd28ce00SJiri Slaby 
254bd28ce00SJiri Slaby static struct hid_driver sony_driver = {
255bd28ce00SJiri Slaby 	.name = "sony",
256bd28ce00SJiri Slaby 	.id_table = sony_devices,
257bd28ce00SJiri Slaby 	.probe = sony_probe,
258cc6e0bbbSJiri Kosina 	.remove = sony_remove,
259cc6e0bbbSJiri Kosina 	.report_fixup = sony_report_fixup,
260c9e4d877SSimon Wood 	.raw_event = sony_raw_event
261bd28ce00SJiri Slaby };
262bd28ce00SJiri Slaby 
263a24f423bSPeter Huewe static int __init sony_init(void)
264bd28ce00SJiri Slaby {
265bd28ce00SJiri Slaby 	return hid_register_driver(&sony_driver);
266bd28ce00SJiri Slaby }
267bd28ce00SJiri Slaby 
268a24f423bSPeter Huewe static void __exit sony_exit(void)
269bd28ce00SJiri Slaby {
270bd28ce00SJiri Slaby 	hid_unregister_driver(&sony_driver);
271bd28ce00SJiri Slaby }
272bd28ce00SJiri Slaby 
273bd28ce00SJiri Slaby module_init(sony_init);
274bd28ce00SJiri Slaby module_exit(sony_exit);
275bd28ce00SJiri Slaby MODULE_LICENSE("GPL");
276