blob: 9c36f0ece20ff6b43631e860621198f694400d5f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * USB Serial Converter driver
3 *
Greg Kroah-Hartman502b95c2005-06-20 21:15:16 -07004 * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
6 * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
Greg Kroah-Hartman502b95c2005-06-20 21:15:16 -070012 * This driver was originally based on the ACM driver by Armin Fuerst (which was
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 * based on a driver by Brad Keryan)
14 *
15 * See Documentation/usb/usb-serial.txt for more information on using this driver
16 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 */
18
19#include <linux/config.h>
20#include <linux/kernel.h>
21#include <linux/errno.h>
22#include <linux/init.h>
23#include <linux/slab.h>
24#include <linux/tty.h>
25#include <linux/tty_driver.h>
26#include <linux/tty_flip.h>
27#include <linux/module.h>
28#include <linux/moduleparam.h>
29#include <linux/spinlock.h>
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -030030#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/list.h>
32#include <linux/smp_lock.h>
33#include <asm/uaccess.h>
34#include <linux/usb.h>
35#include "usb-serial.h"
36#include "pl2303.h"
37
38/*
39 * Version Information
40 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
42#define DRIVER_DESC "USB Serial Driver core"
43
44/* Driver structure we register with the USB core */
45static struct usb_driver usb_serial_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 .name = "usbserial",
47 .probe = usb_serial_probe,
48 .disconnect = usb_serial_disconnect,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -080049 .no_dynamic_id = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -070050};
51
52/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
53 the MODULE_DEVICE_TABLE declarations in each serial driver
54 cause the "hotplug" program to pull in whatever module is necessary
55 via modprobe, and modprobe will load usbserial because the serial
56 drivers depend on it.
57*/
58
59static int debug;
60static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
61static LIST_HEAD(usb_serial_driver_list);
62
63struct usb_serial *usb_serial_get_by_index(unsigned index)
64{
65 struct usb_serial *serial = serial_table[index];
66
67 if (serial)
68 kref_get(&serial->kref);
69 return serial;
70}
71
72static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor)
73{
74 unsigned int i, j;
75 int good_spot;
76
77 dbg("%s %d", __FUNCTION__, num_ports);
78
79 *minor = 0;
80 for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
81 if (serial_table[i])
82 continue;
83
84 good_spot = 1;
85 for (j = 1; j <= num_ports-1; ++j)
86 if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) {
87 good_spot = 0;
88 i += j;
89 break;
90 }
91 if (good_spot == 0)
92 continue;
93
94 *minor = i;
95 dbg("%s - minor base = %d", __FUNCTION__, *minor);
96 for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
97 serial_table[i] = serial;
98 return serial;
99 }
100 return NULL;
101}
102
103static void return_serial(struct usb_serial *serial)
104{
105 int i;
106
107 dbg("%s", __FUNCTION__);
108
109 if (serial == NULL)
110 return;
111
112 for (i = 0; i < serial->num_ports; ++i) {
113 serial_table[serial->minor + i] = NULL;
114 }
115}
116
117static void destroy_serial(struct kref *kref)
118{
119 struct usb_serial *serial;
120 struct usb_serial_port *port;
121 int i;
122
123 serial = to_usb_serial(kref);
124
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -0700125 dbg("%s - %s", __FUNCTION__, serial->type->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127 serial->type->shutdown(serial);
128
129 /* return the minor range that this device had */
130 return_serial(serial);
131
132 for (i = 0; i < serial->num_ports; ++i)
133 serial->port[i]->open_count = 0;
134
135 /* the ports are cleaned up and released in port_release() */
136 for (i = 0; i < serial->num_ports; ++i)
137 if (serial->port[i]->dev.parent != NULL) {
138 device_unregister(&serial->port[i]->dev);
139 serial->port[i] = NULL;
140 }
141
142 /* If this is a "fake" port, we have to clean it up here, as it will
143 * not get cleaned up in port_release() as it was never registered with
144 * the driver core */
145 if (serial->num_ports < serial->num_port_pointers) {
146 for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
147 port = serial->port[i];
148 if (!port)
149 continue;
150 usb_kill_urb(port->read_urb);
151 usb_free_urb(port->read_urb);
152 usb_kill_urb(port->write_urb);
153 usb_free_urb(port->write_urb);
154 usb_kill_urb(port->interrupt_in_urb);
155 usb_free_urb(port->interrupt_in_urb);
156 usb_kill_urb(port->interrupt_out_urb);
157 usb_free_urb(port->interrupt_out_urb);
158 kfree(port->bulk_in_buffer);
159 kfree(port->bulk_out_buffer);
160 kfree(port->interrupt_in_buffer);
161 kfree(port->interrupt_out_buffer);
162 }
163 }
164
165 usb_put_dev(serial->dev);
166
167 /* free up any memory that we allocated */
168 kfree (serial);
169}
170
171/*****************************************************************************
172 * Driver tty interface functions
173 *****************************************************************************/
174static int serial_open (struct tty_struct *tty, struct file * filp)
175{
176 struct usb_serial *serial;
177 struct usb_serial_port *port;
178 unsigned int portNumber;
179 int retval;
180
181 dbg("%s", __FUNCTION__);
182
183 /* get the serial object associated with this tty pointer */
184 serial = usb_serial_get_by_index(tty->index);
185 if (!serial) {
186 tty->driver_data = NULL;
187 return -ENODEV;
188 }
189
190 portNumber = tty->index - serial->minor;
191 port = serial->port[portNumber];
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300192 if (!port) {
193 retval = -ENODEV;
194 goto bailout_kref_put;
195 }
Luiz Fernando Capitulino8a4613f2005-11-28 19:16:07 -0200196
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300197 if (mutex_lock_interruptible(&port->mutex)) {
198 retval = -ERESTARTSYS;
199 goto bailout_kref_put;
200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 ++port->open_count;
203
204 if (port->open_count == 1) {
205
206 /* set up our port structure making the tty driver
207 * remember our port object, and us it */
208 tty->driver_data = port;
209 port->tty = tty;
210
211 /* lock this module before we call it
212 * this may fail, which means we must bail out,
213 * safe because we are called with BKL held */
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700214 if (!try_module_get(serial->type->driver.owner)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 retval = -ENODEV;
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300216 goto bailout_mutex_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 }
218
219 /* only call the device specific open if this
220 * is the first time the port is opened */
221 retval = serial->type->open(port, filp);
222 if (retval)
223 goto bailout_module_put;
224 }
225
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300226 mutex_unlock(&port->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 return 0;
228
229bailout_module_put:
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700230 module_put(serial->type->driver.owner);
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300231bailout_mutex_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 port->open_count = 0;
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300233 mutex_unlock(&port->mutex);
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300234bailout_kref_put:
Luiz Fernando Capitulino704936a2006-05-11 22:34:17 -0300235 kref_put(&serial->kref, destroy_serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 return retval;
237}
238
239static void serial_close(struct tty_struct *tty, struct file * filp)
240{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200241 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243 if (!port)
244 return;
245
246 dbg("%s - port %d", __FUNCTION__, port->number);
247
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300248 mutex_lock(&port->mutex);
Luiz Fernando Capitulino8a4613f2005-11-28 19:16:07 -0200249
Greg Kroah-Hartman91c0bce2006-03-06 13:25:52 -0800250 if (port->open_count == 0) {
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300251 mutex_unlock(&port->mutex);
Greg Kroah-Hartman91c0bce2006-03-06 13:25:52 -0800252 return;
253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255 --port->open_count;
256 if (port->open_count == 0) {
257 /* only call the device specific close if this
258 * port is being closed by the last owner */
259 port->serial->type->close(port, filp);
260
261 if (port->tty) {
262 if (port->tty->driver_data)
263 port->tty->driver_data = NULL;
264 port->tty = NULL;
265 }
266
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700267 module_put(port->serial->type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 }
269
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300270 mutex_unlock(&port->mutex);
Greg Kroah-Hartman91c0bce2006-03-06 13:25:52 -0800271 kref_put(&port->serial->kref, destroy_serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272}
273
274static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
275{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200276 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 int retval = -EINVAL;
278
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200279 if (!port)
280 goto exit;
281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
283
284 if (!port->open_count) {
285 dbg("%s - port not opened", __FUNCTION__);
286 goto exit;
287 }
288
289 /* pass on to the driver specific version of this function */
290 retval = port->serial->type->write(port, buf, count);
291
292exit:
293 return retval;
294}
295
296static int serial_write_room (struct tty_struct *tty)
297{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200298 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 int retval = -EINVAL;
300
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200301 if (!port)
302 goto exit;
303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 dbg("%s - port %d", __FUNCTION__, port->number);
305
306 if (!port->open_count) {
307 dbg("%s - port not open", __FUNCTION__);
308 goto exit;
309 }
310
311 /* pass on to the driver specific version of this function */
312 retval = port->serial->type->write_room(port);
313
314exit:
315 return retval;
316}
317
318static int serial_chars_in_buffer (struct tty_struct *tty)
319{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200320 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 int retval = -EINVAL;
322
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200323 if (!port)
324 goto exit;
325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 dbg("%s = port %d", __FUNCTION__, port->number);
327
328 if (!port->open_count) {
329 dbg("%s - port not open", __FUNCTION__);
330 goto exit;
331 }
332
333 /* pass on to the driver specific version of this function */
334 retval = port->serial->type->chars_in_buffer(port);
335
336exit:
337 return retval;
338}
339
340static void serial_throttle (struct tty_struct * tty)
341{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200342 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200344 if (!port)
345 return;
346
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 dbg("%s - port %d", __FUNCTION__, port->number);
348
349 if (!port->open_count) {
350 dbg ("%s - port not open", __FUNCTION__);
351 return;
352 }
353
354 /* pass on to the driver specific version of this function */
355 if (port->serial->type->throttle)
356 port->serial->type->throttle(port);
357}
358
359static void serial_unthrottle (struct tty_struct * tty)
360{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200361 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200363 if (!port)
364 return;
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 dbg("%s - port %d", __FUNCTION__, port->number);
367
368 if (!port->open_count) {
369 dbg("%s - port not open", __FUNCTION__);
370 return;
371 }
372
373 /* pass on to the driver specific version of this function */
374 if (port->serial->type->unthrottle)
375 port->serial->type->unthrottle(port);
376}
377
378static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
379{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200380 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 int retval = -ENODEV;
382
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200383 if (!port)
384 goto exit;
385
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
387
388 if (!port->open_count) {
389 dbg ("%s - port not open", __FUNCTION__);
390 goto exit;
391 }
392
393 /* pass on to the driver specific version of this function if it is available */
394 if (port->serial->type->ioctl)
395 retval = port->serial->type->ioctl(port, file, cmd, arg);
396 else
397 retval = -ENOIOCTLCMD;
398
399exit:
400 return retval;
401}
402
403static void serial_set_termios (struct tty_struct *tty, struct termios * old)
404{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200405 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200407 if (!port)
408 return;
409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 dbg("%s - port %d", __FUNCTION__, port->number);
411
412 if (!port->open_count) {
413 dbg("%s - port not open", __FUNCTION__);
414 return;
415 }
416
417 /* pass on to the driver specific version of this function if it is available */
418 if (port->serial->type->set_termios)
419 port->serial->type->set_termios(port, old);
420}
421
422static void serial_break (struct tty_struct *tty, int break_state)
423{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200424 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200426 if (!port)
427 return;
428
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 dbg("%s - port %d", __FUNCTION__, port->number);
430
431 if (!port->open_count) {
432 dbg("%s - port not open", __FUNCTION__);
433 return;
434 }
435
436 /* pass on to the driver specific version of this function if it is available */
437 if (port->serial->type->break_ctl)
438 port->serial->type->break_ctl(port, break_state);
439}
440
441static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
442{
443 struct usb_serial *serial;
444 int length = 0;
445 int i;
446 off_t begin = 0;
447 char tmp[40];
448
449 dbg("%s", __FUNCTION__);
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -0700450 length += sprintf (page, "usbserinfo:1.0 driver:2.0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
452 serial = usb_serial_get_by_index(i);
453 if (serial == NULL)
454 continue;
455
456 length += sprintf (page+length, "%d:", i);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700457 if (serial->type->driver.owner)
458 length += sprintf (page+length, " module:%s", module_name(serial->type->driver.owner));
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -0700459 length += sprintf (page+length, " name:\"%s\"", serial->type->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 length += sprintf (page+length, " vendor:%04x product:%04x",
461 le16_to_cpu(serial->dev->descriptor.idVendor),
462 le16_to_cpu(serial->dev->descriptor.idProduct));
463 length += sprintf (page+length, " num_ports:%d", serial->num_ports);
464 length += sprintf (page+length, " port:%d", i - serial->minor + 1);
465
466 usb_make_path(serial->dev, tmp, sizeof(tmp));
467 length += sprintf (page+length, " path:%s", tmp);
468
469 length += sprintf (page+length, "\n");
470 if ((length + begin) > (off + count))
471 goto done;
472 if ((length + begin) < off) {
473 begin += length;
474 length = 0;
475 }
476 kref_put(&serial->kref, destroy_serial);
477 }
478 *eof = 1;
479done:
480 if (off >= (length + begin))
481 return 0;
482 *start = page + (off-begin);
483 return ((count < begin+length-off) ? count : begin+length-off);
484}
485
486static int serial_tiocmget (struct tty_struct *tty, struct file *file)
487{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200488 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200490 if (!port)
491 goto exit;
492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 dbg("%s - port %d", __FUNCTION__, port->number);
494
495 if (!port->open_count) {
496 dbg("%s - port not open", __FUNCTION__);
497 goto exit;
498 }
499
500 if (port->serial->type->tiocmget)
501 return port->serial->type->tiocmget(port, file);
502
503exit:
504 return -EINVAL;
505}
506
507static int serial_tiocmset (struct tty_struct *tty, struct file *file,
508 unsigned int set, unsigned int clear)
509{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200510 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200512 if (!port)
513 goto exit;
514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 dbg("%s - port %d", __FUNCTION__, port->number);
516
517 if (!port->open_count) {
518 dbg("%s - port not open", __FUNCTION__);
519 goto exit;
520 }
521
522 if (port->serial->type->tiocmset)
523 return port->serial->type->tiocmset(port, file, set, clear);
524
525exit:
526 return -EINVAL;
527}
528
529void usb_serial_port_softint(void *private)
530{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200531 struct usb_serial_port *port = private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 struct tty_struct *tty;
533
534 dbg("%s - port %d", __FUNCTION__, port->number);
535
536 if (!port)
537 return;
538
539 tty = port->tty;
540 if (!tty)
541 return;
542
543 tty_wakeup(tty);
544}
545
546static void port_release(struct device *dev)
547{
548 struct usb_serial_port *port = to_usb_serial_port(dev);
549
550 dbg ("%s - %s", __FUNCTION__, dev->bus_id);
551 usb_kill_urb(port->read_urb);
552 usb_free_urb(port->read_urb);
553 usb_kill_urb(port->write_urb);
554 usb_free_urb(port->write_urb);
555 usb_kill_urb(port->interrupt_in_urb);
556 usb_free_urb(port->interrupt_in_urb);
557 usb_kill_urb(port->interrupt_out_urb);
558 usb_free_urb(port->interrupt_out_urb);
559 kfree(port->bulk_in_buffer);
560 kfree(port->bulk_out_buffer);
561 kfree(port->interrupt_in_buffer);
562 kfree(port->interrupt_out_buffer);
563 kfree(port);
564}
565
566static struct usb_serial * create_serial (struct usb_device *dev,
567 struct usb_interface *interface,
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700568 struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
570 struct usb_serial *serial;
571
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100572 serial = kzalloc(sizeof(*serial), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 if (!serial) {
574 dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
575 return NULL;
576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 serial->dev = usb_get_dev(dev);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700578 serial->type = driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 serial->interface = interface;
580 kref_init(&serial->kref);
581
582 return serial;
583}
584
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700585static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586{
587 struct list_head *p;
588 const struct usb_device_id *id;
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700589 struct usb_serial_driver *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Adrian Bunk93b1fae2006-01-10 00:13:33 +0100591 /* Check if the usb id matches a known device */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 list_for_each(p, &usb_serial_driver_list) {
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700593 t = list_entry(p, struct usb_serial_driver, driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 id = usb_match_id(iface, t->id_table);
595 if (id != NULL) {
596 dbg("descriptor matches");
597 return t;
598 }
599 }
600
601 return NULL;
602}
603
604int usb_serial_probe(struct usb_interface *interface,
605 const struct usb_device_id *id)
606{
607 struct usb_device *dev = interface_to_usbdev (interface);
608 struct usb_serial *serial = NULL;
609 struct usb_serial_port *port;
610 struct usb_host_interface *iface_desc;
611 struct usb_endpoint_descriptor *endpoint;
612 struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
613 struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
614 struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
615 struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700616 struct usb_serial_driver *type = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 int retval;
618 int minor;
619 int buffer_size;
620 int i;
621 int num_interrupt_in = 0;
622 int num_interrupt_out = 0;
623 int num_bulk_in = 0;
624 int num_bulk_out = 0;
625 int num_ports = 0;
626 int max_endpoints;
627
628 type = search_serial_device(interface);
629 if (!type) {
630 dbg("none matched");
631 return -ENODEV;
632 }
633
634 serial = create_serial (dev, interface, type);
635 if (!serial) {
636 dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
637 return -ENOMEM;
638 }
639
640 /* if this device type has a probe function, call it */
641 if (type->probe) {
642 const struct usb_device_id *id;
643
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700644 if (!try_module_get(type->driver.owner)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 dev_err(&interface->dev, "module get failed, exiting\n");
646 kfree (serial);
647 return -EIO;
648 }
649
650 id = usb_match_id(interface, type->id_table);
651 retval = type->probe(serial, id);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700652 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 if (retval) {
655 dbg ("sub driver rejected device");
656 kfree (serial);
657 return retval;
658 }
659 }
660
661 /* descriptor matches, let's find the endpoints needed */
662 /* check out the endpoints */
663 iface_desc = interface->cur_altsetting;
664 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
665 endpoint = &iface_desc->endpoint[i].desc;
666
667 if ((endpoint->bEndpointAddress & 0x80) &&
668 ((endpoint->bmAttributes & 3) == 0x02)) {
669 /* we found a bulk in endpoint */
670 dbg("found bulk in on endpoint %d", i);
671 bulk_in_endpoint[num_bulk_in] = endpoint;
672 ++num_bulk_in;
673 }
674
675 if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
676 ((endpoint->bmAttributes & 3) == 0x02)) {
677 /* we found a bulk out endpoint */
678 dbg("found bulk out on endpoint %d", i);
679 bulk_out_endpoint[num_bulk_out] = endpoint;
680 ++num_bulk_out;
681 }
682
683 if ((endpoint->bEndpointAddress & 0x80) &&
684 ((endpoint->bmAttributes & 3) == 0x03)) {
685 /* we found a interrupt in endpoint */
686 dbg("found interrupt in on endpoint %d", i);
687 interrupt_in_endpoint[num_interrupt_in] = endpoint;
688 ++num_interrupt_in;
689 }
690
691 if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
692 ((endpoint->bmAttributes & 3) == 0x03)) {
693 /* we found an interrupt out endpoint */
694 dbg("found interrupt out on endpoint %d", i);
695 interrupt_out_endpoint[num_interrupt_out] = endpoint;
696 ++num_interrupt_out;
697 }
698 }
699
700#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
701 /* BEGIN HORRIBLE HACK FOR PL2303 */
702 /* this is needed due to the looney way its endpoints are set up */
703 if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
704 (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
705 ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
706 (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID))) {
707 if (interface != dev->actconfig->interface[0]) {
708 /* check out the endpoints of the other interface*/
709 iface_desc = dev->actconfig->interface[0]->cur_altsetting;
710 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
711 endpoint = &iface_desc->endpoint[i].desc;
712 if ((endpoint->bEndpointAddress & 0x80) &&
713 ((endpoint->bmAttributes & 3) == 0x03)) {
714 /* we found a interrupt in endpoint */
715 dbg("found interrupt in for Prolific device on separate interface");
716 interrupt_in_endpoint[num_interrupt_in] = endpoint;
717 ++num_interrupt_in;
718 }
719 }
720 }
721
722 /* Now make sure the PL-2303 is configured correctly.
723 * If not, give up now and hope this hack will work
724 * properly during a later invocation of usb_serial_probe
725 */
726 if (num_bulk_in == 0 || num_bulk_out == 0) {
727 dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
728 kfree (serial);
729 return -ENODEV;
730 }
731 }
732 /* END HORRIBLE HACK FOR PL2303 */
733#endif
734
735 /* found all that we need */
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -0700736 dev_info(&interface->dev, "%s converter detected\n", type->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738#ifdef CONFIG_USB_SERIAL_GENERIC
739 if (type == &usb_serial_generic_device) {
740 num_ports = num_bulk_out;
741 if (num_ports == 0) {
742 dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
743 kfree (serial);
744 return -EIO;
745 }
746 }
747#endif
748 if (!num_ports) {
749 /* if this device type has a calc_num_ports function, call it */
750 if (type->calc_num_ports) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700751 if (!try_module_get(type->driver.owner)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 dev_err(&interface->dev, "module get failed, exiting\n");
753 kfree (serial);
754 return -EIO;
755 }
756 num_ports = type->calc_num_ports (serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700757 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 }
759 if (!num_ports)
760 num_ports = type->num_ports;
761 }
762
763 if (get_free_serial (serial, num_ports, &minor) == NULL) {
764 dev_err(&interface->dev, "No more free serial devices\n");
765 kfree (serial);
766 return -ENOMEM;
767 }
768
769 serial->minor = minor;
770 serial->num_ports = num_ports;
771 serial->num_bulk_in = num_bulk_in;
772 serial->num_bulk_out = num_bulk_out;
773 serial->num_interrupt_in = num_interrupt_in;
774 serial->num_interrupt_out = num_interrupt_out;
775
776 /* create our ports, we need as many as the max endpoints */
777 /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
778 max_endpoints = max(num_bulk_in, num_bulk_out);
779 max_endpoints = max(max_endpoints, num_interrupt_in);
780 max_endpoints = max(max_endpoints, num_interrupt_out);
781 max_endpoints = max(max_endpoints, (int)serial->num_ports);
782 serial->num_port_pointers = max_endpoints;
783 dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
784 for (i = 0; i < max_endpoints; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100785 port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 if (!port)
787 goto probe_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 port->number = i + serial->minor;
789 port->serial = serial;
Greg Kroah-Hartman507ca9b2005-04-23 12:49:16 -0700790 spin_lock_init(&port->lock);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300791 mutex_init(&port->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 INIT_WORK(&port->work, usb_serial_port_softint, port);
793 serial->port[i] = port;
794 }
795
796 /* set up the endpoint information */
797 for (i = 0; i < num_bulk_in; ++i) {
798 endpoint = bulk_in_endpoint[i];
799 port = serial->port[i];
800 port->read_urb = usb_alloc_urb (0, GFP_KERNEL);
801 if (!port->read_urb) {
802 dev_err(&interface->dev, "No free urbs available\n");
803 goto probe_error;
804 }
805 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
806 port->bulk_in_size = buffer_size;
807 port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
808 port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
809 if (!port->bulk_in_buffer) {
810 dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer\n");
811 goto probe_error;
812 }
813 usb_fill_bulk_urb (port->read_urb, dev,
814 usb_rcvbulkpipe (dev,
815 endpoint->bEndpointAddress),
816 port->bulk_in_buffer, buffer_size,
817 serial->type->read_bulk_callback,
818 port);
819 }
820
821 for (i = 0; i < num_bulk_out; ++i) {
822 endpoint = bulk_out_endpoint[i];
823 port = serial->port[i];
824 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
825 if (!port->write_urb) {
826 dev_err(&interface->dev, "No free urbs available\n");
827 goto probe_error;
828 }
829 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
830 port->bulk_out_size = buffer_size;
831 port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
832 port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
833 if (!port->bulk_out_buffer) {
834 dev_err(&interface->dev, "Couldn't allocate bulk_out_buffer\n");
835 goto probe_error;
836 }
837 usb_fill_bulk_urb (port->write_urb, dev,
838 usb_sndbulkpipe (dev,
839 endpoint->bEndpointAddress),
840 port->bulk_out_buffer, buffer_size,
841 serial->type->write_bulk_callback,
842 port);
843 }
844
845 if (serial->type->read_int_callback) {
846 for (i = 0; i < num_interrupt_in; ++i) {
847 endpoint = interrupt_in_endpoint[i];
848 port = serial->port[i];
849 port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
850 if (!port->interrupt_in_urb) {
851 dev_err(&interface->dev, "No free urbs available\n");
852 goto probe_error;
853 }
854 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
855 port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
856 port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
857 if (!port->interrupt_in_buffer) {
858 dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");
859 goto probe_error;
860 }
861 usb_fill_int_urb (port->interrupt_in_urb, dev,
862 usb_rcvintpipe (dev,
863 endpoint->bEndpointAddress),
864 port->interrupt_in_buffer, buffer_size,
865 serial->type->read_int_callback, port,
866 endpoint->bInterval);
867 }
868 } else if (num_interrupt_in) {
869 dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
870 }
871
872 if (serial->type->write_int_callback) {
873 for (i = 0; i < num_interrupt_out; ++i) {
874 endpoint = interrupt_out_endpoint[i];
875 port = serial->port[i];
876 port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
877 if (!port->interrupt_out_urb) {
878 dev_err(&interface->dev, "No free urbs available\n");
879 goto probe_error;
880 }
881 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
882 port->interrupt_out_size = buffer_size;
883 port->interrupt_out_endpointAddress = endpoint->bEndpointAddress;
884 port->interrupt_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
885 if (!port->interrupt_out_buffer) {
886 dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n");
887 goto probe_error;
888 }
889 usb_fill_int_urb (port->interrupt_out_urb, dev,
890 usb_sndintpipe (dev,
891 endpoint->bEndpointAddress),
892 port->interrupt_out_buffer, buffer_size,
893 serial->type->write_int_callback, port,
894 endpoint->bInterval);
895 }
896 } else if (num_interrupt_out) {
897 dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
898 }
899
900 /* if this device type has an attach function, call it */
901 if (type->attach) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700902 if (!try_module_get(type->driver.owner)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 dev_err(&interface->dev, "module get failed, exiting\n");
904 goto probe_error;
905 }
906 retval = type->attach (serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700907 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (retval < 0)
909 goto probe_error;
910 if (retval > 0) {
911 /* quietly accept this device, but don't bind to a serial port
912 * as it's about to disappear */
913 goto exit;
914 }
915 }
916
917 /* register all of the individual ports with the driver core */
918 for (i = 0; i < num_ports; ++i) {
919 port = serial->port[i];
920 port->dev.parent = &interface->dev;
921 port->dev.driver = NULL;
922 port->dev.bus = &usb_serial_bus_type;
923 port->dev.release = &port_release;
924
925 snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
926 dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);
927 device_register (&port->dev);
928 }
929
930 usb_serial_console_init (debug, minor);
931
932exit:
933 /* success */
934 usb_set_intfdata (interface, serial);
935 return 0;
936
937probe_error:
938 for (i = 0; i < num_bulk_in; ++i) {
939 port = serial->port[i];
940 if (!port)
941 continue;
942 if (port->read_urb)
943 usb_free_urb (port->read_urb);
944 kfree(port->bulk_in_buffer);
945 }
946 for (i = 0; i < num_bulk_out; ++i) {
947 port = serial->port[i];
948 if (!port)
949 continue;
950 if (port->write_urb)
951 usb_free_urb (port->write_urb);
952 kfree(port->bulk_out_buffer);
953 }
954 for (i = 0; i < num_interrupt_in; ++i) {
955 port = serial->port[i];
956 if (!port)
957 continue;
958 if (port->interrupt_in_urb)
959 usb_free_urb (port->interrupt_in_urb);
960 kfree(port->interrupt_in_buffer);
961 }
962 for (i = 0; i < num_interrupt_out; ++i) {
963 port = serial->port[i];
964 if (!port)
965 continue;
966 if (port->interrupt_out_urb)
967 usb_free_urb (port->interrupt_out_urb);
968 kfree(port->interrupt_out_buffer);
969 }
970
971 /* return the minor range that this device had */
972 return_serial (serial);
973
974 /* free up any memory that we allocated */
975 for (i = 0; i < serial->num_port_pointers; ++i)
976 kfree(serial->port[i]);
977 kfree (serial);
978 return -EIO;
979}
980
981void usb_serial_disconnect(struct usb_interface *interface)
982{
983 int i;
984 struct usb_serial *serial = usb_get_intfdata (interface);
985 struct device *dev = &interface->dev;
986 struct usb_serial_port *port;
987
988 dbg ("%s", __FUNCTION__);
989
990 usb_set_intfdata (interface, NULL);
991 if (serial) {
992 for (i = 0; i < serial->num_ports; ++i) {
993 port = serial->port[i];
994 if (port && port->tty)
995 tty_hangup(port->tty);
996 }
997 /* let the last holder of this object
998 * cause it to be cleaned up */
999 kref_put(&serial->kref, destroy_serial);
1000 }
1001 dev_info(dev, "device disconnected\n");
1002}
1003
1004static struct tty_operations serial_ops = {
1005 .open = serial_open,
1006 .close = serial_close,
1007 .write = serial_write,
1008 .write_room = serial_write_room,
1009 .ioctl = serial_ioctl,
1010 .set_termios = serial_set_termios,
1011 .throttle = serial_throttle,
1012 .unthrottle = serial_unthrottle,
1013 .break_ctl = serial_break,
1014 .chars_in_buffer = serial_chars_in_buffer,
1015 .read_proc = serial_read_proc,
1016 .tiocmget = serial_tiocmget,
1017 .tiocmset = serial_tiocmset,
1018};
1019
1020struct tty_driver *usb_serial_tty_driver;
1021
1022static int __init usb_serial_init(void)
1023{
1024 int i;
1025 int result;
1026
1027 usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
1028 if (!usb_serial_tty_driver)
1029 return -ENOMEM;
1030
1031 /* Initialize our global data */
1032 for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
1033 serial_table[i] = NULL;
1034 }
1035
1036 result = bus_register(&usb_serial_bus_type);
1037 if (result) {
1038 err("%s - registering bus driver failed", __FUNCTION__);
1039 goto exit_bus;
1040 }
1041
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 usb_serial_tty_driver->owner = THIS_MODULE;
1043 usb_serial_tty_driver->driver_name = "usbserial";
1044 usb_serial_tty_driver->devfs_name = "usb/tts/";
1045 usb_serial_tty_driver->name = "ttyUSB";
1046 usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
1047 usb_serial_tty_driver->minor_start = 0;
1048 usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
1049 usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
1050 usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
1051 usb_serial_tty_driver->init_termios = tty_std_termios;
1052 usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1053 tty_set_operations(usb_serial_tty_driver, &serial_ops);
1054 result = tty_register_driver(usb_serial_tty_driver);
1055 if (result) {
1056 err("%s - tty_register_driver failed", __FUNCTION__);
1057 goto exit_reg_driver;
1058 }
1059
1060 /* register the USB driver */
1061 result = usb_register(&usb_serial_driver);
1062 if (result < 0) {
1063 err("%s - usb_register failed", __FUNCTION__);
1064 goto exit_tty;
1065 }
1066
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001067 /* register the generic driver, if we should */
1068 result = usb_serial_generic_register(debug);
1069 if (result < 0) {
1070 err("%s - registering generic driver failed", __FUNCTION__);
1071 goto exit_generic;
1072 }
1073
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001074 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
1076 return result;
1077
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001078exit_generic:
1079 usb_deregister(&usb_serial_driver);
1080
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081exit_tty:
1082 tty_unregister_driver(usb_serial_tty_driver);
1083
1084exit_reg_driver:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 bus_unregister(&usb_serial_bus_type);
1086
1087exit_bus:
1088 err ("%s - returning with error %d", __FUNCTION__, result);
1089 put_tty_driver(usb_serial_tty_driver);
1090 return result;
1091}
1092
1093
1094static void __exit usb_serial_exit(void)
1095{
1096 usb_serial_console_exit();
1097
1098 usb_serial_generic_deregister();
1099
1100 usb_deregister(&usb_serial_driver);
1101 tty_unregister_driver(usb_serial_tty_driver);
1102 put_tty_driver(usb_serial_tty_driver);
1103 bus_unregister(&usb_serial_bus_type);
1104}
1105
1106
1107module_init(usb_serial_init);
1108module_exit(usb_serial_exit);
1109
1110#define set_to_generic_if_null(type, function) \
1111 do { \
1112 if (!type->function) { \
1113 type->function = usb_serial_generic_##function; \
1114 dbg("Had to override the " #function \
1115 " usb serial operation with the generic one.");\
1116 } \
1117 } while (0)
1118
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001119static void fixup_generic(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120{
1121 set_to_generic_if_null(device, open);
1122 set_to_generic_if_null(device, write);
1123 set_to_generic_if_null(device, close);
1124 set_to_generic_if_null(device, write_room);
1125 set_to_generic_if_null(device, chars_in_buffer);
1126 set_to_generic_if_null(device, read_bulk_callback);
1127 set_to_generic_if_null(device, write_bulk_callback);
1128 set_to_generic_if_null(device, shutdown);
1129}
1130
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001131int usb_serial_register(struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132{
1133 int retval;
1134
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001135 fixup_generic(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001137 if (!driver->description)
1138 driver->description = driver->driver.name;
1139
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 /* Add this device to our list of devices */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001141 list_add(&driver->driver_list, &usb_serial_driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001143 retval = usb_serial_bus_register(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 if (retval) {
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001145 err("problem %d when registering driver %s", retval, driver->description);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001146 list_del(&driver->driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148 else
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001149 info("USB Serial support registered for %s", driver->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151 return retval;
1152}
1153
1154
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001155void usb_serial_deregister(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156{
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001157 info("USB Serial deregistering driver %s", device->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 list_del(&device->driver_list);
1159 usb_serial_bus_deregister(device);
1160}
1161
1162
1163
1164/* If the usb-serial core is built into the core, the usb-serial drivers
1165 need these symbols to load properly as modules. */
1166EXPORT_SYMBOL_GPL(usb_serial_register);
1167EXPORT_SYMBOL_GPL(usb_serial_deregister);
1168EXPORT_SYMBOL_GPL(usb_serial_probe);
1169EXPORT_SYMBOL_GPL(usb_serial_disconnect);
1170EXPORT_SYMBOL_GPL(usb_serial_port_softint);
1171
1172
1173/* Module information */
1174MODULE_AUTHOR( DRIVER_AUTHOR );
1175MODULE_DESCRIPTION( DRIVER_DESC );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176MODULE_LICENSE("GPL");
1177
1178module_param(debug, bool, S_IRUGO | S_IWUSR);
1179MODULE_PARM_DESC(debug, "Debug enabled or not");