]>
Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: GPL-2.0+ |
1da177e4 LT |
2 | /* -*- linux-c -*- */ |
3 | ||
4 | /* | |
5 | * Driver for USB Rio 500 | |
6 | * | |
7 | * Cesar Miquel (miquel@df.uba.ar) | |
8 | * | |
9 | * based on hp_scanner.c by David E. Nelson (dnelson@jump.net) | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License as | |
13 | * published by the Free Software Foundation; either version 2 of the | |
14 | * License, or (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, but | |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 | * | |
25 | * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee). | |
26 | * | |
27 | * Changelog: | |
28 | * 30/05/2003 replaced lock/unlock kernel with up/down | |
29 | * Daniele Bellucci bellucda@tiscali.it | |
30 | * */ | |
31 | ||
32 | #include <linux/module.h> | |
33 | #include <linux/kernel.h> | |
34 | #include <linux/signal.h> | |
174cd4b1 | 35 | #include <linux/sched/signal.h> |
925ce689 | 36 | #include <linux/mutex.h> |
1da177e4 LT |
37 | #include <linux/errno.h> |
38 | #include <linux/random.h> | |
39 | #include <linux/poll.h> | |
1da177e4 LT |
40 | #include <linux/slab.h> |
41 | #include <linux/spinlock.h> | |
42 | #include <linux/usb.h> | |
1da177e4 LT |
43 | #include <linux/wait.h> |
44 | ||
45 | #include "rio500_usb.h" | |
46 | ||
1da177e4 LT |
47 | #define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>" |
48 | #define DRIVER_DESC "USB Rio 500 driver" | |
49 | ||
50 | #define RIO_MINOR 64 | |
51 | ||
52 | /* stall/wait timeout for rio */ | |
53 | #define NAK_TIMEOUT (HZ) | |
54 | ||
55 | #define IBUF_SIZE 0x1000 | |
56 | ||
57 | /* Size of the rio buffer */ | |
58 | #define OBUF_SIZE 0x10000 | |
59 | ||
60 | struct rio_usb_data { | |
61 | struct usb_device *rio_dev; /* init: probe_rio */ | |
62 | unsigned int ifnum; /* Interface number of the USB device */ | |
63 | int isopen; /* nz if open */ | |
64 | int present; /* Device is present on the bus */ | |
65 | char *obuf, *ibuf; /* transfer buffers */ | |
66 | char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */ | |
67 | wait_queue_head_t wait_q; /* for timeouts */ | |
2cba72f0 | 68 | struct mutex lock; /* general race avoidance */ |
1da177e4 LT |
69 | }; |
70 | ||
925ce689 | 71 | static DEFINE_MUTEX(rio500_mutex); |
1da177e4 LT |
72 | static struct rio_usb_data rio_instance; |
73 | ||
74 | static int open_rio(struct inode *inode, struct file *file) | |
75 | { | |
76 | struct rio_usb_data *rio = &rio_instance; | |
511e2d02 ON |
77 | |
78 | /* against disconnect() */ | |
925ce689 | 79 | mutex_lock(&rio500_mutex); |
2cba72f0 | 80 | mutex_lock(&(rio->lock)); |
1da177e4 LT |
81 | |
82 | if (rio->isopen || !rio->present) { | |
2cba72f0 | 83 | mutex_unlock(&(rio->lock)); |
925ce689 | 84 | mutex_unlock(&rio500_mutex); |
1da177e4 LT |
85 | return -EBUSY; |
86 | } | |
87 | rio->isopen = 1; | |
88 | ||
89 | init_waitqueue_head(&rio->wait_q); | |
90 | ||
2cba72f0 | 91 | mutex_unlock(&(rio->lock)); |
1da177e4 | 92 | |
1b29a375 | 93 | dev_info(&rio->rio_dev->dev, "Rio opened.\n"); |
925ce689 | 94 | mutex_unlock(&rio500_mutex); |
1da177e4 LT |
95 | |
96 | return 0; | |
97 | } | |
98 | ||
99 | static int close_rio(struct inode *inode, struct file *file) | |
100 | { | |
101 | struct rio_usb_data *rio = &rio_instance; | |
102 | ||
103 | rio->isopen = 0; | |
104 | ||
1b29a375 | 105 | dev_info(&rio->rio_dev->dev, "Rio closed.\n"); |
1da177e4 LT |
106 | return 0; |
107 | } | |
108 | ||
54592157 | 109 | static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) |
1da177e4 LT |
110 | { |
111 | struct RioCommand rio_cmd; | |
112 | struct rio_usb_data *rio = &rio_instance; | |
113 | void __user *data; | |
114 | unsigned char *buffer; | |
115 | int result, requesttype; | |
116 | int retries; | |
117 | int retval=0; | |
118 | ||
2cba72f0 | 119 | mutex_lock(&(rio->lock)); |
1da177e4 | 120 | /* Sanity check to make sure rio is connected, powered, etc */ |
3328d975 | 121 | if (rio->present == 0 || rio->rio_dev == NULL) { |
1da177e4 LT |
122 | retval = -ENODEV; |
123 | goto err_out; | |
124 | } | |
125 | ||
126 | switch (cmd) { | |
127 | case RIO_RECV_COMMAND: | |
128 | data = (void __user *) arg; | |
129 | if (data == NULL) | |
130 | break; | |
131 | if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) { | |
132 | retval = -EFAULT; | |
133 | goto err_out; | |
134 | } | |
135 | if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) { | |
136 | retval = -EINVAL; | |
137 | goto err_out; | |
138 | } | |
139 | buffer = (unsigned char *) __get_free_page(GFP_KERNEL); | |
140 | if (buffer == NULL) { | |
141 | retval = -ENOMEM; | |
142 | goto err_out; | |
143 | } | |
144 | if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) { | |
145 | retval = -EFAULT; | |
146 | free_page((unsigned long) buffer); | |
147 | goto err_out; | |
148 | } | |
149 | ||
150 | requesttype = rio_cmd.requesttype | USB_DIR_IN | | |
151 | USB_TYPE_VENDOR | USB_RECIP_DEVICE; | |
e1a344d3 GKH |
152 | dev_dbg(&rio->rio_dev->dev, |
153 | "sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", | |
154 | requesttype, rio_cmd.request, rio_cmd.value, | |
155 | rio_cmd.index, rio_cmd.length); | |
1da177e4 LT |
156 | /* Send rio control message */ |
157 | retries = 3; | |
158 | while (retries) { | |
159 | result = usb_control_msg(rio->rio_dev, | |
160 | usb_rcvctrlpipe(rio-> rio_dev, 0), | |
161 | rio_cmd.request, | |
162 | requesttype, | |
163 | rio_cmd.value, | |
164 | rio_cmd.index, buffer, | |
165 | rio_cmd.length, | |
166 | jiffies_to_msecs(rio_cmd.timeout)); | |
167 | if (result == -ETIMEDOUT) | |
168 | retries--; | |
169 | else if (result < 0) { | |
c41fba13 GKH |
170 | dev_err(&rio->rio_dev->dev, |
171 | "Error executing ioctrl. code = %d\n", | |
172 | result); | |
1da177e4 LT |
173 | retries = 0; |
174 | } else { | |
e1a344d3 GKH |
175 | dev_dbg(&rio->rio_dev->dev, |
176 | "Executed ioctl. Result = %d (data=%02x)\n", | |
177 | result, buffer[0]); | |
1da177e4 LT |
178 | if (copy_to_user(rio_cmd.buffer, buffer, |
179 | rio_cmd.length)) { | |
180 | free_page((unsigned long) buffer); | |
181 | retval = -EFAULT; | |
182 | goto err_out; | |
183 | } | |
184 | retries = 0; | |
185 | } | |
186 | ||
187 | /* rio_cmd.buffer contains a raw stream of single byte | |
188 | data which has been returned from rio. Data is | |
189 | interpreted at application level. For data that | |
190 | will be cast to data types longer than 1 byte, data | |
191 | will be little_endian and will potentially need to | |
192 | be swapped at the app level */ | |
193 | ||
194 | } | |
195 | free_page((unsigned long) buffer); | |
196 | break; | |
197 | ||
198 | case RIO_SEND_COMMAND: | |
199 | data = (void __user *) arg; | |
200 | if (data == NULL) | |
201 | break; | |
202 | if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) { | |
203 | retval = -EFAULT; | |
204 | goto err_out; | |
205 | } | |
206 | if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) { | |
207 | retval = -EINVAL; | |
208 | goto err_out; | |
209 | } | |
210 | buffer = (unsigned char *) __get_free_page(GFP_KERNEL); | |
211 | if (buffer == NULL) { | |
212 | retval = -ENOMEM; | |
213 | goto err_out; | |
214 | } | |
215 | if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) { | |
216 | free_page((unsigned long)buffer); | |
217 | retval = -EFAULT; | |
218 | goto err_out; | |
219 | } | |
220 | ||
221 | requesttype = rio_cmd.requesttype | USB_DIR_OUT | | |
222 | USB_TYPE_VENDOR | USB_RECIP_DEVICE; | |
e1a344d3 GKH |
223 | dev_dbg(&rio->rio_dev->dev, |
224 | "sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", | |
225 | requesttype, rio_cmd.request, rio_cmd.value, | |
226 | rio_cmd.index, rio_cmd.length); | |
1da177e4 LT |
227 | /* Send rio control message */ |
228 | retries = 3; | |
229 | while (retries) { | |
230 | result = usb_control_msg(rio->rio_dev, | |
231 | usb_sndctrlpipe(rio-> rio_dev, 0), | |
232 | rio_cmd.request, | |
233 | requesttype, | |
234 | rio_cmd.value, | |
235 | rio_cmd.index, buffer, | |
236 | rio_cmd.length, | |
237 | jiffies_to_msecs(rio_cmd.timeout)); | |
238 | if (result == -ETIMEDOUT) | |
239 | retries--; | |
240 | else if (result < 0) { | |
c41fba13 GKH |
241 | dev_err(&rio->rio_dev->dev, |
242 | "Error executing ioctrl. code = %d\n", | |
243 | result); | |
1da177e4 LT |
244 | retries = 0; |
245 | } else { | |
e1a344d3 GKH |
246 | dev_dbg(&rio->rio_dev->dev, |
247 | "Executed ioctl. Result = %d\n", result); | |
1da177e4 LT |
248 | retries = 0; |
249 | ||
250 | } | |
251 | ||
252 | } | |
253 | free_page((unsigned long) buffer); | |
254 | break; | |
255 | ||
256 | default: | |
257 | retval = -ENOTTY; | |
258 | break; | |
259 | } | |
260 | ||
261 | ||
262 | err_out: | |
2cba72f0 | 263 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
264 | return retval; |
265 | } | |
266 | ||
267 | static ssize_t | |
268 | write_rio(struct file *file, const char __user *buffer, | |
269 | size_t count, loff_t * ppos) | |
270 | { | |
271 | DEFINE_WAIT(wait); | |
272 | struct rio_usb_data *rio = &rio_instance; | |
273 | ||
274 | unsigned long copy_size; | |
275 | unsigned long bytes_written = 0; | |
276 | unsigned int partial; | |
277 | ||
278 | int result = 0; | |
279 | int maxretry; | |
280 | int errn = 0; | |
2cba72f0 | 281 | int intr; |
1da177e4 | 282 | |
2cba72f0 ON |
283 | intr = mutex_lock_interruptible(&(rio->lock)); |
284 | if (intr) | |
285 | return -EINTR; | |
1da177e4 | 286 | /* Sanity check to make sure rio is connected, powered, etc */ |
3328d975 | 287 | if (rio->present == 0 || rio->rio_dev == NULL) { |
2cba72f0 | 288 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
289 | return -ENODEV; |
290 | } | |
291 | ||
292 | ||
293 | ||
294 | do { | |
295 | unsigned long thistime; | |
296 | char *obuf = rio->obuf; | |
297 | ||
298 | thistime = copy_size = | |
299 | (count >= OBUF_SIZE) ? OBUF_SIZE : count; | |
300 | if (copy_from_user(rio->obuf, buffer, copy_size)) { | |
301 | errn = -EFAULT; | |
302 | goto error; | |
303 | } | |
304 | maxretry = 5; | |
305 | while (thistime) { | |
306 | if (!rio->rio_dev) { | |
307 | errn = -ENODEV; | |
308 | goto error; | |
309 | } | |
310 | if (signal_pending(current)) { | |
2cba72f0 | 311 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
312 | return bytes_written ? bytes_written : -EINTR; |
313 | } | |
314 | ||
315 | result = usb_bulk_msg(rio->rio_dev, | |
316 | usb_sndbulkpipe(rio->rio_dev, 2), | |
317 | obuf, thistime, &partial, 5000); | |
318 | ||
e1a344d3 GKH |
319 | dev_dbg(&rio->rio_dev->dev, |
320 | "write stats: result:%d thistime:%lu partial:%u\n", | |
321 | result, thistime, partial); | |
1da177e4 LT |
322 | |
323 | if (result == -ETIMEDOUT) { /* NAK - so hold for a while */ | |
324 | if (!maxretry--) { | |
325 | errn = -ETIME; | |
326 | goto error; | |
327 | } | |
328 | prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE); | |
329 | schedule_timeout(NAK_TIMEOUT); | |
330 | finish_wait(&rio->wait_q, &wait); | |
331 | continue; | |
332 | } else if (!result && partial) { | |
333 | obuf += partial; | |
334 | thistime -= partial; | |
335 | } else | |
336 | break; | |
17e67910 | 337 | } |
1da177e4 | 338 | if (result) { |
c41fba13 GKH |
339 | dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n", |
340 | result); | |
1da177e4 LT |
341 | errn = -EIO; |
342 | goto error; | |
343 | } | |
344 | bytes_written += copy_size; | |
345 | count -= copy_size; | |
346 | buffer += copy_size; | |
347 | } while (count > 0); | |
348 | ||
2cba72f0 | 349 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
350 | |
351 | return bytes_written ? bytes_written : -EIO; | |
352 | ||
353 | error: | |
2cba72f0 | 354 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
355 | return errn; |
356 | } | |
357 | ||
358 | static ssize_t | |
359 | read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) | |
360 | { | |
361 | DEFINE_WAIT(wait); | |
362 | struct rio_usb_data *rio = &rio_instance; | |
363 | ssize_t read_count; | |
364 | unsigned int partial; | |
365 | int this_read; | |
366 | int result; | |
367 | int maxretry = 10; | |
368 | char *ibuf; | |
2cba72f0 | 369 | int intr; |
1da177e4 | 370 | |
2cba72f0 ON |
371 | intr = mutex_lock_interruptible(&(rio->lock)); |
372 | if (intr) | |
373 | return -EINTR; | |
1da177e4 | 374 | /* Sanity check to make sure rio is connected, powered, etc */ |
3328d975 | 375 | if (rio->present == 0 || rio->rio_dev == NULL) { |
2cba72f0 | 376 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
377 | return -ENODEV; |
378 | } | |
379 | ||
380 | ibuf = rio->ibuf; | |
381 | ||
382 | read_count = 0; | |
383 | ||
384 | ||
385 | while (count > 0) { | |
386 | if (signal_pending(current)) { | |
2cba72f0 | 387 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
388 | return read_count ? read_count : -EINTR; |
389 | } | |
390 | if (!rio->rio_dev) { | |
2cba72f0 | 391 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
392 | return -ENODEV; |
393 | } | |
394 | this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count; | |
395 | ||
396 | result = usb_bulk_msg(rio->rio_dev, | |
397 | usb_rcvbulkpipe(rio->rio_dev, 1), | |
398 | ibuf, this_read, &partial, | |
399 | 8000); | |
400 | ||
e1a344d3 GKH |
401 | dev_dbg(&rio->rio_dev->dev, |
402 | "read stats: result:%d this_read:%u partial:%u\n", | |
403 | result, this_read, partial); | |
1da177e4 LT |
404 | |
405 | if (partial) { | |
406 | count = this_read = partial; | |
407 | } else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */ | |
408 | if (!maxretry--) { | |
2cba72f0 | 409 | mutex_unlock(&(rio->lock)); |
c41fba13 GKH |
410 | dev_err(&rio->rio_dev->dev, |
411 | "read_rio: maxretry timeout\n"); | |
1da177e4 LT |
412 | return -ETIME; |
413 | } | |
414 | prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE); | |
415 | schedule_timeout(NAK_TIMEOUT); | |
416 | finish_wait(&rio->wait_q, &wait); | |
417 | continue; | |
418 | } else if (result != -EREMOTEIO) { | |
2cba72f0 | 419 | mutex_unlock(&(rio->lock)); |
c41fba13 | 420 | dev_err(&rio->rio_dev->dev, |
651b297c | 421 | "Read Whoops - result:%d partial:%u this_read:%u\n", |
c41fba13 | 422 | result, partial, this_read); |
1da177e4 LT |
423 | return -EIO; |
424 | } else { | |
2cba72f0 | 425 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
426 | return (0); |
427 | } | |
428 | ||
429 | if (this_read) { | |
430 | if (copy_to_user(buffer, ibuf, this_read)) { | |
2cba72f0 | 431 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
432 | return -EFAULT; |
433 | } | |
434 | count -= this_read; | |
435 | read_count += this_read; | |
436 | buffer += this_read; | |
437 | } | |
438 | } | |
2cba72f0 | 439 | mutex_unlock(&(rio->lock)); |
1da177e4 LT |
440 | return read_count; |
441 | } | |
442 | ||
828c0950 | 443 | static const struct file_operations usb_rio_fops = { |
1da177e4 LT |
444 | .owner = THIS_MODULE, |
445 | .read = read_rio, | |
446 | .write = write_rio, | |
54592157 | 447 | .unlocked_ioctl = ioctl_rio, |
1da177e4 LT |
448 | .open = open_rio, |
449 | .release = close_rio, | |
6038f373 | 450 | .llseek = noop_llseek, |
1da177e4 LT |
451 | }; |
452 | ||
453 | static struct usb_class_driver usb_rio_class = { | |
d6e5bcf4 | 454 | .name = "rio500%d", |
1da177e4 | 455 | .fops = &usb_rio_fops, |
1da177e4 LT |
456 | .minor_base = RIO_MINOR, |
457 | }; | |
458 | ||
459 | static int probe_rio(struct usb_interface *intf, | |
460 | const struct usb_device_id *id) | |
461 | { | |
462 | struct usb_device *dev = interface_to_usbdev(intf); | |
463 | struct rio_usb_data *rio = &rio_instance; | |
464 | int retval; | |
465 | ||
1b29a375 | 466 | dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum); |
1da177e4 LT |
467 | |
468 | retval = usb_register_dev(intf, &usb_rio_class); | |
469 | if (retval) { | |
c41fba13 GKH |
470 | dev_err(&dev->dev, |
471 | "Not able to get a minor for this device.\n"); | |
1da177e4 LT |
472 | return -ENOMEM; |
473 | } | |
474 | ||
475 | rio->rio_dev = dev; | |
476 | ||
0e8eb0f0 | 477 | if (!(rio->obuf = kmalloc(OBUF_SIZE, GFP_KERNEL))) { |
c41fba13 GKH |
478 | dev_err(&dev->dev, |
479 | "probe_rio: Not enough memory for the output buffer\n"); | |
1da177e4 LT |
480 | usb_deregister_dev(intf, &usb_rio_class); |
481 | return -ENOMEM; | |
482 | } | |
e1a344d3 | 483 | dev_dbg(&intf->dev, "obuf address:%p\n", rio->obuf); |
1da177e4 | 484 | |
0e8eb0f0 | 485 | if (!(rio->ibuf = kmalloc(IBUF_SIZE, GFP_KERNEL))) { |
c41fba13 GKH |
486 | dev_err(&dev->dev, |
487 | "probe_rio: Not enough memory for the input buffer\n"); | |
1da177e4 LT |
488 | usb_deregister_dev(intf, &usb_rio_class); |
489 | kfree(rio->obuf); | |
490 | return -ENOMEM; | |
491 | } | |
e1a344d3 | 492 | dev_dbg(&intf->dev, "ibuf address:%p\n", rio->ibuf); |
1da177e4 | 493 | |
2cba72f0 | 494 | mutex_init(&(rio->lock)); |
1da177e4 LT |
495 | |
496 | usb_set_intfdata (intf, rio); | |
497 | rio->present = 1; | |
498 | ||
499 | return 0; | |
500 | } | |
501 | ||
502 | static void disconnect_rio(struct usb_interface *intf) | |
503 | { | |
504 | struct rio_usb_data *rio = usb_get_intfdata (intf); | |
505 | ||
506 | usb_set_intfdata (intf, NULL); | |
925ce689 | 507 | mutex_lock(&rio500_mutex); |
1da177e4 LT |
508 | if (rio) { |
509 | usb_deregister_dev(intf, &usb_rio_class); | |
510 | ||
2cba72f0 | 511 | mutex_lock(&(rio->lock)); |
1da177e4 LT |
512 | if (rio->isopen) { |
513 | rio->isopen = 0; | |
514 | /* better let it finish - the release will do whats needed */ | |
515 | rio->rio_dev = NULL; | |
2cba72f0 | 516 | mutex_unlock(&(rio->lock)); |
925ce689 | 517 | mutex_unlock(&rio500_mutex); |
1da177e4 LT |
518 | return; |
519 | } | |
520 | kfree(rio->ibuf); | |
521 | kfree(rio->obuf); | |
522 | ||
1b29a375 | 523 | dev_info(&intf->dev, "USB Rio disconnected.\n"); |
1da177e4 LT |
524 | |
525 | rio->present = 0; | |
2cba72f0 | 526 | mutex_unlock(&(rio->lock)); |
1da177e4 | 527 | } |
925ce689 | 528 | mutex_unlock(&rio500_mutex); |
1da177e4 LT |
529 | } |
530 | ||
33b9e162 | 531 | static const struct usb_device_id rio_table[] = { |
1da177e4 LT |
532 | { USB_DEVICE(0x0841, 1) }, /* Rio 500 */ |
533 | { } /* Terminating entry */ | |
534 | }; | |
535 | ||
536 | MODULE_DEVICE_TABLE (usb, rio_table); | |
537 | ||
538 | static struct usb_driver rio_driver = { | |
1da177e4 LT |
539 | .name = "rio500", |
540 | .probe = probe_rio, | |
541 | .disconnect = disconnect_rio, | |
542 | .id_table = rio_table, | |
543 | }; | |
544 | ||
65db4305 | 545 | module_usb_driver(rio_driver); |
1da177e4 LT |
546 | |
547 | MODULE_AUTHOR( DRIVER_AUTHOR ); | |
548 | MODULE_DESCRIPTION( DRIVER_DESC ); | |
549 | MODULE_LICENSE("GPL"); | |
550 |