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

converted USB to use the driver core's hotplug call.

parent 7b5eb7a9
...@@ -510,57 +510,42 @@ static int usb_device_match (struct device *dev, struct device_driver *drv) ...@@ -510,57 +510,42 @@ static int usb_device_match (struct device *dev, struct device_driver *drv)
* cases, we know no other thread can recycle our address, since we must * cases, we know no other thread can recycle our address, since we must
* already have been serialized enough to prevent that. * already have been serialized enough to prevent that.
*/ */
static void call_policy (char *verb, struct usb_device *dev) static int usb_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{ {
char *argv [3], **envp, *buf, *scratch; struct usb_interface *intf;
int i = 0, value; struct usb_device *usb_dev;
char *scratch;
int i = 0;
int length = 0;
if (!hotplug_path [0]) dbg ("%s", __FUNCTION__);
return;
if (in_interrupt ()) {
dbg ("In_interrupt");
return;
}
if (!current->fs->root) {
/* statically linked USB is initted rather early */
dbg ("call_policy %s, num %d -- no FS yet", verb, dev->devnum);
return;
}
if (dev->devnum < 0) {
dbg ("device already deleted ??");
return;
}
if (!(envp = (char **) kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
dbg ("enomem");
return;
}
if (!(buf = kmalloc (256, GFP_KERNEL))) {
kfree (envp);
dbg ("enomem2");
return;
}
/* only one standardized param to hotplug command: type */ if (!dev)
argv [0] = hotplug_path; return -ENODEV;
argv [1] = "usb";
argv [2] = 0;
/* minimal command environment */ /* check for generic driver, we do not call do hotplug calls for it */
envp [i++] = "HOME=/"; if (dev->driver == &usb_generic_driver)
envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; return -ENODEV;
#ifdef DEBUG intf = to_usb_interface(dev);
/* hint that policy agent should enter no-stdout debug mode */ if (!intf)
envp [i++] = "DEBUG=kernel"; return -ENODEV;
#endif
/* extensible set of named bus-specific parameters,
* supporting multiple driver selection algorithms.
*/
scratch = buf;
/* action: add, remove */ usb_dev = interface_to_usbdev (intf);
envp [i++] = scratch; if (!usb_dev)
scratch += sprintf (scratch, "ACTION=%s", verb) + 1; return -ENODEV;
if (usb_dev->devnum < 0) {
dbg ("device already deleted ??");
return -ENODEV;
}
if (!usb_dev->bus) {
dbg ("bus already removed?");
return -ENODEV;
}
scratch = buffer;
#ifdef CONFIG_USB_DEVICEFS #ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read /* If this is available, userspace programs can directly read
...@@ -569,27 +554,48 @@ static void call_policy (char *verb, struct usb_device *dev) ...@@ -569,27 +554,48 @@ static void call_policy (char *verb, struct usb_device *dev)
* *
* FIXME reduce hardwired intelligence here * FIXME reduce hardwired intelligence here
*/ */
envp [i++] = "DEVFS=/proc/bus/usb";
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "DEVICE=/proc/bus/usb/%03d/%03d", length += snprintf (scratch, buffer_size - length,
dev->bus->busnum, dev->devnum) + 1; "%s", "DEVFS=/proc/bus/usb");
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
#endif #endif
/* per-device configuration hacks are common */ /* per-device configuration hacks are common */
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "PRODUCT=%x/%x/%x", length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
dev->descriptor.idVendor, usb_dev->descriptor.idVendor,
dev->descriptor.idProduct, usb_dev->descriptor.idProduct,
dev->descriptor.bcdDevice) + 1; usb_dev->descriptor.bcdDevice);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
/* class-based driver binding models */ /* class-based driver binding models */
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "TYPE=%d/%d/%d", length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",
dev->descriptor.bDeviceClass, usb_dev->descriptor.bDeviceClass,
dev->descriptor.bDeviceSubClass, usb_dev->descriptor.bDeviceSubClass,
dev->descriptor.bDeviceProtocol) + 1; usb_dev->descriptor.bDeviceProtocol);
if (dev->descriptor.bDeviceClass == 0) { if ((buffer_size - length <= 0) || (i >= num_envp))
int alt = dev->actconfig->interface [0].act_altsetting; return -ENOMEM;
++length;
scratch += length;
if (usb_dev->descriptor.bDeviceClass == 0) {
int alt = intf->act_altsetting;
/* a simple/common case: one config, one interface, one driver /* a simple/common case: one config, one interface, one driver
* with current altsetting being a reasonable setting. * with current altsetting being a reasonable setting.
...@@ -597,31 +603,29 @@ static void call_policy (char *verb, struct usb_device *dev) ...@@ -597,31 +603,29 @@ static void call_policy (char *verb, struct usb_device *dev)
* device-specific binding policies. * device-specific binding policies.
*/ */
envp [i++] = scratch; envp [i++] = scratch;
scratch += sprintf (scratch, "INTERFACE=%d/%d/%d", length += snprintf (scratch, buffer_size - length,
dev->actconfig->interface [0].altsetting [alt].bInterfaceClass, "INTERFACE=%d/%d/%d",
dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass, intf->altsetting[alt].bInterfaceClass,
dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol) intf->altsetting[alt].bInterfaceSubClass,
+ 1; intf->altsetting[alt].bInterfaceProtocol);
/* INTERFACE-0, INTERFACE-1, ... ? */ if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
} }
envp [i++] = 0; envp [i++] = 0;
/* assert: (scratch - buf) < sizeof buf */
/* NOTE: user mode daemons can call the agents too */ return 0;
dbg ("kusbd: %s %s %d", argv [0], verb, dev->devnum);
value = call_usermodehelper (argv [0], argv, envp);
kfree (buf);
kfree (envp);
if (value != 0)
dbg ("kusbd policy returned 0x%x", value);
} }
#else #else
static inline void static int usb_hotplug (struct device *dev, char **envp,
call_policy (char *verb, struct usb_device *dev) char *buffer, int buffer_size)
{ } {
return -ENODEV;
}
#endif /* CONFIG_HOTPLUG */ #endif /* CONFIG_HOTPLUG */
...@@ -894,9 +898,6 @@ void usb_disconnect(struct usb_device **pdev) ...@@ -894,9 +898,6 @@ 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);
...@@ -1174,9 +1175,6 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -1174,9 +1175,6 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
/* add a /proc/bus/usb entry */ /* add a /proc/bus/usb entry */
usbfs_add_device(dev); usbfs_add_device(dev);
/* userspace may load modules and/or configure further */
call_policy ("add", dev);
return 0; return 0;
} }
...@@ -1439,6 +1437,7 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, ...@@ -1439,6 +1437,7 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
struct bus_type usb_bus_type = { struct bus_type usb_bus_type = {
.name = "usb", .name = "usb",
.match = usb_device_match, .match = usb_device_match,
.hotplug = usb_hotplug,
}; };
/* /*
......
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