xref: /openbmc/linux/drivers/usb/serial/usb-serial.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * USB Serial Converter driver
41da177e4SLinus Torvalds  *
5659597b7SJohan Hovold  * Copyright (C) 2009 - 2013 Johan Hovold (jhovold@gmail.com)
67186364eSGreg Kroah-Hartman  * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com)
71da177e4SLinus Torvalds  * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
81da177e4SLinus Torvalds  * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * This driver was originally based on the ACM driver by Armin Fuerst (which was
111da177e4SLinus Torvalds  * based on a driver by Brad Keryan)
121da177e4SLinus Torvalds  *
13ecefae6dSMauro Carvalho Chehab  * See Documentation/usb/usb-serial.rst for more information on using this
14a8d6f0a9SAlan Cox  * driver
151da177e4SLinus Torvalds  */
161da177e4SLinus Torvalds 
1792931d24SGreg Kroah-Hartman #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1892931d24SGreg Kroah-Hartman 
191da177e4SLinus Torvalds #include <linux/kernel.h>
201da177e4SLinus Torvalds #include <linux/errno.h>
211da177e4SLinus Torvalds #include <linux/init.h>
221da177e4SLinus Torvalds #include <linux/slab.h>
231da177e4SLinus Torvalds #include <linux/tty.h>
241da177e4SLinus Torvalds #include <linux/tty_driver.h>
251da177e4SLinus Torvalds #include <linux/tty_flip.h>
261da177e4SLinus Torvalds #include <linux/module.h>
271da177e4SLinus Torvalds #include <linux/moduleparam.h>
286fd69d3cSAlexey Dobriyan #include <linux/seq_file.h>
291da177e4SLinus Torvalds #include <linux/spinlock.h>
301ce7dd26SLuiz Fernando Capitulino #include <linux/mutex.h>
311da177e4SLinus Torvalds #include <linux/list.h>
32a8d6f0a9SAlan Cox #include <linux/uaccess.h>
33c56d3000SAlan Cox #include <linux/serial.h>
341da177e4SLinus Torvalds #include <linux/usb.h>
35a969888cSGreg Kroah-Hartman #include <linux/usb/serial.h>
368e8dce06SDavid VomLehn #include <linux/kfifo.h>
37e5b1e206SGreg Kroah-Hartman #include <linux/idr.h>
381da177e4SLinus Torvalds 
39ee42f6c9SGreg Kroah-Hartman #define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
401da177e4SLinus Torvalds #define DRIVER_DESC "USB Serial Driver core"
411da177e4SLinus Torvalds 
42455b4f7eSGreg Kroah-Hartman #define USB_SERIAL_TTY_MAJOR	188
43455b4f7eSGreg Kroah-Hartman #define USB_SERIAL_TTY_MINORS	512	/* should be enough for a while */
44455b4f7eSGreg Kroah-Hartman 
451da177e4SLinus Torvalds /* There is no MODULE_DEVICE_TABLE for usbserial.c.  Instead
461da177e4SLinus Torvalds    the MODULE_DEVICE_TABLE declarations in each serial driver
471da177e4SLinus Torvalds    cause the "hotplug" program to pull in whatever module is necessary
481da177e4SLinus Torvalds    via modprobe, and modprobe will load usbserial because the serial
491da177e4SLinus Torvalds    drivers depend on it.
501da177e4SLinus Torvalds */
511da177e4SLinus Torvalds 
52e5b1e206SGreg Kroah-Hartman static DEFINE_IDR(serial_minors);
533ddad823SOliver Neukum static DEFINE_MUTEX(table_lock);
541da177e4SLinus Torvalds static LIST_HEAD(usb_serial_driver_list);
551da177e4SLinus Torvalds 
568bc2c1b2SAlan Stern /*
57e5b1e206SGreg Kroah-Hartman  * Look up the serial port structure.  If it is found and it hasn't been
58e5b1e206SGreg Kroah-Hartman  * disconnected, return with the parent usb_serial structure's disc_mutex held
59e5b1e206SGreg Kroah-Hartman  * and its refcount incremented.  Otherwise return NULL.
608bc2c1b2SAlan Stern  */
usb_serial_port_get_by_minor(unsigned minor)61e5b1e206SGreg Kroah-Hartman struct usb_serial_port *usb_serial_port_get_by_minor(unsigned minor)
621da177e4SLinus Torvalds {
6334ef50e5SOliver Neukum 	struct usb_serial *serial;
64e5b1e206SGreg Kroah-Hartman 	struct usb_serial_port *port;
6534ef50e5SOliver Neukum 
663ddad823SOliver Neukum 	mutex_lock(&table_lock);
67e5b1e206SGreg Kroah-Hartman 	port = idr_find(&serial_minors, minor);
68e5b1e206SGreg Kroah-Hartman 	if (!port)
69e5b1e206SGreg Kroah-Hartman 		goto exit;
701da177e4SLinus Torvalds 
71e5b1e206SGreg Kroah-Hartman 	serial = port->serial;
728bc2c1b2SAlan Stern 	mutex_lock(&serial->disc_mutex);
738bc2c1b2SAlan Stern 	if (serial->disconnected) {
748bc2c1b2SAlan Stern 		mutex_unlock(&serial->disc_mutex);
75e5b1e206SGreg Kroah-Hartman 		port = NULL;
768bc2c1b2SAlan Stern 	} else {
771da177e4SLinus Torvalds 		kref_get(&serial->kref);
788bc2c1b2SAlan Stern 	}
79e5b1e206SGreg Kroah-Hartman exit:
803ddad823SOliver Neukum 	mutex_unlock(&table_lock);
81e5b1e206SGreg Kroah-Hartman 	return port;
821da177e4SLinus Torvalds }
831da177e4SLinus Torvalds 
allocate_minors(struct usb_serial * serial,int num_ports)84e5b1e206SGreg Kroah-Hartman static int allocate_minors(struct usb_serial *serial, int num_ports)
851da177e4SLinus Torvalds {
86e5b1e206SGreg Kroah-Hartman 	struct usb_serial_port *port;
871da177e4SLinus Torvalds 	unsigned int i, j;
88e5b1e206SGreg Kroah-Hartman 	int minor;
891da177e4SLinus Torvalds 
9092931d24SGreg Kroah-Hartman 	dev_dbg(&serial->interface->dev, "%s %d\n", __func__, num_ports);
911da177e4SLinus Torvalds 
923ddad823SOliver Neukum 	mutex_lock(&table_lock);
93e5b1e206SGreg Kroah-Hartman 	for (i = 0; i < num_ports; ++i) {
94e5b1e206SGreg Kroah-Hartman 		port = serial->port[i];
95194e958cSJohan Hovold 		minor = idr_alloc(&serial_minors, port, 0,
96194e958cSJohan Hovold 					USB_SERIAL_TTY_MINORS, GFP_KERNEL);
97e5b1e206SGreg Kroah-Hartman 		if (minor < 0)
98e5b1e206SGreg Kroah-Hartman 			goto error;
99e5b1e206SGreg Kroah-Hartman 		port->minor = minor;
100e5b1e206SGreg Kroah-Hartman 		port->port_number = i;
1011da177e4SLinus Torvalds 	}
102e5b1e206SGreg Kroah-Hartman 	serial->minors_reserved = 1;
1033ddad823SOliver Neukum 	mutex_unlock(&table_lock);
104e5b1e206SGreg Kroah-Hartman 	return 0;
105e5b1e206SGreg Kroah-Hartman error:
106e5b1e206SGreg Kroah-Hartman 	/* unwind the already allocated minors */
107e5b1e206SGreg Kroah-Hartman 	for (j = 0; j < i; ++j)
108e5b1e206SGreg Kroah-Hartman 		idr_remove(&serial_minors, serial->port[j]->minor);
1093ddad823SOliver Neukum 	mutex_unlock(&table_lock);
110e5b1e206SGreg Kroah-Hartman 	return minor;
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds 
release_minors(struct usb_serial * serial)113e5b1e206SGreg Kroah-Hartman static void release_minors(struct usb_serial *serial)
1141da177e4SLinus Torvalds {
1151da177e4SLinus Torvalds 	int i;
1161da177e4SLinus Torvalds 
1178bc2c1b2SAlan Stern 	mutex_lock(&table_lock);
118a8d6f0a9SAlan Cox 	for (i = 0; i < serial->num_ports; ++i)
119e5b1e206SGreg Kroah-Hartman 		idr_remove(&serial_minors, serial->port[i]->minor);
1208bc2c1b2SAlan Stern 	mutex_unlock(&table_lock);
121e5b1e206SGreg Kroah-Hartman 	serial->minors_reserved = 0;
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds 
usb_serial_claim_interface(struct usb_serial * serial,struct usb_interface * intf)1245de03c99SJohan Hovold int usb_serial_claim_interface(struct usb_serial *serial, struct usb_interface *intf)
1255de03c99SJohan Hovold {
1265de03c99SJohan Hovold 	struct usb_driver *driver = serial->type->usb_driver;
1275de03c99SJohan Hovold 	int ret;
1285de03c99SJohan Hovold 
1295de03c99SJohan Hovold 	if (serial->sibling)
1305de03c99SJohan Hovold 		return -EBUSY;
1315de03c99SJohan Hovold 
1325de03c99SJohan Hovold 	ret = usb_driver_claim_interface(driver, intf, serial);
1335de03c99SJohan Hovold 	if (ret) {
1345de03c99SJohan Hovold 		dev_err(&serial->interface->dev,
1355de03c99SJohan Hovold 				"failed to claim sibling interface: %d\n", ret);
1365de03c99SJohan Hovold 		return ret;
1375de03c99SJohan Hovold 	}
1385de03c99SJohan Hovold 
1395de03c99SJohan Hovold 	serial->sibling = intf;
1405de03c99SJohan Hovold 
1415de03c99SJohan Hovold 	return 0;
1425de03c99SJohan Hovold }
1435de03c99SJohan Hovold EXPORT_SYMBOL_GPL(usb_serial_claim_interface);
1445de03c99SJohan Hovold 
release_sibling(struct usb_serial * serial,struct usb_interface * intf)1455de03c99SJohan Hovold static void release_sibling(struct usb_serial *serial, struct usb_interface *intf)
1465de03c99SJohan Hovold {
1475de03c99SJohan Hovold 	struct usb_driver *driver = serial->type->usb_driver;
1485de03c99SJohan Hovold 	struct usb_interface *sibling;
1495de03c99SJohan Hovold 
1505de03c99SJohan Hovold 	if (!serial->sibling)
1515de03c99SJohan Hovold 		return;
1525de03c99SJohan Hovold 
1535de03c99SJohan Hovold 	if (intf == serial->sibling)
1545de03c99SJohan Hovold 		sibling = serial->interface;
1555de03c99SJohan Hovold 	else
1565de03c99SJohan Hovold 		sibling = serial->sibling;
1575de03c99SJohan Hovold 
1585de03c99SJohan Hovold 	usb_set_intfdata(sibling, NULL);
1595de03c99SJohan Hovold 	usb_driver_release_interface(driver, sibling);
1605de03c99SJohan Hovold }
1615de03c99SJohan Hovold 
destroy_serial(struct kref * kref)1621da177e4SLinus Torvalds static void destroy_serial(struct kref *kref)
1631da177e4SLinus Torvalds {
1641da177e4SLinus Torvalds 	struct usb_serial *serial;
1651da177e4SLinus Torvalds 	struct usb_serial_port *port;
1661da177e4SLinus Torvalds 	int i;
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 	serial = to_usb_serial(kref);
1691da177e4SLinus Torvalds 
170521b85aeSJim Radford 	/* return the minor range that this device had */
171e5b1e206SGreg Kroah-Hartman 	if (serial->minors_reserved)
172e5b1e206SGreg Kroah-Hartman 		release_minors(serial);
173521b85aeSJim Radford 
17479b80b8aSJohan Hovold 	if (serial->attached && serial->type->release)
175f9c99bb8SAlan Stern 		serial->type->release(serial);
176f9c99bb8SAlan Stern 
17741bd34ddSAlan Stern 	/* Now that nothing is using the ports, they can be freed */
17841bd34ddSAlan Stern 	for (i = 0; i < serial->num_port_pointers; ++i) {
179f9c99bb8SAlan Stern 		port = serial->port[i];
18041bd34ddSAlan Stern 		if (port) {
18141bd34ddSAlan Stern 			port->serial = NULL;
182f9c99bb8SAlan Stern 			put_device(&port->dev);
183f9c99bb8SAlan Stern 		}
1841da177e4SLinus Torvalds 	}
1851da177e4SLinus Torvalds 
186d7971051SJohan Hovold 	usb_put_intf(serial->interface);
1871da177e4SLinus Torvalds 	usb_put_dev(serial->dev);
1881da177e4SLinus Torvalds 	kfree(serial);
1891da177e4SLinus Torvalds }
1901da177e4SLinus Torvalds 
usb_serial_put(struct usb_serial * serial)19173e487fdSGuennadi Liakhovetski void usb_serial_put(struct usb_serial *serial)
19273e487fdSGuennadi Liakhovetski {
19373e487fdSGuennadi Liakhovetski 	kref_put(&serial->kref, destroy_serial);
19473e487fdSGuennadi Liakhovetski }
19573e487fdSGuennadi Liakhovetski 
1961da177e4SLinus Torvalds /*****************************************************************************
1971da177e4SLinus Torvalds  * Driver tty interface functions
1981da177e4SLinus Torvalds  *****************************************************************************/
199f5b0953aSAlan Stern 
200f5b0953aSAlan Stern /**
201f5b0953aSAlan Stern  * serial_install - install tty
202f5b0953aSAlan Stern  * @driver: the driver (USB in our case)
203f5b0953aSAlan Stern  * @tty: the tty being created
204f5b0953aSAlan Stern  *
205579bebe5SJohan Hovold  * Initialise the termios structure for this tty.  We use the default
206f5b0953aSAlan Stern  * USB serial settings but permit them to be overridden by
207579bebe5SJohan Hovold  * serial->type->init_termios on first open.
208cc56cd01SAlan Stern  *
209cc56cd01SAlan Stern  * This is the first place a new tty gets used.  Hence this is where we
210cc56cd01SAlan Stern  * acquire references to the usb_serial structure and the driver module,
2116400b974SJohan Hovold  * where we store a pointer to the port.  All these actions are reversed
2126400b974SJohan Hovold  * in serial_cleanup().
213f5b0953aSAlan Stern  */
serial_install(struct tty_driver * driver,struct tty_struct * tty)214f5b0953aSAlan Stern static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
215f5b0953aSAlan Stern {
216f5b0953aSAlan Stern 	int idx = tty->index;
217f5b0953aSAlan Stern 	struct usb_serial *serial;
218cc56cd01SAlan Stern 	struct usb_serial_port *port;
219579bebe5SJohan Hovold 	bool init_termios;
220cc56cd01SAlan Stern 	int retval = -ENODEV;
221cc56cd01SAlan Stern 
222e5b1e206SGreg Kroah-Hartman 	port = usb_serial_port_get_by_minor(idx);
223e5b1e206SGreg Kroah-Hartman 	if (!port)
224cc56cd01SAlan Stern 		return retval;
225cc56cd01SAlan Stern 
226e5b1e206SGreg Kroah-Hartman 	serial = port->serial;
227cc56cd01SAlan Stern 	if (!try_module_get(serial->type->driver.owner))
22896a83c95SJohan Hovold 		goto err_put_serial;
229cc56cd01SAlan Stern 
230579bebe5SJohan Hovold 	init_termios = (driver->termios[idx] == NULL);
231579bebe5SJohan Hovold 
23279ef5189SJohan Hovold 	retval = tty_standard_install(driver, tty);
23376f82a7aSJiri Slaby 	if (retval)
2346400b974SJohan Hovold 		goto err_put_module;
23576f82a7aSJiri Slaby 
2367e29bb4bSAlan Stern 	mutex_unlock(&serial->disc_mutex);
2377e29bb4bSAlan Stern 
238579bebe5SJohan Hovold 	/* allow the driver to update the initial settings */
239579bebe5SJohan Hovold 	if (init_termios && serial->type->init_termios)
240f5b0953aSAlan Stern 		serial->type->init_termios(tty);
241cc56cd01SAlan Stern 
242cc56cd01SAlan Stern 	tty->driver_data = port;
243cc56cd01SAlan Stern 
244cc56cd01SAlan Stern 	return retval;
245cc56cd01SAlan Stern 
24696a83c95SJohan Hovold err_put_module:
247cc56cd01SAlan Stern 	module_put(serial->type->driver.owner);
24896a83c95SJohan Hovold err_put_serial:
249cc56cd01SAlan Stern 	usb_serial_put(serial);
250cc56cd01SAlan Stern 	mutex_unlock(&serial->disc_mutex);
251cc56cd01SAlan Stern 	return retval;
252f5b0953aSAlan Stern }
253f5b0953aSAlan Stern 
serial_port_activate(struct tty_port * tport,struct tty_struct * tty)254395e08daSJohan Hovold static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty)
2551da177e4SLinus Torvalds {
25664bc3979SAlan Cox 	struct usb_serial_port *port =
25764bc3979SAlan Cox 		container_of(tport, struct usb_serial_port, port);
258320348c8SAlan Stern 	struct usb_serial *serial = port->serial;
259320348c8SAlan Stern 	int retval;
2601da177e4SLinus Torvalds 
2612d93148aSAlan Stern 	mutex_lock(&serial->disc_mutex);
2626400b974SJohan Hovold 	if (serial->disconnected) {
263320348c8SAlan Stern 		retval = -ENODEV;
2646400b974SJohan Hovold 		goto out_unlock;
2656400b974SJohan Hovold 	}
2666400b974SJohan Hovold 
2676400b974SJohan Hovold 	retval = usb_autopm_get_interface(serial->interface);
2686400b974SJohan Hovold 	if (retval)
2696400b974SJohan Hovold 		goto out_unlock;
2706400b974SJohan Hovold 
271320348c8SAlan Stern 	retval = port->serial->type->open(tty, port);
2726400b974SJohan Hovold 	if (retval)
2736400b974SJohan Hovold 		usb_autopm_put_interface(serial->interface);
2746400b974SJohan Hovold out_unlock:
2752d93148aSAlan Stern 	mutex_unlock(&serial->disc_mutex);
2763827d876SJohan Hovold 
2773827d876SJohan Hovold 	if (retval < 0)
2783827d876SJohan Hovold 		retval = usb_translate_errors(retval);
2793827d876SJohan Hovold 
280320348c8SAlan Stern 	return retval;
2811da177e4SLinus Torvalds }
282320348c8SAlan Stern 
serial_open(struct tty_struct * tty,struct file * filp)28364bc3979SAlan Cox static int serial_open(struct tty_struct *tty, struct file *filp)
28464bc3979SAlan Cox {
28564bc3979SAlan Cox 	struct usb_serial_port *port = tty->driver_data;
28664bc3979SAlan Cox 
28707125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
288d12e211dSJohan Hovold 
28964bc3979SAlan Cox 	return tty_port_open(&port->port, tty, filp);
2901da177e4SLinus Torvalds }
2911da177e4SLinus Torvalds 
292335f8514SAlan Cox /**
293395e08daSJohan Hovold  * serial_port_shutdown - shut down hardware
294e1108a63SAlan Cox  * @tport: tty port to shut down
295335f8514SAlan Cox  *
2968a7298d3SPeter Hurley  * Shut down a USB serial port. Serialized against activate by the
2978a7298d3SPeter Hurley  * tport mutex and kept to matching open/close pairs
298688ee1d1SJohan Hovold  * of calls by the tty-port initialized flag.
2998a7298d3SPeter Hurley  *
3008a7298d3SPeter Hurley  * Not called if tty is console.
301335f8514SAlan Cox  */
serial_port_shutdown(struct tty_port * tport)302395e08daSJohan Hovold static void serial_port_shutdown(struct tty_port *tport)
3031da177e4SLinus Torvalds {
304e1108a63SAlan Cox 	struct usb_serial_port *port =
305e1108a63SAlan Cox 		container_of(tport, struct usb_serial_port, port);
306335f8514SAlan Cox 	struct usb_serial_driver *drv = port->serial->type;
3078a7298d3SPeter Hurley 
308335f8514SAlan Cox 	if (drv->close)
309335f8514SAlan Cox 		drv->close(port);
3106400b974SJohan Hovold 
3116400b974SJohan Hovold 	usb_autopm_put_interface(port->serial->interface);
31291c0bce2SGreg Kroah-Hartman }
3131da177e4SLinus Torvalds 
serial_hangup(struct tty_struct * tty)314f5b0953aSAlan Stern static void serial_hangup(struct tty_struct *tty)
315335f8514SAlan Cox {
3164455e344SAlan Cox 	struct usb_serial_port *port = tty->driver_data;
31792931d24SGreg Kroah-Hartman 
31807125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
319d12e211dSJohan Hovold 
320f5b0953aSAlan Stern 	tty_port_hangup(&port->port);
3211da177e4SLinus Torvalds }
3221da177e4SLinus Torvalds 
serial_close(struct tty_struct * tty,struct file * filp)323335f8514SAlan Cox static void serial_close(struct tty_struct *tty, struct file *filp)
324335f8514SAlan Cox {
325335f8514SAlan Cox 	struct usb_serial_port *port = tty->driver_data;
32692931d24SGreg Kroah-Hartman 
32707125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
328d12e211dSJohan Hovold 
329e1108a63SAlan Cox 	tty_port_close(&port->port, tty, filp);
330335f8514SAlan Cox }
331335f8514SAlan Cox 
332f5b0953aSAlan Stern /**
333f278a2f7SDave Young  * serial_cleanup - free resources post close/hangup
334615e58ccSJohan Hovold  * @tty: tty to clean up
335f5b0953aSAlan Stern  *
336f5b0953aSAlan Stern  * Do the resource freeing and refcount dropping for the port.
337f5b0953aSAlan Stern  * Avoid freeing the console.
338f5b0953aSAlan Stern  *
33936b3c070SAlan Cox  * Called asynchronously after the last tty kref is dropped.
340f5b0953aSAlan Stern  */
serial_cleanup(struct tty_struct * tty)341f278a2f7SDave Young static void serial_cleanup(struct tty_struct *tty)
342335f8514SAlan Cox {
343335f8514SAlan Cox 	struct usb_serial_port *port = tty->driver_data;
344f5b0953aSAlan Stern 	struct usb_serial *serial;
345f5b0953aSAlan Stern 	struct module *owner;
346f5b0953aSAlan Stern 
34707125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
348d12e211dSJohan Hovold 
349f5b0953aSAlan Stern 	/* The console is magical.  Do not hang up the console hardware
350f5b0953aSAlan Stern 	 * or there will be tears.
351f5b0953aSAlan Stern 	 */
352bd5afa9eSJason Wessel 	if (port->port.console)
353f5b0953aSAlan Stern 		return;
354f5b0953aSAlan Stern 
355cc56cd01SAlan Stern 	tty->driver_data = NULL;
356cc56cd01SAlan Stern 
357f5b0953aSAlan Stern 	serial = port->serial;
358f5b0953aSAlan Stern 	owner = serial->type->driver.owner;
359f5b0953aSAlan Stern 
360f5b0953aSAlan Stern 	usb_serial_put(serial);
361f5b0953aSAlan Stern 	module_put(owner);
362335f8514SAlan Cox }
363335f8514SAlan Cox 
serial_write(struct tty_struct * tty,const u8 * buf,size_t count)364*95713967SJiri Slaby (SUSE) static ssize_t serial_write(struct tty_struct *tty, const u8 *buf, size_t count)
3651da177e4SLinus Torvalds {
36681671ddbSTobias Klauser 	struct usb_serial_port *port = tty->driver_data;
3673ff4fd94SOliver Neukum 	int retval = -ENODEV;
3681da177e4SLinus Torvalds 
369f34d7a5bSAlan Cox 	if (port->serial->dev->state == USB_STATE_NOTATTACHED)
370487f9c67SLuiz Fernando Capitulino 		goto exit;
371487f9c67SLuiz Fernando Capitulino 
372*95713967SJiri Slaby (SUSE) 	dev_dbg(&port->dev, "%s - %zu byte(s)\n", __func__, count);
3731da177e4SLinus Torvalds 
37495da310eSAlan Cox 	retval = port->serial->type->write(tty, port, buf, count);
375c6249ff7SJohan Hovold 	if (retval < 0)
376c6249ff7SJohan Hovold 		retval = usb_translate_errors(retval);
3771da177e4SLinus Torvalds exit:
3781da177e4SLinus Torvalds 	return retval;
3791da177e4SLinus Torvalds }
3801da177e4SLinus Torvalds 
serial_write_room(struct tty_struct * tty)38103b3b1a2SJiri Slaby static unsigned int serial_write_room(struct tty_struct *tty)
3821da177e4SLinus Torvalds {
38381671ddbSTobias Klauser 	struct usb_serial_port *port = tty->driver_data;
38492931d24SGreg Kroah-Hartman 
38507125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
3869993b42bSJohan Hovold 
38795da310eSAlan Cox 	return port->serial->type->write_room(tty);
3881da177e4SLinus Torvalds }
3891da177e4SLinus Torvalds 
serial_chars_in_buffer(struct tty_struct * tty)390fff4ef17SJiri Slaby static unsigned int serial_chars_in_buffer(struct tty_struct *tty)
3911da177e4SLinus Torvalds {
39281671ddbSTobias Klauser 	struct usb_serial_port *port = tty->driver_data;
393810360a0SJohan Hovold 	struct usb_serial *serial = port->serial;
39492931d24SGreg Kroah-Hartman 
39507125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
3961da177e4SLinus Torvalds 
397810360a0SJohan Hovold 	if (serial->disconnected)
3984746b6c6SJohan Hovold 		return 0;
399810360a0SJohan Hovold 
4004746b6c6SJohan Hovold 	return serial->type->chars_in_buffer(tty);
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds 
serial_wait_until_sent(struct tty_struct * tty,int timeout)4030693196fSJohan Hovold static void serial_wait_until_sent(struct tty_struct *tty, int timeout)
4040693196fSJohan Hovold {
4050693196fSJohan Hovold 	struct usb_serial_port *port = tty->driver_data;
4060693196fSJohan Hovold 	struct usb_serial *serial = port->serial;
4070693196fSJohan Hovold 
40807125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
4090693196fSJohan Hovold 
4100693196fSJohan Hovold 	if (!port->serial->type->wait_until_sent)
4110693196fSJohan Hovold 		return;
4120693196fSJohan Hovold 
4130693196fSJohan Hovold 	mutex_lock(&serial->disc_mutex);
4140693196fSJohan Hovold 	if (!serial->disconnected)
4150693196fSJohan Hovold 		port->serial->type->wait_until_sent(tty, timeout);
4160693196fSJohan Hovold 	mutex_unlock(&serial->disc_mutex);
4170693196fSJohan Hovold }
4180693196fSJohan Hovold 
serial_throttle(struct tty_struct * tty)4191da177e4SLinus Torvalds static void serial_throttle(struct tty_struct *tty)
4201da177e4SLinus Torvalds {
42181671ddbSTobias Klauser 	struct usb_serial_port *port = tty->driver_data;
42292931d24SGreg Kroah-Hartman 
42307125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 	if (port->serial->type->throttle)
42695da310eSAlan Cox 		port->serial->type->throttle(tty);
4271da177e4SLinus Torvalds }
4281da177e4SLinus Torvalds 
serial_unthrottle(struct tty_struct * tty)4291da177e4SLinus Torvalds static void serial_unthrottle(struct tty_struct *tty)
4301da177e4SLinus Torvalds {
43181671ddbSTobias Klauser 	struct usb_serial_port *port = tty->driver_data;
43292931d24SGreg Kroah-Hartman 
43307125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds 	if (port->serial->type->unthrottle)
43695da310eSAlan Cox 		port->serial->type->unthrottle(tty);
4371da177e4SLinus Torvalds }
4381da177e4SLinus Torvalds 
serial_get_serial(struct tty_struct * tty,struct serial_struct * ss)43981732b26SAl Viro static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss)
44081732b26SAl Viro {
44181732b26SAl Viro 	struct usb_serial_port *port = tty->driver_data;
44201fd45f6SJohan Hovold 	struct tty_port *tport = &port->port;
44301fd45f6SJohan Hovold 	unsigned int close_delay, closing_wait;
44401fd45f6SJohan Hovold 
44501fd45f6SJohan Hovold 	mutex_lock(&tport->mutex);
44601fd45f6SJohan Hovold 
44701fd45f6SJohan Hovold 	close_delay = jiffies_to_msecs(tport->close_delay) / 10;
44801fd45f6SJohan Hovold 	closing_wait = tport->closing_wait;
44901fd45f6SJohan Hovold 	if (closing_wait != ASYNC_CLOSING_WAIT_NONE)
45001fd45f6SJohan Hovold 		closing_wait = jiffies_to_msecs(closing_wait) / 10;
45101fd45f6SJohan Hovold 
45201fd45f6SJohan Hovold 	ss->line = port->minor;
45301fd45f6SJohan Hovold 	ss->close_delay = close_delay;
45401fd45f6SJohan Hovold 	ss->closing_wait = closing_wait;
45581732b26SAl Viro 
45681732b26SAl Viro 	if (port->serial->type->get_serial)
45701fd45f6SJohan Hovold 		port->serial->type->get_serial(tty, ss);
45801fd45f6SJohan Hovold 
45901fd45f6SJohan Hovold 	mutex_unlock(&tport->mutex);
46001fd45f6SJohan Hovold 
46101fd45f6SJohan Hovold 	return 0;
46281732b26SAl Viro }
46381732b26SAl Viro 
serial_set_serial(struct tty_struct * tty,struct serial_struct * ss)46481732b26SAl Viro static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss)
46581732b26SAl Viro {
46681732b26SAl Viro 	struct usb_serial_port *port = tty->driver_data;
46701fd45f6SJohan Hovold 	struct tty_port *tport = &port->port;
46801fd45f6SJohan Hovold 	unsigned int close_delay, closing_wait;
46901fd45f6SJohan Hovold 	int ret = 0;
47081732b26SAl Viro 
47101fd45f6SJohan Hovold 	close_delay = msecs_to_jiffies(ss->close_delay * 10);
47201fd45f6SJohan Hovold 	closing_wait = ss->closing_wait;
47301fd45f6SJohan Hovold 	if (closing_wait != ASYNC_CLOSING_WAIT_NONE)
47401fd45f6SJohan Hovold 		closing_wait = msecs_to_jiffies(closing_wait * 10);
47501fd45f6SJohan Hovold 
47601fd45f6SJohan Hovold 	mutex_lock(&tport->mutex);
47701fd45f6SJohan Hovold 
47801fd45f6SJohan Hovold 	if (!capable(CAP_SYS_ADMIN)) {
47901fd45f6SJohan Hovold 		if (close_delay != tport->close_delay ||
48001fd45f6SJohan Hovold 				closing_wait != tport->closing_wait) {
48101fd45f6SJohan Hovold 			ret = -EPERM;
48201fd45f6SJohan Hovold 			goto out_unlock;
48301fd45f6SJohan Hovold 		}
48401fd45f6SJohan Hovold 	}
48501fd45f6SJohan Hovold 
48601fd45f6SJohan Hovold 	if (port->serial->type->set_serial) {
48701fd45f6SJohan Hovold 		ret = port->serial->type->set_serial(tty, ss);
48801fd45f6SJohan Hovold 		if (ret)
48901fd45f6SJohan Hovold 			goto out_unlock;
49001fd45f6SJohan Hovold 	}
49101fd45f6SJohan Hovold 
49201fd45f6SJohan Hovold 	tport->close_delay = close_delay;
49301fd45f6SJohan Hovold 	tport->closing_wait = closing_wait;
49401fd45f6SJohan Hovold out_unlock:
49501fd45f6SJohan Hovold 	mutex_unlock(&tport->mutex);
49601fd45f6SJohan Hovold 
49701fd45f6SJohan Hovold 	return ret;
49881732b26SAl Viro }
49981732b26SAl Viro 
serial_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg)5006caa76b7SAlan Cox static int serial_ioctl(struct tty_struct *tty,
501a8d6f0a9SAlan Cox 					unsigned int cmd, unsigned long arg)
5021da177e4SLinus Torvalds {
50381671ddbSTobias Klauser 	struct usb_serial_port *port = tty->driver_data;
504f4488035SJohan Hovold 	int retval = -ENOIOCTLCMD;
5051da177e4SLinus Torvalds 
50607125072SJohan Hovold 	dev_dbg(&port->dev, "%s - cmd 0x%04x\n", __func__, cmd);
5071da177e4SLinus Torvalds 
508143d9d96SJohan Hovold 	switch (cmd) {
509143d9d96SJohan Hovold 	case TIOCMIWAIT:
510143d9d96SJohan Hovold 		if (port->serial->type->tiocmiwait)
511143d9d96SJohan Hovold 			retval = port->serial->type->tiocmiwait(tty, arg);
512143d9d96SJohan Hovold 		break;
513143d9d96SJohan Hovold 	default:
5149993b42bSJohan Hovold 		if (port->serial->type->ioctl)
51500a0d0d6SAlan Cox 			retval = port->serial->type->ioctl(tty, cmd, arg);
516143d9d96SJohan Hovold 	}
5179993b42bSJohan Hovold 
5181da177e4SLinus Torvalds 	return retval;
5191da177e4SLinus Torvalds }
5201da177e4SLinus Torvalds 
serial_set_termios(struct tty_struct * tty,const struct ktermios * old)521a8c11c15SIlpo Järvinen static void serial_set_termios(struct tty_struct *tty,
522a8c11c15SIlpo Järvinen 		               const struct ktermios *old)
5231da177e4SLinus Torvalds {
52481671ddbSTobias Klauser 	struct usb_serial_port *port = tty->driver_data;
52592931d24SGreg Kroah-Hartman 
52607125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds 	if (port->serial->type->set_termios)
52995da310eSAlan Cox 		port->serial->type->set_termios(tty, port, old);
53033785091SAlan Cox 	else
531adc8d746SAlan Cox 		tty_termios_copy_hw(&tty->termios, old);
5321da177e4SLinus Torvalds }
5331da177e4SLinus Torvalds 
serial_break(struct tty_struct * tty,int break_state)5349e98966cSAlan Cox static int serial_break(struct tty_struct *tty, int break_state)
5351da177e4SLinus Torvalds {
53681671ddbSTobias Klauser 	struct usb_serial_port *port = tty->driver_data;
5371da177e4SLinus Torvalds 
53807125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
5391da177e4SLinus Torvalds 
5406b447f04SAlan Cox 	if (port->serial->type->break_ctl)
5416ff58ae1SJohan Hovold 		return port->serial->type->break_ctl(tty, break_state);
5429993b42bSJohan Hovold 
543c9d93405SJohan Hovold 	return -ENOTTY;
544f34d7a5bSAlan Cox }
5451da177e4SLinus Torvalds 
serial_proc_show(struct seq_file * m,void * v)5466fd69d3cSAlexey Dobriyan static int serial_proc_show(struct seq_file *m, void *v)
5471da177e4SLinus Torvalds {
5481da177e4SLinus Torvalds 	struct usb_serial *serial;
549e5b1e206SGreg Kroah-Hartman 	struct usb_serial_port *port;
5501da177e4SLinus Torvalds 	int i;
5511da177e4SLinus Torvalds 	char tmp[40];
5521da177e4SLinus Torvalds 
5536fd69d3cSAlexey Dobriyan 	seq_puts(m, "usbserinfo:1.0 driver:2.0\n");
554455b4f7eSGreg Kroah-Hartman 	for (i = 0; i < USB_SERIAL_TTY_MINORS; ++i) {
555e5b1e206SGreg Kroah-Hartman 		port = usb_serial_port_get_by_minor(i);
556e5b1e206SGreg Kroah-Hartman 		if (port == NULL)
5571da177e4SLinus Torvalds 			continue;
558e5b1e206SGreg Kroah-Hartman 		serial = port->serial;
5591da177e4SLinus Torvalds 
5606fd69d3cSAlexey Dobriyan 		seq_printf(m, "%d:", i);
56118fcac35SGreg Kroah-Hartman 		if (serial->type->driver.owner)
5626fd69d3cSAlexey Dobriyan 			seq_printf(m, " module:%s",
563a8d6f0a9SAlan Cox 				module_name(serial->type->driver.owner));
5646fd69d3cSAlexey Dobriyan 		seq_printf(m, " name:\"%s\"",
565a8d6f0a9SAlan Cox 				serial->type->description);
5666fd69d3cSAlexey Dobriyan 		seq_printf(m, " vendor:%04x product:%04x",
5671da177e4SLinus Torvalds 			le16_to_cpu(serial->dev->descriptor.idVendor),
5681da177e4SLinus Torvalds 			le16_to_cpu(serial->dev->descriptor.idProduct));
5696fd69d3cSAlexey Dobriyan 		seq_printf(m, " num_ports:%d", serial->num_ports);
570e5b1e206SGreg Kroah-Hartman 		seq_printf(m, " port:%d", port->port_number);
5711da177e4SLinus Torvalds 		usb_make_path(serial->dev, tmp, sizeof(tmp));
5726fd69d3cSAlexey Dobriyan 		seq_printf(m, " path:%s", tmp);
5731da177e4SLinus Torvalds 
5746fd69d3cSAlexey Dobriyan 		seq_putc(m, '\n');
57573e487fdSGuennadi Liakhovetski 		usb_serial_put(serial);
5768bc2c1b2SAlan Stern 		mutex_unlock(&serial->disc_mutex);
5771da177e4SLinus Torvalds 	}
5781da177e4SLinus Torvalds 	return 0;
5791da177e4SLinus Torvalds }
5801da177e4SLinus Torvalds 
serial_tiocmget(struct tty_struct * tty)58160b33c13SAlan Cox static int serial_tiocmget(struct tty_struct *tty)
5821da177e4SLinus Torvalds {
58381671ddbSTobias Klauser 	struct usb_serial_port *port = tty->driver_data;
5841da177e4SLinus Torvalds 
58507125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
5861da177e4SLinus Torvalds 
5871da177e4SLinus Torvalds 	if (port->serial->type->tiocmget)
58860b33c13SAlan Cox 		return port->serial->type->tiocmget(tty);
5895f92aee9SJohan Hovold 	return -ENOTTY;
5901da177e4SLinus Torvalds }
5911da177e4SLinus Torvalds 
serial_tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)59220b9d177SAlan Cox static int serial_tiocmset(struct tty_struct *tty,
5931da177e4SLinus Torvalds 			    unsigned int set, unsigned int clear)
5941da177e4SLinus Torvalds {
59581671ddbSTobias Klauser 	struct usb_serial_port *port = tty->driver_data;
5961da177e4SLinus Torvalds 
59707125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds 	if (port->serial->type->tiocmset)
60020b9d177SAlan Cox 		return port->serial->type->tiocmset(tty, set, clear);
6015f92aee9SJohan Hovold 	return -ENOTTY;
6021da177e4SLinus Torvalds }
6031da177e4SLinus Torvalds 
serial_get_icount(struct tty_struct * tty,struct serial_icounter_struct * icount)604d281da7fSAlan Cox static int serial_get_icount(struct tty_struct *tty,
605d281da7fSAlan Cox 				struct serial_icounter_struct *icount)
606d281da7fSAlan Cox {
607d281da7fSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
608d281da7fSAlan Cox 
60907125072SJohan Hovold 	dev_dbg(&port->dev, "%s\n", __func__);
610d281da7fSAlan Cox 
611d281da7fSAlan Cox 	if (port->serial->type->get_icount)
612d281da7fSAlan Cox 		return port->serial->type->get_icount(tty, icount);
6135f92aee9SJohan Hovold 	return -ENOTTY;
614d281da7fSAlan Cox }
615d281da7fSAlan Cox 
616cf2c7481SPete Zaitcev /*
617cf2c7481SPete Zaitcev  * We would be calling tty_wakeup here, but unfortunately some line
618cf2c7481SPete Zaitcev  * disciplines have an annoying habit of calling tty->write from
619cf2c7481SPete Zaitcev  * the write wakeup callback (e.g. n_hdlc.c).
620cf2c7481SPete Zaitcev  */
usb_serial_port_softint(struct usb_serial_port * port)621cf2c7481SPete Zaitcev void usb_serial_port_softint(struct usb_serial_port *port)
622cf2c7481SPete Zaitcev {
623cf2c7481SPete Zaitcev 	schedule_work(&port->work);
624cf2c7481SPete Zaitcev }
625a8d6f0a9SAlan Cox EXPORT_SYMBOL_GPL(usb_serial_port_softint);
626cf2c7481SPete Zaitcev 
usb_serial_port_work(struct work_struct * work)627c4028958SDavid Howells static void usb_serial_port_work(struct work_struct *work)
6281da177e4SLinus Torvalds {
629c4028958SDavid Howells 	struct usb_serial_port *port =
630c4028958SDavid Howells 		container_of(work, struct usb_serial_port, work);
6311da177e4SLinus Torvalds 
6326aad04f2SJiri Slaby 	tty_port_tty_wakeup(&port->port);
6331da177e4SLinus Torvalds }
6341da177e4SLinus Torvalds 
usb_serial_port_poison_urbs(struct usb_serial_port * port)6356a5c821cSJohan Hovold static void usb_serial_port_poison_urbs(struct usb_serial_port *port)
63634f8e761SPete Zaitcev {
63727c7acf2SJohan Hovold 	int i;
63827c7acf2SJohan Hovold 
639d83b4053SJohan Hovold 	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
6406a5c821cSJohan Hovold 		usb_poison_urb(port->read_urbs[i]);
64127c7acf2SJohan Hovold 	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
6426a5c821cSJohan Hovold 		usb_poison_urb(port->write_urbs[i]);
6436a5c821cSJohan Hovold 
6446a5c821cSJohan Hovold 	usb_poison_urb(port->interrupt_in_urb);
6456a5c821cSJohan Hovold 	usb_poison_urb(port->interrupt_out_urb);
64634ef50e5SOliver Neukum }
64734ef50e5SOliver Neukum 
usb_serial_port_unpoison_urbs(struct usb_serial_port * port)6486a5c821cSJohan Hovold static void usb_serial_port_unpoison_urbs(struct usb_serial_port *port)
6496a5c821cSJohan Hovold {
6506a5c821cSJohan Hovold 	int i;
6516a5c821cSJohan Hovold 
6526a5c821cSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
6536a5c821cSJohan Hovold 		usb_unpoison_urb(port->read_urbs[i]);
6546a5c821cSJohan Hovold 	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
6556a5c821cSJohan Hovold 		usb_unpoison_urb(port->write_urbs[i]);
6566a5c821cSJohan Hovold 
6576a5c821cSJohan Hovold 	usb_unpoison_urb(port->interrupt_in_urb);
6586a5c821cSJohan Hovold 	usb_unpoison_urb(port->interrupt_out_urb);
65934ef50e5SOliver Neukum }
66034ef50e5SOliver Neukum 
usb_serial_port_release(struct device * dev)66169a3d212SJohan Hovold static void usb_serial_port_release(struct device *dev)
66234ef50e5SOliver Neukum {
66341bd34ddSAlan Stern 	struct usb_serial_port *port = to_usb_serial_port(dev);
66427c7acf2SJohan Hovold 	int i;
66541bd34ddSAlan Stern 
66692931d24SGreg Kroah-Hartman 	dev_dbg(dev, "%s\n", __func__);
66741bd34ddSAlan Stern 
66834ef50e5SOliver Neukum 	usb_free_urb(port->interrupt_in_urb);
6691da177e4SLinus Torvalds 	usb_free_urb(port->interrupt_out_urb);
670d83b4053SJohan Hovold 	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
671d83b4053SJohan Hovold 		usb_free_urb(port->read_urbs[i]);
672d83b4053SJohan Hovold 		kfree(port->bulk_in_buffers[i]);
673d83b4053SJohan Hovold 	}
67427c7acf2SJohan Hovold 	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
67527c7acf2SJohan Hovold 		usb_free_urb(port->write_urbs[i]);
67627c7acf2SJohan Hovold 		kfree(port->bulk_out_buffers[i]);
67727c7acf2SJohan Hovold 	}
678119eecc8SStefani Seibold 	kfifo_free(&port->write_fifo);
6791da177e4SLinus Torvalds 	kfree(port->interrupt_in_buffer);
6801da177e4SLinus Torvalds 	kfree(port->interrupt_out_buffer);
681191c5f10SJiri Slaby 	tty_port_destroy(&port->port);
6821da177e4SLinus Torvalds 	kfree(port);
6831da177e4SLinus Torvalds }
6841da177e4SLinus Torvalds 
create_serial(struct usb_device * dev,struct usb_interface * interface,struct usb_serial_driver * driver)6851da177e4SLinus Torvalds static struct usb_serial *create_serial(struct usb_device *dev,
6861da177e4SLinus Torvalds 					struct usb_interface *interface,
687ea65370dSGreg Kroah-Hartman 					struct usb_serial_driver *driver)
6881da177e4SLinus Torvalds {
6891da177e4SLinus Torvalds 	struct usb_serial *serial;
6901da177e4SLinus Torvalds 
69180b6ca48SEric Sesterhenn 	serial = kzalloc(sizeof(*serial), GFP_KERNEL);
6926b03f7f7SJohan Hovold 	if (!serial)
6931da177e4SLinus Torvalds 		return NULL;
6941da177e4SLinus Torvalds 	serial->dev = usb_get_dev(dev);
695ea65370dSGreg Kroah-Hartman 	serial->type = driver;
696d7971051SJohan Hovold 	serial->interface = usb_get_intf(interface);
6971da177e4SLinus Torvalds 	kref_init(&serial->kref);
698a1cd7e99SOliver Neukum 	mutex_init(&serial->disc_mutex);
699e5b1e206SGreg Kroah-Hartman 	serial->minors_reserved = 0;
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	return serial;
7021da177e4SLinus Torvalds }
7031da177e4SLinus Torvalds 
match_dynamic_id(struct usb_interface * intf,struct usb_serial_driver * drv)70493bacefcSGreg Kroah-Hartman static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
70593bacefcSGreg Kroah-Hartman 					    struct usb_serial_driver *drv)
70693bacefcSGreg Kroah-Hartman {
70793bacefcSGreg Kroah-Hartman 	struct usb_dynid *dynid;
70893bacefcSGreg Kroah-Hartman 
70993bacefcSGreg Kroah-Hartman 	spin_lock(&drv->dynids.lock);
71093bacefcSGreg Kroah-Hartman 	list_for_each_entry(dynid, &drv->dynids.list, node) {
71193bacefcSGreg Kroah-Hartman 		if (usb_match_one_id(intf, &dynid->id)) {
71293bacefcSGreg Kroah-Hartman 			spin_unlock(&drv->dynids.lock);
71393bacefcSGreg Kroah-Hartman 			return &dynid->id;
71493bacefcSGreg Kroah-Hartman 		}
71593bacefcSGreg Kroah-Hartman 	}
71693bacefcSGreg Kroah-Hartman 	spin_unlock(&drv->dynids.lock);
71793bacefcSGreg Kroah-Hartman 	return NULL;
71893bacefcSGreg Kroah-Hartman }
71993bacefcSGreg Kroah-Hartman 
get_iface_id(struct usb_serial_driver * drv,struct usb_interface * intf)72093bacefcSGreg Kroah-Hartman static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
72193bacefcSGreg Kroah-Hartman 						struct usb_interface *intf)
72293bacefcSGreg Kroah-Hartman {
72393bacefcSGreg Kroah-Hartman 	const struct usb_device_id *id;
72493bacefcSGreg Kroah-Hartman 
72593bacefcSGreg Kroah-Hartman 	id = usb_match_id(intf, drv->id_table);
72693bacefcSGreg Kroah-Hartman 	if (id) {
72792931d24SGreg Kroah-Hartman 		dev_dbg(&intf->dev, "static descriptor matches\n");
72893bacefcSGreg Kroah-Hartman 		goto exit;
72993bacefcSGreg Kroah-Hartman 	}
73093bacefcSGreg Kroah-Hartman 	id = match_dynamic_id(intf, drv);
73193bacefcSGreg Kroah-Hartman 	if (id)
73292931d24SGreg Kroah-Hartman 		dev_dbg(&intf->dev, "dynamic descriptor matches\n");
73393bacefcSGreg Kroah-Hartman exit:
73493bacefcSGreg Kroah-Hartman 	return id;
73593bacefcSGreg Kroah-Hartman }
73693bacefcSGreg Kroah-Hartman 
7370daeed38SAndi Kleen /* Caller must hold table_lock */
search_serial_device(struct usb_interface * iface)738a8d6f0a9SAlan Cox static struct usb_serial_driver *search_serial_device(
739a8d6f0a9SAlan Cox 					struct usb_interface *iface)
7401da177e4SLinus Torvalds {
741954c3f8aSBjørn Mork 	const struct usb_device_id *id = NULL;
742063a2da8SAlan Stern 	struct usb_serial_driver *drv;
743954c3f8aSBjørn Mork 	struct usb_driver *driver = to_usb_driver(iface->dev.driver);
7441da177e4SLinus Torvalds 
74593b1fae4SAdrian Bunk 	/* Check if the usb id matches a known device */
746063a2da8SAlan Stern 	list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
747954c3f8aSBjørn Mork 		if (drv->usb_driver == driver)
748063a2da8SAlan Stern 			id = get_iface_id(drv, iface);
74993bacefcSGreg Kroah-Hartman 		if (id)
750063a2da8SAlan Stern 			return drv;
7511da177e4SLinus Torvalds 	}
7521da177e4SLinus Torvalds 
7531da177e4SLinus Torvalds 	return NULL;
7541da177e4SLinus Torvalds }
7551da177e4SLinus Torvalds 
serial_port_carrier_raised(struct tty_port * port)756b300fb26SIlpo Järvinen static bool serial_port_carrier_raised(struct tty_port *port)
757335f8514SAlan Cox {
758335f8514SAlan Cox 	struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
759335f8514SAlan Cox 	struct usb_serial_driver *drv = p->serial->type;
7603e1f4901SJohan Hovold 
761335f8514SAlan Cox 	if (drv->carrier_raised)
762335f8514SAlan Cox 		return drv->carrier_raised(p);
763335f8514SAlan Cox 	/* No carrier control - don't block */
764b300fb26SIlpo Järvinen 	return true;
765335f8514SAlan Cox }
766335f8514SAlan Cox 
serial_port_dtr_rts(struct tty_port * port,bool on)7675d420399SIlpo Järvinen static void serial_port_dtr_rts(struct tty_port *port, bool on)
768335f8514SAlan Cox {
769335f8514SAlan Cox 	struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
770f5f45304SJohan Hovold 	struct usb_serial_driver *drv = p->serial->type;
7713e1f4901SJohan Hovold 
772f5f45304SJohan Hovold 	if (drv->dtr_rts)
773335f8514SAlan Cox 		drv->dtr_rts(p, on);
774335f8514SAlan Cox }
775335f8514SAlan Cox 
port_number_show(struct device * dev,struct device_attribute * attr,char * buf)7762deb96b5SJohan Hovold static ssize_t port_number_show(struct device *dev,
7772deb96b5SJohan Hovold 				struct device_attribute *attr, char *buf)
7782deb96b5SJohan Hovold {
7792deb96b5SJohan Hovold 	struct usb_serial_port *port = to_usb_serial_port(dev);
7802deb96b5SJohan Hovold 
7812deb96b5SJohan Hovold 	return sprintf(buf, "%u\n", port->port_number);
7822deb96b5SJohan Hovold }
7832deb96b5SJohan Hovold static DEVICE_ATTR_RO(port_number);
7842deb96b5SJohan Hovold 
7852deb96b5SJohan Hovold static struct attribute *usb_serial_port_attrs[] = {
7862deb96b5SJohan Hovold 	&dev_attr_port_number.attr,
7872deb96b5SJohan Hovold 	NULL
7882deb96b5SJohan Hovold };
7892deb96b5SJohan Hovold ATTRIBUTE_GROUPS(usb_serial_port);
7902deb96b5SJohan Hovold 
791335f8514SAlan Cox static const struct tty_port_operations serial_port_ops = {
792395e08daSJohan Hovold 	.carrier_raised		= serial_port_carrier_raised,
793395e08daSJohan Hovold 	.dtr_rts		= serial_port_dtr_rts,
794395e08daSJohan Hovold 	.activate		= serial_port_activate,
795395e08daSJohan Hovold 	.shutdown		= serial_port_shutdown,
796335f8514SAlan Cox };
797335f8514SAlan Cox 
store_endpoint(struct usb_serial * serial,struct usb_serial_endpoints * epds,struct usb_endpoint_descriptor * epd)798b3431093SJohan Hovold static void store_endpoint(struct usb_serial *serial,
799b3431093SJohan Hovold 					struct usb_serial_endpoints *epds,
800b3431093SJohan Hovold 					struct usb_endpoint_descriptor *epd)
801b3431093SJohan Hovold {
802b3431093SJohan Hovold 	struct device *dev = &serial->interface->dev;
803b3431093SJohan Hovold 	u8 addr = epd->bEndpointAddress;
804b3431093SJohan Hovold 
805b3431093SJohan Hovold 	if (usb_endpoint_is_bulk_in(epd)) {
806b3431093SJohan Hovold 		if (epds->num_bulk_in == ARRAY_SIZE(epds->bulk_in))
807b3431093SJohan Hovold 			return;
808b3431093SJohan Hovold 		dev_dbg(dev, "found bulk in endpoint %02x\n", addr);
809b3431093SJohan Hovold 		epds->bulk_in[epds->num_bulk_in++] = epd;
810b3431093SJohan Hovold 	} else if (usb_endpoint_is_bulk_out(epd)) {
811b3431093SJohan Hovold 		if (epds->num_bulk_out == ARRAY_SIZE(epds->bulk_out))
812b3431093SJohan Hovold 			return;
813b3431093SJohan Hovold 		dev_dbg(dev, "found bulk out endpoint %02x\n", addr);
814b3431093SJohan Hovold 		epds->bulk_out[epds->num_bulk_out++] = epd;
815b3431093SJohan Hovold 	} else if (usb_endpoint_is_int_in(epd)) {
816b3431093SJohan Hovold 		if (epds->num_interrupt_in == ARRAY_SIZE(epds->interrupt_in))
817b3431093SJohan Hovold 			return;
818b3431093SJohan Hovold 		dev_dbg(dev, "found interrupt in endpoint %02x\n", addr);
819b3431093SJohan Hovold 		epds->interrupt_in[epds->num_interrupt_in++] = epd;
820b3431093SJohan Hovold 	} else if (usb_endpoint_is_int_out(epd)) {
821b3431093SJohan Hovold 		if (epds->num_interrupt_out == ARRAY_SIZE(epds->interrupt_out))
822b3431093SJohan Hovold 			return;
823b3431093SJohan Hovold 		dev_dbg(dev, "found interrupt out endpoint %02x\n", addr);
824b3431093SJohan Hovold 		epds->interrupt_out[epds->num_interrupt_out++] = epd;
825b3431093SJohan Hovold 	}
826b3431093SJohan Hovold }
827b3431093SJohan Hovold 
find_endpoints(struct usb_serial * serial,struct usb_serial_endpoints * epds,struct usb_interface * intf)8281546e6aeSJohan Hovold static void find_endpoints(struct usb_serial *serial,
8295de03c99SJohan Hovold 					struct usb_serial_endpoints *epds,
8305de03c99SJohan Hovold 					struct usb_interface *intf)
8311546e6aeSJohan Hovold {
8321546e6aeSJohan Hovold 	struct usb_host_interface *iface_desc;
8331546e6aeSJohan Hovold 	struct usb_endpoint_descriptor *epd;
8341546e6aeSJohan Hovold 	unsigned int i;
8351546e6aeSJohan Hovold 
8365de03c99SJohan Hovold 	iface_desc = intf->cur_altsetting;
8371546e6aeSJohan Hovold 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
8381546e6aeSJohan Hovold 		epd = &iface_desc->endpoint[i].desc;
839b3431093SJohan Hovold 		store_endpoint(serial, epds, epd);
8401546e6aeSJohan Hovold 	}
8411546e6aeSJohan Hovold }
8421546e6aeSJohan Hovold 
setup_port_bulk_in(struct usb_serial_port * port,struct usb_endpoint_descriptor * epd)84345e5d4d4SJohan Hovold static int setup_port_bulk_in(struct usb_serial_port *port,
84445e5d4d4SJohan Hovold 					struct usb_endpoint_descriptor *epd)
84545e5d4d4SJohan Hovold {
84645e5d4d4SJohan Hovold 	struct usb_serial_driver *type = port->serial->type;
84745e5d4d4SJohan Hovold 	struct usb_device *udev = port->serial->dev;
84845e5d4d4SJohan Hovold 	int buffer_size;
84945e5d4d4SJohan Hovold 	int i;
85045e5d4d4SJohan Hovold 
85145e5d4d4SJohan Hovold 	buffer_size = max_t(int, type->bulk_in_size, usb_endpoint_maxp(epd));
85245e5d4d4SJohan Hovold 	port->bulk_in_size = buffer_size;
85345e5d4d4SJohan Hovold 	port->bulk_in_endpointAddress = epd->bEndpointAddress;
85445e5d4d4SJohan Hovold 
85545e5d4d4SJohan Hovold 	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
85645e5d4d4SJohan Hovold 		set_bit(i, &port->read_urbs_free);
85745e5d4d4SJohan Hovold 		port->read_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
85845e5d4d4SJohan Hovold 		if (!port->read_urbs[i])
85945e5d4d4SJohan Hovold 			return -ENOMEM;
86045e5d4d4SJohan Hovold 		port->bulk_in_buffers[i] = kmalloc(buffer_size, GFP_KERNEL);
86145e5d4d4SJohan Hovold 		if (!port->bulk_in_buffers[i])
86245e5d4d4SJohan Hovold 			return -ENOMEM;
86345e5d4d4SJohan Hovold 		usb_fill_bulk_urb(port->read_urbs[i], udev,
86445e5d4d4SJohan Hovold 				usb_rcvbulkpipe(udev, epd->bEndpointAddress),
86545e5d4d4SJohan Hovold 				port->bulk_in_buffers[i], buffer_size,
86645e5d4d4SJohan Hovold 				type->read_bulk_callback, port);
86745e5d4d4SJohan Hovold 	}
86845e5d4d4SJohan Hovold 
86945e5d4d4SJohan Hovold 	port->read_urb = port->read_urbs[0];
87045e5d4d4SJohan Hovold 	port->bulk_in_buffer = port->bulk_in_buffers[0];
87145e5d4d4SJohan Hovold 
87245e5d4d4SJohan Hovold 	return 0;
87345e5d4d4SJohan Hovold }
87445e5d4d4SJohan Hovold 
setup_port_bulk_out(struct usb_serial_port * port,struct usb_endpoint_descriptor * epd)87545e5d4d4SJohan Hovold static int setup_port_bulk_out(struct usb_serial_port *port,
87645e5d4d4SJohan Hovold 					struct usb_endpoint_descriptor *epd)
87745e5d4d4SJohan Hovold {
87845e5d4d4SJohan Hovold 	struct usb_serial_driver *type = port->serial->type;
87945e5d4d4SJohan Hovold 	struct usb_device *udev = port->serial->dev;
88045e5d4d4SJohan Hovold 	int buffer_size;
88145e5d4d4SJohan Hovold 	int i;
88245e5d4d4SJohan Hovold 
88345e5d4d4SJohan Hovold 	if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
88445e5d4d4SJohan Hovold 		return -ENOMEM;
88545e5d4d4SJohan Hovold 	if (type->bulk_out_size)
88645e5d4d4SJohan Hovold 		buffer_size = type->bulk_out_size;
88745e5d4d4SJohan Hovold 	else
88845e5d4d4SJohan Hovold 		buffer_size = usb_endpoint_maxp(epd);
88945e5d4d4SJohan Hovold 	port->bulk_out_size = buffer_size;
89045e5d4d4SJohan Hovold 	port->bulk_out_endpointAddress = epd->bEndpointAddress;
89145e5d4d4SJohan Hovold 
89245e5d4d4SJohan Hovold 	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
89345e5d4d4SJohan Hovold 		set_bit(i, &port->write_urbs_free);
89445e5d4d4SJohan Hovold 		port->write_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
89545e5d4d4SJohan Hovold 		if (!port->write_urbs[i])
89645e5d4d4SJohan Hovold 			return -ENOMEM;
89745e5d4d4SJohan Hovold 		port->bulk_out_buffers[i] = kmalloc(buffer_size, GFP_KERNEL);
89845e5d4d4SJohan Hovold 		if (!port->bulk_out_buffers[i])
89945e5d4d4SJohan Hovold 			return -ENOMEM;
90045e5d4d4SJohan Hovold 		usb_fill_bulk_urb(port->write_urbs[i], udev,
90145e5d4d4SJohan Hovold 				usb_sndbulkpipe(udev, epd->bEndpointAddress),
90245e5d4d4SJohan Hovold 				port->bulk_out_buffers[i], buffer_size,
90345e5d4d4SJohan Hovold 				type->write_bulk_callback, port);
90445e5d4d4SJohan Hovold 	}
90545e5d4d4SJohan Hovold 
90645e5d4d4SJohan Hovold 	port->write_urb = port->write_urbs[0];
90745e5d4d4SJohan Hovold 	port->bulk_out_buffer = port->bulk_out_buffers[0];
90845e5d4d4SJohan Hovold 
90945e5d4d4SJohan Hovold 	return 0;
91045e5d4d4SJohan Hovold }
91145e5d4d4SJohan Hovold 
setup_port_interrupt_in(struct usb_serial_port * port,struct usb_endpoint_descriptor * epd)91245e5d4d4SJohan Hovold static int setup_port_interrupt_in(struct usb_serial_port *port,
91345e5d4d4SJohan Hovold 					struct usb_endpoint_descriptor *epd)
91445e5d4d4SJohan Hovold {
91545e5d4d4SJohan Hovold 	struct usb_serial_driver *type = port->serial->type;
91645e5d4d4SJohan Hovold 	struct usb_device *udev = port->serial->dev;
91745e5d4d4SJohan Hovold 	int buffer_size;
91845e5d4d4SJohan Hovold 
91945e5d4d4SJohan Hovold 	port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
92045e5d4d4SJohan Hovold 	if (!port->interrupt_in_urb)
92145e5d4d4SJohan Hovold 		return -ENOMEM;
92245e5d4d4SJohan Hovold 	buffer_size = usb_endpoint_maxp(epd);
92345e5d4d4SJohan Hovold 	port->interrupt_in_endpointAddress = epd->bEndpointAddress;
92445e5d4d4SJohan Hovold 	port->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
92545e5d4d4SJohan Hovold 	if (!port->interrupt_in_buffer)
92645e5d4d4SJohan Hovold 		return -ENOMEM;
92745e5d4d4SJohan Hovold 	usb_fill_int_urb(port->interrupt_in_urb, udev,
92845e5d4d4SJohan Hovold 			usb_rcvintpipe(udev, epd->bEndpointAddress),
92945e5d4d4SJohan Hovold 			port->interrupt_in_buffer, buffer_size,
93045e5d4d4SJohan Hovold 			type->read_int_callback, port,
93145e5d4d4SJohan Hovold 			epd->bInterval);
93245e5d4d4SJohan Hovold 
93345e5d4d4SJohan Hovold 	return 0;
93445e5d4d4SJohan Hovold }
93545e5d4d4SJohan Hovold 
setup_port_interrupt_out(struct usb_serial_port * port,struct usb_endpoint_descriptor * epd)93645e5d4d4SJohan Hovold static int setup_port_interrupt_out(struct usb_serial_port *port,
93745e5d4d4SJohan Hovold 					struct usb_endpoint_descriptor *epd)
93845e5d4d4SJohan Hovold {
93945e5d4d4SJohan Hovold 	struct usb_serial_driver *type = port->serial->type;
94045e5d4d4SJohan Hovold 	struct usb_device *udev = port->serial->dev;
94145e5d4d4SJohan Hovold 	int buffer_size;
94245e5d4d4SJohan Hovold 
94345e5d4d4SJohan Hovold 	port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
94445e5d4d4SJohan Hovold 	if (!port->interrupt_out_urb)
94545e5d4d4SJohan Hovold 		return -ENOMEM;
94645e5d4d4SJohan Hovold 	buffer_size = usb_endpoint_maxp(epd);
94745e5d4d4SJohan Hovold 	port->interrupt_out_size = buffer_size;
94845e5d4d4SJohan Hovold 	port->interrupt_out_endpointAddress = epd->bEndpointAddress;
94945e5d4d4SJohan Hovold 	port->interrupt_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
95045e5d4d4SJohan Hovold 	if (!port->interrupt_out_buffer)
95145e5d4d4SJohan Hovold 		return -ENOMEM;
95245e5d4d4SJohan Hovold 	usb_fill_int_urb(port->interrupt_out_urb, udev,
95345e5d4d4SJohan Hovold 			usb_sndintpipe(udev, epd->bEndpointAddress),
95445e5d4d4SJohan Hovold 			port->interrupt_out_buffer, buffer_size,
95545e5d4d4SJohan Hovold 			type->write_int_callback, port,
95645e5d4d4SJohan Hovold 			epd->bInterval);
95745e5d4d4SJohan Hovold 
95845e5d4d4SJohan Hovold 	return 0;
95945e5d4d4SJohan Hovold }
96045e5d4d4SJohan Hovold 
usb_serial_probe(struct usb_interface * interface,const struct usb_device_id * id)9612edd284bSGreg Kroah-Hartman static int usb_serial_probe(struct usb_interface *interface,
9621da177e4SLinus Torvalds 			       const struct usb_device_id *id)
9631da177e4SLinus Torvalds {
96492931d24SGreg Kroah-Hartman 	struct device *ddev = &interface->dev;
9651da177e4SLinus Torvalds 	struct usb_device *dev = interface_to_usbdev(interface);
9661da177e4SLinus Torvalds 	struct usb_serial *serial = NULL;
9671da177e4SLinus Torvalds 	struct usb_serial_port *port;
9681546e6aeSJohan Hovold 	struct usb_serial_endpoints *epds;
969ea65370dSGreg Kroah-Hartman 	struct usb_serial_driver *type = NULL;
9701da177e4SLinus Torvalds 	int retval;
9711da177e4SLinus Torvalds 	int i;
9721da177e4SLinus Torvalds 	int num_ports = 0;
973ef88f33fSJohan Hovold 	unsigned char max_endpoints;
9741da177e4SLinus Torvalds 
9750daeed38SAndi Kleen 	mutex_lock(&table_lock);
9761da177e4SLinus Torvalds 	type = search_serial_device(interface);
9771da177e4SLinus Torvalds 	if (!type) {
9780daeed38SAndi Kleen 		mutex_unlock(&table_lock);
97992931d24SGreg Kroah-Hartman 		dev_dbg(ddev, "none matched\n");
9801da177e4SLinus Torvalds 		return -ENODEV;
9811da177e4SLinus Torvalds 	}
9821da177e4SLinus Torvalds 
9830daeed38SAndi Kleen 	if (!try_module_get(type->driver.owner)) {
9840daeed38SAndi Kleen 		mutex_unlock(&table_lock);
98592931d24SGreg Kroah-Hartman 		dev_err(ddev, "module get failed, exiting\n");
9860daeed38SAndi Kleen 		return -EIO;
9870daeed38SAndi Kleen 	}
9880daeed38SAndi Kleen 	mutex_unlock(&table_lock);
9890daeed38SAndi Kleen 
9901da177e4SLinus Torvalds 	serial = create_serial(dev, interface, type);
9911da177e4SLinus Torvalds 	if (!serial) {
992c2fef456SJohan Hovold 		retval = -ENOMEM;
993c2fef456SJohan Hovold 		goto err_put_module;
9941da177e4SLinus Torvalds 	}
9951da177e4SLinus Torvalds 
9961da177e4SLinus Torvalds 	/* if this device type has a probe function, call it */
9971da177e4SLinus Torvalds 	if (type->probe) {
9981da177e4SLinus Torvalds 		const struct usb_device_id *id;
9991da177e4SLinus Torvalds 
100093bacefcSGreg Kroah-Hartman 		id = get_iface_id(type, interface);
10011da177e4SLinus Torvalds 		retval = type->probe(serial, id);
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds 		if (retval) {
100492931d24SGreg Kroah-Hartman 			dev_dbg(ddev, "sub driver rejected device\n");
10055de03c99SJohan Hovold 			goto err_release_sibling;
10061da177e4SLinus Torvalds 		}
10071da177e4SLinus Torvalds 	}
10081da177e4SLinus Torvalds 
10091da177e4SLinus Torvalds 	/* descriptor matches, let's find the endpoints needed */
10101546e6aeSJohan Hovold 	epds = kzalloc(sizeof(*epds), GFP_KERNEL);
10111546e6aeSJohan Hovold 	if (!epds) {
10121546e6aeSJohan Hovold 		retval = -ENOMEM;
10135de03c99SJohan Hovold 		goto err_release_sibling;
1014d979e9f9SJohan Hovold 	}
10151da177e4SLinus Torvalds 
10165de03c99SJohan Hovold 	find_endpoints(serial, epds, interface);
10175de03c99SJohan Hovold 	if (serial->sibling)
10185de03c99SJohan Hovold 		find_endpoints(serial, epds, serial->sibling);
10191da177e4SLinus Torvalds 
102092e6b2c6SJohan Hovold 	if (epds->num_bulk_in < type->num_bulk_in ||
102192e6b2c6SJohan Hovold 			epds->num_bulk_out < type->num_bulk_out ||
102292e6b2c6SJohan Hovold 			epds->num_interrupt_in < type->num_interrupt_in ||
102392e6b2c6SJohan Hovold 			epds->num_interrupt_out < type->num_interrupt_out) {
102492e6b2c6SJohan Hovold 		dev_err(ddev, "required endpoints missing\n");
102592e6b2c6SJohan Hovold 		retval = -ENODEV;
102692e6b2c6SJohan Hovold 		goto err_free_epds;
102792e6b2c6SJohan Hovold 	}
1028a794499bSJohan Hovold 
102907814246SJohan Hovold 	if (type->calc_num_ports) {
103007814246SJohan Hovold 		retval = type->calc_num_ports(serial, epds);
103107814246SJohan Hovold 		if (retval < 0)
103207814246SJohan Hovold 			goto err_free_epds;
103307814246SJohan Hovold 		num_ports = retval;
103407814246SJohan Hovold 	}
1035a794499bSJohan Hovold 
10361da177e4SLinus Torvalds 	if (!num_ports)
10371da177e4SLinus Torvalds 		num_ports = type->num_ports;
10381da177e4SLinus Torvalds 
10395654699fSJohan Hovold 	if (num_ports > MAX_NUM_PORTS) {
10405654699fSJohan Hovold 		dev_warn(ddev, "too many ports requested: %d\n", num_ports);
10415654699fSJohan Hovold 		num_ports = MAX_NUM_PORTS;
10425654699fSJohan Hovold 	}
10435654699fSJohan Hovold 
1044ef88f33fSJohan Hovold 	serial->num_ports = (unsigned char)num_ports;
10451546e6aeSJohan Hovold 	serial->num_bulk_in = epds->num_bulk_in;
10461546e6aeSJohan Hovold 	serial->num_bulk_out = epds->num_bulk_out;
10471546e6aeSJohan Hovold 	serial->num_interrupt_in = epds->num_interrupt_in;
10481546e6aeSJohan Hovold 	serial->num_interrupt_out = epds->num_interrupt_out;
10491da177e4SLinus Torvalds 
1050063a2da8SAlan Stern 	/* found all that we need */
105192931d24SGreg Kroah-Hartman 	dev_info(ddev, "%s converter detected\n", type->description);
1052063a2da8SAlan Stern 
10531da177e4SLinus Torvalds 	/* create our ports, we need as many as the max endpoints */
1054a8d6f0a9SAlan Cox 	/* we don't use num_ports here because some devices have more
1055a8d6f0a9SAlan Cox 	   endpoint pairs than ports */
10561546e6aeSJohan Hovold 	max_endpoints = max(epds->num_bulk_in, epds->num_bulk_out);
10571546e6aeSJohan Hovold 	max_endpoints = max(max_endpoints, epds->num_interrupt_in);
10581546e6aeSJohan Hovold 	max_endpoints = max(max_endpoints, epds->num_interrupt_out);
1059ef88f33fSJohan Hovold 	max_endpoints = max(max_endpoints, serial->num_ports);
10601da177e4SLinus Torvalds 	serial->num_port_pointers = max_endpoints;
10614b10f0f3SOliver Neukum 
1062d9a38a87SJohan Hovold 	dev_dbg(ddev, "setting up %d port structure(s)\n", max_endpoints);
10631da177e4SLinus Torvalds 	for (i = 0; i < max_endpoints; ++i) {
106480b6ca48SEric Sesterhenn 		port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
1065c22ac6d2SJohan Hovold 		if (!port) {
1066c22ac6d2SJohan Hovold 			retval = -ENOMEM;
1067c22ac6d2SJohan Hovold 			goto err_free_epds;
1068c22ac6d2SJohan Hovold 		}
10694a90f09bSAlan Cox 		tty_port_init(&port->port);
1070335f8514SAlan Cox 		port->port.ops = &serial_port_ops;
10711da177e4SLinus Torvalds 		port->serial = serial;
1072507ca9bcSGreg Kroah-Hartman 		spin_lock_init(&port->lock);
1073e1108a63SAlan Cox 		/* Keep this for private driver use for the moment but
1074e1108a63SAlan Cox 		   should probably go away */
1075c4028958SDavid Howells 		INIT_WORK(&port->work, usb_serial_port_work);
10761da177e4SLinus Torvalds 		serial->port[i] = port;
107741bd34ddSAlan Stern 		port->dev.parent = &interface->dev;
107841bd34ddSAlan Stern 		port->dev.driver = NULL;
107941bd34ddSAlan Stern 		port->dev.bus = &usb_serial_bus_type;
108069a3d212SJohan Hovold 		port->dev.release = &usb_serial_port_release;
10812deb96b5SJohan Hovold 		port->dev.groups = usb_serial_port_groups;
108241bd34ddSAlan Stern 		device_initialize(&port->dev);
10831da177e4SLinus Torvalds 	}
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds 	/* set up the endpoint information */
10861546e6aeSJohan Hovold 	for (i = 0; i < epds->num_bulk_in; ++i) {
108745e5d4d4SJohan Hovold 		retval = setup_port_bulk_in(serial->port[i], epds->bulk_in[i]);
108845e5d4d4SJohan Hovold 		if (retval)
1089c22ac6d2SJohan Hovold 			goto err_free_epds;
10901da177e4SLinus Torvalds 	}
10911da177e4SLinus Torvalds 
10921546e6aeSJohan Hovold 	for (i = 0; i < epds->num_bulk_out; ++i) {
109345e5d4d4SJohan Hovold 		retval = setup_port_bulk_out(serial->port[i],
109445e5d4d4SJohan Hovold 				epds->bulk_out[i]);
109545e5d4d4SJohan Hovold 		if (retval)
1096c22ac6d2SJohan Hovold 			goto err_free_epds;
10971da177e4SLinus Torvalds 	}
10981da177e4SLinus Torvalds 
10991da177e4SLinus Torvalds 	if (serial->type->read_int_callback) {
11001546e6aeSJohan Hovold 		for (i = 0; i < epds->num_interrupt_in; ++i) {
110145e5d4d4SJohan Hovold 			retval = setup_port_interrupt_in(serial->port[i],
110245e5d4d4SJohan Hovold 					epds->interrupt_in[i]);
110345e5d4d4SJohan Hovold 			if (retval)
1104c22ac6d2SJohan Hovold 				goto err_free_epds;
11051da177e4SLinus Torvalds 		}
11061546e6aeSJohan Hovold 	} else if (epds->num_interrupt_in) {
110792931d24SGreg Kroah-Hartman 		dev_dbg(ddev, "The device claims to support interrupt in transfers, but read_int_callback is not defined\n");
11081da177e4SLinus Torvalds 	}
11091da177e4SLinus Torvalds 
11101da177e4SLinus Torvalds 	if (serial->type->write_int_callback) {
11111546e6aeSJohan Hovold 		for (i = 0; i < epds->num_interrupt_out; ++i) {
111245e5d4d4SJohan Hovold 			retval = setup_port_interrupt_out(serial->port[i],
111345e5d4d4SJohan Hovold 					epds->interrupt_out[i]);
111445e5d4d4SJohan Hovold 			if (retval)
1115c22ac6d2SJohan Hovold 				goto err_free_epds;
11161da177e4SLinus Torvalds 		}
11171546e6aeSJohan Hovold 	} else if (epds->num_interrupt_out) {
111892931d24SGreg Kroah-Hartman 		dev_dbg(ddev, "The device claims to support interrupt out transfers, but write_int_callback is not defined\n");
11191da177e4SLinus Torvalds 	}
11201da177e4SLinus Torvalds 
1121bdce6612SJohan Hovold 	usb_set_intfdata(interface, serial);
1122bdce6612SJohan Hovold 
11231da177e4SLinus Torvalds 	/* if this device type has an attach function, call it */
11241da177e4SLinus Torvalds 	if (type->attach) {
11251da177e4SLinus Torvalds 		retval = type->attach(serial);
11261da177e4SLinus Torvalds 		if (retval < 0)
1127c22ac6d2SJohan Hovold 			goto err_free_epds;
1128a4720c65SAlan Stern 		serial->attached = 1;
11291da177e4SLinus Torvalds 		if (retval > 0) {
1130a8d6f0a9SAlan Cox 			/* quietly accept this device, but don't bind to a
1131a8d6f0a9SAlan Cox 			   serial port as it's about to disappear */
11320a3c8549SAlan Stern 			serial->num_ports = 0;
11331da177e4SLinus Torvalds 			goto exit;
11341da177e4SLinus Torvalds 		}
1135a4720c65SAlan Stern 	} else {
1136a4720c65SAlan Stern 		serial->attached = 1;
11371da177e4SLinus Torvalds 	}
11381da177e4SLinus Torvalds 
1139c22ac6d2SJohan Hovold 	retval = allocate_minors(serial, num_ports);
1140c22ac6d2SJohan Hovold 	if (retval) {
1141e5b1e206SGreg Kroah-Hartman 		dev_err(ddev, "No more free serial minor numbers\n");
1142c22ac6d2SJohan Hovold 		goto err_free_epds;
114334ef50e5SOliver Neukum 	}
114434ef50e5SOliver Neukum 
11451da177e4SLinus Torvalds 	/* register all of the individual ports with the driver core */
11461da177e4SLinus Torvalds 	for (i = 0; i < num_ports; ++i) {
11471da177e4SLinus Torvalds 		port = serial->port[i];
11481143832eSGreg Kroah-Hartman 		dev_set_name(&port->dev, "ttyUSB%d", port->minor);
1149d9a38a87SJohan Hovold 		dev_dbg(ddev, "registering %s\n", dev_name(&port->dev));
1150a7a6b79bSMing Lei 		device_enable_async_suspend(&port->dev);
1151a7a6b79bSMing Lei 
115241bd34ddSAlan Stern 		retval = device_add(&port->dev);
1153891a3b1fSAlan Stern 		if (retval)
115492931d24SGreg Kroah-Hartman 			dev_err(ddev, "Error registering port device, continuing\n");
11551da177e4SLinus Torvalds 	}
11561da177e4SLinus Torvalds 
1157126d26f6SJohan Hovold 	if (num_ports > 0)
1158e5b1e206SGreg Kroah-Hartman 		usb_serial_console_init(serial->port[0]->minor);
11591da177e4SLinus Torvalds exit:
11601546e6aeSJohan Hovold 	kfree(epds);
1161d92a3ca6SMing Lei 	module_put(type->driver.owner);
11621da177e4SLinus Torvalds 	return 0;
11631da177e4SLinus Torvalds 
116492e6b2c6SJohan Hovold err_free_epds:
116592e6b2c6SJohan Hovold 	kfree(epds);
11665de03c99SJohan Hovold err_release_sibling:
11675de03c99SJohan Hovold 	release_sibling(serial, interface);
116841bd34ddSAlan Stern 	usb_serial_put(serial);
1169c2fef456SJohan Hovold err_put_module:
1170d92a3ca6SMing Lei 	module_put(type->driver.owner);
1171c2fef456SJohan Hovold 
1172c2fef456SJohan Hovold 	return retval;
11731da177e4SLinus Torvalds }
11741da177e4SLinus Torvalds 
usb_serial_disconnect(struct usb_interface * interface)117532078f91SGreg Kroah-Hartman static void usb_serial_disconnect(struct usb_interface *interface)
11761da177e4SLinus Torvalds {
11771da177e4SLinus Torvalds 	int i;
11781da177e4SLinus Torvalds 	struct usb_serial *serial = usb_get_intfdata(interface);
11791da177e4SLinus Torvalds 	struct device *dev = &interface->dev;
11801da177e4SLinus Torvalds 	struct usb_serial_port *port;
11813fff3b43SJohan Hovold 	struct tty_struct *tty;
11821da177e4SLinus Torvalds 
11835de03c99SJohan Hovold 	/* sibling interface is cleaning up */
11845de03c99SJohan Hovold 	if (!serial)
11855de03c99SJohan Hovold 		return;
11865de03c99SJohan Hovold 
118773e487fdSGuennadi Liakhovetski 	usb_serial_console_disconnect(serial);
11881da177e4SLinus Torvalds 
1189a1cd7e99SOliver Neukum 	mutex_lock(&serial->disc_mutex);
1190a1cd7e99SOliver Neukum 	/* must set a flag, to signal subdrivers */
1191a1cd7e99SOliver Neukum 	serial->disconnected = 1;
11922d93148aSAlan Stern 	mutex_unlock(&serial->disc_mutex);
11932d93148aSAlan Stern 
11941da177e4SLinus Torvalds 	for (i = 0; i < serial->num_ports; ++i) {
11951da177e4SLinus Torvalds 		port = serial->port[i];
11963fff3b43SJohan Hovold 		tty = tty_port_tty_get(&port->port);
11974a90f09bSAlan Cox 		if (tty) {
1198d2b39182SAlan Cox 			tty_vhangup(tty);
11994a90f09bSAlan Cox 			tty_kref_put(tty);
12004a90f09bSAlan Cox 		}
12016a5c821cSJohan Hovold 		usb_serial_port_poison_urbs(port);
1202c371de14SJohan Hovold 		wake_up_interruptible(&port->port.delta_msr_wait);
12032d93148aSAlan Stern 		cancel_work_sync(&port->work);
1204891a3b1fSAlan Stern 		if (device_is_registered(&port->dev))
12052d93148aSAlan Stern 			device_del(&port->dev);
120634ef50e5SOliver Neukum 	}
12070f16cfe3SJohan Hovold 	if (serial->type->disconnect)
1208f9c99bb8SAlan Stern 		serial->type->disconnect(serial);
12092d93148aSAlan Stern 
12105de03c99SJohan Hovold 	release_sibling(serial, interface);
12115de03c99SJohan Hovold 
121241bd34ddSAlan Stern 	/* let the last holder of this object cause it to be cleaned up */
121373e487fdSGuennadi Liakhovetski 	usb_serial_put(serial);
12141da177e4SLinus Torvalds 	dev_info(dev, "device disconnected\n");
12151da177e4SLinus Torvalds }
12161da177e4SLinus Torvalds 
usb_serial_suspend(struct usb_interface * intf,pm_message_t message)1217ec22559eSOliver Neukum int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
1218ec22559eSOliver Neukum {
1219ec22559eSOliver Neukum 	struct usb_serial *serial = usb_get_intfdata(intf);
12205de03c99SJohan Hovold 	int i, r;
12215de03c99SJohan Hovold 
12225de03c99SJohan Hovold 	/* suspend when called for first sibling interface */
12235de03c99SJohan Hovold 	if (serial->suspend_count++)
12245de03c99SJohan Hovold 		return 0;
1225ec22559eSOliver Neukum 
122693e4f47fSMing Lei 	/*
122793e4f47fSMing Lei 	 * serial->type->suspend() MUST return 0 in system sleep context,
122893e4f47fSMing Lei 	 * otherwise, the resume callback has to recover device from
122993e4f47fSMing Lei 	 * previous suspend failure.
123093e4f47fSMing Lei 	 */
123181e5b23cSOliver Neukum 	if (serial->type->suspend) {
123281e5b23cSOliver Neukum 		r = serial->type->suspend(serial, message);
12335de03c99SJohan Hovold 		if (r < 0) {
12345de03c99SJohan Hovold 			serial->suspend_count--;
12355de03c99SJohan Hovold 			return r;
12365de03c99SJohan Hovold 		}
123781e5b23cSOliver Neukum 	}
123881e5b23cSOliver Neukum 
12393fff3b43SJohan Hovold 	for (i = 0; i < serial->num_ports; ++i)
12403fff3b43SJohan Hovold 		usb_serial_port_poison_urbs(serial->port[i]);
12415de03c99SJohan Hovold 
12425de03c99SJohan Hovold 	return 0;
1243ec22559eSOliver Neukum }
1244ec22559eSOliver Neukum EXPORT_SYMBOL(usb_serial_suspend);
1245ec22559eSOliver Neukum 
usb_serial_unpoison_port_urbs(struct usb_serial * serial)12466a5c821cSJohan Hovold static void usb_serial_unpoison_port_urbs(struct usb_serial *serial)
12476a5c821cSJohan Hovold {
12486a5c821cSJohan Hovold 	int i;
12496a5c821cSJohan Hovold 
12503fff3b43SJohan Hovold 	for (i = 0; i < serial->num_ports; ++i)
12513fff3b43SJohan Hovold 		usb_serial_port_unpoison_urbs(serial->port[i]);
12526a5c821cSJohan Hovold }
12536a5c821cSJohan Hovold 
usb_serial_resume(struct usb_interface * intf)1254ec22559eSOliver Neukum int usb_serial_resume(struct usb_interface *intf)
1255ec22559eSOliver Neukum {
1256ec22559eSOliver Neukum 	struct usb_serial *serial = usb_get_intfdata(intf);
1257c49cfa91SOliver Neukum 	int rv;
1258ec22559eSOliver Neukum 
12595de03c99SJohan Hovold 	/* resume when called for last sibling interface */
12605de03c99SJohan Hovold 	if (--serial->suspend_count)
12615de03c99SJohan Hovold 		return 0;
12625de03c99SJohan Hovold 
12636a5c821cSJohan Hovold 	usb_serial_unpoison_port_urbs(serial);
12646a5c821cSJohan Hovold 
12658abaee23SSarah Sharp 	if (serial->type->resume)
1266c49cfa91SOliver Neukum 		rv = serial->type->resume(serial);
1267c49cfa91SOliver Neukum 	else
1268c49cfa91SOliver Neukum 		rv = usb_serial_generic_resume(serial);
1269f8bece8dSOliver Neukum 
1270c49cfa91SOliver Neukum 	return rv;
1271ec22559eSOliver Neukum }
1272ec22559eSOliver Neukum EXPORT_SYMBOL(usb_serial_resume);
1273ec22559eSOliver Neukum 
usb_serial_reset_resume(struct usb_interface * intf)12747186364eSGreg Kroah-Hartman static int usb_serial_reset_resume(struct usb_interface *intf)
12757186364eSGreg Kroah-Hartman {
12767186364eSGreg Kroah-Hartman 	struct usb_serial *serial = usb_get_intfdata(intf);
12777186364eSGreg Kroah-Hartman 	int rv;
12787186364eSGreg Kroah-Hartman 
12795de03c99SJohan Hovold 	/* resume when called for last sibling interface */
12805de03c99SJohan Hovold 	if (--serial->suspend_count)
12815de03c99SJohan Hovold 		return 0;
12825de03c99SJohan Hovold 
12836a5c821cSJohan Hovold 	usb_serial_unpoison_port_urbs(serial);
12846a5c821cSJohan Hovold 
1285ca0400d2SJohan Hovold 	if (serial->type->reset_resume) {
12867186364eSGreg Kroah-Hartman 		rv = serial->type->reset_resume(serial);
1287ca0400d2SJohan Hovold 	} else {
1288dcd82cd1SGreg Kroah-Hartman 		rv = -EOPNOTSUPP;
1289dcd82cd1SGreg Kroah-Hartman 		intf->needs_binding = 1;
1290dcd82cd1SGreg Kroah-Hartman 	}
12917186364eSGreg Kroah-Hartman 
12927186364eSGreg Kroah-Hartman 	return rv;
12937186364eSGreg Kroah-Hartman }
12947186364eSGreg Kroah-Hartman 
1295b68e31d0SJeff Dike static const struct tty_operations serial_ops = {
12961da177e4SLinus Torvalds 	.open =			serial_open,
12971da177e4SLinus Torvalds 	.close =		serial_close,
12981da177e4SLinus Torvalds 	.write =		serial_write,
1299335f8514SAlan Cox 	.hangup =		serial_hangup,
13001da177e4SLinus Torvalds 	.write_room =		serial_write_room,
13011da177e4SLinus Torvalds 	.ioctl =		serial_ioctl,
13021da177e4SLinus Torvalds 	.set_termios =		serial_set_termios,
13031da177e4SLinus Torvalds 	.throttle =		serial_throttle,
13041da177e4SLinus Torvalds 	.unthrottle =		serial_unthrottle,
13051da177e4SLinus Torvalds 	.break_ctl =		serial_break,
13061da177e4SLinus Torvalds 	.chars_in_buffer =	serial_chars_in_buffer,
13070693196fSJohan Hovold 	.wait_until_sent =	serial_wait_until_sent,
13081da177e4SLinus Torvalds 	.tiocmget =		serial_tiocmget,
13091da177e4SLinus Torvalds 	.tiocmset =		serial_tiocmset,
1310d281da7fSAlan Cox 	.get_icount =		serial_get_icount,
131181732b26SAl Viro 	.set_serial =		serial_set_serial,
131281732b26SAl Viro 	.get_serial =		serial_get_serial,
1313f278a2f7SDave Young 	.cleanup =		serial_cleanup,
1314fe1ae7fdSAlan Cox 	.install =		serial_install,
13158a8dcabfSChristoph Hellwig 	.proc_show =		serial_proc_show,
13161da177e4SLinus Torvalds };
13171da177e4SLinus Torvalds 
1318335f8514SAlan Cox 
13191da177e4SLinus Torvalds struct tty_driver *usb_serial_tty_driver;
13201da177e4SLinus Torvalds 
usb_serial_init(void)13211da177e4SLinus Torvalds static int __init usb_serial_init(void)
13221da177e4SLinus Torvalds {
13231da177e4SLinus Torvalds 	int result;
13241da177e4SLinus Torvalds 
132539b7b42bSJiri Slaby 	usb_serial_tty_driver = tty_alloc_driver(USB_SERIAL_TTY_MINORS,
132639b7b42bSJiri Slaby 			TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
132739b7b42bSJiri Slaby 	if (IS_ERR(usb_serial_tty_driver))
132839b7b42bSJiri Slaby 		return PTR_ERR(usb_serial_tty_driver);
13291da177e4SLinus Torvalds 
13301da177e4SLinus Torvalds 	/* Initialize our global data */
13311da177e4SLinus Torvalds 	result = bus_register(&usb_serial_bus_type);
13321da177e4SLinus Torvalds 	if (result) {
133392931d24SGreg Kroah-Hartman 		pr_err("%s - registering bus driver failed\n", __func__);
133496a83c95SJohan Hovold 		goto err_put_driver;
13351da177e4SLinus Torvalds 	}
13361da177e4SLinus Torvalds 
13371da177e4SLinus Torvalds 	usb_serial_tty_driver->driver_name = "usbserial";
13381da177e4SLinus Torvalds 	usb_serial_tty_driver->name = "ttyUSB";
1339455b4f7eSGreg Kroah-Hartman 	usb_serial_tty_driver->major = USB_SERIAL_TTY_MAJOR;
13401da177e4SLinus Torvalds 	usb_serial_tty_driver->minor_start = 0;
13411da177e4SLinus Torvalds 	usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
13421da177e4SLinus Torvalds 	usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
13431da177e4SLinus Torvalds 	usb_serial_tty_driver->init_termios = tty_std_termios;
1344a8d6f0a9SAlan Cox 	usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
1345a8d6f0a9SAlan Cox 							| HUPCL | CLOCAL;
1346a5b6f60cSAlan Cox 	usb_serial_tty_driver->init_termios.c_ispeed = 9600;
1347a5b6f60cSAlan Cox 	usb_serial_tty_driver->init_termios.c_ospeed = 9600;
13481da177e4SLinus Torvalds 	tty_set_operations(usb_serial_tty_driver, &serial_ops);
13491da177e4SLinus Torvalds 	result = tty_register_driver(usb_serial_tty_driver);
13501da177e4SLinus Torvalds 	if (result) {
135192931d24SGreg Kroah-Hartman 		pr_err("%s - tty_register_driver failed\n", __func__);
135296a83c95SJohan Hovold 		goto err_unregister_bus;
13531da177e4SLinus Torvalds 	}
13541da177e4SLinus Torvalds 
135506299db3SGreg Kroah-Hartman 	/* register the generic driver, if we should */
13563033bc8dSGreg Kroah-Hartman 	result = usb_serial_generic_register();
135706299db3SGreg Kroah-Hartman 	if (result < 0) {
135892931d24SGreg Kroah-Hartman 		pr_err("%s - registering generic driver failed\n", __func__);
135996a83c95SJohan Hovold 		goto err_unregister_driver;
136006299db3SGreg Kroah-Hartman 	}
136106299db3SGreg Kroah-Hartman 
13621da177e4SLinus Torvalds 	return result;
13631da177e4SLinus Torvalds 
136496a83c95SJohan Hovold err_unregister_driver:
13651da177e4SLinus Torvalds 	tty_unregister_driver(usb_serial_tty_driver);
136696a83c95SJohan Hovold err_unregister_bus:
13671da177e4SLinus Torvalds 	bus_unregister(&usb_serial_bus_type);
136896a83c95SJohan Hovold err_put_driver:
136992931d24SGreg Kroah-Hartman 	pr_err("%s - returning with error %d\n", __func__, result);
13709f90a4ddSJiri Slaby 	tty_driver_kref_put(usb_serial_tty_driver);
13711da177e4SLinus Torvalds 	return result;
13721da177e4SLinus Torvalds }
13731da177e4SLinus Torvalds 
13741da177e4SLinus Torvalds 
usb_serial_exit(void)13751da177e4SLinus Torvalds static void __exit usb_serial_exit(void)
13761da177e4SLinus Torvalds {
13771da177e4SLinus Torvalds 	usb_serial_console_exit();
13781da177e4SLinus Torvalds 
13791da177e4SLinus Torvalds 	usb_serial_generic_deregister();
13801da177e4SLinus Torvalds 
13811da177e4SLinus Torvalds 	tty_unregister_driver(usb_serial_tty_driver);
13829f90a4ddSJiri Slaby 	tty_driver_kref_put(usb_serial_tty_driver);
13831da177e4SLinus Torvalds 	bus_unregister(&usb_serial_bus_type);
1384d23f47d4SJohannes Thumshirn 	idr_destroy(&serial_minors);
13851da177e4SLinus Torvalds }
13861da177e4SLinus Torvalds 
13871da177e4SLinus Torvalds 
13881da177e4SLinus Torvalds module_init(usb_serial_init);
13891da177e4SLinus Torvalds module_exit(usb_serial_exit);
13901da177e4SLinus Torvalds 
13911da177e4SLinus Torvalds #define set_to_generic_if_null(type, function)				\
13921da177e4SLinus Torvalds 	do {								\
13931da177e4SLinus Torvalds 		if (!type->function) {					\
13941da177e4SLinus Torvalds 			type->function = usb_serial_generic_##function;	\
1395c3452f5eSJohan Hovold 			pr_debug("%s: using generic " #function	"\n",	\
1396c3452f5eSJohan Hovold 						type->driver.name);	\
13971da177e4SLinus Torvalds 		}							\
13981da177e4SLinus Torvalds 	} while (0)
13991da177e4SLinus Torvalds 
usb_serial_operations_init(struct usb_serial_driver * device)1400c3452f5eSJohan Hovold static void usb_serial_operations_init(struct usb_serial_driver *device)
14011da177e4SLinus Torvalds {
14021da177e4SLinus Torvalds 	set_to_generic_if_null(device, open);
14031da177e4SLinus Torvalds 	set_to_generic_if_null(device, write);
14041da177e4SLinus Torvalds 	set_to_generic_if_null(device, close);
14051da177e4SLinus Torvalds 	set_to_generic_if_null(device, write_room);
14061da177e4SLinus Torvalds 	set_to_generic_if_null(device, chars_in_buffer);
1407dcf01050SJohan Hovold 	if (device->tx_empty)
1408dcf01050SJohan Hovold 		set_to_generic_if_null(device, wait_until_sent);
14091da177e4SLinus Torvalds 	set_to_generic_if_null(device, read_bulk_callback);
14101da177e4SLinus Torvalds 	set_to_generic_if_null(device, write_bulk_callback);
141123154320SJohan Hovold 	set_to_generic_if_null(device, process_read_urb);
1412eaa3bcb0SJohan Hovold 	set_to_generic_if_null(device, prepare_write_buffer);
14131da177e4SLinus Torvalds }
14141da177e4SLinus Torvalds 
usb_serial_register(struct usb_serial_driver * driver)1415f799e767SGreg Kroah-Hartman static int usb_serial_register(struct usb_serial_driver *driver)
14161da177e4SLinus Torvalds {
14171da177e4SLinus Torvalds 	int retval;
14181da177e4SLinus Torvalds 
1419e4abe665SDave Young 	if (usb_disabled())
1420e4abe665SDave Young 		return -ENODEV;
1421e4abe665SDave Young 
1422269bda1cSGreg Kroah-Hartman 	if (!driver->description)
1423269bda1cSGreg Kroah-Hartman 		driver->description = driver->driver.name;
14245620b5f7SAlan Stern 	if (!driver->usb_driver) {
14255620b5f7SAlan Stern 		WARN(1, "Serial driver %s has no usb_driver\n",
14265620b5f7SAlan Stern 				driver->description);
14275620b5f7SAlan Stern 		return -EINVAL;
14285620b5f7SAlan Stern 	}
1429269bda1cSGreg Kroah-Hartman 
1430fdb838efSJohan Hovold 	/* Prevent individual ports from being unbound. */
1431fdb838efSJohan Hovold 	driver->driver.suppress_bind_attrs = true;
1432fdb838efSJohan Hovold 
1433c3452f5eSJohan Hovold 	usb_serial_operations_init(driver);
1434c3452f5eSJohan Hovold 
14351da177e4SLinus Torvalds 	/* Add this device to our list of devices */
14360daeed38SAndi Kleen 	mutex_lock(&table_lock);
1437ea65370dSGreg Kroah-Hartman 	list_add(&driver->driver_list, &usb_serial_driver_list);
14381da177e4SLinus Torvalds 
1439ea65370dSGreg Kroah-Hartman 	retval = usb_serial_bus_register(driver);
14401da177e4SLinus Torvalds 	if (retval) {
144192931d24SGreg Kroah-Hartman 		pr_err("problem %d when registering driver %s\n", retval, driver->description);
1442ea65370dSGreg Kroah-Hartman 		list_del(&driver->driver_list);
1443ca0400d2SJohan Hovold 	} else {
1444ee42f6c9SGreg Kroah-Hartman 		pr_info("USB Serial support registered for %s\n", driver->description);
1445ca0400d2SJohan Hovold 	}
14460daeed38SAndi Kleen 	mutex_unlock(&table_lock);
14471da177e4SLinus Torvalds 	return retval;
14481da177e4SLinus Torvalds }
14491da177e4SLinus Torvalds 
usb_serial_deregister(struct usb_serial_driver * device)1450f799e767SGreg Kroah-Hartman static void usb_serial_deregister(struct usb_serial_driver *device)
14511da177e4SLinus Torvalds {
1452ee42f6c9SGreg Kroah-Hartman 	pr_info("USB Serial deregistering driver %s\n", device->description);
145310164c2aSJohan Hovold 
14540daeed38SAndi Kleen 	mutex_lock(&table_lock);
14551da177e4SLinus Torvalds 	list_del(&device->driver_list);
14560daeed38SAndi Kleen 	mutex_unlock(&table_lock);
145710164c2aSJohan Hovold 
145810164c2aSJohan Hovold 	usb_serial_bus_deregister(device);
14591da177e4SLinus Torvalds }
14601da177e4SLinus Torvalds 
1461765e0ba6SAlan Stern /**
1462765e0ba6SAlan Stern  * usb_serial_register_drivers - register drivers for a usb-serial module
1463765e0ba6SAlan Stern  * @serial_drivers: NULL-terminated array of pointers to drivers to be registered
146468e24113SGreg Kroah-Hartman  * @name: name of the usb_driver for this set of @serial_drivers
146568e24113SGreg Kroah-Hartman  * @id_table: list of all devices this @serial_drivers set binds to
1466765e0ba6SAlan Stern  *
146768e24113SGreg Kroah-Hartman  * Registers all the drivers in the @serial_drivers array, and dynamically
146868e24113SGreg Kroah-Hartman  * creates a struct usb_driver with the name @name and id_table of @id_table.
1469765e0ba6SAlan Stern  */
usb_serial_register_drivers(struct usb_serial_driver * const serial_drivers[],const char * name,const struct usb_device_id * id_table)147068e24113SGreg Kroah-Hartman int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[],
147168e24113SGreg Kroah-Hartman 				const char *name,
147268e24113SGreg Kroah-Hartman 				const struct usb_device_id *id_table)
1473765e0ba6SAlan Stern {
1474765e0ba6SAlan Stern 	int rc;
147568e24113SGreg Kroah-Hartman 	struct usb_driver *udriver;
1476765e0ba6SAlan Stern 	struct usb_serial_driver * const *sd;
1477765e0ba6SAlan Stern 
1478765e0ba6SAlan Stern 	/*
1479765e0ba6SAlan Stern 	 * udriver must be registered before any of the serial drivers,
1480765e0ba6SAlan Stern 	 * because the store_new_id() routine for the serial drivers (in
1481765e0ba6SAlan Stern 	 * bus.c) probes udriver.
1482765e0ba6SAlan Stern 	 *
1483765e0ba6SAlan Stern 	 * Performance hack: We don't want udriver to be probed until
1484765e0ba6SAlan Stern 	 * the serial drivers are registered, because the probe would
1485765e0ba6SAlan Stern 	 * simply fail for lack of a matching serial driver.
148668e24113SGreg Kroah-Hartman 	 * So we leave udriver's id_table set to NULL until we are all set.
14875cbe61c5SAlan Stern 	 *
14885cbe61c5SAlan Stern 	 * Suspend/resume support is implemented in the usb-serial core,
14895cbe61c5SAlan Stern 	 * so fill in the PM-related fields in udriver.
1490765e0ba6SAlan Stern 	 */
149168e24113SGreg Kroah-Hartman 	udriver = kzalloc(sizeof(*udriver), GFP_KERNEL);
149268e24113SGreg Kroah-Hartman 	if (!udriver)
149368e24113SGreg Kroah-Hartman 		return -ENOMEM;
1494765e0ba6SAlan Stern 
149568e24113SGreg Kroah-Hartman 	udriver->name = name;
1496765e0ba6SAlan Stern 	udriver->no_dynamic_id = 1;
14975cbe61c5SAlan Stern 	udriver->supports_autosuspend = 1;
14985cbe61c5SAlan Stern 	udriver->suspend = usb_serial_suspend;
14995cbe61c5SAlan Stern 	udriver->resume = usb_serial_resume;
15005026bb07SGreg Kroah-Hartman 	udriver->probe = usb_serial_probe;
150132078f91SGreg Kroah-Hartman 	udriver->disconnect = usb_serial_disconnect;
15027186364eSGreg Kroah-Hartman 
15037186364eSGreg Kroah-Hartman 	/* we only set the reset_resume field if the serial_driver has one */
15047186364eSGreg Kroah-Hartman 	for (sd = serial_drivers; *sd; ++sd) {
150544b0f083SGreg Kroah-Hartman 		if ((*sd)->reset_resume) {
15067186364eSGreg Kroah-Hartman 			udriver->reset_resume = usb_serial_reset_resume;
15077186364eSGreg Kroah-Hartman 			break;
15087186364eSGreg Kroah-Hartman 		}
150944b0f083SGreg Kroah-Hartman 	}
15107186364eSGreg Kroah-Hartman 
1511765e0ba6SAlan Stern 	rc = usb_register(udriver);
1512765e0ba6SAlan Stern 	if (rc)
151396a83c95SJohan Hovold 		goto err_free_driver;
1514765e0ba6SAlan Stern 
1515765e0ba6SAlan Stern 	for (sd = serial_drivers; *sd; ++sd) {
1516765e0ba6SAlan Stern 		(*sd)->usb_driver = udriver;
1517765e0ba6SAlan Stern 		rc = usb_serial_register(*sd);
1518765e0ba6SAlan Stern 		if (rc)
151996a83c95SJohan Hovold 			goto err_deregister_drivers;
1520765e0ba6SAlan Stern 	}
1521765e0ba6SAlan Stern 
152268e24113SGreg Kroah-Hartman 	/* Now set udriver's id_table and look for matches */
152368e24113SGreg Kroah-Hartman 	udriver->id_table = id_table;
1524765e0ba6SAlan Stern 	rc = driver_attach(&udriver->drvwrap.driver);
1525765e0ba6SAlan Stern 	return 0;
1526765e0ba6SAlan Stern 
152796a83c95SJohan Hovold err_deregister_drivers:
1528765e0ba6SAlan Stern 	while (sd-- > serial_drivers)
1529765e0ba6SAlan Stern 		usb_serial_deregister(*sd);
1530765e0ba6SAlan Stern 	usb_deregister(udriver);
153196a83c95SJohan Hovold err_free_driver:
1532647024a7SAlexey Klimov 	kfree(udriver);
1533765e0ba6SAlan Stern 	return rc;
1534765e0ba6SAlan Stern }
1535765e0ba6SAlan Stern EXPORT_SYMBOL_GPL(usb_serial_register_drivers);
1536765e0ba6SAlan Stern 
1537765e0ba6SAlan Stern /**
1538765e0ba6SAlan Stern  * usb_serial_deregister_drivers - deregister drivers for a usb-serial module
1539765e0ba6SAlan Stern  * @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered
1540765e0ba6SAlan Stern  *
154168e24113SGreg Kroah-Hartman  * Deregisters all the drivers in the @serial_drivers array and deregisters and
154268e24113SGreg Kroah-Hartman  * frees the struct usb_driver that was created by the call to
154368e24113SGreg Kroah-Hartman  * usb_serial_register_drivers().
1544765e0ba6SAlan Stern  */
usb_serial_deregister_drivers(struct usb_serial_driver * const serial_drivers[])154568e24113SGreg Kroah-Hartman void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[])
1546765e0ba6SAlan Stern {
154768e24113SGreg Kroah-Hartman 	struct usb_driver *udriver = (*serial_drivers)->usb_driver;
154868e24113SGreg Kroah-Hartman 
1549765e0ba6SAlan Stern 	for (; *serial_drivers; ++serial_drivers)
1550765e0ba6SAlan Stern 		usb_serial_deregister(*serial_drivers);
1551765e0ba6SAlan Stern 	usb_deregister(udriver);
155268e24113SGreg Kroah-Hartman 	kfree(udriver);
1553765e0ba6SAlan Stern }
1554765e0ba6SAlan Stern EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers);
15551da177e4SLinus Torvalds 
15561da177e4SLinus Torvalds MODULE_AUTHOR(DRIVER_AUTHOR);
15571da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
1558627cfa89SJohan Hovold MODULE_LICENSE("GPL v2");
1559