+static decl_subsys(bus, &ktype_bus, NULL);
+
+
+#ifdef CONFIG_HOTPLUG
+
+/* Manually detach a device from its associated driver. */
+static int driver_helper(struct device *dev, void *data)
+{
+ const char *name = data;
+
+ if (strcmp(name, dev->bus_id) == 0)
+ return 1;
+ return 0;
+}
+
+static ssize_t driver_unbind(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ struct bus_type *bus = get_bus(drv->bus);
+ struct device *dev;
+ int err = -ENODEV;
+
+ dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+ if (dev && dev->driver == drv) {
+ if (dev->parent) /* Needed for USB */
+ down(&dev->parent->sem);
+ device_release_driver(dev);
+ if (dev->parent)
+ up(&dev->parent->sem);
+ err = count;
+ }
+ put_device(dev);
+ put_bus(bus);
+ return err;
+}
+static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
+
+/*
+ * Manually attach a device to a driver.
+ * Note: the driver must want to bind to the device,
+ * it is not possible to override the driver's id table.
+ */
+static ssize_t driver_bind(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ struct bus_type *bus = get_bus(drv->bus);
+ struct device *dev;
+ int err = -ENODEV;
+
+ dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+ if (dev && dev->driver == NULL) {
+ if (dev->parent) /* Needed for USB */
+ down(&dev->parent->sem);
+ down(&dev->sem);
+ err = driver_probe_device(drv, dev);
+ up(&dev->sem);
+ if (dev->parent)
+ up(&dev->parent->sem);
+
+ if (err > 0) /* success */
+ err = count;
+ else if (err == 0) /* driver didn't accept device */
+ err = -ENODEV;
+ }
+ put_device(dev);
+ put_bus(bus);
+ return err;
+}
+static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
+
+#endif
+
+static struct device * next_device(struct klist_iter * i)
+{
+ struct klist_node * n = klist_next(i);
+ return n ? container_of(n, struct device, knode_bus) : NULL;
+}