xref: /linux/drivers/hid/hid-sony.c (revision fddb33f2e8872fa4857dd29f0b71a523c9ed5577)
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 
27cc6e0bbbSJiri Kosina #define VAIO_RDESC_CONSTANT 0x0001
28cc6e0bbbSJiri Kosina 
29cc6e0bbbSJiri Kosina struct sony_sc {
30cc6e0bbbSJiri Kosina 	unsigned long quirks;
31cc6e0bbbSJiri Kosina };
32cc6e0bbbSJiri Kosina 
33cc6e0bbbSJiri Kosina /* Sony Vaio VGX has wrongly mouse pointer declared as constant */
34cc6e0bbbSJiri Kosina static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
35cc6e0bbbSJiri Kosina 		unsigned int rsize)
36cc6e0bbbSJiri Kosina {
37cc6e0bbbSJiri Kosina 	struct sony_sc *sc = hid_get_drvdata(hdev);
38cc6e0bbbSJiri Kosina 
39cc6e0bbbSJiri Kosina 	if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
40cc6e0bbbSJiri Kosina 			rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
41cc6e0bbbSJiri Kosina 		dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report "
42cc6e0bbbSJiri Kosina 				"descriptor\n");
43cc6e0bbbSJiri Kosina 		rdesc[55] = 0x06;
44cc6e0bbbSJiri Kosina 	}
45cc6e0bbbSJiri Kosina }
46cc6e0bbbSJiri Kosina 
47bd28ce00SJiri Slaby /*
48bd28ce00SJiri Slaby  * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
49bd28ce00SJiri Slaby  * to "operational".  Without this, the ps3 controller will not report any
50bd28ce00SJiri Slaby  * events.
51bd28ce00SJiri Slaby  */
52f9ce7c28SBastien Nocera static int sony_set_operational_usb(struct hid_device *hdev)
53bd28ce00SJiri Slaby {
54bd28ce00SJiri Slaby 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
55bd28ce00SJiri Slaby 	struct usb_device *dev = interface_to_usbdev(intf);
56bd28ce00SJiri Slaby 	__u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
57bd28ce00SJiri Slaby 	int ret;
58bd28ce00SJiri Slaby 	char *buf = kmalloc(18, GFP_KERNEL);
59bd28ce00SJiri Slaby 
60bd28ce00SJiri Slaby 	if (!buf)
61bd28ce00SJiri Slaby 		return -ENOMEM;
62bd28ce00SJiri Slaby 
63bd28ce00SJiri Slaby 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
64bd28ce00SJiri Slaby 				 HID_REQ_GET_REPORT,
65bd28ce00SJiri Slaby 				 USB_DIR_IN | USB_TYPE_CLASS |
66bd28ce00SJiri Slaby 				 USB_RECIP_INTERFACE,
67bd28ce00SJiri Slaby 				 (3 << 8) | 0xf2, ifnum, buf, 17,
68bd28ce00SJiri Slaby 				 USB_CTRL_GET_TIMEOUT);
69bd28ce00SJiri Slaby 	if (ret < 0)
70bd28ce00SJiri Slaby 		dev_err(&hdev->dev, "can't set operational mode\n");
71bd28ce00SJiri Slaby 
72bd28ce00SJiri Slaby 	kfree(buf);
73bd28ce00SJiri Slaby 
74bd28ce00SJiri Slaby 	return ret;
75bd28ce00SJiri Slaby }
76bd28ce00SJiri Slaby 
77f9ce7c28SBastien Nocera static int sony_set_operational_bt(struct hid_device *hdev)
78f9ce7c28SBastien Nocera {
79*fddb33f2SAntonio Ospite 	unsigned char buf[] = { 0xf4,  0x42, 0x03, 0x00, 0x00 };
80f9ce7c28SBastien Nocera 	return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
81f9ce7c28SBastien Nocera }
82f9ce7c28SBastien Nocera 
83bd28ce00SJiri Slaby static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
84bd28ce00SJiri Slaby {
85bd28ce00SJiri Slaby 	int ret;
86cc6e0bbbSJiri Kosina 	unsigned long quirks = id->driver_data;
87cc6e0bbbSJiri Kosina 	struct sony_sc *sc;
88cc6e0bbbSJiri Kosina 
89cc6e0bbbSJiri Kosina 	sc = kzalloc(sizeof(*sc), GFP_KERNEL);
90cc6e0bbbSJiri Kosina 	if (sc == NULL) {
91eabe5c90SBastien Nocera 		dev_err(&hdev->dev, "can't alloc sony descriptor\n");
92cc6e0bbbSJiri Kosina 		return -ENOMEM;
93cc6e0bbbSJiri Kosina 	}
94cc6e0bbbSJiri Kosina 
95cc6e0bbbSJiri Kosina 	sc->quirks = quirks;
96cc6e0bbbSJiri Kosina 	hid_set_drvdata(hdev, sc);
97bd28ce00SJiri Slaby 
98bd28ce00SJiri Slaby 	ret = hid_parse(hdev);
99bd28ce00SJiri Slaby 	if (ret) {
100bd28ce00SJiri Slaby 		dev_err(&hdev->dev, "parse failed\n");
101bd28ce00SJiri Slaby 		goto err_free;
102bd28ce00SJiri Slaby 	}
103bd28ce00SJiri Slaby 
10493c10132SJiri Slaby 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
10593c10132SJiri Slaby 			HID_CONNECT_HIDDEV_FORCE);
106bd28ce00SJiri Slaby 	if (ret) {
107bd28ce00SJiri Slaby 		dev_err(&hdev->dev, "hw start failed\n");
108bd28ce00SJiri Slaby 		goto err_free;
109bd28ce00SJiri Slaby 	}
110bd28ce00SJiri Slaby 
111f9ce7c28SBastien Nocera 	switch (hdev->bus) {
112f9ce7c28SBastien Nocera 	case BUS_USB:
113f9ce7c28SBastien Nocera 		ret = sony_set_operational_usb(hdev);
114f9ce7c28SBastien Nocera 		break;
115f9ce7c28SBastien Nocera 	case BUS_BLUETOOTH:
116f9ce7c28SBastien Nocera 		ret = sony_set_operational_bt(hdev);
117f9ce7c28SBastien Nocera 		break;
118f9ce7c28SBastien Nocera 	default:
119f9ce7c28SBastien Nocera 		ret = 0;
120f9ce7c28SBastien Nocera 	}
121f9ce7c28SBastien Nocera 
1224dfdc464SJiri Kosina 	if (ret < 0)
123bd28ce00SJiri Slaby 		goto err_stop;
124bd28ce00SJiri Slaby 
125bd28ce00SJiri Slaby 	return 0;
126bd28ce00SJiri Slaby err_stop:
127bd28ce00SJiri Slaby 	hid_hw_stop(hdev);
128bd28ce00SJiri Slaby err_free:
129cc6e0bbbSJiri Kosina 	kfree(sc);
130bd28ce00SJiri Slaby 	return ret;
131bd28ce00SJiri Slaby }
132bd28ce00SJiri Slaby 
133cc6e0bbbSJiri Kosina static void sony_remove(struct hid_device *hdev)
134cc6e0bbbSJiri Kosina {
135cc6e0bbbSJiri Kosina 	hid_hw_stop(hdev);
136cc6e0bbbSJiri Kosina 	kfree(hid_get_drvdata(hdev));
137cc6e0bbbSJiri Kosina }
138cc6e0bbbSJiri Kosina 
139bd28ce00SJiri Slaby static const struct hid_device_id sony_devices[] = {
140bd28ce00SJiri Slaby 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
141f9ce7c28SBastien Nocera 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
142cc6e0bbbSJiri Kosina 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
143cc6e0bbbSJiri Kosina 		.driver_data = VAIO_RDESC_CONSTANT },
144bd28ce00SJiri Slaby 	{ }
145bd28ce00SJiri Slaby };
146bd28ce00SJiri Slaby MODULE_DEVICE_TABLE(hid, sony_devices);
147bd28ce00SJiri Slaby 
148bd28ce00SJiri Slaby static struct hid_driver sony_driver = {
149bd28ce00SJiri Slaby 	.name = "sony",
150bd28ce00SJiri Slaby 	.id_table = sony_devices,
151bd28ce00SJiri Slaby 	.probe = sony_probe,
152cc6e0bbbSJiri Kosina 	.remove = sony_remove,
153cc6e0bbbSJiri Kosina 	.report_fixup = sony_report_fixup,
154bd28ce00SJiri Slaby };
155bd28ce00SJiri Slaby 
156a24f423bSPeter Huewe static int __init sony_init(void)
157bd28ce00SJiri Slaby {
158bd28ce00SJiri Slaby 	return hid_register_driver(&sony_driver);
159bd28ce00SJiri Slaby }
160bd28ce00SJiri Slaby 
161a24f423bSPeter Huewe static void __exit sony_exit(void)
162bd28ce00SJiri Slaby {
163bd28ce00SJiri Slaby 	hid_unregister_driver(&sony_driver);
164bd28ce00SJiri Slaby }
165bd28ce00SJiri Slaby 
166bd28ce00SJiri Slaby module_init(sony_init);
167bd28ce00SJiri Slaby module_exit(sony_exit);
168bd28ce00SJiri Slaby MODULE_LICENSE("GPL");
169