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

USB: Convert the core code to use struct device_driver.

parent 7c3ccad2
...@@ -111,7 +111,6 @@ static char *format_endpt = ...@@ -111,7 +111,6 @@ static char *format_endpt =
/* /*
* Need access to the driver and USB bus lists. * Need access to the driver and USB bus lists.
* extern struct list_head usb_driver_list;
* extern struct list_head usb_bus_list; * extern struct list_head usb_bus_list;
* However, these will come from functions that return ptrs to each of them. * However, these will come from functions that return ptrs to each of them.
*/ */
......
...@@ -298,15 +298,15 @@ static void destroy_all_async(struct dev_state *ps) ...@@ -298,15 +298,15 @@ static void destroy_all_async(struct dev_state *ps)
* they're also undone when devices disconnect. * they're also undone when devices disconnect.
*/ */
static void *driver_probe(struct usb_device *dev, unsigned int intf, static int driver_probe (struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
return NULL; return -ENODEV;
} }
static void driver_disconnect(struct usb_device *dev, void *context) static void driver_disconnect(struct usb_interface *intf)
{ {
struct dev_state *ps = (struct dev_state *)context; struct dev_state *ps = dev_get_drvdata (&intf->dev);
if (!ps) if (!ps)
return; return;
...@@ -317,6 +317,7 @@ static void driver_disconnect(struct usb_device *dev, void *context) ...@@ -317,6 +317,7 @@ static void driver_disconnect(struct usb_device *dev, void *context)
/* prevent new I/O requests */ /* prevent new I/O requests */
ps->dev = 0; ps->dev = 0;
ps->ifclaimed = 0; ps->ifclaimed = 0;
dev_set_drvdata (&intf->dev, NULL);
/* force async requests to complete */ /* force async requests to complete */
destroy_all_async (ps); destroy_all_async (ps);
...@@ -427,30 +428,6 @@ static int findintfif(struct usb_device *dev, unsigned int ifn) ...@@ -427,30 +428,6 @@ static int findintfif(struct usb_device *dev, unsigned int ifn)
return -ENOENT; return -ENOENT;
} }
extern struct list_head usb_driver_list;
#if 0
static int finddriver(struct usb_driver **driver, char *name)
{
struct list_head *tmp;
tmp = usb_driver_list.next;
while (tmp != &usb_driver_list) {
struct usb_driver *d = list_entry(tmp, struct usb_driver,
driver_list);
if (!strcmp(d->name, name)) {
*driver = d;
return 0;
}
tmp = tmp->next;
}
return -EINVAL;
}
#endif
static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index) static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index)
{ {
int ret; int ret;
...@@ -723,11 +700,10 @@ static int proc_resetdevice(struct dev_state *ps) ...@@ -723,11 +700,10 @@ static int proc_resetdevice(struct dev_state *ps)
if (test_bit(i, &ps->ifclaimed)) if (test_bit(i, &ps->ifclaimed))
continue; continue;
lock_kernel(); err ("%s - this function is broken", __FUNCTION__);
if (intf->driver && ps->dev) { if (intf->driver && ps->dev) {
usb_bind_driver (intf->driver, intf); usb_device_probe (&intf->dev);
} }
unlock_kernel();
} }
return 0; return 0;
...@@ -1090,22 +1066,19 @@ static int proc_ioctl (struct dev_state *ps, void *arg) ...@@ -1090,22 +1066,19 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
/* disconnect kernel driver from interface, leaving it unbound. */ /* disconnect kernel driver from interface, leaving it unbound. */
case USBDEVFS_DISCONNECT: case USBDEVFS_DISCONNECT:
/* this function is voodoo. without locking it is a maybe thing */ /* this function is voodoo. */
lock_kernel(); driver = ifp->driver;
driver = ifp->driver; if (driver) {
if (driver) { dbg ("disconnect '%s' from dev %d interface %d",
dbg ("disconnect '%s' from dev %d interface %d", driver->name, ps->dev->devnum, ctrl.ifno);
driver->name, ps->dev->devnum, ctrl.ifno); usb_device_remove(&ifp->dev);
usb_unbind_driver(ps->dev, ifp); } else
usb_driver_release_interface (driver, ifp);
} else
retval = -EINVAL; retval = -EINVAL;
unlock_kernel(); break;
break;
/* let kernel drivers try to (re)bind to the interface */ /* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT: case USBDEVFS_CONNECT:
usb_find_interface_driver (ps->dev, ifp); retval = usb_device_probe (&ifp->dev);
break; break;
/* talk directly to the interface's driver */ /* talk directly to the interface's driver */
......
...@@ -722,12 +722,10 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev ...@@ -722,12 +722,10 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev
{ {
int retval; int retval;
usb_dev->dev.parent = parent_dev; sprintf (&usb_dev->dev.bus_id[0], "usb%d", usb_dev->bus->busnum);
strcpy (&usb_dev->dev.name[0], "usb_name"); retval = usb_new_device (usb_dev, parent_dev);
strcpy (&usb_dev->dev.bus_id[0], "usb_bus");
retval = usb_new_device (usb_dev);
if (retval) if (retval)
put_device (&usb_dev->dev); err("%s - usb_new_device failed with value %d", __FUNCTION__, retval);
return retval; return retval;
} }
EXPORT_SYMBOL (usb_register_root_hub); EXPORT_SYMBOL (usb_register_root_hub);
......
...@@ -270,7 +270,7 @@ extern void usb_hc_died (struct usb_hcd *hcd); ...@@ -270,7 +270,7 @@ extern void usb_hc_died (struct usb_hcd *hcd);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Enumeration is only for the hub driver, or HCD virtual root hubs */ /* Enumeration is only for the hub driver, or HCD virtual root hubs */
extern int usb_new_device(struct usb_device *dev); extern int usb_new_device(struct usb_device *dev, struct device *parent);
extern void usb_connect(struct usb_device *dev); extern void usb_connect(struct usb_device *dev);
extern void usb_disconnect(struct usb_device **); extern void usb_disconnect(struct usb_device **);
...@@ -396,12 +396,6 @@ extern int usb_find_interface_driver (struct usb_device *dev, ...@@ -396,12 +396,6 @@ extern int usb_find_interface_driver (struct usb_device *dev,
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
/* for probe/disconnect with correct module usage counting */
void *usb_bind_driver(struct usb_driver *driver, struct usb_interface *intf);
void usb_unbind_driver(struct usb_device *device, struct usb_interface *intf);
extern struct list_head usb_driver_list;
/* /*
* USB device fs stuff * USB device fs stuff
*/ */
......
...@@ -175,6 +175,7 @@ static void hub_tt_kevent (void *arg) ...@@ -175,6 +175,7 @@ static void hub_tt_kevent (void *arg)
while (!list_empty (&hub->tt.clear_list)) { while (!list_empty (&hub->tt.clear_list)) {
struct list_head *temp; struct list_head *temp;
struct usb_tt_clear *clear; struct usb_tt_clear *clear;
struct usb_device *dev;
int status; int status;
temp = hub->tt.clear_list.next; temp = hub->tt.clear_list.next;
...@@ -183,13 +184,13 @@ static void hub_tt_kevent (void *arg) ...@@ -183,13 +184,13 @@ static void hub_tt_kevent (void *arg)
/* drop lock so HCD can concurrently report other TT errors */ /* drop lock so HCD can concurrently report other TT errors */
spin_unlock_irqrestore (&hub->tt.lock, flags); spin_unlock_irqrestore (&hub->tt.lock, flags);
status = hub_clear_tt_buffer (hub->dev, dev = interface_to_usbdev (hub->intf);
clear->devinfo, clear->tt); status = hub_clear_tt_buffer (dev, clear->devinfo, clear->tt);
spin_lock_irqsave (&hub->tt.lock, flags); spin_lock_irqsave (&hub->tt.lock, flags);
if (status) if (status)
err ("usb-%s-%s clear tt %d (%04x) error %d", err ("usb-%s-%s clear tt %d (%04x) error %d",
hub->dev->bus->bus_name, hub->dev->devpath, dev->bus->bus_name, dev->devpath,
clear->tt, clear->devinfo, status); clear->tt, clear->devinfo, status);
kfree (clear); kfree (clear);
} }
...@@ -245,12 +246,14 @@ void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe) ...@@ -245,12 +246,14 @@ void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
static void usb_hub_power_on(struct usb_hub *hub) static void usb_hub_power_on(struct usb_hub *hub)
{ {
struct usb_device *dev;
int i; int i;
/* Enable power to the ports */ /* Enable power to the ports */
dbg("enabling power on all ports"); dbg("enabling power on all ports");
dev = interface_to_usbdev(hub->intf);
for (i = 0; i < hub->descriptor->bNbrPorts; i++) for (i = 0; i < hub->descriptor->bNbrPorts; i++)
usb_set_port_feature(hub->dev, i + 1, USB_PORT_FEAT_POWER); usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
/* Wait for power to be enabled */ /* Wait for power to be enabled */
wait_ms(hub->descriptor->bPwrOn2PwrGood * 2); wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
...@@ -259,7 +262,7 @@ static void usb_hub_power_on(struct usb_hub *hub) ...@@ -259,7 +262,7 @@ static void usb_hub_power_on(struct usb_hub *hub)
static int usb_hub_configure(struct usb_hub *hub, static int usb_hub_configure(struct usb_hub *hub,
struct usb_endpoint_descriptor *endpoint) struct usb_endpoint_descriptor *endpoint)
{ {
struct usb_device *dev = hub->dev; struct usb_device *dev = interface_to_usbdev (hub->intf);
struct usb_hub_status hubstatus; struct usb_hub_status hubstatus;
unsigned int pipe; unsigned int pipe;
int maxp, ret; int maxp, ret;
...@@ -425,39 +428,81 @@ static int usb_hub_configure(struct usb_hub *hub, ...@@ -425,39 +428,81 @@ static int usb_hub_configure(struct usb_hub *hub,
return 0; return 0;
} }
static void *hub_probe(struct usb_device *dev, unsigned int i, static void hub_disconnect(struct usb_interface *intf)
const struct usb_device_id *id)
{ {
struct usb_interface_descriptor *interface; struct usb_hub *hub = dev_get_drvdata (&intf->dev);
unsigned long flags;
if (!hub)
return;
dev_set_drvdata (&intf->dev, NULL);
spin_lock_irqsave(&hub_event_lock, flags);
/* Delete it and then reset it */
list_del(&hub->event_list);
INIT_LIST_HEAD(&hub->event_list);
list_del(&hub->hub_list);
INIT_LIST_HEAD(&hub->hub_list);
spin_unlock_irqrestore(&hub_event_lock, flags);
down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
up(&hub->khubd_sem);
/* assuming we used keventd, it must quiesce too */
if (hub->tt.hub)
flush_scheduled_tasks ();
if (hub->urb) {
usb_unlink_urb(hub->urb);
usb_free_urb(hub->urb);
hub->urb = NULL;
}
if (hub->descriptor) {
kfree(hub->descriptor);
hub->descriptor = NULL;
}
/* Free the memory */
kfree(hub);
}
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_interface_descriptor *desc;
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
struct usb_device *dev;
struct usb_hub *hub; struct usb_hub *hub;
unsigned long flags; unsigned long flags;
interface = &dev->actconfig->interface[i].altsetting[0]; desc = intf->altsetting + intf->act_altsetting;
dev = interface_to_usbdev(intf);
/* Some hubs have a subclass of 1, which AFAICT according to the */ /* Some hubs have a subclass of 1, which AFAICT according to the */
/* specs is not defined, but it works */ /* specs is not defined, but it works */
if ((interface->bInterfaceSubClass != 0) && if ((desc->bInterfaceSubClass != 0) &&
(interface->bInterfaceSubClass != 1)) { (desc->bInterfaceSubClass != 1)) {
err("invalid subclass (%d) for USB hub device #%d", err("invalid subclass (%d) for USB hub device #%d",
interface->bInterfaceSubClass, dev->devnum); desc->bInterfaceSubClass, dev->devnum);
return NULL; return -EIO;
} }
/* Multiple endpoints? What kind of mutant ninja-hub is this? */ /* Multiple endpoints? What kind of mutant ninja-hub is this? */
if (interface->bNumEndpoints != 1) { if (desc->bNumEndpoints != 1) {
err("invalid bNumEndpoints (%d) for USB hub device #%d", err("invalid bNumEndpoints (%d) for USB hub device #%d",
interface->bNumEndpoints, dev->devnum); desc->bNumEndpoints, dev->devnum);
return NULL; return -EIO;
} }
endpoint = &interface->endpoint[0]; endpoint = &desc->endpoint[0];
/* Output endpoint? Curiousier and curiousier.. */ /* Output endpoint? Curiousier and curiousier.. */
if (!(endpoint->bEndpointAddress & USB_DIR_IN)) { if (!(endpoint->bEndpointAddress & USB_DIR_IN)) {
err("Device #%d is hub class, but has output endpoint?", err("Device #%d is hub class, but has output endpoint?",
dev->devnum); dev->devnum);
return NULL; return -EIO;
} }
/* If it's not an interrupt endpoint, we'd better punt! */ /* If it's not an interrupt endpoint, we'd better punt! */
...@@ -465,7 +510,7 @@ static void *hub_probe(struct usb_device *dev, unsigned int i, ...@@ -465,7 +510,7 @@ static void *hub_probe(struct usb_device *dev, unsigned int i,
!= USB_ENDPOINT_XFER_INT) { != USB_ENDPOINT_XFER_INT) {
err("Device #%d is hub class, but endpoint is not interrupt?", err("Device #%d is hub class, but endpoint is not interrupt?",
dev->devnum); dev->devnum);
return NULL; return -EIO;
} }
/* We found a hub */ /* We found a hub */
...@@ -474,13 +519,13 @@ static void *hub_probe(struct usb_device *dev, unsigned int i, ...@@ -474,13 +519,13 @@ static void *hub_probe(struct usb_device *dev, unsigned int i,
hub = kmalloc(sizeof(*hub), GFP_KERNEL); hub = kmalloc(sizeof(*hub), GFP_KERNEL);
if (!hub) { if (!hub) {
err("couldn't kmalloc hub struct"); err("couldn't kmalloc hub struct");
return NULL; return -ENOMEM;
} }
memset(hub, 0, sizeof(*hub)); memset(hub, 0, sizeof(*hub));
INIT_LIST_HEAD(&hub->event_list); INIT_LIST_HEAD(&hub->event_list);
hub->dev = dev; hub->intf = intf;
init_MUTEX(&hub->khubd_sem); init_MUTEX(&hub->khubd_sem);
/* Record the new hub's existence */ /* Record the new hub's existence */
...@@ -489,65 +534,17 @@ static void *hub_probe(struct usb_device *dev, unsigned int i, ...@@ -489,65 +534,17 @@ static void *hub_probe(struct usb_device *dev, unsigned int i,
list_add(&hub->hub_list, &hub_list); list_add(&hub->hub_list, &hub_list);
spin_unlock_irqrestore(&hub_event_lock, flags); spin_unlock_irqrestore(&hub_event_lock, flags);
dev_set_drvdata (&intf->dev, hub);
if (usb_hub_configure(hub, endpoint) >= 0) { if (usb_hub_configure(hub, endpoint) >= 0) {
strcpy (dev->actconfig->interface[i].dev.name, strcpy (intf->dev.name, "Hub/Port Status Changes");
"Hub/Port Status Changes"); return 0;
return hub;
} }
err("hub configuration failed for device at %s", dev->devpath); err("hub configuration failed for device at %s", dev->devpath);
/* free hub, but first clean up its list. */ hub_disconnect (intf);
spin_lock_irqsave(&hub_event_lock, flags); return -ENODEV;
/* Delete it and then reset it */
list_del(&hub->event_list);
INIT_LIST_HEAD(&hub->event_list);
list_del(&hub->hub_list);
INIT_LIST_HEAD(&hub->hub_list);
spin_unlock_irqrestore(&hub_event_lock, flags);
kfree(hub);
return NULL;
}
static void hub_disconnect(struct usb_device *dev, void *ptr)
{
struct usb_hub *hub = (struct usb_hub *)ptr;
unsigned long flags;
spin_lock_irqsave(&hub_event_lock, flags);
/* Delete it and then reset it */
list_del(&hub->event_list);
INIT_LIST_HEAD(&hub->event_list);
list_del(&hub->hub_list);
INIT_LIST_HEAD(&hub->hub_list);
spin_unlock_irqrestore(&hub_event_lock, flags);
down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
up(&hub->khubd_sem);
/* assuming we used keventd, it must quiesce too */
if (hub->tt.hub)
flush_scheduled_tasks ();
if (hub->urb) {
usb_unlink_urb(hub->urb);
usb_free_urb(hub->urb);
hub->urb = NULL;
}
if (hub->descriptor) {
kfree(hub->descriptor);
hub->descriptor = NULL;
}
/* Free the memory */
kfree(hub);
} }
static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data) static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data)
...@@ -584,7 +581,7 @@ static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data) ...@@ -584,7 +581,7 @@ static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data)
static int usb_hub_reset(struct usb_hub *hub) static int usb_hub_reset(struct usb_hub *hub)
{ {
struct usb_device *dev = hub->dev; struct usb_device *dev = interface_to_usbdev(hub->intf);
int i; int i;
/* Disconnect any attached devices */ /* Disconnect any attached devices */
...@@ -796,7 +793,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port) ...@@ -796,7 +793,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port)
static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
u16 portstatus, u16 portchange) u16 portstatus, u16 portchange)
{ {
struct usb_device *hub = hubstate->dev; struct usb_device *hub = interface_to_usbdev(hubstate->intf);
struct usb_device *dev; struct usb_device *dev;
unsigned int delay = HUB_SHORT_RESET_TIME; unsigned int delay = HUB_SHORT_RESET_TIME;
int i; int i;
...@@ -891,11 +888,10 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -891,11 +888,10 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
/* put the device in the global device tree. the hub port /* put the device in the global device tree. the hub port
* is the "bus_id"; hubs show in hierarchy like bridges * is the "bus_id"; hubs show in hierarchy like bridges
*/ */
dev->dev.parent = &dev->parent->dev; dev->dev.parent = dev->parent->dev.parent->parent;
sprintf (&dev->dev.bus_id[0], "%d", port + 1);
/* Run it through the hoops (find a driver, etc) */ /* Run it through the hoops (find a driver, etc) */
if (!usb_new_device(dev)) if (!usb_new_device(dev, &hub->dev))
goto done; goto done;
/* Free the configuration if there was an error */ /* Free the configuration if there was an error */
...@@ -940,7 +936,7 @@ static void usb_hub_events(void) ...@@ -940,7 +936,7 @@ static void usb_hub_events(void)
tmp = hub_event_list.next; tmp = hub_event_list.next;
hub = list_entry(tmp, struct usb_hub, event_list); hub = list_entry(tmp, struct usb_hub, event_list);
dev = hub->dev; dev = interface_to_usbdev(hub->intf);
list_del(tmp); list_del(tmp);
INIT_LIST_HEAD(tmp); INIT_LIST_HEAD(tmp);
...@@ -1081,8 +1077,8 @@ MODULE_DEVICE_TABLE (usb, hub_id_table); ...@@ -1081,8 +1077,8 @@ MODULE_DEVICE_TABLE (usb, hub_id_table);
static struct usb_driver hub_driver = { static struct usb_driver hub_driver = {
.name = "hub", .name = "hub",
.probe = hub_probe, .probe = hub_probe,
.ioctl = hub_ioctl,
.disconnect = hub_disconnect, .disconnect = hub_disconnect,
.ioctl = hub_ioctl,
.id_table = hub_id_table, .id_table = hub_id_table,
}; };
......
...@@ -170,7 +170,7 @@ struct usb_tt_clear { ...@@ -170,7 +170,7 @@ struct usb_tt_clear {
extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe); extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe);
struct usb_hub { struct usb_hub {
struct usb_device *dev; /* the "real" device */ struct usb_interface *intf; /* the "real" device */
struct urb *urb; /* for interrupt polling pipe */ struct urb *urb; /* for interrupt polling pipe */
/* buffer for urb ... 1 bit each for hub and children, rounded up */ /* buffer for urb ... 1 bit each for hub and children, rounded up */
......
...@@ -48,225 +48,139 @@ extern void usb_hub_cleanup(void); ...@@ -48,225 +48,139 @@ extern void usb_hub_cleanup(void);
extern int usb_major_init(void); extern int usb_major_init(void);
extern void usb_major_cleanup(void); extern void usb_major_cleanup(void);
/*
* Prototypes for the device driver probing/loading functions
*/
static void usb_find_drivers(struct usb_device *);
static void usb_check_support(struct usb_device *);
/*
* We have a per-interface "registered driver" list.
*/
LIST_HEAD(usb_driver_list);
/** static int generic_probe (struct device *dev)
* usb_register - register a USB driver
* @new_driver: USB operations for the driver
*
* Registers a USB driver with the USB core. The list of unattached
* interfaces will be rescanned whenever a new driver is added, allowing
* the new driver to attach to any recognized devices.
* Returns a negative error code on failure and 0 on success.
*
* NOTE: if you want your driver to use the USB major number, you must call
* usb_register_dev() to enable that functionality. This function no longer
* takes care of that.
*/
int usb_register(struct usb_driver *new_driver)
{ {
int retval = 0; return 0;
}
info("registered new driver %s", new_driver->name); static int generic_remove (struct device *dev)
{
init_MUTEX(&new_driver->serialize); return 0;
}
/* Add it to the list of known drivers */ static void generic_release (struct device_driver * drv)
list_add_tail(&new_driver->driver_list, &usb_driver_list); {
}
usb_scan_devices(); static struct device_driver usb_generic_driver = {
.name = "generic usb driver",
.probe = generic_probe,
.remove = generic_remove,
.release = generic_release,
};
int usb_device_probe(struct device *dev)
{
struct usb_interface * intf = to_usb_interface(dev);
struct usb_driver * driver = to_usb_driver(dev->driver);
const struct usb_device_id *id;
int error = -ENODEV;
int m;
usbfs_update_special(); dbg("%s", __FUNCTION__);
return retval; if (!driver->probe)
} return error;
if (driver->owner) {
m = try_inc_mod_count(driver->owner);
if (m == 0)
return error;
}
/** id = usb_match_id (intf, driver->id_table);
* usb_scan_devices - scans all unclaimed USB interfaces if (id) {
* Context: !in_interrupt () dbg ("%s - got id", __FUNCTION__);
* down (&driver->serialize);
* Goes through all unclaimed USB interfaces, and offers them to all error = driver->probe (intf, id);
* registered USB drivers through the 'probe' function. up (&driver->serialize);
* This will automatically be called after usb_register is called. }
* It is called by some of the subsystems layered over USB if (!error)
* after one of their subdrivers are registered. intf->driver = driver;
*/
void usb_scan_devices(void)
{
struct list_head *tmp;
down (&usb_bus_list_lock); if (driver->owner)
tmp = usb_bus_list.next; __MOD_DEC_USE_COUNT(driver->owner);
while (tmp != &usb_bus_list) {
struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list);
tmp = tmp->next; return error;
usb_check_support(bus->root_hub);
}
up (&usb_bus_list_lock);
} }
/** int usb_device_remove(struct device *dev)
* usb_unbind_driver - disconnects a driver from a device (usbcore-internal)
* @device: usb device to be disconnected
* @intf: interface of the device to be disconnected
* Context: BKL held
*
* Handles module usage count correctly
*/
void usb_unbind_driver(struct usb_device *device, struct usb_interface *intf)
{ {
struct usb_interface *intf;
struct usb_driver *driver; struct usb_driver *driver;
void *priv;
int m; int m;
driver = intf->driver; intf = list_entry(dev,struct usb_interface,dev);
priv = intf->private_data; driver = to_usb_driver(dev->driver);
if (!driver || !driver->disconnect) if (!driver) {
return; err("%s does not have a valid driver to work with!",
__FUNCTION__);
return -ENODEV;
}
/* as soon as we increase the module use count we drop the BKL
before that we must not sleep */
if (driver->owner) { if (driver->owner) {
m = try_inc_mod_count(driver->owner); m = try_inc_mod_count(driver->owner);
if (m == 0) { if (m == 0) {
err("Dieing driver still bound to device.\n"); err("Dieing driver still bound to device.\n");
return; return -EIO;
} }
unlock_kernel();
} }
down(&driver->serialize); /* if we sleep here on an umanaged driver
the holder of the lock guards against
module unload */
driver->disconnect(device, priv); /* if we sleep here on an umanaged driver
* the holder of the lock guards against
* module unload */
down(&driver->serialize);
if (intf->driver && intf->driver->disconnect)
intf->driver->disconnect(intf);
/* if driver->disconnect didn't release the interface */
if (intf->driver)
usb_driver_release_interface(driver, intf);
up(&driver->serialize); up(&driver->serialize);
if (driver->owner) { if (driver->owner)
lock_kernel();
__MOD_DEC_USE_COUNT(driver->owner); __MOD_DEC_USE_COUNT(driver->owner);
}
return 0;
} }
/** /**
* usb_bind_driver - connect a driver to a device's interface (usbcore-internal) * usb_register - register a USB driver
* @driver: device driver to be bound to interface * @new_driver: USB operations for the driver
* @interface: interface that the driver will be using
* Context: BKL held
*
* Does a safe binding of a driver to one of a device's interfaces.
* Returns the driver's data for the binding, or null indicating
* that the driver did not bind to this interface.
* *
* This differs from usb_driver_claim_interface(), which is called from * Registers a USB driver with the USB core. The list of unattached
* drivers and neither calls the driver's probe() entry nor does any * interfaces will be rescanned whenever a new driver is added, allowing
* locking to guard against removing driver modules. * the new driver to attach to any recognized devices.
* Returns a negative error code on failure and 0 on success.
*
* NOTE: if you want your driver to use the USB major number, you must call
* usb_register_dev() to enable that functionality. This function no longer
* takes care of that.
*/ */
void * int usb_register(struct usb_driver *new_driver)
usb_bind_driver (struct usb_driver *driver, struct usb_interface *interface)
{ {
int i,m; int retval = 0;
void *private = NULL;
const struct usb_device_id *id;
struct usb_device *dev = interface_to_usbdev (interface);
int ifnum;
if (driver->owner) {
m = try_inc_mod_count(driver->owner);
if (m == 0)
return NULL; /* this horse is dead - don't ride*/
unlock_kernel();
}
// START TEMPORARY
// driver->probe() hasn't yet changed to take interface not dev+ifnum,
// so we still need ifnum here.
for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++)
if (&dev->actconfig->interface [ifnum] == interface)
break;
BUG_ON (ifnum == dev->actconfig->bNumInterfaces);
// END TEMPORARY
id = driver->id_table;
/* new style driver? */
if (id) {
for (i = 0; i < interface->num_altsetting; i++) {
interface->act_altsetting = i;
id = usb_match_id(interface, id);
if (id) {
down(&driver->serialize);
private = driver->probe(dev,ifnum,id);
up(&driver->serialize);
if (private != NULL)
break;
}
}
/* if driver not bound, leave defaults unchanged */ new_driver->driver.name = (char *)new_driver->name;
if (private == NULL) new_driver->driver.bus = &usb_bus_type;
interface->act_altsetting = 0; new_driver->driver.probe = usb_device_probe;
} else { /* "old style" driver */ new_driver->driver.remove = usb_device_remove;
down(&driver->serialize);
private = driver->probe(dev, ifnum, NULL);
up(&driver->serialize);
}
if (driver->owner) {
lock_kernel();
__MOD_DEC_USE_COUNT(driver->owner);
}
return private; init_MUTEX(&new_driver->serialize);
}
/* retval = driver_register(&new_driver->driver);
* This function is part of a depth-first search down the device tree,
* removing any instances of a device driver.
*/
static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
{
int i;
if (!dev) { if (!retval) {
err("null device being purged!!!"); info("registered new driver %s", new_driver->name);
return; usbfs_update_special();
} else {
err("problem %d when registering driver %s",
retval, new_driver->name);
} }
for (i=0; i<USB_MAXCHILDREN; i++) return retval;
if (dev->children[i])
usb_drivers_purge(driver, dev->children[i]);
if (!dev->actconfig)
return;
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
if (interface->driver == driver) {
usb_unbind_driver(dev, interface);
/* if driver->disconnect didn't release the interface */
if (interface->driver)
usb_driver_release_interface(driver, interface);
/*
* This will go through the list looking for another
* driver that can handle the device
*/
usb_find_interface_driver(dev, interface);
}
}
} }
/** /**
...@@ -282,25 +196,9 @@ static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev) ...@@ -282,25 +196,9 @@ static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
*/ */
void usb_deregister(struct usb_driver *driver) void usb_deregister(struct usb_driver *driver)
{ {
struct list_head *tmp;
info("deregistering driver %s", driver->name); info("deregistering driver %s", driver->name);
/* remove_driver (&driver->driver);
* first we remove the driver, to be sure it doesn't get used by
* another thread while we are stepping through removing entries
*/
list_del(&driver->driver_list);
down (&usb_bus_list_lock);
tmp = usb_bus_list.next;
while (tmp != &usb_bus_list) {
struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
tmp = tmp->next;
usb_drivers_purge(driver, bus->root_hub);
}
up (&usb_bus_list_lock);
usbfs_update_special(); usbfs_update_special();
} }
...@@ -359,34 +257,6 @@ struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, uns ...@@ -359,34 +257,6 @@ struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, uns
return NULL; return NULL;
} }
/*
* This function is for doing a depth-first search for devices which
* have support, for dynamic loading of driver modules.
*/
static void usb_check_support(struct usb_device *dev)
{
int i;
if (!dev) {
err("null device being checked!!!");
return;
}
for (i=0; i<USB_MAXCHILDREN; i++)
if (dev->children[i])
usb_check_support(dev->children[i]);
if (!dev->actconfig)
return;
/* now we check this device */
if (dev->devnum > 0)
for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
usb_find_interface_driver (dev,
dev->actconfig->interface + i);
}
/** /**
* usb_driver_claim_interface - bind a driver to an interface * usb_driver_claim_interface - bind a driver to an interface
* @driver: the driver to be bound * @driver: the driver to be bound
...@@ -418,7 +288,7 @@ void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface ...@@ -418,7 +288,7 @@ void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface
iface->driver = driver; iface->driver = driver;
iface->private_data = priv; iface->private_data = priv;
} /* usb_driver_claim_interface() */ }
/** /**
* usb_interface_claimed - returns true iff an interface is claimed * usb_interface_claimed - returns true iff an interface is claimed
...@@ -463,7 +333,6 @@ void usb_driver_release_interface(struct usb_driver *driver, struct usb_interfac ...@@ -463,7 +333,6 @@ void usb_driver_release_interface(struct usb_driver *driver, struct usb_interfac
iface->private_data = NULL; iface->private_data = NULL;
} }
/** /**
* usb_match_id - find first usb_device_id matching device or interface * usb_match_id - find first usb_device_id matching device or interface
* @interface: the interface of interest * @interface: the interface of interest
...@@ -595,72 +464,25 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id) ...@@ -595,72 +464,25 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
return NULL; return NULL;
} }
/* static int usb_device_match (struct device *dev, struct device_driver *drv)
* This entrypoint gets called for unclaimed interfaces.
*
* We now walk the list of registered USB drivers,
* looking for one that will accept this interface.
*
* "New Style" drivers use a table describing the devices and interfaces
* they handle. Those tables are available to user mode tools deciding
* whether to load driver modules for a new device.
*
* The probe return value is changed to be a private pointer. This way
* the drivers don't have to dig around in our structures to set the
* private pointer if they only need one interface.
*
* Returns: 0 if a driver accepted the interface, -1 otherwise
*/
int usb_find_interface_driver (
struct usb_device *dev,
struct usb_interface *interface
)
{ {
struct list_head *tmp; struct usb_interface *intf;
void *private; struct usb_driver *usb_drv;
struct usb_driver *driver; const struct usb_device_id *id;
int ifnum;
down(&dev->serialize);
/* FIXME It's just luck that for some devices with drivers that set
* configuration in probe(), the interface numbers still make sense.
* That's one of several unsafe assumptions involved in configuring
* devices, and in binding drivers to their interfaces.
*/
for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++)
if (&dev->actconfig->interface [ifnum] == interface)
break;
BUG_ON (ifnum == dev->actconfig->bNumInterfaces);
if (usb_interface_claimed(interface))
goto out_err;
private = NULL;
lock_kernel();
for (tmp = usb_driver_list.next; tmp != &usb_driver_list;) {
driver = list_entry(tmp, struct usb_driver, driver_list);
tmp = tmp->next;
private = usb_bind_driver(driver, interface);
/* probe() may have changed the config on us */ intf = to_usb_interface(dev);
interface = dev->actconfig->interface + ifnum;
if (private) { usb_drv = to_usb_driver(drv);
usb_driver_claim_interface(driver, interface, private); id = usb_drv->id_table;
up(&dev->serialize);
unlock_kernel(); id = usb_match_id (intf, usb_drv->id_table);
return 0; if (id)
} return 1;
}
unlock_kernel();
out_err: return 0;
up(&dev->serialize);
return -1;
} }
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
/* /*
...@@ -890,71 +712,6 @@ show_serial (struct device *dev, char *buf, size_t count, loff_t off) ...@@ -890,71 +712,6 @@ show_serial (struct device *dev, char *buf, size_t count, loff_t off)
} }
static DEVICE_ATTR(serial,S_IRUGO,show_serial,NULL); static DEVICE_ATTR(serial,S_IRUGO,show_serial,NULL);
/*
* This entrypoint gets called for each new device.
*
* All interfaces are scanned for matching drivers.
*/
static void usb_find_drivers(struct usb_device *dev)
{
unsigned ifnum;
unsigned rejected = 0;
unsigned claimed = 0;
/* FIXME should get called for each new configuration not just the
* first one for a device. switching configs (or altsettings) should
* undo driverfs and HCD state for the previous interfaces.
*/
for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
struct usb_interface *interface = &dev->actconfig->interface[ifnum];
struct usb_interface_descriptor *desc = interface->altsetting;
/* register this interface with driverfs */
interface->dev.parent = &dev->dev;
interface->dev.bus = &usb_bus_type;
sprintf (&interface->dev.bus_id[0], "%s-%s:%d",
dev->bus->bus_name, dev->devpath,
interface->altsetting->bInterfaceNumber);
if (!desc->iInterface
|| usb_string (dev, desc->iInterface,
interface->dev.name,
sizeof interface->dev.name) <= 0) {
/* typically devices won't bother with interface
* descriptions; this is the normal case. an
* interface's driver might describe it better.
* (also: iInterface is per-altsetting ...)
*/
sprintf (&interface->dev.name[0],
"usb-%s-%s interface %d",
dev->bus->bus_name, dev->devpath,
interface->altsetting->bInterfaceNumber);
}
device_register (&interface->dev);
device_create_file (&interface->dev, &dev_attr_altsetting);
/* if this interface hasn't already been claimed */
if (!usb_interface_claimed(interface)) {
if (usb_find_interface_driver(dev, interface))
rejected++;
else
claimed++;
}
}
if (rejected)
dbg("unhandled interfaces on device");
if (!claimed) {
warn("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.",
dev->devnum,
dev->descriptor.idVendor,
dev->descriptor.idProduct);
#ifdef DEBUG
usb_show_device(dev);
#endif
}
}
/** /**
* usb_alloc_dev - allocate a usb device structure (usbcore-internal) * usb_alloc_dev - allocate a usb device structure (usbcore-internal)
* @parent: hub to which device is connected * @parent: hub to which device is connected
...@@ -1109,32 +866,21 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -1109,32 +866,21 @@ void usb_disconnect(struct usb_device **pdev)
info("USB disconnect on device %d", dev->devnum); info("USB disconnect on device %d", dev->devnum);
lock_kernel(); /* Free up all the children before we remove this device */
if (dev->actconfig) {
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
struct usb_driver *driver = interface->driver;
if (driver) {
usb_unbind_driver(dev, interface);
/* if driver->disconnect didn't release the interface */
if (interface->driver)
usb_driver_release_interface(driver, interface);
}
/* remove our device node for this interface */
put_device(&interface->dev);
}
}
unlock_kernel();
/* Free up all the children.. */
for (i = 0; i < USB_MAXCHILDREN; i++) { for (i = 0; i < USB_MAXCHILDREN; i++) {
struct usb_device **child = dev->children + i; struct usb_device **child = dev->children + i;
if (*child) if (*child)
usb_disconnect(child); usb_disconnect(child);
} }
/* Let policy agent unload modules etc */ if (dev->actconfig) {
call_policy ("remove", dev); for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
/* remove this interface */
put_device(&interface->dev);
}
}
/* Free the device number and remove the /proc/bus/usb entry */ /* Free the device number and remove the /proc/bus/usb entry */
if (dev->devnum > 0) { if (dev->devnum > 0) {
...@@ -1143,6 +889,9 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -1143,6 +889,9 @@ void usb_disconnect(struct usb_device **pdev)
put_device(&dev->dev); put_device(&dev->dev);
} }
/* Let policy agent unload modules etc */
call_policy ("remove", dev);
/* Decrement the reference count, it'll auto free everything when */ /* Decrement the reference count, it'll auto free everything when */
/* it hits 0 which could very well be now */ /* it hits 0 which could very well be now */
usb_put_dev(dev); usb_put_dev(dev);
...@@ -1271,7 +1020,7 @@ static void set_device_description (struct usb_device *dev) ...@@ -1271,7 +1020,7 @@ static void set_device_description (struct usb_device *dev)
*/ */
#define NEW_DEVICE_RETRYS 2 #define NEW_DEVICE_RETRYS 2
#define SET_ADDRESS_RETRYS 2 #define SET_ADDRESS_RETRYS 2
int usb_new_device(struct usb_device *dev) int usb_new_device(struct usb_device *dev, struct device *parent)
{ {
int err = 0; int err = 0;
int i; int i;
...@@ -1361,10 +1110,23 @@ int usb_new_device(struct usb_device *dev) ...@@ -1361,10 +1110,23 @@ int usb_new_device(struct usb_device *dev)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif #endif
/* register this device in the driverfs tree */ /*
* Set the driver for the usb device to point to the "generic" driver.
* This prevents the main usb device from being sent to the usb bus
* probe function. Yes, it's a hack, but a nice one :)
*/
usb_generic_driver.bus = &usb_bus_type;
dev->dev.parent = parent;
dev->dev.driver = &usb_generic_driver;
dev->dev.bus = &usb_bus_type;
if (dev->dev.bus_id[0] == 0)
sprintf (&dev->dev.bus_id[0], "%d-%s",
dev->bus->busnum, dev->devpath);
err = device_register (&dev->dev); err = device_register (&dev->dev);
if (err) if (err)
return err; return err;
/* add the USB device specific driverfs files */
device_create_file (&dev->dev, &dev_attr_configuration); device_create_file (&dev->dev, &dev_attr_configuration);
if (dev->descriptor.iManufacturer) if (dev->descriptor.iManufacturer)
device_create_file (&dev->dev, &dev_attr_manufacturer); device_create_file (&dev->dev, &dev_attr_manufacturer);
...@@ -1373,11 +1135,38 @@ int usb_new_device(struct usb_device *dev) ...@@ -1373,11 +1135,38 @@ int usb_new_device(struct usb_device *dev)
if (dev->descriptor.iSerialNumber) if (dev->descriptor.iSerialNumber)
device_create_file (&dev->dev, &dev_attr_serial); device_create_file (&dev->dev, &dev_attr_serial);
/* now that the basic setup is over, add a /proc/bus/usb entry */ /* Register all of the interfaces for this device with the driver core.
usbfs_add_device(dev); * Remember, interfaces get bound to drivers, not devices. */
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
struct usb_interface_descriptor *desc = interface->altsetting;
/* find drivers willing to handle this device */ interface->dev.parent = &dev->dev;
usb_find_drivers(dev); interface->dev.bus = &usb_bus_type;
sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
dev->bus->busnum, dev->devpath,
interface->altsetting->bInterfaceNumber);
if (!desc->iInterface
|| usb_string (dev, desc->iInterface,
interface->dev.name,
sizeof interface->dev.name) <= 0) {
/* typically devices won't bother with interface
* descriptions; this is the normal case. an
* interface's driver might describe it better.
* (also: iInterface is per-altsetting ...)
*/
sprintf (&interface->dev.name[0],
"usb-%s-%s interface %d",
dev->bus->bus_name, dev->devpath,
interface->altsetting->bInterfaceNumber);
}
dbg ("%s - registering %s", __FUNCTION__, interface->dev.bus_id);
device_register (&interface->dev);
device_create_file (&interface->dev, &dev_attr_altsetting);
}
/* add a /proc/bus/usb entry */
usbfs_add_device(dev);
/* userspace may load modules and/or configure further */ /* userspace may load modules and/or configure further */
call_policy ("add", dev); call_policy ("add", dev);
...@@ -1385,7 +1174,6 @@ int usb_new_device(struct usb_device *dev) ...@@ -1385,7 +1174,6 @@ int usb_new_device(struct usb_device *dev)
return 0; return 0;
} }
/** /**
* usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP
* @dev: device the buffer will be used with * @dev: device the buffer will be used with
...@@ -1531,7 +1319,6 @@ void usb_buffer_unmap (struct urb *urb) ...@@ -1531,7 +1319,6 @@ void usb_buffer_unmap (struct urb *urb)
? USB_DIR_IN ? USB_DIR_IN
: USB_DIR_OUT); : USB_DIR_OUT);
} }
/** /**
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
* @dev: device to which the scatterlist will be mapped * @dev: device to which the scatterlist will be mapped
...@@ -1642,20 +1429,10 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, ...@@ -1642,20 +1429,10 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
: USB_DIR_OUT); : USB_DIR_OUT);
} }
#ifdef CONFIG_PROC_FS
struct list_head *usb_driver_get_list(void)
{
return &usb_driver_list;
}
struct list_head *usb_bus_get_list(void)
{
return &usb_bus_list;
}
#endif
struct bus_type usb_bus_type = { struct bus_type usb_bus_type = {
.name = "usb", .name = "usb",
.match = usb_device_match,
}; };
/* /*
...@@ -1694,7 +1471,9 @@ EXPORT_SYMBOL(usb_epnum_to_ep_desc); ...@@ -1694,7 +1471,9 @@ EXPORT_SYMBOL(usb_epnum_to_ep_desc);
EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister); EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_scan_devices);
EXPORT_SYMBOL(usb_device_probe);
EXPORT_SYMBOL(usb_device_remove);
EXPORT_SYMBOL(usb_alloc_dev); EXPORT_SYMBOL(usb_alloc_dev);
EXPORT_SYMBOL(usb_free_dev); EXPORT_SYMBOL(usb_free_dev);
......
...@@ -227,7 +227,7 @@ struct usb_interface { ...@@ -227,7 +227,7 @@ struct usb_interface {
int act_altsetting; /* active alternate setting */ int act_altsetting; /* active alternate setting */
int num_altsetting; /* number of alternate settings */ int num_altsetting; /* number of alternate settings */
int max_altsetting; /* total memory allocated */ int max_altsetting; /* total memory allocated */
struct usb_driver *driver; /* driver */ struct usb_driver *driver; /* driver */
struct device dev; /* interface specific device info */ struct device dev; /* interface specific device info */
void *private_data; void *private_data;
...@@ -399,9 +399,6 @@ extern struct usb_device *usb_get_dev(struct usb_device *dev); ...@@ -399,9 +399,6 @@ extern struct usb_device *usb_get_dev(struct usb_device *dev);
extern void usb_free_dev(struct usb_device *); extern void usb_free_dev(struct usb_device *);
#define usb_put_dev usb_free_dev #define usb_put_dev usb_free_dev
/* for when layers above USB add new non-USB drivers */
extern void usb_scan_devices(void);
/* mostly for devices emulating SCSI over USB */ /* mostly for devices emulating SCSI over USB */
extern int usb_reset_device(struct usb_device *dev); extern int usb_reset_device(struct usb_device *dev);
...@@ -623,10 +620,10 @@ struct usb_device_id { ...@@ -623,10 +620,10 @@ struct usb_device_id {
* expose information to user space regardless of where they * expose information to user space regardless of where they
* do (or don't) show up otherwise in the filesystem. * do (or don't) show up otherwise in the filesystem.
* @id_table: USB drivers use ID table to support hotplugging. * @id_table: USB drivers use ID table to support hotplugging.
* Export this with MODULE_DEVICE_TABLE(usb,...), or use NULL to * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set
* say that probe() should be called for any unclaimed interfce. * or your driver's probe function will never get called.
* *
* USB drivers should provide a name, probe() and disconnect() methods, * USB drivers must provide a name, probe() and disconnect() methods,
* and an id_table. Other driver fields are optional. * and an id_table. Other driver fields are optional.
* *
* The id_table is used in hotplugging. It holds a set of descriptors, * The id_table is used in hotplugging. It holds a set of descriptors,
...@@ -643,32 +640,23 @@ struct usb_device_id { ...@@ -643,32 +640,23 @@ struct usb_device_id {
*/ */
struct usb_driver { struct usb_driver {
struct module *owner; struct module *owner;
const char *name; const char *name;
void *(*probe)( int (*probe) (struct usb_interface *intf,
struct usb_device *dev, /* the device */ const struct usb_device_id *id);
unsigned intf, /* what interface */
const struct usb_device_id *id /* from id_table */
);
void (*disconnect)(
struct usb_device *dev, /* the device */
void *handle /* as returned by probe() */
);
struct list_head driver_list;
struct semaphore serialize;
/* ioctl -- userspace apps can talk to drivers through usbfs */ void (*disconnect) (struct usb_interface *intf);
int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
int (*ioctl) (struct usb_device *dev, unsigned int code, void *buf);
/* support for "new-style" USB hotplugging */
const struct usb_device_id *id_table; const struct usb_device_id *id_table;
/* suspend before the bus suspends; struct device_driver driver;
* disconnect or resume when the bus resumes */
/* void (*suspend)(struct usb_device *dev); */ struct semaphore serialize;
/* void (*resume)(struct usb_device *dev); */
}; };
#define to_usb_driver(d) container_of(d, struct usb_driver, driver)
extern struct bus_type usb_bus_type; extern struct bus_type usb_bus_type;
...@@ -682,6 +670,9 @@ extern void usb_deregister(struct usb_driver *); ...@@ -682,6 +670,9 @@ extern void usb_deregister(struct usb_driver *);
extern int usb_register_dev(struct file_operations *fops, int minor, int num_minors, int *start_minor); extern int usb_register_dev(struct file_operations *fops, int minor, int num_minors, int *start_minor);
extern void usb_deregister_dev(int num_minors, int start_minor); extern void usb_deregister_dev(int num_minors, int start_minor);
extern int usb_device_probe(struct device *dev);
extern int usb_device_remove(struct device *dev);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* /*
......
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