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 =
/*
* 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.
*/
......
......@@ -298,15 +298,15 @@ static void destroy_all_async(struct dev_state *ps)
* 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 @@ static void driver_disconnect(struct usb_device *dev, void *context)
/* 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 @@ static int findintfif(struct usb_device *dev, unsigned int ifn)
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 @@ static int proc_resetdevice(struct dev_state *ps)
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 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
/* 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 */
......
......@@ -722,12 +722,10 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev
{
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);
......
......@@ -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 */
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 **);
......@@ -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))
/* 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
*/
......
......@@ -175,6 +175,7 @@ static void hub_tt_kevent (void *arg)
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 @@ static void hub_tt_kevent (void *arg)
/* 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 @@ void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
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 void usb_hub_power_on(struct usb_hub *hub)
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 @@ static int usb_hub_configure(struct usb_hub *hub,
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 @@ static void *hub_probe(struct usb_device *dev, unsigned int i,
!= 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 @@ static void *hub_probe(struct usb_device *dev, unsigned int i,
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 @@ static void *hub_probe(struct usb_device *dev, unsigned int i,
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 hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data)
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 int usb_hub_port_debounce(struct usb_device *hub, int port)
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 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
/* 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 @@ static void usb_hub_events(void)
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 @@ MODULE_DEVICE_TABLE (usb, hub_id_table);
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,
};
......
......@@ -170,7 +170,7 @@ struct usb_tt_clear {
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 */
......
......@@ -48,225 +48,139 @@ extern void usb_hub_cleanup(void);
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.
* usb_register - register a USB driver
* @new_driver: USB operations for the driver
*
* 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.
* 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; i<USB_MAXCHILDREN; i++)
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);
}
}
return retval;
}
/**
......@@ -282,25 +196,9 @@ static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
*/
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 @@ struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, uns
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
* @driver: the driver to be bound
......@@ -418,7 +288,7 @@ void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface
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 @@ void usb_driver_release_interface(struct usb_driver *driver, struct usb_interfac
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 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
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);
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);
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
/* probe() may have changed the config on us */
interface = dev->actconfig->interface + ifnum;
intf = to_usb_interface(dev);
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 @@ show_serial (struct device *dev, char *buf, size_t count, loff_t off)
}
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 @@ void usb_disconnect(struct usb_device **pdev)
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 @@ void usb_disconnect(struct usb_device **pdev)
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 @@ static void set_device_description (struct usb_device *dev)
*/
#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 @@ int usb_new_device(struct usb_device *dev)
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 @@ int usb_new_device(struct usb_device *dev)
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 @@ int usb_new_device(struct usb_device *dev)
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 @@ void usb_buffer_unmap (struct urb *urb)
? 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 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
: 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_epnum_to_ep_desc);
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);
......
......@@ -227,7 +227,7 @@ struct usb_interface {
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 struct usb_device *usb_get_dev(struct usb_device *dev);
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 @@ struct usb_device_id {
* 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_device_id {
*/
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() */
);
struct list_head driver_list;
struct semaphore serialize;
int (*probe) (struct usb_interface *intf,
const struct usb_device_id *id);
/* ioctl -- userspace apps can talk to drivers through usbfs */
int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
void (*disconnect) (struct usb_interface *intf);
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;
......@@ -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 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