ChangeSet 1.868, 2002/12/10 17:02:12-08:00, greg@kroah.com [PATCH] USB: Added usb-serial driver core bus support. This means that all individual usb-serial ports show up as their own devices in the driver model tree. diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c --- a/drivers/usb/serial/usb-serial.c Fri Dec 13 17:19:16 2002 +++ b/drivers/usb/serial/usb-serial.c Fri Dec 13 17:19:16 2002 @@ -14,6 +14,10 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (12/10/2002) gkh + * Split the ports off into their own struct device, and added a + * usb-serial bus driver. + * * (11/19/2002) gkh * removed a few #ifdefs for the generic code and cleaned up the failure * logic in initialization. @@ -345,7 +349,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.8" +#define DRIVER_VERSION "v2.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" #define DRIVER_DESC "USB Serial Driver core" @@ -385,6 +389,32 @@ static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ static LIST_HEAD(usb_serial_driver_list); +static int usb_serial_device_match (struct device *dev, struct device_driver *drv) +{ + struct usb_serial_device_type *driver; + const struct usb_serial_port *port; + + /* + * drivers are already assigned to ports in serial_probe so it's + * a simple check here. + */ + port = to_usb_serial_port(dev); + if (!port) + return 0; + + driver = to_usb_serial_driver(drv); + + if (driver == port->serial->type) + return 1; + + return 0; +} + +static struct bus_type usb_serial_bus_type = { + .name = "usb-serial", + .match = usb_serial_device_match, +}; + struct usb_serial *usb_serial_get_by_minor (unsigned int minor) { return serial_table[minor]; @@ -1132,11 +1162,17 @@ } } - /* initialize the devfs nodes for this device and let the user know what ports we are bound to */ - for (i = 0; i < serial->num_ports; ++i) { - tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number); - info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", - type->name, serial->port[i].number, serial->port[i].number); + /* register all of the individual ports with the driver core */ + for (i = 0; i < num_ports; ++i) { + port = &serial->port[i]; + port->dev.parent = &serial->dev->dev; + port->dev.driver = NULL; + port->dev.bus = &usb_serial_bus_type; + + snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number); + snprintf (&port->dev.name[0], sizeof(port->dev.name), "usb serial port %d", port->number); + dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id); + device_register (&port->dev); } usb_serial_console_init (debug, minor); @@ -1204,6 +1240,9 @@ serial_shutdown (serial); for (i = 0; i < serial->num_ports; ++i) + device_unregister(&serial->port[i].dev); + + for (i = 0; i < serial->num_ports; ++i) serial->port[i].open_count = 0; for (i = 0; i < serial->num_bulk_in; ++i) { @@ -1233,12 +1272,6 @@ if (port->interrupt_in_buffer) kfree (port->interrupt_in_buffer); } - - for (i = 0; i < serial->num_ports; ++i) { - tty_unregister_devfs (&serial_tty_driver, serial->port[i].number); - info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->port[i].number); - } - /* return the minor range that this device had */ return_serial (serial); @@ -1294,6 +1327,8 @@ serial_table[i] = NULL; } + bus_register(&usb_serial_bus_type); + /* register the generic driver, if we should */ result = usb_serial_generic_register(debug); if (result < 0) { @@ -1341,21 +1376,103 @@ usb_deregister(&usb_serial_driver); tty_unregister_driver(&serial_tty_driver); + bus_unregister(&usb_serial_bus_type); } module_init(usb_serial_init); module_exit(usb_serial_exit); +static int usb_serial_device_probe (struct device *dev) +{ + struct usb_serial_device_type *driver; + struct usb_serial_port *port; + int retval = 0; + int minor; + + port = to_usb_serial_port(dev); + if (!port) { + retval = -ENODEV; + goto exit; + } + + driver = port->serial->type; + if (driver->port_probe) { + if (!try_module_get(driver->owner)) { + err ("module get failed, exiting"); + retval = -EIO; + goto exit; + } + retval = driver->port_probe (port); + module_put(driver->owner); + if (retval) + goto exit; + } + + minor = port->number; + + tty_register_devfs (&serial_tty_driver, 0, minor); + info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", + driver->name, minor, minor); + +exit: + return retval; +} + +static int usb_serial_device_remove (struct device *dev) +{ + struct usb_serial_device_type *driver; + struct usb_serial_port *port; + int retval = 0; + int minor; + + port = to_usb_serial_port(dev); + if (!port) { + return -ENODEV; + } + + driver = port->serial->type; + if (driver->port_remove) { + if (!try_module_get(driver->owner)) { + err ("module get failed, exiting"); + retval = -EIO; + goto exit; + } + retval = driver->port_remove (port); + module_put(driver->owner); + } +exit: + minor = port->number; + tty_unregister_devfs (&serial_tty_driver, minor); + info("%s converter now disconnected from ttyUSB%d", + driver->name, minor); + + return retval; +} int usb_serial_register(struct usb_serial_device_type *new_device) { + int retval; + /* Add this device to our list of devices */ list_add(&new_device->driver_list, &usb_serial_driver_list); - info ("USB Serial support registered for %s", new_device->name); + new_device->driver.name = (char *)new_device->name; + new_device->driver.bus = &usb_serial_bus_type; + new_device->driver.probe = usb_serial_device_probe; + new_device->driver.remove = usb_serial_device_remove; + + retval = driver_register(&new_device->driver); + + if (!retval) { + info("USB Serial support registered for %s", + new_device->name); + } else { + err("problem %d when registering driver %s", + retval, new_device->name); + } - return 0; + return retval; } diff -Nru a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h --- a/drivers/usb/serial/usb-serial.h Fri Dec 13 17:19:16 2002 +++ b/drivers/usb/serial/usb-serial.h Fri Dec 13 17:19:16 2002 @@ -121,7 +121,9 @@ int open_count; struct semaphore sem; void * private; + struct device dev; }; +#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev) /** * usb_serial - structure used by the usb-serial core for a device @@ -206,13 +208,17 @@ char num_ports; struct list_head driver_list; - + struct device_driver driver; + int (*probe) (struct usb_serial *serial); int (*attach) (struct usb_serial *serial); int (*calc_num_ports) (struct usb_serial *serial); void (*shutdown) (struct usb_serial *serial); + 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); @@ -229,6 +235,7 @@ void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs); void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs); }; +#define to_usb_serial_driver(d) container_of(d, struct usb_serial_device_type, driver) extern int usb_serial_register(struct usb_serial_device_type *new_device); extern void usb_serial_deregister(struct usb_serial_device_type *device);