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