blob: da890f030fac7299e365b07a009f1b076e4fa828 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 /* If this is a "fake" port, we have to clean it up here, as it will
145 * not get cleaned up in port_release() as it was never registered with
146 * the driver core */
147 if (serial->num_ports < serial->num_port_pointers) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100148 for (i = serial->num_ports;
149 i < serial->num_port_pointers; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 port = serial->port[i];
151 if (!port)
152 continue;
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700153 port_free(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 }
155 }
156
157 usb_put_dev(serial->dev);
158
159 /* free up any memory that we allocated */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100160 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161}
162
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200163void usb_serial_put(struct usb_serial *serial)
164{
Oliver Neukum3ddad822007-07-24 15:13:42 +0200165 mutex_lock(&table_lock);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200166 kref_put(&serial->kref, destroy_serial);
Oliver Neukum3ddad822007-07-24 15:13:42 +0200167 mutex_unlock(&table_lock);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200168}
169
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170/*****************************************************************************
171 * Driver tty interface functions
172 *****************************************************************************/
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100173static int serial_open (struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
175 struct usb_serial *serial;
176 struct usb_serial_port *port;
177 unsigned int portNumber;
Alan Stern2d931482009-04-14 11:31:02 -0400178 int retval = 0;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100179
Harvey Harrison441b62c2008-03-03 16:08:34 -0800180 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 /* get the serial object associated with this tty pointer */
183 serial = usb_serial_get_by_index(tty->index);
184 if (!serial) {
185 tty->driver_data = NULL;
186 return -ENODEV;
187 }
188
Alan Stern2d931482009-04-14 11:31:02 -0400189 mutex_lock(&serial->disc_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 portNumber = tty->index - serial->minor;
191 port = serial->port[portNumber];
Alan Stern2d931482009-04-14 11:31:02 -0400192 if (!port || serial->disconnected)
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300193 retval = -ENODEV;
Alan Stern2d931482009-04-14 11:31:02 -0400194 else
195 get_device(&port->dev);
196 /*
197 * Note: Our locking order requirement does not allow port->mutex
198 * to be acquired while serial->disc_mutex is held.
199 */
200 mutex_unlock(&serial->disc_mutex);
201 if (retval)
202 goto bailout_serial_put;
James Woodcock331879f2009-02-11 15:06:53 +0000203
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300204 if (mutex_lock_interruptible(&port->mutex)) {
205 retval = -ERESTARTSYS;
Alan Stern2d931482009-04-14 11:31:02 -0400206 goto bailout_port_put;
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300207 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100208
Alan Cox95da3102008-07-22 11:09:07 +0100209 ++port->port.count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Paul Fulghumca854852006-04-13 22:28:17 +0200211 /* set up our port structure making the tty driver
212 * remember our port object, and us it */
213 tty->driver_data = port;
Alan Cox4a90f092008-10-13 10:39:46 +0100214 tty_port_tty_set(&port->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Alan Cox95da3102008-07-22 11:09:07 +0100216 if (port->port.count == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218 /* lock this module before we call it
219 * this may fail, which means we must bail out,
220 * safe because we are called with BKL held */
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700221 if (!try_module_get(serial->type->driver.owner)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 retval = -ENODEV;
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300223 goto bailout_mutex_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 }
225
Alan Stern2d931482009-04-14 11:31:02 -0400226 mutex_lock(&serial->disc_mutex);
227 if (serial->disconnected)
228 retval = -ENODEV;
229 else
230 retval = usb_autopm_get_interface(serial->interface);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800231 if (retval)
232 goto bailout_module_put;
Alan Stern2d931482009-04-14 11:31:02 -0400233
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100234 /* only call the device specific open if this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 * is the first time the port is opened */
Alan Cox95da3102008-07-22 11:09:07 +0100236 retval = serial->type->open(tty, port, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 if (retval)
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800238 goto bailout_interface_put;
Alan Stern2d931482009-04-14 11:31:02 -0400239 mutex_unlock(&serial->disc_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 }
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300241 mutex_unlock(&port->mutex);
Alan Cox335f8512009-06-11 12:26:29 +0100242 /* Now do the correct tty layer semantics */
243 retval = tty_port_block_til_ready(&port->port, tty, filp);
244 if (retval == 0)
245 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800247bailout_interface_put:
248 usb_autopm_put_interface(serial->interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249bailout_module_put:
Alan Stern2d931482009-04-14 11:31:02 -0400250 mutex_unlock(&serial->disc_mutex);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700251 module_put(serial->type->driver.owner);
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300252bailout_mutex_unlock:
Alan Cox95da3102008-07-22 11:09:07 +0100253 port->port.count = 0;
Frank Gevaertsb059c812006-06-14 15:52:05 +0200254 tty->driver_data = NULL;
Alan Cox4a90f092008-10-13 10:39:46 +0100255 tty_port_tty_set(&port->port, NULL);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300256 mutex_unlock(&port->mutex);
Alan Stern2d931482009-04-14 11:31:02 -0400257bailout_port_put:
258 put_device(&port->dev);
259bailout_serial_put:
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200260 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 return retval;
262}
263
Alan Cox335f8512009-06-11 12:26:29 +0100264/**
265 * serial_do_down - shut down hardware
266 * @port: port to shut down
267 *
268 * Shut down a USB port unless it is the console. We never shut down the
269 * console hardware as it will always be in use.
270 *
271 * Don't free any resources at this point
272 */
273static void serial_do_down(struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
Alan Cox335f8512009-06-11 12:26:29 +0100275 struct usb_serial_driver *drv = port->serial->type;
Alan Stern2d931482009-04-14 11:31:02 -0400276 struct usb_serial *serial;
277 struct module *owner;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Alan Cox335f8512009-06-11 12:26:29 +0100279 /* The console is magical, do not hang up the console hardware
280 or there will be tears */
281 if (port->console)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 return;
283
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300284 mutex_lock(&port->mutex);
Alan Stern2d931482009-04-14 11:31:02 -0400285 serial = port->serial;
286 owner = serial->type->driver.owner;
Luiz Fernando Capitulino8a4613f2005-11-28 19:16:07 -0200287
Alan Cox335f8512009-06-11 12:26:29 +0100288 if (drv->close)
289 drv->close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300291 mutex_unlock(&port->mutex);
Alan Cox335f8512009-06-11 12:26:29 +0100292}
293
294/**
295 * serial_do_free - free resources post close/hangup
296 * @port: port to free up
297 *
298 * Do the resource freeing and refcount dropping for the port. We must
299 * be careful about ordering and we must avoid freeing up the console.
300 */
301
302static void serial_do_free(struct usb_serial_port *port)
303{
304 struct usb_serial *serial;
305 struct module *owner;
306
307 /* The console is magical, do not hang up the console hardware
308 or there will be tears */
309 if (port->console)
310 return;
311
312 serial = port->serial;
313 owner = serial->type->driver.owner;
Alan Stern2d931482009-04-14 11:31:02 -0400314 put_device(&port->dev);
Alan Stern2d931482009-04-14 11:31:02 -0400315 /* Mustn't dereference port any more */
Alan Cox335f8512009-06-11 12:26:29 +0100316 mutex_lock(&serial->disc_mutex);
317 if (!serial->disconnected)
318 usb_autopm_put_interface(serial->interface);
319 mutex_unlock(&serial->disc_mutex);
Alan Stern2d931482009-04-14 11:31:02 -0400320 usb_serial_put(serial);
Alan Stern2d931482009-04-14 11:31:02 -0400321 /* Mustn't dereference serial any more */
Alan Cox335f8512009-06-11 12:26:29 +0100322 module_put(owner);
323}
324
325static void serial_close(struct tty_struct *tty, struct file *filp)
326{
327 struct usb_serial_port *port = tty->driver_data;
328
329 dbg("%s - port %d", __func__, port->number);
330
331
332 if (tty_port_close_start(&port->port, tty, filp) == 0)
333 return;
334
335 serial_do_down(port);
336 tty_port_close_end(&port->port, tty);
337 tty_port_tty_set(&port->port, NULL);
338 serial_do_free(port);
339}
340
341static void serial_hangup(struct tty_struct *tty)
342{
343 struct usb_serial_port *port = tty->driver_data;
344 serial_do_down(port);
345 tty_port_hangup(&port->port);
346 serial_do_free(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347}
348
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100349static int serial_write(struct tty_struct *tty, const unsigned char *buf,
350 int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200352 struct usb_serial_port *port = tty->driver_data;
Oliver Neukum3ff4fd92007-01-13 07:32:27 +0100353 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Alan Coxf34d7a52008-04-30 00:54:13 -0700355 if (port->serial->dev->state == USB_STATE_NOTATTACHED)
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200356 goto exit;
357
Harvey Harrison441b62c2008-03-03 16:08:34 -0800358 dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Alan Cox95da3102008-07-22 11:09:07 +0100360 /* count is managed under the mutex lock for the tty so cannot
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100361 drop to zero until after the last close completes */
Alan Cox95da3102008-07-22 11:09:07 +0100362 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100365 retval = port->serial->type->write(tty, port, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
367exit:
368 return retval;
369}
370
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100371static int serial_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200373 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800374 dbg("%s - port %d", __func__, port->number);
Alan Cox95da3102008-07-22 11:09:07 +0100375 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100377 return port->serial->type->write_room(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378}
379
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100380static int serial_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200382 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800383 dbg("%s = port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Alan Cox95da3102008-07-22 11:09:07 +0100385 WARN_ON(!port->port.count);
Alan Coxeff69372009-01-02 13:47:06 +0000386 /* if the device was unplugged then any remaining characters
387 fell out of the connector ;) */
388 if (port->serial->disconnected)
389 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100391 return port->serial->type->chars_in_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392}
393
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100394static void serial_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200396 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800397 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Alan Cox95da3102008-07-22 11:09:07 +0100399 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 /* pass on to the driver specific version of this function */
401 if (port->serial->type->throttle)
Alan Cox95da3102008-07-22 11:09:07 +0100402 port->serial->type->throttle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
404
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100405static void serial_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200407 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800408 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Alan Cox95da3102008-07-22 11:09:07 +0100410 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 /* pass on to the driver specific version of this function */
412 if (port->serial->type->unthrottle)
Alan Cox95da3102008-07-22 11:09:07 +0100413 port->serial->type->unthrottle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100416static int serial_ioctl(struct tty_struct *tty, struct file *file,
417 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200419 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 int retval = -ENODEV;
421
Harvey Harrison441b62c2008-03-03 16:08:34 -0800422 dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Alan Cox95da3102008-07-22 11:09:07 +0100424 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100426 /* pass on to the driver specific version of this function
427 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700428 if (port->serial->type->ioctl) {
Alan Cox95da3102008-07-22 11:09:07 +0100429 retval = port->serial->type->ioctl(tty, file, cmd, arg);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100430 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 return retval;
433}
434
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100435static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200437 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800438 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Alan Cox95da3102008-07-22 11:09:07 +0100440 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100441 /* pass on to the driver specific version of this function
442 if it is available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 if (port->serial->type->set_termios)
Alan Cox95da3102008-07-22 11:09:07 +0100444 port->serial->type->set_termios(tty, port, old);
Alan Cox33785092007-10-18 01:24:22 -0700445 else
446 tty_termios_copy_hw(tty->termios, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447}
448
Alan Cox9e989662008-07-22 11:18:03 +0100449static int serial_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200451 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
Harvey Harrison441b62c2008-03-03 16:08:34 -0800453 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
Alan Cox95da3102008-07-22 11:09:07 +0100455 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100456 /* pass on to the driver specific version of this function
457 if it is available */
Alan Cox6b447f042009-01-02 13:48:56 +0000458 if (port->serial->type->break_ctl)
Alan Cox95da3102008-07-22 11:09:07 +0100459 port->serial->type->break_ctl(tty, break_state);
Alan Cox9e989662008-07-22 11:18:03 +0100460 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461}
462
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700463static int serial_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464{
465 struct usb_serial *serial;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 char tmp[40];
468
Harvey Harrison441b62c2008-03-03 16:08:34 -0800469 dbg("%s", __func__);
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700470 seq_puts(m, "usbserinfo:1.0 driver:2.0\n");
471 for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 serial = usb_serial_get_by_index(i);
473 if (serial == NULL)
474 continue;
475
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700476 seq_printf(m, "%d:", i);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700477 if (serial->type->driver.owner)
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700478 seq_printf(m, " module:%s",
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100479 module_name(serial->type->driver.owner));
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700480 seq_printf(m, " name:\"%s\"",
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100481 serial->type->description);
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700482 seq_printf(m, " vendor:%04x product:%04x",
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100483 le16_to_cpu(serial->dev->descriptor.idVendor),
484 le16_to_cpu(serial->dev->descriptor.idProduct));
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700485 seq_printf(m, " num_ports:%d", serial->num_ports);
486 seq_printf(m, " port:%d", i - serial->minor + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 usb_make_path(serial->dev, tmp, sizeof(tmp));
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700488 seq_printf(m, " path:%s", tmp);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100489
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700490 seq_putc(m, '\n');
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200491 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 }
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700493 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494}
495
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -0700496static int serial_proc_open(struct inode *inode, struct file *file)
497{
498 return single_open(file, serial_proc_show, NULL);
499}
500
501static const struct file_operations serial_proc_fops = {
502 .owner = THIS_MODULE,
503 .open = serial_proc_open,
504 .read = seq_read,
505 .llseek = seq_lseek,
506 .release = single_release,
507};
508
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100509static int serial_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200511 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
Harvey Harrison441b62c2008-03-03 16:08:34 -0800513 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Alan Cox95da3102008-07-22 11:09:07 +0100515 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 if (port->serial->type->tiocmget)
Alan Cox95da3102008-07-22 11:09:07 +0100517 return port->serial->type->tiocmget(tty, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 return -EINVAL;
519}
520
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100521static int serial_tiocmset(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 unsigned int set, unsigned int clear)
523{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200524 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Harvey Harrison441b62c2008-03-03 16:08:34 -0800526 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Alan Cox95da3102008-07-22 11:09:07 +0100528 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 if (port->serial->type->tiocmset)
Alan Cox95da3102008-07-22 11:09:07 +0100530 return port->serial->type->tiocmset(tty, file, set, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return -EINVAL;
532}
533
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700534/*
535 * We would be calling tty_wakeup here, but unfortunately some line
536 * disciplines have an annoying habit of calling tty->write from
537 * the write wakeup callback (e.g. n_hdlc.c).
538 */
539void usb_serial_port_softint(struct usb_serial_port *port)
540{
541 schedule_work(&port->work);
542}
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100543EXPORT_SYMBOL_GPL(usb_serial_port_softint);
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700544
David Howellsc4028952006-11-22 14:57:56 +0000545static void usb_serial_port_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
David Howellsc4028952006-11-22 14:57:56 +0000547 struct usb_serial_port *port =
548 container_of(work, struct usb_serial_port, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 struct tty_struct *tty;
550
Harvey Harrison441b62c2008-03-03 16:08:34 -0800551 dbg("%s - port %d", __func__, port->number);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100552
Alan Cox4a90f092008-10-13 10:39:46 +0100553 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 if (!tty)
555 return;
556
557 tty_wakeup(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100558 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559}
560
561static void port_release(struct device *dev)
562{
563 struct usb_serial_port *port = to_usb_serial_port(dev);
564
Kay Sievers7071a3c2008-05-02 06:02:41 +0200565 dbg ("%s - %s", __func__, dev_name(dev));
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700566 port_free(port);
567}
568
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100569static void kill_traffic(struct usb_serial_port *port)
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700570{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 usb_kill_urb(port->write_urb);
Oliver Neukum5adceac2007-08-17 14:01:38 +0200573 /*
574 * This is tricky.
575 * Some drivers submit the read_urb in the
576 * handler for the write_urb or vice versa
577 * this order determines the order in which
578 * usb_kill_urb() must be used to reliably
579 * kill the URBs. As it is unknown here,
580 * both orders must be used in turn.
581 * The call below is not redundant.
582 */
583 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 usb_kill_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 usb_kill_urb(port->interrupt_out_urb);
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100586}
587
588static void port_free(struct usb_serial_port *port)
589{
Alan Stern2d931482009-04-14 11:31:02 -0400590 /*
591 * Stop all the traffic before cancelling the work, so that
592 * nobody will restart it by calling usb_serial_port_softint.
593 */
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100594 kill_traffic(port);
Alan Stern2d931482009-04-14 11:31:02 -0400595 cancel_work_sync(&port->work);
596
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100597 usb_free_urb(port->read_urb);
598 usb_free_urb(port->write_urb);
599 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 usb_free_urb(port->interrupt_out_urb);
601 kfree(port->bulk_in_buffer);
602 kfree(port->bulk_out_buffer);
603 kfree(port->interrupt_in_buffer);
604 kfree(port->interrupt_out_buffer);
605 kfree(port);
606}
607
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100608static struct usb_serial *create_serial(struct usb_device *dev,
609 struct usb_interface *interface,
610 struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
612 struct usb_serial *serial;
613
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100614 serial = kzalloc(sizeof(*serial), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if (!serial) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800616 dev_err(&dev->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 return NULL;
618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 serial->dev = usb_get_dev(dev);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700620 serial->type = driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 serial->interface = interface;
622 kref_init(&serial->kref);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +0100623 mutex_init(&serial->disc_mutex);
Alan Stern0282b7f2008-07-29 12:01:04 -0400624 serial->minor = SERIAL_TTY_NO_MINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626 return serial;
627}
628
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100629static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100630 struct usb_serial_driver *drv)
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100631{
632 struct usb_dynid *dynid;
633
634 spin_lock(&drv->dynids.lock);
635 list_for_each_entry(dynid, &drv->dynids.list, node) {
636 if (usb_match_one_id(intf, &dynid->id)) {
637 spin_unlock(&drv->dynids.lock);
638 return &dynid->id;
639 }
640 }
641 spin_unlock(&drv->dynids.lock);
642 return NULL;
643}
644
645static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
646 struct usb_interface *intf)
647{
648 const struct usb_device_id *id;
649
650 id = usb_match_id(intf, drv->id_table);
651 if (id) {
652 dbg("static descriptor matches");
653 goto exit;
654 }
655 id = match_dynamic_id(intf, drv);
656 if (id)
657 dbg("dynamic descriptor matches");
658exit:
659 return id;
660}
661
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100662static struct usb_serial_driver *search_serial_device(
663 struct usb_interface *iface)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 const struct usb_device_id *id;
Alan Stern063a2da2007-10-10 16:24:06 -0400666 struct usb_serial_driver *drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Adrian Bunk93b1fae2006-01-10 00:13:33 +0100668 /* Check if the usb id matches a known device */
Alan Stern063a2da2007-10-10 16:24:06 -0400669 list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
670 id = get_iface_id(drv, iface);
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100671 if (id)
Alan Stern063a2da2007-10-10 16:24:06 -0400672 return drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 }
674
675 return NULL;
676}
677
Alan Cox335f8512009-06-11 12:26:29 +0100678static int serial_carrier_raised(struct tty_port *port)
679{
680 struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
681 struct usb_serial_driver *drv = p->serial->type;
682 if (drv->carrier_raised)
683 return drv->carrier_raised(p);
684 /* No carrier control - don't block */
685 return 1;
686}
687
688static void serial_dtr_rts(struct tty_port *port, int on)
689{
690 struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
691 struct usb_serial_driver *drv = p->serial->type;
692 if (drv->dtr_rts)
693 drv->dtr_rts(p, on);
694}
695
696static const struct tty_port_operations serial_port_ops = {
697 .carrier_raised = serial_carrier_raised,
698 .dtr_rts = serial_dtr_rts,
699};
700
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701int usb_serial_probe(struct usb_interface *interface,
702 const struct usb_device_id *id)
703{
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100704 struct usb_device *dev = interface_to_usbdev(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 struct usb_serial *serial = NULL;
706 struct usb_serial_port *port;
707 struct usb_host_interface *iface_desc;
708 struct usb_endpoint_descriptor *endpoint;
709 struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
710 struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
711 struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
712 struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700713 struct usb_serial_driver *type = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 int retval;
Andre Hauptdd9ca5d2008-06-18 15:56:00 +0200715 unsigned int minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 int buffer_size;
717 int i;
718 int num_interrupt_in = 0;
719 int num_interrupt_out = 0;
720 int num_bulk_in = 0;
721 int num_bulk_out = 0;
722 int num_ports = 0;
723 int max_endpoints;
724
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100725 lock_kernel(); /* guard against unloading a serial driver module */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 type = search_serial_device(interface);
727 if (!type) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100728 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 dbg("none matched");
730 return -ENODEV;
731 }
732
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100733 serial = create_serial(dev, interface, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 if (!serial) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100735 unlock_kernel();
Harvey Harrison441b62c2008-03-03 16:08:34 -0800736 dev_err(&interface->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 return -ENOMEM;
738 }
739
740 /* if this device type has a probe function, call it */
741 if (type->probe) {
742 const struct usb_device_id *id;
743
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700744 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100745 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100746 dev_err(&interface->dev,
747 "module get failed, exiting\n");
748 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 return -EIO;
750 }
751
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100752 id = get_iface_id(type, interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 retval = type->probe(serial, id);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700754 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
756 if (retval) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100757 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100758 dbg("sub driver rejected device");
759 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return retval;
761 }
762 }
763
764 /* descriptor matches, let's find the endpoints needed */
765 /* check out the endpoints */
766 iface_desc = interface->cur_altsetting;
767 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
768 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700769
770 if (usb_endpoint_is_bulk_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 /* we found a bulk in endpoint */
772 dbg("found bulk in on endpoint %d", i);
773 bulk_in_endpoint[num_bulk_in] = endpoint;
774 ++num_bulk_in;
775 }
776
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700777 if (usb_endpoint_is_bulk_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 /* we found a bulk out endpoint */
779 dbg("found bulk out on endpoint %d", i);
780 bulk_out_endpoint[num_bulk_out] = endpoint;
781 ++num_bulk_out;
782 }
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700783
784 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 /* we found a interrupt in endpoint */
786 dbg("found interrupt in on endpoint %d", i);
787 interrupt_in_endpoint[num_interrupt_in] = endpoint;
788 ++num_interrupt_in;
789 }
790
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700791 if (usb_endpoint_is_int_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 /* we found an interrupt out endpoint */
793 dbg("found interrupt out on endpoint %d", i);
794 interrupt_out_endpoint[num_interrupt_out] = endpoint;
795 ++num_interrupt_out;
796 }
797 }
798
799#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100800 /* BEGIN HORRIBLE HACK FOR PL2303 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 /* this is needed due to the looney way its endpoints are set up */
802 if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
803 (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
804 ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
Johannes Steingraeber8fd80132006-09-16 16:17:34 +0200805 (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
806 ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
Andreas Bombece816cf2008-09-14 01:58:55 +0200807 (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) ||
808 ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
809 (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 if (interface != dev->actconfig->interface[0]) {
811 /* check out the endpoints of the other interface*/
812 iface_desc = dev->actconfig->interface[0]->cur_altsetting;
813 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
814 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700815 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 /* we found a interrupt in endpoint */
817 dbg("found interrupt in for Prolific device on separate interface");
818 interrupt_in_endpoint[num_interrupt_in] = endpoint;
819 ++num_interrupt_in;
820 }
821 }
822 }
823
824 /* Now make sure the PL-2303 is configured correctly.
825 * If not, give up now and hope this hack will work
826 * properly during a later invocation of usb_serial_probe
827 */
828 if (num_bulk_in == 0 || num_bulk_out == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100829 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100831 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 return -ENODEV;
833 }
834 }
835 /* END HORRIBLE HACK FOR PL2303 */
836#endif
837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838#ifdef CONFIG_USB_SERIAL_GENERIC
839 if (type == &usb_serial_generic_device) {
840 num_ports = num_bulk_out;
841 if (num_ports == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100842 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100843 dev_err(&interface->dev,
844 "Generic device with no bulk out, not allowed.\n");
845 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 return -EIO;
847 }
848 }
849#endif
850 if (!num_ports) {
851 /* if this device type has a calc_num_ports function, call it */
852 if (type->calc_num_ports) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700853 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100854 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100855 dev_err(&interface->dev,
856 "module get failed, exiting\n");
857 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 return -EIO;
859 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100860 num_ports = type->calc_num_ports(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700861 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 }
863 if (!num_ports)
864 num_ports = type->num_ports;
865 }
866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 serial->num_ports = num_ports;
868 serial->num_bulk_in = num_bulk_in;
869 serial->num_bulk_out = num_bulk_out;
870 serial->num_interrupt_in = num_interrupt_in;
871 serial->num_interrupt_out = num_interrupt_out;
872
Alan Stern063a2da2007-10-10 16:24:06 -0400873 /* found all that we need */
874 dev_info(&interface->dev, "%s converter detected\n",
875 type->description);
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 /* create our ports, we need as many as the max endpoints */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100878 /* we don't use num_ports here because some devices have more
879 endpoint pairs than ports */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 max_endpoints = max(num_bulk_in, num_bulk_out);
881 max_endpoints = max(max_endpoints, num_interrupt_in);
882 max_endpoints = max(max_endpoints, num_interrupt_out);
883 max_endpoints = max(max_endpoints, (int)serial->num_ports);
884 serial->num_port_pointers = max_endpoints;
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100885 unlock_kernel();
886
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100887 dbg("%s - setting up %d port structures for this device",
888 __func__, max_endpoints);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 for (i = 0; i < max_endpoints; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100890 port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 if (!port)
892 goto probe_error;
Alan Cox4a90f092008-10-13 10:39:46 +0100893 tty_port_init(&port->port);
Alan Cox335f8512009-06-11 12:26:29 +0100894 port->port.ops = &serial_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 port->serial = serial;
Greg Kroah-Hartman507ca9b2005-04-23 12:49:16 -0700896 spin_lock_init(&port->lock);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300897 mutex_init(&port->mutex);
David Howellsc4028952006-11-22 14:57:56 +0000898 INIT_WORK(&port->work, usb_serial_port_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 serial->port[i] = port;
900 }
901
902 /* set up the endpoint information */
903 for (i = 0; i < num_bulk_in; ++i) {
904 endpoint = bulk_in_endpoint[i];
905 port = serial->port[i];
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100906 port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 if (!port->read_urb) {
908 dev_err(&interface->dev, "No free urbs available\n");
909 goto probe_error;
910 }
911 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
912 port->bulk_in_size = buffer_size;
913 port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100914 port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 if (!port->bulk_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100916 dev_err(&interface->dev,
917 "Couldn't allocate bulk_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 goto probe_error;
919 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100920 usb_fill_bulk_urb(port->read_urb, dev,
921 usb_rcvbulkpipe(dev,
922 endpoint->bEndpointAddress),
923 port->bulk_in_buffer, buffer_size,
924 serial->type->read_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
926
927 for (i = 0; i < num_bulk_out; ++i) {
928 endpoint = bulk_out_endpoint[i];
929 port = serial->port[i];
930 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
931 if (!port->write_urb) {
932 dev_err(&interface->dev, "No free urbs available\n");
933 goto probe_error;
934 }
935 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
936 port->bulk_out_size = buffer_size;
937 port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100938 port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 if (!port->bulk_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100940 dev_err(&interface->dev,
941 "Couldn't allocate bulk_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 goto probe_error;
943 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100944 usb_fill_bulk_urb(port->write_urb, dev,
945 usb_sndbulkpipe(dev,
946 endpoint->bEndpointAddress),
947 port->bulk_out_buffer, buffer_size,
948 serial->type->write_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 }
950
951 if (serial->type->read_int_callback) {
952 for (i = 0; i < num_interrupt_in; ++i) {
953 endpoint = interrupt_in_endpoint[i];
954 port = serial->port[i];
955 port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
956 if (!port->interrupt_in_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100957 dev_err(&interface->dev,
958 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 goto probe_error;
960 }
961 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100962 port->interrupt_in_endpointAddress =
963 endpoint->bEndpointAddress;
964 port->interrupt_in_buffer = kmalloc(buffer_size,
965 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 if (!port->interrupt_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100967 dev_err(&interface->dev,
968 "Couldn't allocate interrupt_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 goto probe_error;
970 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100971 usb_fill_int_urb(port->interrupt_in_urb, dev,
972 usb_rcvintpipe(dev,
973 endpoint->bEndpointAddress),
974 port->interrupt_in_buffer, buffer_size,
975 serial->type->read_int_callback, port,
976 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 }
978 } else if (num_interrupt_in) {
979 dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
980 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (serial->type->write_int_callback) {
983 for (i = 0; i < num_interrupt_out; ++i) {
984 endpoint = interrupt_out_endpoint[i];
985 port = serial->port[i];
986 port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
987 if (!port->interrupt_out_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100988 dev_err(&interface->dev,
989 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 goto probe_error;
991 }
992 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
993 port->interrupt_out_size = buffer_size;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100994 port->interrupt_out_endpointAddress =
995 endpoint->bEndpointAddress;
996 port->interrupt_out_buffer = kmalloc(buffer_size,
997 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (!port->interrupt_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100999 dev_err(&interface->dev,
1000 "Couldn't allocate interrupt_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 goto probe_error;
1002 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001003 usb_fill_int_urb(port->interrupt_out_urb, dev,
1004 usb_sndintpipe(dev,
1005 endpoint->bEndpointAddress),
1006 port->interrupt_out_buffer, buffer_size,
1007 serial->type->write_int_callback, port,
1008 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 }
1010 } else if (num_interrupt_out) {
1011 dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
1012 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 /* if this device type has an attach function, call it */
1015 if (type->attach) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -07001016 if (!try_module_get(type->driver.owner)) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001017 dev_err(&interface->dev,
1018 "module get failed, exiting\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 goto probe_error;
1020 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001021 retval = type->attach(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -07001022 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 if (retval < 0)
1024 goto probe_error;
1025 if (retval > 0) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001026 /* quietly accept this device, but don't bind to a
1027 serial port as it's about to disappear */
Alan Stern0a3c8542009-05-27 11:25:52 -04001028 serial->num_ports = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 goto exit;
1030 }
1031 }
1032
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001033 if (get_free_serial(serial, num_ports, &minor) == NULL) {
Oliver Neukum34ef50e2007-01-13 07:29:26 +01001034 dev_err(&interface->dev, "No more free serial devices\n");
1035 goto probe_error;
1036 }
Oliver Neukumc744f992007-02-26 15:43:00 +01001037 serial->minor = minor;
Oliver Neukum34ef50e2007-01-13 07:29:26 +01001038
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 /* register all of the individual ports with the driver core */
1040 for (i = 0; i < num_ports; ++i) {
1041 port = serial->port[i];
1042 port->dev.parent = &interface->dev;
1043 port->dev.driver = NULL;
1044 port->dev.bus = &usb_serial_bus_type;
1045 port->dev.release = &port_release;
1046
Kay Sievers0031a062008-05-02 06:02:41 +02001047 dev_set_name(&port->dev, "ttyUSB%d", port->number);
Kay Sievers7071a3c2008-05-02 06:02:41 +02001048 dbg ("%s - registering %s", __func__, dev_name(&port->dev));
Alan Sternc706ebd2009-06-02 11:54:11 -04001049 port->dev_state = PORT_REGISTERING;
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -07001050 retval = device_register(&port->dev);
Alan Sternc706ebd2009-06-02 11:54:11 -04001051 if (retval) {
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -07001052 dev_err(&port->dev, "Error registering port device, "
1053 "continuing\n");
Alan Sternc706ebd2009-06-02 11:54:11 -04001054 port->dev_state = PORT_UNREGISTERED;
1055 } else {
1056 port->dev_state = PORT_REGISTERED;
1057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
1059
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001060 usb_serial_console_init(debug, minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
1062exit:
1063 /* success */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001064 usb_set_intfdata(interface, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 return 0;
1066
1067probe_error:
1068 for (i = 0; i < num_bulk_in; ++i) {
1069 port = serial->port[i];
1070 if (!port)
1071 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001072 usb_free_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 kfree(port->bulk_in_buffer);
1074 }
1075 for (i = 0; i < num_bulk_out; ++i) {
1076 port = serial->port[i];
1077 if (!port)
1078 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001079 usb_free_urb(port->write_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 kfree(port->bulk_out_buffer);
1081 }
1082 for (i = 0; i < num_interrupt_in; ++i) {
1083 port = serial->port[i];
1084 if (!port)
1085 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001086 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 kfree(port->interrupt_in_buffer);
1088 }
1089 for (i = 0; i < num_interrupt_out; ++i) {
1090 port = serial->port[i];
1091 if (!port)
1092 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001093 usb_free_urb(port->interrupt_out_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 kfree(port->interrupt_out_buffer);
1095 }
1096
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 /* free up any memory that we allocated */
1098 for (i = 0; i < serial->num_port_pointers; ++i)
1099 kfree(serial->port[i]);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001100 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 return -EIO;
1102}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001103EXPORT_SYMBOL_GPL(usb_serial_probe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105void usb_serial_disconnect(struct usb_interface *interface)
1106{
1107 int i;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001108 struct usb_serial *serial = usb_get_intfdata(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 struct device *dev = &interface->dev;
1110 struct usb_serial_port *port;
1111
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +02001112 usb_serial_console_disconnect(serial);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001113 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001115 mutex_lock(&serial->disc_mutex);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001116 usb_set_intfdata(interface, NULL);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001117 /* must set a flag, to signal subdrivers */
1118 serial->disconnected = 1;
Alan Stern2d931482009-04-14 11:31:02 -04001119 mutex_unlock(&serial->disc_mutex);
1120
1121 /* Unfortunately, many of the sub-drivers expect the port structures
1122 * to exist when their shutdown method is called, so we have to go
1123 * through this awkward two-step unregistration procedure.
1124 */
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001125 for (i = 0; i < serial->num_ports; ++i) {
1126 port = serial->port[i];
1127 if (port) {
Alan Cox4a90f092008-10-13 10:39:46 +01001128 struct tty_struct *tty = tty_port_tty_get(&port->port);
1129 if (tty) {
Alan Cox335f8512009-06-11 12:26:29 +01001130 /* The hangup will occur asynchronously but
1131 the object refcounts will sort out all the
1132 cleanup */
Alan Cox4a90f092008-10-13 10:39:46 +01001133 tty_hangup(tty);
1134 tty_kref_put(tty);
1135 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001136 kill_traffic(port);
Alan Stern2d931482009-04-14 11:31:02 -04001137 cancel_work_sync(&port->work);
Alan Sternc706ebd2009-06-02 11:54:11 -04001138 if (port->dev_state == PORT_REGISTERED) {
1139
1140 /* Make sure the port is bound so that the
1141 * driver's port_remove method is called.
1142 */
1143 if (!port->dev.driver) {
1144 int rc;
1145
1146 port->dev.driver =
1147 &serial->type->driver;
1148 rc = device_bind_driver(&port->dev);
1149 }
1150 port->dev_state = PORT_UNREGISTERING;
1151 device_del(&port->dev);
1152 port->dev_state = PORT_UNREGISTERED;
1153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 }
Alan Stern2d931482009-04-14 11:31:02 -04001156 serial->type->shutdown(serial);
1157 for (i = 0; i < serial->num_ports; ++i) {
1158 port = serial->port[i];
1159 if (port) {
1160 put_device(&port->dev);
1161 serial->port[i] = NULL;
1162 }
1163 }
1164
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001165 /* let the last holder of this object
1166 * cause it to be cleaned up */
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001167 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 dev_info(dev, "device disconnected\n");
1169}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001170EXPORT_SYMBOL_GPL(usb_serial_disconnect);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
Oliver Neukumec225592007-04-27 20:54:57 +02001172int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1173{
1174 struct usb_serial *serial = usb_get_intfdata(intf);
1175 struct usb_serial_port *port;
1176 int i, r = 0;
1177
Oliver Neukumf8bece82009-02-05 16:54:25 +01001178 serial->suspending = 1;
1179
Oliver Neukume31c1882007-07-23 08:58:39 +02001180 for (i = 0; i < serial->num_ports; ++i) {
1181 port = serial->port[i];
1182 if (port)
1183 kill_traffic(port);
Oliver Neukumec225592007-04-27 20:54:57 +02001184 }
1185
1186 if (serial->type->suspend)
Oliver Neukume31c1882007-07-23 08:58:39 +02001187 r = serial->type->suspend(serial, message);
Oliver Neukumec225592007-04-27 20:54:57 +02001188
1189 return r;
1190}
1191EXPORT_SYMBOL(usb_serial_suspend);
1192
1193int usb_serial_resume(struct usb_interface *intf)
1194{
1195 struct usb_serial *serial = usb_get_intfdata(intf);
Oliver Neukumc49cfa912009-02-06 18:06:43 +01001196 int rv;
Oliver Neukumec225592007-04-27 20:54:57 +02001197
Oliver Neukumf8bece82009-02-05 16:54:25 +01001198 serial->suspending = 0;
Sarah Sharp8abaee22007-10-25 10:58:43 -07001199 if (serial->type->resume)
Oliver Neukumc49cfa912009-02-06 18:06:43 +01001200 rv = serial->type->resume(serial);
1201 else
1202 rv = usb_serial_generic_resume(serial);
Oliver Neukumf8bece82009-02-05 16:54:25 +01001203
Oliver Neukumc49cfa912009-02-06 18:06:43 +01001204 return rv;
Oliver Neukumec225592007-04-27 20:54:57 +02001205}
1206EXPORT_SYMBOL(usb_serial_resume);
1207
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001208static const struct tty_operations serial_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 .open = serial_open,
1210 .close = serial_close,
1211 .write = serial_write,
Alan Cox335f8512009-06-11 12:26:29 +01001212 .hangup = serial_hangup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 .write_room = serial_write_room,
1214 .ioctl = serial_ioctl,
1215 .set_termios = serial_set_termios,
1216 .throttle = serial_throttle,
1217 .unthrottle = serial_unthrottle,
1218 .break_ctl = serial_break,
1219 .chars_in_buffer = serial_chars_in_buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 .tiocmget = serial_tiocmget,
1221 .tiocmset = serial_tiocmset,
Alexey Dobriyan6fd69d32009-03-31 15:19:21 -07001222 .proc_fops = &serial_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223};
1224
Alan Cox335f8512009-06-11 12:26:29 +01001225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226struct tty_driver *usb_serial_tty_driver;
1227
1228static int __init usb_serial_init(void)
1229{
1230 int i;
1231 int result;
1232
1233 usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
1234 if (!usb_serial_tty_driver)
1235 return -ENOMEM;
1236
1237 /* Initialize our global data */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001238 for (i = 0; i < SERIAL_TTY_MINORS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 serial_table[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
1241 result = bus_register(&usb_serial_bus_type);
1242 if (result) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001243 printk(KERN_ERR "usb-serial: %s - registering bus driver "
1244 "failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 goto exit_bus;
1246 }
1247
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 usb_serial_tty_driver->owner = THIS_MODULE;
1249 usb_serial_tty_driver->driver_name = "usbserial";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 usb_serial_tty_driver->name = "ttyUSB";
1251 usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
1252 usb_serial_tty_driver->minor_start = 0;
1253 usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
1254 usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001255 usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
1256 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 usb_serial_tty_driver->init_termios = tty_std_termios;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001258 usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
1259 | HUPCL | CLOCAL;
Alan Coxa5b6f602008-04-08 17:16:06 +01001260 usb_serial_tty_driver->init_termios.c_ispeed = 9600;
1261 usb_serial_tty_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 tty_set_operations(usb_serial_tty_driver, &serial_ops);
1263 result = tty_register_driver(usb_serial_tty_driver);
1264 if (result) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001265 printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n",
1266 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 goto exit_reg_driver;
1268 }
1269
1270 /* register the USB driver */
1271 result = usb_register(&usb_serial_driver);
1272 if (result < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001273 printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
1274 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 goto exit_tty;
1276 }
1277
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001278 /* register the generic driver, if we should */
1279 result = usb_serial_generic_register(debug);
1280 if (result < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001281 printk(KERN_ERR "usb-serial: %s - registering generic "
1282 "driver failed\n", __func__);
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001283 goto exit_generic;
1284 }
1285
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001286 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
1288 return result;
1289
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001290exit_generic:
1291 usb_deregister(&usb_serial_driver);
1292
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293exit_tty:
1294 tty_unregister_driver(usb_serial_tty_driver);
1295
1296exit_reg_driver:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 bus_unregister(&usb_serial_bus_type);
1298
1299exit_bus:
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001300 printk(KERN_ERR "usb-serial: %s - returning with error %d\n",
1301 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 put_tty_driver(usb_serial_tty_driver);
1303 return result;
1304}
1305
1306
1307static void __exit usb_serial_exit(void)
1308{
1309 usb_serial_console_exit();
1310
1311 usb_serial_generic_deregister();
1312
1313 usb_deregister(&usb_serial_driver);
1314 tty_unregister_driver(usb_serial_tty_driver);
1315 put_tty_driver(usb_serial_tty_driver);
1316 bus_unregister(&usb_serial_bus_type);
1317}
1318
1319
1320module_init(usb_serial_init);
1321module_exit(usb_serial_exit);
1322
1323#define set_to_generic_if_null(type, function) \
1324 do { \
1325 if (!type->function) { \
1326 type->function = usb_serial_generic_##function; \
1327 dbg("Had to override the " #function \
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001328 " usb serial operation with the generic one.");\
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 } \
1330 } while (0)
1331
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001332static void fixup_generic(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333{
1334 set_to_generic_if_null(device, open);
1335 set_to_generic_if_null(device, write);
1336 set_to_generic_if_null(device, close);
1337 set_to_generic_if_null(device, write_room);
1338 set_to_generic_if_null(device, chars_in_buffer);
1339 set_to_generic_if_null(device, read_bulk_callback);
1340 set_to_generic_if_null(device, write_bulk_callback);
1341 set_to_generic_if_null(device, shutdown);
1342}
1343
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001344int usb_serial_register(struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001346 /* must be called with BKL held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 int retval;
1348
Dave Younge4abe662009-02-14 21:21:13 +08001349 if (usb_disabled())
1350 return -ENODEV;
1351
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001352 fixup_generic(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001354 if (!driver->description)
1355 driver->description = driver->driver.name;
1356
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 /* Add this device to our list of devices */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001358 list_add(&driver->driver_list, &usb_serial_driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001360 retval = usb_serial_bus_register(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 if (retval) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001362 printk(KERN_ERR "usb-serial: problem %d when registering "
1363 "driver %s\n", retval, driver->description);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001364 list_del(&driver->driver_list);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001365 } else
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001366 printk(KERN_INFO "USB Serial support registered for %s\n",
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001367 driver->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369 return retval;
1370}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001371EXPORT_SYMBOL_GPL(usb_serial_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
1373
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001374void usb_serial_deregister(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001376 /* must be called with BKL held */
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001377 printk(KERN_INFO "USB Serial deregistering driver %s\n",
1378 device->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 list_del(&device->driver_list);
1380 usb_serial_bus_deregister(device);
1381}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382EXPORT_SYMBOL_GPL(usb_serial_deregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
1384/* Module information */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001385MODULE_AUTHOR(DRIVER_AUTHOR);
1386MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387MODULE_LICENSE("GPL");
1388
1389module_param(debug, bool, S_IRUGO | S_IWUSR);
1390MODULE_PARM_DESC(debug, "Debug enabled or not");