blob: d595aa5586a733003532e6f0a7a95e051e3ce659 [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 *
Alan Coxa8d6f0a2008-07-22 11:12:24 +010015 * See Documentation/usb/usb-serial.txt for more information on using this
16 * driver
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 */
19
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#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>
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -070029#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/spinlock.h>
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -030031#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/list.h>
Alan Coxa8d6f0a2008-07-22 11:12:24 +010033#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070035#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#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
Pete Zaitcev34f8e762006-06-21 15:00:45 -070044static void port_free(struct usb_serial_port *port);
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046/* Driver structure we register with the USB core */
47static struct usb_driver usb_serial_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 .name = "usbserial",
49 .probe = usb_serial_probe,
50 .disconnect = usb_serial_disconnect,
Oliver Neukumec225592007-04-27 20:54:57 +020051 .suspend = usb_serial_suspend,
52 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -080053 .no_dynamic_id = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -070054};
55
56/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
57 the MODULE_DEVICE_TABLE declarations in each serial driver
58 cause the "hotplug" program to pull in whatever module is necessary
59 via modprobe, and modprobe will load usbserial because the serial
60 drivers depend on it.
61*/
62
63static int debug;
Alan Coxa8d6f0a2008-07-22 11:12:24 +010064/* initially all NULL */
65static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
Oliver Neukum3ddad822007-07-24 15:13:42 +020066static DEFINE_MUTEX(table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static LIST_HEAD(usb_serial_driver_list);
68
69struct usb_serial *usb_serial_get_by_index(unsigned index)
70{
Oliver Neukum34ef50e2007-01-13 07:29:26 +010071 struct usb_serial *serial;
72
Oliver Neukum3ddad822007-07-24 15:13:42 +020073 mutex_lock(&table_lock);
Oliver Neukum34ef50e2007-01-13 07:29:26 +010074 serial = serial_table[index];
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
76 if (serial)
77 kref_get(&serial->kref);
Oliver Neukum3ddad822007-07-24 15:13:42 +020078 mutex_unlock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 return serial;
80}
81
Alan Coxa8d6f0a2008-07-22 11:12:24 +010082static struct usb_serial *get_free_serial(struct usb_serial *serial,
83 int num_ports, unsigned int *minor)
Linus Torvalds1da177e2005-04-16 15:20:36 -070084{
85 unsigned int i, j;
86 int good_spot;
87
Harvey Harrison441b62c2008-03-03 16:08:34 -080088 dbg("%s %d", __func__, num_ports);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 *minor = 0;
Oliver Neukum3ddad822007-07-24 15:13:42 +020091 mutex_lock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
93 if (serial_table[i])
94 continue;
95
96 good_spot = 1;
97 for (j = 1; j <= num_ports-1; ++j)
98 if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) {
99 good_spot = 0;
100 i += j;
101 break;
102 }
103 if (good_spot == 0)
104 continue;
105
106 *minor = i;
Oliver Neukuma1f721c2007-03-05 15:23:51 +0100107 j = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800108 dbg("%s - minor base = %d", __func__, *minor);
Oliver Neukuma1f721c2007-03-05 15:23:51 +0100109 for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 serial_table[i] = serial;
Oliver Neukuma1f721c2007-03-05 15:23:51 +0100111 serial->port[j++]->number = i;
112 }
Oliver Neukum3ddad822007-07-24 15:13:42 +0200113 mutex_unlock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 return serial;
115 }
Oliver Neukum3ddad822007-07-24 15:13:42 +0200116 mutex_unlock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 return NULL;
118}
119
120static void return_serial(struct usb_serial *serial)
121{
122 int i;
123
Harvey Harrison441b62c2008-03-03 16:08:34 -0800124 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100126 for (i = 0; i < serial->num_ports; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 serial_table[serial->minor + i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128}
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
Harvey Harrison441b62c2008-03-03 16:08:34 -0800138 dbg("%s - %s", __func__, serial->type->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Jim Radford521b85a2007-03-13 08:30:50 -0700140 /* return the minor range that this device had */
Alan Stern0282b7f2008-07-29 12:01:04 -0400141 if (serial->minor != SERIAL_TTY_NO_MINOR)
142 return_serial(serial);
Jim Radford521b85a2007-03-13 08:30:50 -0700143
Alan Sternf9c99bb2009-06-02 11:53:55 -0400144 serial->type->release(serial);
145
146 for (i = 0; i < serial->num_ports; ++i) {
147 port = serial->port[i];
148 if (port)
149 put_device(&port->dev);
150 }
151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 /* If this is a "fake" port, we have to clean it up here, as it will
153 * not get cleaned up in port_release() as it was never registered with
154 * the driver core */
155 if (serial->num_ports < serial->num_port_pointers) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100156 for (i = serial->num_ports;
157 i < serial->num_port_pointers; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 port = serial->port[i];
Alan Sternf9c99bb2009-06-02 11:53:55 -0400159 if (port)
160 port_free(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 }
162 }
163
164 usb_put_dev(serial->dev);
165
166 /* free up any memory that we allocated */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100167 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200170void usb_serial_put(struct usb_serial *serial)
171{
Oliver Neukum3ddad822007-07-24 15:13:42 +0200172 mutex_lock(&table_lock);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200173 kref_put(&serial->kref, destroy_serial);
Oliver Neukum3ddad822007-07-24 15:13:42 +0200174 mutex_unlock(&table_lock);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200175}
176
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177/*****************************************************************************
178 * Driver tty interface functions
179 *****************************************************************************/
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100180static int serial_open (struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181{
182 struct usb_serial *serial;
183 struct usb_serial_port *port;
184 unsigned int portNumber;
Alan Stern2d931482009-04-14 11:31:02 -0400185 int retval = 0;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100186
Harvey Harrison441b62c2008-03-03 16:08:34 -0800187 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
189 /* get the serial object associated with this tty pointer */
190 serial = usb_serial_get_by_index(tty->index);
191 if (!serial) {
192 tty->driver_data = NULL;
193 return -ENODEV;
194 }
195
Alan Stern2d931482009-04-14 11:31:02 -0400196 mutex_lock(&serial->disc_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 portNumber = tty->index - serial->minor;
198 port = serial->port[portNumber];
Alan Stern2d931482009-04-14 11:31:02 -0400199 if (!port || serial->disconnected)
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300200 retval = -ENODEV;
Alan Stern2d931482009-04-14 11:31:02 -0400201 else
202 get_device(&port->dev);
203 /*
204 * Note: Our locking order requirement does not allow port->mutex
205 * to be acquired while serial->disc_mutex is held.
206 */
207 mutex_unlock(&serial->disc_mutex);
208 if (retval)
209 goto bailout_serial_put;
James Woodcock331879f2009-02-11 15:06:53 +0000210
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300211 if (mutex_lock_interruptible(&port->mutex)) {
212 retval = -ERESTARTSYS;
Alan Stern2d931482009-04-14 11:31:02 -0400213 goto bailout_port_put;
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300214 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100215
Alan Cox95da3102008-07-22 11:09:07 +0100216 ++port->port.count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Paul Fulghumca854852006-04-13 22:28:17 +0200218 /* set up our port structure making the tty driver
219 * remember our port object, and us it */
220 tty->driver_data = port;
Alan Cox4a90f092008-10-13 10:39:46 +0100221 tty_port_tty_set(&port->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
Alan Cox95da3102008-07-22 11:09:07 +0100223 if (port->port.count == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
225 /* lock this module before we call it
226 * this may fail, which means we must bail out,
227 * safe because we are called with BKL held */
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700228 if (!try_module_get(serial->type->driver.owner)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 retval = -ENODEV;
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300230 goto bailout_mutex_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 }
232
Alan Stern2d931482009-04-14 11:31:02 -0400233 mutex_lock(&serial->disc_mutex);
234 if (serial->disconnected)
235 retval = -ENODEV;
236 else
237 retval = usb_autopm_get_interface(serial->interface);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800238 if (retval)
239 goto bailout_module_put;
Alan Stern2d931482009-04-14 11:31:02 -0400240
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100241 /* only call the device specific open if this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 * is the first time the port is opened */
Alan Cox95da3102008-07-22 11:09:07 +0100243 retval = serial->type->open(tty, port, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 if (retval)
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800245 goto bailout_interface_put;
Alan Stern2d931482009-04-14 11:31:02 -0400246 mutex_unlock(&serial->disc_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 }
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300248 mutex_unlock(&port->mutex);
Alan Cox335f8512009-06-11 12:26:29 +0100249 /* Now do the correct tty layer semantics */
250 retval = tty_port_block_til_ready(&port->port, tty, filp);
251 if (retval == 0)
252 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800254bailout_interface_put:
255 usb_autopm_put_interface(serial->interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256bailout_module_put:
Alan Stern2d931482009-04-14 11:31:02 -0400257 mutex_unlock(&serial->disc_mutex);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700258 module_put(serial->type->driver.owner);
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300259bailout_mutex_unlock:
Alan Cox95da3102008-07-22 11:09:07 +0100260 port->port.count = 0;
Frank Gevaertsb059c812006-06-14 15:52:05 +0200261 tty->driver_data = NULL;
Alan Cox4a90f092008-10-13 10:39:46 +0100262 tty_port_tty_set(&port->port, NULL);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300263 mutex_unlock(&port->mutex);
Alan Stern2d931482009-04-14 11:31:02 -0400264bailout_port_put:
265 put_device(&port->dev);
266bailout_serial_put:
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200267 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 return retval;
269}
270
Alan Cox335f8512009-06-11 12:26:29 +0100271/**
272 * serial_do_down - shut down hardware
273 * @port: port to shut down
274 *
275 * Shut down a USB port unless it is the console. We never shut down the
276 * console hardware as it will always be in use.
277 *
278 * Don't free any resources at this point
279 */
280static void serial_do_down(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
Alan Cox335f8512009-06-11 12:26:29 +0100282 struct usb_serial_driver *drv = port->serial->type;
Alan Stern2d931482009-04-14 11:31:02 -0400283 struct usb_serial *serial;
284 struct module *owner;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Alan Cox335f8512009-06-11 12:26:29 +0100286 /* The console is magical, do not hang up the console hardware
287 or there will be tears */
288 if (port->console)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 return;
290
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300291 mutex_lock(&port->mutex);
Alan Stern2d931482009-04-14 11:31:02 -0400292 serial = port->serial;
293 owner = serial->type->driver.owner;
Luiz Fernando Capitulino8a4613f2005-11-28 19:16:07 -0200294
Alan Cox335f8512009-06-11 12:26:29 +0100295 if (drv->close)
296 drv->close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300298 mutex_unlock(&port->mutex);
Alan Cox335f8512009-06-11 12:26:29 +0100299}
300
301/**
302 * serial_do_free - free resources post close/hangup
303 * @port: port to free up
304 *
305 * Do the resource freeing and refcount dropping for the port. We must
306 * be careful about ordering and we must avoid freeing up the console.
307 */
308
309static void serial_do_free(struct usb_serial_port *port)
310{
311 struct usb_serial *serial;
312 struct module *owner;
313
314 /* The console is magical, do not hang up the console hardware
315 or there will be tears */
316 if (port->console)
317 return;
318
319 serial = port->serial;
320 owner = serial->type->driver.owner;
Alan Stern2d931482009-04-14 11:31:02 -0400321 put_device(&port->dev);
Alan Stern2d931482009-04-14 11:31:02 -0400322 /* Mustn't dereference port any more */
Alan Cox335f8512009-06-11 12:26:29 +0100323 mutex_lock(&serial->disc_mutex);
324 if (!serial->disconnected)
325 usb_autopm_put_interface(serial->interface);
326 mutex_unlock(&serial->disc_mutex);
Alan Stern2d931482009-04-14 11:31:02 -0400327 usb_serial_put(serial);
Alan Stern2d931482009-04-14 11:31:02 -0400328 /* Mustn't dereference serial any more */
Alan Cox335f8512009-06-11 12:26:29 +0100329 module_put(owner);
330}
331
332static void serial_close(struct tty_struct *tty, struct file *filp)
333{
334 struct usb_serial_port *port = tty->driver_data;
335
336 dbg("%s - port %d", __func__, port->number);
337
338
339 if (tty_port_close_start(&port->port, tty, filp) == 0)
340 return;
341
342 serial_do_down(port);
343 tty_port_close_end(&port->port, tty);
344 tty_port_tty_set(&port->port, NULL);
345 serial_do_free(port);
346}
347
348static void serial_hangup(struct tty_struct *tty)
349{
350 struct usb_serial_port *port = tty->driver_data;
351 serial_do_down(port);
352 tty_port_hangup(&port->port);
353 serial_do_free(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354}
355
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100356static int serial_write(struct tty_struct *tty, const unsigned char *buf,
357 int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200359 struct usb_serial_port *port = tty->driver_data;
Oliver Neukum3ff4fd92007-01-13 07:32:27 +0100360 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Alan Coxf34d7a52008-04-30 00:54:13 -0700362 if (port->serial->dev->state == USB_STATE_NOTATTACHED)
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200363 goto exit;
364
Harvey Harrison441b62c2008-03-03 16:08:34 -0800365 dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Alan Cox95da3102008-07-22 11:09:07 +0100367 /* count is managed under the mutex lock for the tty so cannot
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100368 drop to zero until after the last close completes */
Alan Cox95da3102008-07-22 11:09:07 +0100369 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100372 retval = port->serial->type->write(tty, port, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374exit:
375 return retval;
376}
377
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100378static int serial_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200380 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800381 dbg("%s - port %d", __func__, port->number);
Alan Cox95da3102008-07-22 11:09:07 +0100382 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100384 return port->serial->type->write_room(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100387static int serial_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200389 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800390 dbg("%s = port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Alan Cox95da3102008-07-22 11:09:07 +0100392 WARN_ON(!port->port.count);
Alan Coxeff69372009-01-02 13:47:06 +0000393 /* if the device was unplugged then any remaining characters
394 fell out of the connector ;) */
395 if (port->serial->disconnected)
396 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100398 return port->serial->type->chars_in_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399}
400
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100401static void serial_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200403 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800404 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Alan Cox95da3102008-07-22 11:09:07 +0100406 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 /* pass on to the driver specific version of this function */
408 if (port->serial->type->throttle)
Alan Cox95da3102008-07-22 11:09:07 +0100409 port->serial->type->throttle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410}
411
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100412static void serial_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200414 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800415 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Alan Cox95da3102008-07-22 11:09:07 +0100417 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 /* pass on to the driver specific version of this function */
419 if (port->serial->type->unthrottle)
Alan Cox95da3102008-07-22 11:09:07 +0100420 port->serial->type->unthrottle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421}
422
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100423static int serial_ioctl(struct tty_struct *tty, struct file *file,
424 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200426 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 int retval = -ENODEV;
428
Harvey Harrison441b62c2008-03-03 16:08:34 -0800429 dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
Alan Cox95da3102008-07-22 11:09:07 +0100431 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100433 /* pass on to the driver specific version of this function
434 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700435 if (port->serial->type->ioctl) {
Alan Cox95da3102008-07-22 11:09:07 +0100436 retval = port->serial->type->ioctl(tty, file, cmd, arg);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100437 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 return retval;
440}
441
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100442static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200444 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800445 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
Alan Cox95da3102008-07-22 11:09:07 +0100447 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100448 /* pass on to the driver specific version of this function
449 if it is available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 if (port->serial->type->set_termios)
Alan Cox95da3102008-07-22 11:09:07 +0100451 port->serial->type->set_termios(tty, port, old);
Alan Cox33785092007-10-18 01:24:22 -0700452 else
453 tty_termios_copy_hw(tty->termios, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454}
455
Alan Cox9e989662008-07-22 11:18:03 +0100456static int serial_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200458 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
Harvey Harrison441b62c2008-03-03 16:08:34 -0800460 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Alan Cox95da3102008-07-22 11:09:07 +0100462 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100463 /* pass on to the driver specific version of this function
464 if it is available */
Alan Cox6b447f042009-01-02 13:48:56 +0000465 if (port->serial->type->break_ctl)
Alan Cox95da3102008-07-22 11:09:07 +0100466 port->serial->type->break_ctl(tty, break_state);
Alan Cox9e989662008-07-22 11:18:03 +0100467 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468}
469
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700470static int serial_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
472 struct usb_serial *serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 char tmp[40];
475
Harvey Harrison441b62c2008-03-03 16:08:34 -0800476 dbg("%s", __func__);
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700477 seq_puts(m, "usbserinfo:1.0 driver:2.0\n");
478 for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 serial = usb_serial_get_by_index(i);
480 if (serial == NULL)
481 continue;
482
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700483 seq_printf(m, "%d:", i);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700484 if (serial->type->driver.owner)
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700485 seq_printf(m, " module:%s",
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100486 module_name(serial->type->driver.owner));
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700487 seq_printf(m, " name:\"%s\"",
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100488 serial->type->description);
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700489 seq_printf(m, " vendor:%04x product:%04x",
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100490 le16_to_cpu(serial->dev->descriptor.idVendor),
491 le16_to_cpu(serial->dev->descriptor.idProduct));
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700492 seq_printf(m, " num_ports:%d", serial->num_ports);
493 seq_printf(m, " port:%d", i - serial->minor + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 usb_make_path(serial->dev, tmp, sizeof(tmp));
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700495 seq_printf(m, " path:%s", tmp);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100496
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700497 seq_putc(m, '\n');
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200498 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700500 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501}
502
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700503static int serial_proc_open(struct inode *inode, struct file *file)
504{
505 return single_open(file, serial_proc_show, NULL);
506}
507
508static const struct file_operations serial_proc_fops = {
509 .owner = THIS_MODULE,
510 .open = serial_proc_open,
511 .read = seq_read,
512 .llseek = seq_lseek,
513 .release = single_release,
514};
515
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100516static int serial_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200518 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Harvey Harrison441b62c2008-03-03 16:08:34 -0800520 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Alan Cox95da3102008-07-22 11:09:07 +0100522 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 if (port->serial->type->tiocmget)
Alan Cox95da3102008-07-22 11:09:07 +0100524 return port->serial->type->tiocmget(tty, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 return -EINVAL;
526}
527
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100528static int serial_tiocmset(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 unsigned int set, unsigned int clear)
530{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200531 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
Harvey Harrison441b62c2008-03-03 16:08:34 -0800533 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Alan Cox95da3102008-07-22 11:09:07 +0100535 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 if (port->serial->type->tiocmset)
Alan Cox95da3102008-07-22 11:09:07 +0100537 return port->serial->type->tiocmset(tty, file, set, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 return -EINVAL;
539}
540
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700541/*
542 * We would be calling tty_wakeup here, but unfortunately some line
543 * disciplines have an annoying habit of calling tty->write from
544 * the write wakeup callback (e.g. n_hdlc.c).
545 */
546void usb_serial_port_softint(struct usb_serial_port *port)
547{
548 schedule_work(&port->work);
549}
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100550EXPORT_SYMBOL_GPL(usb_serial_port_softint);
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700551
David Howellsc4028952006-11-22 14:57:56 +0000552static void usb_serial_port_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
David Howellsc4028952006-11-22 14:57:56 +0000554 struct usb_serial_port *port =
555 container_of(work, struct usb_serial_port, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 struct tty_struct *tty;
557
Harvey Harrison441b62c2008-03-03 16:08:34 -0800558 dbg("%s - port %d", __func__, port->number);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100559
Alan Cox4a90f092008-10-13 10:39:46 +0100560 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 if (!tty)
562 return;
563
564 tty_wakeup(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100565 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566}
567
568static void port_release(struct device *dev)
569{
570 struct usb_serial_port *port = to_usb_serial_port(dev);
571
Kay Sievers7071a3c2008-05-02 06:02:41 +0200572 dbg ("%s - %s", __func__, dev_name(dev));
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700573 port_free(port);
574}
575
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100576static void kill_traffic(struct usb_serial_port *port)
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700577{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 usb_kill_urb(port->write_urb);
Oliver Neukum5adceac2007-08-17 14:01:38 +0200580 /*
581 * This is tricky.
582 * Some drivers submit the read_urb in the
583 * handler for the write_urb or vice versa
584 * this order determines the order in which
585 * usb_kill_urb() must be used to reliably
586 * kill the URBs. As it is unknown here,
587 * both orders must be used in turn.
588 * The call below is not redundant.
589 */
590 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 usb_kill_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 usb_kill_urb(port->interrupt_out_urb);
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100593}
594
595static void port_free(struct usb_serial_port *port)
596{
Alan Stern2d931482009-04-14 11:31:02 -0400597 /*
598 * Stop all the traffic before cancelling the work, so that
599 * nobody will restart it by calling usb_serial_port_softint.
600 */
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100601 kill_traffic(port);
Alan Stern2d931482009-04-14 11:31:02 -0400602 cancel_work_sync(&port->work);
603
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100604 usb_free_urb(port->read_urb);
605 usb_free_urb(port->write_urb);
606 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 usb_free_urb(port->interrupt_out_urb);
608 kfree(port->bulk_in_buffer);
609 kfree(port->bulk_out_buffer);
610 kfree(port->interrupt_in_buffer);
611 kfree(port->interrupt_out_buffer);
612 kfree(port);
613}
614
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100615static struct usb_serial *create_serial(struct usb_device *dev,
616 struct usb_interface *interface,
617 struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
619 struct usb_serial *serial;
620
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100621 serial = kzalloc(sizeof(*serial), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 if (!serial) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800623 dev_err(&dev->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 return NULL;
625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 serial->dev = usb_get_dev(dev);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700627 serial->type = driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 serial->interface = interface;
629 kref_init(&serial->kref);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +0100630 mutex_init(&serial->disc_mutex);
Alan Stern0282b7f2008-07-29 12:01:04 -0400631 serial->minor = SERIAL_TTY_NO_MINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 return serial;
634}
635
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100636static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100637 struct usb_serial_driver *drv)
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100638{
639 struct usb_dynid *dynid;
640
641 spin_lock(&drv->dynids.lock);
642 list_for_each_entry(dynid, &drv->dynids.list, node) {
643 if (usb_match_one_id(intf, &dynid->id)) {
644 spin_unlock(&drv->dynids.lock);
645 return &dynid->id;
646 }
647 }
648 spin_unlock(&drv->dynids.lock);
649 return NULL;
650}
651
652static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
653 struct usb_interface *intf)
654{
655 const struct usb_device_id *id;
656
657 id = usb_match_id(intf, drv->id_table);
658 if (id) {
659 dbg("static descriptor matches");
660 goto exit;
661 }
662 id = match_dynamic_id(intf, drv);
663 if (id)
664 dbg("dynamic descriptor matches");
665exit:
666 return id;
667}
668
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100669static struct usb_serial_driver *search_serial_device(
670 struct usb_interface *iface)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 const struct usb_device_id *id;
Alan Stern063a2da2007-10-10 16:24:06 -0400673 struct usb_serial_driver *drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Adrian Bunk93b1fae2006-01-10 00:13:33 +0100675 /* Check if the usb id matches a known device */
Alan Stern063a2da2007-10-10 16:24:06 -0400676 list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
677 id = get_iface_id(drv, iface);
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100678 if (id)
Alan Stern063a2da2007-10-10 16:24:06 -0400679 return drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 }
681
682 return NULL;
683}
684
Alan Cox335f8512009-06-11 12:26:29 +0100685static int serial_carrier_raised(struct tty_port *port)
686{
687 struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
688 struct usb_serial_driver *drv = p->serial->type;
689 if (drv->carrier_raised)
690 return drv->carrier_raised(p);
691 /* No carrier control - don't block */
692 return 1;
693}
694
695static void serial_dtr_rts(struct tty_port *port, int on)
696{
697 struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
698 struct usb_serial_driver *drv = p->serial->type;
699 if (drv->dtr_rts)
700 drv->dtr_rts(p, on);
701}
702
703static const struct tty_port_operations serial_port_ops = {
704 .carrier_raised = serial_carrier_raised,
705 .dtr_rts = serial_dtr_rts,
706};
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708int usb_serial_probe(struct usb_interface *interface,
709 const struct usb_device_id *id)
710{
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100711 struct usb_device *dev = interface_to_usbdev(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 struct usb_serial *serial = NULL;
713 struct usb_serial_port *port;
714 struct usb_host_interface *iface_desc;
715 struct usb_endpoint_descriptor *endpoint;
716 struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
717 struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
718 struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
719 struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700720 struct usb_serial_driver *type = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 int retval;
Andre Hauptdd9ca5d2008-06-18 15:56:00 +0200722 unsigned int minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 int buffer_size;
724 int i;
725 int num_interrupt_in = 0;
726 int num_interrupt_out = 0;
727 int num_bulk_in = 0;
728 int num_bulk_out = 0;
729 int num_ports = 0;
730 int max_endpoints;
731
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100732 lock_kernel(); /* guard against unloading a serial driver module */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 type = search_serial_device(interface);
734 if (!type) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100735 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 dbg("none matched");
737 return -ENODEV;
738 }
739
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100740 serial = create_serial(dev, interface, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 if (!serial) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100742 unlock_kernel();
Harvey Harrison441b62c2008-03-03 16:08:34 -0800743 dev_err(&interface->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return -ENOMEM;
745 }
746
747 /* if this device type has a probe function, call it */
748 if (type->probe) {
749 const struct usb_device_id *id;
750
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700751 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100752 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100753 dev_err(&interface->dev,
754 "module get failed, exiting\n");
755 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 return -EIO;
757 }
758
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100759 id = get_iface_id(type, interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 retval = type->probe(serial, id);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700761 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
763 if (retval) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100764 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100765 dbg("sub driver rejected device");
766 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 return retval;
768 }
769 }
770
771 /* descriptor matches, let's find the endpoints needed */
772 /* check out the endpoints */
773 iface_desc = interface->cur_altsetting;
774 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
775 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700776
777 if (usb_endpoint_is_bulk_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 /* we found a bulk in endpoint */
779 dbg("found bulk in on endpoint %d", i);
780 bulk_in_endpoint[num_bulk_in] = endpoint;
781 ++num_bulk_in;
782 }
783
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700784 if (usb_endpoint_is_bulk_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 /* we found a bulk out endpoint */
786 dbg("found bulk out on endpoint %d", i);
787 bulk_out_endpoint[num_bulk_out] = endpoint;
788 ++num_bulk_out;
789 }
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700790
791 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 /* we found a interrupt in endpoint */
793 dbg("found interrupt in on endpoint %d", i);
794 interrupt_in_endpoint[num_interrupt_in] = endpoint;
795 ++num_interrupt_in;
796 }
797
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700798 if (usb_endpoint_is_int_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 /* we found an interrupt out endpoint */
800 dbg("found interrupt out on endpoint %d", i);
801 interrupt_out_endpoint[num_interrupt_out] = endpoint;
802 ++num_interrupt_out;
803 }
804 }
805
806#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100807 /* BEGIN HORRIBLE HACK FOR PL2303 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 /* this is needed due to the looney way its endpoints are set up */
809 if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
810 (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
811 ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
Johannes Steingraeber8fd80132006-09-16 16:17:34 +0200812 (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
813 ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
Andreas Bombece816cf2008-09-14 01:58:55 +0200814 (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) ||
815 ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
816 (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (interface != dev->actconfig->interface[0]) {
818 /* check out the endpoints of the other interface*/
819 iface_desc = dev->actconfig->interface[0]->cur_altsetting;
820 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
821 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700822 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 /* we found a interrupt in endpoint */
824 dbg("found interrupt in for Prolific device on separate interface");
825 interrupt_in_endpoint[num_interrupt_in] = endpoint;
826 ++num_interrupt_in;
827 }
828 }
829 }
830
831 /* Now make sure the PL-2303 is configured correctly.
832 * If not, give up now and hope this hack will work
833 * properly during a later invocation of usb_serial_probe
834 */
835 if (num_bulk_in == 0 || num_bulk_out == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100836 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100838 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 return -ENODEV;
840 }
841 }
842 /* END HORRIBLE HACK FOR PL2303 */
843#endif
844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845#ifdef CONFIG_USB_SERIAL_GENERIC
846 if (type == &usb_serial_generic_device) {
847 num_ports = num_bulk_out;
848 if (num_ports == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100849 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100850 dev_err(&interface->dev,
851 "Generic device with no bulk out, not allowed.\n");
852 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 return -EIO;
854 }
855 }
856#endif
857 if (!num_ports) {
858 /* if this device type has a calc_num_ports function, call it */
859 if (type->calc_num_ports) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700860 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100861 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100862 dev_err(&interface->dev,
863 "module get failed, exiting\n");
864 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 return -EIO;
866 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100867 num_ports = type->calc_num_ports(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700868 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 }
870 if (!num_ports)
871 num_ports = type->num_ports;
872 }
873
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 serial->num_ports = num_ports;
875 serial->num_bulk_in = num_bulk_in;
876 serial->num_bulk_out = num_bulk_out;
877 serial->num_interrupt_in = num_interrupt_in;
878 serial->num_interrupt_out = num_interrupt_out;
879
Alan Stern063a2da2007-10-10 16:24:06 -0400880 /* 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 */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100885 /* we don't use num_ports here because some devices have more
886 endpoint pairs than ports */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 max_endpoints = max(num_bulk_in, num_bulk_out);
888 max_endpoints = max(max_endpoints, num_interrupt_in);
889 max_endpoints = max(max_endpoints, num_interrupt_out);
890 max_endpoints = max(max_endpoints, (int)serial->num_ports);
891 serial->num_port_pointers = max_endpoints;
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100892 unlock_kernel();
893
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100894 dbg("%s - setting up %d port structures for this device",
895 __func__, max_endpoints);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 for (i = 0; i < max_endpoints; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100897 port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 if (!port)
899 goto probe_error;
Alan Cox4a90f092008-10-13 10:39:46 +0100900 tty_port_init(&port->port);
Alan Cox335f8512009-06-11 12:26:29 +0100901 port->port.ops = &serial_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 port->serial = serial;
Greg Kroah-Hartman507ca9b2005-04-23 12:49:16 -0700903 spin_lock_init(&port->lock);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300904 mutex_init(&port->mutex);
David Howellsc4028952006-11-22 14:57:56 +0000905 INIT_WORK(&port->work, usb_serial_port_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 serial->port[i] = port;
907 }
908
909 /* set up the endpoint information */
910 for (i = 0; i < num_bulk_in; ++i) {
911 endpoint = bulk_in_endpoint[i];
912 port = serial->port[i];
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100913 port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 if (!port->read_urb) {
915 dev_err(&interface->dev, "No free urbs available\n");
916 goto probe_error;
917 }
918 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
919 port->bulk_in_size = buffer_size;
920 port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100921 port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 if (!port->bulk_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100923 dev_err(&interface->dev,
924 "Couldn't allocate bulk_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 goto probe_error;
926 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100927 usb_fill_bulk_urb(port->read_urb, dev,
928 usb_rcvbulkpipe(dev,
929 endpoint->bEndpointAddress),
930 port->bulk_in_buffer, buffer_size,
931 serial->type->read_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 }
933
934 for (i = 0; i < num_bulk_out; ++i) {
935 endpoint = bulk_out_endpoint[i];
936 port = serial->port[i];
937 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
938 if (!port->write_urb) {
939 dev_err(&interface->dev, "No free urbs available\n");
940 goto probe_error;
941 }
942 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
943 port->bulk_out_size = buffer_size;
944 port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100945 port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 if (!port->bulk_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100947 dev_err(&interface->dev,
948 "Couldn't allocate bulk_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 goto probe_error;
950 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100951 usb_fill_bulk_urb(port->write_urb, dev,
952 usb_sndbulkpipe(dev,
953 endpoint->bEndpointAddress),
954 port->bulk_out_buffer, buffer_size,
955 serial->type->write_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
957
958 if (serial->type->read_int_callback) {
959 for (i = 0; i < num_interrupt_in; ++i) {
960 endpoint = interrupt_in_endpoint[i];
961 port = serial->port[i];
962 port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
963 if (!port->interrupt_in_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100964 dev_err(&interface->dev,
965 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 goto probe_error;
967 }
968 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100969 port->interrupt_in_endpointAddress =
970 endpoint->bEndpointAddress;
971 port->interrupt_in_buffer = kmalloc(buffer_size,
972 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 if (!port->interrupt_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100974 dev_err(&interface->dev,
975 "Couldn't allocate interrupt_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 goto probe_error;
977 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100978 usb_fill_int_urb(port->interrupt_in_urb, dev,
979 usb_rcvintpipe(dev,
980 endpoint->bEndpointAddress),
981 port->interrupt_in_buffer, buffer_size,
982 serial->type->read_int_callback, port,
983 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 }
985 } else if (num_interrupt_in) {
986 dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
987 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 if (serial->type->write_int_callback) {
990 for (i = 0; i < num_interrupt_out; ++i) {
991 endpoint = interrupt_out_endpoint[i];
992 port = serial->port[i];
993 port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
994 if (!port->interrupt_out_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100995 dev_err(&interface->dev,
996 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 goto probe_error;
998 }
999 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
1000 port->interrupt_out_size = buffer_size;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001001 port->interrupt_out_endpointAddress =
1002 endpoint->bEndpointAddress;
1003 port->interrupt_out_buffer = kmalloc(buffer_size,
1004 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 if (!port->interrupt_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001006 dev_err(&interface->dev,
1007 "Couldn't allocate interrupt_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 goto probe_error;
1009 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001010 usb_fill_int_urb(port->interrupt_out_urb, dev,
1011 usb_sndintpipe(dev,
1012 endpoint->bEndpointAddress),
1013 port->interrupt_out_buffer, buffer_size,
1014 serial->type->write_int_callback, port,
1015 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 }
1017 } else if (num_interrupt_out) {
1018 dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
1019 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 /* if this device type has an attach function, call it */
1022 if (type->attach) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -07001023 if (!try_module_get(type->driver.owner)) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001024 dev_err(&interface->dev,
1025 "module get failed, exiting\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 goto probe_error;
1027 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001028 retval = type->attach(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -07001029 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 if (retval < 0)
1031 goto probe_error;
1032 if (retval > 0) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001033 /* quietly accept this device, but don't bind to a
1034 serial port as it's about to disappear */
Alan Stern0a3c8542009-05-27 11:25:52 -04001035 serial->num_ports = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 goto exit;
1037 }
1038 }
1039
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001040 if (get_free_serial(serial, num_ports, &minor) == NULL) {
Oliver Neukum34ef50e2007-01-13 07:29:26 +01001041 dev_err(&interface->dev, "No more free serial devices\n");
1042 goto probe_error;
1043 }
Oliver Neukumc744f992007-02-26 15:43:00 +01001044 serial->minor = minor;
Oliver Neukum34ef50e2007-01-13 07:29:26 +01001045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 /* register all of the individual ports with the driver core */
1047 for (i = 0; i < num_ports; ++i) {
1048 port = serial->port[i];
1049 port->dev.parent = &interface->dev;
1050 port->dev.driver = NULL;
1051 port->dev.bus = &usb_serial_bus_type;
1052 port->dev.release = &port_release;
1053
Kay Sievers0031a062008-05-02 06:02:41 +02001054 dev_set_name(&port->dev, "ttyUSB%d", port->number);
Kay Sievers7071a3c2008-05-02 06:02:41 +02001055 dbg ("%s - registering %s", __func__, dev_name(&port->dev));
Alan Sternc706ebd2009-06-02 11:54:11 -04001056 port->dev_state = PORT_REGISTERING;
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -07001057 retval = device_register(&port->dev);
Alan Sternc706ebd2009-06-02 11:54:11 -04001058 if (retval) {
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -07001059 dev_err(&port->dev, "Error registering port device, "
1060 "continuing\n");
Alan Sternc706ebd2009-06-02 11:54:11 -04001061 port->dev_state = PORT_UNREGISTERED;
1062 } else {
1063 port->dev_state = PORT_REGISTERED;
1064 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 }
1066
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001067 usb_serial_console_init(debug, minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
1069exit:
1070 /* success */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001071 usb_set_intfdata(interface, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 return 0;
1073
1074probe_error:
1075 for (i = 0; i < num_bulk_in; ++i) {
1076 port = serial->port[i];
1077 if (!port)
1078 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001079 usb_free_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 kfree(port->bulk_in_buffer);
1081 }
1082 for (i = 0; i < num_bulk_out; ++i) {
1083 port = serial->port[i];
1084 if (!port)
1085 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001086 usb_free_urb(port->write_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 kfree(port->bulk_out_buffer);
1088 }
1089 for (i = 0; i < num_interrupt_in; ++i) {
1090 port = serial->port[i];
1091 if (!port)
1092 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001093 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 kfree(port->interrupt_in_buffer);
1095 }
1096 for (i = 0; i < num_interrupt_out; ++i) {
1097 port = serial->port[i];
1098 if (!port)
1099 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001100 usb_free_urb(port->interrupt_out_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 kfree(port->interrupt_out_buffer);
1102 }
1103
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 /* free up any memory that we allocated */
1105 for (i = 0; i < serial->num_port_pointers; ++i)
1106 kfree(serial->port[i]);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001107 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 return -EIO;
1109}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001110EXPORT_SYMBOL_GPL(usb_serial_probe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112void usb_serial_disconnect(struct usb_interface *interface)
1113{
1114 int i;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001115 struct usb_serial *serial = usb_get_intfdata(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 struct device *dev = &interface->dev;
1117 struct usb_serial_port *port;
1118
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +02001119 usb_serial_console_disconnect(serial);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001120 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001122 mutex_lock(&serial->disc_mutex);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001123 usb_set_intfdata(interface, NULL);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001124 /* must set a flag, to signal subdrivers */
1125 serial->disconnected = 1;
Alan Stern2d931482009-04-14 11:31:02 -04001126 mutex_unlock(&serial->disc_mutex);
1127
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001128 for (i = 0; i < serial->num_ports; ++i) {
1129 port = serial->port[i];
1130 if (port) {
Alan Cox4a90f092008-10-13 10:39:46 +01001131 struct tty_struct *tty = tty_port_tty_get(&port->port);
1132 if (tty) {
Alan Cox335f8512009-06-11 12:26:29 +01001133 /* The hangup will occur asynchronously but
1134 the object refcounts will sort out all the
1135 cleanup */
Alan Cox4a90f092008-10-13 10:39:46 +01001136 tty_hangup(tty);
1137 tty_kref_put(tty);
1138 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001139 kill_traffic(port);
Alan Stern2d931482009-04-14 11:31:02 -04001140 cancel_work_sync(&port->work);
Alan Sternc706ebd2009-06-02 11:54:11 -04001141 if (port->dev_state == PORT_REGISTERED) {
1142
1143 /* Make sure the port is bound so that the
1144 * driver's port_remove method is called.
1145 */
1146 if (!port->dev.driver) {
1147 int rc;
1148
1149 port->dev.driver =
1150 &serial->type->driver;
1151 rc = device_bind_driver(&port->dev);
1152 }
1153 port->dev_state = PORT_UNREGISTERING;
1154 device_del(&port->dev);
1155 port->dev_state = PORT_UNREGISTERED;
1156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 }
Alan Sternf9c99bb2009-06-02 11:53:55 -04001159 serial->type->disconnect(serial);
Alan Stern2d931482009-04-14 11:31:02 -04001160
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001161 /* let the last holder of this object
1162 * cause it to be cleaned up */
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001163 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 dev_info(dev, "device disconnected\n");
1165}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001166EXPORT_SYMBOL_GPL(usb_serial_disconnect);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
Oliver Neukumec225592007-04-27 20:54:57 +02001168int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1169{
1170 struct usb_serial *serial = usb_get_intfdata(intf);
1171 struct usb_serial_port *port;
1172 int i, r = 0;
1173
Oliver Neukumf8bece82009-02-05 16:54:25 +01001174 serial->suspending = 1;
1175
Oliver Neukume31c1882007-07-23 08:58:39 +02001176 for (i = 0; i < serial->num_ports; ++i) {
1177 port = serial->port[i];
1178 if (port)
1179 kill_traffic(port);
Oliver Neukumec225592007-04-27 20:54:57 +02001180 }
1181
1182 if (serial->type->suspend)
Oliver Neukume31c1882007-07-23 08:58:39 +02001183 r = serial->type->suspend(serial, message);
Oliver Neukumec225592007-04-27 20:54:57 +02001184
1185 return r;
1186}
1187EXPORT_SYMBOL(usb_serial_suspend);
1188
1189int usb_serial_resume(struct usb_interface *intf)
1190{
1191 struct usb_serial *serial = usb_get_intfdata(intf);
Oliver Neukumc49cfa912009-02-06 18:06:43 +01001192 int rv;
Oliver Neukumec225592007-04-27 20:54:57 +02001193
Oliver Neukumf8bece82009-02-05 16:54:25 +01001194 serial->suspending = 0;
Sarah Sharp8abaee22007-10-25 10:58:43 -07001195 if (serial->type->resume)
Oliver Neukumc49cfa912009-02-06 18:06:43 +01001196 rv = serial->type->resume(serial);
1197 else
1198 rv = usb_serial_generic_resume(serial);
Oliver Neukumf8bece82009-02-05 16:54:25 +01001199
Oliver Neukumc49cfa912009-02-06 18:06:43 +01001200 return rv;
Oliver Neukumec225592007-04-27 20:54:57 +02001201}
1202EXPORT_SYMBOL(usb_serial_resume);
1203
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001204static const struct tty_operations serial_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 .open = serial_open,
1206 .close = serial_close,
1207 .write = serial_write,
Alan Cox335f8512009-06-11 12:26:29 +01001208 .hangup = serial_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 .write_room = serial_write_room,
1210 .ioctl = serial_ioctl,
1211 .set_termios = serial_set_termios,
1212 .throttle = serial_throttle,
1213 .unthrottle = serial_unthrottle,
1214 .break_ctl = serial_break,
1215 .chars_in_buffer = serial_chars_in_buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 .tiocmget = serial_tiocmget,
1217 .tiocmset = serial_tiocmset,
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -07001218 .proc_fops = &serial_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219};
1220
Alan Cox335f8512009-06-11 12:26:29 +01001221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222struct tty_driver *usb_serial_tty_driver;
1223
1224static int __init usb_serial_init(void)
1225{
1226 int i;
1227 int result;
1228
1229 usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
1230 if (!usb_serial_tty_driver)
1231 return -ENOMEM;
1232
1233 /* Initialize our global data */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001234 for (i = 0; i < SERIAL_TTY_MINORS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 serial_table[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237 result = bus_register(&usb_serial_bus_type);
1238 if (result) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001239 printk(KERN_ERR "usb-serial: %s - registering bus driver "
1240 "failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 goto exit_bus;
1242 }
1243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 usb_serial_tty_driver->owner = THIS_MODULE;
1245 usb_serial_tty_driver->driver_name = "usbserial";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 usb_serial_tty_driver->name = "ttyUSB";
1247 usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
1248 usb_serial_tty_driver->minor_start = 0;
1249 usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
1250 usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001251 usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
1252 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 usb_serial_tty_driver->init_termios = tty_std_termios;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001254 usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
1255 | HUPCL | CLOCAL;
Alan Coxa5b6f602008-04-08 17:16:06 +01001256 usb_serial_tty_driver->init_termios.c_ispeed = 9600;
1257 usb_serial_tty_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 tty_set_operations(usb_serial_tty_driver, &serial_ops);
1259 result = tty_register_driver(usb_serial_tty_driver);
1260 if (result) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001261 printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n",
1262 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 goto exit_reg_driver;
1264 }
1265
1266 /* register the USB driver */
1267 result = usb_register(&usb_serial_driver);
1268 if (result < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001269 printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
1270 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 goto exit_tty;
1272 }
1273
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001274 /* register the generic driver, if we should */
1275 result = usb_serial_generic_register(debug);
1276 if (result < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001277 printk(KERN_ERR "usb-serial: %s - registering generic "
1278 "driver failed\n", __func__);
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001279 goto exit_generic;
1280 }
1281
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001282 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
1284 return result;
1285
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001286exit_generic:
1287 usb_deregister(&usb_serial_driver);
1288
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289exit_tty:
1290 tty_unregister_driver(usb_serial_tty_driver);
1291
1292exit_reg_driver:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 bus_unregister(&usb_serial_bus_type);
1294
1295exit_bus:
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001296 printk(KERN_ERR "usb-serial: %s - returning with error %d\n",
1297 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 put_tty_driver(usb_serial_tty_driver);
1299 return result;
1300}
1301
1302
1303static void __exit usb_serial_exit(void)
1304{
1305 usb_serial_console_exit();
1306
1307 usb_serial_generic_deregister();
1308
1309 usb_deregister(&usb_serial_driver);
1310 tty_unregister_driver(usb_serial_tty_driver);
1311 put_tty_driver(usb_serial_tty_driver);
1312 bus_unregister(&usb_serial_bus_type);
1313}
1314
1315
1316module_init(usb_serial_init);
1317module_exit(usb_serial_exit);
1318
1319#define set_to_generic_if_null(type, function) \
1320 do { \
1321 if (!type->function) { \
1322 type->function = usb_serial_generic_##function; \
1323 dbg("Had to override the " #function \
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001324 " usb serial operation with the generic one.");\
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 } \
1326 } while (0)
1327
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001328static void fixup_generic(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329{
1330 set_to_generic_if_null(device, open);
1331 set_to_generic_if_null(device, write);
1332 set_to_generic_if_null(device, close);
1333 set_to_generic_if_null(device, write_room);
1334 set_to_generic_if_null(device, chars_in_buffer);
1335 set_to_generic_if_null(device, read_bulk_callback);
1336 set_to_generic_if_null(device, write_bulk_callback);
Alan Sternf9c99bb2009-06-02 11:53:55 -04001337 set_to_generic_if_null(device, disconnect);
1338 set_to_generic_if_null(device, release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339}
1340
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001341int usb_serial_register(struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001343 /* must be called with BKL held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 int retval;
1345
Dave Younge4abe662009-02-14 21:21:13 +08001346 if (usb_disabled())
1347 return -ENODEV;
1348
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001349 fixup_generic(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001351 if (!driver->description)
1352 driver->description = driver->driver.name;
1353
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 /* Add this device to our list of devices */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001355 list_add(&driver->driver_list, &usb_serial_driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001357 retval = usb_serial_bus_register(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 if (retval) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001359 printk(KERN_ERR "usb-serial: problem %d when registering "
1360 "driver %s\n", retval, driver->description);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001361 list_del(&driver->driver_list);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001362 } else
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001363 printk(KERN_INFO "USB Serial support registered for %s\n",
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001364 driver->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
1366 return retval;
1367}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001368EXPORT_SYMBOL_GPL(usb_serial_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
1370
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001371void usb_serial_deregister(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001373 /* must be called with BKL held */
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001374 printk(KERN_INFO "USB Serial deregistering driver %s\n",
1375 device->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 list_del(&device->driver_list);
1377 usb_serial_bus_deregister(device);
1378}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379EXPORT_SYMBOL_GPL(usb_serial_deregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
1381/* Module information */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001382MODULE_AUTHOR(DRIVER_AUTHOR);
1383MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384MODULE_LICENSE("GPL");
1385
1386module_param(debug, bool, S_IRUGO | S_IWUSR);
1387MODULE_PARM_DESC(debug, "Debug enabled or not");