blob: 794b5ffe4397bcfd84f38c3d7affaebac6be77af [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 Cox4a90f092008-10-13 10:39:46 +0100217 tty_port_tty_set(&port->port, 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 Cox4a90f092008-10-13 10:39:46 +0100249 tty_port_tty_set(&port->port, 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)) {
Alan Cox4a90f092008-10-13 10:39:46 +0100279 struct tty_struct *tty = tty_port_tty_get(&port->port);
280 if (tty) {
281 if (tty->driver_data)
282 tty->driver_data = NULL;
283 tty_port_tty_set(&port->port, NULL);
Alan Coxfce48772008-10-30 15:54:12 +0000284 tty_kref_put(tty);
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 Cox4a90f092008-10-13 10:39:46 +0100513 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if (!tty)
515 return;
516
517 tty_wakeup(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100518 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519}
520
521static void port_release(struct device *dev)
522{
523 struct usb_serial_port *port = to_usb_serial_port(dev);
524
Kay Sievers7071a3c2008-05-02 06:02:41 +0200525 dbg ("%s - %s", __func__, dev_name(dev));
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700526 port_free(port);
527}
528
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100529static void kill_traffic(struct usb_serial_port *port)
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700530{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 usb_kill_urb(port->write_urb);
Oliver Neukum5adceac2007-08-17 14:01:38 +0200533 /*
534 * This is tricky.
535 * Some drivers submit the read_urb in the
536 * handler for the write_urb or vice versa
537 * this order determines the order in which
538 * usb_kill_urb() must be used to reliably
539 * kill the URBs. As it is unknown here,
540 * both orders must be used in turn.
541 * The call below is not redundant.
542 */
543 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 usb_kill_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 usb_kill_urb(port->interrupt_out_urb);
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100546}
547
548static void port_free(struct usb_serial_port *port)
549{
550 kill_traffic(port);
551 usb_free_urb(port->read_urb);
552 usb_free_urb(port->write_urb);
553 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 usb_free_urb(port->interrupt_out_urb);
555 kfree(port->bulk_in_buffer);
556 kfree(port->bulk_out_buffer);
557 kfree(port->interrupt_in_buffer);
558 kfree(port->interrupt_out_buffer);
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700559 flush_scheduled_work(); /* port->work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 kfree(port);
561}
562
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100563static struct usb_serial *create_serial(struct usb_device *dev,
564 struct usb_interface *interface,
565 struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
567 struct usb_serial *serial;
568
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100569 serial = kzalloc(sizeof(*serial), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (!serial) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800571 dev_err(&dev->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 return NULL;
573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 serial->dev = usb_get_dev(dev);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700575 serial->type = driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 serial->interface = interface;
577 kref_init(&serial->kref);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +0100578 mutex_init(&serial->disc_mutex);
Alan Stern0282b7f2008-07-29 12:01:04 -0400579 serial->minor = SERIAL_TTY_NO_MINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581 return serial;
582}
583
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100584static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100585 struct usb_serial_driver *drv)
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100586{
587 struct usb_dynid *dynid;
588
589 spin_lock(&drv->dynids.lock);
590 list_for_each_entry(dynid, &drv->dynids.list, node) {
591 if (usb_match_one_id(intf, &dynid->id)) {
592 spin_unlock(&drv->dynids.lock);
593 return &dynid->id;
594 }
595 }
596 spin_unlock(&drv->dynids.lock);
597 return NULL;
598}
599
600static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
601 struct usb_interface *intf)
602{
603 const struct usb_device_id *id;
604
605 id = usb_match_id(intf, drv->id_table);
606 if (id) {
607 dbg("static descriptor matches");
608 goto exit;
609 }
610 id = match_dynamic_id(intf, drv);
611 if (id)
612 dbg("dynamic descriptor matches");
613exit:
614 return id;
615}
616
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100617static struct usb_serial_driver *search_serial_device(
618 struct usb_interface *iface)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 const struct usb_device_id *id;
Alan Stern063a2da2007-10-10 16:24:06 -0400621 struct usb_serial_driver *drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
Adrian Bunk93b1fae2006-01-10 00:13:33 +0100623 /* Check if the usb id matches a known device */
Alan Stern063a2da2007-10-10 16:24:06 -0400624 list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
625 id = get_iface_id(drv, iface);
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100626 if (id)
Alan Stern063a2da2007-10-10 16:24:06 -0400627 return drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
629
630 return NULL;
631}
632
633int usb_serial_probe(struct usb_interface *interface,
634 const struct usb_device_id *id)
635{
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100636 struct usb_device *dev = interface_to_usbdev(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 struct usb_serial *serial = NULL;
638 struct usb_serial_port *port;
639 struct usb_host_interface *iface_desc;
640 struct usb_endpoint_descriptor *endpoint;
641 struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
642 struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
643 struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
644 struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700645 struct usb_serial_driver *type = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 int retval;
Andre Hauptdd9ca5d2008-06-18 15:56:00 +0200647 unsigned int minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 int buffer_size;
649 int i;
650 int num_interrupt_in = 0;
651 int num_interrupt_out = 0;
652 int num_bulk_in = 0;
653 int num_bulk_out = 0;
654 int num_ports = 0;
655 int max_endpoints;
656
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100657 lock_kernel(); /* guard against unloading a serial driver module */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 type = search_serial_device(interface);
659 if (!type) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100660 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 dbg("none matched");
662 return -ENODEV;
663 }
664
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100665 serial = create_serial(dev, interface, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 if (!serial) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100667 unlock_kernel();
Harvey Harrison441b62c2008-03-03 16:08:34 -0800668 dev_err(&interface->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 return -ENOMEM;
670 }
671
672 /* if this device type has a probe function, call it */
673 if (type->probe) {
674 const struct usb_device_id *id;
675
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700676 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100677 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100678 dev_err(&interface->dev,
679 "module get failed, exiting\n");
680 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return -EIO;
682 }
683
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100684 id = get_iface_id(type, interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 retval = type->probe(serial, id);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700686 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 if (retval) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100689 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100690 dbg("sub driver rejected device");
691 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return retval;
693 }
694 }
695
696 /* descriptor matches, let's find the endpoints needed */
697 /* check out the endpoints */
698 iface_desc = interface->cur_altsetting;
699 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
700 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700701
702 if (usb_endpoint_is_bulk_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 /* we found a bulk in endpoint */
704 dbg("found bulk in on endpoint %d", i);
705 bulk_in_endpoint[num_bulk_in] = endpoint;
706 ++num_bulk_in;
707 }
708
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700709 if (usb_endpoint_is_bulk_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 /* we found a bulk out endpoint */
711 dbg("found bulk out on endpoint %d", i);
712 bulk_out_endpoint[num_bulk_out] = endpoint;
713 ++num_bulk_out;
714 }
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700715
716 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 /* we found a interrupt in endpoint */
718 dbg("found interrupt in on endpoint %d", i);
719 interrupt_in_endpoint[num_interrupt_in] = endpoint;
720 ++num_interrupt_in;
721 }
722
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700723 if (usb_endpoint_is_int_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 /* we found an interrupt out endpoint */
725 dbg("found interrupt out on endpoint %d", i);
726 interrupt_out_endpoint[num_interrupt_out] = endpoint;
727 ++num_interrupt_out;
728 }
729 }
730
731#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100732 /* BEGIN HORRIBLE HACK FOR PL2303 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 /* this is needed due to the looney way its endpoints are set up */
734 if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
735 (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
736 ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
Johannes Steingraeber8fd80132006-09-16 16:17:34 +0200737 (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
738 ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
Andreas Bombece816cf2008-09-14 01:58:55 +0200739 (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) ||
740 ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
741 (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 if (interface != dev->actconfig->interface[0]) {
743 /* check out the endpoints of the other interface*/
744 iface_desc = dev->actconfig->interface[0]->cur_altsetting;
745 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
746 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700747 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 /* we found a interrupt in endpoint */
749 dbg("found interrupt in for Prolific device on separate interface");
750 interrupt_in_endpoint[num_interrupt_in] = endpoint;
751 ++num_interrupt_in;
752 }
753 }
754 }
755
756 /* Now make sure the PL-2303 is configured correctly.
757 * If not, give up now and hope this hack will work
758 * properly during a later invocation of usb_serial_probe
759 */
760 if (num_bulk_in == 0 || num_bulk_out == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100761 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100763 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return -ENODEV;
765 }
766 }
767 /* END HORRIBLE HACK FOR PL2303 */
768#endif
769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770#ifdef CONFIG_USB_SERIAL_GENERIC
771 if (type == &usb_serial_generic_device) {
772 num_ports = num_bulk_out;
773 if (num_ports == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100774 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100775 dev_err(&interface->dev,
776 "Generic device with no bulk out, not allowed.\n");
777 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return -EIO;
779 }
780 }
781#endif
782 if (!num_ports) {
783 /* if this device type has a calc_num_ports function, call it */
784 if (type->calc_num_ports) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700785 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100786 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100787 dev_err(&interface->dev,
788 "module get failed, exiting\n");
789 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 return -EIO;
791 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100792 num_ports = type->calc_num_ports(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700793 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 }
795 if (!num_ports)
796 num_ports = type->num_ports;
797 }
798
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 serial->num_ports = num_ports;
800 serial->num_bulk_in = num_bulk_in;
801 serial->num_bulk_out = num_bulk_out;
802 serial->num_interrupt_in = num_interrupt_in;
803 serial->num_interrupt_out = num_interrupt_out;
804
Alan Stern063a2da2007-10-10 16:24:06 -0400805 /* found all that we need */
806 dev_info(&interface->dev, "%s converter detected\n",
807 type->description);
808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 /* create our ports, we need as many as the max endpoints */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100810 /* we don't use num_ports here because some devices have more
811 endpoint pairs than ports */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 max_endpoints = max(num_bulk_in, num_bulk_out);
813 max_endpoints = max(max_endpoints, num_interrupt_in);
814 max_endpoints = max(max_endpoints, num_interrupt_out);
815 max_endpoints = max(max_endpoints, (int)serial->num_ports);
816 serial->num_port_pointers = max_endpoints;
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100817 unlock_kernel();
818
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100819 dbg("%s - setting up %d port structures for this device",
820 __func__, max_endpoints);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 for (i = 0; i < max_endpoints; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100822 port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 if (!port)
824 goto probe_error;
Alan Cox4a90f092008-10-13 10:39:46 +0100825 tty_port_init(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 port->serial = serial;
Greg Kroah-Hartman507ca9b2005-04-23 12:49:16 -0700827 spin_lock_init(&port->lock);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300828 mutex_init(&port->mutex);
David Howellsc4028952006-11-22 14:57:56 +0000829 INIT_WORK(&port->work, usb_serial_port_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 serial->port[i] = port;
831 }
832
833 /* set up the endpoint information */
834 for (i = 0; i < num_bulk_in; ++i) {
835 endpoint = bulk_in_endpoint[i];
836 port = serial->port[i];
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100837 port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (!port->read_urb) {
839 dev_err(&interface->dev, "No free urbs available\n");
840 goto probe_error;
841 }
842 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
843 port->bulk_in_size = buffer_size;
844 port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100845 port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 if (!port->bulk_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100847 dev_err(&interface->dev,
848 "Couldn't allocate bulk_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 goto probe_error;
850 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100851 usb_fill_bulk_urb(port->read_urb, dev,
852 usb_rcvbulkpipe(dev,
853 endpoint->bEndpointAddress),
854 port->bulk_in_buffer, buffer_size,
855 serial->type->read_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 }
857
858 for (i = 0; i < num_bulk_out; ++i) {
859 endpoint = bulk_out_endpoint[i];
860 port = serial->port[i];
861 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
862 if (!port->write_urb) {
863 dev_err(&interface->dev, "No free urbs available\n");
864 goto probe_error;
865 }
866 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
867 port->bulk_out_size = buffer_size;
868 port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100869 port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 if (!port->bulk_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100871 dev_err(&interface->dev,
872 "Couldn't allocate bulk_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 goto probe_error;
874 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100875 usb_fill_bulk_urb(port->write_urb, dev,
876 usb_sndbulkpipe(dev,
877 endpoint->bEndpointAddress),
878 port->bulk_out_buffer, buffer_size,
879 serial->type->write_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 }
881
882 if (serial->type->read_int_callback) {
883 for (i = 0; i < num_interrupt_in; ++i) {
884 endpoint = interrupt_in_endpoint[i];
885 port = serial->port[i];
886 port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
887 if (!port->interrupt_in_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100888 dev_err(&interface->dev,
889 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 goto probe_error;
891 }
892 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100893 port->interrupt_in_endpointAddress =
894 endpoint->bEndpointAddress;
895 port->interrupt_in_buffer = kmalloc(buffer_size,
896 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 if (!port->interrupt_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100898 dev_err(&interface->dev,
899 "Couldn't allocate interrupt_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 goto probe_error;
901 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100902 usb_fill_int_urb(port->interrupt_in_urb, dev,
903 usb_rcvintpipe(dev,
904 endpoint->bEndpointAddress),
905 port->interrupt_in_buffer, buffer_size,
906 serial->type->read_int_callback, port,
907 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 }
909 } else if (num_interrupt_in) {
910 dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
911 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100912
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 if (serial->type->write_int_callback) {
914 for (i = 0; i < num_interrupt_out; ++i) {
915 endpoint = interrupt_out_endpoint[i];
916 port = serial->port[i];
917 port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
918 if (!port->interrupt_out_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100919 dev_err(&interface->dev,
920 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 goto probe_error;
922 }
923 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
924 port->interrupt_out_size = buffer_size;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100925 port->interrupt_out_endpointAddress =
926 endpoint->bEndpointAddress;
927 port->interrupt_out_buffer = kmalloc(buffer_size,
928 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 if (!port->interrupt_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100930 dev_err(&interface->dev,
931 "Couldn't allocate interrupt_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 goto probe_error;
933 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100934 usb_fill_int_urb(port->interrupt_out_urb, dev,
935 usb_sndintpipe(dev,
936 endpoint->bEndpointAddress),
937 port->interrupt_out_buffer, buffer_size,
938 serial->type->write_int_callback, port,
939 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 }
941 } else if (num_interrupt_out) {
942 dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
943 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100944
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 /* if this device type has an attach function, call it */
946 if (type->attach) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700947 if (!try_module_get(type->driver.owner)) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100948 dev_err(&interface->dev,
949 "module get failed, exiting\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 goto probe_error;
951 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100952 retval = type->attach(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700953 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 if (retval < 0)
955 goto probe_error;
956 if (retval > 0) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100957 /* quietly accept this device, but don't bind to a
958 serial port as it's about to disappear */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 goto exit;
960 }
961 }
962
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100963 if (get_free_serial(serial, num_ports, &minor) == NULL) {
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100964 dev_err(&interface->dev, "No more free serial devices\n");
965 goto probe_error;
966 }
Oliver Neukumc744f992007-02-26 15:43:00 +0100967 serial->minor = minor;
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100968
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 /* register all of the individual ports with the driver core */
970 for (i = 0; i < num_ports; ++i) {
971 port = serial->port[i];
972 port->dev.parent = &interface->dev;
973 port->dev.driver = NULL;
974 port->dev.bus = &usb_serial_bus_type;
975 port->dev.release = &port_release;
976
Kay Sievers0031a062008-05-02 06:02:41 +0200977 dev_set_name(&port->dev, "ttyUSB%d", port->number);
Kay Sievers7071a3c2008-05-02 06:02:41 +0200978 dbg ("%s - registering %s", __func__, dev_name(&port->dev));
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -0700979 retval = device_register(&port->dev);
980 if (retval)
981 dev_err(&port->dev, "Error registering port device, "
982 "continuing\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 }
984
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100985 usb_serial_console_init(debug, minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987exit:
988 /* success */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100989 usb_set_intfdata(interface, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 return 0;
991
992probe_error:
993 for (i = 0; i < num_bulk_in; ++i) {
994 port = serial->port[i];
995 if (!port)
996 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +0100997 usb_free_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 kfree(port->bulk_in_buffer);
999 }
1000 for (i = 0; i < num_bulk_out; ++i) {
1001 port = serial->port[i];
1002 if (!port)
1003 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001004 usb_free_urb(port->write_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 kfree(port->bulk_out_buffer);
1006 }
1007 for (i = 0; i < num_interrupt_in; ++i) {
1008 port = serial->port[i];
1009 if (!port)
1010 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001011 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 kfree(port->interrupt_in_buffer);
1013 }
1014 for (i = 0; i < num_interrupt_out; ++i) {
1015 port = serial->port[i];
1016 if (!port)
1017 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001018 usb_free_urb(port->interrupt_out_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 kfree(port->interrupt_out_buffer);
1020 }
1021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 /* free up any memory that we allocated */
1023 for (i = 0; i < serial->num_port_pointers; ++i)
1024 kfree(serial->port[i]);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001025 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 return -EIO;
1027}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001028EXPORT_SYMBOL_GPL(usb_serial_probe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030void usb_serial_disconnect(struct usb_interface *interface)
1031{
1032 int i;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001033 struct usb_serial *serial = usb_get_intfdata(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 struct device *dev = &interface->dev;
1035 struct usb_serial_port *port;
1036
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +02001037 usb_serial_console_disconnect(serial);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001038 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001040 mutex_lock(&serial->disc_mutex);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001041 usb_set_intfdata(interface, NULL);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001042 /* must set a flag, to signal subdrivers */
1043 serial->disconnected = 1;
1044 for (i = 0; i < serial->num_ports; ++i) {
1045 port = serial->port[i];
1046 if (port) {
Alan Cox4a90f092008-10-13 10:39:46 +01001047 struct tty_struct *tty = tty_port_tty_get(&port->port);
1048 if (tty) {
1049 tty_hangup(tty);
1050 tty_kref_put(tty);
1051 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001052 kill_traffic(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001055 /* let the last holder of this object
1056 * cause it to be cleaned up */
1057 mutex_unlock(&serial->disc_mutex);
1058 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 dev_info(dev, "device disconnected\n");
1060}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001061EXPORT_SYMBOL_GPL(usb_serial_disconnect);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
Oliver Neukumec225592007-04-27 20:54:57 +02001063int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1064{
1065 struct usb_serial *serial = usb_get_intfdata(intf);
1066 struct usb_serial_port *port;
1067 int i, r = 0;
1068
Oliver Neukume31c1882007-07-23 08:58:39 +02001069 for (i = 0; i < serial->num_ports; ++i) {
1070 port = serial->port[i];
1071 if (port)
1072 kill_traffic(port);
Oliver Neukumec225592007-04-27 20:54:57 +02001073 }
1074
1075 if (serial->type->suspend)
Oliver Neukume31c1882007-07-23 08:58:39 +02001076 r = serial->type->suspend(serial, message);
Oliver Neukumec225592007-04-27 20:54:57 +02001077
1078 return r;
1079}
1080EXPORT_SYMBOL(usb_serial_suspend);
1081
1082int usb_serial_resume(struct usb_interface *intf)
1083{
1084 struct usb_serial *serial = usb_get_intfdata(intf);
1085
Sarah Sharp8abaee22007-10-25 10:58:43 -07001086 if (serial->type->resume)
1087 return serial->type->resume(serial);
1088 return 0;
Oliver Neukumec225592007-04-27 20:54:57 +02001089}
1090EXPORT_SYMBOL(usb_serial_resume);
1091
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001092static const struct tty_operations serial_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 .open = serial_open,
1094 .close = serial_close,
1095 .write = serial_write,
1096 .write_room = serial_write_room,
1097 .ioctl = serial_ioctl,
1098 .set_termios = serial_set_termios,
1099 .throttle = serial_throttle,
1100 .unthrottle = serial_unthrottle,
1101 .break_ctl = serial_break,
1102 .chars_in_buffer = serial_chars_in_buffer,
1103 .read_proc = serial_read_proc,
1104 .tiocmget = serial_tiocmget,
1105 .tiocmset = serial_tiocmset,
1106};
1107
1108struct tty_driver *usb_serial_tty_driver;
1109
1110static int __init usb_serial_init(void)
1111{
1112 int i;
1113 int result;
1114
1115 usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
1116 if (!usb_serial_tty_driver)
1117 return -ENOMEM;
1118
1119 /* Initialize our global data */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001120 for (i = 0; i < SERIAL_TTY_MINORS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 serial_table[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
1123 result = bus_register(&usb_serial_bus_type);
1124 if (result) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001125 printk(KERN_ERR "usb-serial: %s - registering bus driver "
1126 "failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 goto exit_bus;
1128 }
1129
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 usb_serial_tty_driver->owner = THIS_MODULE;
1131 usb_serial_tty_driver->driver_name = "usbserial";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 usb_serial_tty_driver->name = "ttyUSB";
1133 usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
1134 usb_serial_tty_driver->minor_start = 0;
1135 usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
1136 usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001137 usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
1138 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 usb_serial_tty_driver->init_termios = tty_std_termios;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001140 usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
1141 | HUPCL | CLOCAL;
Alan Coxa5b6f602008-04-08 17:16:06 +01001142 usb_serial_tty_driver->init_termios.c_ispeed = 9600;
1143 usb_serial_tty_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 tty_set_operations(usb_serial_tty_driver, &serial_ops);
1145 result = tty_register_driver(usb_serial_tty_driver);
1146 if (result) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001147 printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n",
1148 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 goto exit_reg_driver;
1150 }
1151
1152 /* register the USB driver */
1153 result = usb_register(&usb_serial_driver);
1154 if (result < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001155 printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
1156 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 goto exit_tty;
1158 }
1159
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001160 /* register the generic driver, if we should */
1161 result = usb_serial_generic_register(debug);
1162 if (result < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001163 printk(KERN_ERR "usb-serial: %s - registering generic "
1164 "driver failed\n", __func__);
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001165 goto exit_generic;
1166 }
1167
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001168 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
1170 return result;
1171
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001172exit_generic:
1173 usb_deregister(&usb_serial_driver);
1174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175exit_tty:
1176 tty_unregister_driver(usb_serial_tty_driver);
1177
1178exit_reg_driver:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 bus_unregister(&usb_serial_bus_type);
1180
1181exit_bus:
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001182 printk(KERN_ERR "usb-serial: %s - returning with error %d\n",
1183 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 put_tty_driver(usb_serial_tty_driver);
1185 return result;
1186}
1187
1188
1189static void __exit usb_serial_exit(void)
1190{
1191 usb_serial_console_exit();
1192
1193 usb_serial_generic_deregister();
1194
1195 usb_deregister(&usb_serial_driver);
1196 tty_unregister_driver(usb_serial_tty_driver);
1197 put_tty_driver(usb_serial_tty_driver);
1198 bus_unregister(&usb_serial_bus_type);
1199}
1200
1201
1202module_init(usb_serial_init);
1203module_exit(usb_serial_exit);
1204
1205#define set_to_generic_if_null(type, function) \
1206 do { \
1207 if (!type->function) { \
1208 type->function = usb_serial_generic_##function; \
1209 dbg("Had to override the " #function \
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001210 " usb serial operation with the generic one.");\
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 } \
1212 } while (0)
1213
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001214static void fixup_generic(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
1216 set_to_generic_if_null(device, open);
1217 set_to_generic_if_null(device, write);
1218 set_to_generic_if_null(device, close);
1219 set_to_generic_if_null(device, write_room);
1220 set_to_generic_if_null(device, chars_in_buffer);
1221 set_to_generic_if_null(device, read_bulk_callback);
1222 set_to_generic_if_null(device, write_bulk_callback);
1223 set_to_generic_if_null(device, shutdown);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -08001224 set_to_generic_if_null(device, resume);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225}
1226
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001227int usb_serial_register(struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001229 /* must be called with BKL held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 int retval;
1231
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001232 fixup_generic(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001234 if (!driver->description)
1235 driver->description = driver->driver.name;
1236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 /* Add this device to our list of devices */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001238 list_add(&driver->driver_list, &usb_serial_driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001240 retval = usb_serial_bus_register(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 if (retval) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001242 printk(KERN_ERR "usb-serial: problem %d when registering "
1243 "driver %s\n", retval, driver->description);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001244 list_del(&driver->driver_list);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001245 } else
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001246 printk(KERN_INFO "USB Serial support registered for %s\n",
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001247 driver->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249 return retval;
1250}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001251EXPORT_SYMBOL_GPL(usb_serial_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
1253
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001254void usb_serial_deregister(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001256 /* must be called with BKL held */
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001257 printk(KERN_INFO "USB Serial deregistering driver %s\n",
1258 device->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 list_del(&device->driver_list);
1260 usb_serial_bus_deregister(device);
1261}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262EXPORT_SYMBOL_GPL(usb_serial_deregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
1264/* Module information */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001265MODULE_AUTHOR(DRIVER_AUTHOR);
1266MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267MODULE_LICENSE("GPL");
1268
1269module_param(debug, bool, S_IRUGO | S_IWUSR);
1270MODULE_PARM_DESC(debug, "Debug enabled or not");