linux/drivers/usb/serial/bus.c
<<
>>
Prefs
   1/*
   2 * USB Serial Converter Bus specific functions
   3 *
   4 * Copyright (C) 2002 Greg Kroah-Hartman (greg@kroah.com)
   5 *
   6 *      This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License version
   8 *      2 as published by the Free Software Foundation.
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/errno.h>
  13#include <linux/tty.h>
  14#include <linux/module.h>
  15#include <linux/usb.h>
  16#include <linux/usb/serial.h>
  17
  18static int usb_serial_device_match(struct device *dev,
  19                                                struct device_driver *drv)
  20{
  21        struct usb_serial_driver *driver;
  22        const struct usb_serial_port *port;
  23
  24        /*
  25         * drivers are already assigned to ports in serial_probe so it's
  26         * a simple check here.
  27         */
  28        port = to_usb_serial_port(dev);
  29        if (!port)
  30                return 0;
  31
  32        driver = to_usb_serial_driver(drv);
  33
  34        if (driver == port->serial->type)
  35                return 1;
  36
  37        return 0;
  38}
  39
  40static ssize_t show_port_number(struct device *dev,
  41                                struct device_attribute *attr, char *buf)
  42{
  43        struct usb_serial_port *port = to_usb_serial_port(dev);
  44
  45        return sprintf(buf, "%d\n", port->number - port->serial->minor);
  46}
  47
  48static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
  49
  50static int usb_serial_device_probe(struct device *dev)
  51{
  52        struct usb_serial_driver *driver;
  53        struct usb_serial_port *port;
  54        int retval = 0;
  55        int minor;
  56
  57        port = to_usb_serial_port(dev);
  58        if (!port) {
  59                retval = -ENODEV;
  60                goto exit;
  61        }
  62        if (port->dev_state != PORT_REGISTERING)
  63                goto exit;
  64
  65        driver = port->serial->type;
  66        if (driver->port_probe) {
  67                retval = driver->port_probe(port);
  68                if (retval)
  69                        goto exit;
  70        }
  71
  72        retval = device_create_file(dev, &dev_attr_port_number);
  73        if (retval) {
  74                if (driver->port_remove)
  75                        retval = driver->port_remove(port);
  76                goto exit;
  77        }
  78
  79        minor = port->number;
  80        tty_register_device(usb_serial_tty_driver, minor, dev);
  81        dev_info(&port->serial->dev->dev,
  82                 "%s converter now attached to ttyUSB%d\n",
  83                 driver->description, minor);
  84
  85exit:
  86        return retval;
  87}
  88
  89static int usb_serial_device_remove(struct device *dev)
  90{
  91        struct usb_serial_driver *driver;
  92        struct usb_serial_port *port;
  93        int retval = 0;
  94        int minor;
  95
  96        port = to_usb_serial_port(dev);
  97        if (!port)
  98                return -ENODEV;
  99
 100        if (port->dev_state != PORT_UNREGISTERING)
 101                return retval;
 102
 103        device_remove_file(&port->dev, &dev_attr_port_number);
 104
 105        driver = port->serial->type;
 106        if (driver->port_remove)
 107                retval = driver->port_remove(port);
 108
 109        minor = port->number;
 110        tty_unregister_device(usb_serial_tty_driver, minor);
 111        dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
 112                 driver->description, minor);
 113
 114        return retval;
 115}
 116
 117#ifdef CONFIG_HOTPLUG
 118static ssize_t store_new_id(struct device_driver *driver,
 119                            const char *buf, size_t count)
 120{
 121        struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
 122        ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
 123
 124        if (retval >= 0 && usb_drv->usb_driver != NULL)
 125                retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
 126                                          &usb_drv->usb_driver->drvwrap.driver,
 127                                          buf, count);
 128        return retval;
 129}
 130
 131static struct driver_attribute drv_attrs[] = {
 132        __ATTR(new_id, S_IWUSR, NULL, store_new_id),
 133        __ATTR_NULL,
 134};
 135
 136static void free_dynids(struct usb_serial_driver *drv)
 137{
 138        struct usb_dynid *dynid, *n;
 139
 140        spin_lock(&drv->dynids.lock);
 141        list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
 142                list_del(&dynid->node);
 143                kfree(dynid);
 144        }
 145        spin_unlock(&drv->dynids.lock);
 146}
 147
 148#else
 149static struct driver_attribute drv_attrs[] = {
 150        __ATTR_NULL,
 151};
 152static inline void free_dynids(struct usb_serial_driver *drv)
 153{
 154}
 155#endif
 156
 157struct bus_type usb_serial_bus_type = {
 158        .name =         "usb-serial",
 159        .match =        usb_serial_device_match,
 160        .probe =        usb_serial_device_probe,
 161        .remove =       usb_serial_device_remove,
 162        .drv_attrs =    drv_attrs,
 163};
 164
 165int usb_serial_bus_register(struct usb_serial_driver *driver)
 166{
 167        int retval;
 168
 169        driver->driver.bus = &usb_serial_bus_type;
 170        spin_lock_init(&driver->dynids.lock);
 171        INIT_LIST_HEAD(&driver->dynids.list);
 172
 173        retval = driver_register(&driver->driver);
 174
 175        return retval;
 176}
 177
 178void usb_serial_bus_deregister(struct usb_serial_driver *driver)
 179{
 180        free_dynids(driver);
 181        driver_unregister(&driver->driver);
 182}
 183
 184