xref: /linux/drivers/hid/hid-sony.c (revision 569b10a506c4d5bc7398d040930539d84d3a2186)
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) 2007 Paul Walmsley
8bd28ce00SJiri Slaby  *  Copyright (c) 2008 Jiri Slaby
9cc6e0bbbSJiri Kosina  *  Copyright (c) 2006-2008 Jiri Kosina
10bd28ce00SJiri Slaby  */
11bd28ce00SJiri Slaby 
12bd28ce00SJiri Slaby /*
13bd28ce00SJiri Slaby  * This program is free software; you can redistribute it and/or modify it
14bd28ce00SJiri Slaby  * under the terms of the GNU General Public License as published by the Free
15bd28ce00SJiri Slaby  * Software Foundation; either version 2 of the License, or (at your option)
16bd28ce00SJiri Slaby  * any later version.
17bd28ce00SJiri Slaby  */
18bd28ce00SJiri Slaby 
19bd28ce00SJiri Slaby #include <linux/device.h>
20bd28ce00SJiri Slaby #include <linux/hid.h>
21bd28ce00SJiri Slaby #include <linux/module.h>
225a0e3ad6STejun Heo #include <linux/slab.h>
23bd28ce00SJiri Slaby #include <linux/usb.h>
24bd28ce00SJiri Slaby 
25bd28ce00SJiri Slaby #include "hid-ids.h"
26bd28ce00SJiri Slaby 
27816651a7SAntonio Ospite #define VAIO_RDESC_CONSTANT     (1 << 0)
28816651a7SAntonio Ospite #define SIXAXIS_CONTROLLER_USB  (1 << 1)
29816651a7SAntonio Ospite #define SIXAXIS_CONTROLLER_BT   (1 << 2)
30cc6e0bbbSJiri Kosina 
31cc6e0bbbSJiri Kosina struct sony_sc {
32cc6e0bbbSJiri Kosina 	unsigned long quirks;
33cc6e0bbbSJiri Kosina };
34cc6e0bbbSJiri Kosina 
35cc6e0bbbSJiri Kosina /* Sony Vaio VGX has wrongly mouse pointer declared as constant */
36cc6e0bbbSJiri Kosina static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
37cc6e0bbbSJiri Kosina 		unsigned int rsize)
38cc6e0bbbSJiri Kosina {
39cc6e0bbbSJiri Kosina 	struct sony_sc *sc = hid_get_drvdata(hdev);
40cc6e0bbbSJiri Kosina 
41cc6e0bbbSJiri Kosina 	if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
42cc6e0bbbSJiri Kosina 			rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
43cc6e0bbbSJiri Kosina 		dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report "
44cc6e0bbbSJiri Kosina 				"descriptor\n");
45cc6e0bbbSJiri Kosina 		rdesc[55] = 0x06;
46cc6e0bbbSJiri Kosina 	}
47cc6e0bbbSJiri Kosina }
48cc6e0bbbSJiri Kosina 
49*569b10a5SAntonio Ospite static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
50*569b10a5SAntonio Ospite 		size_t count, unsigned char report_type)
51*569b10a5SAntonio Ospite {
52*569b10a5SAntonio Ospite 	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
53*569b10a5SAntonio Ospite 	struct usb_device *dev = interface_to_usbdev(intf);
54*569b10a5SAntonio Ospite 	struct usb_host_interface *interface = intf->cur_altsetting;
55*569b10a5SAntonio Ospite 	int report_id = buf[0];
56*569b10a5SAntonio Ospite 	int ret;
57*569b10a5SAntonio Ospite 
58*569b10a5SAntonio Ospite 	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
59*569b10a5SAntonio Ospite 		HID_REQ_SET_REPORT,
60*569b10a5SAntonio Ospite 		USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
61*569b10a5SAntonio Ospite 		((report_type + 1) << 8) | report_id,
62*569b10a5SAntonio Ospite 		interface->desc.bInterfaceNumber, buf, count,
63*569b10a5SAntonio Ospite 		USB_CTRL_SET_TIMEOUT);
64*569b10a5SAntonio Ospite 
65*569b10a5SAntonio Ospite 	return ret;
66*569b10a5SAntonio Ospite }
67*569b10a5SAntonio Ospite 
68bd28ce00SJiri Slaby /*
69bd28ce00SJiri Slaby  * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
70bd28ce00SJiri Slaby  * to "operational".  Without this, the ps3 controller will not report any
71bd28ce00SJiri Slaby  * events.
72bd28ce00SJiri Slaby  */
73816651a7SAntonio Ospite static int sixaxis_set_operational_usb(struct hid_device *hdev)
74bd28ce00SJiri Slaby {
75bd28ce00SJiri Slaby 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
76bd28ce00SJiri Slaby 	struct usb_device *dev = interface_to_usbdev(intf);
77bd28ce00SJiri Slaby 	__u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
78bd28ce00SJiri Slaby 	int ret;
79bd28ce00SJiri Slaby 	char *buf = kmalloc(18, GFP_KERNEL);
80bd28ce00SJiri Slaby 
81bd28ce00SJiri Slaby 	if (!buf)
82bd28ce00SJiri Slaby 		return -ENOMEM;
83bd28ce00SJiri Slaby 
84bd28ce00SJiri Slaby 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
85bd28ce00SJiri Slaby 				 HID_REQ_GET_REPORT,
86bd28ce00SJiri Slaby 				 USB_DIR_IN | USB_TYPE_CLASS |
87bd28ce00SJiri Slaby 				 USB_RECIP_INTERFACE,
88bd28ce00SJiri Slaby 				 (3 << 8) | 0xf2, ifnum, buf, 17,
89bd28ce00SJiri Slaby 				 USB_CTRL_GET_TIMEOUT);
90bd28ce00SJiri Slaby 	if (ret < 0)
91bd28ce00SJiri Slaby 		dev_err(&hdev->dev, "can't set operational mode\n");
92bd28ce00SJiri Slaby 
93bd28ce00SJiri Slaby 	kfree(buf);
94bd28ce00SJiri Slaby 
95bd28ce00SJiri Slaby 	return ret;
96bd28ce00SJiri Slaby }
97bd28ce00SJiri Slaby 
98816651a7SAntonio Ospite static int sixaxis_set_operational_bt(struct hid_device *hdev)
99f9ce7c28SBastien Nocera {
100fddb33f2SAntonio Ospite 	unsigned char buf[] = { 0xf4,  0x42, 0x03, 0x00, 0x00 };
101f9ce7c28SBastien Nocera 	return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
102f9ce7c28SBastien Nocera }
103f9ce7c28SBastien Nocera 
104bd28ce00SJiri Slaby static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
105bd28ce00SJiri Slaby {
106bd28ce00SJiri Slaby 	int ret;
107cc6e0bbbSJiri Kosina 	unsigned long quirks = id->driver_data;
108cc6e0bbbSJiri Kosina 	struct sony_sc *sc;
109cc6e0bbbSJiri Kosina 
110cc6e0bbbSJiri Kosina 	sc = kzalloc(sizeof(*sc), GFP_KERNEL);
111cc6e0bbbSJiri Kosina 	if (sc == NULL) {
112eabe5c90SBastien Nocera 		dev_err(&hdev->dev, "can't alloc sony descriptor\n");
113cc6e0bbbSJiri Kosina 		return -ENOMEM;
114cc6e0bbbSJiri Kosina 	}
115cc6e0bbbSJiri Kosina 
116cc6e0bbbSJiri Kosina 	sc->quirks = quirks;
117cc6e0bbbSJiri Kosina 	hid_set_drvdata(hdev, sc);
118bd28ce00SJiri Slaby 
119bd28ce00SJiri Slaby 	ret = hid_parse(hdev);
120bd28ce00SJiri Slaby 	if (ret) {
121bd28ce00SJiri Slaby 		dev_err(&hdev->dev, "parse failed\n");
122bd28ce00SJiri Slaby 		goto err_free;
123bd28ce00SJiri Slaby 	}
124bd28ce00SJiri Slaby 
12593c10132SJiri Slaby 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
12693c10132SJiri Slaby 			HID_CONNECT_HIDDEV_FORCE);
127bd28ce00SJiri Slaby 	if (ret) {
128bd28ce00SJiri Slaby 		dev_err(&hdev->dev, "hw start failed\n");
129bd28ce00SJiri Slaby 		goto err_free;
130bd28ce00SJiri Slaby 	}
131bd28ce00SJiri Slaby 
132*569b10a5SAntonio Ospite 	if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
133*569b10a5SAntonio Ospite 		hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
134816651a7SAntonio Ospite 		ret = sixaxis_set_operational_usb(hdev);
135*569b10a5SAntonio Ospite 	}
136816651a7SAntonio Ospite 	else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
137816651a7SAntonio Ospite 		ret = sixaxis_set_operational_bt(hdev);
138816651a7SAntonio Ospite 	else
139f9ce7c28SBastien Nocera 		ret = 0;
140f9ce7c28SBastien Nocera 
1414dfdc464SJiri Kosina 	if (ret < 0)
142bd28ce00SJiri Slaby 		goto err_stop;
143bd28ce00SJiri Slaby 
144bd28ce00SJiri Slaby 	return 0;
145bd28ce00SJiri Slaby err_stop:
146bd28ce00SJiri Slaby 	hid_hw_stop(hdev);
147bd28ce00SJiri Slaby err_free:
148cc6e0bbbSJiri Kosina 	kfree(sc);
149bd28ce00SJiri Slaby 	return ret;
150bd28ce00SJiri Slaby }
151bd28ce00SJiri Slaby 
152cc6e0bbbSJiri Kosina static void sony_remove(struct hid_device *hdev)
153cc6e0bbbSJiri Kosina {
154cc6e0bbbSJiri Kosina 	hid_hw_stop(hdev);
155cc6e0bbbSJiri Kosina 	kfree(hid_get_drvdata(hdev));
156cc6e0bbbSJiri Kosina }
157cc6e0bbbSJiri Kosina 
158bd28ce00SJiri Slaby static const struct hid_device_id sony_devices[] = {
159816651a7SAntonio Ospite 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
160816651a7SAntonio Ospite 		.driver_data = SIXAXIS_CONTROLLER_USB },
161816651a7SAntonio Ospite 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
162816651a7SAntonio Ospite 		.driver_data = SIXAXIS_CONTROLLER_BT },
163cc6e0bbbSJiri Kosina 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
164cc6e0bbbSJiri Kosina 		.driver_data = VAIO_RDESC_CONSTANT },
165bd28ce00SJiri Slaby 	{ }
166bd28ce00SJiri Slaby };
167bd28ce00SJiri Slaby MODULE_DEVICE_TABLE(hid, sony_devices);
168bd28ce00SJiri Slaby 
169bd28ce00SJiri Slaby static struct hid_driver sony_driver = {
170bd28ce00SJiri Slaby 	.name = "sony",
171bd28ce00SJiri Slaby 	.id_table = sony_devices,
172bd28ce00SJiri Slaby 	.probe = sony_probe,
173cc6e0bbbSJiri Kosina 	.remove = sony_remove,
174cc6e0bbbSJiri Kosina 	.report_fixup = sony_report_fixup,
175bd28ce00SJiri Slaby };
176bd28ce00SJiri Slaby 
177a24f423bSPeter Huewe static int __init sony_init(void)
178bd28ce00SJiri Slaby {
179bd28ce00SJiri Slaby 	return hid_register_driver(&sony_driver);
180bd28ce00SJiri Slaby }
181bd28ce00SJiri Slaby 
182a24f423bSPeter Huewe static void __exit sony_exit(void)
183bd28ce00SJiri Slaby {
184bd28ce00SJiri Slaby 	hid_unregister_driver(&sony_driver);
185bd28ce00SJiri Slaby }
186bd28ce00SJiri Slaby 
187bd28ce00SJiri Slaby module_init(sony_init);
188bd28ce00SJiri Slaby module_exit(sony_exit);
189bd28ce00SJiri Slaby MODULE_LICENSE("GPL");
190