diff options
author | Jarod Wilson <jarod@redhat.com> | 2010-07-26 19:29:00 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-08-02 15:43:23 -0400 |
commit | eedaf1ae7c365cb150a45cb4857bdef7adc0eb0e (patch) | |
tree | 1a28e9207397e53040972b64ad0cdd8bc3bc5810 | |
parent | 35f168d10f64aafcee86c984efca8cb6537bfe26 (diff) |
V4L/DVB: staging/lirc: add lirc_igorplugusb driver
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/staging/lirc/lirc_igorplugusb.c | 555 |
1 files changed, 555 insertions, 0 deletions
diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/lirc/lirc_igorplugusb.c new file mode 100644 index 000000000000..bce600ede263 --- /dev/null +++ b/drivers/staging/lirc/lirc_igorplugusb.c | |||
@@ -0,0 +1,555 @@ | |||
1 | /* | ||
2 | * lirc_igorplugusb - USB remote support for LIRC | ||
3 | * | ||
4 | * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware. | ||
5 | * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm | ||
6 | * | ||
7 | * The device can only record bursts of up to 36 pulses/spaces. | ||
8 | * Works fine with RC5. Longer commands lead to device buffer overrun. | ||
9 | * (Maybe a better firmware or a microcontroller with more ram can help?) | ||
10 | * | ||
11 | * Version 0.1 [beta status] | ||
12 | * | ||
13 | * Copyright (C) 2004 Jan M. Hochstein | ||
14 | * <hochstein@algo.informatik.tu-darmstadt.de> | ||
15 | * | ||
16 | * This driver was derived from: | ||
17 | * Paul Miller <pmiller9@users.sourceforge.net> | ||
18 | * "lirc_atiusb" module | ||
19 | * Vladimir Dergachev <volodya@minspring.com>'s 2002 | ||
20 | * "USB ATI Remote support" (input device) | ||
21 | * Adrian Dewhurst <sailor-lk@sailorfrag.net>'s 2002 | ||
22 | * "USB StreamZap remote driver" (LIRC) | ||
23 | * Artur Lipowski <alipowski@kki.net.pl>'s 2002 | ||
24 | * "lirc_dev" and "lirc_gpio" LIRC modules | ||
25 | */ | ||
26 | |||
27 | /* | ||
28 | * This program is free software; you can redistribute it and/or modify | ||
29 | * it under the terms of the GNU General Public License as published by | ||
30 | * the Free Software Foundation; either version 2 of the License, or | ||
31 | * (at your option) any later version. | ||
32 | * | ||
33 | * This program is distributed in the hope that it will be useful, | ||
34 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
35 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
36 | * GNU General Public License for more details. | ||
37 | * | ||
38 | * You should have received a copy of the GNU General Public License | ||
39 | * along with this program; if not, write to the Free Software | ||
40 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
41 | */ | ||
42 | |||
43 | #include <linux/module.h> | ||
44 | #include <linux/kernel.h> | ||
45 | #include <linux/kmod.h> | ||
46 | #include <linux/sched.h> | ||
47 | #include <linux/errno.h> | ||
48 | #include <linux/fs.h> | ||
49 | #include <linux/usb.h> | ||
50 | #include <linux/time.h> | ||
51 | |||
52 | #include <media/lirc.h> | ||
53 | #include <media/lirc_dev.h> | ||
54 | |||
55 | |||
56 | /* module identification */ | ||
57 | #define DRIVER_VERSION "0.1" | ||
58 | #define DRIVER_AUTHOR \ | ||
59 | "Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>" | ||
60 | #define DRIVER_DESC "USB remote driver for LIRC" | ||
61 | #define DRIVER_NAME "lirc_igorplugusb" | ||
62 | |||
63 | /* debugging support */ | ||
64 | #ifdef CONFIG_USB_DEBUG | ||
65 | static int debug = 1; | ||
66 | #else | ||
67 | static int debug; | ||
68 | #endif | ||
69 | |||
70 | #define dprintk(fmt, args...) \ | ||
71 | do { \ | ||
72 | if (debug) \ | ||
73 | printk(KERN_DEBUG fmt, ## args); \ | ||
74 | } while (0) | ||
75 | |||
76 | /* One mode2 pulse/space has 4 bytes. */ | ||
77 | #define CODE_LENGTH sizeof(int) | ||
78 | |||
79 | /* Igor's firmware cannot record bursts longer than 36. */ | ||
80 | #define DEVICE_BUFLEN 36 | ||
81 | |||
82 | /* | ||
83 | * Header at the beginning of the device's buffer: | ||
84 | * unsigned char data_length | ||
85 | * unsigned char data_start (!=0 means ring-buffer overrun) | ||
86 | * unsigned char counter (incremented by each burst) | ||
87 | */ | ||
88 | #define DEVICE_HEADERLEN 3 | ||
89 | |||
90 | /* This is for the gap */ | ||
91 | #define ADDITIONAL_LIRC_BYTES 2 | ||
92 | |||
93 | /* times to poll per second */ | ||
94 | #define SAMPLE_RATE 100 | ||
95 | static int sample_rate = SAMPLE_RATE; | ||
96 | |||
97 | |||
98 | /**** Igor's USB Request Codes */ | ||
99 | |||
100 | #define SET_INFRABUFFER_EMPTY 1 | ||
101 | /** | ||
102 | * Params: none | ||
103 | * Answer: empty | ||
104 | */ | ||
105 | |||
106 | #define GET_INFRACODE 2 | ||
107 | /** | ||
108 | * Params: | ||
109 | * wValue: offset to begin reading infra buffer | ||
110 | * | ||
111 | * Answer: infra data | ||
112 | */ | ||
113 | |||
114 | #define SET_DATAPORT_DIRECTION 3 | ||
115 | /** | ||
116 | * Params: | ||
117 | * wValue: (byte) 1 bit for each data port pin (0=in, 1=out) | ||
118 | * | ||
119 | * Answer: empty | ||
120 | */ | ||
121 | |||
122 | #define GET_DATAPORT_DIRECTION 4 | ||
123 | /** | ||
124 | * Params: none | ||
125 | * | ||
126 | * Answer: (byte) 1 bit for each data port pin (0=in, 1=out) | ||
127 | */ | ||
128 | |||
129 | #define SET_OUT_DATAPORT 5 | ||
130 | /** | ||
131 | * Params: | ||
132 | * wValue: byte to write to output data port | ||
133 | * | ||
134 | * Answer: empty | ||
135 | */ | ||
136 | |||
137 | #define GET_OUT_DATAPORT 6 | ||
138 | /** | ||
139 | * Params: none | ||
140 | * | ||
141 | * Answer: least significant 3 bits read from output data port | ||
142 | */ | ||
143 | |||
144 | #define GET_IN_DATAPORT 7 | ||
145 | /** | ||
146 | * Params: none | ||
147 | * | ||
148 | * Answer: least significant 3 bits read from input data port | ||
149 | */ | ||
150 | |||
151 | #define READ_EEPROM 8 | ||
152 | /** | ||
153 | * Params: | ||
154 | * wValue: offset to begin reading EEPROM | ||
155 | * | ||
156 | * Answer: EEPROM bytes | ||
157 | */ | ||
158 | |||
159 | #define WRITE_EEPROM 9 | ||
160 | /** | ||
161 | * Params: | ||
162 | * wValue: offset to EEPROM byte | ||
163 | * wIndex: byte to write | ||
164 | * | ||
165 | * Answer: empty | ||
166 | */ | ||
167 | |||
168 | #define SEND_RS232 10 | ||
169 | /** | ||
170 | * Params: | ||
171 | * wValue: byte to send | ||
172 | * | ||
173 | * Answer: empty | ||
174 | */ | ||
175 | |||
176 | #define RECV_RS232 11 | ||
177 | /** | ||
178 | * Params: none | ||
179 | * | ||
180 | * Answer: byte received | ||
181 | */ | ||
182 | |||
183 | #define SET_RS232_BAUD 12 | ||
184 | /** | ||
185 | * Params: | ||
186 | * wValue: byte to write to UART bit rate register (UBRR) | ||
187 | * | ||
188 | * Answer: empty | ||
189 | */ | ||
190 | |||
191 | #define GET_RS232_BAUD 13 | ||
192 | /** | ||
193 | * Params: none | ||
194 | * | ||
195 | * Answer: byte read from UART bit rate register (UBRR) | ||
196 | */ | ||
197 | |||
198 | |||
199 | /* data structure for each usb remote */ | ||
200 | struct igorplug { | ||
201 | |||
202 | /* usb */ | ||
203 | struct usb_device *usbdev; | ||
204 | struct urb *urb_in; | ||
205 | int devnum; | ||
206 | |||
207 | unsigned char *buf_in; | ||
208 | unsigned int len_in; | ||
209 | int in_space; | ||
210 | struct timeval last_time; | ||
211 | |||
212 | dma_addr_t dma_in; | ||
213 | |||
214 | /* lirc */ | ||
215 | struct lirc_driver *d; | ||
216 | |||
217 | /* handle sending (init strings) */ | ||
218 | int send_flags; | ||
219 | wait_queue_head_t wait_out; | ||
220 | }; | ||
221 | |||
222 | static int unregister_from_lirc(struct igorplug *ir) | ||
223 | { | ||
224 | struct lirc_driver *d = ir->d; | ||
225 | int devnum; | ||
226 | |||
227 | if (!ir->d) | ||
228 | return -EINVAL; | ||
229 | |||
230 | devnum = ir->devnum; | ||
231 | dprintk(DRIVER_NAME "[%d]: unregister from lirc called\n", devnum); | ||
232 | |||
233 | lirc_unregister_driver(d->minor); | ||
234 | |||
235 | printk(DRIVER_NAME "[%d]: usb remote disconnected\n", devnum); | ||
236 | |||
237 | kfree(d); | ||
238 | ir->d = NULL; | ||
239 | kfree(ir); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int set_use_inc(void *data) | ||
244 | { | ||
245 | struct igorplug *ir = data; | ||
246 | |||
247 | if (!ir) { | ||
248 | printk(DRIVER_NAME "[?]: set_use_inc called with no context\n"); | ||
249 | return -EIO; | ||
250 | } | ||
251 | dprintk(DRIVER_NAME "[%d]: set use inc\n", ir->devnum); | ||
252 | |||
253 | if (!ir->usbdev) | ||
254 | return -ENODEV; | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static void set_use_dec(void *data) | ||
260 | { | ||
261 | struct igorplug *ir = data; | ||
262 | |||
263 | if (!ir) { | ||
264 | printk(DRIVER_NAME "[?]: set_use_dec called with no context\n"); | ||
265 | return; | ||
266 | } | ||
267 | dprintk(DRIVER_NAME "[%d]: set use dec\n", ir->devnum); | ||
268 | } | ||
269 | |||
270 | |||
271 | /** | ||
272 | * Called in user context. | ||
273 | * return 0 if data was added to the buffer and | ||
274 | * -ENODATA if none was available. This should add some number of bits | ||
275 | * evenly divisible by code_length to the buffer | ||
276 | */ | ||
277 | static int usb_remote_poll(void *data, struct lirc_buffer *buf) | ||
278 | { | ||
279 | int ret; | ||
280 | struct igorplug *ir = (struct igorplug *)data; | ||
281 | |||
282 | if (!ir->usbdev) /* Has the device been removed? */ | ||
283 | return -ENODEV; | ||
284 | |||
285 | memset(ir->buf_in, 0, ir->len_in); | ||
286 | |||
287 | ret = usb_control_msg( | ||
288 | ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), | ||
289 | GET_INFRACODE, USB_TYPE_VENDOR|USB_DIR_IN, | ||
290 | 0/* offset */, /*unused*/0, | ||
291 | ir->buf_in, ir->len_in, | ||
292 | /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); | ||
293 | if (ret > 0) { | ||
294 | int i = DEVICE_HEADERLEN; | ||
295 | int code, timediff; | ||
296 | struct timeval now; | ||
297 | |||
298 | if (ret <= 1) /* ACK packet has 1 byte --> ignore */ | ||
299 | return -ENODATA; | ||
300 | |||
301 | dprintk(DRIVER_NAME ": Got %d bytes. Header: %02x %02x %02x\n", | ||
302 | ret, ir->buf_in[0], ir->buf_in[1], ir->buf_in[2]); | ||
303 | |||
304 | if (ir->buf_in[2] != 0) { | ||
305 | printk(DRIVER_NAME "[%d]: Device buffer overrun.\n", | ||
306 | ir->devnum); | ||
307 | /* start at earliest byte */ | ||
308 | i = DEVICE_HEADERLEN + ir->buf_in[2]; | ||
309 | /* where are we now? space, gap or pulse? */ | ||
310 | } | ||
311 | |||
312 | do_gettimeofday(&now); | ||
313 | timediff = now.tv_sec - ir->last_time.tv_sec; | ||
314 | if (timediff + 1 > PULSE_MASK / 1000000) | ||
315 | timediff = PULSE_MASK; | ||
316 | else { | ||
317 | timediff *= 1000000; | ||
318 | timediff += now.tv_usec - ir->last_time.tv_usec; | ||
319 | } | ||
320 | ir->last_time.tv_sec = now.tv_sec; | ||
321 | ir->last_time.tv_usec = now.tv_usec; | ||
322 | |||
323 | /* create leading gap */ | ||
324 | code = timediff; | ||
325 | lirc_buffer_write(buf, (unsigned char *)&code); | ||
326 | ir->in_space = 1; /* next comes a pulse */ | ||
327 | |||
328 | /* MODE2: pulse/space (PULSE_BIT) in 1us units */ | ||
329 | |||
330 | while (i < ret) { | ||
331 | /* 1 Igor-tick = 85.333333 us */ | ||
332 | code = (unsigned int)ir->buf_in[i] * 85 | ||
333 | + (unsigned int)ir->buf_in[i] / 3; | ||
334 | if (ir->in_space) | ||
335 | code |= PULSE_BIT; | ||
336 | lirc_buffer_write(buf, (unsigned char *)&code); | ||
337 | /* 1 chunk = CODE_LENGTH bytes */ | ||
338 | ir->in_space ^= 1; | ||
339 | ++i; | ||
340 | } | ||
341 | |||
342 | ret = usb_control_msg( | ||
343 | ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), | ||
344 | SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, | ||
345 | /*unused*/0, /*unused*/0, | ||
346 | /*dummy*/ir->buf_in, /*dummy*/ir->len_in, | ||
347 | /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); | ||
348 | if (ret < 0) | ||
349 | printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: " | ||
350 | "error %d\n", ir->devnum, ret); | ||
351 | return 0; | ||
352 | } else if (ret < 0) | ||
353 | printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n", | ||
354 | ir->devnum, ret); | ||
355 | |||
356 | return -ENODATA; | ||
357 | } | ||
358 | |||
359 | |||
360 | |||
361 | static int usb_remote_probe(struct usb_interface *intf, | ||
362 | const struct usb_device_id *id) | ||
363 | { | ||
364 | struct usb_device *dev = NULL; | ||
365 | struct usb_host_interface *idesc = NULL; | ||
366 | struct usb_host_endpoint *ep_ctl2; | ||
367 | struct igorplug *ir = NULL; | ||
368 | struct lirc_driver *driver = NULL; | ||
369 | int devnum, pipe, maxp; | ||
370 | int minor = 0; | ||
371 | char buf[63], name[128] = ""; | ||
372 | int mem_failure = 0; | ||
373 | int ret; | ||
374 | |||
375 | dprintk(DRIVER_NAME ": usb probe called.\n"); | ||
376 | |||
377 | dev = interface_to_usbdev(intf); | ||
378 | |||
379 | idesc = intf->cur_altsetting; | ||
380 | |||
381 | if (idesc->desc.bNumEndpoints != 1) | ||
382 | return -ENODEV; | ||
383 | ep_ctl2 = idesc->endpoint; | ||
384 | if (((ep_ctl2->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) | ||
385 | != USB_DIR_IN) | ||
386 | || (ep_ctl2->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | ||
387 | != USB_ENDPOINT_XFER_CONTROL) | ||
388 | return -ENODEV; | ||
389 | pipe = usb_rcvctrlpipe(dev, ep_ctl2->desc.bEndpointAddress); | ||
390 | devnum = dev->devnum; | ||
391 | maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); | ||
392 | |||
393 | dprintk(DRIVER_NAME "[%d]: bytes_in_key=%lu maxp=%d\n", | ||
394 | devnum, CODE_LENGTH, maxp); | ||
395 | |||
396 | |||
397 | mem_failure = 0; | ||
398 | ir = kzalloc(sizeof(struct igorplug), GFP_KERNEL); | ||
399 | if (!ir) { | ||
400 | mem_failure = 1; | ||
401 | goto mem_failure_switch; | ||
402 | } | ||
403 | driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); | ||
404 | if (!driver) { | ||
405 | mem_failure = 2; | ||
406 | goto mem_failure_switch; | ||
407 | } | ||
408 | |||
409 | ir->buf_in = usb_alloc_coherent(dev, | ||
410 | DEVICE_BUFLEN+DEVICE_HEADERLEN, | ||
411 | GFP_ATOMIC, &ir->dma_in); | ||
412 | if (!ir->buf_in) { | ||
413 | mem_failure = 3; | ||
414 | goto mem_failure_switch; | ||
415 | } | ||
416 | |||
417 | strcpy(driver->name, DRIVER_NAME " "); | ||
418 | driver->minor = -1; | ||
419 | driver->code_length = CODE_LENGTH * 8; /* in bits */ | ||
420 | driver->features = LIRC_CAN_REC_MODE2; | ||
421 | driver->data = ir; | ||
422 | driver->chunk_size = CODE_LENGTH; | ||
423 | driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES; | ||
424 | driver->set_use_inc = &set_use_inc; | ||
425 | driver->set_use_dec = &set_use_dec; | ||
426 | driver->sample_rate = sample_rate; /* per second */ | ||
427 | driver->add_to_buf = &usb_remote_poll; | ||
428 | driver->dev = &intf->dev; | ||
429 | driver->owner = THIS_MODULE; | ||
430 | |||
431 | init_waitqueue_head(&ir->wait_out); | ||
432 | |||
433 | minor = lirc_register_driver(driver); | ||
434 | if (minor < 0) | ||
435 | mem_failure = 9; | ||
436 | |||
437 | mem_failure_switch: | ||
438 | |||
439 | switch (mem_failure) { | ||
440 | case 9: | ||
441 | usb_free_coherent(dev, DEVICE_BUFLEN+DEVICE_HEADERLEN, | ||
442 | ir->buf_in, ir->dma_in); | ||
443 | case 3: | ||
444 | kfree(driver); | ||
445 | case 2: | ||
446 | kfree(ir); | ||
447 | case 1: | ||
448 | printk(DRIVER_NAME "[%d]: out of memory (code=%d)\n", | ||
449 | devnum, mem_failure); | ||
450 | return -ENOMEM; | ||
451 | } | ||
452 | |||
453 | driver->minor = minor; | ||
454 | ir->d = driver; | ||
455 | ir->devnum = devnum; | ||
456 | ir->usbdev = dev; | ||
457 | ir->len_in = DEVICE_BUFLEN+DEVICE_HEADERLEN; | ||
458 | ir->in_space = 1; /* First mode2 event is a space. */ | ||
459 | do_gettimeofday(&ir->last_time); | ||
460 | |||
461 | if (dev->descriptor.iManufacturer | ||
462 | && usb_string(dev, dev->descriptor.iManufacturer, | ||
463 | buf, sizeof(buf)) > 0) | ||
464 | strlcpy(name, buf, sizeof(name)); | ||
465 | if (dev->descriptor.iProduct | ||
466 | && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0) | ||
467 | snprintf(name + strlen(name), sizeof(name) - strlen(name), | ||
468 | " %s", buf); | ||
469 | printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name, | ||
470 | dev->bus->busnum, devnum); | ||
471 | |||
472 | /* clear device buffer */ | ||
473 | ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), | ||
474 | SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN, | ||
475 | /*unused*/0, /*unused*/0, | ||
476 | /*dummy*/ir->buf_in, /*dummy*/ir->len_in, | ||
477 | /*timeout*/HZ * USB_CTRL_GET_TIMEOUT); | ||
478 | if (ret < 0) | ||
479 | printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n", | ||
480 | devnum, ret); | ||
481 | |||
482 | usb_set_intfdata(intf, ir); | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | |||
487 | static void usb_remote_disconnect(struct usb_interface *intf) | ||
488 | { | ||
489 | struct usb_device *dev = interface_to_usbdev(intf); | ||
490 | struct igorplug *ir = usb_get_intfdata(intf); | ||
491 | usb_set_intfdata(intf, NULL); | ||
492 | |||
493 | if (!ir || !ir->d) | ||
494 | return; | ||
495 | |||
496 | ir->usbdev = NULL; | ||
497 | wake_up_all(&ir->wait_out); | ||
498 | |||
499 | usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in); | ||
500 | |||
501 | unregister_from_lirc(ir); | ||
502 | } | ||
503 | |||
504 | static struct usb_device_id usb_remote_id_table[] = { | ||
505 | /* Igor Plug USB (Atmel's Manufact. ID) */ | ||
506 | { USB_DEVICE(0x03eb, 0x0002) }, | ||
507 | |||
508 | /* Terminating entry */ | ||
509 | { } | ||
510 | }; | ||
511 | |||
512 | static struct usb_driver usb_remote_driver = { | ||
513 | .name = DRIVER_NAME, | ||
514 | .probe = usb_remote_probe, | ||
515 | .disconnect = usb_remote_disconnect, | ||
516 | .id_table = usb_remote_id_table | ||
517 | }; | ||
518 | |||
519 | static int __init usb_remote_init(void) | ||
520 | { | ||
521 | int i; | ||
522 | |||
523 | printk(KERN_INFO "\n" | ||
524 | DRIVER_NAME ": " DRIVER_DESC " v" DRIVER_VERSION "\n"); | ||
525 | printk(DRIVER_NAME ": " DRIVER_AUTHOR "\n"); | ||
526 | dprintk(DRIVER_NAME ": debug mode enabled\n"); | ||
527 | |||
528 | i = usb_register(&usb_remote_driver); | ||
529 | if (i < 0) { | ||
530 | printk(DRIVER_NAME ": usb register failed, result = %d\n", i); | ||
531 | return -ENODEV; | ||
532 | } | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static void __exit usb_remote_exit(void) | ||
538 | { | ||
539 | usb_deregister(&usb_remote_driver); | ||
540 | } | ||
541 | |||
542 | module_init(usb_remote_init); | ||
543 | module_exit(usb_remote_exit); | ||
544 | |||
545 | #include <linux/vermagic.h> | ||
546 | MODULE_INFO(vermagic, VERMAGIC_STRING); | ||
547 | |||
548 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
549 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
550 | MODULE_LICENSE("GPL"); | ||
551 | MODULE_DEVICE_TABLE(usb, usb_remote_id_table); | ||
552 | |||
553 | module_param(sample_rate, int, S_IRUGO | S_IWUSR); | ||
554 | MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)"); | ||
555 | |||