162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * USB Serial Converter driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2009 - 2013 Johan Hovold (jhovold@gmail.com) 662306a36Sopenharmony_ci * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com) 762306a36Sopenharmony_ci * Copyright (C) 2000 Peter Berger (pberger@brimson.com) 862306a36Sopenharmony_ci * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This driver was originally based on the ACM driver by Armin Fuerst (which was 1162306a36Sopenharmony_ci * based on a driver by Brad Keryan) 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * See Documentation/usb/usb-serial.rst for more information on using this 1462306a36Sopenharmony_ci * driver 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/errno.h> 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <linux/tty.h> 2462306a36Sopenharmony_ci#include <linux/tty_driver.h> 2562306a36Sopenharmony_ci#include <linux/tty_flip.h> 2662306a36Sopenharmony_ci#include <linux/module.h> 2762306a36Sopenharmony_ci#include <linux/moduleparam.h> 2862306a36Sopenharmony_ci#include <linux/seq_file.h> 2962306a36Sopenharmony_ci#include <linux/spinlock.h> 3062306a36Sopenharmony_ci#include <linux/mutex.h> 3162306a36Sopenharmony_ci#include <linux/list.h> 3262306a36Sopenharmony_ci#include <linux/uaccess.h> 3362306a36Sopenharmony_ci#include <linux/serial.h> 3462306a36Sopenharmony_ci#include <linux/usb.h> 3562306a36Sopenharmony_ci#include <linux/usb/serial.h> 3662306a36Sopenharmony_ci#include <linux/kfifo.h> 3762306a36Sopenharmony_ci#include <linux/idr.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@linuxfoundation.org>" 4062306a36Sopenharmony_ci#define DRIVER_DESC "USB Serial Driver core" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define USB_SERIAL_TTY_MAJOR 188 4362306a36Sopenharmony_ci#define USB_SERIAL_TTY_MINORS 512 /* should be enough for a while */ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead 4662306a36Sopenharmony_ci the MODULE_DEVICE_TABLE declarations in each serial driver 4762306a36Sopenharmony_ci cause the "hotplug" program to pull in whatever module is necessary 4862306a36Sopenharmony_ci via modprobe, and modprobe will load usbserial because the serial 4962306a36Sopenharmony_ci drivers depend on it. 5062306a36Sopenharmony_ci*/ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic DEFINE_IDR(serial_minors); 5362306a36Sopenharmony_cistatic DEFINE_MUTEX(table_lock); 5462306a36Sopenharmony_cistatic LIST_HEAD(usb_serial_driver_list); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Look up the serial port structure. If it is found and it hasn't been 5862306a36Sopenharmony_ci * disconnected, return with the parent usb_serial structure's disc_mutex held 5962306a36Sopenharmony_ci * and its refcount incremented. Otherwise return NULL. 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_cistruct usb_serial_port *usb_serial_port_get_by_minor(unsigned minor) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct usb_serial *serial; 6462306a36Sopenharmony_ci struct usb_serial_port *port; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci mutex_lock(&table_lock); 6762306a36Sopenharmony_ci port = idr_find(&serial_minors, minor); 6862306a36Sopenharmony_ci if (!port) 6962306a36Sopenharmony_ci goto exit; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci serial = port->serial; 7262306a36Sopenharmony_ci mutex_lock(&serial->disc_mutex); 7362306a36Sopenharmony_ci if (serial->disconnected) { 7462306a36Sopenharmony_ci mutex_unlock(&serial->disc_mutex); 7562306a36Sopenharmony_ci port = NULL; 7662306a36Sopenharmony_ci } else { 7762306a36Sopenharmony_ci kref_get(&serial->kref); 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ciexit: 8062306a36Sopenharmony_ci mutex_unlock(&table_lock); 8162306a36Sopenharmony_ci return port; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int allocate_minors(struct usb_serial *serial, int num_ports) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct usb_serial_port *port; 8762306a36Sopenharmony_ci unsigned int i, j; 8862306a36Sopenharmony_ci int minor; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci dev_dbg(&serial->interface->dev, "%s %d\n", __func__, num_ports); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci mutex_lock(&table_lock); 9362306a36Sopenharmony_ci for (i = 0; i < num_ports; ++i) { 9462306a36Sopenharmony_ci port = serial->port[i]; 9562306a36Sopenharmony_ci minor = idr_alloc(&serial_minors, port, 0, 9662306a36Sopenharmony_ci USB_SERIAL_TTY_MINORS, GFP_KERNEL); 9762306a36Sopenharmony_ci if (minor < 0) 9862306a36Sopenharmony_ci goto error; 9962306a36Sopenharmony_ci port->minor = minor; 10062306a36Sopenharmony_ci port->port_number = i; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci serial->minors_reserved = 1; 10362306a36Sopenharmony_ci mutex_unlock(&table_lock); 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_cierror: 10662306a36Sopenharmony_ci /* unwind the already allocated minors */ 10762306a36Sopenharmony_ci for (j = 0; j < i; ++j) 10862306a36Sopenharmony_ci idr_remove(&serial_minors, serial->port[j]->minor); 10962306a36Sopenharmony_ci mutex_unlock(&table_lock); 11062306a36Sopenharmony_ci return minor; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic void release_minors(struct usb_serial *serial) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci int i; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci mutex_lock(&table_lock); 11862306a36Sopenharmony_ci for (i = 0; i < serial->num_ports; ++i) 11962306a36Sopenharmony_ci idr_remove(&serial_minors, serial->port[i]->minor); 12062306a36Sopenharmony_ci mutex_unlock(&table_lock); 12162306a36Sopenharmony_ci serial->minors_reserved = 0; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciint usb_serial_claim_interface(struct usb_serial *serial, struct usb_interface *intf) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct usb_driver *driver = serial->type->usb_driver; 12762306a36Sopenharmony_ci int ret; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (serial->sibling) 13062306a36Sopenharmony_ci return -EBUSY; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ret = usb_driver_claim_interface(driver, intf, serial); 13362306a36Sopenharmony_ci if (ret) { 13462306a36Sopenharmony_ci dev_err(&serial->interface->dev, 13562306a36Sopenharmony_ci "failed to claim sibling interface: %d\n", ret); 13662306a36Sopenharmony_ci return ret; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci serial->sibling = intf; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_serial_claim_interface); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic void release_sibling(struct usb_serial *serial, struct usb_interface *intf) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct usb_driver *driver = serial->type->usb_driver; 14862306a36Sopenharmony_ci struct usb_interface *sibling; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (!serial->sibling) 15162306a36Sopenharmony_ci return; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (intf == serial->sibling) 15462306a36Sopenharmony_ci sibling = serial->interface; 15562306a36Sopenharmony_ci else 15662306a36Sopenharmony_ci sibling = serial->sibling; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci usb_set_intfdata(sibling, NULL); 15962306a36Sopenharmony_ci usb_driver_release_interface(driver, sibling); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void destroy_serial(struct kref *kref) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct usb_serial *serial; 16562306a36Sopenharmony_ci struct usb_serial_port *port; 16662306a36Sopenharmony_ci int i; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci serial = to_usb_serial(kref); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* return the minor range that this device had */ 17162306a36Sopenharmony_ci if (serial->minors_reserved) 17262306a36Sopenharmony_ci release_minors(serial); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (serial->attached && serial->type->release) 17562306a36Sopenharmony_ci serial->type->release(serial); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* Now that nothing is using the ports, they can be freed */ 17862306a36Sopenharmony_ci for (i = 0; i < serial->num_port_pointers; ++i) { 17962306a36Sopenharmony_ci port = serial->port[i]; 18062306a36Sopenharmony_ci if (port) { 18162306a36Sopenharmony_ci port->serial = NULL; 18262306a36Sopenharmony_ci put_device(&port->dev); 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci usb_put_intf(serial->interface); 18762306a36Sopenharmony_ci usb_put_dev(serial->dev); 18862306a36Sopenharmony_ci kfree(serial); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_civoid usb_serial_put(struct usb_serial *serial) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci kref_put(&serial->kref, destroy_serial); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/***************************************************************************** 19762306a36Sopenharmony_ci * Driver tty interface functions 19862306a36Sopenharmony_ci *****************************************************************************/ 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/** 20162306a36Sopenharmony_ci * serial_install - install tty 20262306a36Sopenharmony_ci * @driver: the driver (USB in our case) 20362306a36Sopenharmony_ci * @tty: the tty being created 20462306a36Sopenharmony_ci * 20562306a36Sopenharmony_ci * Initialise the termios structure for this tty. We use the default 20662306a36Sopenharmony_ci * USB serial settings but permit them to be overridden by 20762306a36Sopenharmony_ci * serial->type->init_termios on first open. 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * This is the first place a new tty gets used. Hence this is where we 21062306a36Sopenharmony_ci * acquire references to the usb_serial structure and the driver module, 21162306a36Sopenharmony_ci * where we store a pointer to the port. All these actions are reversed 21262306a36Sopenharmony_ci * in serial_cleanup(). 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_cistatic int serial_install(struct tty_driver *driver, struct tty_struct *tty) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci int idx = tty->index; 21762306a36Sopenharmony_ci struct usb_serial *serial; 21862306a36Sopenharmony_ci struct usb_serial_port *port; 21962306a36Sopenharmony_ci bool init_termios; 22062306a36Sopenharmony_ci int retval = -ENODEV; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci port = usb_serial_port_get_by_minor(idx); 22362306a36Sopenharmony_ci if (!port) 22462306a36Sopenharmony_ci return retval; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci serial = port->serial; 22762306a36Sopenharmony_ci if (!try_module_get(serial->type->driver.owner)) 22862306a36Sopenharmony_ci goto err_put_serial; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci init_termios = (driver->termios[idx] == NULL); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci retval = tty_standard_install(driver, tty); 23362306a36Sopenharmony_ci if (retval) 23462306a36Sopenharmony_ci goto err_put_module; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci mutex_unlock(&serial->disc_mutex); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* allow the driver to update the initial settings */ 23962306a36Sopenharmony_ci if (init_termios && serial->type->init_termios) 24062306a36Sopenharmony_ci serial->type->init_termios(tty); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci tty->driver_data = port; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return retval; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cierr_put_module: 24762306a36Sopenharmony_ci module_put(serial->type->driver.owner); 24862306a36Sopenharmony_cierr_put_serial: 24962306a36Sopenharmony_ci usb_serial_put(serial); 25062306a36Sopenharmony_ci mutex_unlock(&serial->disc_mutex); 25162306a36Sopenharmony_ci return retval; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int serial_port_activate(struct tty_port *tport, struct tty_struct *tty) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct usb_serial_port *port = 25762306a36Sopenharmony_ci container_of(tport, struct usb_serial_port, port); 25862306a36Sopenharmony_ci struct usb_serial *serial = port->serial; 25962306a36Sopenharmony_ci int retval; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci mutex_lock(&serial->disc_mutex); 26262306a36Sopenharmony_ci if (serial->disconnected) { 26362306a36Sopenharmony_ci retval = -ENODEV; 26462306a36Sopenharmony_ci goto out_unlock; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci retval = usb_autopm_get_interface(serial->interface); 26862306a36Sopenharmony_ci if (retval) 26962306a36Sopenharmony_ci goto out_unlock; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci retval = port->serial->type->open(tty, port); 27262306a36Sopenharmony_ci if (retval) 27362306a36Sopenharmony_ci usb_autopm_put_interface(serial->interface); 27462306a36Sopenharmony_ciout_unlock: 27562306a36Sopenharmony_ci mutex_unlock(&serial->disc_mutex); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (retval < 0) 27862306a36Sopenharmony_ci retval = usb_translate_errors(retval); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return retval; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int serial_open(struct tty_struct *tty, struct file *filp) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return tty_port_open(&port->port, tty, filp); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/** 29362306a36Sopenharmony_ci * serial_port_shutdown - shut down hardware 29462306a36Sopenharmony_ci * @tport: tty port to shut down 29562306a36Sopenharmony_ci * 29662306a36Sopenharmony_ci * Shut down a USB serial port. Serialized against activate by the 29762306a36Sopenharmony_ci * tport mutex and kept to matching open/close pairs 29862306a36Sopenharmony_ci * of calls by the tty-port initialized flag. 29962306a36Sopenharmony_ci * 30062306a36Sopenharmony_ci * Not called if tty is console. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_cistatic void serial_port_shutdown(struct tty_port *tport) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct usb_serial_port *port = 30562306a36Sopenharmony_ci container_of(tport, struct usb_serial_port, port); 30662306a36Sopenharmony_ci struct usb_serial_driver *drv = port->serial->type; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (drv->close) 30962306a36Sopenharmony_ci drv->close(port); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci usb_autopm_put_interface(port->serial->interface); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic void serial_hangup(struct tty_struct *tty) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci tty_port_hangup(&port->port); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void serial_close(struct tty_struct *tty, struct file *filp) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci tty_port_close(&port->port, tty, filp); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/** 33362306a36Sopenharmony_ci * serial_cleanup - free resources post close/hangup 33462306a36Sopenharmony_ci * @tty: tty to clean up 33562306a36Sopenharmony_ci * 33662306a36Sopenharmony_ci * Do the resource freeing and refcount dropping for the port. 33762306a36Sopenharmony_ci * Avoid freeing the console. 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci * Called asynchronously after the last tty kref is dropped. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_cistatic void serial_cleanup(struct tty_struct *tty) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 34462306a36Sopenharmony_ci struct usb_serial *serial; 34562306a36Sopenharmony_ci struct module *owner; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* The console is magical. Do not hang up the console hardware 35062306a36Sopenharmony_ci * or there will be tears. 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_ci if (port->port.console) 35362306a36Sopenharmony_ci return; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci tty->driver_data = NULL; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci serial = port->serial; 35862306a36Sopenharmony_ci owner = serial->type->driver.owner; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci usb_serial_put(serial); 36162306a36Sopenharmony_ci module_put(owner); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic ssize_t serial_write(struct tty_struct *tty, const u8 *buf, size_t count) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 36762306a36Sopenharmony_ci int retval = -ENODEV; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (port->serial->dev->state == USB_STATE_NOTATTACHED) 37062306a36Sopenharmony_ci goto exit; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - %zu byte(s)\n", __func__, count); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci retval = port->serial->type->write(tty, port, buf, count); 37562306a36Sopenharmony_ci if (retval < 0) 37662306a36Sopenharmony_ci retval = usb_translate_errors(retval); 37762306a36Sopenharmony_ciexit: 37862306a36Sopenharmony_ci return retval; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic unsigned int serial_write_room(struct tty_struct *tty) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci return port->serial->type->write_room(tty); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic unsigned int serial_chars_in_buffer(struct tty_struct *tty) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 39362306a36Sopenharmony_ci struct usb_serial *serial = port->serial; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (serial->disconnected) 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return serial->type->chars_in_buffer(tty); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void serial_wait_until_sent(struct tty_struct *tty, int timeout) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 40662306a36Sopenharmony_ci struct usb_serial *serial = port->serial; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (!port->serial->type->wait_until_sent) 41162306a36Sopenharmony_ci return; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci mutex_lock(&serial->disc_mutex); 41462306a36Sopenharmony_ci if (!serial->disconnected) 41562306a36Sopenharmony_ci port->serial->type->wait_until_sent(tty, timeout); 41662306a36Sopenharmony_ci mutex_unlock(&serial->disc_mutex); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic void serial_throttle(struct tty_struct *tty) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (port->serial->type->throttle) 42662306a36Sopenharmony_ci port->serial->type->throttle(tty); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic void serial_unthrottle(struct tty_struct *tty) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (port->serial->type->unthrottle) 43662306a36Sopenharmony_ci port->serial->type->unthrottle(tty); 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 44262306a36Sopenharmony_ci struct tty_port *tport = &port->port; 44362306a36Sopenharmony_ci unsigned int close_delay, closing_wait; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci mutex_lock(&tport->mutex); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci close_delay = jiffies_to_msecs(tport->close_delay) / 10; 44862306a36Sopenharmony_ci closing_wait = tport->closing_wait; 44962306a36Sopenharmony_ci if (closing_wait != ASYNC_CLOSING_WAIT_NONE) 45062306a36Sopenharmony_ci closing_wait = jiffies_to_msecs(closing_wait) / 10; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci ss->line = port->minor; 45362306a36Sopenharmony_ci ss->close_delay = close_delay; 45462306a36Sopenharmony_ci ss->closing_wait = closing_wait; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (port->serial->type->get_serial) 45762306a36Sopenharmony_ci port->serial->type->get_serial(tty, ss); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci mutex_unlock(&tport->mutex); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 46762306a36Sopenharmony_ci struct tty_port *tport = &port->port; 46862306a36Sopenharmony_ci unsigned int close_delay, closing_wait; 46962306a36Sopenharmony_ci int ret = 0; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci close_delay = msecs_to_jiffies(ss->close_delay * 10); 47262306a36Sopenharmony_ci closing_wait = ss->closing_wait; 47362306a36Sopenharmony_ci if (closing_wait != ASYNC_CLOSING_WAIT_NONE) 47462306a36Sopenharmony_ci closing_wait = msecs_to_jiffies(closing_wait * 10); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci mutex_lock(&tport->mutex); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) { 47962306a36Sopenharmony_ci if (close_delay != tport->close_delay || 48062306a36Sopenharmony_ci closing_wait != tport->closing_wait) { 48162306a36Sopenharmony_ci ret = -EPERM; 48262306a36Sopenharmony_ci goto out_unlock; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (port->serial->type->set_serial) { 48762306a36Sopenharmony_ci ret = port->serial->type->set_serial(tty, ss); 48862306a36Sopenharmony_ci if (ret) 48962306a36Sopenharmony_ci goto out_unlock; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci tport->close_delay = close_delay; 49362306a36Sopenharmony_ci tport->closing_wait = closing_wait; 49462306a36Sopenharmony_ciout_unlock: 49562306a36Sopenharmony_ci mutex_unlock(&tport->mutex); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return ret; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int serial_ioctl(struct tty_struct *tty, 50162306a36Sopenharmony_ci unsigned int cmd, unsigned long arg) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 50462306a36Sopenharmony_ci int retval = -ENOIOCTLCMD; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - cmd 0x%04x\n", __func__, cmd); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci switch (cmd) { 50962306a36Sopenharmony_ci case TIOCMIWAIT: 51062306a36Sopenharmony_ci if (port->serial->type->tiocmiwait) 51162306a36Sopenharmony_ci retval = port->serial->type->tiocmiwait(tty, arg); 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci default: 51462306a36Sopenharmony_ci if (port->serial->type->ioctl) 51562306a36Sopenharmony_ci retval = port->serial->type->ioctl(tty, cmd, arg); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return retval; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic void serial_set_termios(struct tty_struct *tty, 52262306a36Sopenharmony_ci const struct ktermios *old) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (port->serial->type->set_termios) 52962306a36Sopenharmony_ci port->serial->type->set_termios(tty, port, old); 53062306a36Sopenharmony_ci else 53162306a36Sopenharmony_ci tty_termios_copy_hw(&tty->termios, old); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int serial_break(struct tty_struct *tty, int break_state) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (port->serial->type->break_ctl) 54162306a36Sopenharmony_ci return port->serial->type->break_ctl(tty, break_state); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci return -ENOTTY; 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic int serial_proc_show(struct seq_file *m, void *v) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct usb_serial *serial; 54962306a36Sopenharmony_ci struct usb_serial_port *port; 55062306a36Sopenharmony_ci int i; 55162306a36Sopenharmony_ci char tmp[40]; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci seq_puts(m, "usbserinfo:1.0 driver:2.0\n"); 55462306a36Sopenharmony_ci for (i = 0; i < USB_SERIAL_TTY_MINORS; ++i) { 55562306a36Sopenharmony_ci port = usb_serial_port_get_by_minor(i); 55662306a36Sopenharmony_ci if (port == NULL) 55762306a36Sopenharmony_ci continue; 55862306a36Sopenharmony_ci serial = port->serial; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci seq_printf(m, "%d:", i); 56162306a36Sopenharmony_ci if (serial->type->driver.owner) 56262306a36Sopenharmony_ci seq_printf(m, " module:%s", 56362306a36Sopenharmony_ci module_name(serial->type->driver.owner)); 56462306a36Sopenharmony_ci seq_printf(m, " name:\"%s\"", 56562306a36Sopenharmony_ci serial->type->description); 56662306a36Sopenharmony_ci seq_printf(m, " vendor:%04x product:%04x", 56762306a36Sopenharmony_ci le16_to_cpu(serial->dev->descriptor.idVendor), 56862306a36Sopenharmony_ci le16_to_cpu(serial->dev->descriptor.idProduct)); 56962306a36Sopenharmony_ci seq_printf(m, " num_ports:%d", serial->num_ports); 57062306a36Sopenharmony_ci seq_printf(m, " port:%d", port->port_number); 57162306a36Sopenharmony_ci usb_make_path(serial->dev, tmp, sizeof(tmp)); 57262306a36Sopenharmony_ci seq_printf(m, " path:%s", tmp); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci seq_putc(m, '\n'); 57562306a36Sopenharmony_ci usb_serial_put(serial); 57662306a36Sopenharmony_ci mutex_unlock(&serial->disc_mutex); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci return 0; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic int serial_tiocmget(struct tty_struct *tty) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (port->serial->type->tiocmget) 58862306a36Sopenharmony_ci return port->serial->type->tiocmget(tty); 58962306a36Sopenharmony_ci return -ENOTTY; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic int serial_tiocmset(struct tty_struct *tty, 59362306a36Sopenharmony_ci unsigned int set, unsigned int clear) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (port->serial->type->tiocmset) 60062306a36Sopenharmony_ci return port->serial->type->tiocmset(tty, set, clear); 60162306a36Sopenharmony_ci return -ENOTTY; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int serial_get_icount(struct tty_struct *tty, 60562306a36Sopenharmony_ci struct serial_icounter_struct *icount) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci dev_dbg(&port->dev, "%s\n", __func__); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (port->serial->type->get_icount) 61262306a36Sopenharmony_ci return port->serial->type->get_icount(tty, icount); 61362306a36Sopenharmony_ci return -ENOTTY; 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci/* 61762306a36Sopenharmony_ci * We would be calling tty_wakeup here, but unfortunately some line 61862306a36Sopenharmony_ci * disciplines have an annoying habit of calling tty->write from 61962306a36Sopenharmony_ci * the write wakeup callback (e.g. n_hdlc.c). 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_civoid usb_serial_port_softint(struct usb_serial_port *port) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci schedule_work(&port->work); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_serial_port_softint); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic void usb_serial_port_work(struct work_struct *work) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct usb_serial_port *port = 63062306a36Sopenharmony_ci container_of(work, struct usb_serial_port, work); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci tty_port_tty_wakeup(&port->port); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void usb_serial_port_poison_urbs(struct usb_serial_port *port) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci int i; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) 64062306a36Sopenharmony_ci usb_poison_urb(port->read_urbs[i]); 64162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) 64262306a36Sopenharmony_ci usb_poison_urb(port->write_urbs[i]); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci usb_poison_urb(port->interrupt_in_urb); 64562306a36Sopenharmony_ci usb_poison_urb(port->interrupt_out_urb); 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic void usb_serial_port_unpoison_urbs(struct usb_serial_port *port) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci int i; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) 65362306a36Sopenharmony_ci usb_unpoison_urb(port->read_urbs[i]); 65462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) 65562306a36Sopenharmony_ci usb_unpoison_urb(port->write_urbs[i]); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci usb_unpoison_urb(port->interrupt_in_urb); 65862306a36Sopenharmony_ci usb_unpoison_urb(port->interrupt_out_urb); 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic void usb_serial_port_release(struct device *dev) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct usb_serial_port *port = to_usb_serial_port(dev); 66462306a36Sopenharmony_ci int i; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci usb_free_urb(port->interrupt_in_urb); 66962306a36Sopenharmony_ci usb_free_urb(port->interrupt_out_urb); 67062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { 67162306a36Sopenharmony_ci usb_free_urb(port->read_urbs[i]); 67262306a36Sopenharmony_ci kfree(port->bulk_in_buffers[i]); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { 67562306a36Sopenharmony_ci usb_free_urb(port->write_urbs[i]); 67662306a36Sopenharmony_ci kfree(port->bulk_out_buffers[i]); 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci kfifo_free(&port->write_fifo); 67962306a36Sopenharmony_ci kfree(port->interrupt_in_buffer); 68062306a36Sopenharmony_ci kfree(port->interrupt_out_buffer); 68162306a36Sopenharmony_ci tty_port_destroy(&port->port); 68262306a36Sopenharmony_ci kfree(port); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic struct usb_serial *create_serial(struct usb_device *dev, 68662306a36Sopenharmony_ci struct usb_interface *interface, 68762306a36Sopenharmony_ci struct usb_serial_driver *driver) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct usb_serial *serial; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci serial = kzalloc(sizeof(*serial), GFP_KERNEL); 69262306a36Sopenharmony_ci if (!serial) 69362306a36Sopenharmony_ci return NULL; 69462306a36Sopenharmony_ci serial->dev = usb_get_dev(dev); 69562306a36Sopenharmony_ci serial->type = driver; 69662306a36Sopenharmony_ci serial->interface = usb_get_intf(interface); 69762306a36Sopenharmony_ci kref_init(&serial->kref); 69862306a36Sopenharmony_ci mutex_init(&serial->disc_mutex); 69962306a36Sopenharmony_ci serial->minors_reserved = 0; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return serial; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic const struct usb_device_id *match_dynamic_id(struct usb_interface *intf, 70562306a36Sopenharmony_ci struct usb_serial_driver *drv) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct usb_dynid *dynid; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci spin_lock(&drv->dynids.lock); 71062306a36Sopenharmony_ci list_for_each_entry(dynid, &drv->dynids.list, node) { 71162306a36Sopenharmony_ci if (usb_match_one_id(intf, &dynid->id)) { 71262306a36Sopenharmony_ci spin_unlock(&drv->dynids.lock); 71362306a36Sopenharmony_ci return &dynid->id; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci spin_unlock(&drv->dynids.lock); 71762306a36Sopenharmony_ci return NULL; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, 72162306a36Sopenharmony_ci struct usb_interface *intf) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci const struct usb_device_id *id; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci id = usb_match_id(intf, drv->id_table); 72662306a36Sopenharmony_ci if (id) { 72762306a36Sopenharmony_ci dev_dbg(&intf->dev, "static descriptor matches\n"); 72862306a36Sopenharmony_ci goto exit; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci id = match_dynamic_id(intf, drv); 73162306a36Sopenharmony_ci if (id) 73262306a36Sopenharmony_ci dev_dbg(&intf->dev, "dynamic descriptor matches\n"); 73362306a36Sopenharmony_ciexit: 73462306a36Sopenharmony_ci return id; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci/* Caller must hold table_lock */ 73862306a36Sopenharmony_cistatic struct usb_serial_driver *search_serial_device( 73962306a36Sopenharmony_ci struct usb_interface *iface) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci const struct usb_device_id *id = NULL; 74262306a36Sopenharmony_ci struct usb_serial_driver *drv; 74362306a36Sopenharmony_ci struct usb_driver *driver = to_usb_driver(iface->dev.driver); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* Check if the usb id matches a known device */ 74662306a36Sopenharmony_ci list_for_each_entry(drv, &usb_serial_driver_list, driver_list) { 74762306a36Sopenharmony_ci if (drv->usb_driver == driver) 74862306a36Sopenharmony_ci id = get_iface_id(drv, iface); 74962306a36Sopenharmony_ci if (id) 75062306a36Sopenharmony_ci return drv; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci return NULL; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic bool serial_port_carrier_raised(struct tty_port *port) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); 75962306a36Sopenharmony_ci struct usb_serial_driver *drv = p->serial->type; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (drv->carrier_raised) 76262306a36Sopenharmony_ci return drv->carrier_raised(p); 76362306a36Sopenharmony_ci /* No carrier control - don't block */ 76462306a36Sopenharmony_ci return true; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic void serial_port_dtr_rts(struct tty_port *port, bool on) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); 77062306a36Sopenharmony_ci struct usb_serial_driver *drv = p->serial->type; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (drv->dtr_rts) 77362306a36Sopenharmony_ci drv->dtr_rts(p, on); 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic ssize_t port_number_show(struct device *dev, 77762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct usb_serial_port *port = to_usb_serial_port(dev); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return sprintf(buf, "%u\n", port->port_number); 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(port_number); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic struct attribute *usb_serial_port_attrs[] = { 78662306a36Sopenharmony_ci &dev_attr_port_number.attr, 78762306a36Sopenharmony_ci NULL 78862306a36Sopenharmony_ci}; 78962306a36Sopenharmony_ciATTRIBUTE_GROUPS(usb_serial_port); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic const struct tty_port_operations serial_port_ops = { 79262306a36Sopenharmony_ci .carrier_raised = serial_port_carrier_raised, 79362306a36Sopenharmony_ci .dtr_rts = serial_port_dtr_rts, 79462306a36Sopenharmony_ci .activate = serial_port_activate, 79562306a36Sopenharmony_ci .shutdown = serial_port_shutdown, 79662306a36Sopenharmony_ci}; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic void store_endpoint(struct usb_serial *serial, 79962306a36Sopenharmony_ci struct usb_serial_endpoints *epds, 80062306a36Sopenharmony_ci struct usb_endpoint_descriptor *epd) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct device *dev = &serial->interface->dev; 80362306a36Sopenharmony_ci u8 addr = epd->bEndpointAddress; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (usb_endpoint_is_bulk_in(epd)) { 80662306a36Sopenharmony_ci if (epds->num_bulk_in == ARRAY_SIZE(epds->bulk_in)) 80762306a36Sopenharmony_ci return; 80862306a36Sopenharmony_ci dev_dbg(dev, "found bulk in endpoint %02x\n", addr); 80962306a36Sopenharmony_ci epds->bulk_in[epds->num_bulk_in++] = epd; 81062306a36Sopenharmony_ci } else if (usb_endpoint_is_bulk_out(epd)) { 81162306a36Sopenharmony_ci if (epds->num_bulk_out == ARRAY_SIZE(epds->bulk_out)) 81262306a36Sopenharmony_ci return; 81362306a36Sopenharmony_ci dev_dbg(dev, "found bulk out endpoint %02x\n", addr); 81462306a36Sopenharmony_ci epds->bulk_out[epds->num_bulk_out++] = epd; 81562306a36Sopenharmony_ci } else if (usb_endpoint_is_int_in(epd)) { 81662306a36Sopenharmony_ci if (epds->num_interrupt_in == ARRAY_SIZE(epds->interrupt_in)) 81762306a36Sopenharmony_ci return; 81862306a36Sopenharmony_ci dev_dbg(dev, "found interrupt in endpoint %02x\n", addr); 81962306a36Sopenharmony_ci epds->interrupt_in[epds->num_interrupt_in++] = epd; 82062306a36Sopenharmony_ci } else if (usb_endpoint_is_int_out(epd)) { 82162306a36Sopenharmony_ci if (epds->num_interrupt_out == ARRAY_SIZE(epds->interrupt_out)) 82262306a36Sopenharmony_ci return; 82362306a36Sopenharmony_ci dev_dbg(dev, "found interrupt out endpoint %02x\n", addr); 82462306a36Sopenharmony_ci epds->interrupt_out[epds->num_interrupt_out++] = epd; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic void find_endpoints(struct usb_serial *serial, 82962306a36Sopenharmony_ci struct usb_serial_endpoints *epds, 83062306a36Sopenharmony_ci struct usb_interface *intf) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct usb_host_interface *iface_desc; 83362306a36Sopenharmony_ci struct usb_endpoint_descriptor *epd; 83462306a36Sopenharmony_ci unsigned int i; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci iface_desc = intf->cur_altsetting; 83762306a36Sopenharmony_ci for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 83862306a36Sopenharmony_ci epd = &iface_desc->endpoint[i].desc; 83962306a36Sopenharmony_ci store_endpoint(serial, epds, epd); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic int setup_port_bulk_in(struct usb_serial_port *port, 84462306a36Sopenharmony_ci struct usb_endpoint_descriptor *epd) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci struct usb_serial_driver *type = port->serial->type; 84762306a36Sopenharmony_ci struct usb_device *udev = port->serial->dev; 84862306a36Sopenharmony_ci int buffer_size; 84962306a36Sopenharmony_ci int i; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci buffer_size = max_t(int, type->bulk_in_size, usb_endpoint_maxp(epd)); 85262306a36Sopenharmony_ci port->bulk_in_size = buffer_size; 85362306a36Sopenharmony_ci port->bulk_in_endpointAddress = epd->bEndpointAddress; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { 85662306a36Sopenharmony_ci set_bit(i, &port->read_urbs_free); 85762306a36Sopenharmony_ci port->read_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); 85862306a36Sopenharmony_ci if (!port->read_urbs[i]) 85962306a36Sopenharmony_ci return -ENOMEM; 86062306a36Sopenharmony_ci port->bulk_in_buffers[i] = kmalloc(buffer_size, GFP_KERNEL); 86162306a36Sopenharmony_ci if (!port->bulk_in_buffers[i]) 86262306a36Sopenharmony_ci return -ENOMEM; 86362306a36Sopenharmony_ci usb_fill_bulk_urb(port->read_urbs[i], udev, 86462306a36Sopenharmony_ci usb_rcvbulkpipe(udev, epd->bEndpointAddress), 86562306a36Sopenharmony_ci port->bulk_in_buffers[i], buffer_size, 86662306a36Sopenharmony_ci type->read_bulk_callback, port); 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci port->read_urb = port->read_urbs[0]; 87062306a36Sopenharmony_ci port->bulk_in_buffer = port->bulk_in_buffers[0]; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return 0; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic int setup_port_bulk_out(struct usb_serial_port *port, 87662306a36Sopenharmony_ci struct usb_endpoint_descriptor *epd) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci struct usb_serial_driver *type = port->serial->type; 87962306a36Sopenharmony_ci struct usb_device *udev = port->serial->dev; 88062306a36Sopenharmony_ci int buffer_size; 88162306a36Sopenharmony_ci int i; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL)) 88462306a36Sopenharmony_ci return -ENOMEM; 88562306a36Sopenharmony_ci if (type->bulk_out_size) 88662306a36Sopenharmony_ci buffer_size = type->bulk_out_size; 88762306a36Sopenharmony_ci else 88862306a36Sopenharmony_ci buffer_size = usb_endpoint_maxp(epd); 88962306a36Sopenharmony_ci port->bulk_out_size = buffer_size; 89062306a36Sopenharmony_ci port->bulk_out_endpointAddress = epd->bEndpointAddress; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { 89362306a36Sopenharmony_ci set_bit(i, &port->write_urbs_free); 89462306a36Sopenharmony_ci port->write_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); 89562306a36Sopenharmony_ci if (!port->write_urbs[i]) 89662306a36Sopenharmony_ci return -ENOMEM; 89762306a36Sopenharmony_ci port->bulk_out_buffers[i] = kmalloc(buffer_size, GFP_KERNEL); 89862306a36Sopenharmony_ci if (!port->bulk_out_buffers[i]) 89962306a36Sopenharmony_ci return -ENOMEM; 90062306a36Sopenharmony_ci usb_fill_bulk_urb(port->write_urbs[i], udev, 90162306a36Sopenharmony_ci usb_sndbulkpipe(udev, epd->bEndpointAddress), 90262306a36Sopenharmony_ci port->bulk_out_buffers[i], buffer_size, 90362306a36Sopenharmony_ci type->write_bulk_callback, port); 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci port->write_urb = port->write_urbs[0]; 90762306a36Sopenharmony_ci port->bulk_out_buffer = port->bulk_out_buffers[0]; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci return 0; 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cistatic int setup_port_interrupt_in(struct usb_serial_port *port, 91362306a36Sopenharmony_ci struct usb_endpoint_descriptor *epd) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci struct usb_serial_driver *type = port->serial->type; 91662306a36Sopenharmony_ci struct usb_device *udev = port->serial->dev; 91762306a36Sopenharmony_ci int buffer_size; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); 92062306a36Sopenharmony_ci if (!port->interrupt_in_urb) 92162306a36Sopenharmony_ci return -ENOMEM; 92262306a36Sopenharmony_ci buffer_size = usb_endpoint_maxp(epd); 92362306a36Sopenharmony_ci port->interrupt_in_endpointAddress = epd->bEndpointAddress; 92462306a36Sopenharmony_ci port->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); 92562306a36Sopenharmony_ci if (!port->interrupt_in_buffer) 92662306a36Sopenharmony_ci return -ENOMEM; 92762306a36Sopenharmony_ci usb_fill_int_urb(port->interrupt_in_urb, udev, 92862306a36Sopenharmony_ci usb_rcvintpipe(udev, epd->bEndpointAddress), 92962306a36Sopenharmony_ci port->interrupt_in_buffer, buffer_size, 93062306a36Sopenharmony_ci type->read_int_callback, port, 93162306a36Sopenharmony_ci epd->bInterval); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci return 0; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic int setup_port_interrupt_out(struct usb_serial_port *port, 93762306a36Sopenharmony_ci struct usb_endpoint_descriptor *epd) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci struct usb_serial_driver *type = port->serial->type; 94062306a36Sopenharmony_ci struct usb_device *udev = port->serial->dev; 94162306a36Sopenharmony_ci int buffer_size; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); 94462306a36Sopenharmony_ci if (!port->interrupt_out_urb) 94562306a36Sopenharmony_ci return -ENOMEM; 94662306a36Sopenharmony_ci buffer_size = usb_endpoint_maxp(epd); 94762306a36Sopenharmony_ci port->interrupt_out_size = buffer_size; 94862306a36Sopenharmony_ci port->interrupt_out_endpointAddress = epd->bEndpointAddress; 94962306a36Sopenharmony_ci port->interrupt_out_buffer = kmalloc(buffer_size, GFP_KERNEL); 95062306a36Sopenharmony_ci if (!port->interrupt_out_buffer) 95162306a36Sopenharmony_ci return -ENOMEM; 95262306a36Sopenharmony_ci usb_fill_int_urb(port->interrupt_out_urb, udev, 95362306a36Sopenharmony_ci usb_sndintpipe(udev, epd->bEndpointAddress), 95462306a36Sopenharmony_ci port->interrupt_out_buffer, buffer_size, 95562306a36Sopenharmony_ci type->write_int_callback, port, 95662306a36Sopenharmony_ci epd->bInterval); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return 0; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic int usb_serial_probe(struct usb_interface *interface, 96262306a36Sopenharmony_ci const struct usb_device_id *id) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci struct device *ddev = &interface->dev; 96562306a36Sopenharmony_ci struct usb_device *dev = interface_to_usbdev(interface); 96662306a36Sopenharmony_ci struct usb_serial *serial = NULL; 96762306a36Sopenharmony_ci struct usb_serial_port *port; 96862306a36Sopenharmony_ci struct usb_serial_endpoints *epds; 96962306a36Sopenharmony_ci struct usb_serial_driver *type = NULL; 97062306a36Sopenharmony_ci int retval; 97162306a36Sopenharmony_ci int i; 97262306a36Sopenharmony_ci int num_ports = 0; 97362306a36Sopenharmony_ci unsigned char max_endpoints; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci mutex_lock(&table_lock); 97662306a36Sopenharmony_ci type = search_serial_device(interface); 97762306a36Sopenharmony_ci if (!type) { 97862306a36Sopenharmony_ci mutex_unlock(&table_lock); 97962306a36Sopenharmony_ci dev_dbg(ddev, "none matched\n"); 98062306a36Sopenharmony_ci return -ENODEV; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (!try_module_get(type->driver.owner)) { 98462306a36Sopenharmony_ci mutex_unlock(&table_lock); 98562306a36Sopenharmony_ci dev_err(ddev, "module get failed, exiting\n"); 98662306a36Sopenharmony_ci return -EIO; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci mutex_unlock(&table_lock); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci serial = create_serial(dev, interface, type); 99162306a36Sopenharmony_ci if (!serial) { 99262306a36Sopenharmony_ci retval = -ENOMEM; 99362306a36Sopenharmony_ci goto err_put_module; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* if this device type has a probe function, call it */ 99762306a36Sopenharmony_ci if (type->probe) { 99862306a36Sopenharmony_ci const struct usb_device_id *id; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci id = get_iface_id(type, interface); 100162306a36Sopenharmony_ci retval = type->probe(serial, id); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (retval) { 100462306a36Sopenharmony_ci dev_dbg(ddev, "sub driver rejected device\n"); 100562306a36Sopenharmony_ci goto err_release_sibling; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* descriptor matches, let's find the endpoints needed */ 101062306a36Sopenharmony_ci epds = kzalloc(sizeof(*epds), GFP_KERNEL); 101162306a36Sopenharmony_ci if (!epds) { 101262306a36Sopenharmony_ci retval = -ENOMEM; 101362306a36Sopenharmony_ci goto err_release_sibling; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci find_endpoints(serial, epds, interface); 101762306a36Sopenharmony_ci if (serial->sibling) 101862306a36Sopenharmony_ci find_endpoints(serial, epds, serial->sibling); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci if (epds->num_bulk_in < type->num_bulk_in || 102162306a36Sopenharmony_ci epds->num_bulk_out < type->num_bulk_out || 102262306a36Sopenharmony_ci epds->num_interrupt_in < type->num_interrupt_in || 102362306a36Sopenharmony_ci epds->num_interrupt_out < type->num_interrupt_out) { 102462306a36Sopenharmony_ci dev_err(ddev, "required endpoints missing\n"); 102562306a36Sopenharmony_ci retval = -ENODEV; 102662306a36Sopenharmony_ci goto err_free_epds; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci if (type->calc_num_ports) { 103062306a36Sopenharmony_ci retval = type->calc_num_ports(serial, epds); 103162306a36Sopenharmony_ci if (retval < 0) 103262306a36Sopenharmony_ci goto err_free_epds; 103362306a36Sopenharmony_ci num_ports = retval; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci if (!num_ports) 103762306a36Sopenharmony_ci num_ports = type->num_ports; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci if (num_ports > MAX_NUM_PORTS) { 104062306a36Sopenharmony_ci dev_warn(ddev, "too many ports requested: %d\n", num_ports); 104162306a36Sopenharmony_ci num_ports = MAX_NUM_PORTS; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci serial->num_ports = (unsigned char)num_ports; 104562306a36Sopenharmony_ci serial->num_bulk_in = epds->num_bulk_in; 104662306a36Sopenharmony_ci serial->num_bulk_out = epds->num_bulk_out; 104762306a36Sopenharmony_ci serial->num_interrupt_in = epds->num_interrupt_in; 104862306a36Sopenharmony_ci serial->num_interrupt_out = epds->num_interrupt_out; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci /* found all that we need */ 105162306a36Sopenharmony_ci dev_info(ddev, "%s converter detected\n", type->description); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* create our ports, we need as many as the max endpoints */ 105462306a36Sopenharmony_ci /* we don't use num_ports here because some devices have more 105562306a36Sopenharmony_ci endpoint pairs than ports */ 105662306a36Sopenharmony_ci max_endpoints = max(epds->num_bulk_in, epds->num_bulk_out); 105762306a36Sopenharmony_ci max_endpoints = max(max_endpoints, epds->num_interrupt_in); 105862306a36Sopenharmony_ci max_endpoints = max(max_endpoints, epds->num_interrupt_out); 105962306a36Sopenharmony_ci max_endpoints = max(max_endpoints, serial->num_ports); 106062306a36Sopenharmony_ci serial->num_port_pointers = max_endpoints; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci dev_dbg(ddev, "setting up %d port structure(s)\n", max_endpoints); 106362306a36Sopenharmony_ci for (i = 0; i < max_endpoints; ++i) { 106462306a36Sopenharmony_ci port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); 106562306a36Sopenharmony_ci if (!port) { 106662306a36Sopenharmony_ci retval = -ENOMEM; 106762306a36Sopenharmony_ci goto err_free_epds; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci tty_port_init(&port->port); 107062306a36Sopenharmony_ci port->port.ops = &serial_port_ops; 107162306a36Sopenharmony_ci port->serial = serial; 107262306a36Sopenharmony_ci spin_lock_init(&port->lock); 107362306a36Sopenharmony_ci /* Keep this for private driver use for the moment but 107462306a36Sopenharmony_ci should probably go away */ 107562306a36Sopenharmony_ci INIT_WORK(&port->work, usb_serial_port_work); 107662306a36Sopenharmony_ci serial->port[i] = port; 107762306a36Sopenharmony_ci port->dev.parent = &interface->dev; 107862306a36Sopenharmony_ci port->dev.driver = NULL; 107962306a36Sopenharmony_ci port->dev.bus = &usb_serial_bus_type; 108062306a36Sopenharmony_ci port->dev.release = &usb_serial_port_release; 108162306a36Sopenharmony_ci port->dev.groups = usb_serial_port_groups; 108262306a36Sopenharmony_ci device_initialize(&port->dev); 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* set up the endpoint information */ 108662306a36Sopenharmony_ci for (i = 0; i < epds->num_bulk_in; ++i) { 108762306a36Sopenharmony_ci retval = setup_port_bulk_in(serial->port[i], epds->bulk_in[i]); 108862306a36Sopenharmony_ci if (retval) 108962306a36Sopenharmony_ci goto err_free_epds; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci for (i = 0; i < epds->num_bulk_out; ++i) { 109362306a36Sopenharmony_ci retval = setup_port_bulk_out(serial->port[i], 109462306a36Sopenharmony_ci epds->bulk_out[i]); 109562306a36Sopenharmony_ci if (retval) 109662306a36Sopenharmony_ci goto err_free_epds; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (serial->type->read_int_callback) { 110062306a36Sopenharmony_ci for (i = 0; i < epds->num_interrupt_in; ++i) { 110162306a36Sopenharmony_ci retval = setup_port_interrupt_in(serial->port[i], 110262306a36Sopenharmony_ci epds->interrupt_in[i]); 110362306a36Sopenharmony_ci if (retval) 110462306a36Sopenharmony_ci goto err_free_epds; 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci } else if (epds->num_interrupt_in) { 110762306a36Sopenharmony_ci dev_dbg(ddev, "The device claims to support interrupt in transfers, but read_int_callback is not defined\n"); 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (serial->type->write_int_callback) { 111162306a36Sopenharmony_ci for (i = 0; i < epds->num_interrupt_out; ++i) { 111262306a36Sopenharmony_ci retval = setup_port_interrupt_out(serial->port[i], 111362306a36Sopenharmony_ci epds->interrupt_out[i]); 111462306a36Sopenharmony_ci if (retval) 111562306a36Sopenharmony_ci goto err_free_epds; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci } else if (epds->num_interrupt_out) { 111862306a36Sopenharmony_ci dev_dbg(ddev, "The device claims to support interrupt out transfers, but write_int_callback is not defined\n"); 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci usb_set_intfdata(interface, serial); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* if this device type has an attach function, call it */ 112462306a36Sopenharmony_ci if (type->attach) { 112562306a36Sopenharmony_ci retval = type->attach(serial); 112662306a36Sopenharmony_ci if (retval < 0) 112762306a36Sopenharmony_ci goto err_free_epds; 112862306a36Sopenharmony_ci serial->attached = 1; 112962306a36Sopenharmony_ci if (retval > 0) { 113062306a36Sopenharmony_ci /* quietly accept this device, but don't bind to a 113162306a36Sopenharmony_ci serial port as it's about to disappear */ 113262306a36Sopenharmony_ci serial->num_ports = 0; 113362306a36Sopenharmony_ci goto exit; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci } else { 113662306a36Sopenharmony_ci serial->attached = 1; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci retval = allocate_minors(serial, num_ports); 114062306a36Sopenharmony_ci if (retval) { 114162306a36Sopenharmony_ci dev_err(ddev, "No more free serial minor numbers\n"); 114262306a36Sopenharmony_ci goto err_free_epds; 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci /* register all of the individual ports with the driver core */ 114662306a36Sopenharmony_ci for (i = 0; i < num_ports; ++i) { 114762306a36Sopenharmony_ci port = serial->port[i]; 114862306a36Sopenharmony_ci dev_set_name(&port->dev, "ttyUSB%d", port->minor); 114962306a36Sopenharmony_ci dev_dbg(ddev, "registering %s\n", dev_name(&port->dev)); 115062306a36Sopenharmony_ci device_enable_async_suspend(&port->dev); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci retval = device_add(&port->dev); 115362306a36Sopenharmony_ci if (retval) 115462306a36Sopenharmony_ci dev_err(ddev, "Error registering port device, continuing\n"); 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if (num_ports > 0) 115862306a36Sopenharmony_ci usb_serial_console_init(serial->port[0]->minor); 115962306a36Sopenharmony_ciexit: 116062306a36Sopenharmony_ci kfree(epds); 116162306a36Sopenharmony_ci module_put(type->driver.owner); 116262306a36Sopenharmony_ci return 0; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_cierr_free_epds: 116562306a36Sopenharmony_ci kfree(epds); 116662306a36Sopenharmony_cierr_release_sibling: 116762306a36Sopenharmony_ci release_sibling(serial, interface); 116862306a36Sopenharmony_ci usb_serial_put(serial); 116962306a36Sopenharmony_cierr_put_module: 117062306a36Sopenharmony_ci module_put(type->driver.owner); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci return retval; 117362306a36Sopenharmony_ci} 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_cistatic void usb_serial_disconnect(struct usb_interface *interface) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci int i; 117862306a36Sopenharmony_ci struct usb_serial *serial = usb_get_intfdata(interface); 117962306a36Sopenharmony_ci struct device *dev = &interface->dev; 118062306a36Sopenharmony_ci struct usb_serial_port *port; 118162306a36Sopenharmony_ci struct tty_struct *tty; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci /* sibling interface is cleaning up */ 118462306a36Sopenharmony_ci if (!serial) 118562306a36Sopenharmony_ci return; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci usb_serial_console_disconnect(serial); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci mutex_lock(&serial->disc_mutex); 119062306a36Sopenharmony_ci /* must set a flag, to signal subdrivers */ 119162306a36Sopenharmony_ci serial->disconnected = 1; 119262306a36Sopenharmony_ci mutex_unlock(&serial->disc_mutex); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci for (i = 0; i < serial->num_ports; ++i) { 119562306a36Sopenharmony_ci port = serial->port[i]; 119662306a36Sopenharmony_ci tty = tty_port_tty_get(&port->port); 119762306a36Sopenharmony_ci if (tty) { 119862306a36Sopenharmony_ci tty_vhangup(tty); 119962306a36Sopenharmony_ci tty_kref_put(tty); 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci usb_serial_port_poison_urbs(port); 120262306a36Sopenharmony_ci wake_up_interruptible(&port->port.delta_msr_wait); 120362306a36Sopenharmony_ci cancel_work_sync(&port->work); 120462306a36Sopenharmony_ci if (device_is_registered(&port->dev)) 120562306a36Sopenharmony_ci device_del(&port->dev); 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci if (serial->type->disconnect) 120862306a36Sopenharmony_ci serial->type->disconnect(serial); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci release_sibling(serial, interface); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci /* let the last holder of this object cause it to be cleaned up */ 121362306a36Sopenharmony_ci usb_serial_put(serial); 121462306a36Sopenharmony_ci dev_info(dev, "device disconnected\n"); 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ciint usb_serial_suspend(struct usb_interface *intf, pm_message_t message) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci struct usb_serial *serial = usb_get_intfdata(intf); 122062306a36Sopenharmony_ci int i, r; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci /* suspend when called for first sibling interface */ 122362306a36Sopenharmony_ci if (serial->suspend_count++) 122462306a36Sopenharmony_ci return 0; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci /* 122762306a36Sopenharmony_ci * serial->type->suspend() MUST return 0 in system sleep context, 122862306a36Sopenharmony_ci * otherwise, the resume callback has to recover device from 122962306a36Sopenharmony_ci * previous suspend failure. 123062306a36Sopenharmony_ci */ 123162306a36Sopenharmony_ci if (serial->type->suspend) { 123262306a36Sopenharmony_ci r = serial->type->suspend(serial, message); 123362306a36Sopenharmony_ci if (r < 0) { 123462306a36Sopenharmony_ci serial->suspend_count--; 123562306a36Sopenharmony_ci return r; 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci for (i = 0; i < serial->num_ports; ++i) 124062306a36Sopenharmony_ci usb_serial_port_poison_urbs(serial->port[i]); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci return 0; 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ciEXPORT_SYMBOL(usb_serial_suspend); 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_cistatic void usb_serial_unpoison_port_urbs(struct usb_serial *serial) 124762306a36Sopenharmony_ci{ 124862306a36Sopenharmony_ci int i; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci for (i = 0; i < serial->num_ports; ++i) 125162306a36Sopenharmony_ci usb_serial_port_unpoison_urbs(serial->port[i]); 125262306a36Sopenharmony_ci} 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ciint usb_serial_resume(struct usb_interface *intf) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci struct usb_serial *serial = usb_get_intfdata(intf); 125762306a36Sopenharmony_ci int rv; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* resume when called for last sibling interface */ 126062306a36Sopenharmony_ci if (--serial->suspend_count) 126162306a36Sopenharmony_ci return 0; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci usb_serial_unpoison_port_urbs(serial); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci if (serial->type->resume) 126662306a36Sopenharmony_ci rv = serial->type->resume(serial); 126762306a36Sopenharmony_ci else 126862306a36Sopenharmony_ci rv = usb_serial_generic_resume(serial); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci return rv; 127162306a36Sopenharmony_ci} 127262306a36Sopenharmony_ciEXPORT_SYMBOL(usb_serial_resume); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_cistatic int usb_serial_reset_resume(struct usb_interface *intf) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci struct usb_serial *serial = usb_get_intfdata(intf); 127762306a36Sopenharmony_ci int rv; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci /* resume when called for last sibling interface */ 128062306a36Sopenharmony_ci if (--serial->suspend_count) 128162306a36Sopenharmony_ci return 0; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci usb_serial_unpoison_port_urbs(serial); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci if (serial->type->reset_resume) { 128662306a36Sopenharmony_ci rv = serial->type->reset_resume(serial); 128762306a36Sopenharmony_ci } else { 128862306a36Sopenharmony_ci rv = -EOPNOTSUPP; 128962306a36Sopenharmony_ci intf->needs_binding = 1; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci return rv; 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_cistatic const struct tty_operations serial_ops = { 129662306a36Sopenharmony_ci .open = serial_open, 129762306a36Sopenharmony_ci .close = serial_close, 129862306a36Sopenharmony_ci .write = serial_write, 129962306a36Sopenharmony_ci .hangup = serial_hangup, 130062306a36Sopenharmony_ci .write_room = serial_write_room, 130162306a36Sopenharmony_ci .ioctl = serial_ioctl, 130262306a36Sopenharmony_ci .set_termios = serial_set_termios, 130362306a36Sopenharmony_ci .throttle = serial_throttle, 130462306a36Sopenharmony_ci .unthrottle = serial_unthrottle, 130562306a36Sopenharmony_ci .break_ctl = serial_break, 130662306a36Sopenharmony_ci .chars_in_buffer = serial_chars_in_buffer, 130762306a36Sopenharmony_ci .wait_until_sent = serial_wait_until_sent, 130862306a36Sopenharmony_ci .tiocmget = serial_tiocmget, 130962306a36Sopenharmony_ci .tiocmset = serial_tiocmset, 131062306a36Sopenharmony_ci .get_icount = serial_get_icount, 131162306a36Sopenharmony_ci .set_serial = serial_set_serial, 131262306a36Sopenharmony_ci .get_serial = serial_get_serial, 131362306a36Sopenharmony_ci .cleanup = serial_cleanup, 131462306a36Sopenharmony_ci .install = serial_install, 131562306a36Sopenharmony_ci .proc_show = serial_proc_show, 131662306a36Sopenharmony_ci}; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_cistruct tty_driver *usb_serial_tty_driver; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_cistatic int __init usb_serial_init(void) 132262306a36Sopenharmony_ci{ 132362306a36Sopenharmony_ci int result; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci usb_serial_tty_driver = tty_alloc_driver(USB_SERIAL_TTY_MINORS, 132662306a36Sopenharmony_ci TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); 132762306a36Sopenharmony_ci if (IS_ERR(usb_serial_tty_driver)) 132862306a36Sopenharmony_ci return PTR_ERR(usb_serial_tty_driver); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci /* Initialize our global data */ 133162306a36Sopenharmony_ci result = bus_register(&usb_serial_bus_type); 133262306a36Sopenharmony_ci if (result) { 133362306a36Sopenharmony_ci pr_err("%s - registering bus driver failed\n", __func__); 133462306a36Sopenharmony_ci goto err_put_driver; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci usb_serial_tty_driver->driver_name = "usbserial"; 133862306a36Sopenharmony_ci usb_serial_tty_driver->name = "ttyUSB"; 133962306a36Sopenharmony_ci usb_serial_tty_driver->major = USB_SERIAL_TTY_MAJOR; 134062306a36Sopenharmony_ci usb_serial_tty_driver->minor_start = 0; 134162306a36Sopenharmony_ci usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; 134262306a36Sopenharmony_ci usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL; 134362306a36Sopenharmony_ci usb_serial_tty_driver->init_termios = tty_std_termios; 134462306a36Sopenharmony_ci usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD 134562306a36Sopenharmony_ci | HUPCL | CLOCAL; 134662306a36Sopenharmony_ci usb_serial_tty_driver->init_termios.c_ispeed = 9600; 134762306a36Sopenharmony_ci usb_serial_tty_driver->init_termios.c_ospeed = 9600; 134862306a36Sopenharmony_ci tty_set_operations(usb_serial_tty_driver, &serial_ops); 134962306a36Sopenharmony_ci result = tty_register_driver(usb_serial_tty_driver); 135062306a36Sopenharmony_ci if (result) { 135162306a36Sopenharmony_ci pr_err("%s - tty_register_driver failed\n", __func__); 135262306a36Sopenharmony_ci goto err_unregister_bus; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* register the generic driver, if we should */ 135662306a36Sopenharmony_ci result = usb_serial_generic_register(); 135762306a36Sopenharmony_ci if (result < 0) { 135862306a36Sopenharmony_ci pr_err("%s - registering generic driver failed\n", __func__); 135962306a36Sopenharmony_ci goto err_unregister_driver; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci return result; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_cierr_unregister_driver: 136562306a36Sopenharmony_ci tty_unregister_driver(usb_serial_tty_driver); 136662306a36Sopenharmony_cierr_unregister_bus: 136762306a36Sopenharmony_ci bus_unregister(&usb_serial_bus_type); 136862306a36Sopenharmony_cierr_put_driver: 136962306a36Sopenharmony_ci pr_err("%s - returning with error %d\n", __func__, result); 137062306a36Sopenharmony_ci tty_driver_kref_put(usb_serial_tty_driver); 137162306a36Sopenharmony_ci return result; 137262306a36Sopenharmony_ci} 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_cistatic void __exit usb_serial_exit(void) 137662306a36Sopenharmony_ci{ 137762306a36Sopenharmony_ci usb_serial_console_exit(); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci usb_serial_generic_deregister(); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci tty_unregister_driver(usb_serial_tty_driver); 138262306a36Sopenharmony_ci tty_driver_kref_put(usb_serial_tty_driver); 138362306a36Sopenharmony_ci bus_unregister(&usb_serial_bus_type); 138462306a36Sopenharmony_ci idr_destroy(&serial_minors); 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_cimodule_init(usb_serial_init); 138962306a36Sopenharmony_cimodule_exit(usb_serial_exit); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci#define set_to_generic_if_null(type, function) \ 139262306a36Sopenharmony_ci do { \ 139362306a36Sopenharmony_ci if (!type->function) { \ 139462306a36Sopenharmony_ci type->function = usb_serial_generic_##function; \ 139562306a36Sopenharmony_ci pr_debug("%s: using generic " #function "\n", \ 139662306a36Sopenharmony_ci type->driver.name); \ 139762306a36Sopenharmony_ci } \ 139862306a36Sopenharmony_ci } while (0) 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_cistatic void usb_serial_operations_init(struct usb_serial_driver *device) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci set_to_generic_if_null(device, open); 140362306a36Sopenharmony_ci set_to_generic_if_null(device, write); 140462306a36Sopenharmony_ci set_to_generic_if_null(device, close); 140562306a36Sopenharmony_ci set_to_generic_if_null(device, write_room); 140662306a36Sopenharmony_ci set_to_generic_if_null(device, chars_in_buffer); 140762306a36Sopenharmony_ci if (device->tx_empty) 140862306a36Sopenharmony_ci set_to_generic_if_null(device, wait_until_sent); 140962306a36Sopenharmony_ci set_to_generic_if_null(device, read_bulk_callback); 141062306a36Sopenharmony_ci set_to_generic_if_null(device, write_bulk_callback); 141162306a36Sopenharmony_ci set_to_generic_if_null(device, process_read_urb); 141262306a36Sopenharmony_ci set_to_generic_if_null(device, prepare_write_buffer); 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic int usb_serial_register(struct usb_serial_driver *driver) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci int retval; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci if (usb_disabled()) 142062306a36Sopenharmony_ci return -ENODEV; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (!driver->description) 142362306a36Sopenharmony_ci driver->description = driver->driver.name; 142462306a36Sopenharmony_ci if (!driver->usb_driver) { 142562306a36Sopenharmony_ci WARN(1, "Serial driver %s has no usb_driver\n", 142662306a36Sopenharmony_ci driver->description); 142762306a36Sopenharmony_ci return -EINVAL; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* Prevent individual ports from being unbound. */ 143162306a36Sopenharmony_ci driver->driver.suppress_bind_attrs = true; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci usb_serial_operations_init(driver); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci /* Add this device to our list of devices */ 143662306a36Sopenharmony_ci mutex_lock(&table_lock); 143762306a36Sopenharmony_ci list_add(&driver->driver_list, &usb_serial_driver_list); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci retval = usb_serial_bus_register(driver); 144062306a36Sopenharmony_ci if (retval) { 144162306a36Sopenharmony_ci pr_err("problem %d when registering driver %s\n", retval, driver->description); 144262306a36Sopenharmony_ci list_del(&driver->driver_list); 144362306a36Sopenharmony_ci } else { 144462306a36Sopenharmony_ci pr_info("USB Serial support registered for %s\n", driver->description); 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci mutex_unlock(&table_lock); 144762306a36Sopenharmony_ci return retval; 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_cistatic void usb_serial_deregister(struct usb_serial_driver *device) 145162306a36Sopenharmony_ci{ 145262306a36Sopenharmony_ci pr_info("USB Serial deregistering driver %s\n", device->description); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci mutex_lock(&table_lock); 145562306a36Sopenharmony_ci list_del(&device->driver_list); 145662306a36Sopenharmony_ci mutex_unlock(&table_lock); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci usb_serial_bus_deregister(device); 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci/** 146262306a36Sopenharmony_ci * usb_serial_register_drivers - register drivers for a usb-serial module 146362306a36Sopenharmony_ci * @serial_drivers: NULL-terminated array of pointers to drivers to be registered 146462306a36Sopenharmony_ci * @name: name of the usb_driver for this set of @serial_drivers 146562306a36Sopenharmony_ci * @id_table: list of all devices this @serial_drivers set binds to 146662306a36Sopenharmony_ci * 146762306a36Sopenharmony_ci * Registers all the drivers in the @serial_drivers array, and dynamically 146862306a36Sopenharmony_ci * creates a struct usb_driver with the name @name and id_table of @id_table. 146962306a36Sopenharmony_ci */ 147062306a36Sopenharmony_ciint usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[], 147162306a36Sopenharmony_ci const char *name, 147262306a36Sopenharmony_ci const struct usb_device_id *id_table) 147362306a36Sopenharmony_ci{ 147462306a36Sopenharmony_ci int rc; 147562306a36Sopenharmony_ci struct usb_driver *udriver; 147662306a36Sopenharmony_ci struct usb_serial_driver * const *sd; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci /* 147962306a36Sopenharmony_ci * udriver must be registered before any of the serial drivers, 148062306a36Sopenharmony_ci * because the store_new_id() routine for the serial drivers (in 148162306a36Sopenharmony_ci * bus.c) probes udriver. 148262306a36Sopenharmony_ci * 148362306a36Sopenharmony_ci * Performance hack: We don't want udriver to be probed until 148462306a36Sopenharmony_ci * the serial drivers are registered, because the probe would 148562306a36Sopenharmony_ci * simply fail for lack of a matching serial driver. 148662306a36Sopenharmony_ci * So we leave udriver's id_table set to NULL until we are all set. 148762306a36Sopenharmony_ci * 148862306a36Sopenharmony_ci * Suspend/resume support is implemented in the usb-serial core, 148962306a36Sopenharmony_ci * so fill in the PM-related fields in udriver. 149062306a36Sopenharmony_ci */ 149162306a36Sopenharmony_ci udriver = kzalloc(sizeof(*udriver), GFP_KERNEL); 149262306a36Sopenharmony_ci if (!udriver) 149362306a36Sopenharmony_ci return -ENOMEM; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci udriver->name = name; 149662306a36Sopenharmony_ci udriver->no_dynamic_id = 1; 149762306a36Sopenharmony_ci udriver->supports_autosuspend = 1; 149862306a36Sopenharmony_ci udriver->suspend = usb_serial_suspend; 149962306a36Sopenharmony_ci udriver->resume = usb_serial_resume; 150062306a36Sopenharmony_ci udriver->probe = usb_serial_probe; 150162306a36Sopenharmony_ci udriver->disconnect = usb_serial_disconnect; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci /* we only set the reset_resume field if the serial_driver has one */ 150462306a36Sopenharmony_ci for (sd = serial_drivers; *sd; ++sd) { 150562306a36Sopenharmony_ci if ((*sd)->reset_resume) { 150662306a36Sopenharmony_ci udriver->reset_resume = usb_serial_reset_resume; 150762306a36Sopenharmony_ci break; 150862306a36Sopenharmony_ci } 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci rc = usb_register(udriver); 151262306a36Sopenharmony_ci if (rc) 151362306a36Sopenharmony_ci goto err_free_driver; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci for (sd = serial_drivers; *sd; ++sd) { 151662306a36Sopenharmony_ci (*sd)->usb_driver = udriver; 151762306a36Sopenharmony_ci rc = usb_serial_register(*sd); 151862306a36Sopenharmony_ci if (rc) 151962306a36Sopenharmony_ci goto err_deregister_drivers; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci /* Now set udriver's id_table and look for matches */ 152362306a36Sopenharmony_ci udriver->id_table = id_table; 152462306a36Sopenharmony_ci rc = driver_attach(&udriver->drvwrap.driver); 152562306a36Sopenharmony_ci return 0; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cierr_deregister_drivers: 152862306a36Sopenharmony_ci while (sd-- > serial_drivers) 152962306a36Sopenharmony_ci usb_serial_deregister(*sd); 153062306a36Sopenharmony_ci usb_deregister(udriver); 153162306a36Sopenharmony_cierr_free_driver: 153262306a36Sopenharmony_ci kfree(udriver); 153362306a36Sopenharmony_ci return rc; 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_serial_register_drivers); 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci/** 153862306a36Sopenharmony_ci * usb_serial_deregister_drivers - deregister drivers for a usb-serial module 153962306a36Sopenharmony_ci * @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered 154062306a36Sopenharmony_ci * 154162306a36Sopenharmony_ci * Deregisters all the drivers in the @serial_drivers array and deregisters and 154262306a36Sopenharmony_ci * frees the struct usb_driver that was created by the call to 154362306a36Sopenharmony_ci * usb_serial_register_drivers(). 154462306a36Sopenharmony_ci */ 154562306a36Sopenharmony_civoid usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[]) 154662306a36Sopenharmony_ci{ 154762306a36Sopenharmony_ci struct usb_driver *udriver = (*serial_drivers)->usb_driver; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci for (; *serial_drivers; ++serial_drivers) 155062306a36Sopenharmony_ci usb_serial_deregister(*serial_drivers); 155162306a36Sopenharmony_ci usb_deregister(udriver); 155262306a36Sopenharmony_ci kfree(udriver); 155362306a36Sopenharmony_ci} 155462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 155762306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 155862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1559