diff options
author | Jiri Kosina <jkosina@suse.cz> | 2007-10-14 08:47:56 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2007-10-14 08:47:56 -0400 |
commit | d057fd4cb892087955568a139d15eae4115a0174 (patch) | |
tree | 4fd631492ff8d2d78c394fd2b054175588a7d633 /drivers/hid | |
parent | bb6c8d8fa9b5587eea18078ce0bcf6bb2905789f (diff) | |
parent | 709d27c04f4eccbc99d57a5569bce028915a4345 (diff) |
Merge branch 'hidraw' into for-linus
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/Kconfig | 19 | ||||
-rw-r--r-- | drivers/hid/Makefile | 2 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 16 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 401 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 38 |
5 files changed, 474 insertions, 2 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 19667fcc722a..cacf89e65af4 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
@@ -46,6 +46,25 @@ config HID_DEBUG | |||
46 | 46 | ||
47 | If unsure, say N | 47 | If unsure, say N |
48 | 48 | ||
49 | config HIDRAW | ||
50 | bool "/dev/hidraw raw HID device support" | ||
51 | depends on HID | ||
52 | ---help--- | ||
53 | Say Y here if you want to support HID devices (from the USB | ||
54 | specification standpoint) that aren't strictly user interface | ||
55 | devices, like monitor controls and Uninterruptable Power Supplies. | ||
56 | |||
57 | This module supports these devices separately using a separate | ||
58 | event interface on /dev/hidraw. | ||
59 | |||
60 | There is also a /dev/hiddev configuration option in the USB HID | ||
61 | configuration menu. In comparison to hiddev, this device does not process | ||
62 | the hid events at all (no parsing, no lookups). This lets applications | ||
63 | to work on raw hid events when they want to, and avoid using transport-specific | ||
64 | userspace libhid/libusb libraries. | ||
65 | |||
66 | If unsure, say Y. | ||
67 | |||
49 | source "drivers/hid/usbhid/Kconfig" | 68 | source "drivers/hid/usbhid/Kconfig" |
50 | 69 | ||
51 | endif # HID_SUPPORT | 70 | endif # HID_SUPPORT |
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 68d1376a53fb..1ac5103f7c93 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile | |||
@@ -4,7 +4,9 @@ | |||
4 | hid-objs := hid-core.o hid-input.o | 4 | hid-objs := hid-core.o hid-input.o |
5 | 5 | ||
6 | obj-$(CONFIG_HID) += hid.o | 6 | obj-$(CONFIG_HID) += hid.o |
7 | |||
7 | hid-$(CONFIG_HID_DEBUG) += hid-debug.o | 8 | hid-$(CONFIG_HID_DEBUG) += hid-debug.o |
9 | hid-$(CONFIG_HIDRAW) += hidraw.o | ||
8 | 10 | ||
9 | obj-$(CONFIG_USB_HID) += usbhid/ | 11 | obj-$(CONFIG_USB_HID) += usbhid/ |
10 | obj-$(CONFIG_USB_MOUSE) += usbhid/ | 12 | obj-$(CONFIG_USB_MOUSE) += usbhid/ |
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 317cf8a7b63c..2884b036495a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/hid.h> | 30 | #include <linux/hid.h> |
31 | #include <linux/hiddev.h> | 31 | #include <linux/hiddev.h> |
32 | #include <linux/hid-debug.h> | 32 | #include <linux/hid-debug.h> |
33 | #include <linux/hidraw.h> | ||
33 | 34 | ||
34 | /* | 35 | /* |
35 | * Version Information | 36 | * Version Information |
@@ -979,6 +980,8 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
979 | 980 | ||
980 | if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) | 981 | if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) |
981 | hid->hiddev_report_event(hid, report); | 982 | hid->hiddev_report_event(hid, report); |
983 | if (hid->claimed & HID_CLAIMED_HIDRAW) | ||
984 | hidraw_report_event(hid, data, size); | ||
982 | 985 | ||
983 | for (n = 0; n < report->maxfield; n++) | 986 | for (n = 0; n < report->maxfield; n++) |
984 | hid_input_field(hid, report->field[n], data, interrupt); | 987 | hid_input_field(hid, report->field[n], data, interrupt); |
@@ -990,5 +993,18 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
990 | } | 993 | } |
991 | EXPORT_SYMBOL_GPL(hid_input_report); | 994 | EXPORT_SYMBOL_GPL(hid_input_report); |
992 | 995 | ||
996 | static int __init hid_init(void) | ||
997 | { | ||
998 | return hidraw_init(); | ||
999 | } | ||
1000 | |||
1001 | static void __exit hid_exit(void) | ||
1002 | { | ||
1003 | hidraw_exit(); | ||
1004 | } | ||
1005 | |||
1006 | module_init(hid_init); | ||
1007 | module_exit(hid_exit); | ||
1008 | |||
993 | MODULE_LICENSE(DRIVER_LICENSE); | 1009 | MODULE_LICENSE(DRIVER_LICENSE); |
994 | 1010 | ||
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c new file mode 100644 index 000000000000..8503197a8131 --- /dev/null +++ b/drivers/hid/hidraw.c | |||
@@ -0,0 +1,401 @@ | |||
1 | /* | ||
2 | * HID raw devices, giving access to raw HID events. | ||
3 | * | ||
4 | * In comparison to hiddev, this device does not process the | ||
5 | * hid events at all (no parsing, no lookups). This lets applications | ||
6 | * to work on raw hid events as they want to, and avoids a need to | ||
7 | * use a transport-specific userspace libhid/libusb libraries. | ||
8 | * | ||
9 | * Copyright (c) 2007 Jiri Kosina | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms and conditions of the GNU General Public License, | ||
15 | * version 2, as published by the Free Software Foundation. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/fs.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/cdev.h> | ||
28 | #include <linux/poll.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/major.h> | ||
31 | #include <linux/hid.h> | ||
32 | #include <linux/mutex.h> | ||
33 | |||
34 | #include <linux/hidraw.h> | ||
35 | |||
36 | static int hidraw_major; | ||
37 | static struct cdev hidraw_cdev; | ||
38 | static struct class *hidraw_class; | ||
39 | static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; | ||
40 | static DEFINE_SPINLOCK(minors_lock); | ||
41 | |||
42 | static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | ||
43 | { | ||
44 | struct hidraw_list *list = file->private_data; | ||
45 | int ret = 0, len; | ||
46 | char *report; | ||
47 | DECLARE_WAITQUEUE(wait, current); | ||
48 | |||
49 | while (ret == 0) { | ||
50 | |||
51 | mutex_lock(&list->read_mutex); | ||
52 | |||
53 | if (list->head == list->tail) { | ||
54 | add_wait_queue(&list->hidraw->wait, &wait); | ||
55 | set_current_state(TASK_INTERRUPTIBLE); | ||
56 | |||
57 | while (list->head == list->tail) { | ||
58 | if (file->f_flags & O_NONBLOCK) { | ||
59 | ret = -EAGAIN; | ||
60 | break; | ||
61 | } | ||
62 | if (signal_pending(current)) { | ||
63 | ret = -ERESTARTSYS; | ||
64 | break; | ||
65 | } | ||
66 | if (!list->hidraw->exist) { | ||
67 | ret = -EIO; | ||
68 | break; | ||
69 | } | ||
70 | |||
71 | /* allow O_NONBLOCK to work well from other threads */ | ||
72 | mutex_unlock(&list->read_mutex); | ||
73 | schedule(); | ||
74 | mutex_lock(&list->read_mutex); | ||
75 | set_current_state(TASK_INTERRUPTIBLE); | ||
76 | } | ||
77 | |||
78 | set_current_state(TASK_RUNNING); | ||
79 | remove_wait_queue(&list->hidraw->wait, &wait); | ||
80 | } | ||
81 | |||
82 | if (ret) | ||
83 | goto out; | ||
84 | |||
85 | report = list->buffer[list->tail].value; | ||
86 | len = list->buffer[list->tail].len > count ? | ||
87 | count : list->buffer[list->tail].len; | ||
88 | |||
89 | if (copy_to_user(buffer, list->buffer[list->tail].value, len)) { | ||
90 | ret = -EFAULT; | ||
91 | goto out; | ||
92 | } | ||
93 | ret += len; | ||
94 | |||
95 | kfree(list->buffer[list->tail].value); | ||
96 | list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1); | ||
97 | } | ||
98 | out: | ||
99 | mutex_unlock(&list->read_mutex); | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | /* the first byte is expected to be a report number */ | ||
104 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | ||
105 | { | ||
106 | unsigned int minor = iminor(file->f_path.dentry->d_inode); | ||
107 | struct hid_device *dev = hidraw_table[minor]->hid; | ||
108 | __u8 *buf; | ||
109 | int ret = 0; | ||
110 | |||
111 | if (!dev->hid_output_raw_report) | ||
112 | return -ENODEV; | ||
113 | |||
114 | if (count > HID_MIN_BUFFER_SIZE) { | ||
115 | printk(KERN_WARNING "hidraw: pid %d passed too large report\n", | ||
116 | current->pid); | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | |||
120 | if (count < 2) { | ||
121 | printk(KERN_WARNING "hidraw: pid %d passed too short report\n", | ||
122 | current->pid); | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | |||
126 | buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); | ||
127 | if (!buf) | ||
128 | return -ENOMEM; | ||
129 | |||
130 | if (copy_from_user(buf, buffer, count)) { | ||
131 | ret = -EFAULT; | ||
132 | goto out; | ||
133 | } | ||
134 | |||
135 | ret = dev->hid_output_raw_report(dev, buf, count); | ||
136 | out: | ||
137 | kfree(buf); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static unsigned int hidraw_poll(struct file *file, poll_table *wait) | ||
142 | { | ||
143 | struct hidraw_list *list = file->private_data; | ||
144 | |||
145 | poll_wait(file, &list->hidraw->wait, wait); | ||
146 | if (list->head != list->tail) | ||
147 | return POLLIN | POLLRDNORM; | ||
148 | if (!list->hidraw->exist) | ||
149 | return POLLERR | POLLHUP; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int hidraw_open(struct inode *inode, struct file *file) | ||
154 | { | ||
155 | unsigned int minor = iminor(inode); | ||
156 | struct hidraw *dev; | ||
157 | struct hidraw_list *list; | ||
158 | int err = 0; | ||
159 | |||
160 | if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) { | ||
161 | err = -ENOMEM; | ||
162 | goto out; | ||
163 | } | ||
164 | |||
165 | spin_lock(&minors_lock); | ||
166 | if (!hidraw_table[minor]) { | ||
167 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | ||
168 | minor); | ||
169 | kfree(list); | ||
170 | err = -ENODEV; | ||
171 | goto out_unlock; | ||
172 | } | ||
173 | |||
174 | list->hidraw = hidraw_table[minor]; | ||
175 | mutex_init(&list->read_mutex); | ||
176 | list_add_tail(&list->node, &hidraw_table[minor]->list); | ||
177 | file->private_data = list; | ||
178 | |||
179 | dev = hidraw_table[minor]; | ||
180 | if (!dev->open++) | ||
181 | dev->hid->hid_open(dev->hid); | ||
182 | |||
183 | out_unlock: | ||
184 | spin_unlock(&minors_lock); | ||
185 | out: | ||
186 | return err; | ||
187 | |||
188 | } | ||
189 | |||
190 | static int hidraw_release(struct inode * inode, struct file * file) | ||
191 | { | ||
192 | unsigned int minor = iminor(inode); | ||
193 | struct hidraw *dev; | ||
194 | struct hidraw_list *list = file->private_data; | ||
195 | |||
196 | if (!hidraw_table[minor]) { | ||
197 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | ||
198 | minor); | ||
199 | return -ENODEV; | ||
200 | } | ||
201 | |||
202 | list_del(&list->node); | ||
203 | dev = hidraw_table[minor]; | ||
204 | if (!dev->open--) { | ||
205 | if (list->hidraw->exist) | ||
206 | dev->hid->hid_close(dev->hid); | ||
207 | else | ||
208 | kfree(list->hidraw); | ||
209 | } | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
215 | { | ||
216 | unsigned int minor = iminor(inode); | ||
217 | struct hidraw *dev = hidraw_table[minor]; | ||
218 | void __user *user_arg = (void __user*) arg; | ||
219 | |||
220 | switch (cmd) { | ||
221 | case HIDIOCGRDESCSIZE: | ||
222 | if (put_user(dev->hid->rsize, (int __user *)arg)) | ||
223 | return -EFAULT; | ||
224 | return 0; | ||
225 | |||
226 | case HIDIOCGRDESC: | ||
227 | { | ||
228 | __u32 len; | ||
229 | |||
230 | if (get_user(len, (int __user *)arg)) | ||
231 | return -EFAULT; | ||
232 | if (copy_to_user(*((__u8 **)(user_arg + | ||
233 | sizeof(__u32))), | ||
234 | dev->hid->rdesc, len)) | ||
235 | return -EFAULT; | ||
236 | return 0; | ||
237 | } | ||
238 | case HIDIOCGRAWINFO: | ||
239 | { | ||
240 | struct hidraw_devinfo dinfo; | ||
241 | |||
242 | dinfo.bustype = dev->hid->bus; | ||
243 | dinfo.vendor = dev->hid->vendor; | ||
244 | dinfo.product = dev->hid->product; | ||
245 | if (copy_to_user(user_arg, &dinfo, sizeof(dinfo))) | ||
246 | return -EFAULT; | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | default: | ||
251 | printk(KERN_EMERG "hidraw: unsupported ioctl() %x\n", | ||
252 | cmd); | ||
253 | } | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | |||
257 | static const struct file_operations hidraw_ops = { | ||
258 | .owner = THIS_MODULE, | ||
259 | .read = hidraw_read, | ||
260 | .write = hidraw_write, | ||
261 | .poll = hidraw_poll, | ||
262 | .open = hidraw_open, | ||
263 | .release = hidraw_release, | ||
264 | .ioctl = hidraw_ioctl, | ||
265 | }; | ||
266 | |||
267 | void hidraw_report_event(struct hid_device *hid, u8 *data, int len) | ||
268 | { | ||
269 | struct hidraw *dev = hid->hidraw; | ||
270 | struct hidraw_list *list; | ||
271 | |||
272 | list_for_each_entry(list, &dev->list, node) { | ||
273 | list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC); | ||
274 | list->buffer[list->head].len = len; | ||
275 | list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1); | ||
276 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | ||
277 | } | ||
278 | |||
279 | wake_up_interruptible(&dev->wait); | ||
280 | } | ||
281 | EXPORT_SYMBOL_GPL(hidraw_report_event); | ||
282 | |||
283 | int hidraw_connect(struct hid_device *hid) | ||
284 | { | ||
285 | int minor, result; | ||
286 | struct hidraw *dev; | ||
287 | |||
288 | /* TODO currently we accept any HID device. This should later | ||
289 | * probably be fixed to accept only those devices which provide | ||
290 | * non-input applications | ||
291 | */ | ||
292 | |||
293 | dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL); | ||
294 | if (!dev) | ||
295 | return -ENOMEM; | ||
296 | |||
297 | result = -EINVAL; | ||
298 | |||
299 | spin_lock(&minors_lock); | ||
300 | |||
301 | for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) { | ||
302 | if (hidraw_table[minor]) | ||
303 | continue; | ||
304 | hidraw_table[minor] = dev; | ||
305 | result = 0; | ||
306 | break; | ||
307 | } | ||
308 | |||
309 | spin_unlock(&minors_lock); | ||
310 | |||
311 | if (result) { | ||
312 | kfree(dev); | ||
313 | goto out; | ||
314 | } | ||
315 | |||
316 | dev->dev = device_create(hidraw_class, NULL, MKDEV(hidraw_major, minor), | ||
317 | "%s%d", "hidraw", minor); | ||
318 | |||
319 | if (IS_ERR(dev->dev)) { | ||
320 | spin_lock(&minors_lock); | ||
321 | hidraw_table[minor] = NULL; | ||
322 | spin_unlock(&minors_lock); | ||
323 | result = PTR_ERR(dev->dev); | ||
324 | kfree(dev); | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | init_waitqueue_head(&dev->wait); | ||
329 | INIT_LIST_HEAD(&dev->list); | ||
330 | |||
331 | dev->hid = hid; | ||
332 | dev->minor = minor; | ||
333 | |||
334 | dev->exist = 1; | ||
335 | hid->hidraw = dev; | ||
336 | |||
337 | out: | ||
338 | return result; | ||
339 | |||
340 | } | ||
341 | EXPORT_SYMBOL_GPL(hidraw_connect); | ||
342 | |||
343 | void hidraw_disconnect(struct hid_device *hid) | ||
344 | { | ||
345 | struct hidraw *hidraw = hid->hidraw; | ||
346 | |||
347 | hidraw->exist = 0; | ||
348 | |||
349 | spin_lock(&minors_lock); | ||
350 | hidraw_table[hidraw->minor] = NULL; | ||
351 | spin_unlock(&minors_lock); | ||
352 | |||
353 | device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); | ||
354 | |||
355 | if (hidraw->open) { | ||
356 | hid->hid_close(hid); | ||
357 | wake_up_interruptible(&hidraw->wait); | ||
358 | } else { | ||
359 | kfree(hidraw); | ||
360 | } | ||
361 | } | ||
362 | EXPORT_SYMBOL_GPL(hidraw_disconnect); | ||
363 | |||
364 | int __init hidraw_init(void) | ||
365 | { | ||
366 | int result; | ||
367 | dev_t dev_id; | ||
368 | |||
369 | result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR, | ||
370 | HIDRAW_MAX_DEVICES, "hidraw"); | ||
371 | |||
372 | hidraw_major = MAJOR(dev_id); | ||
373 | |||
374 | if (result < 0) { | ||
375 | printk(KERN_WARNING "hidraw: can't get major number\n"); | ||
376 | result = 0; | ||
377 | goto out; | ||
378 | } | ||
379 | |||
380 | hidraw_class = class_create(THIS_MODULE, "hidraw"); | ||
381 | if (IS_ERR(hidraw_class)) { | ||
382 | result = PTR_ERR(hidraw_class); | ||
383 | unregister_chrdev(hidraw_major, "hidraw"); | ||
384 | goto out; | ||
385 | } | ||
386 | |||
387 | cdev_init(&hidraw_cdev, &hidraw_ops); | ||
388 | cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES); | ||
389 | out: | ||
390 | return result; | ||
391 | } | ||
392 | |||
393 | void __exit hidraw_exit(void) | ||
394 | { | ||
395 | dev_t dev_id = MKDEV(hidraw_major, 0); | ||
396 | |||
397 | cdev_del(&hidraw_cdev); | ||
398 | class_destroy(hidraw_class); | ||
399 | unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); | ||
400 | |||
401 | } | ||
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index a34e0f098f63..b38e559b7a46 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/hid.h> | 32 | #include <linux/hid.h> |
33 | #include <linux/hiddev.h> | 33 | #include <linux/hiddev.h> |
34 | #include <linux/hid-debug.h> | 34 | #include <linux/hid-debug.h> |
35 | #include <linux/hidraw.h> | ||
35 | #include "usbhid.h" | 36 | #include "usbhid.h" |
36 | 37 | ||
37 | /* | 38 | /* |
@@ -639,6 +640,28 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) | |||
639 | return 0; | 640 | return 0; |
640 | } | 641 | } |
641 | 642 | ||
643 | static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count) | ||
644 | { | ||
645 | struct usbhid_device *usbhid = hid->driver_data; | ||
646 | struct usb_device *dev = hid_to_usb_dev(hid); | ||
647 | struct usb_interface *intf = usbhid->intf; | ||
648 | struct usb_host_interface *interface = intf->cur_altsetting; | ||
649 | int ret; | ||
650 | |||
651 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
652 | HID_REQ_SET_REPORT, | ||
653 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
654 | cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf), | ||
655 | interface->desc.bInterfaceNumber, buf + 1, count - 1, | ||
656 | USB_CTRL_SET_TIMEOUT); | ||
657 | |||
658 | /* count also the report id */ | ||
659 | if (ret > 0) | ||
660 | ret++; | ||
661 | |||
662 | return ret; | ||
663 | } | ||
664 | |||
642 | static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) | 665 | static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) |
643 | { | 666 | { |
644 | struct usbhid_device *usbhid = hid->driver_data; | 667 | struct usbhid_device *usbhid = hid->driver_data; |
@@ -882,6 +905,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) | |||
882 | hid->hiddev_hid_event = hiddev_hid_event; | 905 | hid->hiddev_hid_event = hiddev_hid_event; |
883 | hid->hiddev_report_event = hiddev_report_event; | 906 | hid->hiddev_report_event = hiddev_report_event; |
884 | #endif | 907 | #endif |
908 | hid->hid_output_raw_report = usbhid_output_raw_report; | ||
885 | return hid; | 909 | return hid; |
886 | 910 | ||
887 | fail: | 911 | fail: |
@@ -920,6 +944,8 @@ static void hid_disconnect(struct usb_interface *intf) | |||
920 | hidinput_disconnect(hid); | 944 | hidinput_disconnect(hid); |
921 | if (hid->claimed & HID_CLAIMED_HIDDEV) | 945 | if (hid->claimed & HID_CLAIMED_HIDDEV) |
922 | hiddev_disconnect(hid); | 946 | hiddev_disconnect(hid); |
947 | if (hid->claimed & HID_CLAIMED_HIDRAW) | ||
948 | hidraw_disconnect(hid); | ||
923 | 949 | ||
924 | usb_free_urb(usbhid->urbin); | 950 | usb_free_urb(usbhid->urbin); |
925 | usb_free_urb(usbhid->urbctrl); | 951 | usb_free_urb(usbhid->urbctrl); |
@@ -952,11 +978,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
952 | hid->claimed |= HID_CLAIMED_INPUT; | 978 | hid->claimed |= HID_CLAIMED_INPUT; |
953 | if (!hiddev_connect(hid)) | 979 | if (!hiddev_connect(hid)) |
954 | hid->claimed |= HID_CLAIMED_HIDDEV; | 980 | hid->claimed |= HID_CLAIMED_HIDDEV; |
981 | if (!hidraw_connect(hid)) | ||
982 | hid->claimed |= HID_CLAIMED_HIDRAW; | ||
955 | 983 | ||
956 | usb_set_intfdata(intf, hid); | 984 | usb_set_intfdata(intf, hid); |
957 | 985 | ||
958 | if (!hid->claimed) { | 986 | if (!hid->claimed) { |
959 | printk ("HID device not claimed by input or hiddev\n"); | 987 | printk ("HID device claimed by neither input, hiddev nor hidraw\n"); |
960 | hid_disconnect(intf); | 988 | hid_disconnect(intf); |
961 | return -ENODEV; | 989 | return -ENODEV; |
962 | } | 990 | } |
@@ -972,10 +1000,16 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) | |||
972 | 1000 | ||
973 | if (hid->claimed & HID_CLAIMED_INPUT) | 1001 | if (hid->claimed & HID_CLAIMED_INPUT) |
974 | printk("input"); | 1002 | printk("input"); |
975 | if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV)) | 1003 | if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) || |
1004 | hid->claimed & HID_CLAIMED_HIDRAW)) | ||
976 | printk(","); | 1005 | printk(","); |
977 | if (hid->claimed & HID_CLAIMED_HIDDEV) | 1006 | if (hid->claimed & HID_CLAIMED_HIDDEV) |
978 | printk("hiddev%d", hid->minor); | 1007 | printk("hiddev%d", hid->minor); |
1008 | if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) && | ||
1009 | (hid->claimed & HID_CLAIMED_HIDRAW)) | ||
1010 | printk(","); | ||
1011 | if (hid->claimed & HID_CLAIMED_HIDRAW) | ||
1012 | printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor); | ||
979 | 1013 | ||
980 | c = "Device"; | 1014 | c = "Device"; |
981 | for (i = 0; i < hid->maxcollection; i++) { | 1015 | for (i = 0; i < hid->maxcollection; i++) { |