• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/hid/
1/*
2 *  HID driver for some sony "special" devices
3 *
4 *  Copyright (c) 1999 Andreas Gal
5 *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
6 *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
7 *  Copyright (c) 2007 Paul Walmsley
8 *  Copyright (c) 2008 Jiri Slaby
9 *  Copyright (c) 2006-2008 Jiri Kosina
10 */
11
12/*
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the Free
15 * Software Foundation; either version 2 of the License, or (at your option)
16 * any later version.
17 */
18
19#include <linux/device.h>
20#include <linux/hid.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/usb.h>
24
25#include "hid-ids.h"
26
27#define VAIO_RDESC_CONSTANT 0x0001
28
29struct sony_sc {
30	unsigned long quirks;
31};
32
33/* Sony Vaio VGX has wrongly mouse pointer declared as constant */
34static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
35		unsigned int rsize)
36{
37	struct sony_sc *sc = hid_get_drvdata(hdev);
38
39	if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
40			rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
41		dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report "
42				"descriptor\n");
43		rdesc[55] = 0x06;
44	}
45}
46
47/*
48 * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
49 * to "operational".  Without this, the ps3 controller will not report any
50 * events.
51 */
52static int sony_set_operational_usb(struct hid_device *hdev)
53{
54	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
55	struct usb_device *dev = interface_to_usbdev(intf);
56	__u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
57	int ret;
58	char *buf = kmalloc(18, GFP_KERNEL);
59
60	if (!buf)
61		return -ENOMEM;
62
63	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
64				 HID_REQ_GET_REPORT,
65				 USB_DIR_IN | USB_TYPE_CLASS |
66				 USB_RECIP_INTERFACE,
67				 (3 << 8) | 0xf2, ifnum, buf, 17,
68				 USB_CTRL_GET_TIMEOUT);
69	if (ret < 0)
70		dev_err(&hdev->dev, "can't set operational mode\n");
71
72	kfree(buf);
73
74	return ret;
75}
76
77static int sony_set_operational_bt(struct hid_device *hdev)
78{
79	unsigned char buf[] = { 0xf4,  0x42, 0x03, 0x00, 0x00 };
80	return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
81}
82
83static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
84{
85	int ret;
86	unsigned long quirks = id->driver_data;
87	struct sony_sc *sc;
88
89	sc = kzalloc(sizeof(*sc), GFP_KERNEL);
90	if (sc == NULL) {
91		dev_err(&hdev->dev, "can't alloc sony descriptor\n");
92		return -ENOMEM;
93	}
94
95	sc->quirks = quirks;
96	hid_set_drvdata(hdev, sc);
97
98	ret = hid_parse(hdev);
99	if (ret) {
100		dev_err(&hdev->dev, "parse failed\n");
101		goto err_free;
102	}
103
104	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
105			HID_CONNECT_HIDDEV_FORCE);
106	if (ret) {
107		dev_err(&hdev->dev, "hw start failed\n");
108		goto err_free;
109	}
110
111	switch (hdev->bus) {
112	case BUS_USB:
113		ret = sony_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	}
121
122	if (ret < 0)
123		goto err_stop;
124
125	return 0;
126err_stop:
127	hid_hw_stop(hdev);
128err_free:
129	kfree(sc);
130	return ret;
131}
132
133static void sony_remove(struct hid_device *hdev)
134{
135	hid_hw_stop(hdev);
136	kfree(hid_get_drvdata(hdev));
137}
138
139static const struct hid_device_id sony_devices[] = {
140	{ 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) },
142	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
143		.driver_data = VAIO_RDESC_CONSTANT },
144	{ }
145};
146MODULE_DEVICE_TABLE(hid, sony_devices);
147
148static struct hid_driver sony_driver = {
149	.name = "sony",
150	.id_table = sony_devices,
151	.probe = sony_probe,
152	.remove = sony_remove,
153	.report_fixup = sony_report_fixup,
154};
155
156static int __init sony_init(void)
157{
158	return hid_register_driver(&sony_driver);
159}
160
161static void __exit sony_exit(void)
162{
163	hid_unregister_driver(&sony_driver);
164}
165
166module_init(sony_init);
167module_exit(sony_exit);
168MODULE_LICENSE("GPL");
169