blob: 8c2d531eedea1f3bf2759ec9796dcf96cb8dcfff [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
125 if (serial == NULL)
126 return;
127
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100128 for (i = 0; i < serial->num_ports; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 serial_table[serial->minor + i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130}
131
132static void destroy_serial(struct kref *kref)
133{
134 struct usb_serial *serial;
135 struct usb_serial_port *port;
136 int i;
137
138 serial = to_usb_serial(kref);
139
Harvey Harrison441b62c2008-03-03 16:08:34 -0800140 dbg("%s - %s", __func__, serial->type->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Jim Radford521b85a2007-03-13 08:30:50 -0700142 serial->type->shutdown(serial);
143
144 /* return the minor range that this device had */
145 return_serial(serial);
146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 for (i = 0; i < serial->num_ports; ++i)
Alan Cox95da3102008-07-22 11:09:07 +0100148 serial->port[i]->port.count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150 /* the ports are cleaned up and released in port_release() */
151 for (i = 0; i < serial->num_ports; ++i)
152 if (serial->port[i]->dev.parent != NULL) {
153 device_unregister(&serial->port[i]->dev);
154 serial->port[i] = NULL;
155 }
156
157 /* If this is a "fake" port, we have to clean it up here, as it will
158 * not get cleaned up in port_release() as it was never registered with
159 * the driver core */
160 if (serial->num_ports < serial->num_port_pointers) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100161 for (i = serial->num_ports;
162 i < serial->num_port_pointers; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 port = serial->port[i];
164 if (!port)
165 continue;
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700166 port_free(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 }
168 }
169
170 usb_put_dev(serial->dev);
171
172 /* free up any memory that we allocated */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100173 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174}
175
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200176void usb_serial_put(struct usb_serial *serial)
177{
Oliver Neukum3ddad822007-07-24 15:13:42 +0200178 mutex_lock(&table_lock);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200179 kref_put(&serial->kref, destroy_serial);
Oliver Neukum3ddad822007-07-24 15:13:42 +0200180 mutex_unlock(&table_lock);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200181}
182
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183/*****************************************************************************
184 * Driver tty interface functions
185 *****************************************************************************/
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100186static int serial_open (struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
188 struct usb_serial *serial;
189 struct usb_serial_port *port;
190 unsigned int portNumber;
191 int retval;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100192
Harvey Harrison441b62c2008-03-03 16:08:34 -0800193 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195 /* get the serial object associated with this tty pointer */
196 serial = usb_serial_get_by_index(tty->index);
197 if (!serial) {
198 tty->driver_data = NULL;
199 return -ENODEV;
200 }
201
202 portNumber = tty->index - serial->minor;
203 port = serial->port[portNumber];
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300204 if (!port) {
205 retval = -ENODEV;
206 goto bailout_kref_put;
207 }
Luiz Fernando Capitulino8a4613f2005-11-28 19:16:07 -0200208
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300209 if (mutex_lock_interruptible(&port->mutex)) {
210 retval = -ERESTARTSYS;
211 goto bailout_kref_put;
212 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100213
Alan Cox95da3102008-07-22 11:09:07 +0100214 ++port->port.count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Paul Fulghumca854852006-04-13 22:28:17 +0200216 /* set up our port structure making the tty driver
217 * remember our port object, and us it */
218 tty->driver_data = port;
Alan Cox95da3102008-07-22 11:09:07 +0100219 port->port.tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Alan Cox95da3102008-07-22 11:09:07 +0100221 if (port->port.count == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223 /* lock this module before we call it
224 * this may fail, which means we must bail out,
225 * safe because we are called with BKL held */
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700226 if (!try_module_get(serial->type->driver.owner)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 retval = -ENODEV;
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300228 goto bailout_mutex_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 }
230
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800231 retval = usb_autopm_get_interface(serial->interface);
232 if (retval)
233 goto bailout_module_put;
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 }
240
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300241 mutex_unlock(&port->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 return 0;
243
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800244bailout_interface_put:
245 usb_autopm_put_interface(serial->interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246bailout_module_put:
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700247 module_put(serial->type->driver.owner);
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300248bailout_mutex_unlock:
Alan Cox95da3102008-07-22 11:09:07 +0100249 port->port.count = 0;
Frank Gevaertsb059c812006-06-14 15:52:05 +0200250 tty->driver_data = NULL;
Alan Cox95da3102008-07-22 11:09:07 +0100251 port->port.tty = NULL;
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300252 mutex_unlock(&port->mutex);
Luiz Fernando Capitulino71a84162006-05-11 22:34:24 -0300253bailout_kref_put:
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200254 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 return retval;
256}
257
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100258static void serial_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200260 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 if (!port)
263 return;
264
Harvey Harrison441b62c2008-03-03 16:08:34 -0800265 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300267 mutex_lock(&port->mutex);
Luiz Fernando Capitulino8a4613f2005-11-28 19:16:07 -0200268
Alan Cox95da3102008-07-22 11:09:07 +0100269 if (port->port.count == 0) {
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300270 mutex_unlock(&port->mutex);
Greg Kroah-Hartman91c0bce2006-03-06 13:25:52 -0800271 return;
272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Alan Cox95da3102008-07-22 11:09:07 +0100274 --port->port.count;
275 if (port->port.count == 0)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100276 /* only call the device specific close if this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 * port is being closed by the last owner */
Alan Cox95da3102008-07-22 11:09:07 +0100278 port->serial->type->close(tty, port, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Alan Cox95da3102008-07-22 11:09:07 +0100280 if (port->port.count == (port->console? 1 : 0)) {
281 if (port->port.tty) {
282 if (port->port.tty->driver_data)
283 port->port.tty->driver_data = NULL;
284 port->port.tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 }
287
Alan Cox95da3102008-07-22 11:09:07 +0100288 if (port->port.count == 0) {
Oliver Neukum62ad2962008-06-25 13:32:49 +0200289 mutex_lock(&port->serial->disc_mutex);
290 if (!port->serial->disconnected)
291 usb_autopm_put_interface(port->serial->interface);
292 mutex_unlock(&port->serial->disc_mutex);
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500293 module_put(port->serial->type->driver.owner);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800294 }
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500295
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300296 mutex_unlock(&port->mutex);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200297 usb_serial_put(port->serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298}
299
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100300static int serial_write(struct tty_struct *tty, const unsigned char *buf,
301 int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200303 struct usb_serial_port *port = tty->driver_data;
Oliver Neukum3ff4fd92007-01-13 07:32:27 +0100304 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Alan Coxf34d7a52008-04-30 00:54:13 -0700306 if (port->serial->dev->state == USB_STATE_NOTATTACHED)
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200307 goto exit;
308
Harvey Harrison441b62c2008-03-03 16:08:34 -0800309 dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Alan Cox95da3102008-07-22 11:09:07 +0100311 /* count is managed under the mutex lock for the tty so cannot
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100312 drop to zero until after the last close completes */
Alan Cox95da3102008-07-22 11:09:07 +0100313 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
315 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100316 retval = port->serial->type->write(tty, port, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318exit:
319 return retval;
320}
321
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100322static int serial_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200324 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800325 dbg("%s - port %d", __func__, port->number);
Alan Cox95da3102008-07-22 11:09:07 +0100326 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100328 return port->serial->type->write_room(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329}
330
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100331static int serial_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200333 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800334 dbg("%s = port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Alan Cox95da3102008-07-22 11:09:07 +0100336 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100338 return port->serial->type->chars_in_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339}
340
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100341static void serial_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200343 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800344 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Alan Cox95da3102008-07-22 11:09:07 +0100346 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 /* pass on to the driver specific version of this function */
348 if (port->serial->type->throttle)
Alan Cox95da3102008-07-22 11:09:07 +0100349 port->serial->type->throttle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350}
351
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100352static void serial_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200354 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800355 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Alan Cox95da3102008-07-22 11:09:07 +0100357 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 /* pass on to the driver specific version of this function */
359 if (port->serial->type->unthrottle)
Alan Cox95da3102008-07-22 11:09:07 +0100360 port->serial->type->unthrottle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361}
362
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100363static int serial_ioctl(struct tty_struct *tty, struct file *file,
364 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200366 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 int retval = -ENODEV;
368
Harvey Harrison441b62c2008-03-03 16:08:34 -0800369 dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Alan Cox95da3102008-07-22 11:09:07 +0100371 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100373 /* pass on to the driver specific version of this function
374 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700375 if (port->serial->type->ioctl) {
376 lock_kernel();
Alan Cox95da3102008-07-22 11:09:07 +0100377 retval = port->serial->type->ioctl(tty, file, cmd, arg);
Alan Coxf34d7a52008-04-30 00:54:13 -0700378 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100379 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 return retval;
382}
383
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100384static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200386 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800387 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Alan Cox95da3102008-07-22 11:09:07 +0100389 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100390 /* pass on to the driver specific version of this function
391 if it is available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 if (port->serial->type->set_termios)
Alan Cox95da3102008-07-22 11:09:07 +0100393 port->serial->type->set_termios(tty, port, old);
Alan Cox33785092007-10-18 01:24:22 -0700394 else
395 tty_termios_copy_hw(tty->termios, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396}
397
Alan Cox9e989662008-07-22 11:18:03 +0100398static int serial_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200400 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Harvey Harrison441b62c2008-03-03 16:08:34 -0800402 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Alan Cox95da3102008-07-22 11:09:07 +0100404 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100405 /* pass on to the driver specific version of this function
406 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700407 if (port->serial->type->break_ctl) {
408 lock_kernel();
Alan Cox95da3102008-07-22 11:09:07 +0100409 port->serial->type->break_ctl(tty, break_state);
Alan Coxf34d7a52008-04-30 00:54:13 -0700410 unlock_kernel();
411 }
Alan Cox9e989662008-07-22 11:18:03 +0100412 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413}
414
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100415static int serial_read_proc(char *page, char **start, off_t off, int count,
416 int *eof, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
418 struct usb_serial *serial;
419 int length = 0;
420 int i;
421 off_t begin = 0;
422 char tmp[40];
423
Harvey Harrison441b62c2008-03-03 16:08:34 -0800424 dbg("%s", __func__);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100425 length += sprintf(page, "usbserinfo:1.0 driver:2.0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
427 serial = usb_serial_get_by_index(i);
428 if (serial == NULL)
429 continue;
430
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100431 length += sprintf(page+length, "%d:", i);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700432 if (serial->type->driver.owner)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100433 length += sprintf(page+length, " module:%s",
434 module_name(serial->type->driver.owner));
435 length += sprintf(page+length, " name:\"%s\"",
436 serial->type->description);
437 length += sprintf(page+length, " vendor:%04x product:%04x",
438 le16_to_cpu(serial->dev->descriptor.idVendor),
439 le16_to_cpu(serial->dev->descriptor.idProduct));
440 length += sprintf(page+length, " num_ports:%d",
441 serial->num_ports);
442 length += sprintf(page+length, " port:%d",
443 i - serial->minor + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 usb_make_path(serial->dev, tmp, sizeof(tmp));
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100445 length += sprintf(page+length, " path:%s", tmp);
446
447 length += sprintf(page+length, "\n");
Matthias Urlichs59925832006-09-11 12:35:20 +0200448 if ((length + begin) > (off + count)) {
449 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 goto done;
Matthias Urlichs59925832006-09-11 12:35:20 +0200451 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if ((length + begin) < off) {
453 begin += length;
454 length = 0;
455 }
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200456 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 }
458 *eof = 1;
459done:
460 if (off >= (length + begin))
461 return 0;
462 *start = page + (off-begin);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100463 return (count < begin+length-off) ? count : begin+length-off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464}
465
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100466static int serial_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200468 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Harvey Harrison441b62c2008-03-03 16:08:34 -0800470 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Alan Cox95da3102008-07-22 11:09:07 +0100472 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 if (port->serial->type->tiocmget)
Alan Cox95da3102008-07-22 11:09:07 +0100474 return port->serial->type->tiocmget(tty, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 return -EINVAL;
476}
477
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100478static int serial_tiocmset(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 unsigned int set, unsigned int clear)
480{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200481 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Harvey Harrison441b62c2008-03-03 16:08:34 -0800483 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Alan Cox95da3102008-07-22 11:09:07 +0100485 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 if (port->serial->type->tiocmset)
Alan Cox95da3102008-07-22 11:09:07 +0100487 return port->serial->type->tiocmset(tty, file, set, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 return -EINVAL;
489}
490
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700491/*
492 * We would be calling tty_wakeup here, but unfortunately some line
493 * disciplines have an annoying habit of calling tty->write from
494 * the write wakeup callback (e.g. n_hdlc.c).
495 */
496void usb_serial_port_softint(struct usb_serial_port *port)
497{
498 schedule_work(&port->work);
499}
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100500EXPORT_SYMBOL_GPL(usb_serial_port_softint);
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700501
David Howellsc4028952006-11-22 14:57:56 +0000502static void usb_serial_port_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
David Howellsc4028952006-11-22 14:57:56 +0000504 struct usb_serial_port *port =
505 container_of(work, struct usb_serial_port, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 struct tty_struct *tty;
507
Harvey Harrison441b62c2008-03-03 16:08:34 -0800508 dbg("%s - port %d", __func__, port->number);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 if (!port)
511 return;
512
Alan Cox95da3102008-07-22 11:09:07 +0100513 tty = port->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if (!tty)
515 return;
516
517 tty_wakeup(tty);
518}
519
520static void port_release(struct device *dev)
521{
522 struct usb_serial_port *port = to_usb_serial_port(dev);
523
Kay Sievers7071a3c2008-05-02 06:02:41 +0200524 dbg ("%s - %s", __func__, dev_name(dev));
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700525 port_free(port);
526}
527
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100528static void kill_traffic(struct usb_serial_port *port)
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700529{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 usb_kill_urb(port->write_urb);
Oliver Neukum5adceac2007-08-17 14:01:38 +0200532 /*
533 * This is tricky.
534 * Some drivers submit the read_urb in the
535 * handler for the write_urb or vice versa
536 * this order determines the order in which
537 * usb_kill_urb() must be used to reliably
538 * kill the URBs. As it is unknown here,
539 * both orders must be used in turn.
540 * The call below is not redundant.
541 */
542 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 usb_kill_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 usb_kill_urb(port->interrupt_out_urb);
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100545}
546
547static void port_free(struct usb_serial_port *port)
548{
549 kill_traffic(port);
550 usb_free_urb(port->read_urb);
551 usb_free_urb(port->write_urb);
552 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 usb_free_urb(port->interrupt_out_urb);
554 kfree(port->bulk_in_buffer);
555 kfree(port->bulk_out_buffer);
556 kfree(port->interrupt_in_buffer);
557 kfree(port->interrupt_out_buffer);
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700558 flush_scheduled_work(); /* port->work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 kfree(port);
560}
561
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100562static struct usb_serial *create_serial(struct usb_device *dev,
563 struct usb_interface *interface,
564 struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565{
566 struct usb_serial *serial;
567
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100568 serial = kzalloc(sizeof(*serial), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 if (!serial) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800570 dev_err(&dev->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 return NULL;
572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 serial->dev = usb_get_dev(dev);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700574 serial->type = driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 serial->interface = interface;
576 kref_init(&serial->kref);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +0100577 mutex_init(&serial->disc_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
579 return serial;
580}
581
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100582static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100583 struct usb_serial_driver *drv)
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100584{
585 struct usb_dynid *dynid;
586
587 spin_lock(&drv->dynids.lock);
588 list_for_each_entry(dynid, &drv->dynids.list, node) {
589 if (usb_match_one_id(intf, &dynid->id)) {
590 spin_unlock(&drv->dynids.lock);
591 return &dynid->id;
592 }
593 }
594 spin_unlock(&drv->dynids.lock);
595 return NULL;
596}
597
598static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
599 struct usb_interface *intf)
600{
601 const struct usb_device_id *id;
602
603 id = usb_match_id(intf, drv->id_table);
604 if (id) {
605 dbg("static descriptor matches");
606 goto exit;
607 }
608 id = match_dynamic_id(intf, drv);
609 if (id)
610 dbg("dynamic descriptor matches");
611exit:
612 return id;
613}
614
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100615static struct usb_serial_driver *search_serial_device(
616 struct usb_interface *iface)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 const struct usb_device_id *id;
Alan Stern063a2da2007-10-10 16:24:06 -0400619 struct usb_serial_driver *drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Adrian Bunk93b1fae2006-01-10 00:13:33 +0100621 /* Check if the usb id matches a known device */
Alan Stern063a2da2007-10-10 16:24:06 -0400622 list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
623 id = get_iface_id(drv, iface);
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100624 if (id)
Alan Stern063a2da2007-10-10 16:24:06 -0400625 return drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 }
627
628 return NULL;
629}
630
631int usb_serial_probe(struct usb_interface *interface,
632 const struct usb_device_id *id)
633{
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100634 struct usb_device *dev = interface_to_usbdev(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 struct usb_serial *serial = NULL;
636 struct usb_serial_port *port;
637 struct usb_host_interface *iface_desc;
638 struct usb_endpoint_descriptor *endpoint;
639 struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
640 struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
641 struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
642 struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700643 struct usb_serial_driver *type = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 int retval;
Andre Hauptdd9ca5d2008-06-18 15:56:00 +0200645 unsigned int minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 int buffer_size;
647 int i;
648 int num_interrupt_in = 0;
649 int num_interrupt_out = 0;
650 int num_bulk_in = 0;
651 int num_bulk_out = 0;
652 int num_ports = 0;
653 int max_endpoints;
654
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100655 lock_kernel(); /* guard against unloading a serial driver module */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 type = search_serial_device(interface);
657 if (!type) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100658 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 dbg("none matched");
660 return -ENODEV;
661 }
662
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100663 serial = create_serial(dev, interface, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 if (!serial) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100665 unlock_kernel();
Harvey Harrison441b62c2008-03-03 16:08:34 -0800666 dev_err(&interface->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 return -ENOMEM;
668 }
669
670 /* if this device type has a probe function, call it */
671 if (type->probe) {
672 const struct usb_device_id *id;
673
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700674 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100675 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100676 dev_err(&interface->dev,
677 "module get failed, exiting\n");
678 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 return -EIO;
680 }
681
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100682 id = get_iface_id(type, interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 retval = type->probe(serial, id);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700684 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
686 if (retval) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100687 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100688 dbg("sub driver rejected device");
689 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 return retval;
691 }
692 }
693
694 /* descriptor matches, let's find the endpoints needed */
695 /* check out the endpoints */
696 iface_desc = interface->cur_altsetting;
697 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
698 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700699
700 if (usb_endpoint_is_bulk_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 /* we found a bulk in endpoint */
702 dbg("found bulk in on endpoint %d", i);
703 bulk_in_endpoint[num_bulk_in] = endpoint;
704 ++num_bulk_in;
705 }
706
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700707 if (usb_endpoint_is_bulk_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 /* we found a bulk out endpoint */
709 dbg("found bulk out on endpoint %d", i);
710 bulk_out_endpoint[num_bulk_out] = endpoint;
711 ++num_bulk_out;
712 }
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700713
714 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 /* we found a interrupt in endpoint */
716 dbg("found interrupt in on endpoint %d", i);
717 interrupt_in_endpoint[num_interrupt_in] = endpoint;
718 ++num_interrupt_in;
719 }
720
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700721 if (usb_endpoint_is_int_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 /* we found an interrupt out endpoint */
723 dbg("found interrupt out on endpoint %d", i);
724 interrupt_out_endpoint[num_interrupt_out] = endpoint;
725 ++num_interrupt_out;
726 }
727 }
728
729#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100730 /* BEGIN HORRIBLE HACK FOR PL2303 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 /* this is needed due to the looney way its endpoints are set up */
732 if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
733 (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
734 ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
Johannes Steingraeber8fd80132006-09-16 16:17:34 +0200735 (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
736 ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
737 (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (interface != dev->actconfig->interface[0]) {
739 /* check out the endpoints of the other interface*/
740 iface_desc = dev->actconfig->interface[0]->cur_altsetting;
741 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
742 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700743 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 /* we found a interrupt in endpoint */
745 dbg("found interrupt in for Prolific device on separate interface");
746 interrupt_in_endpoint[num_interrupt_in] = endpoint;
747 ++num_interrupt_in;
748 }
749 }
750 }
751
752 /* Now make sure the PL-2303 is configured correctly.
753 * If not, give up now and hope this hack will work
754 * properly during a later invocation of usb_serial_probe
755 */
756 if (num_bulk_in == 0 || num_bulk_out == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100757 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100759 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return -ENODEV;
761 }
762 }
763 /* END HORRIBLE HACK FOR PL2303 */
764#endif
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766#ifdef CONFIG_USB_SERIAL_GENERIC
767 if (type == &usb_serial_generic_device) {
768 num_ports = num_bulk_out;
769 if (num_ports == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100770 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100771 dev_err(&interface->dev,
772 "Generic device with no bulk out, not allowed.\n");
773 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return -EIO;
775 }
776 }
777#endif
778 if (!num_ports) {
779 /* if this device type has a calc_num_ports function, call it */
780 if (type->calc_num_ports) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700781 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100782 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100783 dev_err(&interface->dev,
784 "module get failed, exiting\n");
785 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 return -EIO;
787 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100788 num_ports = type->calc_num_ports(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700789 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791 if (!num_ports)
792 num_ports = type->num_ports;
793 }
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 serial->num_ports = num_ports;
796 serial->num_bulk_in = num_bulk_in;
797 serial->num_bulk_out = num_bulk_out;
798 serial->num_interrupt_in = num_interrupt_in;
799 serial->num_interrupt_out = num_interrupt_out;
800
Alan Stern063a2da2007-10-10 16:24:06 -0400801 /* found all that we need */
802 dev_info(&interface->dev, "%s converter detected\n",
803 type->description);
804
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 /* create our ports, we need as many as the max endpoints */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100806 /* we don't use num_ports here because some devices have more
807 endpoint pairs than ports */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 max_endpoints = max(num_bulk_in, num_bulk_out);
809 max_endpoints = max(max_endpoints, num_interrupt_in);
810 max_endpoints = max(max_endpoints, num_interrupt_out);
811 max_endpoints = max(max_endpoints, (int)serial->num_ports);
812 serial->num_port_pointers = max_endpoints;
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100813 unlock_kernel();
814
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100815 dbg("%s - setting up %d port structures for this device",
816 __func__, max_endpoints);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 for (i = 0; i < max_endpoints; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100818 port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 if (!port)
820 goto probe_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 port->serial = serial;
Greg Kroah-Hartman507ca9b2005-04-23 12:49:16 -0700822 spin_lock_init(&port->lock);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300823 mutex_init(&port->mutex);
David Howellsc4028952006-11-22 14:57:56 +0000824 INIT_WORK(&port->work, usb_serial_port_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 serial->port[i] = port;
826 }
827
828 /* set up the endpoint information */
829 for (i = 0; i < num_bulk_in; ++i) {
830 endpoint = bulk_in_endpoint[i];
831 port = serial->port[i];
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100832 port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 if (!port->read_urb) {
834 dev_err(&interface->dev, "No free urbs available\n");
835 goto probe_error;
836 }
837 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
838 port->bulk_in_size = buffer_size;
839 port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100840 port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (!port->bulk_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100842 dev_err(&interface->dev,
843 "Couldn't allocate bulk_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 goto probe_error;
845 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100846 usb_fill_bulk_urb(port->read_urb, dev,
847 usb_rcvbulkpipe(dev,
848 endpoint->bEndpointAddress),
849 port->bulk_in_buffer, buffer_size,
850 serial->type->read_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 }
852
853 for (i = 0; i < num_bulk_out; ++i) {
854 endpoint = bulk_out_endpoint[i];
855 port = serial->port[i];
856 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
857 if (!port->write_urb) {
858 dev_err(&interface->dev, "No free urbs available\n");
859 goto probe_error;
860 }
861 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
862 port->bulk_out_size = buffer_size;
863 port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100864 port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 if (!port->bulk_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100866 dev_err(&interface->dev,
867 "Couldn't allocate bulk_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 goto probe_error;
869 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100870 usb_fill_bulk_urb(port->write_urb, dev,
871 usb_sndbulkpipe(dev,
872 endpoint->bEndpointAddress),
873 port->bulk_out_buffer, buffer_size,
874 serial->type->write_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 }
876
877 if (serial->type->read_int_callback) {
878 for (i = 0; i < num_interrupt_in; ++i) {
879 endpoint = interrupt_in_endpoint[i];
880 port = serial->port[i];
881 port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
882 if (!port->interrupt_in_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100883 dev_err(&interface->dev,
884 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 goto probe_error;
886 }
887 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100888 port->interrupt_in_endpointAddress =
889 endpoint->bEndpointAddress;
890 port->interrupt_in_buffer = kmalloc(buffer_size,
891 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 if (!port->interrupt_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100893 dev_err(&interface->dev,
894 "Couldn't allocate interrupt_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 goto probe_error;
896 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100897 usb_fill_int_urb(port->interrupt_in_urb, dev,
898 usb_rcvintpipe(dev,
899 endpoint->bEndpointAddress),
900 port->interrupt_in_buffer, buffer_size,
901 serial->type->read_int_callback, port,
902 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 }
904 } else if (num_interrupt_in) {
905 dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
906 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100907
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (serial->type->write_int_callback) {
909 for (i = 0; i < num_interrupt_out; ++i) {
910 endpoint = interrupt_out_endpoint[i];
911 port = serial->port[i];
912 port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
913 if (!port->interrupt_out_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100914 dev_err(&interface->dev,
915 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 goto probe_error;
917 }
918 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
919 port->interrupt_out_size = buffer_size;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100920 port->interrupt_out_endpointAddress =
921 endpoint->bEndpointAddress;
922 port->interrupt_out_buffer = kmalloc(buffer_size,
923 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 if (!port->interrupt_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100925 dev_err(&interface->dev,
926 "Couldn't allocate interrupt_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 goto probe_error;
928 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100929 usb_fill_int_urb(port->interrupt_out_urb, dev,
930 usb_sndintpipe(dev,
931 endpoint->bEndpointAddress),
932 port->interrupt_out_buffer, buffer_size,
933 serial->type->write_int_callback, port,
934 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 }
936 } else if (num_interrupt_out) {
937 dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
938 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100939
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 /* if this device type has an attach function, call it */
941 if (type->attach) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700942 if (!try_module_get(type->driver.owner)) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100943 dev_err(&interface->dev,
944 "module get failed, exiting\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 goto probe_error;
946 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100947 retval = type->attach(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700948 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 if (retval < 0)
950 goto probe_error;
951 if (retval > 0) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100952 /* quietly accept this device, but don't bind to a
953 serial port as it's about to disappear */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 goto exit;
955 }
956 }
957
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100958 if (get_free_serial(serial, num_ports, &minor) == NULL) {
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100959 dev_err(&interface->dev, "No more free serial devices\n");
960 goto probe_error;
961 }
Oliver Neukumc744f992007-02-26 15:43:00 +0100962 serial->minor = minor;
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 /* register all of the individual ports with the driver core */
965 for (i = 0; i < num_ports; ++i) {
966 port = serial->port[i];
967 port->dev.parent = &interface->dev;
968 port->dev.driver = NULL;
969 port->dev.bus = &usb_serial_bus_type;
970 port->dev.release = &port_release;
971
Kay Sievers0031a062008-05-02 06:02:41 +0200972 dev_set_name(&port->dev, "ttyUSB%d", port->number);
Kay Sievers7071a3c2008-05-02 06:02:41 +0200973 dbg ("%s - registering %s", __func__, dev_name(&port->dev));
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -0700974 retval = device_register(&port->dev);
975 if (retval)
976 dev_err(&port->dev, "Error registering port device, "
977 "continuing\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 }
979
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100980 usb_serial_console_init(debug, minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982exit:
983 /* success */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100984 usb_set_intfdata(interface, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 return 0;
986
987probe_error:
988 for (i = 0; i < num_bulk_in; ++i) {
989 port = serial->port[i];
990 if (!port)
991 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +0100992 usb_free_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 kfree(port->bulk_in_buffer);
994 }
995 for (i = 0; i < num_bulk_out; ++i) {
996 port = serial->port[i];
997 if (!port)
998 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +0100999 usb_free_urb(port->write_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 kfree(port->bulk_out_buffer);
1001 }
1002 for (i = 0; i < num_interrupt_in; ++i) {
1003 port = serial->port[i];
1004 if (!port)
1005 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001006 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 kfree(port->interrupt_in_buffer);
1008 }
1009 for (i = 0; i < num_interrupt_out; ++i) {
1010 port = serial->port[i];
1011 if (!port)
1012 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001013 usb_free_urb(port->interrupt_out_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 kfree(port->interrupt_out_buffer);
1015 }
1016
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 /* free up any memory that we allocated */
1018 for (i = 0; i < serial->num_port_pointers; ++i)
1019 kfree(serial->port[i]);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001020 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 return -EIO;
1022}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001023EXPORT_SYMBOL_GPL(usb_serial_probe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025void usb_serial_disconnect(struct usb_interface *interface)
1026{
1027 int i;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001028 struct usb_serial *serial = usb_get_intfdata(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 struct device *dev = &interface->dev;
1030 struct usb_serial_port *port;
1031
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +02001032 usb_serial_console_disconnect(serial);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001033 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001035 mutex_lock(&serial->disc_mutex);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001036 usb_set_intfdata(interface, NULL);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001037 /* must set a flag, to signal subdrivers */
1038 serial->disconnected = 1;
1039 for (i = 0; i < serial->num_ports; ++i) {
1040 port = serial->port[i];
1041 if (port) {
Alan Cox95da3102008-07-22 11:09:07 +01001042 if (port->port.tty)
1043 tty_hangup(port->port.tty);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001044 kill_traffic(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001047 /* let the last holder of this object
1048 * cause it to be cleaned up */
1049 mutex_unlock(&serial->disc_mutex);
1050 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 dev_info(dev, "device disconnected\n");
1052}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001053EXPORT_SYMBOL_GPL(usb_serial_disconnect);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054
Oliver Neukumec225592007-04-27 20:54:57 +02001055int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1056{
1057 struct usb_serial *serial = usb_get_intfdata(intf);
1058 struct usb_serial_port *port;
1059 int i, r = 0;
1060
Oliver Neukume31c1882007-07-23 08:58:39 +02001061 for (i = 0; i < serial->num_ports; ++i) {
1062 port = serial->port[i];
1063 if (port)
1064 kill_traffic(port);
Oliver Neukumec225592007-04-27 20:54:57 +02001065 }
1066
1067 if (serial->type->suspend)
Oliver Neukume31c1882007-07-23 08:58:39 +02001068 r = serial->type->suspend(serial, message);
Oliver Neukumec225592007-04-27 20:54:57 +02001069
1070 return r;
1071}
1072EXPORT_SYMBOL(usb_serial_suspend);
1073
1074int usb_serial_resume(struct usb_interface *intf)
1075{
1076 struct usb_serial *serial = usb_get_intfdata(intf);
1077
Sarah Sharp8abaee22007-10-25 10:58:43 -07001078 if (serial->type->resume)
1079 return serial->type->resume(serial);
1080 return 0;
Oliver Neukumec225592007-04-27 20:54:57 +02001081}
1082EXPORT_SYMBOL(usb_serial_resume);
1083
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001084static const struct tty_operations serial_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 .open = serial_open,
1086 .close = serial_close,
1087 .write = serial_write,
1088 .write_room = serial_write_room,
1089 .ioctl = serial_ioctl,
1090 .set_termios = serial_set_termios,
1091 .throttle = serial_throttle,
1092 .unthrottle = serial_unthrottle,
1093 .break_ctl = serial_break,
1094 .chars_in_buffer = serial_chars_in_buffer,
1095 .read_proc = serial_read_proc,
1096 .tiocmget = serial_tiocmget,
1097 .tiocmset = serial_tiocmset,
1098};
1099
1100struct tty_driver *usb_serial_tty_driver;
1101
1102static int __init usb_serial_init(void)
1103{
1104 int i;
1105 int result;
1106
1107 usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
1108 if (!usb_serial_tty_driver)
1109 return -ENOMEM;
1110
1111 /* Initialize our global data */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001112 for (i = 0; i < SERIAL_TTY_MINORS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 serial_table[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
1115 result = bus_register(&usb_serial_bus_type);
1116 if (result) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001117 err("%s - registering bus driver failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 goto exit_bus;
1119 }
1120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 usb_serial_tty_driver->owner = THIS_MODULE;
1122 usb_serial_tty_driver->driver_name = "usbserial";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 usb_serial_tty_driver->name = "ttyUSB";
1124 usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
1125 usb_serial_tty_driver->minor_start = 0;
1126 usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
1127 usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001128 usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
1129 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 usb_serial_tty_driver->init_termios = tty_std_termios;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001131 usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
1132 | HUPCL | CLOCAL;
Alan Coxa5b6f602008-04-08 17:16:06 +01001133 usb_serial_tty_driver->init_termios.c_ispeed = 9600;
1134 usb_serial_tty_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 tty_set_operations(usb_serial_tty_driver, &serial_ops);
1136 result = tty_register_driver(usb_serial_tty_driver);
1137 if (result) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001138 err("%s - tty_register_driver failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 goto exit_reg_driver;
1140 }
1141
1142 /* register the USB driver */
1143 result = usb_register(&usb_serial_driver);
1144 if (result < 0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001145 err("%s - usb_register failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 goto exit_tty;
1147 }
1148
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001149 /* register the generic driver, if we should */
1150 result = usb_serial_generic_register(debug);
1151 if (result < 0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001152 err("%s - registering generic driver failed", __func__);
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001153 goto exit_generic;
1154 }
1155
Greg Kroah-Hartman17a882f2005-06-20 21:15:16 -07001156 info(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
1158 return result;
1159
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001160exit_generic:
1161 usb_deregister(&usb_serial_driver);
1162
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163exit_tty:
1164 tty_unregister_driver(usb_serial_tty_driver);
1165
1166exit_reg_driver:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 bus_unregister(&usb_serial_bus_type);
1168
1169exit_bus:
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001170 err("%s - returning with error %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 put_tty_driver(usb_serial_tty_driver);
1172 return result;
1173}
1174
1175
1176static void __exit usb_serial_exit(void)
1177{
1178 usb_serial_console_exit();
1179
1180 usb_serial_generic_deregister();
1181
1182 usb_deregister(&usb_serial_driver);
1183 tty_unregister_driver(usb_serial_tty_driver);
1184 put_tty_driver(usb_serial_tty_driver);
1185 bus_unregister(&usb_serial_bus_type);
1186}
1187
1188
1189module_init(usb_serial_init);
1190module_exit(usb_serial_exit);
1191
1192#define set_to_generic_if_null(type, function) \
1193 do { \
1194 if (!type->function) { \
1195 type->function = usb_serial_generic_##function; \
1196 dbg("Had to override the " #function \
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001197 " usb serial operation with the generic one.");\
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 } \
1199 } while (0)
1200
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001201static void fixup_generic(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
1203 set_to_generic_if_null(device, open);
1204 set_to_generic_if_null(device, write);
1205 set_to_generic_if_null(device, close);
1206 set_to_generic_if_null(device, write_room);
1207 set_to_generic_if_null(device, chars_in_buffer);
1208 set_to_generic_if_null(device, read_bulk_callback);
1209 set_to_generic_if_null(device, write_bulk_callback);
1210 set_to_generic_if_null(device, shutdown);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -08001211 set_to_generic_if_null(device, resume);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212}
1213
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001214int usb_serial_register(struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001216 /* must be called with BKL held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 int retval;
1218
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001219 fixup_generic(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001221 if (!driver->description)
1222 driver->description = driver->driver.name;
1223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 /* Add this device to our list of devices */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001225 list_add(&driver->driver_list, &usb_serial_driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001227 retval = usb_serial_bus_register(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 if (retval) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001229 err("problem %d when registering driver %s",
1230 retval, driver->description);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001231 list_del(&driver->driver_list);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001232 } else
1233 info("USB Serial support registered for %s",
1234 driver->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
1236 return retval;
1237}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001238EXPORT_SYMBOL_GPL(usb_serial_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
1240
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001241void usb_serial_deregister(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001243 /* must be called with BKL held */
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001244 info("USB Serial deregistering driver %s", device->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 list_del(&device->driver_list);
1246 usb_serial_bus_deregister(device);
1247}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248EXPORT_SYMBOL_GPL(usb_serial_deregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250/* Module information */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001251MODULE_AUTHOR(DRIVER_AUTHOR);
1252MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253MODULE_LICENSE("GPL");
1254
1255module_param(debug, bool, S_IRUGO | S_IWUSR);
1256MODULE_PARM_DESC(debug, "Debug enabled or not");