Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * USB Serial Converter Bus specific functions
0004  *
0005  * Copyright (C) 2002 Greg Kroah-Hartman (greg@kroah.com)
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/errno.h>
0010 #include <linux/tty.h>
0011 #include <linux/slab.h>
0012 #include <linux/module.h>
0013 #include <linux/usb.h>
0014 #include <linux/usb/serial.h>
0015 
0016 static int usb_serial_device_match(struct device *dev,
0017                         struct device_driver *drv)
0018 {
0019     const struct usb_serial_port *port = to_usb_serial_port(dev);
0020     struct usb_serial_driver *driver = to_usb_serial_driver(drv);
0021 
0022     /*
0023      * drivers are already assigned to ports in serial_probe so it's
0024      * a simple check here.
0025      */
0026     if (driver == port->serial->type)
0027         return 1;
0028 
0029     return 0;
0030 }
0031 
0032 static int usb_serial_device_probe(struct device *dev)
0033 {
0034     struct usb_serial_port *port = to_usb_serial_port(dev);
0035     struct usb_serial_driver *driver;
0036     struct device *tty_dev;
0037     int retval = 0;
0038     int minor;
0039 
0040     /* make sure suspend/resume doesn't race against port_probe */
0041     retval = usb_autopm_get_interface(port->serial->interface);
0042     if (retval)
0043         return retval;
0044 
0045     driver = port->serial->type;
0046     if (driver->port_probe) {
0047         retval = driver->port_probe(port);
0048         if (retval)
0049             goto err_autopm_put;
0050     }
0051 
0052     minor = port->minor;
0053     tty_dev = tty_port_register_device(&port->port, usb_serial_tty_driver,
0054                        minor, dev);
0055     if (IS_ERR(tty_dev)) {
0056         retval = PTR_ERR(tty_dev);
0057         goto err_port_remove;
0058     }
0059 
0060     usb_autopm_put_interface(port->serial->interface);
0061 
0062     dev_info(&port->serial->dev->dev,
0063          "%s converter now attached to ttyUSB%d\n",
0064          driver->description, minor);
0065 
0066     return 0;
0067 
0068 err_port_remove:
0069     if (driver->port_remove)
0070         driver->port_remove(port);
0071 err_autopm_put:
0072     usb_autopm_put_interface(port->serial->interface);
0073 
0074     return retval;
0075 }
0076 
0077 static void usb_serial_device_remove(struct device *dev)
0078 {
0079     struct usb_serial_port *port = to_usb_serial_port(dev);
0080     struct usb_serial_driver *driver;
0081     int minor;
0082     int autopm_err;
0083 
0084     /*
0085      * Make sure suspend/resume doesn't race against port_remove.
0086      *
0087      * Note that no further runtime PM callbacks will be made if
0088      * autopm_get fails.
0089      */
0090     autopm_err = usb_autopm_get_interface(port->serial->interface);
0091 
0092     minor = port->minor;
0093     tty_unregister_device(usb_serial_tty_driver, minor);
0094 
0095     driver = port->serial->type;
0096     if (driver->port_remove)
0097         driver->port_remove(port);
0098 
0099     dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
0100          driver->description, minor);
0101 
0102     if (!autopm_err)
0103         usb_autopm_put_interface(port->serial->interface);
0104 }
0105 
0106 static ssize_t new_id_store(struct device_driver *driver,
0107                 const char *buf, size_t count)
0108 {
0109     struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
0110     ssize_t retval = usb_store_new_id(&usb_drv->dynids, usb_drv->id_table,
0111                      driver, buf, count);
0112 
0113     if (retval >= 0 && usb_drv->usb_driver != NULL)
0114         retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
0115                       usb_drv->usb_driver->id_table,
0116                       &usb_drv->usb_driver->drvwrap.driver,
0117                       buf, count);
0118     return retval;
0119 }
0120 
0121 static ssize_t new_id_show(struct device_driver *driver, char *buf)
0122 {
0123     struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
0124 
0125     return usb_show_dynids(&usb_drv->dynids, buf);
0126 }
0127 static DRIVER_ATTR_RW(new_id);
0128 
0129 static struct attribute *usb_serial_drv_attrs[] = {
0130     &driver_attr_new_id.attr,
0131     NULL,
0132 };
0133 ATTRIBUTE_GROUPS(usb_serial_drv);
0134 
0135 static void free_dynids(struct usb_serial_driver *drv)
0136 {
0137     struct usb_dynid *dynid, *n;
0138 
0139     spin_lock(&drv->dynids.lock);
0140     list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
0141         list_del(&dynid->node);
0142         kfree(dynid);
0143     }
0144     spin_unlock(&drv->dynids.lock);
0145 }
0146 
0147 struct bus_type usb_serial_bus_type = {
0148     .name =     "usb-serial",
0149     .match =    usb_serial_device_match,
0150     .probe =    usb_serial_device_probe,
0151     .remove =   usb_serial_device_remove,
0152     .drv_groups =   usb_serial_drv_groups,
0153 };
0154 
0155 int usb_serial_bus_register(struct usb_serial_driver *driver)
0156 {
0157     int retval;
0158 
0159     driver->driver.bus = &usb_serial_bus_type;
0160     spin_lock_init(&driver->dynids.lock);
0161     INIT_LIST_HEAD(&driver->dynids.list);
0162 
0163     retval = driver_register(&driver->driver);
0164 
0165     return retval;
0166 }
0167 
0168 void usb_serial_bus_deregister(struct usb_serial_driver *driver)
0169 {
0170     free_dynids(driver);
0171     driver_unregister(&driver->driver);
0172 }
0173