Showing the changes to drivers/staging/lirc/lirc_igorplugusb.c (1 of 1 file). Show all
Unified · Split
| @@ -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 | + | |