Commit de21edae authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

[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.
parent 8dad78d0
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
* *
* See Documentation/usb/usb-serial.txt for more information on using this driver * 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 * (11/19/2002) gkh
* removed a few #ifdefs for the generic code and cleaned up the failure * removed a few #ifdefs for the generic code and cleaned up the failure
* logic in initialization. * logic in initialization.
...@@ -345,7 +349,7 @@ ...@@ -345,7 +349,7 @@
/* /*
* Version Information * 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_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core" #define DRIVER_DESC "USB Serial Driver core"
...@@ -385,6 +389,32 @@ static struct termios * serial_termios_locked[SERIAL_TTY_MINORS]; ...@@ -385,6 +389,32 @@ static struct termios * serial_termios_locked[SERIAL_TTY_MINORS];
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
static LIST_HEAD(usb_serial_driver_list); 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) struct usb_serial *usb_serial_get_by_minor (unsigned int minor)
{ {
return serial_table[minor]; return serial_table[minor];
...@@ -1132,11 +1162,17 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1132,11 +1162,17 @@ int usb_serial_probe(struct usb_interface *interface,
} }
} }
/* initialize the devfs nodes for this device and let the user know what ports we are bound to */ /* register all of the individual ports with the driver core */
for (i = 0; i < serial->num_ports; ++i) { for (i = 0; i < num_ports; ++i) {
tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number); port = &serial->port[i];
info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", port->dev.parent = &serial->dev->dev;
type->name, serial->port[i].number, serial->port[i].number); 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); usb_serial_console_init (debug, minor);
...@@ -1203,6 +1239,9 @@ void usb_serial_disconnect(struct usb_interface *interface) ...@@ -1203,6 +1239,9 @@ void usb_serial_disconnect(struct usb_interface *interface)
serial->dev = NULL; serial->dev = NULL;
serial_shutdown (serial); 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) for (i = 0; i < serial->num_ports; ++i)
serial->port[i].open_count = 0; serial->port[i].open_count = 0;
...@@ -1233,12 +1272,6 @@ void usb_serial_disconnect(struct usb_interface *interface) ...@@ -1233,12 +1272,6 @@ void usb_serial_disconnect(struct usb_interface *interface)
if (port->interrupt_in_buffer) if (port->interrupt_in_buffer)
kfree (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 the minor range that this device had */
return_serial (serial); return_serial (serial);
...@@ -1294,6 +1327,8 @@ static int __init usb_serial_init(void) ...@@ -1294,6 +1327,8 @@ static int __init usb_serial_init(void)
serial_table[i] = NULL; serial_table[i] = NULL;
} }
bus_register(&usb_serial_bus_type);
/* register the generic driver, if we should */ /* register the generic driver, if we should */
result = usb_serial_generic_register(debug); result = usb_serial_generic_register(debug);
if (result < 0) { if (result < 0) {
...@@ -1341,21 +1376,103 @@ static void __exit usb_serial_exit(void) ...@@ -1341,21 +1376,103 @@ static void __exit usb_serial_exit(void)
usb_deregister(&usb_serial_driver); usb_deregister(&usb_serial_driver);
tty_unregister_driver(&serial_tty_driver); tty_unregister_driver(&serial_tty_driver);
bus_unregister(&usb_serial_bus_type);
} }
module_init(usb_serial_init); module_init(usb_serial_init);
module_exit(usb_serial_exit); 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 usb_serial_register(struct usb_serial_device_type *new_device)
{ {
int retval;
/* Add this device to our list of devices */ /* Add this device to our list of devices */
list_add(&new_device->driver_list, &usb_serial_driver_list); 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;
return 0; 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 retval;
} }
......
...@@ -121,7 +121,9 @@ struct usb_serial_port { ...@@ -121,7 +121,9 @@ struct usb_serial_port {
int open_count; int open_count;
struct semaphore sem; struct semaphore sem;
void * private; 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 * usb_serial - structure used by the usb-serial core for a device
...@@ -206,13 +208,17 @@ struct usb_serial_device_type { ...@@ -206,13 +208,17 @@ struct usb_serial_device_type {
char num_ports; char num_ports;
struct list_head driver_list; struct list_head driver_list;
struct device_driver driver;
int (*probe) (struct usb_serial *serial); int (*probe) (struct usb_serial *serial);
int (*attach) (struct usb_serial *serial); int (*attach) (struct usb_serial *serial);
int (*calc_num_ports) (struct usb_serial *serial); int (*calc_num_ports) (struct usb_serial *serial);
void (*shutdown) (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 */ /* serial function calls */
int (*open) (struct usb_serial_port *port, struct file * filp); int (*open) (struct usb_serial_port *port, struct file * filp);
void (*close) (struct usb_serial_port *port, struct file * filp); void (*close) (struct usb_serial_port *port, struct file * filp);
...@@ -229,6 +235,7 @@ struct usb_serial_device_type { ...@@ -229,6 +235,7 @@ struct usb_serial_device_type {
void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs); void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs);
void (*write_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 int usb_serial_register(struct usb_serial_device_type *new_device);
extern void usb_serial_deregister(struct usb_serial_device_type *device); extern void usb_serial_deregister(struct usb_serial_device_type *device);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment