# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.577 -> 1.578 # drivers/usb/core/hub.h 1.12 -> 1.13 # drivers/usb/core/hcd.h 1.15 -> 1.16 # include/linux/usb.h 1.48 -> 1.49 # drivers/usb/core/devices.c 1.17 -> 1.18 # drivers/usb/core/hub.c 1.34 -> 1.35 # drivers/usb/core/devio.c 1.33 -> 1.34 # drivers/usb/core/usb.c 1.84 -> 1.85 # drivers/usb/core/hcd.c 1.33 -> 1.34 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/09/16 greg@kroah.com 1.578 # USB: Convert the core code to use struct device_driver. # -------------------------------------------- # diff -Nru a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c --- a/drivers/usb/core/devices.c Mon Sep 16 15:00:43 2002 +++ b/drivers/usb/core/devices.c Mon Sep 16 15:00:43 2002 @@ -111,7 +111,6 @@ /* * Need access to the driver and USB bus lists. - * extern struct list_head usb_driver_list; * extern struct list_head usb_bus_list; * However, these will come from functions that return ptrs to each of them. */ diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c --- a/drivers/usb/core/devio.c Mon Sep 16 15:00:43 2002 +++ b/drivers/usb/core/devio.c Mon Sep 16 15:00:43 2002 @@ -298,15 +298,15 @@ * they're also undone when devices disconnect. */ -static void *driver_probe(struct usb_device *dev, unsigned int intf, - const struct usb_device_id *id) +static int driver_probe (struct usb_interface *intf, + 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) return; @@ -317,6 +317,7 @@ /* prevent new I/O requests */ ps->dev = 0; ps->ifclaimed = 0; + dev_set_drvdata (&intf->dev, NULL); /* force async requests to complete */ destroy_all_async (ps); @@ -427,30 +428,6 @@ 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) { int ret; @@ -723,11 +700,10 @@ if (test_bit(i, &ps->ifclaimed)) continue; - lock_kernel(); + err ("%s - this function is broken", __FUNCTION__); if (intf->driver && ps->dev) { - usb_bind_driver (intf->driver, intf); + usb_device_probe (&intf->dev); } - unlock_kernel(); } return 0; @@ -1090,22 +1066,19 @@ /* disconnect kernel driver from interface, leaving it unbound. */ case USBDEVFS_DISCONNECT: - /* this function is voodoo. without locking it is a maybe thing */ - lock_kernel(); - driver = ifp->driver; - if (driver) { - dbg ("disconnect '%s' from dev %d interface %d", - driver->name, ps->dev->devnum, ctrl.ifno); - usb_unbind_driver(ps->dev, ifp); - usb_driver_release_interface (driver, ifp); - } else + /* this function is voodoo. */ + driver = ifp->driver; + if (driver) { + dbg ("disconnect '%s' from dev %d interface %d", + driver->name, ps->dev->devnum, ctrl.ifno); + usb_device_remove(&ifp->dev); + } else retval = -EINVAL; - unlock_kernel(); - break; + break; /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: - usb_find_interface_driver (ps->dev, ifp); + retval = usb_device_probe (&ifp->dev); break; /* talk directly to the interface's driver */ diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Mon Sep 16 15:00:43 2002 +++ b/drivers/usb/core/hcd.c Mon Sep 16 15:00:43 2002 @@ -722,12 +722,10 @@ { int retval; - usb_dev->dev.parent = parent_dev; - strcpy (&usb_dev->dev.name[0], "usb_name"); - strcpy (&usb_dev->dev.bus_id[0], "usb_bus"); - retval = usb_new_device (usb_dev); + sprintf (&usb_dev->dev.bus_id[0], "usb%d", usb_dev->bus->busnum); + retval = usb_new_device (usb_dev, parent_dev); if (retval) - put_device (&usb_dev->dev); + err("%s - usb_new_device failed with value %d", __FUNCTION__, retval); return retval; } EXPORT_SYMBOL (usb_register_root_hub); diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h Mon Sep 16 15:00:43 2002 +++ b/drivers/usb/core/hcd.h Mon Sep 16 15:00:43 2002 @@ -270,7 +270,7 @@ /* -------------------------------------------------------------------------- */ /* 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_disconnect(struct usb_device **); @@ -395,12 +395,6 @@ #define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep))) #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 diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Mon Sep 16 15:00:43 2002 +++ b/drivers/usb/core/hub.c Mon Sep 16 15:00:43 2002 @@ -175,6 +175,7 @@ while (!list_empty (&hub->tt.clear_list)) { struct list_head *temp; struct usb_tt_clear *clear; + struct usb_device *dev; int status; temp = hub->tt.clear_list.next; @@ -183,13 +184,13 @@ /* drop lock so HCD can concurrently report other TT errors */ spin_unlock_irqrestore (&hub->tt.lock, flags); - status = hub_clear_tt_buffer (hub->dev, - clear->devinfo, clear->tt); + dev = interface_to_usbdev (hub->intf); + status = hub_clear_tt_buffer (dev, clear->devinfo, clear->tt); spin_lock_irqsave (&hub->tt.lock, flags); if (status) 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); kfree (clear); } @@ -245,12 +246,14 @@ static void usb_hub_power_on(struct usb_hub *hub) { + struct usb_device *dev; int i; /* Enable power to the ports */ dbg("enabling power on all ports"); + dev = interface_to_usbdev(hub->intf); 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_ms(hub->descriptor->bPwrOn2PwrGood * 2); @@ -259,7 +262,7 @@ static int usb_hub_configure(struct usb_hub *hub, 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; unsigned int pipe; int maxp, ret; @@ -425,39 +428,81 @@ return 0; } -static void *hub_probe(struct usb_device *dev, unsigned int i, - const struct usb_device_id *id) +static void hub_disconnect(struct usb_interface *intf) { - 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_device *dev; struct usb_hub *hub; 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 */ /* specs is not defined, but it works */ - if ((interface->bInterfaceSubClass != 0) && - (interface->bInterfaceSubClass != 1)) { + if ((desc->bInterfaceSubClass != 0) && + (desc->bInterfaceSubClass != 1)) { err("invalid subclass (%d) for USB hub device #%d", - interface->bInterfaceSubClass, dev->devnum); - return NULL; + desc->bInterfaceSubClass, dev->devnum); + return -EIO; } /* 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", - interface->bNumEndpoints, dev->devnum); - return NULL; + desc->bNumEndpoints, dev->devnum); + return -EIO; } - endpoint = &interface->endpoint[0]; + endpoint = &desc->endpoint[0]; /* Output endpoint? Curiousier and curiousier.. */ if (!(endpoint->bEndpointAddress & USB_DIR_IN)) { err("Device #%d is hub class, but has output endpoint?", dev->devnum); - return NULL; + return -EIO; } /* If it's not an interrupt endpoint, we'd better punt! */ @@ -465,7 +510,7 @@ != USB_ENDPOINT_XFER_INT) { err("Device #%d is hub class, but endpoint is not interrupt?", dev->devnum); - return NULL; + return -EIO; } /* We found a hub */ @@ -474,13 +519,13 @@ hub = kmalloc(sizeof(*hub), GFP_KERNEL); if (!hub) { err("couldn't kmalloc hub struct"); - return NULL; + return -ENOMEM; } memset(hub, 0, sizeof(*hub)); INIT_LIST_HEAD(&hub->event_list); - hub->dev = dev; + hub->intf = intf; init_MUTEX(&hub->khubd_sem); /* Record the new hub's existence */ @@ -489,65 +534,17 @@ list_add(&hub->hub_list, &hub_list); spin_unlock_irqrestore(&hub_event_lock, flags); + dev_set_drvdata (&intf->dev, hub); + if (usb_hub_configure(hub, endpoint) >= 0) { - strcpy (dev->actconfig->interface[i].dev.name, - "Hub/Port Status Changes"); - return hub; + strcpy (intf->dev.name, "Hub/Port Status Changes"); + return 0; } err("hub configuration failed for device at %s", dev->devpath); - /* free hub, but first clean up its list. */ - 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); - - 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); + hub_disconnect (intf); + return -ENODEV; } static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data) @@ -584,7 +581,7 @@ 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; /* Disconnect any attached devices */ @@ -796,7 +793,7 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, u16 portstatus, u16 portchange) { - struct usb_device *hub = hubstate->dev; + struct usb_device *hub = interface_to_usbdev(hubstate->intf); struct usb_device *dev; unsigned int delay = HUB_SHORT_RESET_TIME; int i; @@ -891,11 +888,10 @@ /* put the device in the global device tree. the hub port * is the "bus_id"; hubs show in hierarchy like bridges */ - dev->dev.parent = &dev->parent->dev; - sprintf (&dev->dev.bus_id[0], "%d", port + 1); + dev->dev.parent = dev->parent->dev.parent->parent; /* Run it through the hoops (find a driver, etc) */ - if (!usb_new_device(dev)) + if (!usb_new_device(dev, &hub->dev)) goto done; /* Free the configuration if there was an error */ @@ -940,7 +936,7 @@ tmp = hub_event_list.next; hub = list_entry(tmp, struct usb_hub, event_list); - dev = hub->dev; + dev = interface_to_usbdev(hub->intf); list_del(tmp); INIT_LIST_HEAD(tmp); @@ -1081,8 +1077,8 @@ static struct usb_driver hub_driver = { .name = "hub", .probe = hub_probe, - .ioctl = hub_ioctl, .disconnect = hub_disconnect, + .ioctl = hub_ioctl, .id_table = hub_id_table, }; diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h --- a/drivers/usb/core/hub.h Mon Sep 16 15:00:43 2002 +++ b/drivers/usb/core/hub.h Mon Sep 16 15:00:43 2002 @@ -170,7 +170,7 @@ extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe); struct usb_hub { - struct usb_device *dev; /* the "real" device */ + struct usb_interface *intf; /* the "real" device */ struct urb *urb; /* for interrupt polling pipe */ /* buffer for urb ... 1 bit each for hub and children, rounded up */ diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Mon Sep 16 15:00:43 2002 +++ b/drivers/usb/core/usb.c Mon Sep 16 15:00:43 2002 @@ -48,225 +48,139 @@ extern int usb_major_init(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); -/** - * 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) +static int generic_probe (struct device *dev) { - int retval = 0; - - info("registered new driver %s", new_driver->name); - - init_MUTEX(&new_driver->serialize); - - /* Add it to the list of known drivers */ - list_add_tail(&new_driver->driver_list, &usb_driver_list); + return 0; +} +static int generic_remove (struct device *dev) +{ + return 0; +} +static void generic_release (struct device_driver * drv) +{ +} - 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; + } -/** - * usb_scan_devices - scans all unclaimed USB interfaces - * Context: !in_interrupt () - * - * Goes through all unclaimed USB interfaces, and offers them to all - * registered USB drivers through the 'probe' function. - * This will automatically be called after usb_register is called. - * It is called by some of the subsystems layered over USB - * after one of their subdrivers are registered. - */ -void usb_scan_devices(void) -{ - struct list_head *tmp; + id = usb_match_id (intf, driver->id_table); + if (id) { + dbg ("%s - got id", __FUNCTION__); + down (&driver->serialize); + error = driver->probe (intf, id); + up (&driver->serialize); + } + if (!error) + intf->driver = driver; - 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); + if (driver->owner) + __MOD_DEC_USE_COUNT(driver->owner); - tmp = tmp->next; - usb_check_support(bus->root_hub); - } - up (&usb_bus_list_lock); + return error; } -/** - * 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) +int usb_device_remove(struct device *dev) { + struct usb_interface *intf; struct usb_driver *driver; - void *priv; int m; - - driver = intf->driver; - priv = intf->private_data; - - if (!driver || !driver->disconnect) - return; + intf = list_entry(dev,struct usb_interface,dev); + driver = to_usb_driver(dev->driver); + + if (!driver) { + 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) { m = try_inc_mod_count(driver->owner); if (m == 0) { 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); - if (driver->owner) { - lock_kernel(); + if (driver->owner) __MOD_DEC_USE_COUNT(driver->owner); - } + + return 0; } /** - * usb_bind_driver - connect a driver to a device's interface (usbcore-internal) - * @driver: device driver to be bound to interface - * @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 - * drivers and neither calls the driver's probe() entry nor does any - * locking to guard against removing driver modules. + * 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. */ -void * -usb_bind_driver (struct usb_driver *driver, struct usb_interface *interface) +int usb_register(struct usb_driver *new_driver) { - int i,m; - 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; - } - } + int retval = 0; - /* if driver not bound, leave defaults unchanged */ - if (private == NULL) - interface->act_altsetting = 0; - } else { /* "old style" driver */ - down(&driver->serialize); - private = driver->probe(dev, ifnum, NULL); - up(&driver->serialize); - } - if (driver->owner) { - lock_kernel(); - __MOD_DEC_USE_COUNT(driver->owner); - } + new_driver->driver.name = (char *)new_driver->name; + new_driver->driver.bus = &usb_bus_type; + new_driver->driver.probe = usb_device_probe; + new_driver->driver.remove = usb_device_remove; - return private; -} + init_MUTEX(&new_driver->serialize); -/* - * 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; + retval = driver_register(&new_driver->driver); - if (!dev) { - err("null device being purged!!!"); - return; + if (!retval) { + info("registered new driver %s", new_driver->name); + usbfs_update_special(); + } else { + err("problem %d when registering driver %s", + retval, new_driver->name); } - for (i=0; ichildren[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); - } - } + return retval; } /** @@ -282,25 +196,9 @@ */ void usb_deregister(struct usb_driver *driver) { - struct list_head *tmp; - info("deregistering driver %s", driver->name); - /* - * 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); + remove_driver (&driver->driver); usbfs_update_special(); } @@ -359,34 +257,6 @@ 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; ichildren[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 * @driver: the driver to be bound @@ -418,7 +288,7 @@ iface->driver = driver; iface->private_data = priv; -} /* usb_driver_claim_interface() */ +} /** * usb_interface_claimed - returns true iff an interface is claimed @@ -463,7 +333,6 @@ iface->private_data = NULL; } - /** * usb_match_id - find first usb_device_id matching device or interface * @interface: the interface of interest @@ -595,72 +464,25 @@ return NULL; } -/* - * 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 -) +static int usb_device_match (struct device *dev, struct device_driver *drv) { - struct list_head *tmp; - void *private; - struct usb_driver *driver; - 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); + struct usb_interface *intf; + struct usb_driver *usb_drv; + const struct usb_device_id *id; - if (usb_interface_claimed(interface)) - goto out_err; + intf = to_usb_interface(dev); - 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 */ - interface = dev->actconfig->interface + ifnum; - - if (private) { - usb_driver_claim_interface(driver, interface, private); - up(&dev->serialize); - unlock_kernel(); - return 0; - } - } - unlock_kernel(); + usb_drv = to_usb_driver(drv); + id = usb_drv->id_table; + + id = usb_match_id (intf, usb_drv->id_table); + if (id) + return 1; -out_err: - up(&dev->serialize); - return -1; + return 0; } + #ifdef CONFIG_HOTPLUG /* @@ -890,71 +712,6 @@ } 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) * @parent: hub to which device is connected @@ -1109,32 +866,21 @@ info("USB disconnect on device %d", dev->devnum); - lock_kernel(); - 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.. */ + /* Free up all the children before we remove this device */ for (i = 0; i < USB_MAXCHILDREN; i++) { struct usb_device **child = dev->children + i; if (*child) usb_disconnect(child); } - /* Let policy agent unload modules etc */ - call_policy ("remove", dev); + if (dev->actconfig) { + 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 */ if (dev->devnum > 0) { @@ -1143,6 +889,9 @@ put_device(&dev->dev); } + /* Let policy agent unload modules etc */ + call_policy ("remove", dev); + /* Decrement the reference count, it'll auto free everything when */ /* it hits 0 which could very well be now */ usb_put_dev(dev); @@ -1271,7 +1020,7 @@ */ #define NEW_DEVICE_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 i; @@ -1361,10 +1110,23 @@ usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); #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); if (err) return err; + + /* add the USB device specific driverfs files */ device_create_file (&dev->dev, &dev_attr_configuration); if (dev->descriptor.iManufacturer) device_create_file (&dev->dev, &dev_attr_manufacturer); @@ -1373,11 +1135,38 @@ if (dev->descriptor.iSerialNumber) device_create_file (&dev->dev, &dev_attr_serial); - /* now that the basic setup is over, add a /proc/bus/usb entry */ - usbfs_add_device(dev); + /* Register all of the interfaces for this device with the driver core. + * 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 */ - usb_find_drivers(dev); + interface->dev.parent = &dev->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 */ call_policy ("add", dev); @@ -1385,7 +1174,6 @@ return 0; } - /** * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP * @dev: device the buffer will be used with @@ -1531,7 +1319,6 @@ ? USB_DIR_IN : USB_DIR_OUT); } - /** * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint * @dev: device to which the scatterlist will be mapped @@ -1642,20 +1429,10 @@ : 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 = { - .name = "usb", + .name = "usb", + .match = usb_device_match, }; /* @@ -1694,7 +1471,9 @@ EXPORT_SYMBOL(usb_register); 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_free_dev); diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Mon Sep 16 15:00:43 2002 +++ b/include/linux/usb.h Mon Sep 16 15:00:43 2002 @@ -227,7 +227,7 @@ int act_altsetting; /* active alternate setting */ int num_altsetting; /* number of alternate settings */ int max_altsetting; /* total memory allocated */ - + struct usb_driver *driver; /* driver */ struct device dev; /* interface specific device info */ void *private_data; @@ -399,9 +399,6 @@ extern void usb_free_dev(struct usb_device *); #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 */ extern int usb_reset_device(struct usb_device *dev); @@ -623,10 +620,10 @@ * expose information to user space regardless of where they * do (or don't) show up otherwise in the filesystem. * @id_table: USB drivers use ID table to support hotplugging. - * Export this with MODULE_DEVICE_TABLE(usb,...), or use NULL to - * say that probe() should be called for any unclaimed interfce. + * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set + * 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. * * The id_table is used in hotplugging. It holds a set of descriptors, @@ -643,32 +640,23 @@ */ struct usb_driver { struct module *owner; + const char *name; - void *(*probe)( - struct usb_device *dev, /* the device */ - 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() */ - ); + int (*probe) (struct usb_interface *intf, + const struct usb_device_id *id); - struct list_head driver_list; - struct semaphore serialize; + void (*disconnect) (struct usb_interface *intf); - /* ioctl -- userspace apps can talk to drivers through usbfs */ - 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; - /* suspend before the bus suspends; - * disconnect or resume when the bus resumes */ - /* void (*suspend)(struct usb_device *dev); */ - /* void (*resume)(struct usb_device *dev); */ + struct device_driver driver; + + struct semaphore serialize; }; +#define to_usb_driver(d) container_of(d, struct usb_driver, driver) extern struct bus_type usb_bus_type; @@ -681,6 +669,9 @@ 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 int usb_device_probe(struct device *dev); +extern int usb_device_remove(struct device *dev); /* -------------------------------------------------------------------------- */