blob: 92ba4f7361e47c835d31681d70f5af772341619e [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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 }
286
Alan Cox95da3102008-07-22 11:09:07 +0100287 if (port->port.count == 0) {
Oliver Neukum62ad2962008-06-25 13:32:49 +0200288 mutex_lock(&port->serial->disc_mutex);
289 if (!port->serial->disconnected)
290 usb_autopm_put_interface(port->serial->interface);
291 mutex_unlock(&port->serial->disc_mutex);
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500292 module_put(port->serial->type->driver.owner);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800293 }
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500294
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300295 mutex_unlock(&port->mutex);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200296 usb_serial_put(port->serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297}
298
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100299static int serial_write(struct tty_struct *tty, const unsigned char *buf,
300 int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200302 struct usb_serial_port *port = tty->driver_data;
Oliver Neukum3ff4fd92007-01-13 07:32:27 +0100303 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Alan Coxf34d7a52008-04-30 00:54:13 -0700305 if (port->serial->dev->state == USB_STATE_NOTATTACHED)
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200306 goto exit;
307
Harvey Harrison441b62c2008-03-03 16:08:34 -0800308 dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Alan Cox95da3102008-07-22 11:09:07 +0100310 /* count is managed under the mutex lock for the tty so cannot
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100311 drop to zero until after the last close completes */
Alan Cox95da3102008-07-22 11:09:07 +0100312 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100315 retval = port->serial->type->write(tty, port, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317exit:
318 return retval;
319}
320
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100321static int serial_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200323 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800324 dbg("%s - port %d", __func__, port->number);
Alan Cox95da3102008-07-22 11:09:07 +0100325 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100327 return port->serial->type->write_room(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328}
329
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100330static int serial_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200332 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800333 dbg("%s = port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Alan Cox95da3102008-07-22 11:09:07 +0100335 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100337 return port->serial->type->chars_in_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338}
339
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100340static void serial_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200342 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800343 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Alan Cox95da3102008-07-22 11:09:07 +0100345 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 /* pass on to the driver specific version of this function */
347 if (port->serial->type->throttle)
Alan Cox95da3102008-07-22 11:09:07 +0100348 port->serial->type->throttle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349}
350
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100351static void serial_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200353 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800354 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
Alan Cox95da3102008-07-22 11:09:07 +0100356 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 /* pass on to the driver specific version of this function */
358 if (port->serial->type->unthrottle)
Alan Cox95da3102008-07-22 11:09:07 +0100359 port->serial->type->unthrottle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100362static int serial_ioctl(struct tty_struct *tty, struct file *file,
363 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200365 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 int retval = -ENODEV;
367
Harvey Harrison441b62c2008-03-03 16:08:34 -0800368 dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Alan Cox95da3102008-07-22 11:09:07 +0100370 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100372 /* pass on to the driver specific version of this function
373 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700374 if (port->serial->type->ioctl) {
375 lock_kernel();
Alan Cox95da3102008-07-22 11:09:07 +0100376 retval = port->serial->type->ioctl(tty, file, cmd, arg);
Alan Coxf34d7a52008-04-30 00:54:13 -0700377 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100378 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 return retval;
381}
382
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100383static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200385 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800386 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
Alan Cox95da3102008-07-22 11:09:07 +0100388 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100389 /* pass on to the driver specific version of this function
390 if it is available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 if (port->serial->type->set_termios)
Alan Cox95da3102008-07-22 11:09:07 +0100392 port->serial->type->set_termios(tty, port, old);
Alan Cox33785092007-10-18 01:24:22 -0700393 else
394 tty_termios_copy_hw(tty->termios, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395}
396
Alan Cox9e989662008-07-22 11:18:03 +0100397static int serial_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200399 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Harvey Harrison441b62c2008-03-03 16:08:34 -0800401 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Alan Cox95da3102008-07-22 11:09:07 +0100403 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100404 /* pass on to the driver specific version of this function
405 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700406 if (port->serial->type->break_ctl) {
407 lock_kernel();
Alan Cox95da3102008-07-22 11:09:07 +0100408 port->serial->type->break_ctl(tty, break_state);
Alan Coxf34d7a52008-04-30 00:54:13 -0700409 unlock_kernel();
410 }
Alan Cox9e989662008-07-22 11:18:03 +0100411 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412}
413
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100414static int serial_read_proc(char *page, char **start, off_t off, int count,
415 int *eof, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416{
417 struct usb_serial *serial;
418 int length = 0;
419 int i;
420 off_t begin = 0;
421 char tmp[40];
422
Harvey Harrison441b62c2008-03-03 16:08:34 -0800423 dbg("%s", __func__);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100424 length += sprintf(page, "usbserinfo:1.0 driver:2.0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
426 serial = usb_serial_get_by_index(i);
427 if (serial == NULL)
428 continue;
429
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100430 length += sprintf(page+length, "%d:", i);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700431 if (serial->type->driver.owner)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100432 length += sprintf(page+length, " module:%s",
433 module_name(serial->type->driver.owner));
434 length += sprintf(page+length, " name:\"%s\"",
435 serial->type->description);
436 length += sprintf(page+length, " vendor:%04x product:%04x",
437 le16_to_cpu(serial->dev->descriptor.idVendor),
438 le16_to_cpu(serial->dev->descriptor.idProduct));
439 length += sprintf(page+length, " num_ports:%d",
440 serial->num_ports);
441 length += sprintf(page+length, " port:%d",
442 i - serial->minor + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 usb_make_path(serial->dev, tmp, sizeof(tmp));
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100444 length += sprintf(page+length, " path:%s", tmp);
445
446 length += sprintf(page+length, "\n");
Matthias Urlichs59925832006-09-11 12:35:20 +0200447 if ((length + begin) > (off + count)) {
448 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 goto done;
Matthias Urlichs59925832006-09-11 12:35:20 +0200450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 if ((length + begin) < off) {
452 begin += length;
453 length = 0;
454 }
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200455 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 }
457 *eof = 1;
458done:
459 if (off >= (length + begin))
460 return 0;
461 *start = page + (off-begin);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100462 return (count < begin+length-off) ? count : begin+length-off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463}
464
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100465static int serial_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200467 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Harvey Harrison441b62c2008-03-03 16:08:34 -0800469 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
Alan Cox95da3102008-07-22 11:09:07 +0100471 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 if (port->serial->type->tiocmget)
Alan Cox95da3102008-07-22 11:09:07 +0100473 return port->serial->type->tiocmget(tty, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 return -EINVAL;
475}
476
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100477static int serial_tiocmset(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 unsigned int set, unsigned int clear)
479{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200480 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Harvey Harrison441b62c2008-03-03 16:08:34 -0800482 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Alan Cox95da3102008-07-22 11:09:07 +0100484 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 if (port->serial->type->tiocmset)
Alan Cox95da3102008-07-22 11:09:07 +0100486 return port->serial->type->tiocmset(tty, file, set, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 return -EINVAL;
488}
489
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700490/*
491 * We would be calling tty_wakeup here, but unfortunately some line
492 * disciplines have an annoying habit of calling tty->write from
493 * the write wakeup callback (e.g. n_hdlc.c).
494 */
495void usb_serial_port_softint(struct usb_serial_port *port)
496{
497 schedule_work(&port->work);
498}
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100499EXPORT_SYMBOL_GPL(usb_serial_port_softint);
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700500
David Howellsc4028952006-11-22 14:57:56 +0000501static void usb_serial_port_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
David Howellsc4028952006-11-22 14:57:56 +0000503 struct usb_serial_port *port =
504 container_of(work, struct usb_serial_port, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 struct tty_struct *tty;
506
Harvey Harrison441b62c2008-03-03 16:08:34 -0800507 dbg("%s - port %d", __func__, port->number);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (!port)
510 return;
511
Alan Cox4a90f092008-10-13 10:39:46 +0100512 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 if (!tty)
514 return;
515
516 tty_wakeup(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100517 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518}
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);
Alan Stern0282b7f2008-07-29 12:01:04 -0400578 serial->minor = SERIAL_TTY_NO_MINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
580 return serial;
581}
582
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100583static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100584 struct usb_serial_driver *drv)
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100585{
586 struct usb_dynid *dynid;
587
588 spin_lock(&drv->dynids.lock);
589 list_for_each_entry(dynid, &drv->dynids.list, node) {
590 if (usb_match_one_id(intf, &dynid->id)) {
591 spin_unlock(&drv->dynids.lock);
592 return &dynid->id;
593 }
594 }
595 spin_unlock(&drv->dynids.lock);
596 return NULL;
597}
598
599static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
600 struct usb_interface *intf)
601{
602 const struct usb_device_id *id;
603
604 id = usb_match_id(intf, drv->id_table);
605 if (id) {
606 dbg("static descriptor matches");
607 goto exit;
608 }
609 id = match_dynamic_id(intf, drv);
610 if (id)
611 dbg("dynamic descriptor matches");
612exit:
613 return id;
614}
615
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100616static struct usb_serial_driver *search_serial_device(
617 struct usb_interface *iface)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 const struct usb_device_id *id;
Alan Stern063a2da2007-10-10 16:24:06 -0400620 struct usb_serial_driver *drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
Adrian Bunk93b1fae2006-01-10 00:13:33 +0100622 /* Check if the usb id matches a known device */
Alan Stern063a2da2007-10-10 16:24:06 -0400623 list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
624 id = get_iface_id(drv, iface);
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100625 if (id)
Alan Stern063a2da2007-10-10 16:24:06 -0400626 return drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
628
629 return NULL;
630}
631
632int usb_serial_probe(struct usb_interface *interface,
633 const struct usb_device_id *id)
634{
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100635 struct usb_device *dev = interface_to_usbdev(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 struct usb_serial *serial = NULL;
637 struct usb_serial_port *port;
638 struct usb_host_interface *iface_desc;
639 struct usb_endpoint_descriptor *endpoint;
640 struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
641 struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
642 struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
643 struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700644 struct usb_serial_driver *type = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 int retval;
Andre Hauptdd9ca5d2008-06-18 15:56:00 +0200646 unsigned int minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 int buffer_size;
648 int i;
649 int num_interrupt_in = 0;
650 int num_interrupt_out = 0;
651 int num_bulk_in = 0;
652 int num_bulk_out = 0;
653 int num_ports = 0;
654 int max_endpoints;
655
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100656 lock_kernel(); /* guard against unloading a serial driver module */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 type = search_serial_device(interface);
658 if (!type) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100659 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 dbg("none matched");
661 return -ENODEV;
662 }
663
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100664 serial = create_serial(dev, interface, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 if (!serial) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100666 unlock_kernel();
Harvey Harrison441b62c2008-03-03 16:08:34 -0800667 dev_err(&interface->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 return -ENOMEM;
669 }
670
671 /* if this device type has a probe function, call it */
672 if (type->probe) {
673 const struct usb_device_id *id;
674
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700675 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100676 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100677 dev_err(&interface->dev,
678 "module get failed, exiting\n");
679 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 return -EIO;
681 }
682
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100683 id = get_iface_id(type, interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 retval = type->probe(serial, id);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700685 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687 if (retval) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100688 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100689 dbg("sub driver rejected device");
690 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return retval;
692 }
693 }
694
695 /* descriptor matches, let's find the endpoints needed */
696 /* check out the endpoints */
697 iface_desc = interface->cur_altsetting;
698 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
699 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700700
701 if (usb_endpoint_is_bulk_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 /* we found a bulk in endpoint */
703 dbg("found bulk in on endpoint %d", i);
704 bulk_in_endpoint[num_bulk_in] = endpoint;
705 ++num_bulk_in;
706 }
707
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700708 if (usb_endpoint_is_bulk_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 /* we found a bulk out endpoint */
710 dbg("found bulk out on endpoint %d", i);
711 bulk_out_endpoint[num_bulk_out] = endpoint;
712 ++num_bulk_out;
713 }
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700714
715 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 /* we found a interrupt in endpoint */
717 dbg("found interrupt in on endpoint %d", i);
718 interrupt_in_endpoint[num_interrupt_in] = endpoint;
719 ++num_interrupt_in;
720 }
721
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700722 if (usb_endpoint_is_int_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 /* we found an interrupt out endpoint */
724 dbg("found interrupt out on endpoint %d", i);
725 interrupt_out_endpoint[num_interrupt_out] = endpoint;
726 ++num_interrupt_out;
727 }
728 }
729
730#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100731 /* BEGIN HORRIBLE HACK FOR PL2303 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 /* this is needed due to the looney way its endpoints are set up */
733 if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
734 (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
735 ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
Johannes Steingraeber8fd80132006-09-16 16:17:34 +0200736 (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
737 ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
Andreas Bombece816cf2008-09-14 01:58:55 +0200738 (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) ||
739 ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
740 (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 if (interface != dev->actconfig->interface[0]) {
742 /* check out the endpoints of the other interface*/
743 iface_desc = dev->actconfig->interface[0]->cur_altsetting;
744 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
745 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700746 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 /* we found a interrupt in endpoint */
748 dbg("found interrupt in for Prolific device on separate interface");
749 interrupt_in_endpoint[num_interrupt_in] = endpoint;
750 ++num_interrupt_in;
751 }
752 }
753 }
754
755 /* Now make sure the PL-2303 is configured correctly.
756 * If not, give up now and hope this hack will work
757 * properly during a later invocation of usb_serial_probe
758 */
759 if (num_bulk_in == 0 || num_bulk_out == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100760 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100762 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return -ENODEV;
764 }
765 }
766 /* END HORRIBLE HACK FOR PL2303 */
767#endif
768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769#ifdef CONFIG_USB_SERIAL_GENERIC
770 if (type == &usb_serial_generic_device) {
771 num_ports = num_bulk_out;
772 if (num_ports == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100773 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100774 dev_err(&interface->dev,
775 "Generic device with no bulk out, not allowed.\n");
776 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 return -EIO;
778 }
779 }
780#endif
781 if (!num_ports) {
782 /* if this device type has a calc_num_ports function, call it */
783 if (type->calc_num_ports) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700784 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100785 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100786 dev_err(&interface->dev,
787 "module get failed, exiting\n");
788 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 return -EIO;
790 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100791 num_ports = type->calc_num_ports(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700792 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
794 if (!num_ports)
795 num_ports = type->num_ports;
796 }
797
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 serial->num_ports = num_ports;
799 serial->num_bulk_in = num_bulk_in;
800 serial->num_bulk_out = num_bulk_out;
801 serial->num_interrupt_in = num_interrupt_in;
802 serial->num_interrupt_out = num_interrupt_out;
803
Alan Stern063a2da2007-10-10 16:24:06 -0400804 /* found all that we need */
805 dev_info(&interface->dev, "%s converter detected\n",
806 type->description);
807
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 /* create our ports, we need as many as the max endpoints */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100809 /* we don't use num_ports here because some devices have more
810 endpoint pairs than ports */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 max_endpoints = max(num_bulk_in, num_bulk_out);
812 max_endpoints = max(max_endpoints, num_interrupt_in);
813 max_endpoints = max(max_endpoints, num_interrupt_out);
814 max_endpoints = max(max_endpoints, (int)serial->num_ports);
815 serial->num_port_pointers = max_endpoints;
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100816 unlock_kernel();
817
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100818 dbg("%s - setting up %d port structures for this device",
819 __func__, max_endpoints);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 for (i = 0; i < max_endpoints; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100821 port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 if (!port)
823 goto probe_error;
Alan Cox4a90f092008-10-13 10:39:46 +0100824 tty_port_init(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 port->serial = serial;
Greg Kroah-Hartman507ca9b2005-04-23 12:49:16 -0700826 spin_lock_init(&port->lock);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300827 mutex_init(&port->mutex);
David Howellsc4028952006-11-22 14:57:56 +0000828 INIT_WORK(&port->work, usb_serial_port_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 serial->port[i] = port;
830 }
831
832 /* set up the endpoint information */
833 for (i = 0; i < num_bulk_in; ++i) {
834 endpoint = bulk_in_endpoint[i];
835 port = serial->port[i];
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100836 port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 if (!port->read_urb) {
838 dev_err(&interface->dev, "No free urbs available\n");
839 goto probe_error;
840 }
841 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
842 port->bulk_in_size = buffer_size;
843 port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100844 port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (!port->bulk_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100846 dev_err(&interface->dev,
847 "Couldn't allocate bulk_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 goto probe_error;
849 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100850 usb_fill_bulk_urb(port->read_urb, dev,
851 usb_rcvbulkpipe(dev,
852 endpoint->bEndpointAddress),
853 port->bulk_in_buffer, buffer_size,
854 serial->type->read_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 }
856
857 for (i = 0; i < num_bulk_out; ++i) {
858 endpoint = bulk_out_endpoint[i];
859 port = serial->port[i];
860 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
861 if (!port->write_urb) {
862 dev_err(&interface->dev, "No free urbs available\n");
863 goto probe_error;
864 }
865 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
866 port->bulk_out_size = buffer_size;
867 port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100868 port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 if (!port->bulk_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100870 dev_err(&interface->dev,
871 "Couldn't allocate bulk_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 goto probe_error;
873 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100874 usb_fill_bulk_urb(port->write_urb, dev,
875 usb_sndbulkpipe(dev,
876 endpoint->bEndpointAddress),
877 port->bulk_out_buffer, buffer_size,
878 serial->type->write_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 }
880
881 if (serial->type->read_int_callback) {
882 for (i = 0; i < num_interrupt_in; ++i) {
883 endpoint = interrupt_in_endpoint[i];
884 port = serial->port[i];
885 port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
886 if (!port->interrupt_in_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100887 dev_err(&interface->dev,
888 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 goto probe_error;
890 }
891 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100892 port->interrupt_in_endpointAddress =
893 endpoint->bEndpointAddress;
894 port->interrupt_in_buffer = kmalloc(buffer_size,
895 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 if (!port->interrupt_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100897 dev_err(&interface->dev,
898 "Couldn't allocate interrupt_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 goto probe_error;
900 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100901 usb_fill_int_urb(port->interrupt_in_urb, dev,
902 usb_rcvintpipe(dev,
903 endpoint->bEndpointAddress),
904 port->interrupt_in_buffer, buffer_size,
905 serial->type->read_int_callback, port,
906 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
908 } else if (num_interrupt_in) {
909 dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
910 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100911
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 if (serial->type->write_int_callback) {
913 for (i = 0; i < num_interrupt_out; ++i) {
914 endpoint = interrupt_out_endpoint[i];
915 port = serial->port[i];
916 port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
917 if (!port->interrupt_out_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100918 dev_err(&interface->dev,
919 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 goto probe_error;
921 }
922 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
923 port->interrupt_out_size = buffer_size;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100924 port->interrupt_out_endpointAddress =
925 endpoint->bEndpointAddress;
926 port->interrupt_out_buffer = kmalloc(buffer_size,
927 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 if (!port->interrupt_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100929 dev_err(&interface->dev,
930 "Couldn't allocate interrupt_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 goto probe_error;
932 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100933 usb_fill_int_urb(port->interrupt_out_urb, dev,
934 usb_sndintpipe(dev,
935 endpoint->bEndpointAddress),
936 port->interrupt_out_buffer, buffer_size,
937 serial->type->write_int_callback, port,
938 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 }
940 } else if (num_interrupt_out) {
941 dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
942 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100943
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 /* if this device type has an attach function, call it */
945 if (type->attach) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700946 if (!try_module_get(type->driver.owner)) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100947 dev_err(&interface->dev,
948 "module get failed, exiting\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 goto probe_error;
950 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100951 retval = type->attach(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700952 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 if (retval < 0)
954 goto probe_error;
955 if (retval > 0) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100956 /* quietly accept this device, but don't bind to a
957 serial port as it's about to disappear */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 goto exit;
959 }
960 }
961
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100962 if (get_free_serial(serial, num_ports, &minor) == NULL) {
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100963 dev_err(&interface->dev, "No more free serial devices\n");
964 goto probe_error;
965 }
Oliver Neukumc744f992007-02-26 15:43:00 +0100966 serial->minor = minor;
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100967
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 /* register all of the individual ports with the driver core */
969 for (i = 0; i < num_ports; ++i) {
970 port = serial->port[i];
971 port->dev.parent = &interface->dev;
972 port->dev.driver = NULL;
973 port->dev.bus = &usb_serial_bus_type;
974 port->dev.release = &port_release;
975
Kay Sievers0031a062008-05-02 06:02:41 +0200976 dev_set_name(&port->dev, "ttyUSB%d", port->number);
Kay Sievers7071a3c2008-05-02 06:02:41 +0200977 dbg ("%s - registering %s", __func__, dev_name(&port->dev));
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -0700978 retval = device_register(&port->dev);
979 if (retval)
980 dev_err(&port->dev, "Error registering port device, "
981 "continuing\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 }
983
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100984 usb_serial_console_init(debug, minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
986exit:
987 /* success */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100988 usb_set_intfdata(interface, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 return 0;
990
991probe_error:
992 for (i = 0; i < num_bulk_in; ++i) {
993 port = serial->port[i];
994 if (!port)
995 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +0100996 usb_free_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 kfree(port->bulk_in_buffer);
998 }
999 for (i = 0; i < num_bulk_out; ++i) {
1000 port = serial->port[i];
1001 if (!port)
1002 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001003 usb_free_urb(port->write_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 kfree(port->bulk_out_buffer);
1005 }
1006 for (i = 0; i < num_interrupt_in; ++i) {
1007 port = serial->port[i];
1008 if (!port)
1009 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001010 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 kfree(port->interrupt_in_buffer);
1012 }
1013 for (i = 0; i < num_interrupt_out; ++i) {
1014 port = serial->port[i];
1015 if (!port)
1016 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001017 usb_free_urb(port->interrupt_out_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 kfree(port->interrupt_out_buffer);
1019 }
1020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 /* free up any memory that we allocated */
1022 for (i = 0; i < serial->num_port_pointers; ++i)
1023 kfree(serial->port[i]);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001024 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return -EIO;
1026}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001027EXPORT_SYMBOL_GPL(usb_serial_probe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
1029void usb_serial_disconnect(struct usb_interface *interface)
1030{
1031 int i;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001032 struct usb_serial *serial = usb_get_intfdata(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 struct device *dev = &interface->dev;
1034 struct usb_serial_port *port;
1035
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +02001036 usb_serial_console_disconnect(serial);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001037 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001039 mutex_lock(&serial->disc_mutex);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001040 usb_set_intfdata(interface, NULL);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001041 /* must set a flag, to signal subdrivers */
1042 serial->disconnected = 1;
1043 for (i = 0; i < serial->num_ports; ++i) {
1044 port = serial->port[i];
1045 if (port) {
Alan Cox4a90f092008-10-13 10:39:46 +01001046 struct tty_struct *tty = tty_port_tty_get(&port->port);
1047 if (tty) {
1048 tty_hangup(tty);
1049 tty_kref_put(tty);
1050 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001051 kill_traffic(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001054 /* let the last holder of this object
1055 * cause it to be cleaned up */
1056 mutex_unlock(&serial->disc_mutex);
1057 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 dev_info(dev, "device disconnected\n");
1059}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001060EXPORT_SYMBOL_GPL(usb_serial_disconnect);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Oliver Neukumec225592007-04-27 20:54:57 +02001062int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1063{
1064 struct usb_serial *serial = usb_get_intfdata(intf);
1065 struct usb_serial_port *port;
1066 int i, r = 0;
1067
Oliver Neukume31c1882007-07-23 08:58:39 +02001068 for (i = 0; i < serial->num_ports; ++i) {
1069 port = serial->port[i];
1070 if (port)
1071 kill_traffic(port);
Oliver Neukumec225592007-04-27 20:54:57 +02001072 }
1073
1074 if (serial->type->suspend)
Oliver Neukume31c1882007-07-23 08:58:39 +02001075 r = serial->type->suspend(serial, message);
Oliver Neukumec225592007-04-27 20:54:57 +02001076
1077 return r;
1078}
1079EXPORT_SYMBOL(usb_serial_suspend);
1080
1081int usb_serial_resume(struct usb_interface *intf)
1082{
1083 struct usb_serial *serial = usb_get_intfdata(intf);
1084
Sarah Sharp8abaee22007-10-25 10:58:43 -07001085 if (serial->type->resume)
1086 return serial->type->resume(serial);
1087 return 0;
Oliver Neukumec225592007-04-27 20:54:57 +02001088}
1089EXPORT_SYMBOL(usb_serial_resume);
1090
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001091static const struct tty_operations serial_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 .open = serial_open,
1093 .close = serial_close,
1094 .write = serial_write,
1095 .write_room = serial_write_room,
1096 .ioctl = serial_ioctl,
1097 .set_termios = serial_set_termios,
1098 .throttle = serial_throttle,
1099 .unthrottle = serial_unthrottle,
1100 .break_ctl = serial_break,
1101 .chars_in_buffer = serial_chars_in_buffer,
1102 .read_proc = serial_read_proc,
1103 .tiocmget = serial_tiocmget,
1104 .tiocmset = serial_tiocmset,
1105};
1106
1107struct tty_driver *usb_serial_tty_driver;
1108
1109static int __init usb_serial_init(void)
1110{
1111 int i;
1112 int result;
1113
1114 usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
1115 if (!usb_serial_tty_driver)
1116 return -ENOMEM;
1117
1118 /* Initialize our global data */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001119 for (i = 0; i < SERIAL_TTY_MINORS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 serial_table[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122 result = bus_register(&usb_serial_bus_type);
1123 if (result) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001124 err("%s - registering bus driver failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 goto exit_bus;
1126 }
1127
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 usb_serial_tty_driver->owner = THIS_MODULE;
1129 usb_serial_tty_driver->driver_name = "usbserial";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 usb_serial_tty_driver->name = "ttyUSB";
1131 usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
1132 usb_serial_tty_driver->minor_start = 0;
1133 usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
1134 usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001135 usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
1136 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 usb_serial_tty_driver->init_termios = tty_std_termios;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001138 usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
1139 | HUPCL | CLOCAL;
Alan Coxa5b6f602008-04-08 17:16:06 +01001140 usb_serial_tty_driver->init_termios.c_ispeed = 9600;
1141 usb_serial_tty_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 tty_set_operations(usb_serial_tty_driver, &serial_ops);
1143 result = tty_register_driver(usb_serial_tty_driver);
1144 if (result) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001145 err("%s - tty_register_driver failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 goto exit_reg_driver;
1147 }
1148
1149 /* register the USB driver */
1150 result = usb_register(&usb_serial_driver);
1151 if (result < 0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001152 err("%s - usb_register failed", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 goto exit_tty;
1154 }
1155
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001156 /* register the generic driver, if we should */
1157 result = usb_serial_generic_register(debug);
1158 if (result < 0) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001159 err("%s - registering generic driver failed", __func__);
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001160 goto exit_generic;
1161 }
1162
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001163 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
1165 return result;
1166
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001167exit_generic:
1168 usb_deregister(&usb_serial_driver);
1169
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170exit_tty:
1171 tty_unregister_driver(usb_serial_tty_driver);
1172
1173exit_reg_driver:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 bus_unregister(&usb_serial_bus_type);
1175
1176exit_bus:
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001177 err("%s - returning with error %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 put_tty_driver(usb_serial_tty_driver);
1179 return result;
1180}
1181
1182
1183static void __exit usb_serial_exit(void)
1184{
1185 usb_serial_console_exit();
1186
1187 usb_serial_generic_deregister();
1188
1189 usb_deregister(&usb_serial_driver);
1190 tty_unregister_driver(usb_serial_tty_driver);
1191 put_tty_driver(usb_serial_tty_driver);
1192 bus_unregister(&usb_serial_bus_type);
1193}
1194
1195
1196module_init(usb_serial_init);
1197module_exit(usb_serial_exit);
1198
1199#define set_to_generic_if_null(type, function) \
1200 do { \
1201 if (!type->function) { \
1202 type->function = usb_serial_generic_##function; \
1203 dbg("Had to override the " #function \
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001204 " usb serial operation with the generic one.");\
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 } \
1206 } while (0)
1207
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001208static void fixup_generic(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209{
1210 set_to_generic_if_null(device, open);
1211 set_to_generic_if_null(device, write);
1212 set_to_generic_if_null(device, close);
1213 set_to_generic_if_null(device, write_room);
1214 set_to_generic_if_null(device, chars_in_buffer);
1215 set_to_generic_if_null(device, read_bulk_callback);
1216 set_to_generic_if_null(device, write_bulk_callback);
1217 set_to_generic_if_null(device, shutdown);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -08001218 set_to_generic_if_null(device, resume);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219}
1220
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001221int usb_serial_register(struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001223 /* must be called with BKL held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 int retval;
1225
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001226 fixup_generic(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001228 if (!driver->description)
1229 driver->description = driver->driver.name;
1230
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 /* Add this device to our list of devices */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001232 list_add(&driver->driver_list, &usb_serial_driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001234 retval = usb_serial_bus_register(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 if (retval) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001236 err("problem %d when registering driver %s",
1237 retval, driver->description);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001238 list_del(&driver->driver_list);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001239 } else
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001240 printk(KERN_INFO "USB Serial support registered for %s\n",
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001241 driver->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
1243 return retval;
1244}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001245EXPORT_SYMBOL_GPL(usb_serial_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001248void usb_serial_deregister(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001250 /* must be called with BKL held */
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001251 printk(KERN_INFO "USB Serial deregistering driver %s\n",
1252 device->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 list_del(&device->driver_list);
1254 usb_serial_bus_deregister(device);
1255}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256EXPORT_SYMBOL_GPL(usb_serial_deregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258/* Module information */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001259MODULE_AUTHOR(DRIVER_AUTHOR);
1260MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261MODULE_LICENSE("GPL");
1262
1263module_param(debug, bool, S_IRUGO | S_IWUSR);
1264MODULE_PARM_DESC(debug, "Debug enabled or not");