diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/dd.c | 82 |
1 files changed, 52 insertions, 30 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 9c88b1e34bc3..510e7884975f 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
@@ -26,28 +26,12 @@ | |||
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", |
@@ -58,6 +42,12 @@ int device_bind_driver(struct device *dev) | |||
58 | BUS_NOTIFY_BOUND_DRIVER, dev); | 42 | BUS_NOTIFY_BOUND_DRIVER, dev); |
59 | 43 | ||
60 | 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 | |||
61 | ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, | 51 | ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, |
62 | kobject_name(&dev->kobj)); | 52 | kobject_name(&dev->kobj)); |
63 | if (ret == 0) { | 53 | if (ret == 0) { |
@@ -70,6 +60,36 @@ int device_bind_driver(struct device *dev) | |||
70 | return ret; | 60 | return ret; |
71 | } | 61 | } |
72 | 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 | |||
73 | struct stupid_thread_structure { | 93 | struct stupid_thread_structure { |
74 | struct device_driver *drv; | 94 | struct device_driver *drv; |
75 | struct device *dev; | 95 | struct device *dev; |
@@ -90,30 +110,32 @@ static int really_probe(void *void_data) | |||
90 | drv->bus->name, drv->name, dev->bus_id); | 110 | drv->bus->name, drv->name, dev->bus_id); |
91 | 111 | ||
92 | 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 | |||
93 | if (dev->bus->probe) { | 119 | if (dev->bus->probe) { |
94 | ret = dev->bus->probe(dev); | 120 | ret = dev->bus->probe(dev); |
95 | if (ret) { | 121 | if (ret) |
96 | dev->driver = NULL; | ||
97 | goto probe_failed; | 122 | goto probe_failed; |
98 | } | ||
99 | } else if (drv->probe) { | 123 | } else if (drv->probe) { |
100 | ret = drv->probe(dev); | 124 | ret = drv->probe(dev); |
101 | if (ret) { | 125 | if (ret) |
102 | dev->driver = NULL; | ||
103 | goto probe_failed; | 126 | goto probe_failed; |
104 | } | ||
105 | } | ||
106 | if (device_bind_driver(dev)) { | ||
107 | printk(KERN_ERR "%s: device_bind_driver(%s) failed\n", | ||
108 | __FUNCTION__, dev->bus_id); | ||
109 | /* How does undo a ->probe? We're screwed. */ | ||
110 | } | 127 | } |
128 | |||
129 | driver_bound(dev); | ||
111 | ret = 1; | 130 | ret = 1; |
112 | pr_debug("%s: Bound Device %s to Driver %s\n", | 131 | pr_debug("%s: Bound Device %s to Driver %s\n", |
113 | drv->bus->name, dev->bus_id, drv->name); | 132 | drv->bus->name, dev->bus_id, drv->name); |
114 | goto done; | 133 | goto done; |
115 | 134 | ||
116 | probe_failed: | 135 | probe_failed: |
136 | driver_sysfs_remove(dev); | ||
137 | dev->driver = NULL; | ||
138 | |||
117 | if (ret == -ENODEV || ret == -ENXIO) { | 139 | if (ret == -ENODEV || ret == -ENXIO) { |
118 | /* Driver matched, but didn't support device | 140 | /* Driver matched, but didn't support device |
119 | * or device not found. | 141 | * or device not found. |
@@ -289,7 +311,7 @@ static void __device_release_driver(struct device * dev) | |||
289 | drv = dev->driver; | 311 | drv = dev->driver; |
290 | if (drv) { | 312 | if (drv) { |
291 | get_driver(drv); | 313 | get_driver(drv); |
292 | sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); | 314 | driver_sysfs_remove(dev); |
293 | sysfs_remove_link(&dev->kobj, "driver"); | 315 | sysfs_remove_link(&dev->kobj, "driver"); |
294 | klist_remove(&dev->knode_driver); | 316 | klist_remove(&dev->knode_driver); |
295 | 317 | ||