This patch will break all USB-Serial drivers. It's big, but most of the changes are just deletions.
I didn't write a document explaning how to make the port yet, will do when I get enough feedback about this work. For now, the important points regarding the port are: 1. The registration process hasn't been changed, ie, you don't have to touch the driver's init function 2. The way you send data to user-space (ie, calling the tty's flip buffer functions) hasn't been changed either 3. The big interface change is the removal of the tty callbacks from the struct usb_serial_driver (open(), close(), write(), write_room(), ioctl(), set_termios(), break_ctl(), chars_in_buffer(), throttle(), unthrottle(), tiocmget(), tiocmset()). Now a driver must assign an allocated 'struct uart_ops' to the 'uart_ops' member of the struct usb_serial_driver. And, of course, define its methods. That's the Serial Core interface, and it's explained in this document: Documentation/serial/driver Now lets speak about the general points: 1. multi-port support The tty version of the USB-Serial's core supports multi-port devices by: A) Allocating a minor number for each port in get_free_serial() B) Filling the 'port' member of the device's struct usb_serial_port with pointers to all the ports already set up C) tty_register_device() will register each minor with the tty core D) At open() time, USB-Serial's core gets the right port to use and puts a pointer to it in the 'tty->private_data' so that the other methods can get it In the Serial Core version, steps A and B are the same, but the others aren't: C) All the _individuals_ ports are registered with the Serial Core by uart_add_one_port() D) All the methods will get the port to be used from the USBSERIAL_PORT macro The most important assumption I've made is this: the USBSERIAL_PORT macro will bring the right port. It can be the third port of a device. The first one. Doesn't matter, the right port will be there. I have no sure whether this is really right. In fact, the multi-port support is my main concern regarding the Serial Core port work. The problem here is that I don't have multi-port devices, then my only choice was to read the code and adapt it for what I think to be right. 2. struct usb_serial reference counting has been removed For two reasons: A) IIUC, it's not needed anymore. In the tty version, the kref_put() is called in three places: serial_close(), serial_read_proc() and usb_serial_disconnect(). serial_read_proc() was dropped and serial_close() is only called when the port is closed last time. Then the call to the destroy_serial() function was moved to usb_serial_disconnect(). If the device is disconnected before calling close(), the Serial Core will notice it and serial_shutdown() won't be called. If the device is close()ed but not disconnected, then yes, that memory will remain allocated 'til the device is disconnected. This leads us to the next reason. B) uart_remove_one_port() cannot be called from the shutdown() method. IOW: we can't call destroy_serial() from serial_shutdown(). If we do this we'll get a deadlock because uart_close() takes the 'state->mutex' lock before calling the shutdown method _and_ the uart_remove_one_port() will try to lock the same mutex when called. 3. The port type In the uart port initialization (in usb_serial_probe()), all ports are configured to be the 'PORT_16650' type. I don't know how the Serial Core uses that information, and 'PORT_16650' is something that worked. 4. Port's fifo size It's 16 for all ports, but it's just another guess. What should it be? 5. Optional methods I've made the methods which has default behaivor defined by the Serial Core as optionals, ie, if an optional method wasn't defined by a driver the USB-Serial's core will perfom the default behaivor. Those methods currently are: tx_empty(), ioctl(), pm() and type(). Signed-off-by: Luiz Fernando N. Capitulino <[EMAIL PROTECTED]> --- drivers/usb/serial/bus.c | 19 + drivers/usb/serial/usb-serial.c | 546 +++++++++++++-------------------------- drivers/usb/serial/usb-serial.h | 23 +- 3 files changed, 195 insertions(+), 393 deletions(-) diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index e9f9f4b..832a34c 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -11,7 +11,7 @@ #include <linux/config.h> #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/tty.h> +#include <linux/serial_core.h> #include <linux/module.h> #include <linux/usb.h> #include "usb-serial.h" @@ -42,7 +42,6 @@ static int usb_serial_device_probe (stru struct usb_serial_driver *driver; struct usb_serial_port *port; int retval = 0; - int minor; port = to_usb_serial_port(dev); if (!port) { @@ -63,11 +62,15 @@ static int usb_serial_device_probe (stru goto exit; } - minor = port->number; - tty_register_device (usb_serial_tty_driver, minor, dev); + port->uart_port.line = port->number; + retval = uart_add_one_port(&usb_serial_uart_driver, &port->uart_port); + if (retval) { + dev_err(dev, "Can't add uart port, exiting\n"); + goto exit; + } dev_info(&port->serial->dev->dev, "%s converter now attached to ttyUSB%d\n", - driver->description, minor); + driver->description, port->number); exit: return retval; @@ -78,7 +81,6 @@ static int usb_serial_device_remove (str struct usb_serial_driver *driver; struct usb_serial_port *port; int retval = 0; - int minor; port = to_usb_serial_port(dev); if (!port) { @@ -96,10 +98,9 @@ static int usb_serial_device_remove (str module_put(driver->driver.owner); } exit: - minor = port->number; - tty_unregister_device (usb_serial_tty_driver, minor); + uart_remove_one_port(&usb_serial_uart_driver, &port->uart_port); dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", - driver->description, minor); + driver->description, port->uart_port.line); return retval; } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 4165035..f4db7a9 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -24,6 +24,7 @@ #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> +#include <linux/serial_core.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/spinlock.h> @@ -60,21 +61,12 @@ static int debug; static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ static LIST_HEAD(usb_serial_driver_list); -struct usb_serial *usb_serial_get_by_index(unsigned index) -{ - struct usb_serial *serial = serial_table[index]; - - if (serial) - kref_get(&serial->kref); - return serial; -} - static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor) { unsigned int i, j; int good_spot; - dbg("%d", num_ports); + dbg("%d ports", num_ports); *minor = 0; for (i = 0; i < SERIAL_TTY_MINORS; ++i) { @@ -104,7 +96,7 @@ static void return_serial(struct usb_ser { int i; - dbg(""); + dbg("%s", serial->type->description); if (serial == NULL) return; @@ -114,14 +106,11 @@ static void return_serial(struct usb_ser } } -static void destroy_serial(struct kref *kref) +static void destroy_serial(struct usb_serial *serial) { - struct usb_serial *serial; struct usb_serial_port *port; int i; - serial = to_usb_serial(kref); - dbg("%s", serial->type->description); serial->type->shutdown(serial); @@ -169,361 +158,184 @@ static void destroy_serial(struct kref * } /***************************************************************************** - * Driver tty interface functions + * Driver Serial Core interface functions *****************************************************************************/ -static int serial_open (struct tty_struct *tty, struct file * filp) +static unsigned int serial_tx_empty(struct uart_port *port) { - struct usb_serial *serial; - struct usb_serial_port *port; - unsigned int portNumber; - int retval; - - dbg(""); - - /* get the serial object associated with this tty pointer */ - serial = usb_serial_get_by_index(tty->index); - if (!serial) { - tty->driver_data = NULL; - return -ENODEV; - } - - portNumber = tty->index - serial->minor; - port = serial->port[portNumber]; - if (!port) { - retval = -ENODEV; - goto bailout_kref_put; - } - - if (mutex_lock_interruptible(&port->mutex)) { - retval = -ERESTARTSYS; - goto bailout_kref_put; - } - - ++port->open_count; - - if (port->open_count == 1) { - - /* set up our port structure making the tty driver - * remember our port object, and us it */ - tty->driver_data = port; - port->tty = tty; - - /* lock this module before we call it - * this may fail, which means we must bail out, - * safe because we are called with BKL held */ - if (!try_module_get(serial->type->driver.owner)) { - retval = -ENODEV; - goto bailout_mutex_unlock; - } + unsigned int (*tx_empty)(struct uart_port *); - /* only call the device specific open if this - * is the first time the port is opened */ - retval = serial->type->open(port, filp); - if (retval) - goto bailout_module_put; - } + dbg("port %d", port->line); - mutex_unlock(&port->mutex); - return 0; + tx_empty = USBSERIAL_PORT->serial->type->uart_ops->tx_empty; + if (tx_empty) + return tx_empty(port); -bailout_module_put: - module_put(serial->type->driver.owner); -bailout_mutex_unlock: - port->open_count = 0; - mutex_unlock(&port->mutex); -bailout_kref_put: - kref_put(&serial->kref, destroy_serial); - return retval; + return TIOCSER_TEMT; } -static void serial_close(struct tty_struct *tty, struct file * filp) +static void serial_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct usb_serial_port *port = tty->driver_data; - - if (!port) - return; - - dbg("port %d", port->number); - - mutex_lock(&port->mutex); + dbg("port %d", port->line); - if (port->open_count == 0) { - mutex_unlock(&port->mutex); - return; - } - - --port->open_count; - if (port->open_count == 0) { - /* only call the device specific close if this - * port is being closed by the last owner */ - port->serial->type->close(port, filp); - - if (port->tty) { - if (port->tty->driver_data) - port->tty->driver_data = NULL; - port->tty = NULL; - } + USBSERIAL_PORT->serial->type->uart_ops->set_mctrl(port, mctrl); +} - module_put(port->serial->type->driver.owner); - } +static unsigned int serial_get_mctrl(struct uart_port *port) +{ + dbg("port %d", port->line); - mutex_unlock(&port->mutex); - kref_put(&port->serial->kref, destroy_serial); + return USBSERIAL_PORT->serial->type->uart_ops->get_mctrl(port); } -static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) +static void serial_stop_tx(struct uart_port *port) { - struct usb_serial_port *port = tty->driver_data; - int retval = -EINVAL; + dbg("port %d", port->line); - if (!port) - goto exit; + USBSERIAL_PORT->serial->type->uart_ops->stop_tx(port); +} - dbg("port %d, %d byte(s)", port->number, count); +static void serial_start_tx(struct uart_port *port) +{ + dbg("port %d", port->line); - if (!port->open_count) { - dbg("port not opened"); - goto exit; - } + USBSERIAL_PORT->serial->type->uart_ops->start_tx(port); +} - /* pass on to the driver specific version of this function */ - retval = port->serial->type->write(port, buf, count); +static void serial_send_xchar(struct uart_port *port, char ch) +{ + dbg("port %d", port->line); -exit: - return retval; + USBSERIAL_PORT->serial->type->uart_ops->send_xchar(port, ch); } -static int serial_write_room (struct tty_struct *tty) +static void serial_stop_rx(struct uart_port *port) { - struct usb_serial_port *port = tty->driver_data; - int retval = -EINVAL; + dbg("port %d", port->line); - if (!port) - goto exit; + USBSERIAL_PORT->serial->type->uart_ops->stop_rx(port); +} - dbg("port %d", port->number); +static void serial_enable_ms(struct uart_port *port) +{ + dbg("port %d", port->line); - if (!port->open_count) { - dbg("port not open"); - goto exit; - } + USBSERIAL_PORT->serial->type->uart_ops->enable_ms(port); +} - /* pass on to the driver specific version of this function */ - retval = port->serial->type->write_room(port); +static void serial_break(struct uart_port *port, int break_state) +{ + dbg("port %d", port->line); -exit: - return retval; + USBSERIAL_PORT->serial->type->uart_ops->break_ctl(port, break_state); } -static int serial_chars_in_buffer (struct tty_struct *tty) +static int serial_startup(struct uart_port *port) { - struct usb_serial_port *port = tty->driver_data; - int retval = -EINVAL; + int ret; - if (!port) - goto exit; + dbg("port %d", port->line); - dbg("port %d", port->number); + if (!try_module_get(USBSERIAL_PORT->serial->type->driver.owner)) + return -ENODEV; - if (!port->open_count) { - dbg("port not open"); - goto exit; - } + ret = USBSERIAL_PORT->serial->type->uart_ops->startup(port); + if (ret) + goto module_put; - /* pass on to the driver specific version of this function */ - retval = port->serial->type->chars_in_buffer(port); + return 0; -exit: - return retval; +module_put: + module_put(USBSERIAL_PORT->serial->type->driver.owner); + return -ENODEV; } -static void serial_throttle (struct tty_struct * tty) +static void serial_shutdown(struct uart_port *port) { - struct usb_serial_port *port = tty->driver_data; + dbg("port %d", port->line); - if (!port) - return; + USBSERIAL_PORT->serial->type->uart_ops->shutdown(port); - dbg("port %d", port->number); - - if (!port->open_count) { - dbg ("port not open"); - return; - } - - /* pass on to the driver specific version of this function */ - if (port->serial->type->throttle) - port->serial->type->throttle(port); + module_put(USBSERIAL_PORT->serial->type->driver.owner); } -static void serial_unthrottle (struct tty_struct * tty) +static int serial_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) { - struct usb_serial_port *port = tty->driver_data; + int (*ioctl)(struct uart_port *, unsigned int, unsigned long); + int ret = -ENOIOCTLCMD; - if (!port) - return; - - dbg("port %d", port->number); + dbg("port %d", port->line); - if (!port->open_count) { - dbg("port not open"); - return; - } + ioctl = USBSERIAL_PORT->serial->type->uart_ops->ioctl; + if (ioctl) + ret = ioctl(port, cmd, arg); - /* pass on to the driver specific version of this function */ - if (port->serial->type->unthrottle) - port->serial->type->unthrottle(port); + return ret; } -static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) +static void serial_set_termios(struct uart_port *port, + struct termios *termios, + struct termios *old_termios) { - struct usb_serial_port *port = tty->driver_data; - int retval = -ENODEV; + dbg("port %d", port->line); - if (!port) - goto exit; - - dbg("port %d, cmd 0x%.4x", port->number, cmd); - - if (!port->open_count) { - dbg ("port not open"); - goto exit; - } - - /* pass on to the driver specific version of this function if it is available */ - if (port->serial->type->ioctl) - retval = port->serial->type->ioctl(port, file, cmd, arg); - else - retval = -ENOIOCTLCMD; - -exit: - return retval; + USBSERIAL_PORT->serial->type->uart_ops->set_termios(port, + termios, + old_termios); } -static void serial_set_termios (struct tty_struct *tty, struct termios * old) +static void serial_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) { - struct usb_serial_port *port = tty->driver_data; + void (*pm)(struct uart_port *, unsigned int, unsigned int); - if (!port) - return; + dbg("port %d", port->line); - dbg("port %d", port->number); - - if (!port->open_count) { - dbg("port not open"); - return; - } - - /* pass on to the driver specific version of this function if it is available */ - if (port->serial->type->set_termios) - port->serial->type->set_termios(port, old); + pm = USBSERIAL_PORT->serial->type->uart_ops->pm; + if (pm) + USBSERIAL_PORT->serial->type->uart_ops->pm(port, state, + oldstate); } -static void serial_break (struct tty_struct *tty, int break_state) +static const char *serial_type(struct uart_port *port) { - struct usb_serial_port *port = tty->driver_data; - - if (!port) - return; + const char *(*type)(struct uart_port *); - dbg("port %d", port->number); + dbg("port %d", port->line); - if (!port->open_count) { - dbg("port not open"); - return; - } + type = USBSERIAL_PORT->serial->type->uart_ops->type; + if (type) + return USBSERIAL_PORT->serial->type->uart_ops->type(port); - /* pass on to the driver specific version of this function if it is available */ - if (port->serial->type->break_ctl) - port->serial->type->break_ctl(port, break_state); + return NULL; } -static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) +static void serial_release_port(struct uart_port *port) { - struct usb_serial *serial; - int length = 0; - int i; - off_t begin = 0; - char tmp[40]; - - dbg(""); - length += sprintf (page, "usbserinfo:1.0 driver:2.0\n"); - for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) { - serial = usb_serial_get_by_index(i); - if (serial == NULL) - continue; + dbg("port %d", port->line); - length += sprintf (page+length, "%d:", i); - if (serial->type->driver.owner) - length += sprintf (page+length, " module:%s", module_name(serial->type->driver.owner)); - length += sprintf (page+length, " name:\"%s\"", serial->type->description); - length += sprintf (page+length, " vendor:%04x product:%04x", - le16_to_cpu(serial->dev->descriptor.idVendor), - le16_to_cpu(serial->dev->descriptor.idProduct)); - length += sprintf (page+length, " num_ports:%d", serial->num_ports); - length += sprintf (page+length, " port:%d", i - serial->minor + 1); - - usb_make_path(serial->dev, tmp, sizeof(tmp)); - length += sprintf (page+length, " path:%s", tmp); - - length += sprintf (page+length, "\n"); - if ((length + begin) > (off + count)) - goto done; - if ((length + begin) < off) { - begin += length; - length = 0; - } - kref_put(&serial->kref, destroy_serial); - } - *eof = 1; -done: - if (off >= (length + begin)) - return 0; - *start = page + (off-begin); - return ((count < begin+length-off) ? count : begin+length-off); + USBSERIAL_PORT->serial->type->uart_ops->release_port(port); } -static int serial_tiocmget (struct tty_struct *tty, struct file *file) +static int serial_request_port(struct uart_port *port) { - struct usb_serial_port *port = tty->driver_data; + dbg("port %d", port->line); - if (!port) - goto exit; - - dbg("port %d", port->number); - - if (!port->open_count) { - dbg("port not open"); - goto exit; - } - - if (port->serial->type->tiocmget) - return port->serial->type->tiocmget(port, file); - -exit: - return -EINVAL; + return USBSERIAL_PORT->serial->type->uart_ops->request_port(port); } -static int serial_tiocmset (struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) +static void serial_config_port(struct uart_port *port, int flags) { - struct usb_serial_port *port = tty->driver_data; - - if (!port) - goto exit; - - dbg("port %d", port->number); + dbg("port %d", port->line); - if (!port->open_count) { - dbg("port not open"); - goto exit; - } + USBSERIAL_PORT->serial->type->uart_ops->config_port(port, flags); +} - if (port->serial->type->tiocmset) - return port->serial->type->tiocmset(port, file, set, clear); +static int serial_verify_port(struct uart_port *port, + struct serial_struct *serinfo) +{ + dbg("port %d", port->line); -exit: - return -EINVAL; + return USBSERIAL_PORT->serial->type->uart_ops->verify_port(port, serinfo); } void usb_serial_port_softint(void *private) @@ -531,12 +343,12 @@ void usb_serial_port_softint(void *priva struct usb_serial_port *port = private; struct tty_struct *tty; - dbg("port %d", port->number); - + dbg("port %d", port->uart_port.line); + if (!port) return; - tty = port->tty; + tty = port->uart_port.info->tty; if (!tty) return; @@ -547,7 +359,8 @@ static void port_release(struct device * { struct usb_serial_port *port = to_usb_serial_port(dev); - dbg ("%s", dev->bus_id); + dbg("Releasing port %s", dev->bus_id); + usb_kill_urb(port->read_urb); usb_free_urb(port->read_urb); usb_kill_urb(port->write_urb); @@ -601,6 +414,28 @@ static struct usb_serial_driver *search_ return NULL; } +static struct uart_ops usb_serial_uart_ops = { + .tx_empty = serial_tx_empty, + .set_mctrl = serial_set_mctrl, + .get_mctrl = serial_get_mctrl, + .stop_tx = serial_stop_tx, + .start_tx = serial_start_tx, + .send_xchar = serial_send_xchar, + .stop_rx = serial_stop_rx, + .enable_ms = serial_enable_ms, + .break_ctl = serial_break, + .startup = serial_startup, + .shutdown = serial_shutdown, + .ioctl = serial_ioctl, + .set_termios = serial_set_termios, + .pm = serial_pm, + .type = serial_type, + .release_port = serial_release_port, + .request_port = serial_request_port, + .config_port = serial_config_port, + .verify_port = serial_verify_port, +}; + int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -931,6 +766,16 @@ #endif port->dev.bus = &usb_serial_bus_type; port->dev.release = &port_release; + /* + * uart_port initialization + */ + port->uart_port.ops = &usb_serial_uart_ops; + port->uart_port.dev = &interface->dev; + port->uart_port.iotype = UPIO_PORT; + port->uart_port.membase = NULL; + port->uart_port.type = PORT_16650; + port->uart_port.fifosize = 16; + snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number); dbg ("registering %s", port->dev.bus_id); device_register (&port->dev); @@ -994,112 +839,79 @@ void usb_serial_disconnect(struct usb_in struct device *dev = &interface->dev; struct usb_serial_port *port; - dbg (""); + dbg("%s", serial->type->description); usb_set_intfdata (interface, NULL); if (serial) { for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; - if (port && port->tty) - tty_hangup(port->tty); + if (port && port->uart_port.info && + port->uart_port.info->tty) + tty_hangup(port->uart_port.info->tty); } - /* let the last holder of this object - * cause it to be cleaned up */ - kref_put(&serial->kref, destroy_serial); + destroy_serial(serial); } - dev_info(dev, "device disconnected\n"); + dev_info(dev, "device disconnected"); } -static struct tty_operations serial_ops = { - .open = serial_open, - .close = serial_close, - .write = serial_write, - .write_room = serial_write_room, - .ioctl = serial_ioctl, - .set_termios = serial_set_termios, - .throttle = serial_throttle, - .unthrottle = serial_unthrottle, - .break_ctl = serial_break, - .chars_in_buffer = serial_chars_in_buffer, - .read_proc = serial_read_proc, - .tiocmget = serial_tiocmget, - .tiocmset = serial_tiocmset, +struct uart_driver usb_serial_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "usbserial", + .dev_name = "ttyUSB", + .major = SERIAL_TTY_MAJOR, + .minor = 0, + .nr = SERIAL_TTY_MINORS, + .cons = NULL, }; -struct tty_driver *usb_serial_tty_driver; - static int __init usb_serial_init(void) { - int i; - int result; + int i, result; - usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS); - if (!usb_serial_tty_driver) - return -ENOMEM; + result = uart_register_driver(&usb_serial_uart_driver); + if (result) + goto exit; /* Initialize our global data */ - for (i = 0; i < SERIAL_TTY_MINORS; ++i) { + for (i = 0; i < SERIAL_TTY_MINORS; ++i) serial_table[i] = NULL; - } result = bus_register(&usb_serial_bus_type); if (result) { - err("registering bus driver failed"); - goto exit_bus; - } - - usb_serial_tty_driver->owner = THIS_MODULE; - usb_serial_tty_driver->driver_name = "usbserial"; - usb_serial_tty_driver->devfs_name = "usb/tts/"; - usb_serial_tty_driver->name = "ttyUSB"; - usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; - usb_serial_tty_driver->minor_start = 0; - usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL; - usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; - usb_serial_tty_driver->init_termios = tty_std_termios; - usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty_set_operations(usb_serial_tty_driver, &serial_ops); - result = tty_register_driver(usb_serial_tty_driver); - if (result) { - err("tty_register_driver failed"); - goto exit_reg_driver; + err("Registering bus driver failed"); + goto exit_uart; } /* register the USB driver */ result = usb_register(&usb_serial_driver); if (result < 0) { err("usb_register failed"); - goto exit_tty; + goto exit_bus; } /* register the generic driver, if we should */ result = usb_serial_generic_register(debug); if (result < 0) { - err("registering generic driver failed"); - goto exit_generic; + err("Registering generic driver failed"); + goto exit_usb; } info(DRIVER_DESC); + dbg("usbserial module loaded"); return result; -exit_generic: +exit_usb: usb_deregister(&usb_serial_driver); - -exit_tty: - tty_unregister_driver(usb_serial_tty_driver); - -exit_reg_driver: - bus_unregister(&usb_serial_bus_type); - exit_bus: - err ("returning with error %d", result); - put_tty_driver(usb_serial_tty_driver); + bus_unregister(&usb_serial_bus_type); +exit_uart: + uart_unregister_driver(&usb_serial_uart_driver); +exit: + err("Returning with error %d", result); return result; } - static void __exit usb_serial_exit(void) { usb_serial_console_exit(); @@ -1107,12 +919,11 @@ static void __exit usb_serial_exit(void) usb_serial_generic_deregister(); usb_deregister(&usb_serial_driver); - tty_unregister_driver(usb_serial_tty_driver); - put_tty_driver(usb_serial_tty_driver); bus_unregister(&usb_serial_bus_type); + uart_unregister_driver(&usb_serial_uart_driver); + dbg("usbserial module exiting"); } - module_init(usb_serial_init); module_exit(usb_serial_exit); @@ -1167,7 +978,6 @@ #endif return retval; } - void usb_serial_deregister(struct usb_serial_driver *device) { info("USB Serial deregistering driver %s", device->description); @@ -1175,8 +985,6 @@ void usb_serial_deregister(struct usb_se usb_serial_bus_deregister(device); } - - /* If the usb-serial core is built into the core, the usb-serial drivers need these symbols to load properly as modules. */ EXPORT_SYMBOL_GPL(usb_serial_register); diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index 40b660b..b273efa 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -17,17 +17,21 @@ #define __LINUX_USB_SERIAL_H #include <linux/config.h> #include <linux/kref.h> #include <linux/mutex.h> +#include <linux/serial_core.h> #define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ #define SERIAL_TTY_MINORS 255 /* loads of devices :) */ #define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */ +#define USBSERIAL_PORT ((struct usb_serial_port *)port) + /* parity check flag */ #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) /** * usb_serial_port: structure for the specific ports of a device. + * @uart_port: the uart_port of this device * @serial: pointer back to the struct usb_serial owner of this port. * @tty: pointer to the corresponding tty for this port. * @lock: spinlock to grab when updating portions of this structure. @@ -60,6 +64,7 @@ #define RELEVANT_IFLAG(iflag) (iflag & ( * ports of a device. */ struct usb_serial_port { + struct uart_port uart_port; struct usb_serial * serial; struct tty_struct * tty; spinlock_t lock; @@ -204,6 +209,8 @@ struct usb_serial_driver { struct list_head driver_list; struct device_driver driver; + struct uart_ops *uart_ops; + int (*probe) (struct usb_serial *serial, const struct usb_device_id *id); int (*attach) (struct usb_serial *serial); int (*calc_num_ports) (struct usb_serial *serial); @@ -213,20 +220,6 @@ struct usb_serial_driver { int (*port_probe) (struct usb_serial_port *port); int (*port_remove) (struct usb_serial_port *port); - /* serial function calls */ - int (*open) (struct usb_serial_port *port, struct file * filp); - void (*close) (struct usb_serial_port *port, struct file * filp); - int (*write) (struct usb_serial_port *port, const unsigned char *buf, int count); - int (*write_room) (struct usb_serial_port *port); - int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); - void (*set_termios) (struct usb_serial_port *port, struct termios * old); - void (*break_ctl) (struct usb_serial_port *port, int break_state); - int (*chars_in_buffer) (struct usb_serial_port *port); - void (*throttle) (struct usb_serial_port *port); - void (*unthrottle) (struct usb_serial_port *port); - int (*tiocmget) (struct usb_serial_port *port, struct file *file); - int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); - void (*read_int_callback)(struct urb *urb, struct pt_regs *regs); void (*write_int_callback)(struct urb *urb, struct pt_regs *regs); void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs); @@ -271,7 +264,7 @@ extern void usb_serial_bus_deregister (s extern struct usb_serial_driver usb_serial_generic_device; extern struct bus_type usb_serial_bus_type; -extern struct tty_driver *usb_serial_tty_driver; +extern struct uart_driver usb_serial_uart_driver; static inline void usb_serial_debug_data(int debug, struct device *dev, -- 1.3.3.g0825d _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel