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