blob: b157c48e8b78df594bd0386f5ff38a725cf18929 [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>
29#include <linux/spinlock.h>
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -030030#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/list.h>
Alan Coxa8d6f0a2008-07-22 11:12:24 +010032#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070034#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include "pl2303.h"
36
37/*
38 * Version Information
39 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
41#define DRIVER_DESC "USB Serial Driver core"
42
Pete Zaitcev34f8e762006-06-21 15:00:45 -070043static void port_free(struct usb_serial_port *port);
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045/* Driver structure we register with the USB core */
46static struct usb_driver usb_serial_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 .name = "usbserial",
48 .probe = usb_serial_probe,
49 .disconnect = usb_serial_disconnect,
Oliver Neukumec225592007-04-27 20:54:57 +020050 .suspend = usb_serial_suspend,
51 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -080052 .no_dynamic_id = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -070053};
54
55/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
56 the MODULE_DEVICE_TABLE declarations in each serial driver
57 cause the "hotplug" program to pull in whatever module is necessary
58 via modprobe, and modprobe will load usbserial because the serial
59 drivers depend on it.
60*/
61
62static int debug;
Alan Coxa8d6f0a2008-07-22 11:12:24 +010063/* initially all NULL */
64static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
Oliver Neukum3ddad822007-07-24 15:13:42 +020065static DEFINE_MUTEX(table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066static LIST_HEAD(usb_serial_driver_list);
67
68struct usb_serial *usb_serial_get_by_index(unsigned index)
69{
Oliver Neukum34ef50e2007-01-13 07:29:26 +010070 struct usb_serial *serial;
71
Oliver Neukum3ddad822007-07-24 15:13:42 +020072 mutex_lock(&table_lock);
Oliver Neukum34ef50e2007-01-13 07:29:26 +010073 serial = serial_table[index];
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
75 if (serial)
76 kref_get(&serial->kref);
Oliver Neukum3ddad822007-07-24 15:13:42 +020077 mutex_unlock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 return serial;
79}
80
Alan Coxa8d6f0a2008-07-22 11:12:24 +010081static struct usb_serial *get_free_serial(struct usb_serial *serial,
82 int num_ports, unsigned int *minor)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083{
84 unsigned int i, j;
85 int good_spot;
86
Harvey Harrison441b62c2008-03-03 16:08:34 -080087 dbg("%s %d", __func__, num_ports);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89 *minor = 0;
Oliver Neukum3ddad822007-07-24 15:13:42 +020090 mutex_lock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
92 if (serial_table[i])
93 continue;
94
95 good_spot = 1;
96 for (j = 1; j <= num_ports-1; ++j)
97 if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) {
98 good_spot = 0;
99 i += j;
100 break;
101 }
102 if (good_spot == 0)
103 continue;
104
105 *minor = i;
Oliver Neukuma1f721c2007-03-05 15:23:51 +0100106 j = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800107 dbg("%s - minor base = %d", __func__, *minor);
Oliver Neukuma1f721c2007-03-05 15:23:51 +0100108 for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 serial_table[i] = serial;
Oliver Neukuma1f721c2007-03-05 15:23:51 +0100110 serial->port[j++]->number = i;
111 }
Oliver Neukum3ddad822007-07-24 15:13:42 +0200112 mutex_unlock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 return serial;
114 }
Oliver Neukum3ddad822007-07-24 15:13:42 +0200115 mutex_unlock(&table_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 return NULL;
117}
118
119static void return_serial(struct usb_serial *serial)
120{
121 int i;
122
Harvey Harrison441b62c2008-03-03 16:08:34 -0800123 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100125 for (i = 0; i < serial->num_ports; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 serial_table[serial->minor + i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
128
129static void destroy_serial(struct kref *kref)
130{
131 struct usb_serial *serial;
132 struct usb_serial_port *port;
133 int i;
134
135 serial = to_usb_serial(kref);
136
Harvey Harrison441b62c2008-03-03 16:08:34 -0800137 dbg("%s - %s", __func__, serial->type->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Jim Radford521b85a2007-03-13 08:30:50 -0700139 serial->type->shutdown(serial);
140
141 /* return the minor range that this device had */
Alan Stern0282b7f2008-07-29 12:01:04 -0400142 if (serial->minor != SERIAL_TTY_NO_MINOR)
143 return_serial(serial);
Jim Radford521b85a2007-03-13 08:30:50 -0700144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 for (i = 0; i < serial->num_ports; ++i)
Alan Cox95da3102008-07-22 11:09:07 +0100146 serial->port[i]->port.count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148 /* the ports are cleaned up and released in port_release() */
149 for (i = 0; i < serial->num_ports; ++i)
150 if (serial->port[i]->dev.parent != NULL) {
151 device_unregister(&serial->port[i]->dev);
152 serial->port[i] = NULL;
153 }
154
155 /* If this is a "fake" port, we have to clean it up here, as it will
156 * not get cleaned up in port_release() as it was never registered with
157 * the driver core */
158 if (serial->num_ports < serial->num_port_pointers) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100159 for (i = serial->num_ports;
160 i < serial->num_port_pointers; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 port = serial->port[i];
162 if (!port)
163 continue;
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700164 port_free(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 }
166 }
167
168 usb_put_dev(serial->dev);
169
170 /* free up any memory that we allocated */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100171 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172}
173
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200174void usb_serial_put(struct usb_serial *serial)
175{
Oliver Neukum3ddad822007-07-24 15:13:42 +0200176 mutex_lock(&table_lock);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200177 kref_put(&serial->kref, destroy_serial);
Oliver Neukum3ddad822007-07-24 15:13:42 +0200178 mutex_unlock(&table_lock);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200179}
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181/*****************************************************************************
182 * Driver tty interface functions
183 *****************************************************************************/
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100184static int serial_open (struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
186 struct usb_serial *serial;
187 struct usb_serial_port *port;
188 unsigned int portNumber;
189 int retval;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100190
Harvey Harrison441b62c2008-03-03 16:08:34 -0800191 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
193 /* get the serial object associated with this tty pointer */
194 serial = usb_serial_get_by_index(tty->index);
195 if (!serial) {
196 tty->driver_data = NULL;
197 return -ENODEV;
198 }
199
200 portNumber = tty->index - serial->minor;
201 port = serial->port[portNumber];
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300202 if (!port) {
203 retval = -ENODEV;
204 goto bailout_kref_put;
205 }
Luiz Fernando Capitulino8a4613f2005-11-28 19:16:07 -0200206
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300207 if (mutex_lock_interruptible(&port->mutex)) {
208 retval = -ERESTARTSYS;
209 goto bailout_kref_put;
210 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100211
Alan Cox95da3102008-07-22 11:09:07 +0100212 ++port->port.count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Paul Fulghumca854852006-04-13 22:28:17 +0200214 /* set up our port structure making the tty driver
215 * remember our port object, and us it */
216 tty->driver_data = port;
Alan Cox95da3102008-07-22 11:09:07 +0100217 port->port.tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Alan Cox95da3102008-07-22 11:09:07 +0100219 if (port->port.count == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221 /* lock this module before we call it
222 * this may fail, which means we must bail out,
223 * safe because we are called with BKL held */
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700224 if (!try_module_get(serial->type->driver.owner)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 retval = -ENODEV;
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300226 goto bailout_mutex_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 }
228
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800229 retval = usb_autopm_get_interface(serial->interface);
230 if (retval)
231 goto bailout_module_put;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100232 /* only call the device specific open if this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 * is the first time the port is opened */
Alan Cox95da3102008-07-22 11:09:07 +0100234 retval = serial->type->open(tty, port, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 if (retval)
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800236 goto bailout_interface_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 }
238
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300239 mutex_unlock(&port->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 return 0;
241
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800242bailout_interface_put:
243 usb_autopm_put_interface(serial->interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244bailout_module_put:
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700245 module_put(serial->type->driver.owner);
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300246bailout_mutex_unlock:
Alan Cox95da3102008-07-22 11:09:07 +0100247 port->port.count = 0;
Frank Gevaertsb059c812006-06-14 15:52:05 +0200248 tty->driver_data = NULL;
Alan Cox95da3102008-07-22 11:09:07 +0100249 port->port.tty = NULL;
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300250 mutex_unlock(&port->mutex);
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300251bailout_kref_put:
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200252 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 return retval;
254}
255
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100256static void serial_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200258 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260 if (!port)
261 return;
262
Harvey Harrison441b62c2008-03-03 16:08:34 -0800263 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300265 mutex_lock(&port->mutex);
Luiz Fernando Capitulino8a4613f2005-11-28 19:16:07 -0200266
Alan Cox95da3102008-07-22 11:09:07 +0100267 if (port->port.count == 0) {
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300268 mutex_unlock(&port->mutex);
Greg Kroah-Hartman91c0bce2006-03-06 13:25:52 -0800269 return;
270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Alan Cox95da3102008-07-22 11:09:07 +0100272 --port->port.count;
273 if (port->port.count == 0)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100274 /* only call the device specific close if this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 * port is being closed by the last owner */
Alan Cox95da3102008-07-22 11:09:07 +0100276 port->serial->type->close(tty, port, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Alan Cox95da3102008-07-22 11:09:07 +0100278 if (port->port.count == (port->console? 1 : 0)) {
279 if (port->port.tty) {
280 if (port->port.tty->driver_data)
281 port->port.tty->driver_data = NULL;
282 port->port.tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 }
285
Alan Cox95da3102008-07-22 11:09:07 +0100286 if (port->port.count == 0) {
Oliver Neukum62ad2962008-06-25 13:32:49 +0200287 mutex_lock(&port->serial->disc_mutex);
288 if (!port->serial->disconnected)
289 usb_autopm_put_interface(port->serial->interface);
290 mutex_unlock(&port->serial->disc_mutex);
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500291 module_put(port->serial->type->driver.owner);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800292 }
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500293
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300294 mutex_unlock(&port->mutex);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200295 usb_serial_put(port->serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100298static int serial_write(struct tty_struct *tty, const unsigned char *buf,
299 int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200301 struct usb_serial_port *port = tty->driver_data;
Oliver Neukum3ff4fd92007-01-13 07:32:27 +0100302 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Alan Coxf34d7a52008-04-30 00:54:13 -0700304 if (port->serial->dev->state == USB_STATE_NOTATTACHED)
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200305 goto exit;
306
Harvey Harrison441b62c2008-03-03 16:08:34 -0800307 dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Alan Cox95da3102008-07-22 11:09:07 +0100309 /* count is managed under the mutex lock for the tty so cannot
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100310 drop to zero until after the last close completes */
Alan Cox95da3102008-07-22 11:09:07 +0100311 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100314 retval = port->serial->type->write(tty, port, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316exit:
317 return retval;
318}
319
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100320static int serial_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200322 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800323 dbg("%s - port %d", __func__, port->number);
Alan Cox95da3102008-07-22 11:09:07 +0100324 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100326 return port->serial->type->write_room(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100329static int serial_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200331 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800332 dbg("%s = port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Alan Cox95da3102008-07-22 11:09:07 +0100334 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100336 return port->serial->type->chars_in_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337}
338
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100339static void serial_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200341 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800342 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Alan Cox95da3102008-07-22 11:09:07 +0100344 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 /* pass on to the driver specific version of this function */
346 if (port->serial->type->throttle)
Alan Cox95da3102008-07-22 11:09:07 +0100347 port->serial->type->throttle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348}
349
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100350static void serial_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200352 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800353 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Alan Cox95da3102008-07-22 11:09:07 +0100355 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 /* pass on to the driver specific version of this function */
357 if (port->serial->type->unthrottle)
Alan Cox95da3102008-07-22 11:09:07 +0100358 port->serial->type->unthrottle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100361static int serial_ioctl(struct tty_struct *tty, struct file *file,
362 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200364 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 int retval = -ENODEV;
366
Harvey Harrison441b62c2008-03-03 16:08:34 -0800367 dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Alan Cox95da3102008-07-22 11:09:07 +0100369 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100371 /* pass on to the driver specific version of this function
372 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700373 if (port->serial->type->ioctl) {
374 lock_kernel();
Alan Cox95da3102008-07-22 11:09:07 +0100375 retval = port->serial->type->ioctl(tty, file, cmd, arg);
Alan Coxf34d7a52008-04-30 00:54:13 -0700376 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100377 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 return retval;
380}
381
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100382static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200384 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800385 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Alan Cox95da3102008-07-22 11:09:07 +0100387 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100388 /* pass on to the driver specific version of this function
389 if it is available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 if (port->serial->type->set_termios)
Alan Cox95da3102008-07-22 11:09:07 +0100391 port->serial->type->set_termios(tty, port, old);
Alan Cox33785092007-10-18 01:24:22 -0700392 else
393 tty_termios_copy_hw(tty->termios, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394}
395
Alan Cox9e989662008-07-22 11:18:03 +0100396static int serial_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200398 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
Harvey Harrison441b62c2008-03-03 16:08:34 -0800400 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Alan Cox95da3102008-07-22 11:09:07 +0100402 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100403 /* pass on to the driver specific version of this function
404 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700405 if (port->serial->type->break_ctl) {
406 lock_kernel();
Alan Cox95da3102008-07-22 11:09:07 +0100407 port->serial->type->break_ctl(tty, break_state);
Alan Coxf34d7a52008-04-30 00:54:13 -0700408 unlock_kernel();
409 }
Alan Cox9e989662008-07-22 11:18:03 +0100410 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411}
412
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100413static int serial_read_proc(char *page, char **start, off_t off, int count,
414 int *eof, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 struct usb_serial *serial;
417 int length = 0;
418 int i;
419 off_t begin = 0;
420 char tmp[40];
421
Harvey Harrison441b62c2008-03-03 16:08:34 -0800422 dbg("%s", __func__);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100423 length += sprintf(page, "usbserinfo:1.0 driver:2.0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
425 serial = usb_serial_get_by_index(i);
426 if (serial == NULL)
427 continue;
428
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100429 length += sprintf(page+length, "%d:", i);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700430 if (serial->type->driver.owner)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100431 length += sprintf(page+length, " module:%s",
432 module_name(serial->type->driver.owner));
433 length += sprintf(page+length, " name:\"%s\"",
434 serial->type->description);
435 length += sprintf(page+length, " vendor:%04x product:%04x",
436 le16_to_cpu(serial->dev->descriptor.idVendor),
437 le16_to_cpu(serial->dev->descriptor.idProduct));
438 length += sprintf(page+length, " num_ports:%d",
439 serial->num_ports);
440 length += sprintf(page+length, " port:%d",
441 i - serial->minor + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 usb_make_path(serial->dev, tmp, sizeof(tmp));
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100443 length += sprintf(page+length, " path:%s", tmp);
444
445 length += sprintf(page+length, "\n");
Matthias Urlichs59925832006-09-11 12:35:20 +0200446 if ((length + begin) > (off + count)) {
447 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 goto done;
Matthias Urlichs59925832006-09-11 12:35:20 +0200449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 if ((length + begin) < off) {
451 begin += length;
452 length = 0;
453 }
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200454 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 }
456 *eof = 1;
457done:
458 if (off >= (length + begin))
459 return 0;
460 *start = page + (off-begin);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100461 return (count < begin+length-off) ? count : begin+length-off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462}
463
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100464static int serial_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200466 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Harvey Harrison441b62c2008-03-03 16:08:34 -0800468 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Alan Cox95da3102008-07-22 11:09:07 +0100470 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 if (port->serial->type->tiocmget)
Alan Cox95da3102008-07-22 11:09:07 +0100472 return port->serial->type->tiocmget(tty, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 return -EINVAL;
474}
475
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100476static int serial_tiocmset(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 unsigned int set, unsigned int clear)
478{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200479 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Harvey Harrison441b62c2008-03-03 16:08:34 -0800481 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Alan Cox95da3102008-07-22 11:09:07 +0100483 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 if (port->serial->type->tiocmset)
Alan Cox95da3102008-07-22 11:09:07 +0100485 return port->serial->type->tiocmset(tty, file, set, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 return -EINVAL;
487}
488
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700489/*
490 * We would be calling tty_wakeup here, but unfortunately some line
491 * disciplines have an annoying habit of calling tty->write from
492 * the write wakeup callback (e.g. n_hdlc.c).
493 */
494void usb_serial_port_softint(struct usb_serial_port *port)
495{
496 schedule_work(&port->work);
497}
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100498EXPORT_SYMBOL_GPL(usb_serial_port_softint);
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700499
David Howellsc4028952006-11-22 14:57:56 +0000500static void usb_serial_port_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
David Howellsc4028952006-11-22 14:57:56 +0000502 struct usb_serial_port *port =
503 container_of(work, struct usb_serial_port, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 struct tty_struct *tty;
505
Harvey Harrison441b62c2008-03-03 16:08:34 -0800506 dbg("%s - port %d", __func__, port->number);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 if (!port)
509 return;
510
Alan Cox95da3102008-07-22 11:09:07 +0100511 tty = port->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (!tty)
513 return;
514
515 tty_wakeup(tty);
516}
517
518static void port_release(struct device *dev)
519{
520 struct usb_serial_port *port = to_usb_serial_port(dev);
521
Kay Sievers7071a3c2008-05-02 06:02:41 +0200522 dbg ("%s - %s", __func__, dev_name(dev));
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700523 port_free(port);
524}
525
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100526static void kill_traffic(struct usb_serial_port *port)
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700527{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 usb_kill_urb(port->write_urb);
Oliver Neukum5adceac2007-08-17 14:01:38 +0200530 /*
531 * This is tricky.
532 * Some drivers submit the read_urb in the
533 * handler for the write_urb or vice versa
534 * this order determines the order in which
535 * usb_kill_urb() must be used to reliably
536 * kill the URBs. As it is unknown here,
537 * both orders must be used in turn.
538 * The call below is not redundant.
539 */
540 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 usb_kill_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 usb_kill_urb(port->interrupt_out_urb);
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100543}
544
545static void port_free(struct usb_serial_port *port)
546{
547 kill_traffic(port);
548 usb_free_urb(port->read_urb);
549 usb_free_urb(port->write_urb);
550 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 usb_free_urb(port->interrupt_out_urb);
552 kfree(port->bulk_in_buffer);
553 kfree(port->bulk_out_buffer);
554 kfree(port->interrupt_in_buffer);
555 kfree(port->interrupt_out_buffer);
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700556 flush_scheduled_work(); /* port->work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 kfree(port);
558}
559
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100560static struct usb_serial *create_serial(struct usb_device *dev,
561 struct usb_interface *interface,
562 struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
564 struct usb_serial *serial;
565
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100566 serial = kzalloc(sizeof(*serial), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 if (!serial) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800568 dev_err(&dev->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 return NULL;
570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 serial->dev = usb_get_dev(dev);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700572 serial->type = driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 serial->interface = interface;
574 kref_init(&serial->kref);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +0100575 mutex_init(&serial->disc_mutex);
Alan Stern0282b7f2008-07-29 12:01:04 -0400576 serial->minor = SERIAL_TTY_NO_MINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 return serial;
579}
580
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100581static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100582 struct usb_serial_driver *drv)
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100583{
584 struct usb_dynid *dynid;
585
586 spin_lock(&drv->dynids.lock);
587 list_for_each_entry(dynid, &drv->dynids.list, node) {
588 if (usb_match_one_id(intf, &dynid->id)) {
589 spin_unlock(&drv->dynids.lock);
590 return &dynid->id;
591 }
592 }
593 spin_unlock(&drv->dynids.lock);
594 return NULL;
595}
596
597static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
598 struct usb_interface *intf)
599{
600 const struct usb_device_id *id;
601
602 id = usb_match_id(intf, drv->id_table);
603 if (id) {
604 dbg("static descriptor matches");
605 goto exit;
606 }
607 id = match_dynamic_id(intf, drv);
608 if (id)
609 dbg("dynamic descriptor matches");
610exit:
611 return id;
612}
613
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100614static struct usb_serial_driver *search_serial_device(
615 struct usb_interface *iface)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 const struct usb_device_id *id;
Alan Stern063a2da2007-10-10 16:24:06 -0400618 struct usb_serial_driver *drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Adrian Bunk93b1fae2006-01-10 00:13:33 +0100620 /* Check if the usb id matches a known device */
Alan Stern063a2da2007-10-10 16:24:06 -0400621 list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
622 id = get_iface_id(drv, iface);
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100623 if (id)
Alan Stern063a2da2007-10-10 16:24:06 -0400624 return drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 }
626
627 return NULL;
628}
629
630int usb_serial_probe(struct usb_interface *interface,
631 const struct usb_device_id *id)
632{
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100633 struct usb_device *dev = interface_to_usbdev(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 struct usb_serial *serial = NULL;
635 struct usb_serial_port *port;
636 struct usb_host_interface *iface_desc;
637 struct usb_endpoint_descriptor *endpoint;
638 struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
639 struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
640 struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
641 struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700642 struct usb_serial_driver *type = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 int retval;
Andre Hauptdd9ca5d2008-06-18 15:56:00 +0200644 unsigned int minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 int buffer_size;
646 int i;
647 int num_interrupt_in = 0;
648 int num_interrupt_out = 0;
649 int num_bulk_in = 0;
650 int num_bulk_out = 0;
651 int num_ports = 0;
652 int max_endpoints;
653
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100654 lock_kernel(); /* guard against unloading a serial driver module */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 type = search_serial_device(interface);
656 if (!type) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100657 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 dbg("none matched");
659 return -ENODEV;
660 }
661
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100662 serial = create_serial(dev, interface, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 if (!serial) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100664 unlock_kernel();
Harvey Harrison441b62c2008-03-03 16:08:34 -0800665 dev_err(&interface->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 return -ENOMEM;
667 }
668
669 /* if this device type has a probe function, call it */
670 if (type->probe) {
671 const struct usb_device_id *id;
672
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700673 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100674 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100675 dev_err(&interface->dev,
676 "module get failed, exiting\n");
677 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 return -EIO;
679 }
680
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100681 id = get_iface_id(type, interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 retval = type->probe(serial, id);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700683 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 if (retval) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100686 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100687 dbg("sub driver rejected device");
688 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 return retval;
690 }
691 }
692
693 /* descriptor matches, let's find the endpoints needed */
694 /* check out the endpoints */
695 iface_desc = interface->cur_altsetting;
696 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
697 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700698
699 if (usb_endpoint_is_bulk_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 /* we found a bulk in endpoint */
701 dbg("found bulk in on endpoint %d", i);
702 bulk_in_endpoint[num_bulk_in] = endpoint;
703 ++num_bulk_in;
704 }
705
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700706 if (usb_endpoint_is_bulk_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* we found a bulk out endpoint */
708 dbg("found bulk out on endpoint %d", i);
709 bulk_out_endpoint[num_bulk_out] = endpoint;
710 ++num_bulk_out;
711 }
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700712
713 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 /* we found a interrupt in endpoint */
715 dbg("found interrupt in on endpoint %d", i);
716 interrupt_in_endpoint[num_interrupt_in] = endpoint;
717 ++num_interrupt_in;
718 }
719
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700720 if (usb_endpoint_is_int_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 /* we found an interrupt out endpoint */
722 dbg("found interrupt out on endpoint %d", i);
723 interrupt_out_endpoint[num_interrupt_out] = endpoint;
724 ++num_interrupt_out;
725 }
726 }
727
728#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100729 /* BEGIN HORRIBLE HACK FOR PL2303 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 /* this is needed due to the looney way its endpoints are set up */
731 if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
732 (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
733 ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
Johannes Steingraeber8fd80132006-09-16 16:17:34 +0200734 (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
735 ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
736 (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 if (interface != dev->actconfig->interface[0]) {
738 /* check out the endpoints of the other interface*/
739 iface_desc = dev->actconfig->interface[0]->cur_altsetting;
740 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
741 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700742 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 /* we found a interrupt in endpoint */
744 dbg("found interrupt in for Prolific device on separate interface");
745 interrupt_in_endpoint[num_interrupt_in] = endpoint;
746 ++num_interrupt_in;
747 }
748 }
749 }
750
751 /* Now make sure the PL-2303 is configured correctly.
752 * If not, give up now and hope this hack will work
753 * properly during a later invocation of usb_serial_probe
754 */
755 if (num_bulk_in == 0 || num_bulk_out == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100756 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100758 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return -ENODEV;
760 }
761 }
762 /* END HORRIBLE HACK FOR PL2303 */
763#endif
764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765#ifdef CONFIG_USB_SERIAL_GENERIC
766 if (type == &usb_serial_generic_device) {
767 num_ports = num_bulk_out;
768 if (num_ports == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100769 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100770 dev_err(&interface->dev,
771 "Generic device with no bulk out, not allowed.\n");
772 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 return -EIO;
774 }
775 }
776#endif
777 if (!num_ports) {
778 /* if this device type has a calc_num_ports function, call it */
779 if (type->calc_num_ports) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700780 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100781 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100782 dev_err(&interface->dev,
783 "module get failed, exiting\n");
784 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 return -EIO;
786 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100787 num_ports = type->calc_num_ports(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700788 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
790 if (!num_ports)
791 num_ports = type->num_ports;
792 }
793
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 serial->num_ports = num_ports;
795 serial->num_bulk_in = num_bulk_in;
796 serial->num_bulk_out = num_bulk_out;
797 serial->num_interrupt_in = num_interrupt_in;
798 serial->num_interrupt_out = num_interrupt_out;
799
Alan Stern063a2da2007-10-10 16:24:06 -0400800 /* found all that we need */
801 dev_info(&interface->dev, "%s converter detected\n",
802 type->description);
803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 /* create our ports, we need as many as the max endpoints */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100805 /* we don't use num_ports here because some devices have more
806 endpoint pairs than ports */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 max_endpoints = max(num_bulk_in, num_bulk_out);
808 max_endpoints = max(max_endpoints, num_interrupt_in);
809 max_endpoints = max(max_endpoints, num_interrupt_out);
810 max_endpoints = max(max_endpoints, (int)serial->num_ports);
811 serial->num_port_pointers = max_endpoints;
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100812 unlock_kernel();
813
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100814 dbg("%s - setting up %d port structures for this device",
815 __func__, max_endpoints);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 for (i = 0; i < max_endpoints; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100817 port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 if (!port)
819 goto probe_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 port->serial = serial;
Greg Kroah-Hartman507ca9b2005-04-23 12:49:16 -0700821 spin_lock_init(&port->lock);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300822 mutex_init(&port->mutex);
David Howellsc4028952006-11-22 14:57:56 +0000823 INIT_WORK(&port->work, usb_serial_port_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 serial->port[i] = port;
825 }
826
827 /* set up the endpoint information */
828 for (i = 0; i < num_bulk_in; ++i) {
829 endpoint = bulk_in_endpoint[i];
830 port = serial->port[i];
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100831 port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 if (!port->read_urb) {
833 dev_err(&interface->dev, "No free urbs available\n");
834 goto probe_error;
835 }
836 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
837 port->bulk_in_size = buffer_size;
838 port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100839 port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (!port->bulk_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100841 dev_err(&interface->dev,
842 "Couldn't allocate bulk_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 goto probe_error;
844 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100845 usb_fill_bulk_urb(port->read_urb, dev,
846 usb_rcvbulkpipe(dev,
847 endpoint->bEndpointAddress),
848 port->bulk_in_buffer, buffer_size,
849 serial->type->read_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
851
852 for (i = 0; i < num_bulk_out; ++i) {
853 endpoint = bulk_out_endpoint[i];
854 port = serial->port[i];
855 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
856 if (!port->write_urb) {
857 dev_err(&interface->dev, "No free urbs available\n");
858 goto probe_error;
859 }
860 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
861 port->bulk_out_size = buffer_size;
862 port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100863 port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 if (!port->bulk_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100865 dev_err(&interface->dev,
866 "Couldn't allocate bulk_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 goto probe_error;
868 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100869 usb_fill_bulk_urb(port->write_urb, dev,
870 usb_sndbulkpipe(dev,
871 endpoint->bEndpointAddress),
872 port->bulk_out_buffer, buffer_size,
873 serial->type->write_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 }
875
876 if (serial->type->read_int_callback) {
877 for (i = 0; i < num_interrupt_in; ++i) {
878 endpoint = interrupt_in_endpoint[i];
879 port = serial->port[i];
880 port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
881 if (!port->interrupt_in_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100882 dev_err(&interface->dev,
883 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 goto probe_error;
885 }
886 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100887 port->interrupt_in_endpointAddress =
888 endpoint->bEndpointAddress;
889 port->interrupt_in_buffer = kmalloc(buffer_size,
890 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 if (!port->interrupt_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100892 dev_err(&interface->dev,
893 "Couldn't allocate interrupt_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 goto probe_error;
895 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100896 usb_fill_int_urb(port->interrupt_in_urb, dev,
897 usb_rcvintpipe(dev,
898 endpoint->bEndpointAddress),
899 port->interrupt_in_buffer, buffer_size,
900 serial->type->read_int_callback, port,
901 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 }
903 } else if (num_interrupt_in) {
904 dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
905 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100906
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 if (serial->type->write_int_callback) {
908 for (i = 0; i < num_interrupt_out; ++i) {
909 endpoint = interrupt_out_endpoint[i];
910 port = serial->port[i];
911 port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
912 if (!port->interrupt_out_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100913 dev_err(&interface->dev,
914 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 goto probe_error;
916 }
917 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
918 port->interrupt_out_size = buffer_size;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100919 port->interrupt_out_endpointAddress =
920 endpoint->bEndpointAddress;
921 port->interrupt_out_buffer = kmalloc(buffer_size,
922 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 if (!port->interrupt_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100924 dev_err(&interface->dev,
925 "Couldn't allocate interrupt_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 goto probe_error;
927 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100928 usb_fill_int_urb(port->interrupt_out_urb, dev,
929 usb_sndintpipe(dev,
930 endpoint->bEndpointAddress),
931 port->interrupt_out_buffer, buffer_size,
932 serial->type->write_int_callback, port,
933 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 }
935 } else if (num_interrupt_out) {
936 dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
937 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100938
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 /* if this device type has an attach function, call it */
940 if (type->attach) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700941 if (!try_module_get(type->driver.owner)) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100942 dev_err(&interface->dev,
943 "module get failed, exiting\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 goto probe_error;
945 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100946 retval = type->attach(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700947 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 if (retval < 0)
949 goto probe_error;
950 if (retval > 0) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100951 /* quietly accept this device, but don't bind to a
952 serial port as it's about to disappear */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 goto exit;
954 }
955 }
956
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100957 if (get_free_serial(serial, num_ports, &minor) == NULL) {
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100958 dev_err(&interface->dev, "No more free serial devices\n");
959 goto probe_error;
960 }
Oliver Neukumc744f992007-02-26 15:43:00 +0100961 serial->minor = minor;
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 /* register all of the individual ports with the driver core */
964 for (i = 0; i < num_ports; ++i) {
965 port = serial->port[i];
966 port->dev.parent = &interface->dev;
967 port->dev.driver = NULL;
968 port->dev.bus = &usb_serial_bus_type;
969 port->dev.release = &port_release;
970
Kay Sievers0031a062008-05-02 06:02:41 +0200971 dev_set_name(&port->dev, "ttyUSB%d", port->number);
Kay Sievers7071a3c2008-05-02 06:02:41 +0200972 dbg ("%s - registering %s", __func__, dev_name(&port->dev));
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -0700973 retval = device_register(&port->dev);
974 if (retval)
975 dev_err(&port->dev, "Error registering port device, "
976 "continuing\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 }
978
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100979 usb_serial_console_init(debug, minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981exit:
982 /* success */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100983 usb_set_intfdata(interface, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 return 0;
985
986probe_error:
987 for (i = 0; i < num_bulk_in; ++i) {
988 port = serial->port[i];
989 if (!port)
990 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +0100991 usb_free_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 kfree(port->bulk_in_buffer);
993 }
994 for (i = 0; i < num_bulk_out; ++i) {
995 port = serial->port[i];
996 if (!port)
997 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +0100998 usb_free_urb(port->write_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 kfree(port->bulk_out_buffer);
1000 }
1001 for (i = 0; i < num_interrupt_in; ++i) {
1002 port = serial->port[i];
1003 if (!port)
1004 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001005 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 kfree(port->interrupt_in_buffer);
1007 }
1008 for (i = 0; i < num_interrupt_out; ++i) {
1009 port = serial->port[i];
1010 if (!port)
1011 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001012 usb_free_urb(port->interrupt_out_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 kfree(port->interrupt_out_buffer);
1014 }
1015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 /* free up any memory that we allocated */
1017 for (i = 0; i < serial->num_port_pointers; ++i)
1018 kfree(serial->port[i]);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001019 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 return -EIO;
1021}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001022EXPORT_SYMBOL_GPL(usb_serial_probe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024void usb_serial_disconnect(struct usb_interface *interface)
1025{
1026 int i;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001027 struct usb_serial *serial = usb_get_intfdata(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 struct device *dev = &interface->dev;
1029 struct usb_serial_port *port;
1030
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +02001031 usb_serial_console_disconnect(serial);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001032 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001034 mutex_lock(&serial->disc_mutex);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001035 usb_set_intfdata(interface, NULL);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001036 /* must set a flag, to signal subdrivers */
1037 serial->disconnected = 1;
1038 for (i = 0; i < serial->num_ports; ++i) {
1039 port = serial->port[i];
1040 if (port) {
Alan Cox95da3102008-07-22 11:09:07 +01001041 if (port->port.tty)
1042 tty_hangup(port->port.tty);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001043 kill_traffic(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001046 /* let the last holder of this object
1047 * cause it to be cleaned up */
1048 mutex_unlock(&serial->disc_mutex);
1049 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 dev_info(dev, "device disconnected\n");
1051}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001052EXPORT_SYMBOL_GPL(usb_serial_disconnect);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Oliver Neukumec225592007-04-27 20:54:57 +02001054int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1055{
1056 struct usb_serial *serial = usb_get_intfdata(intf);
1057 struct usb_serial_port *port;
1058 int i, r = 0;
1059
Oliver Neukume31c1882007-07-23 08:58:39 +02001060 for (i = 0; i < serial->num_ports; ++i) {
1061 port = serial->port[i];
1062 if (port)
1063 kill_traffic(port);
Oliver Neukumec225592007-04-27 20:54:57 +02001064 }
1065
1066 if (serial->type->suspend)
Oliver Neukume31c1882007-07-23 08:58:39 +02001067 r = serial->type->suspend(serial, message);
Oliver Neukumec225592007-04-27 20:54:57 +02001068
1069 return r;
1070}
1071EXPORT_SYMBOL(usb_serial_suspend);
1072
1073int usb_serial_resume(struct usb_interface *intf)
1074{
1075 struct usb_serial *serial = usb_get_intfdata(intf);
1076
Sarah Sharp8abaee22007-10-25 10:58:43 -07001077 if (serial->type->resume)
1078 return serial->type->resume(serial);
1079 return 0;
Oliver Neukumec225592007-04-27 20:54:57 +02001080}
1081EXPORT_SYMBOL(usb_serial_resume);
1082
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001083static const struct tty_operations serial_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 .open = serial_open,
1085 .close = serial_close,
1086 .write = serial_write,
1087 .write_room = serial_write_room,
1088 .ioctl = serial_ioctl,
1089 .set_termios = serial_set_termios,
1090 .throttle = serial_throttle,
1091 .unthrottle = serial_unthrottle,
1092 .break_ctl = serial_break,
1093 .chars_in_buffer = serial_chars_in_buffer,
1094 .read_proc = serial_read_proc,
1095 .tiocmget = serial_tiocmget,
1096 .tiocmset = serial_tiocmset,
1097};
1098
1099struct tty_driver *usb_serial_tty_driver;
1100
1101static int __init usb_serial_init(void)
1102{
1103 int i;
1104 int result;
1105
1106 usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
1107 if (!usb_serial_tty_driver)
1108 return -ENOMEM;
1109
1110 /* Initialize our global data */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001111 for (i = 0; i < SERIAL_TTY_MINORS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 serial_table[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
1114 result = bus_register(&usb_serial_bus_type);
1115 if (result) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001116 err("%s - registering bus driver failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 goto exit_bus;
1118 }
1119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 usb_serial_tty_driver->owner = THIS_MODULE;
1121 usb_serial_tty_driver->driver_name = "usbserial";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 usb_serial_tty_driver->name = "ttyUSB";
1123 usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
1124 usb_serial_tty_driver->minor_start = 0;
1125 usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
1126 usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001127 usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
1128 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 usb_serial_tty_driver->init_termios = tty_std_termios;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001130 usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
1131 | HUPCL | CLOCAL;
Alan Coxa5b6f602008-04-08 17:16:06 +01001132 usb_serial_tty_driver->init_termios.c_ispeed = 9600;
1133 usb_serial_tty_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 tty_set_operations(usb_serial_tty_driver, &serial_ops);
1135 result = tty_register_driver(usb_serial_tty_driver);
1136 if (result) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001137 err("%s - tty_register_driver failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 goto exit_reg_driver;
1139 }
1140
1141 /* register the USB driver */
1142 result = usb_register(&usb_serial_driver);
1143 if (result < 0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001144 err("%s - usb_register failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 goto exit_tty;
1146 }
1147
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001148 /* register the generic driver, if we should */
1149 result = usb_serial_generic_register(debug);
1150 if (result < 0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001151 err("%s - registering generic driver failed", __func__);
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001152 goto exit_generic;
1153 }
1154
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001155 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
1157 return result;
1158
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001159exit_generic:
1160 usb_deregister(&usb_serial_driver);
1161
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162exit_tty:
1163 tty_unregister_driver(usb_serial_tty_driver);
1164
1165exit_reg_driver:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 bus_unregister(&usb_serial_bus_type);
1167
1168exit_bus:
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001169 err("%s - returning with error %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 put_tty_driver(usb_serial_tty_driver);
1171 return result;
1172}
1173
1174
1175static void __exit usb_serial_exit(void)
1176{
1177 usb_serial_console_exit();
1178
1179 usb_serial_generic_deregister();
1180
1181 usb_deregister(&usb_serial_driver);
1182 tty_unregister_driver(usb_serial_tty_driver);
1183 put_tty_driver(usb_serial_tty_driver);
1184 bus_unregister(&usb_serial_bus_type);
1185}
1186
1187
1188module_init(usb_serial_init);
1189module_exit(usb_serial_exit);
1190
1191#define set_to_generic_if_null(type, function) \
1192 do { \
1193 if (!type->function) { \
1194 type->function = usb_serial_generic_##function; \
1195 dbg("Had to override the " #function \
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001196 " usb serial operation with the generic one.");\
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 } \
1198 } while (0)
1199
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001200static void fixup_generic(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
1202 set_to_generic_if_null(device, open);
1203 set_to_generic_if_null(device, write);
1204 set_to_generic_if_null(device, close);
1205 set_to_generic_if_null(device, write_room);
1206 set_to_generic_if_null(device, chars_in_buffer);
1207 set_to_generic_if_null(device, read_bulk_callback);
1208 set_to_generic_if_null(device, write_bulk_callback);
1209 set_to_generic_if_null(device, shutdown);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -08001210 set_to_generic_if_null(device, resume);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211}
1212
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001213int usb_serial_register(struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001215 /* must be called with BKL held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 int retval;
1217
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001218 fixup_generic(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001220 if (!driver->description)
1221 driver->description = driver->driver.name;
1222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 /* Add this device to our list of devices */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001224 list_add(&driver->driver_list, &usb_serial_driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001226 retval = usb_serial_bus_register(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 if (retval) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001228 err("problem %d when registering driver %s",
1229 retval, driver->description);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001230 list_del(&driver->driver_list);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001231 } else
1232 info("USB Serial support registered for %s",
1233 driver->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
1235 return retval;
1236}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001237EXPORT_SYMBOL_GPL(usb_serial_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
1239
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001240void usb_serial_deregister(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001242 /* must be called with BKL held */
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001243 info("USB Serial deregistering driver %s", device->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 list_del(&device->driver_list);
1245 usb_serial_bus_deregister(device);
1246}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247EXPORT_SYMBOL_GPL(usb_serial_deregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249/* Module information */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001250MODULE_AUTHOR(DRIVER_AUTHOR);
1251MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252MODULE_LICENSE("GPL");
1253
1254module_param(debug, bool, S_IRUGO | S_IWUSR);
1255MODULE_PARM_DESC(debug, "Debug enabled or not");