blob: 080ade223d53fe1306206f8b0f93388f75c17246 [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 Cox4bd43f22009-01-02 13:44:04 +0000272 if (port->port.count == 1)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100273 /* only call the device specific close if this
Alan Cox4bd43f22009-01-02 13:44:04 +0000274 * port is being closed by the last owner. Ensure we do
275 * this before we drop the port count. The call is protected
276 * by the port mutex
277 */
Alan Cox95da3102008-07-22 11:09:07 +0100278 port->serial->type->close(tty, port, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Alan Cox4bd43f22009-01-02 13:44:04 +0000280 if (port->port.count == (port->console ? 2 : 1)) {
Alan Cox4a90f092008-10-13 10:39:46 +0100281 struct tty_struct *tty = tty_port_tty_get(&port->port);
282 if (tty) {
Alan Cox4bd43f22009-01-02 13:44:04 +0000283 /* We must do this before we drop the port count to
284 zero. */
Alan Cox4a90f092008-10-13 10:39:46 +0100285 if (tty->driver_data)
286 tty->driver_data = NULL;
287 tty_port_tty_set(&port->port, NULL);
Alan Coxfce48772008-10-30 15:54:12 +0000288 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 }
291
Alan Cox4bd43f22009-01-02 13:44:04 +0000292 if (port->port.count == 1) {
Oliver Neukum62ad2962008-06-25 13:32:49 +0200293 mutex_lock(&port->serial->disc_mutex);
294 if (!port->serial->disconnected)
295 usb_autopm_put_interface(port->serial->interface);
296 mutex_unlock(&port->serial->disc_mutex);
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500297 module_put(port->serial->type->driver.owner);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -0800298 }
Alan Cox4bd43f22009-01-02 13:44:04 +0000299 --port->port.count;
Aristeu Rozanski9a6b1ef2007-11-12 15:15:02 -0500300
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300301 mutex_unlock(&port->mutex);
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200302 usb_serial_put(port->serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303}
304
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100305static int serial_write(struct tty_struct *tty, const unsigned char *buf,
306 int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200308 struct usb_serial_port *port = tty->driver_data;
Oliver Neukum3ff4fd92007-01-13 07:32:27 +0100309 int retval = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Alan Coxf34d7a52008-04-30 00:54:13 -0700311 if (port->serial->dev->state == USB_STATE_NOTATTACHED)
Luiz Fernando Capitulino487f9c62005-11-28 19:16:05 -0200312 goto exit;
313
Harvey Harrison441b62c2008-03-03 16:08:34 -0800314 dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
Alan Cox95da3102008-07-22 11:09:07 +0100316 /* count is managed under the mutex lock for the tty so cannot
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100317 drop to zero until after the last close completes */
Alan Cox95da3102008-07-22 11:09:07 +0100318 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100321 retval = port->serial->type->write(tty, port, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323exit:
324 return retval;
325}
326
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100327static int serial_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200329 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800330 dbg("%s - port %d", __func__, port->number);
Alan Cox95da3102008-07-22 11:09:07 +0100331 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100333 return port->serial->type->write_room(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100336static int serial_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200338 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800339 dbg("%s = port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Alan Cox95da3102008-07-22 11:09:07 +0100341 WARN_ON(!port->port.count);
Alan Coxeff69372009-01-02 13:47:06 +0000342 /* if the device was unplugged then any remaining characters
343 fell out of the connector ;) */
344 if (port->serial->disconnected)
345 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100347 return port->serial->type->chars_in_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348}
349
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100350static void serial_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200352 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800353 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
Alan Cox95da3102008-07-22 11:09:07 +0100355 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 /* pass on to the driver specific version of this function */
357 if (port->serial->type->throttle)
Alan Cox95da3102008-07-22 11:09:07 +0100358 port->serial->type->throttle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100361static void serial_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200363 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800364 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Alan Cox95da3102008-07-22 11:09:07 +0100366 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 /* pass on to the driver specific version of this function */
368 if (port->serial->type->unthrottle)
Alan Cox95da3102008-07-22 11:09:07 +0100369 port->serial->type->unthrottle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370}
371
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100372static int serial_ioctl(struct tty_struct *tty, struct file *file,
373 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200375 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 int retval = -ENODEV;
377
Harvey Harrison441b62c2008-03-03 16:08:34 -0800378 dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Alan Cox95da3102008-07-22 11:09:07 +0100380 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100382 /* pass on to the driver specific version of this function
383 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700384 if (port->serial->type->ioctl) {
Alan Cox95da3102008-07-22 11:09:07 +0100385 retval = port->serial->type->ioctl(tty, file, cmd, arg);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100386 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 return retval;
389}
390
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100391static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200393 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800394 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Alan Cox95da3102008-07-22 11:09:07 +0100396 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100397 /* pass on to the driver specific version of this function
398 if it is available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 if (port->serial->type->set_termios)
Alan Cox95da3102008-07-22 11:09:07 +0100400 port->serial->type->set_termios(tty, port, old);
Alan Cox33785092007-10-18 01:24:22 -0700401 else
402 tty_termios_copy_hw(tty->termios, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
404
Alan Cox9e989662008-07-22 11:18:03 +0100405static int serial_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200407 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Harvey Harrison441b62c2008-03-03 16:08:34 -0800409 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Alan Cox95da3102008-07-22 11:09:07 +0100411 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100412 /* pass on to the driver specific version of this function
413 if it is available */
Alan Cox6b447f042009-01-02 13:48:56 +0000414 if (port->serial->type->break_ctl)
Alan Cox95da3102008-07-22 11:09:07 +0100415 port->serial->type->break_ctl(tty, break_state);
Alan Cox9e989662008-07-22 11:18:03 +0100416 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417}
418
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100419static int serial_read_proc(char *page, char **start, off_t off, int count,
420 int *eof, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421{
422 struct usb_serial *serial;
423 int length = 0;
424 int i;
425 off_t begin = 0;
426 char tmp[40];
427
Harvey Harrison441b62c2008-03-03 16:08:34 -0800428 dbg("%s", __func__);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100429 length += sprintf(page, "usbserinfo:1.0 driver:2.0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
431 serial = usb_serial_get_by_index(i);
432 if (serial == NULL)
433 continue;
434
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100435 length += sprintf(page+length, "%d:", i);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700436 if (serial->type->driver.owner)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100437 length += sprintf(page+length, " module:%s",
438 module_name(serial->type->driver.owner));
439 length += sprintf(page+length, " name:\"%s\"",
440 serial->type->description);
441 length += sprintf(page+length, " vendor:%04x product:%04x",
442 le16_to_cpu(serial->dev->descriptor.idVendor),
443 le16_to_cpu(serial->dev->descriptor.idProduct));
444 length += sprintf(page+length, " num_ports:%d",
445 serial->num_ports);
446 length += sprintf(page+length, " port:%d",
447 i - serial->minor + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 usb_make_path(serial->dev, tmp, sizeof(tmp));
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100449 length += sprintf(page+length, " path:%s", tmp);
450
451 length += sprintf(page+length, "\n");
Matthias Urlichs59925832006-09-11 12:35:20 +0200452 if ((length + begin) > (off + count)) {
453 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 goto done;
Matthias Urlichs59925832006-09-11 12:35:20 +0200455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 if ((length + begin) < off) {
457 begin += length;
458 length = 0;
459 }
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200460 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 }
462 *eof = 1;
463done:
464 if (off >= (length + begin))
465 return 0;
466 *start = page + (off-begin);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100467 return (count < begin+length-off) ? count : begin+length-off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468}
469
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100470static int serial_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200472 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Harvey Harrison441b62c2008-03-03 16:08:34 -0800474 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Alan Cox95da3102008-07-22 11:09:07 +0100476 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 if (port->serial->type->tiocmget)
Alan Cox95da3102008-07-22 11:09:07 +0100478 return port->serial->type->tiocmget(tty, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 return -EINVAL;
480}
481
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100482static int serial_tiocmset(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 unsigned int set, unsigned int clear)
484{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200485 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Harvey Harrison441b62c2008-03-03 16:08:34 -0800487 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Alan Cox95da3102008-07-22 11:09:07 +0100489 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 if (port->serial->type->tiocmset)
Alan Cox95da3102008-07-22 11:09:07 +0100491 return port->serial->type->tiocmset(tty, file, set, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 return -EINVAL;
493}
494
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700495/*
496 * We would be calling tty_wakeup here, but unfortunately some line
497 * disciplines have an annoying habit of calling tty->write from
498 * the write wakeup callback (e.g. n_hdlc.c).
499 */
500void usb_serial_port_softint(struct usb_serial_port *port)
501{
502 schedule_work(&port->work);
503}
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100504EXPORT_SYMBOL_GPL(usb_serial_port_softint);
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700505
David Howellsc4028952006-11-22 14:57:56 +0000506static void usb_serial_port_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
David Howellsc4028952006-11-22 14:57:56 +0000508 struct usb_serial_port *port =
509 container_of(work, struct usb_serial_port, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 struct tty_struct *tty;
511
Harvey Harrison441b62c2008-03-03 16:08:34 -0800512 dbg("%s - port %d", __func__, port->number);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if (!port)
515 return;
516
Alan Cox4a90f092008-10-13 10:39:46 +0100517 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 if (!tty)
519 return;
520
521 tty_wakeup(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100522 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523}
524
525static void port_release(struct device *dev)
526{
527 struct usb_serial_port *port = to_usb_serial_port(dev);
528
Kay Sievers7071a3c2008-05-02 06:02:41 +0200529 dbg ("%s - %s", __func__, dev_name(dev));
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700530 port_free(port);
531}
532
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100533static void kill_traffic(struct usb_serial_port *port)
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700534{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 usb_kill_urb(port->write_urb);
Oliver Neukum5adceac2007-08-17 14:01:38 +0200537 /*
538 * This is tricky.
539 * Some drivers submit the read_urb in the
540 * handler for the write_urb or vice versa
541 * this order determines the order in which
542 * usb_kill_urb() must be used to reliably
543 * kill the URBs. As it is unknown here,
544 * both orders must be used in turn.
545 * The call below is not redundant.
546 */
547 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 usb_kill_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 usb_kill_urb(port->interrupt_out_urb);
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100550}
551
552static void port_free(struct usb_serial_port *port)
553{
554 kill_traffic(port);
555 usb_free_urb(port->read_urb);
556 usb_free_urb(port->write_urb);
557 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 usb_free_urb(port->interrupt_out_urb);
559 kfree(port->bulk_in_buffer);
560 kfree(port->bulk_out_buffer);
561 kfree(port->interrupt_in_buffer);
562 kfree(port->interrupt_out_buffer);
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700563 flush_scheduled_work(); /* port->work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 kfree(port);
565}
566
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100567static struct usb_serial *create_serial(struct usb_device *dev,
568 struct usb_interface *interface,
569 struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 struct usb_serial *serial;
572
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100573 serial = kzalloc(sizeof(*serial), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 if (!serial) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800575 dev_err(&dev->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return NULL;
577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 serial->dev = usb_get_dev(dev);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700579 serial->type = driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 serial->interface = interface;
581 kref_init(&serial->kref);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +0100582 mutex_init(&serial->disc_mutex);
Alan Stern0282b7f2008-07-29 12:01:04 -0400583 serial->minor = SERIAL_TTY_NO_MINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
585 return serial;
586}
587
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100588static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100589 struct usb_serial_driver *drv)
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100590{
591 struct usb_dynid *dynid;
592
593 spin_lock(&drv->dynids.lock);
594 list_for_each_entry(dynid, &drv->dynids.list, node) {
595 if (usb_match_one_id(intf, &dynid->id)) {
596 spin_unlock(&drv->dynids.lock);
597 return &dynid->id;
598 }
599 }
600 spin_unlock(&drv->dynids.lock);
601 return NULL;
602}
603
604static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
605 struct usb_interface *intf)
606{
607 const struct usb_device_id *id;
608
609 id = usb_match_id(intf, drv->id_table);
610 if (id) {
611 dbg("static descriptor matches");
612 goto exit;
613 }
614 id = match_dynamic_id(intf, drv);
615 if (id)
616 dbg("dynamic descriptor matches");
617exit:
618 return id;
619}
620
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100621static struct usb_serial_driver *search_serial_device(
622 struct usb_interface *iface)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 const struct usb_device_id *id;
Alan Stern063a2da2007-10-10 16:24:06 -0400625 struct usb_serial_driver *drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
Adrian Bunk93b1fae2006-01-10 00:13:33 +0100627 /* Check if the usb id matches a known device */
Alan Stern063a2da2007-10-10 16:24:06 -0400628 list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
629 id = get_iface_id(drv, iface);
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100630 if (id)
Alan Stern063a2da2007-10-10 16:24:06 -0400631 return drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 }
633
634 return NULL;
635}
636
637int usb_serial_probe(struct usb_interface *interface,
638 const struct usb_device_id *id)
639{
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100640 struct usb_device *dev = interface_to_usbdev(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 struct usb_serial *serial = NULL;
642 struct usb_serial_port *port;
643 struct usb_host_interface *iface_desc;
644 struct usb_endpoint_descriptor *endpoint;
645 struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
646 struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
647 struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
648 struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700649 struct usb_serial_driver *type = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 int retval;
Andre Hauptdd9ca5d2008-06-18 15:56:00 +0200651 unsigned int minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 int buffer_size;
653 int i;
654 int num_interrupt_in = 0;
655 int num_interrupt_out = 0;
656 int num_bulk_in = 0;
657 int num_bulk_out = 0;
658 int num_ports = 0;
659 int max_endpoints;
660
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100661 lock_kernel(); /* guard against unloading a serial driver module */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 type = search_serial_device(interface);
663 if (!type) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100664 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 dbg("none matched");
666 return -ENODEV;
667 }
668
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100669 serial = create_serial(dev, interface, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 if (!serial) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100671 unlock_kernel();
Harvey Harrison441b62c2008-03-03 16:08:34 -0800672 dev_err(&interface->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 return -ENOMEM;
674 }
675
676 /* if this device type has a probe function, call it */
677 if (type->probe) {
678 const struct usb_device_id *id;
679
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700680 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100681 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100682 dev_err(&interface->dev,
683 "module get failed, exiting\n");
684 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return -EIO;
686 }
687
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100688 id = get_iface_id(type, interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 retval = type->probe(serial, id);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700690 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692 if (retval) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100693 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100694 dbg("sub driver rejected device");
695 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return retval;
697 }
698 }
699
700 /* descriptor matches, let's find the endpoints needed */
701 /* check out the endpoints */
702 iface_desc = interface->cur_altsetting;
703 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
704 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700705
706 if (usb_endpoint_is_bulk_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* we found a bulk in endpoint */
708 dbg("found bulk in on endpoint %d", i);
709 bulk_in_endpoint[num_bulk_in] = endpoint;
710 ++num_bulk_in;
711 }
712
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700713 if (usb_endpoint_is_bulk_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 /* we found a bulk out endpoint */
715 dbg("found bulk out on endpoint %d", i);
716 bulk_out_endpoint[num_bulk_out] = endpoint;
717 ++num_bulk_out;
718 }
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700719
720 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 /* we found a interrupt in endpoint */
722 dbg("found interrupt in on endpoint %d", i);
723 interrupt_in_endpoint[num_interrupt_in] = endpoint;
724 ++num_interrupt_in;
725 }
726
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700727 if (usb_endpoint_is_int_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 /* we found an interrupt out endpoint */
729 dbg("found interrupt out on endpoint %d", i);
730 interrupt_out_endpoint[num_interrupt_out] = endpoint;
731 ++num_interrupt_out;
732 }
733 }
734
735#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100736 /* BEGIN HORRIBLE HACK FOR PL2303 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 /* this is needed due to the looney way its endpoints are set up */
738 if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
739 (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
740 ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
Johannes Steingraeber8fd80132006-09-16 16:17:34 +0200741 (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
742 ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
Andreas Bombece816cf2008-09-14 01:58:55 +0200743 (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) ||
744 ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
745 (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (interface != dev->actconfig->interface[0]) {
747 /* check out the endpoints of the other interface*/
748 iface_desc = dev->actconfig->interface[0]->cur_altsetting;
749 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
750 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700751 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 /* we found a interrupt in endpoint */
753 dbg("found interrupt in for Prolific device on separate interface");
754 interrupt_in_endpoint[num_interrupt_in] = endpoint;
755 ++num_interrupt_in;
756 }
757 }
758 }
759
760 /* Now make sure the PL-2303 is configured correctly.
761 * If not, give up now and hope this hack will work
762 * properly during a later invocation of usb_serial_probe
763 */
764 if (num_bulk_in == 0 || num_bulk_out == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100765 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100767 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 return -ENODEV;
769 }
770 }
771 /* END HORRIBLE HACK FOR PL2303 */
772#endif
773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774#ifdef CONFIG_USB_SERIAL_GENERIC
775 if (type == &usb_serial_generic_device) {
776 num_ports = num_bulk_out;
777 if (num_ports == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100778 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100779 dev_err(&interface->dev,
780 "Generic device with no bulk out, not allowed.\n");
781 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return -EIO;
783 }
784 }
785#endif
786 if (!num_ports) {
787 /* if this device type has a calc_num_ports function, call it */
788 if (type->calc_num_ports) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700789 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100790 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100791 dev_err(&interface->dev,
792 "module get failed, exiting\n");
793 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 return -EIO;
795 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100796 num_ports = type->calc_num_ports(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700797 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 }
799 if (!num_ports)
800 num_ports = type->num_ports;
801 }
802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 serial->num_ports = num_ports;
804 serial->num_bulk_in = num_bulk_in;
805 serial->num_bulk_out = num_bulk_out;
806 serial->num_interrupt_in = num_interrupt_in;
807 serial->num_interrupt_out = num_interrupt_out;
808
Alan Stern063a2da2007-10-10 16:24:06 -0400809 /* found all that we need */
810 dev_info(&interface->dev, "%s converter detected\n",
811 type->description);
812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 /* create our ports, we need as many as the max endpoints */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100814 /* we don't use num_ports here because some devices have more
815 endpoint pairs than ports */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 max_endpoints = max(num_bulk_in, num_bulk_out);
817 max_endpoints = max(max_endpoints, num_interrupt_in);
818 max_endpoints = max(max_endpoints, num_interrupt_out);
819 max_endpoints = max(max_endpoints, (int)serial->num_ports);
820 serial->num_port_pointers = max_endpoints;
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100821 unlock_kernel();
822
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100823 dbg("%s - setting up %d port structures for this device",
824 __func__, max_endpoints);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 for (i = 0; i < max_endpoints; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100826 port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 if (!port)
828 goto probe_error;
Alan Cox4a90f092008-10-13 10:39:46 +0100829 tty_port_init(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 port->serial = serial;
Greg Kroah-Hartman507ca9b2005-04-23 12:49:16 -0700831 spin_lock_init(&port->lock);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300832 mutex_init(&port->mutex);
David Howellsc4028952006-11-22 14:57:56 +0000833 INIT_WORK(&port->work, usb_serial_port_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 serial->port[i] = port;
835 }
836
837 /* set up the endpoint information */
838 for (i = 0; i < num_bulk_in; ++i) {
839 endpoint = bulk_in_endpoint[i];
840 port = serial->port[i];
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100841 port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 if (!port->read_urb) {
843 dev_err(&interface->dev, "No free urbs available\n");
844 goto probe_error;
845 }
846 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
847 port->bulk_in_size = buffer_size;
848 port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100849 port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (!port->bulk_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100851 dev_err(&interface->dev,
852 "Couldn't allocate bulk_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 goto probe_error;
854 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100855 usb_fill_bulk_urb(port->read_urb, dev,
856 usb_rcvbulkpipe(dev,
857 endpoint->bEndpointAddress),
858 port->bulk_in_buffer, buffer_size,
859 serial->type->read_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 }
861
862 for (i = 0; i < num_bulk_out; ++i) {
863 endpoint = bulk_out_endpoint[i];
864 port = serial->port[i];
865 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
866 if (!port->write_urb) {
867 dev_err(&interface->dev, "No free urbs available\n");
868 goto probe_error;
869 }
870 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
871 port->bulk_out_size = buffer_size;
872 port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100873 port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 if (!port->bulk_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100875 dev_err(&interface->dev,
876 "Couldn't allocate bulk_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 goto probe_error;
878 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100879 usb_fill_bulk_urb(port->write_urb, dev,
880 usb_sndbulkpipe(dev,
881 endpoint->bEndpointAddress),
882 port->bulk_out_buffer, buffer_size,
883 serial->type->write_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 }
885
886 if (serial->type->read_int_callback) {
887 for (i = 0; i < num_interrupt_in; ++i) {
888 endpoint = interrupt_in_endpoint[i];
889 port = serial->port[i];
890 port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
891 if (!port->interrupt_in_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100892 dev_err(&interface->dev,
893 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 goto probe_error;
895 }
896 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100897 port->interrupt_in_endpointAddress =
898 endpoint->bEndpointAddress;
899 port->interrupt_in_buffer = kmalloc(buffer_size,
900 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (!port->interrupt_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100902 dev_err(&interface->dev,
903 "Couldn't allocate interrupt_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 goto probe_error;
905 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100906 usb_fill_int_urb(port->interrupt_in_urb, dev,
907 usb_rcvintpipe(dev,
908 endpoint->bEndpointAddress),
909 port->interrupt_in_buffer, buffer_size,
910 serial->type->read_int_callback, port,
911 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 }
913 } else if (num_interrupt_in) {
914 dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
915 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100916
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 if (serial->type->write_int_callback) {
918 for (i = 0; i < num_interrupt_out; ++i) {
919 endpoint = interrupt_out_endpoint[i];
920 port = serial->port[i];
921 port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
922 if (!port->interrupt_out_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100923 dev_err(&interface->dev,
924 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 goto probe_error;
926 }
927 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
928 port->interrupt_out_size = buffer_size;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100929 port->interrupt_out_endpointAddress =
930 endpoint->bEndpointAddress;
931 port->interrupt_out_buffer = kmalloc(buffer_size,
932 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 if (!port->interrupt_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100934 dev_err(&interface->dev,
935 "Couldn't allocate interrupt_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 goto probe_error;
937 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100938 usb_fill_int_urb(port->interrupt_out_urb, dev,
939 usb_sndintpipe(dev,
940 endpoint->bEndpointAddress),
941 port->interrupt_out_buffer, buffer_size,
942 serial->type->write_int_callback, port,
943 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 }
945 } else if (num_interrupt_out) {
946 dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
947 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100948
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 /* if this device type has an attach function, call it */
950 if (type->attach) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700951 if (!try_module_get(type->driver.owner)) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100952 dev_err(&interface->dev,
953 "module get failed, exiting\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 goto probe_error;
955 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100956 retval = type->attach(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700957 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 if (retval < 0)
959 goto probe_error;
960 if (retval > 0) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100961 /* quietly accept this device, but don't bind to a
962 serial port as it's about to disappear */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 goto exit;
964 }
965 }
966
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100967 if (get_free_serial(serial, num_ports, &minor) == NULL) {
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100968 dev_err(&interface->dev, "No more free serial devices\n");
969 goto probe_error;
970 }
Oliver Neukumc744f992007-02-26 15:43:00 +0100971 serial->minor = minor;
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100972
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 /* register all of the individual ports with the driver core */
974 for (i = 0; i < num_ports; ++i) {
975 port = serial->port[i];
976 port->dev.parent = &interface->dev;
977 port->dev.driver = NULL;
978 port->dev.bus = &usb_serial_bus_type;
979 port->dev.release = &port_release;
980
Kay Sievers0031a062008-05-02 06:02:41 +0200981 dev_set_name(&port->dev, "ttyUSB%d", port->number);
Kay Sievers7071a3c2008-05-02 06:02:41 +0200982 dbg ("%s - registering %s", __func__, dev_name(&port->dev));
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -0700983 retval = device_register(&port->dev);
984 if (retval)
985 dev_err(&port->dev, "Error registering port device, "
986 "continuing\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 }
988
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100989 usb_serial_console_init(debug, minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991exit:
992 /* success */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100993 usb_set_intfdata(interface, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 return 0;
995
996probe_error:
997 for (i = 0; i < num_bulk_in; ++i) {
998 port = serial->port[i];
999 if (!port)
1000 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001001 usb_free_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 kfree(port->bulk_in_buffer);
1003 }
1004 for (i = 0; i < num_bulk_out; ++i) {
1005 port = serial->port[i];
1006 if (!port)
1007 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001008 usb_free_urb(port->write_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 kfree(port->bulk_out_buffer);
1010 }
1011 for (i = 0; i < num_interrupt_in; ++i) {
1012 port = serial->port[i];
1013 if (!port)
1014 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001015 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 kfree(port->interrupt_in_buffer);
1017 }
1018 for (i = 0; i < num_interrupt_out; ++i) {
1019 port = serial->port[i];
1020 if (!port)
1021 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001022 usb_free_urb(port->interrupt_out_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 kfree(port->interrupt_out_buffer);
1024 }
1025
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 /* free up any memory that we allocated */
1027 for (i = 0; i < serial->num_port_pointers; ++i)
1028 kfree(serial->port[i]);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001029 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 return -EIO;
1031}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001032EXPORT_SYMBOL_GPL(usb_serial_probe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034void usb_serial_disconnect(struct usb_interface *interface)
1035{
1036 int i;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001037 struct usb_serial *serial = usb_get_intfdata(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 struct device *dev = &interface->dev;
1039 struct usb_serial_port *port;
1040
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +02001041 usb_serial_console_disconnect(serial);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001042 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001044 mutex_lock(&serial->disc_mutex);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001045 usb_set_intfdata(interface, NULL);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001046 /* must set a flag, to signal subdrivers */
1047 serial->disconnected = 1;
1048 for (i = 0; i < serial->num_ports; ++i) {
1049 port = serial->port[i];
1050 if (port) {
Alan Cox4a90f092008-10-13 10:39:46 +01001051 struct tty_struct *tty = tty_port_tty_get(&port->port);
1052 if (tty) {
1053 tty_hangup(tty);
1054 tty_kref_put(tty);
1055 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001056 kill_traffic(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001059 /* let the last holder of this object
1060 * cause it to be cleaned up */
1061 mutex_unlock(&serial->disc_mutex);
1062 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 dev_info(dev, "device disconnected\n");
1064}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001065EXPORT_SYMBOL_GPL(usb_serial_disconnect);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Oliver Neukumec225592007-04-27 20:54:57 +02001067int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1068{
1069 struct usb_serial *serial = usb_get_intfdata(intf);
1070 struct usb_serial_port *port;
1071 int i, r = 0;
1072
Oliver Neukume31c1882007-07-23 08:58:39 +02001073 for (i = 0; i < serial->num_ports; ++i) {
1074 port = serial->port[i];
1075 if (port)
1076 kill_traffic(port);
Oliver Neukumec225592007-04-27 20:54:57 +02001077 }
1078
1079 if (serial->type->suspend)
Oliver Neukume31c1882007-07-23 08:58:39 +02001080 r = serial->type->suspend(serial, message);
Oliver Neukumec225592007-04-27 20:54:57 +02001081
1082 return r;
1083}
1084EXPORT_SYMBOL(usb_serial_suspend);
1085
1086int usb_serial_resume(struct usb_interface *intf)
1087{
1088 struct usb_serial *serial = usb_get_intfdata(intf);
1089
Sarah Sharp8abaee22007-10-25 10:58:43 -07001090 if (serial->type->resume)
1091 return serial->type->resume(serial);
1092 return 0;
Oliver Neukumec225592007-04-27 20:54:57 +02001093}
1094EXPORT_SYMBOL(usb_serial_resume);
1095
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001096static const struct tty_operations serial_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 .open = serial_open,
1098 .close = serial_close,
1099 .write = serial_write,
1100 .write_room = serial_write_room,
1101 .ioctl = serial_ioctl,
1102 .set_termios = serial_set_termios,
1103 .throttle = serial_throttle,
1104 .unthrottle = serial_unthrottle,
1105 .break_ctl = serial_break,
1106 .chars_in_buffer = serial_chars_in_buffer,
1107 .read_proc = serial_read_proc,
1108 .tiocmget = serial_tiocmget,
1109 .tiocmset = serial_tiocmset,
1110};
1111
1112struct tty_driver *usb_serial_tty_driver;
1113
1114static int __init usb_serial_init(void)
1115{
1116 int i;
1117 int result;
1118
1119 usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
1120 if (!usb_serial_tty_driver)
1121 return -ENOMEM;
1122
1123 /* Initialize our global data */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001124 for (i = 0; i < SERIAL_TTY_MINORS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 serial_table[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
1127 result = bus_register(&usb_serial_bus_type);
1128 if (result) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001129 printk(KERN_ERR "usb-serial: %s - registering bus driver "
1130 "failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 goto exit_bus;
1132 }
1133
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 usb_serial_tty_driver->owner = THIS_MODULE;
1135 usb_serial_tty_driver->driver_name = "usbserial";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 usb_serial_tty_driver->name = "ttyUSB";
1137 usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
1138 usb_serial_tty_driver->minor_start = 0;
1139 usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
1140 usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001141 usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
1142 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 usb_serial_tty_driver->init_termios = tty_std_termios;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001144 usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
1145 | HUPCL | CLOCAL;
Alan Coxa5b6f602008-04-08 17:16:06 +01001146 usb_serial_tty_driver->init_termios.c_ispeed = 9600;
1147 usb_serial_tty_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 tty_set_operations(usb_serial_tty_driver, &serial_ops);
1149 result = tty_register_driver(usb_serial_tty_driver);
1150 if (result) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001151 printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n",
1152 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 goto exit_reg_driver;
1154 }
1155
1156 /* register the USB driver */
1157 result = usb_register(&usb_serial_driver);
1158 if (result < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001159 printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
1160 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 goto exit_tty;
1162 }
1163
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001164 /* register the generic driver, if we should */
1165 result = usb_serial_generic_register(debug);
1166 if (result < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001167 printk(KERN_ERR "usb-serial: %s - registering generic "
1168 "driver failed\n", __func__);
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001169 goto exit_generic;
1170 }
1171
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001172 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
1174 return result;
1175
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001176exit_generic:
1177 usb_deregister(&usb_serial_driver);
1178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179exit_tty:
1180 tty_unregister_driver(usb_serial_tty_driver);
1181
1182exit_reg_driver:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 bus_unregister(&usb_serial_bus_type);
1184
1185exit_bus:
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001186 printk(KERN_ERR "usb-serial: %s - returning with error %d\n",
1187 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 put_tty_driver(usb_serial_tty_driver);
1189 return result;
1190}
1191
1192
1193static void __exit usb_serial_exit(void)
1194{
1195 usb_serial_console_exit();
1196
1197 usb_serial_generic_deregister();
1198
1199 usb_deregister(&usb_serial_driver);
1200 tty_unregister_driver(usb_serial_tty_driver);
1201 put_tty_driver(usb_serial_tty_driver);
1202 bus_unregister(&usb_serial_bus_type);
1203}
1204
1205
1206module_init(usb_serial_init);
1207module_exit(usb_serial_exit);
1208
1209#define set_to_generic_if_null(type, function) \
1210 do { \
1211 if (!type->function) { \
1212 type->function = usb_serial_generic_##function; \
1213 dbg("Had to override the " #function \
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001214 " usb serial operation with the generic one.");\
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 } \
1216 } while (0)
1217
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001218static void fixup_generic(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219{
1220 set_to_generic_if_null(device, open);
1221 set_to_generic_if_null(device, write);
1222 set_to_generic_if_null(device, close);
1223 set_to_generic_if_null(device, write_room);
1224 set_to_generic_if_null(device, chars_in_buffer);
1225 set_to_generic_if_null(device, read_bulk_callback);
1226 set_to_generic_if_null(device, write_bulk_callback);
1227 set_to_generic_if_null(device, shutdown);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -08001228 set_to_generic_if_null(device, resume);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229}
1230
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001231int usb_serial_register(struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001233 /* must be called with BKL held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 int retval;
1235
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001236 fixup_generic(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001238 if (!driver->description)
1239 driver->description = driver->driver.name;
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 /* Add this device to our list of devices */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001242 list_add(&driver->driver_list, &usb_serial_driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001244 retval = usb_serial_bus_register(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 if (retval) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001246 printk(KERN_ERR "usb-serial: problem %d when registering "
1247 "driver %s\n", retval, driver->description);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001248 list_del(&driver->driver_list);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001249 } else
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001250 printk(KERN_INFO "USB Serial support registered for %s\n",
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001251 driver->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
1253 return retval;
1254}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001255EXPORT_SYMBOL_GPL(usb_serial_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001258void usb_serial_deregister(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001260 /* must be called with BKL held */
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001261 printk(KERN_INFO "USB Serial deregistering driver %s\n",
1262 device->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 list_del(&device->driver_list);
1264 usb_serial_bus_deregister(device);
1265}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266EXPORT_SYMBOL_GPL(usb_serial_deregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267
1268/* Module information */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001269MODULE_AUTHOR(DRIVER_AUTHOR);
1270MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271MODULE_LICENSE("GPL");
1272
1273module_param(debug, bool, S_IRUGO | S_IWUSR);
1274MODULE_PARM_DESC(debug, "Debug enabled or not");