From: Mark McLoughlin <markmc@redhat.com> Date: Tue, 14 Apr 2009 18:43:58 +0100 Subject: [misc] add /sys/bus/*/driver_probe Message-id: 1239731038.8530.93.camel@blaa O-Subject: [RHEL5.4 PATCH 1/5] [driver core] add /sys/bus/*/driver_probe Bugzilla: 491842 RH-Acked-by: Prarit Bhargava <prarit@redhat.com> RH-Acked-by: Don Dutile <ddutile@redhat.com> RH-Acked-by: Chris Wright <chrisw@redhat.com> https://bugzilla.redhat.com/491842 This patch adds a new per-bus sysfs file: # ls -l /sys/subsystem/usb drwxr-xr-x 2 root root 0 2007-02-16 16:42 devices drwxr-xr-x 7 root root 0 2007-02-16 14:55 drivers --w------- 1 root root 4096 2007-02-16 16:42 drivers_probe The command "drivers_probe" accepts a bus_id and the bus tries to bind a driver to this device. This is needed by libvirt in order to re-bind the real device driver to a PCI device once a guest is finished using it. This is a backport of a patch which also included a drivers_autprobe command. The original commit is here: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=b8c5cec23d Signed-off-by: Mark McLoughlin <markmc@redhat.com> diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 2643bf8..2beb313 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -27,6 +27,8 @@ #define to_driver(obj) container_of(obj, struct device_driver, kobj) +static int bus_rescan_devices_helper(struct device *dev, void *data); + static ssize_t drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { @@ -199,6 +201,18 @@ static ssize_t driver_bind(struct device_driver *drv, } static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); +static ssize_t store_drivers_probe(struct bus_type *bus, + const char *buf, size_t count) +{ + struct device *dev; + + dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); + if (!dev) + return -ENODEV; + if (bus_rescan_devices_helper(dev, NULL) != 0) + return -EINVAL; + return count; +} #endif static struct device * next_device(struct klist_iter * i) @@ -466,9 +480,23 @@ static void remove_bind_files(struct device_driver *drv) driver_remove_file(drv, &driver_attr_bind); driver_remove_file(drv, &driver_attr_unbind); } + +static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe); + +static int add_probe_files(struct bus_type *bus) +{ + return bus_create_file(bus, &bus_attr_drivers_probe); +} + +static void remove_probe_files(struct bus_type *bus) +{ + bus_remove_file(bus, &bus_attr_drivers_probe); +} #else static inline void add_bind_files(struct device_driver *drv) {} static inline void remove_bind_files(struct device_driver *drv) {} +static inline int add_probe_files(struct bus_type *bus) { return 0; } +static inline void remove_probe_files(struct bus_type *bus) {} #endif /** @@ -786,11 +814,18 @@ int bus_register(struct bus_type * bus) klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); klist_init(&bus->klist_drivers, klist_drivers_get, klist_drivers_put); + + retval = add_probe_files(bus); + if (retval) + goto bus_probe_files_fail; + bus_add_attrs(bus); pr_debug("bus type '%s' registered\n", bus->name); return 0; +bus_probe_files_fail: + kset_unregister(&bus->drivers); bus_drivers_fail: kset_unregister(&bus->devices); bus_devices_fail: @@ -833,6 +868,7 @@ void bus_unregister(struct bus_type * bus) pr_debug("bus %s: unregistering\n", bus->name); free_notifier_for_bus(bus); bus_remove_attrs(bus); + remove_probe_files(bus); kset_unregister(&bus->drivers); kset_unregister(&bus->devices); subsystem_unregister(&bus->subsys);