blob: aafa684a900facf3ee510efa442468998138b763 [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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 /* pass on to the driver specific version of this function */
Alan Cox95da3102008-07-22 11:09:07 +0100343 return port->serial->type->chars_in_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344}
345
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100346static void serial_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200348 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800349 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Alan Cox95da3102008-07-22 11:09:07 +0100351 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 /* pass on to the driver specific version of this function */
353 if (port->serial->type->throttle)
Alan Cox95da3102008-07-22 11:09:07 +0100354 port->serial->type->throttle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355}
356
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100357static void serial_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200359 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800360 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Alan Cox95da3102008-07-22 11:09:07 +0100362 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 /* pass on to the driver specific version of this function */
364 if (port->serial->type->unthrottle)
Alan Cox95da3102008-07-22 11:09:07 +0100365 port->serial->type->unthrottle(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366}
367
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100368static int serial_ioctl(struct tty_struct *tty, struct file *file,
369 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200371 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 int retval = -ENODEV;
373
Harvey Harrison441b62c2008-03-03 16:08:34 -0800374 dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
Alan Cox95da3102008-07-22 11:09:07 +0100376 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100378 /* pass on to the driver specific version of this function
379 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700380 if (port->serial->type->ioctl) {
381 lock_kernel();
Alan Cox95da3102008-07-22 11:09:07 +0100382 retval = port->serial->type->ioctl(tty, file, cmd, arg);
Alan Coxf34d7a52008-04-30 00:54:13 -0700383 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100384 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 retval = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 return retval;
387}
388
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100389static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200391 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800392 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Alan Cox95da3102008-07-22 11:09:07 +0100394 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100395 /* pass on to the driver specific version of this function
396 if it is available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 if (port->serial->type->set_termios)
Alan Cox95da3102008-07-22 11:09:07 +0100398 port->serial->type->set_termios(tty, port, old);
Alan Cox33785092007-10-18 01:24:22 -0700399 else
400 tty_termios_copy_hw(tty->termios, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401}
402
Alan Cox9e989662008-07-22 11:18:03 +0100403static int serial_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200405 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Harvey Harrison441b62c2008-03-03 16:08:34 -0800407 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Alan Cox95da3102008-07-22 11:09:07 +0100409 WARN_ON(!port->port.count);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100410 /* pass on to the driver specific version of this function
411 if it is available */
Alan Coxf34d7a52008-04-30 00:54:13 -0700412 if (port->serial->type->break_ctl) {
413 lock_kernel();
Alan Cox95da3102008-07-22 11:09:07 +0100414 port->serial->type->break_ctl(tty, break_state);
Alan Coxf34d7a52008-04-30 00:54:13 -0700415 unlock_kernel();
416 }
Alan Cox9e989662008-07-22 11:18:03 +0100417 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418}
419
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100420static int serial_read_proc(char *page, char **start, off_t off, int count,
421 int *eof, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
423 struct usb_serial *serial;
424 int length = 0;
425 int i;
426 off_t begin = 0;
427 char tmp[40];
428
Harvey Harrison441b62c2008-03-03 16:08:34 -0800429 dbg("%s", __func__);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100430 length += sprintf(page, "usbserinfo:1.0 driver:2.0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
432 serial = usb_serial_get_by_index(i);
433 if (serial == NULL)
434 continue;
435
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100436 length += sprintf(page+length, "%d:", i);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700437 if (serial->type->driver.owner)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100438 length += sprintf(page+length, " module:%s",
439 module_name(serial->type->driver.owner));
440 length += sprintf(page+length, " name:\"%s\"",
441 serial->type->description);
442 length += sprintf(page+length, " vendor:%04x product:%04x",
443 le16_to_cpu(serial->dev->descriptor.idVendor),
444 le16_to_cpu(serial->dev->descriptor.idProduct));
445 length += sprintf(page+length, " num_ports:%d",
446 serial->num_ports);
447 length += sprintf(page+length, " port:%d",
448 i - serial->minor + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 usb_make_path(serial->dev, tmp, sizeof(tmp));
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100450 length += sprintf(page+length, " path:%s", tmp);
451
452 length += sprintf(page+length, "\n");
Matthias Urlichs59925832006-09-11 12:35:20 +0200453 if ((length + begin) > (off + count)) {
454 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 goto done;
Matthias Urlichs59925832006-09-11 12:35:20 +0200456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 if ((length + begin) < off) {
458 begin += length;
459 length = 0;
460 }
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +0200461 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 }
463 *eof = 1;
464done:
465 if (off >= (length + begin))
466 return 0;
467 *start = page + (off-begin);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100468 return (count < begin+length-off) ? count : begin+length-off;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469}
470
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100471static int serial_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200473 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
Harvey Harrison441b62c2008-03-03 16:08:34 -0800475 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Alan Cox95da3102008-07-22 11:09:07 +0100477 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 if (port->serial->type->tiocmget)
Alan Cox95da3102008-07-22 11:09:07 +0100479 return port->serial->type->tiocmget(tty, file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 return -EINVAL;
481}
482
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100483static int serial_tiocmset(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 unsigned int set, unsigned int clear)
485{
Tobias Klauser81671dd2005-07-04 19:32:51 +0200486 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Harvey Harrison441b62c2008-03-03 16:08:34 -0800488 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Alan Cox95da3102008-07-22 11:09:07 +0100490 WARN_ON(!port->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 if (port->serial->type->tiocmset)
Alan Cox95da3102008-07-22 11:09:07 +0100492 return port->serial->type->tiocmset(tty, file, set, clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 return -EINVAL;
494}
495
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700496/*
497 * We would be calling tty_wakeup here, but unfortunately some line
498 * disciplines have an annoying habit of calling tty->write from
499 * the write wakeup callback (e.g. n_hdlc.c).
500 */
501void usb_serial_port_softint(struct usb_serial_port *port)
502{
503 schedule_work(&port->work);
504}
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100505EXPORT_SYMBOL_GPL(usb_serial_port_softint);
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700506
David Howellsc4028952006-11-22 14:57:56 +0000507static void usb_serial_port_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
David Howellsc4028952006-11-22 14:57:56 +0000509 struct usb_serial_port *port =
510 container_of(work, struct usb_serial_port, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 struct tty_struct *tty;
512
Harvey Harrison441b62c2008-03-03 16:08:34 -0800513 dbg("%s - port %d", __func__, port->number);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 if (!port)
516 return;
517
Alan Cox4a90f092008-10-13 10:39:46 +0100518 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 if (!tty)
520 return;
521
522 tty_wakeup(tty);
Alan Cox4a90f092008-10-13 10:39:46 +0100523 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524}
525
526static void port_release(struct device *dev)
527{
528 struct usb_serial_port *port = to_usb_serial_port(dev);
529
Kay Sievers7071a3c2008-05-02 06:02:41 +0200530 dbg ("%s - %s", __func__, dev_name(dev));
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700531 port_free(port);
532}
533
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100534static void kill_traffic(struct usb_serial_port *port)
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700535{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 usb_kill_urb(port->write_urb);
Oliver Neukum5adceac2007-08-17 14:01:38 +0200538 /*
539 * This is tricky.
540 * Some drivers submit the read_urb in the
541 * handler for the write_urb or vice versa
542 * this order determines the order in which
543 * usb_kill_urb() must be used to reliably
544 * kill the URBs. As it is unknown here,
545 * both orders must be used in turn.
546 * The call below is not redundant.
547 */
548 usb_kill_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 usb_kill_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 usb_kill_urb(port->interrupt_out_urb);
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100551}
552
553static void port_free(struct usb_serial_port *port)
554{
555 kill_traffic(port);
556 usb_free_urb(port->read_urb);
557 usb_free_urb(port->write_urb);
558 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 usb_free_urb(port->interrupt_out_urb);
560 kfree(port->bulk_in_buffer);
561 kfree(port->bulk_out_buffer);
562 kfree(port->interrupt_in_buffer);
563 kfree(port->interrupt_out_buffer);
Pete Zaitcev34f8e762006-06-21 15:00:45 -0700564 flush_scheduled_work(); /* port->work */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 kfree(port);
566}
567
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100568static struct usb_serial *create_serial(struct usb_device *dev,
569 struct usb_interface *interface,
570 struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
572 struct usb_serial *serial;
573
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100574 serial = kzalloc(sizeof(*serial), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 if (!serial) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800576 dev_err(&dev->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 return NULL;
578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 serial->dev = usb_get_dev(dev);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700580 serial->type = driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 serial->interface = interface;
582 kref_init(&serial->kref);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +0100583 mutex_init(&serial->disc_mutex);
Alan Stern0282b7f2008-07-29 12:01:04 -0400584 serial->minor = SERIAL_TTY_NO_MINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
586 return serial;
587}
588
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100589static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100590 struct usb_serial_driver *drv)
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100591{
592 struct usb_dynid *dynid;
593
594 spin_lock(&drv->dynids.lock);
595 list_for_each_entry(dynid, &drv->dynids.list, node) {
596 if (usb_match_one_id(intf, &dynid->id)) {
597 spin_unlock(&drv->dynids.lock);
598 return &dynid->id;
599 }
600 }
601 spin_unlock(&drv->dynids.lock);
602 return NULL;
603}
604
605static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
606 struct usb_interface *intf)
607{
608 const struct usb_device_id *id;
609
610 id = usb_match_id(intf, drv->id_table);
611 if (id) {
612 dbg("static descriptor matches");
613 goto exit;
614 }
615 id = match_dynamic_id(intf, drv);
616 if (id)
617 dbg("dynamic descriptor matches");
618exit:
619 return id;
620}
621
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100622static struct usb_serial_driver *search_serial_device(
623 struct usb_interface *iface)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 const struct usb_device_id *id;
Alan Stern063a2da2007-10-10 16:24:06 -0400626 struct usb_serial_driver *drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Adrian Bunk93b1fae2006-01-10 00:13:33 +0100628 /* Check if the usb id matches a known device */
Alan Stern063a2da2007-10-10 16:24:06 -0400629 list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
630 id = get_iface_id(drv, iface);
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100631 if (id)
Alan Stern063a2da2007-10-10 16:24:06 -0400632 return drv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 }
634
635 return NULL;
636}
637
638int usb_serial_probe(struct usb_interface *interface,
639 const struct usb_device_id *id)
640{
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100641 struct usb_device *dev = interface_to_usbdev(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 struct usb_serial *serial = NULL;
643 struct usb_serial_port *port;
644 struct usb_host_interface *iface_desc;
645 struct usb_endpoint_descriptor *endpoint;
646 struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
647 struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
648 struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
649 struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -0700650 struct usb_serial_driver *type = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 int retval;
Andre Hauptdd9ca5d2008-06-18 15:56:00 +0200652 unsigned int minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 int buffer_size;
654 int i;
655 int num_interrupt_in = 0;
656 int num_interrupt_out = 0;
657 int num_bulk_in = 0;
658 int num_bulk_out = 0;
659 int num_ports = 0;
660 int max_endpoints;
661
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100662 lock_kernel(); /* guard against unloading a serial driver module */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 type = search_serial_device(interface);
664 if (!type) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100665 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 dbg("none matched");
667 return -ENODEV;
668 }
669
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100670 serial = create_serial(dev, interface, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 if (!serial) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100672 unlock_kernel();
Harvey Harrison441b62c2008-03-03 16:08:34 -0800673 dev_err(&interface->dev, "%s - out of memory\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 return -ENOMEM;
675 }
676
677 /* if this device type has a probe function, call it */
678 if (type->probe) {
679 const struct usb_device_id *id;
680
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700681 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100682 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100683 dev_err(&interface->dev,
684 "module get failed, exiting\n");
685 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return -EIO;
687 }
688
Greg Kroah-Hartman93bacef2006-12-17 21:50:23 +0100689 id = get_iface_id(type, interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 retval = type->probe(serial, id);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700691 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693 if (retval) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100694 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100695 dbg("sub driver rejected device");
696 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return retval;
698 }
699 }
700
701 /* descriptor matches, let's find the endpoints needed */
702 /* check out the endpoints */
703 iface_desc = interface->cur_altsetting;
704 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
705 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700706
707 if (usb_endpoint_is_bulk_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 /* we found a bulk in endpoint */
709 dbg("found bulk in on endpoint %d", i);
710 bulk_in_endpoint[num_bulk_in] = endpoint;
711 ++num_bulk_in;
712 }
713
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700714 if (usb_endpoint_is_bulk_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 /* we found a bulk out endpoint */
716 dbg("found bulk out on endpoint %d", i);
717 bulk_out_endpoint[num_bulk_out] = endpoint;
718 ++num_bulk_out;
719 }
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700720
721 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 /* we found a interrupt in endpoint */
723 dbg("found interrupt in on endpoint %d", i);
724 interrupt_in_endpoint[num_interrupt_in] = endpoint;
725 ++num_interrupt_in;
726 }
727
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700728 if (usb_endpoint_is_int_out(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 /* we found an interrupt out endpoint */
730 dbg("found interrupt out on endpoint %d", i);
731 interrupt_out_endpoint[num_interrupt_out] = endpoint;
732 ++num_interrupt_out;
733 }
734 }
735
736#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100737 /* BEGIN HORRIBLE HACK FOR PL2303 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 /* this is needed due to the looney way its endpoints are set up */
739 if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
740 (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
741 ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
Johannes Steingraeber8fd80132006-09-16 16:17:34 +0200742 (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
743 ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
Andreas Bombece816cf2008-09-14 01:58:55 +0200744 (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) ||
745 ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
746 (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if (interface != dev->actconfig->interface[0]) {
748 /* check out the endpoints of the other interface*/
749 iface_desc = dev->actconfig->interface[0]->cur_altsetting;
750 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
751 endpoint = &iface_desc->endpoint[i].desc;
Luiz Fernando N. Capitulino4fa1bbf2006-09-27 11:58:53 -0700752 if (usb_endpoint_is_int_in(endpoint)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 /* we found a interrupt in endpoint */
754 dbg("found interrupt in for Prolific device on separate interface");
755 interrupt_in_endpoint[num_interrupt_in] = endpoint;
756 ++num_interrupt_in;
757 }
758 }
759 }
760
761 /* Now make sure the PL-2303 is configured correctly.
762 * If not, give up now and hope this hack will work
763 * properly during a later invocation of usb_serial_probe
764 */
765 if (num_bulk_in == 0 || num_bulk_out == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100766 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100768 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 return -ENODEV;
770 }
771 }
772 /* END HORRIBLE HACK FOR PL2303 */
773#endif
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775#ifdef CONFIG_USB_SERIAL_GENERIC
776 if (type == &usb_serial_generic_device) {
777 num_ports = num_bulk_out;
778 if (num_ports == 0) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100779 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100780 dev_err(&interface->dev,
781 "Generic device with no bulk out, not allowed.\n");
782 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return -EIO;
784 }
785 }
786#endif
787 if (!num_ports) {
788 /* if this device type has a calc_num_ports function, call it */
789 if (type->calc_num_ports) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700790 if (!try_module_get(type->driver.owner)) {
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100791 unlock_kernel();
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100792 dev_err(&interface->dev,
793 "module get failed, exiting\n");
794 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 return -EIO;
796 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100797 num_ports = type->calc_num_ports(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700798 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 }
800 if (!num_ports)
801 num_ports = type->num_ports;
802 }
803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 serial->num_ports = num_ports;
805 serial->num_bulk_in = num_bulk_in;
806 serial->num_bulk_out = num_bulk_out;
807 serial->num_interrupt_in = num_interrupt_in;
808 serial->num_interrupt_out = num_interrupt_out;
809
Alan Stern063a2da2007-10-10 16:24:06 -0400810 /* found all that we need */
811 dev_info(&interface->dev, "%s converter detected\n",
812 type->description);
813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 /* create our ports, we need as many as the max endpoints */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100815 /* we don't use num_ports here because some devices have more
816 endpoint pairs than ports */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 max_endpoints = max(num_bulk_in, num_bulk_out);
818 max_endpoints = max(max_endpoints, num_interrupt_in);
819 max_endpoints = max(max_endpoints, num_interrupt_out);
820 max_endpoints = max(max_endpoints, (int)serial->num_ports);
821 serial->num_port_pointers = max_endpoints;
Oliver Neukum4b10f0f2007-01-13 07:31:27 +0100822 unlock_kernel();
823
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100824 dbg("%s - setting up %d port structures for this device",
825 __func__, max_endpoints);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 for (i = 0; i < max_endpoints; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100827 port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 if (!port)
829 goto probe_error;
Alan Cox4a90f092008-10-13 10:39:46 +0100830 tty_port_init(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 port->serial = serial;
Greg Kroah-Hartman507ca9b2005-04-23 12:49:16 -0700832 spin_lock_init(&port->lock);
Luiz Fernando Capitulino1ce7dd22006-03-24 17:12:31 -0300833 mutex_init(&port->mutex);
David Howellsc4028952006-11-22 14:57:56 +0000834 INIT_WORK(&port->work, usb_serial_port_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 serial->port[i] = port;
836 }
837
838 /* set up the endpoint information */
839 for (i = 0; i < num_bulk_in; ++i) {
840 endpoint = bulk_in_endpoint[i];
841 port = serial->port[i];
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100842 port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 if (!port->read_urb) {
844 dev_err(&interface->dev, "No free urbs available\n");
845 goto probe_error;
846 }
847 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
848 port->bulk_in_size = buffer_size;
849 port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100850 port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (!port->bulk_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100852 dev_err(&interface->dev,
853 "Couldn't allocate bulk_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 goto probe_error;
855 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100856 usb_fill_bulk_urb(port->read_urb, dev,
857 usb_rcvbulkpipe(dev,
858 endpoint->bEndpointAddress),
859 port->bulk_in_buffer, buffer_size,
860 serial->type->read_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 }
862
863 for (i = 0; i < num_bulk_out; ++i) {
864 endpoint = bulk_out_endpoint[i];
865 port = serial->port[i];
866 port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
867 if (!port->write_urb) {
868 dev_err(&interface->dev, "No free urbs available\n");
869 goto probe_error;
870 }
871 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
872 port->bulk_out_size = buffer_size;
873 port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100874 port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 if (!port->bulk_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100876 dev_err(&interface->dev,
877 "Couldn't allocate bulk_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 goto probe_error;
879 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100880 usb_fill_bulk_urb(port->write_urb, dev,
881 usb_sndbulkpipe(dev,
882 endpoint->bEndpointAddress),
883 port->bulk_out_buffer, buffer_size,
884 serial->type->write_bulk_callback, port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 }
886
887 if (serial->type->read_int_callback) {
888 for (i = 0; i < num_interrupt_in; ++i) {
889 endpoint = interrupt_in_endpoint[i];
890 port = serial->port[i];
891 port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
892 if (!port->interrupt_in_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100893 dev_err(&interface->dev,
894 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 goto probe_error;
896 }
897 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100898 port->interrupt_in_endpointAddress =
899 endpoint->bEndpointAddress;
900 port->interrupt_in_buffer = kmalloc(buffer_size,
901 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 if (!port->interrupt_in_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100903 dev_err(&interface->dev,
904 "Couldn't allocate interrupt_in_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 goto probe_error;
906 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100907 usb_fill_int_urb(port->interrupt_in_urb, dev,
908 usb_rcvintpipe(dev,
909 endpoint->bEndpointAddress),
910 port->interrupt_in_buffer, buffer_size,
911 serial->type->read_int_callback, port,
912 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 }
914 } else if (num_interrupt_in) {
915 dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
916 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100917
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 if (serial->type->write_int_callback) {
919 for (i = 0; i < num_interrupt_out; ++i) {
920 endpoint = interrupt_out_endpoint[i];
921 port = serial->port[i];
922 port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
923 if (!port->interrupt_out_urb) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100924 dev_err(&interface->dev,
925 "No free urbs available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 goto probe_error;
927 }
928 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
929 port->interrupt_out_size = buffer_size;
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100930 port->interrupt_out_endpointAddress =
931 endpoint->bEndpointAddress;
932 port->interrupt_out_buffer = kmalloc(buffer_size,
933 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 if (!port->interrupt_out_buffer) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100935 dev_err(&interface->dev,
936 "Couldn't allocate interrupt_out_buffer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 goto probe_error;
938 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100939 usb_fill_int_urb(port->interrupt_out_urb, dev,
940 usb_sndintpipe(dev,
941 endpoint->bEndpointAddress),
942 port->interrupt_out_buffer, buffer_size,
943 serial->type->write_int_callback, port,
944 endpoint->bInterval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 }
946 } else if (num_interrupt_out) {
947 dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
948 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100949
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 /* if this device type has an attach function, call it */
951 if (type->attach) {
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700952 if (!try_module_get(type->driver.owner)) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100953 dev_err(&interface->dev,
954 "module get failed, exiting\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 goto probe_error;
956 }
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100957 retval = type->attach(serial);
Greg Kroah-Hartman18fcac32005-06-20 21:15:16 -0700958 module_put(type->driver.owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 if (retval < 0)
960 goto probe_error;
961 if (retval > 0) {
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100962 /* quietly accept this device, but don't bind to a
963 serial port as it's about to disappear */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 goto exit;
965 }
966 }
967
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100968 if (get_free_serial(serial, num_ports, &minor) == NULL) {
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100969 dev_err(&interface->dev, "No more free serial devices\n");
970 goto probe_error;
971 }
Oliver Neukumc744f992007-02-26 15:43:00 +0100972 serial->minor = minor;
Oliver Neukum34ef50e2007-01-13 07:29:26 +0100973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 /* register all of the individual ports with the driver core */
975 for (i = 0; i < num_ports; ++i) {
976 port = serial->port[i];
977 port->dev.parent = &interface->dev;
978 port->dev.driver = NULL;
979 port->dev.bus = &usb_serial_bus_type;
980 port->dev.release = &port_release;
981
Kay Sievers0031a062008-05-02 06:02:41 +0200982 dev_set_name(&port->dev, "ttyUSB%d", port->number);
Kay Sievers7071a3c2008-05-02 06:02:41 +0200983 dbg ("%s - registering %s", __func__, dev_name(&port->dev));
Greg Kroah-Hartman13f4db92006-08-28 11:43:25 -0700984 retval = device_register(&port->dev);
985 if (retval)
986 dev_err(&port->dev, "Error registering port device, "
987 "continuing\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 }
989
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100990 usb_serial_console_init(debug, minor);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992exit:
993 /* success */
Alan Coxa8d6f0a2008-07-22 11:12:24 +0100994 usb_set_intfdata(interface, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 return 0;
996
997probe_error:
998 for (i = 0; i < num_bulk_in; ++i) {
999 port = serial->port[i];
1000 if (!port)
1001 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001002 usb_free_urb(port->read_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 kfree(port->bulk_in_buffer);
1004 }
1005 for (i = 0; i < num_bulk_out; ++i) {
1006 port = serial->port[i];
1007 if (!port)
1008 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001009 usb_free_urb(port->write_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 kfree(port->bulk_out_buffer);
1011 }
1012 for (i = 0; i < num_interrupt_in; ++i) {
1013 port = serial->port[i];
1014 if (!port)
1015 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001016 usb_free_urb(port->interrupt_in_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 kfree(port->interrupt_in_buffer);
1018 }
1019 for (i = 0; i < num_interrupt_out; ++i) {
1020 port = serial->port[i];
1021 if (!port)
1022 continue;
Mariusz Kozlowski95d43162006-11-08 15:36:51 +01001023 usb_free_urb(port->interrupt_out_urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 kfree(port->interrupt_out_buffer);
1025 }
1026
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 /* free up any memory that we allocated */
1028 for (i = 0; i < serial->num_port_pointers; ++i)
1029 kfree(serial->port[i]);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001030 kfree(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return -EIO;
1032}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001033EXPORT_SYMBOL_GPL(usb_serial_probe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
1035void usb_serial_disconnect(struct usb_interface *interface)
1036{
1037 int i;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001038 struct usb_serial *serial = usb_get_intfdata(interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 struct device *dev = &interface->dev;
1040 struct usb_serial_port *port;
1041
Guennadi Liakhovetski73e487f2006-04-25 07:46:17 +02001042 usb_serial_console_disconnect(serial);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001043 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001045 mutex_lock(&serial->disc_mutex);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001046 usb_set_intfdata(interface, NULL);
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001047 /* must set a flag, to signal subdrivers */
1048 serial->disconnected = 1;
1049 for (i = 0; i < serial->num_ports; ++i) {
1050 port = serial->port[i];
1051 if (port) {
Alan Cox4a90f092008-10-13 10:39:46 +01001052 struct tty_struct *tty = tty_port_tty_get(&port->port);
1053 if (tty) {
1054 tty_hangup(tty);
1055 tty_kref_put(tty);
1056 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001057 kill_traffic(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
Oliver Neukuma1cd7e92008-01-16 17:18:52 +01001060 /* let the last holder of this object
1061 * cause it to be cleaned up */
1062 mutex_unlock(&serial->disc_mutex);
1063 usb_serial_put(serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 dev_info(dev, "device disconnected\n");
1065}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001066EXPORT_SYMBOL_GPL(usb_serial_disconnect);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
Oliver Neukumec225592007-04-27 20:54:57 +02001068int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1069{
1070 struct usb_serial *serial = usb_get_intfdata(intf);
1071 struct usb_serial_port *port;
1072 int i, r = 0;
1073
Oliver Neukume31c1882007-07-23 08:58:39 +02001074 for (i = 0; i < serial->num_ports; ++i) {
1075 port = serial->port[i];
1076 if (port)
1077 kill_traffic(port);
Oliver Neukumec225592007-04-27 20:54:57 +02001078 }
1079
1080 if (serial->type->suspend)
Oliver Neukume31c1882007-07-23 08:58:39 +02001081 r = serial->type->suspend(serial, message);
Oliver Neukumec225592007-04-27 20:54:57 +02001082
1083 return r;
1084}
1085EXPORT_SYMBOL(usb_serial_suspend);
1086
1087int usb_serial_resume(struct usb_interface *intf)
1088{
1089 struct usb_serial *serial = usb_get_intfdata(intf);
1090
Sarah Sharp8abaee22007-10-25 10:58:43 -07001091 if (serial->type->resume)
1092 return serial->type->resume(serial);
1093 return 0;
Oliver Neukumec225592007-04-27 20:54:57 +02001094}
1095EXPORT_SYMBOL(usb_serial_resume);
1096
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001097static const struct tty_operations serial_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 .open = serial_open,
1099 .close = serial_close,
1100 .write = serial_write,
1101 .write_room = serial_write_room,
1102 .ioctl = serial_ioctl,
1103 .set_termios = serial_set_termios,
1104 .throttle = serial_throttle,
1105 .unthrottle = serial_unthrottle,
1106 .break_ctl = serial_break,
1107 .chars_in_buffer = serial_chars_in_buffer,
1108 .read_proc = serial_read_proc,
1109 .tiocmget = serial_tiocmget,
1110 .tiocmset = serial_tiocmset,
1111};
1112
1113struct tty_driver *usb_serial_tty_driver;
1114
1115static int __init usb_serial_init(void)
1116{
1117 int i;
1118 int result;
1119
1120 usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
1121 if (!usb_serial_tty_driver)
1122 return -ENOMEM;
1123
1124 /* Initialize our global data */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001125 for (i = 0; i < SERIAL_TTY_MINORS; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 serial_table[i] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
1128 result = bus_register(&usb_serial_bus_type);
1129 if (result) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001130 printk(KERN_ERR "usb-serial: %s - registering bus driver "
1131 "failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 goto exit_bus;
1133 }
1134
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 usb_serial_tty_driver->owner = THIS_MODULE;
1136 usb_serial_tty_driver->driver_name = "usbserial";
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 usb_serial_tty_driver->name = "ttyUSB";
1138 usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
1139 usb_serial_tty_driver->minor_start = 0;
1140 usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
1141 usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001142 usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
1143 TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 usb_serial_tty_driver->init_termios = tty_std_termios;
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001145 usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
1146 | HUPCL | CLOCAL;
Alan Coxa5b6f602008-04-08 17:16:06 +01001147 usb_serial_tty_driver->init_termios.c_ispeed = 9600;
1148 usb_serial_tty_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 tty_set_operations(usb_serial_tty_driver, &serial_ops);
1150 result = tty_register_driver(usb_serial_tty_driver);
1151 if (result) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001152 printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n",
1153 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 goto exit_reg_driver;
1155 }
1156
1157 /* register the USB driver */
1158 result = usb_register(&usb_serial_driver);
1159 if (result < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001160 printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
1161 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 goto exit_tty;
1163 }
1164
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001165 /* register the generic driver, if we should */
1166 result = usb_serial_generic_register(debug);
1167 if (result < 0) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001168 printk(KERN_ERR "usb-serial: %s - registering generic "
1169 "driver failed\n", __func__);
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001170 goto exit_generic;
1171 }
1172
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001173 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
1175 return result;
1176
Greg Kroah-Hartman06299db2005-05-26 05:55:55 -07001177exit_generic:
1178 usb_deregister(&usb_serial_driver);
1179
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180exit_tty:
1181 tty_unregister_driver(usb_serial_tty_driver);
1182
1183exit_reg_driver:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 bus_unregister(&usb_serial_bus_type);
1185
1186exit_bus:
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001187 printk(KERN_ERR "usb-serial: %s - returning with error %d\n",
1188 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 put_tty_driver(usb_serial_tty_driver);
1190 return result;
1191}
1192
1193
1194static void __exit usb_serial_exit(void)
1195{
1196 usb_serial_console_exit();
1197
1198 usb_serial_generic_deregister();
1199
1200 usb_deregister(&usb_serial_driver);
1201 tty_unregister_driver(usb_serial_tty_driver);
1202 put_tty_driver(usb_serial_tty_driver);
1203 bus_unregister(&usb_serial_bus_type);
1204}
1205
1206
1207module_init(usb_serial_init);
1208module_exit(usb_serial_exit);
1209
1210#define set_to_generic_if_null(type, function) \
1211 do { \
1212 if (!type->function) { \
1213 type->function = usb_serial_generic_##function; \
1214 dbg("Had to override the " #function \
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001215 " usb serial operation with the generic one.");\
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 } \
1217 } while (0)
1218
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001219static void fixup_generic(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220{
1221 set_to_generic_if_null(device, open);
1222 set_to_generic_if_null(device, write);
1223 set_to_generic_if_null(device, close);
1224 set_to_generic_if_null(device, write_room);
1225 set_to_generic_if_null(device, chars_in_buffer);
1226 set_to_generic_if_null(device, read_bulk_callback);
1227 set_to_generic_if_null(device, write_bulk_callback);
1228 set_to_generic_if_null(device, shutdown);
Sarah Sharpf0fbd5b2007-11-13 17:10:09 -08001229 set_to_generic_if_null(device, resume);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230}
1231
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001232int usb_serial_register(struct usb_serial_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001234 /* must be called with BKL held */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 int retval;
1236
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001237 fixup_generic(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Greg Kroah-Hartman269bda12005-06-20 21:15:16 -07001239 if (!driver->description)
1240 driver->description = driver->driver.name;
1241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 /* Add this device to our list of devices */
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001243 list_add(&driver->driver_list, &usb_serial_driver_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001245 retval = usb_serial_bus_register(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 if (retval) {
Greg Kroah-Hartman194343d2008-08-20 16:56:34 -07001247 printk(KERN_ERR "usb-serial: problem %d when registering "
1248 "driver %s\n", retval, driver->description);
Greg Kroah-Hartmanea653702005-06-20 21:15:16 -07001249 list_del(&driver->driver_list);
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001250 } else
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001251 printk(KERN_INFO "USB Serial support registered for %s\n",
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001252 driver->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 return retval;
1255}
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001256EXPORT_SYMBOL_GPL(usb_serial_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001259void usb_serial_deregister(struct usb_serial_driver *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260{
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001261 /* must be called with BKL held */
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001262 printk(KERN_INFO "USB Serial deregistering driver %s\n",
1263 device->description);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 list_del(&device->driver_list);
1265 usb_serial_bus_deregister(device);
1266}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267EXPORT_SYMBOL_GPL(usb_serial_deregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
1269/* Module information */
Alan Coxa8d6f0a2008-07-22 11:12:24 +01001270MODULE_AUTHOR(DRIVER_AUTHOR);
1271MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272MODULE_LICENSE("GPL");
1273
1274module_param(debug, bool, S_IRUGO | S_IWUSR);
1275MODULE_PARM_DESC(debug, "Debug enabled or not");