* cases, we know no other thread can recycle our address, since we must
* 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;
- int i = 0, value;
+ struct usb_interface *intf;
+ struct usb_device *usb_dev;
+ char *scratch;
+ int i = 0;
+ int length = 0;
- if (!hotplug_path [0])
- 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;
- }
+ dbg ("%s", __FUNCTION__);
- /* only one standardized param to hotplug command: type */
- argv [0] = hotplug_path;
- argv [1] = "usb";
- argv [2] = 0;
+ if (!dev)
+ return -ENODEV;
- /* minimal command environment */
- envp [i++] = "HOME=/";
- envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+ /* check for generic driver, we do not call do hotplug calls for it */
+ if (dev->driver == &usb_generic_driver)
+ return -ENODEV;
-#ifdef DEBUG
- /* hint that policy agent should enter no-stdout debug mode */
- envp [i++] = "DEBUG=kernel";
-#endif
- /* extensible set of named bus-specific parameters,
- * supporting multiple driver selection algorithms.
- */
- scratch = buf;
+ intf = to_usb_interface(dev);
+ if (!intf)
+ return -ENODEV;
- /* action: add, remove */
- envp [i++] = scratch;
- scratch += sprintf (scratch, "ACTION=%s", verb) + 1;
+ usb_dev = interface_to_usbdev (intf);
+ if (!usb_dev)
+ 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
/* If this is available, userspace programs can directly read
*
* FIXME reduce hardwired intelligence here
*/
- envp [i++] = "DEVFS=/proc/bus/usb";
envp [i++] = scratch;
- scratch += sprintf (scratch, "DEVICE=/proc/bus/usb/%03d/%03d",
- dev->bus->busnum, dev->devnum) + 1;
+ length += snprintf (scratch, buffer_size - length,
+ "%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
/* per-device configuration hacks are common */
envp [i++] = scratch;
- scratch += sprintf (scratch, "PRODUCT=%x/%x/%x",
- dev->descriptor.idVendor,
- dev->descriptor.idProduct,
- dev->descriptor.bcdDevice) + 1;
+ length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
+ usb_dev->descriptor.idVendor,
+ usb_dev->descriptor.idProduct,
+ usb_dev->descriptor.bcdDevice);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
+ return -ENOMEM;
+ ++length;
+ scratch += length;
/* class-based driver binding models */
envp [i++] = scratch;
- scratch += sprintf (scratch, "TYPE=%d/%d/%d",
- dev->descriptor.bDeviceClass,
- dev->descriptor.bDeviceSubClass,
- dev->descriptor.bDeviceProtocol) + 1;
- if (dev->descriptor.bDeviceClass == 0) {
- int alt = dev->actconfig->interface [0].act_altsetting;
+ length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",
+ usb_dev->descriptor.bDeviceClass,
+ usb_dev->descriptor.bDeviceSubClass,
+ usb_dev->descriptor.bDeviceProtocol);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
+ 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
* with current altsetting being a reasonable setting.
* device-specific binding policies.
*/
envp [i++] = scratch;
- scratch += sprintf (scratch, "INTERFACE=%d/%d/%d",
- dev->actconfig->interface [0].altsetting [alt].bInterfaceClass,
- dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass,
- dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol)
- + 1;
- /* INTERFACE-0, INTERFACE-1, ... ? */
+ length += snprintf (scratch, buffer_size - length,
+ "INTERFACE=%d/%d/%d",
+ intf->altsetting[alt].bInterfaceClass,
+ intf->altsetting[alt].bInterfaceSubClass,
+ intf->altsetting[alt].bInterfaceProtocol);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
+ return -ENOMEM;
+ ++length;
+ scratch += length;
+
}
envp [i++] = 0;
- /* assert: (scratch - buf) < sizeof buf */
- /* NOTE: user mode daemons can call the agents too */
-
- 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);
+ return 0;
}
#else
-static inline void
-call_policy (char *verb, struct usb_device *dev)
-{ }
+static int usb_hotplug (struct device *dev, char **envp,
+ char *buffer, int buffer_size)
+{
+ return -ENODEV;
+}
#endif /* CONFIG_HOTPLUG */
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);
/* add a /proc/bus/usb entry */
usbfs_add_device(dev);
- /* userspace may load modules and/or configure further */
- call_policy ("add", dev);
-
return 0;
}
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
+ .hotplug = usb_hotplug,
};
/*