diff options
Diffstat (limited to 'drivers/base/dd.c')
-rw-r--r-- | drivers/base/dd.c | 92 |
1 files changed, 62 insertions, 30 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index c5d6bb4290ad..510e7884975f 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
@@ -26,33 +26,28 @@ | |||
26 | #define to_drv(node) container_of(node, struct device_driver, kobj.entry) | 26 | #define to_drv(node) container_of(node, struct device_driver, kobj.entry) |
27 | 27 | ||
28 | 28 | ||
29 | /** | 29 | static void driver_bound(struct device *dev) |
30 | * device_bind_driver - bind a driver to one device. | ||
31 | * @dev: device. | ||
32 | * | ||
33 | * Allow manual attachment of a driver to a device. | ||
34 | * Caller must have already set @dev->driver. | ||
35 | * | ||
36 | * Note that this does not modify the bus reference count | ||
37 | * nor take the bus's rwsem. Please verify those are accounted | ||
38 | * for before calling this. (It is ok to call with no other effort | ||
39 | * from a driver's probe() method.) | ||
40 | * | ||
41 | * This function must be called with @dev->sem held. | ||
42 | */ | ||
43 | int device_bind_driver(struct device *dev) | ||
44 | { | 30 | { |
45 | int ret; | ||
46 | |||
47 | if (klist_node_attached(&dev->knode_driver)) { | 31 | if (klist_node_attached(&dev->knode_driver)) { |
48 | printk(KERN_WARNING "%s: device %s already bound\n", | 32 | printk(KERN_WARNING "%s: device %s already bound\n", |
49 | __FUNCTION__, kobject_name(&dev->kobj)); | 33 | __FUNCTION__, kobject_name(&dev->kobj)); |
50 | return 0; | 34 | return; |
51 | } | 35 | } |
52 | 36 | ||
53 | pr_debug("bound device '%s' to driver '%s'\n", | 37 | pr_debug("bound device '%s' to driver '%s'\n", |
54 | dev->bus_id, dev->driver->name); | 38 | dev->bus_id, dev->driver->name); |
39 | |||
40 | if (dev->bus) | ||
41 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | ||
42 | BUS_NOTIFY_BOUND_DRIVER, dev); | ||
43 | |||
55 | klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); | 44 | klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); |
45 | } | ||
46 | |||
47 | static int driver_sysfs_add(struct device *dev) | ||
48 | { | ||
49 | int ret; | ||
50 | |||
56 | ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, | 51 | ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, |
57 | kobject_name(&dev->kobj)); | 52 | kobject_name(&dev->kobj)); |
58 | if (ret == 0) { | 53 | if (ret == 0) { |
@@ -65,6 +60,36 @@ int device_bind_driver(struct device *dev) | |||
65 | return ret; | 60 | return ret; |
66 | } | 61 | } |
67 | 62 | ||
63 | static void driver_sysfs_remove(struct device *dev) | ||
64 | { | ||
65 | struct device_driver *drv = dev->driver; | ||
66 | |||
67 | if (drv) { | ||
68 | sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); | ||
69 | sysfs_remove_link(&dev->kobj, "driver"); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * device_bind_driver - bind a driver to one device. | ||
75 | * @dev: device. | ||
76 | * | ||
77 | * Allow manual attachment of a driver to a device. | ||
78 | * Caller must have already set @dev->driver. | ||
79 | * | ||
80 | * Note that this does not modify the bus reference count | ||
81 | * nor take the bus's rwsem. Please verify those are accounted | ||
82 | * for before calling this. (It is ok to call with no other effort | ||
83 | * from a driver's probe() method.) | ||
84 | * | ||
85 | * This function must be called with @dev->sem held. | ||
86 | */ | ||
87 | int device_bind_driver(struct device *dev) | ||
88 | { | ||
89 | driver_bound(dev); | ||
90 | return driver_sysfs_add(dev); | ||
91 | } | ||
92 | |||
68 | struct stupid_thread_structure { | 93 | struct stupid_thread_structure { |
69 | struct device_driver *drv; | 94 | struct device_driver *drv; |
70 | struct device *dev; | 95 | struct device *dev; |
@@ -85,30 +110,32 @@ static int really_probe(void *void_data) | |||
85 | drv->bus->name, drv->name, dev->bus_id); | 110 | drv->bus->name, drv->name, dev->bus_id); |
86 | 111 | ||
87 | dev->driver = drv; | 112 | dev->driver = drv; |
113 | if (driver_sysfs_add(dev)) { | ||
114 | printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", | ||
115 | __FUNCTION__, dev->bus_id); | ||
116 | goto probe_failed; | ||
117 | } | ||
118 | |||
88 | if (dev->bus->probe) { | 119 | if (dev->bus->probe) { |
89 | ret = dev->bus->probe(dev); | 120 | ret = dev->bus->probe(dev); |
90 | if (ret) { | 121 | if (ret) |
91 | dev->driver = NULL; | ||
92 | goto probe_failed; | 122 | goto probe_failed; |
93 | } | ||
94 | } else if (drv->probe) { | 123 | } else if (drv->probe) { |
95 | ret = drv->probe(dev); | 124 | ret = drv->probe(dev); |
96 | if (ret) { | 125 | if (ret) |
97 | dev->driver = NULL; | ||
98 | goto probe_failed; | 126 | goto probe_failed; |
99 | } | ||
100 | } | ||
101 | if (device_bind_driver(dev)) { | ||
102 | printk(KERN_ERR "%s: device_bind_driver(%s) failed\n", | ||
103 | __FUNCTION__, dev->bus_id); | ||
104 | /* How does undo a ->probe? We're screwed. */ | ||
105 | } | 127 | } |
128 | |||
129 | driver_bound(dev); | ||
106 | ret = 1; | 130 | ret = 1; |
107 | pr_debug("%s: Bound Device %s to Driver %s\n", | 131 | pr_debug("%s: Bound Device %s to Driver %s\n", |
108 | drv->bus->name, dev->bus_id, drv->name); | 132 | drv->bus->name, dev->bus_id, drv->name); |
109 | goto done; | 133 | goto done; |
110 | 134 | ||
111 | probe_failed: | 135 | probe_failed: |
136 | driver_sysfs_remove(dev); | ||
137 | dev->driver = NULL; | ||
138 | |||
112 | if (ret == -ENODEV || ret == -ENXIO) { | 139 | if (ret == -ENODEV || ret == -ENXIO) { |
113 | /* Driver matched, but didn't support device | 140 | /* Driver matched, but didn't support device |
114 | * or device not found. | 141 | * or device not found. |
@@ -284,10 +311,15 @@ static void __device_release_driver(struct device * dev) | |||
284 | drv = dev->driver; | 311 | drv = dev->driver; |
285 | if (drv) { | 312 | if (drv) { |
286 | get_driver(drv); | 313 | get_driver(drv); |
287 | sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); | 314 | driver_sysfs_remove(dev); |
288 | sysfs_remove_link(&dev->kobj, "driver"); | 315 | sysfs_remove_link(&dev->kobj, "driver"); |
289 | klist_remove(&dev->knode_driver); | 316 | klist_remove(&dev->knode_driver); |
290 | 317 | ||
318 | if (dev->bus) | ||
319 | blocking_notifier_call_chain(&dev->bus->bus_notifier, | ||
320 | BUS_NOTIFY_UNBIND_DRIVER, | ||
321 | dev); | ||
322 | |||
291 | if (dev->bus && dev->bus->remove) | 323 | if (dev->bus && dev->bus->remove) |
292 | dev->bus->remove(dev); | 324 | dev->bus->remove(dev); |
293 | else if (drv->remove) | 325 | else if (drv->remove) |