blob: aea861e9173e89f7742ce2d2076a70ff6a3e4126 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/init.h>
22#include <linux/slab.h>
23#include <linux/tty.h>
24#include <linux/tty_driver.h>
25#include <linux/tty_flip.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/spinlock.h>
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -030029#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <asm/uaccess.h>
32#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070033#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include "pl2303.h"
35
36/*
37 * Version Information
38 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
40#define DRIVER_DESC "USB Serial Driver core"
41
Pete Zaitcev34f8e762006-06-21 15:00:45 -070042static void port_free(struct usb_serial_port *port);
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044/* 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,
Oliver Neukumec225592007-04-27 20:54:57 +020049 .suspend = usb_serial_suspend,
50 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -080051 .no_dynamic_id = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -070052};
53
54/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
55 the MODULE_DEVICE_TABLE declarations in each serial driver
56 cause the "hotplug" program to pull in whatever module is necessary
57 via modprobe, and modprobe will load usbserial because the serial
58 drivers depend on it.
59*/
60
61static int debug;
62static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
Oliver Neukum3ddad822007-07-24 15:13:42 +020063static DEFINE_MUTEX(table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064static LIST_HEAD(usb_serial_driver_list);
65
66struct usb_serial *usb_serial_get_by_index(unsigned index)
67{
Oliver Neukum34ef50e2007-01-13 07:29:26 +010068 struct usb_serial *serial;
69
Oliver Neukum3ddad822007-07-24 15:13:42 +020070 mutex_lock(&table_lock);
Oliver Neukum34ef50e2007-01-13 07:29:26 +010071 serial = serial_table[index];
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73 if (serial)
74 kref_get(&serial->kref);
Oliver Neukum3ddad822007-07-24 15:13:42 +020075 mutex_unlock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 return serial;
77}
78
79static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor)
80{
81 unsigned int i, j;
82 int good_spot;
83
84 dbg("%s %d", __FUNCTION__, num_ports);
85
86 *minor = 0;
Oliver Neukum3ddad822007-07-24 15:13:42 +020087 mutex_lock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
89 if (serial_table[i])
90 continue;
91
92 good_spot = 1;
93 for (j = 1; j <= num_ports-1; ++j)
94 if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) {
95 good_spot = 0;
96 i += j;
97 break;
98 }
99 if (good_spot == 0)
100 continue;
101
102 *minor = i;
Oliver Neukuma1f721c2007-03-05 15:23:51 +0100103 j = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 dbg("%s - minor base = %d", __FUNCTION__, *minor);
Oliver Neukuma1f721c2007-03-05 15:23:51 +0100105 for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 serial_table[i] = serial;
Oliver Neukuma1f721c2007-03-05 15:23:51 +0100107 serial->port[j++]->number = i;
108 }
Oliver Neukum3ddad822007-07-24 15:13:42 +0200109 mutex_unlock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 return serial;
111 }
Oliver Neukum3ddad822007-07-24 15:13:42 +0200112 mutex_unlock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 return NULL;
114}
115
116static void return_serial(struct usb_serial *serial)
117{
118 int i;
119
120 dbg("%s", __FUNCTION__);
121
122 if (serial == NULL)
123 return;
124
125 for (i = 0; i < serial->num_ports; ++i) {
126 serial_table[serial->minor + i] = NULL;
127 }
128}
129
130static void destroy_serial(struct kref *kref)
131{
132 struct usb_serial *serial;
133 struct usb_serial_port *port;
134 int i;
135
136 serial = to_usb_serial(kref);
137
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -0700138 dbg("%s - %s", __FUNCTION__, serial->type->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Jim Radford521b85a2007-03-13 08:30:50 -0700140 serial->type->shutdown(serial);
141
142 /* return the minor range that this device had */
143 return_serial(serial);
144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 for (i = 0; i < serial->num_ports; ++i)
146 serial->port[i]->open_count = 0;
147
148 /* the ports are cleaned up and released in port_release() */
149 for (i = 0; i < serial->num_ports; ++i)
150 if (serial->port[i]->dev.parent != NULL) {
151 device_unregister(&serial->port[i]->dev);
152 serial->port[i] = NULL;
153 }
154
155 /* If this is a "fake" port, we have to clean it up here, as it will
156 * not get cleaned up in port_release() as it was never registered with
157 * the driver core */
158 if (serial->num_ports < serial->num_port_pointers) {
159 for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
160 port = serial->port[i];
161 if (!port)
162 continue;
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700163 port_free(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 }
165 }
166
167 usb_put_dev(serial->dev);
168
169 /* free up any memory that we allocated */
170 kfree (serial);
171}
172
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200173void usb_serial_put(struct usb_serial *serial)
174{
Oliver Neukum3ddad822007-07-24 15:13:42 +0200175 mutex_lock(&table_lock);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200176 kref_put(&serial->kref, destroy_serial);
Oliver Neukum3ddad822007-07-24 15:13:42 +0200177 mutex_unlock(&table_lock);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200178}
179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180/*****************************************************************************
181 * Driver tty interface functions
182 *****************************************************************************/
183static int serial_open (struct tty_struct *tty, struct file * filp)
184{
185 struct usb_serial *serial;
186 struct usb_serial_port *port;
187 unsigned int portNumber;
188 int retval;
189
190 dbg("%s", __FUNCTION__);
191
192 /* get the serial object associated with this tty pointer */
193 serial = usb_serial_get_by_index(tty->index);
194 if (!serial) {
195 tty->driver_data = NULL;
196 return -ENODEV;
197 }
198
199 portNumber = tty->index - serial->minor;
200 port = serial->port[portNumber];
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300201 if (!port) {
202 retval = -ENODEV;
203 goto bailout_kref_put;
204 }
Luiz Fernando Capitulino8a4613f2005-11-28 19:16:07 -0200205
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300206 if (mutex_lock_interruptible(&port->mutex)) {
207 retval = -ERESTARTSYS;
208 goto bailout_kref_put;
209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
211 ++port->open_count;
212
Paul Fulghumca854852006-04-13 22:28:17 +0200213 /* set up our port structure making the tty driver
214 * remember our port object, and us it */
215 tty->driver_data = port;
216 port->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Paul Fulghumca854852006-04-13 22:28:17 +0200218 if (port->open_count == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220 /* lock this module before we call it
221 * this may fail, which means we must bail out,
222 * safe because we are called with BKL held */
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700223 if (!try_module_get(serial->type->driver.owner)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 retval = -ENODEV;
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300225 goto bailout_mutex_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 }
227
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800228 retval = usb_autopm_get_interface(serial->interface);
229 if (retval)
230 goto bailout_module_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 /* only call the device specific open if this
232 * is the first time the port is opened */
233 retval = serial->type->open(port, filp);
234 if (retval)
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800235 goto bailout_interface_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 }
237
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300238 mutex_unlock(&port->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 return 0;
240
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800241bailout_interface_put:
242 usb_autopm_put_interface(serial->interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243bailout_module_put:
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700244 module_put(serial->type->driver.owner);
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300245bailout_mutex_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 port->open_count = 0;
Frank Gevaertsb059c812006-06-14 15:52:05 +0200247 tty->driver_data = NULL;
248 port->tty = NULL;
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300249 mutex_unlock(&port->mutex);
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300250bailout_kref_put:
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200251 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 return retval;
253}
254
255static void serial_close(struct tty_struct *tty, struct file * filp)
256{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200257 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
259 if (!port)
260 return;
261
262 dbg("%s - port %d", __FUNCTION__, port->number);
263
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300264 mutex_lock(&port->mutex);
Luiz Fernando Capitulino8a4613f2005-11-28 19:16:07 -0200265
Greg Kroah-Hartman91c0bce2006-03-06 13:25:52 -0800266 if (port->open_count == 0) {
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300267 mutex_unlock(&port->mutex);
Greg Kroah-Hartman91c0bce2006-03-06 13:25:52 -0800268 return;
269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
271 --port->open_count;
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500272 if (port->open_count == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 /* only call the device specific close if this
274 * port is being closed by the last owner */
275 port->serial->type->close(port, filp);
276
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500277 if (port->open_count == (port->console? 1 : 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 if (port->tty) {
279 if (port->tty->driver_data)
280 port->tty->driver_data = NULL;
281 port->tty = NULL;
282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 }
284
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800285 if (port->open_count == 0) {
286 usb_autopm_put_interface(port->serial->interface);
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500287 module_put(port->serial->type->driver.owner);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800288 }
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500289
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300290 mutex_unlock(&port->mutex);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200291 usb_serial_put(port->serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292}
293
294static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
295{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200296 struct usb_serial_port *port = tty->driver_data;
Oliver Neukum3ff4fd92007-01-13 07:32:27 +0100297 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200299 if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200300 goto exit;
301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
303
304 if (!port->open_count) {
Oliver Neukum3ff4fd92007-01-13 07:32:27 +0100305 retval = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 dbg("%s - port not opened", __FUNCTION__);
307 goto exit;
308 }
309
310 /* pass on to the driver specific version of this function */
311 retval = port->serial->type->write(port, buf, count);
312
313exit:
314 return retval;
315}
316
317static int serial_write_room (struct tty_struct *tty)
318{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200319 struct usb_serial_port *port = tty->driver_data;
Luiz Fernando N. Capitulinodb54a532006-06-12 22:46:20 -0300320 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200322 if (!port)
323 goto exit;
324
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 dbg("%s - port %d", __FUNCTION__, port->number);
326
327 if (!port->open_count) {
328 dbg("%s - port not open", __FUNCTION__);
329 goto exit;
330 }
331
332 /* pass on to the driver specific version of this function */
333 retval = port->serial->type->write_room(port);
334
335exit:
336 return retval;
337}
338
339static int serial_chars_in_buffer (struct tty_struct *tty)
340{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200341 struct usb_serial_port *port = tty->driver_data;
Luiz Fernando N. Capitulinodb54a532006-06-12 22:46:20 -0300342 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200344 if (!port)
345 goto exit;
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 goto exit;
352 }
353
354 /* pass on to the driver specific version of this function */
355 retval = port->serial->type->chars_in_buffer(port);
356
357exit:
358 return retval;
359}
360
361static void serial_throttle (struct tty_struct * tty)
362{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200363 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200365 if (!port)
366 return;
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 dbg("%s - port %d", __FUNCTION__, port->number);
369
370 if (!port->open_count) {
371 dbg ("%s - port not open", __FUNCTION__);
372 return;
373 }
374
375 /* pass on to the driver specific version of this function */
376 if (port->serial->type->throttle)
377 port->serial->type->throttle(port);
378}
379
380static void serial_unthrottle (struct tty_struct * tty)
381{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200382 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200384 if (!port)
385 return;
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 dbg("%s - port %d", __FUNCTION__, port->number);
388
389 if (!port->open_count) {
390 dbg("%s - port not open", __FUNCTION__);
391 return;
392 }
393
394 /* pass on to the driver specific version of this function */
395 if (port->serial->type->unthrottle)
396 port->serial->type->unthrottle(port);
397}
398
399static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
400{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200401 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 int retval = -ENODEV;
403
Alan Cox20978902008-02-20 20:47:56 +0000404 lock_kernel();
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200405 if (!port)
406 goto exit;
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
409
Alan Cox20978902008-02-20 20:47:56 +0000410 /* Caution - port->open_count is BKL protected */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 if (!port->open_count) {
412 dbg ("%s - port not open", __FUNCTION__);
413 goto exit;
414 }
415
416 /* pass on to the driver specific version of this function if it is available */
417 if (port->serial->type->ioctl)
418 retval = port->serial->type->ioctl(port, file, cmd, arg);
419 else
420 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421exit:
Alan Cox20978902008-02-20 20:47:56 +0000422 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 return retval;
424}
425
Alan Cox606d0992006-12-08 02:38:45 -0800426static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200428 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200430 if (!port)
431 return;
432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 dbg("%s - port %d", __FUNCTION__, port->number);
434
435 if (!port->open_count) {
436 dbg("%s - port not open", __FUNCTION__);
437 return;
438 }
439
440 /* pass on to the driver specific version of this function if it is available */
441 if (port->serial->type->set_termios)
442 port->serial->type->set_termios(port, old);
Alan Cox33785092007-10-18 01:24:22 -0700443 else
444 tty_termios_copy_hw(tty->termios, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
446
447static void serial_break (struct tty_struct *tty, int break_state)
448{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200449 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Alan Cox20978902008-02-20 20:47:56 +0000451 lock_kernel();
452 if (!port) {
453 unlock_kernel();
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200454 return;
Alan Cox20978902008-02-20 20:47:56 +0000455 }
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200456
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 dbg("%s - port %d", __FUNCTION__, port->number);
458
459 if (!port->open_count) {
460 dbg("%s - port not open", __FUNCTION__);
Alan Cox20978902008-02-20 20:47:56 +0000461 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 return;
463 }
464
465 /* pass on to the driver specific version of this function if it is available */
466 if (port->serial->type->break_ctl)
467 port->serial->type->break_ctl(port, break_state);
Alan Cox20978902008-02-20 20:47:56 +0000468 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469}
470
471static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
472{
473 struct usb_serial *serial;
474 int length = 0;
475 int i;
476 off_t begin = 0;
477 char tmp[40];
478
479 dbg("%s", __FUNCTION__);
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -0700480 length += sprintf (page, "usbserinfo:1.0 driver:2.0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
482 serial = usb_serial_get_by_index(i);
483 if (serial == NULL)
484 continue;
485
486 length += sprintf (page+length, "%d:", i);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700487 if (serial->type->driver.owner)
488 length += sprintf (page+length, " module:%s", module_name(serial->type->driver.owner));
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -0700489 length += sprintf (page+length, " name:\"%s\"", serial->type->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 length += sprintf (page+length, " vendor:%04x product:%04x",
491 le16_to_cpu(serial->dev->descriptor.idVendor),
492 le16_to_cpu(serial->dev->descriptor.idProduct));
493 length += sprintf (page+length, " num_ports:%d", serial->num_ports);
494 length += sprintf (page+length, " port:%d", i - serial->minor + 1);
495
496 usb_make_path(serial->dev, tmp, sizeof(tmp));
497 length += sprintf (page+length, " path:%s", tmp);
498
499 length += sprintf (page+length, "\n");
Matthias Urlichs59925832006-09-11 12:35:20 +0200500 if ((length + begin) > (off + count)) {
501 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 goto done;
Matthias Urlichs59925832006-09-11 12:35:20 +0200503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 if ((length + begin) < off) {
505 begin += length;
506 length = 0;
507 }
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200508 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 }
510 *eof = 1;
511done:
512 if (off >= (length + begin))
513 return 0;
514 *start = page + (off-begin);
515 return ((count < begin+length-off) ? count : begin+length-off);
516}
517
518static int serial_tiocmget (struct tty_struct *tty, struct file *file)
519{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200520 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200522 if (!port)
Luiz Fernando N. Capitulinodb54a532006-06-12 22:46:20 -0300523 return -ENODEV;
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 dbg("%s - port %d", __FUNCTION__, port->number);
526
527 if (!port->open_count) {
528 dbg("%s - port not open", __FUNCTION__);
Luiz Fernando N. Capitulinodb54a532006-06-12 22:46:20 -0300529 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 }
531
532 if (port->serial->type->tiocmget)
533 return port->serial->type->tiocmget(port, file);
534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return -EINVAL;
536}
537
538static int serial_tiocmset (struct tty_struct *tty, struct file *file,
539 unsigned int set, unsigned int clear)
540{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200541 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200543 if (!port)
Luiz Fernando N. Capitulinodb54a532006-06-12 22:46:20 -0300544 return -ENODEV;
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200545
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 dbg("%s - port %d", __FUNCTION__, port->number);
547
548 if (!port->open_count) {
549 dbg("%s - port not open", __FUNCTION__);
Luiz Fernando N. Capitulinodb54a532006-06-12 22:46:20 -0300550 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 }
552
553 if (port->serial->type->tiocmset)
554 return port->serial->type->tiocmset(port, file, set, clear);
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 return -EINVAL;
557}
558
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700559/*
560 * We would be calling tty_wakeup here, but unfortunately some line
561 * disciplines have an annoying habit of calling tty->write from
562 * the write wakeup callback (e.g. n_hdlc.c).
563 */
564void usb_serial_port_softint(struct usb_serial_port *port)
565{
566 schedule_work(&port->work);
567}
568
David Howellsc4028952006-11-22 14:57:56 +0000569static void usb_serial_port_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
David Howellsc4028952006-11-22 14:57:56 +0000571 struct usb_serial_port *port =
572 container_of(work, struct usb_serial_port, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 struct tty_struct *tty;
574
575 dbg("%s - port %d", __FUNCTION__, port->number);
576
577 if (!port)
578 return;
579
580 tty = port->tty;
581 if (!tty)
582 return;
583
584 tty_wakeup(tty);
585}
586
587static void port_release(struct device *dev)
588{
589 struct usb_serial_port *port = to_usb_serial_port(dev);
590
591 dbg ("%s - %s", __FUNCTION__, dev->bus_id);
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700592 port_free(port);
593}
594
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100595static void kill_traffic(struct usb_serial_port *port)
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700596{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 usb_kill_urb(port->write_urb);
Oliver Neukum5adceac2007-08-17 14:01:38 +0200599 /*
600 * This is tricky.
601 * Some drivers submit the read_urb in the
602 * handler for the write_urb or vice versa
603 * this order determines the order in which
604 * usb_kill_urb() must be used to reliably
605 * kill the URBs. As it is unknown here,
606 * both orders must be used in turn.
607 * The call below is not redundant.
608 */
609 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 usb_kill_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 usb_kill_urb(port->interrupt_out_urb);
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100612}
613
614static void port_free(struct usb_serial_port *port)
615{
616 kill_traffic(port);
617 usb_free_urb(port->read_urb);
618 usb_free_urb(port->write_urb);
619 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 usb_free_urb(port->interrupt_out_urb);
621 kfree(port->bulk_in_buffer);
622 kfree(port->bulk_out_buffer);
623 kfree(port->interrupt_in_buffer);
624 kfree(port->interrupt_out_buffer);
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700625 flush_scheduled_work(); /* port->work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 kfree(port);
627}
628
629static struct usb_serial * create_serial (struct usb_device *dev,
630 struct usb_interface *interface,
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700631 struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632{
633 struct usb_serial *serial;
634
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100635 serial = kzalloc(sizeof(*serial), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 if (!serial) {
637 dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
638 return NULL;
639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 serial->dev = usb_get_dev(dev);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700641 serial->type = driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 serial->interface = interface;
643 kref_init(&serial->kref);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +0100644 mutex_init(&serial->disc_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
646 return serial;
647}
648
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100649static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
650 struct usb_serial_driver *drv)
651{
652 struct usb_dynid *dynid;
653
654 spin_lock(&drv->dynids.lock);
655 list_for_each_entry(dynid, &drv->dynids.list, node) {
656 if (usb_match_one_id(intf, &dynid->id)) {
657 spin_unlock(&drv->dynids.lock);
658 return &dynid->id;
659 }
660 }
661 spin_unlock(&drv->dynids.lock);
662 return NULL;
663}
664
665static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
666 struct usb_interface *intf)
667{
668 const struct usb_device_id *id;
669
670 id = usb_match_id(intf, drv->id_table);
671 if (id) {
672 dbg("static descriptor matches");
673 goto exit;
674 }
675 id = match_dynamic_id(intf, drv);
676 if (id)
677 dbg("dynamic descriptor matches");
678exit:
679 return id;
680}
681
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700682static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 const struct usb_device_id *id;
Alan Stern063a2da2007-10-10 16:24:06 -0400685 struct usb_serial_driver *drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Adrian Bunk93b1fae2006-01-10 00:13:33 +0100687 /* Check if the usb id matches a known device */
Alan Stern063a2da2007-10-10 16:24:06 -0400688 list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
689 id = get_iface_id(drv, iface);
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100690 if (id)
Alan Stern063a2da2007-10-10 16:24:06 -0400691 return drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 }
693
694 return NULL;
695}
696
697int usb_serial_probe(struct usb_interface *interface,
698 const struct usb_device_id *id)
699{
700 struct usb_device *dev = interface_to_usbdev (interface);
701 struct usb_serial *serial = NULL;
702 struct usb_serial_port *port;
703 struct usb_host_interface *iface_desc;
704 struct usb_endpoint_descriptor *endpoint;
705 struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
706 struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
707 struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
708 struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700709 struct usb_serial_driver *type = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 int retval;
711 int minor;
712 int buffer_size;
713 int i;
714 int num_interrupt_in = 0;
715 int num_interrupt_out = 0;
716 int num_bulk_in = 0;
717 int num_bulk_out = 0;
718 int num_ports = 0;
719 int max_endpoints;
720
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100721 lock_kernel(); /* guard against unloading a serial driver module */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 type = search_serial_device(interface);
723 if (!type) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100724 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 dbg("none matched");
726 return -ENODEV;
727 }
728
729 serial = create_serial (dev, interface, type);
730 if (!serial) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100731 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
733 return -ENOMEM;
734 }
735
736 /* if this device type has a probe function, call it */
737 if (type->probe) {
738 const struct usb_device_id *id;
739
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700740 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100741 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 dev_err(&interface->dev, "module get failed, exiting\n");
743 kfree (serial);
744 return -EIO;
745 }
746
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100747 id = get_iface_id(type, interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 retval = type->probe(serial, id);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700749 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751 if (retval) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100752 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 dbg ("sub driver rejected device");
754 kfree (serial);
755 return retval;
756 }
757 }
758
759 /* descriptor matches, let's find the endpoints needed */
760 /* check out the endpoints */
761 iface_desc = interface->cur_altsetting;
762 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
763 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700764
765 if (usb_endpoint_is_bulk_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 /* we found a bulk in endpoint */
767 dbg("found bulk in on endpoint %d", i);
768 bulk_in_endpoint[num_bulk_in] = endpoint;
769 ++num_bulk_in;
770 }
771
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700772 if (usb_endpoint_is_bulk_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 /* we found a bulk out endpoint */
774 dbg("found bulk out on endpoint %d", i);
775 bulk_out_endpoint[num_bulk_out] = endpoint;
776 ++num_bulk_out;
777 }
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700778
779 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 /* we found a interrupt in endpoint */
781 dbg("found interrupt in on endpoint %d", i);
782 interrupt_in_endpoint[num_interrupt_in] = endpoint;
783 ++num_interrupt_in;
784 }
785
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700786 if (usb_endpoint_is_int_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 /* we found an interrupt out endpoint */
788 dbg("found interrupt out on endpoint %d", i);
789 interrupt_out_endpoint[num_interrupt_out] = endpoint;
790 ++num_interrupt_out;
791 }
792 }
793
794#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
795 /* BEGIN HORRIBLE HACK FOR PL2303 */
796 /* this is needed due to the looney way its endpoints are set up */
797 if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
798 (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
799 ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
Johannes Steingraeber8fd80132006-09-16 16:17:34 +0200800 (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
801 ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
802 (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (interface != dev->actconfig->interface[0]) {
804 /* check out the endpoints of the other interface*/
805 iface_desc = dev->actconfig->interface[0]->cur_altsetting;
806 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
807 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700808 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 /* we found a interrupt in endpoint */
810 dbg("found interrupt in for Prolific device on separate interface");
811 interrupt_in_endpoint[num_interrupt_in] = endpoint;
812 ++num_interrupt_in;
813 }
814 }
815 }
816
817 /* Now make sure the PL-2303 is configured correctly.
818 * If not, give up now and hope this hack will work
819 * properly during a later invocation of usb_serial_probe
820 */
821 if (num_bulk_in == 0 || num_bulk_out == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100822 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
824 kfree (serial);
825 return -ENODEV;
826 }
827 }
828 /* END HORRIBLE HACK FOR PL2303 */
829#endif
830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831#ifdef CONFIG_USB_SERIAL_GENERIC
832 if (type == &usb_serial_generic_device) {
833 num_ports = num_bulk_out;
834 if (num_ports == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100835 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
837 kfree (serial);
838 return -EIO;
839 }
840 }
841#endif
842 if (!num_ports) {
843 /* if this device type has a calc_num_ports function, call it */
844 if (type->calc_num_ports) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700845 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100846 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 dev_err(&interface->dev, "module get failed, exiting\n");
848 kfree (serial);
849 return -EIO;
850 }
851 num_ports = type->calc_num_ports (serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700852 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
854 if (!num_ports)
855 num_ports = type->num_ports;
856 }
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 serial->num_ports = num_ports;
859 serial->num_bulk_in = num_bulk_in;
860 serial->num_bulk_out = num_bulk_out;
861 serial->num_interrupt_in = num_interrupt_in;
862 serial->num_interrupt_out = num_interrupt_out;
863
Greg Kroah-Hartman07c3b1a2008-04-14 14:17:29 -0700864#if 0
Alan Stern063a2da2007-10-10 16:24:06 -0400865 /* check that the device meets the driver's requirements */
866 if ((type->num_interrupt_in != NUM_DONT_CARE &&
867 type->num_interrupt_in != num_interrupt_in)
868 || (type->num_interrupt_out != NUM_DONT_CARE &&
869 type->num_interrupt_out != num_interrupt_out)
870 || (type->num_bulk_in != NUM_DONT_CARE &&
871 type->num_bulk_in != num_bulk_in)
872 || (type->num_bulk_out != NUM_DONT_CARE &&
873 type->num_bulk_out != num_bulk_out)) {
874 dbg("wrong number of endpoints");
875 kfree(serial);
876 return -EIO;
877 }
Greg Kroah-Hartman07c3b1a2008-04-14 14:17:29 -0700878#endif
Alan Stern063a2da2007-10-10 16:24:06 -0400879
880 /* found all that we need */
881 dev_info(&interface->dev, "%s converter detected\n",
882 type->description);
883
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 /* create our ports, we need as many as the max endpoints */
885 /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
886 max_endpoints = max(num_bulk_in, num_bulk_out);
887 max_endpoints = max(max_endpoints, num_interrupt_in);
888 max_endpoints = max(max_endpoints, num_interrupt_out);
889 max_endpoints = max(max_endpoints, (int)serial->num_ports);
890 serial->num_port_pointers = max_endpoints;
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100891 unlock_kernel();
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
894 for (i = 0; i < max_endpoints; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100895 port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 if (!port)
897 goto probe_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 port->serial = serial;
Greg Kroah-Hartman507ca9b2005-04-23 12:49:16 -0700899 spin_lock_init(&port->lock);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300900 mutex_init(&port->mutex);
David Howellsc4028952006-11-22 14:57:56 +0000901 INIT_WORK(&port->work, usb_serial_port_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 serial->port[i] = port;
903 }
904
905 /* set up the endpoint information */
906 for (i = 0; i < num_bulk_in; ++i) {
907 endpoint = bulk_in_endpoint[i];
908 port = serial->port[i];
909 port->read_urb = usb_alloc_urb (0, GFP_KERNEL);
910 if (!port->read_urb) {
911 dev_err(&interface->dev, "No free urbs available\n");
912 goto probe_error;
913 }
914 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
915 port->bulk_in_size = buffer_size;
916 port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
917 port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
918 if (!port->bulk_in_buffer) {
919 dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer\n");
920 goto probe_error;
921 }
922 usb_fill_bulk_urb (port->read_urb, dev,
923 usb_rcvbulkpipe (dev,
924 endpoint->bEndpointAddress),
925 port->bulk_in_buffer, buffer_size,
926 serial->type->read_bulk_callback,
927 port);
928 }
929
930 for (i = 0; i < num_bulk_out; ++i) {
931 endpoint = bulk_out_endpoint[i];
932 port = serial->port[i];
933 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
934 if (!port->write_urb) {
935 dev_err(&interface->dev, "No free urbs available\n");
936 goto probe_error;
937 }
938 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
939 port->bulk_out_size = buffer_size;
940 port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
941 port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
942 if (!port->bulk_out_buffer) {
943 dev_err(&interface->dev, "Couldn't allocate bulk_out_buffer\n");
944 goto probe_error;
945 }
946 usb_fill_bulk_urb (port->write_urb, dev,
947 usb_sndbulkpipe (dev,
948 endpoint->bEndpointAddress),
949 port->bulk_out_buffer, buffer_size,
950 serial->type->write_bulk_callback,
951 port);
952 }
953
954 if (serial->type->read_int_callback) {
955 for (i = 0; i < num_interrupt_in; ++i) {
956 endpoint = interrupt_in_endpoint[i];
957 port = serial->port[i];
958 port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
959 if (!port->interrupt_in_urb) {
960 dev_err(&interface->dev, "No free urbs available\n");
961 goto probe_error;
962 }
963 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
964 port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
965 port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
966 if (!port->interrupt_in_buffer) {
967 dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");
968 goto probe_error;
969 }
970 usb_fill_int_urb (port->interrupt_in_urb, dev,
971 usb_rcvintpipe (dev,
972 endpoint->bEndpointAddress),
973 port->interrupt_in_buffer, buffer_size,
974 serial->type->read_int_callback, port,
975 endpoint->bInterval);
976 }
977 } else if (num_interrupt_in) {
978 dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
979 }
980
981 if (serial->type->write_int_callback) {
982 for (i = 0; i < num_interrupt_out; ++i) {
983 endpoint = interrupt_out_endpoint[i];
984 port = serial->port[i];
985 port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
986 if (!port->interrupt_out_urb) {
987 dev_err(&interface->dev, "No free urbs available\n");
988 goto probe_error;
989 }
990 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
991 port->interrupt_out_size = buffer_size;
992 port->interrupt_out_endpointAddress = endpoint->bEndpointAddress;
993 port->interrupt_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
994 if (!port->interrupt_out_buffer) {
995 dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n");
996 goto probe_error;
997 }
998 usb_fill_int_urb (port->interrupt_out_urb, dev,
999 usb_sndintpipe (dev,
1000 endpoint->bEndpointAddress),
1001 port->interrupt_out_buffer, buffer_size,
1002 serial->type->write_int_callback, port,
1003 endpoint->bInterval);
1004 }
1005 } else if (num_interrupt_out) {
1006 dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
1007 }
1008
1009 /* if this device type has an attach function, call it */
1010 if (type->attach) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -07001011 if (!try_module_get(type->driver.owner)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 dev_err(&interface->dev, "module get failed, exiting\n");
1013 goto probe_error;
1014 }
1015 retval = type->attach (serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -07001016 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (retval < 0)
1018 goto probe_error;
1019 if (retval > 0) {
1020 /* quietly accept this device, but don't bind to a serial port
1021 * as it's about to disappear */
1022 goto exit;
1023 }
1024 }
1025
Oliver Neukum34ef50e2007-01-13 07:29:26 +01001026 if (get_free_serial (serial, num_ports, &minor) == NULL) {
1027 dev_err(&interface->dev, "No more free serial devices\n");
1028 goto probe_error;
1029 }
Oliver Neukumc744f992007-02-26 15:43:00 +01001030 serial->minor = minor;
Oliver Neukum34ef50e2007-01-13 07:29:26 +01001031
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 /* register all of the individual ports with the driver core */
1033 for (i = 0; i < num_ports; ++i) {
1034 port = serial->port[i];
1035 port->dev.parent = &interface->dev;
1036 port->dev.driver = NULL;
1037 port->dev.bus = &usb_serial_bus_type;
1038 port->dev.release = &port_release;
1039
1040 snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
1041 dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -07001042 retval = device_register(&port->dev);
1043 if (retval)
1044 dev_err(&port->dev, "Error registering port device, "
1045 "continuing\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
1047
1048 usb_serial_console_init (debug, minor);
1049
1050exit:
1051 /* success */
1052 usb_set_intfdata (interface, serial);
1053 return 0;
1054
1055probe_error:
1056 for (i = 0; i < num_bulk_in; ++i) {
1057 port = serial->port[i];
1058 if (!port)
1059 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001060 usb_free_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 kfree(port->bulk_in_buffer);
1062 }
1063 for (i = 0; i < num_bulk_out; ++i) {
1064 port = serial->port[i];
1065 if (!port)
1066 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001067 usb_free_urb(port->write_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 kfree(port->bulk_out_buffer);
1069 }
1070 for (i = 0; i < num_interrupt_in; ++i) {
1071 port = serial->port[i];
1072 if (!port)
1073 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001074 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 kfree(port->interrupt_in_buffer);
1076 }
1077 for (i = 0; i < num_interrupt_out; ++i) {
1078 port = serial->port[i];
1079 if (!port)
1080 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001081 usb_free_urb(port->interrupt_out_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 kfree(port->interrupt_out_buffer);
1083 }
1084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 /* free up any memory that we allocated */
1086 for (i = 0; i < serial->num_port_pointers; ++i)
1087 kfree(serial->port[i]);
1088 kfree (serial);
1089 return -EIO;
1090}
1091
1092void usb_serial_disconnect(struct usb_interface *interface)
1093{
1094 int i;
1095 struct usb_serial *serial = usb_get_intfdata (interface);
1096 struct device *dev = &interface->dev;
1097 struct usb_serial_port *port;
1098
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +02001099 usb_serial_console_disconnect(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 dbg ("%s", __FUNCTION__);
1101
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001102 mutex_lock(&serial->disc_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 usb_set_intfdata (interface, NULL);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001104 /* must set a flag, to signal subdrivers */
1105 serial->disconnected = 1;
1106 for (i = 0; i < serial->num_ports; ++i) {
1107 port = serial->port[i];
1108 if (port) {
1109 if (port->tty)
1110 tty_hangup(port->tty);
1111 kill_traffic(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001114 /* let the last holder of this object
1115 * cause it to be cleaned up */
1116 mutex_unlock(&serial->disc_mutex);
1117 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 dev_info(dev, "device disconnected\n");
1119}
1120
Oliver Neukumec225592007-04-27 20:54:57 +02001121int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1122{
1123 struct usb_serial *serial = usb_get_intfdata(intf);
1124 struct usb_serial_port *port;
1125 int i, r = 0;
1126
Oliver Neukume31c1882007-07-23 08:58:39 +02001127 for (i = 0; i < serial->num_ports; ++i) {
1128 port = serial->port[i];
1129 if (port)
1130 kill_traffic(port);
Oliver Neukumec225592007-04-27 20:54:57 +02001131 }
1132
1133 if (serial->type->suspend)
Oliver Neukume31c1882007-07-23 08:58:39 +02001134 r = serial->type->suspend(serial, message);
Oliver Neukumec225592007-04-27 20:54:57 +02001135
1136 return r;
1137}
1138EXPORT_SYMBOL(usb_serial_suspend);
1139
1140int usb_serial_resume(struct usb_interface *intf)
1141{
1142 struct usb_serial *serial = usb_get_intfdata(intf);
1143
Sarah Sharp8abaee22007-10-25 10:58:43 -07001144 if (serial->type->resume)
1145 return serial->type->resume(serial);
1146 return 0;
Oliver Neukumec225592007-04-27 20:54:57 +02001147}
1148EXPORT_SYMBOL(usb_serial_resume);
1149
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001150static const struct tty_operations serial_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 .open = serial_open,
1152 .close = serial_close,
1153 .write = serial_write,
1154 .write_room = serial_write_room,
1155 .ioctl = serial_ioctl,
1156 .set_termios = serial_set_termios,
1157 .throttle = serial_throttle,
1158 .unthrottle = serial_unthrottle,
1159 .break_ctl = serial_break,
1160 .chars_in_buffer = serial_chars_in_buffer,
1161 .read_proc = serial_read_proc,
1162 .tiocmget = serial_tiocmget,
1163 .tiocmset = serial_tiocmset,
1164};
1165
1166struct tty_driver *usb_serial_tty_driver;
1167
1168static int __init usb_serial_init(void)
1169{
1170 int i;
1171 int result;
1172
1173 usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
1174 if (!usb_serial_tty_driver)
1175 return -ENOMEM;
1176
1177 /* Initialize our global data */
1178 for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
1179 serial_table[i] = NULL;
1180 }
1181
1182 result = bus_register(&usb_serial_bus_type);
1183 if (result) {
1184 err("%s - registering bus driver failed", __FUNCTION__);
1185 goto exit_bus;
1186 }
1187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 usb_serial_tty_driver->owner = THIS_MODULE;
1189 usb_serial_tty_driver->driver_name = "usbserial";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 usb_serial_tty_driver->name = "ttyUSB";
1191 usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
1192 usb_serial_tty_driver->minor_start = 0;
1193 usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
1194 usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07001195 usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 usb_serial_tty_driver->init_termios = tty_std_termios;
1197 usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1198 tty_set_operations(usb_serial_tty_driver, &serial_ops);
1199 result = tty_register_driver(usb_serial_tty_driver);
1200 if (result) {
1201 err("%s - tty_register_driver failed", __FUNCTION__);
1202 goto exit_reg_driver;
1203 }
1204
1205 /* register the USB driver */
1206 result = usb_register(&usb_serial_driver);
1207 if (result < 0) {
1208 err("%s - usb_register failed", __FUNCTION__);
1209 goto exit_tty;
1210 }
1211
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001212 /* register the generic driver, if we should */
1213 result = usb_serial_generic_register(debug);
1214 if (result < 0) {
1215 err("%s - registering generic driver failed", __FUNCTION__);
1216 goto exit_generic;
1217 }
1218
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001219 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221 return result;
1222
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001223exit_generic:
1224 usb_deregister(&usb_serial_driver);
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226exit_tty:
1227 tty_unregister_driver(usb_serial_tty_driver);
1228
1229exit_reg_driver:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 bus_unregister(&usb_serial_bus_type);
1231
1232exit_bus:
1233 err ("%s - returning with error %d", __FUNCTION__, result);
1234 put_tty_driver(usb_serial_tty_driver);
1235 return result;
1236}
1237
1238
1239static void __exit usb_serial_exit(void)
1240{
1241 usb_serial_console_exit();
1242
1243 usb_serial_generic_deregister();
1244
1245 usb_deregister(&usb_serial_driver);
1246 tty_unregister_driver(usb_serial_tty_driver);
1247 put_tty_driver(usb_serial_tty_driver);
1248 bus_unregister(&usb_serial_bus_type);
1249}
1250
1251
1252module_init(usb_serial_init);
1253module_exit(usb_serial_exit);
1254
1255#define set_to_generic_if_null(type, function) \
1256 do { \
1257 if (!type->function) { \
1258 type->function = usb_serial_generic_##function; \
1259 dbg("Had to override the " #function \
1260 " usb serial operation with the generic one.");\
1261 } \
1262 } while (0)
1263
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001264static void fixup_generic(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265{
1266 set_to_generic_if_null(device, open);
1267 set_to_generic_if_null(device, write);
1268 set_to_generic_if_null(device, close);
1269 set_to_generic_if_null(device, write_room);
1270 set_to_generic_if_null(device, chars_in_buffer);
1271 set_to_generic_if_null(device, read_bulk_callback);
1272 set_to_generic_if_null(device, write_bulk_callback);
1273 set_to_generic_if_null(device, shutdown);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -08001274 set_to_generic_if_null(device, resume);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275}
1276
Oliver Neukum4b10f0f2007-01-13 07:31:27 +01001277int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278{
1279 int retval;
1280
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001281 fixup_generic(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001283 if (!driver->description)
1284 driver->description = driver->driver.name;
1285
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 /* Add this device to our list of devices */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001287 list_add(&driver->driver_list, &usb_serial_driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001289 retval = usb_serial_bus_register(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 if (retval) {
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001291 err("problem %d when registering driver %s", retval, driver->description);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001292 list_del(&driver->driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 }
1294 else
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001295 info("USB Serial support registered for %s", driver->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
1297 return retval;
1298}
1299
1300
Oliver Neukum4b10f0f2007-01-13 07:31:27 +01001301void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001303 info("USB Serial deregistering driver %s", device->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 list_del(&device->driver_list);
1305 usb_serial_bus_deregister(device);
1306}
1307
1308
1309
1310/* If the usb-serial core is built into the core, the usb-serial drivers
1311 need these symbols to load properly as modules. */
1312EXPORT_SYMBOL_GPL(usb_serial_register);
1313EXPORT_SYMBOL_GPL(usb_serial_deregister);
1314EXPORT_SYMBOL_GPL(usb_serial_probe);
1315EXPORT_SYMBOL_GPL(usb_serial_disconnect);
1316EXPORT_SYMBOL_GPL(usb_serial_port_softint);
1317
1318
1319/* Module information */
1320MODULE_AUTHOR( DRIVER_AUTHOR );
1321MODULE_DESCRIPTION( DRIVER_DESC );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322MODULE_LICENSE("GPL");
1323
1324module_param(debug, bool, S_IRUGO | S_IWUSR);
1325MODULE_PARM_DESC(debug, "Debug enabled or not");