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 */
......
This diff is collapsed.
......@@ -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