diff options
Diffstat (limited to 'drivers/base/dd.c')
-rw-r--r-- | drivers/base/dd.c | 66 |
1 files changed, 35 insertions, 31 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 6a48824e43ff..18dba8e78da7 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
@@ -94,19 +94,11 @@ int device_bind_driver(struct device *dev) | |||
94 | return ret; | 94 | return ret; |
95 | } | 95 | } |
96 | 96 | ||
97 | struct stupid_thread_structure { | ||
98 | struct device_driver *drv; | ||
99 | struct device *dev; | ||
100 | }; | ||
101 | |||
102 | static atomic_t probe_count = ATOMIC_INIT(0); | 97 | static atomic_t probe_count = ATOMIC_INIT(0); |
103 | static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); | 98 | static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); |
104 | 99 | ||
105 | static int really_probe(void *void_data) | 100 | static int really_probe(struct device *dev, struct device_driver *drv) |
106 | { | 101 | { |
107 | struct stupid_thread_structure *data = void_data; | ||
108 | struct device_driver *drv = data->drv; | ||
109 | struct device *dev = data->dev; | ||
110 | int ret = 0; | 102 | int ret = 0; |
111 | 103 | ||
112 | atomic_inc(&probe_count); | 104 | atomic_inc(&probe_count); |
@@ -154,7 +146,6 @@ probe_failed: | |||
154 | */ | 146 | */ |
155 | ret = 0; | 147 | ret = 0; |
156 | done: | 148 | done: |
157 | kfree(data); | ||
158 | atomic_dec(&probe_count); | 149 | atomic_dec(&probe_count); |
159 | wake_up(&probe_waitqueue); | 150 | wake_up(&probe_waitqueue); |
160 | return ret; | 151 | return ret; |
@@ -186,16 +177,14 @@ int driver_probe_done(void) | |||
186 | * format of the ID structures, nor what is to be considered a match and | 177 | * format of the ID structures, nor what is to be considered a match and |
187 | * what is not. | 178 | * what is not. |
188 | * | 179 | * |
189 | * This function returns 1 if a match is found, an error if one occurs | 180 | * This function returns 1 if a match is found, -ENODEV if the device is |
190 | * (that is not -ENODEV or -ENXIO), and 0 otherwise. | 181 | * not registered, and 0 otherwise. |
191 | * | 182 | * |
192 | * This function must be called with @dev->sem held. When called for a | 183 | * This function must be called with @dev->sem held. When called for a |
193 | * USB interface, @dev->parent->sem must be held as well. | 184 | * USB interface, @dev->parent->sem must be held as well. |
194 | */ | 185 | */ |
195 | int driver_probe_device(struct device_driver * drv, struct device * dev) | 186 | int driver_probe_device(struct device_driver * drv, struct device * dev) |
196 | { | 187 | { |
197 | struct stupid_thread_structure *data; | ||
198 | struct task_struct *probe_task; | ||
199 | int ret = 0; | 188 | int ret = 0; |
200 | 189 | ||
201 | if (!device_is_registered(dev)) | 190 | if (!device_is_registered(dev)) |
@@ -206,19 +195,7 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) | |||
206 | pr_debug("%s: Matched Device %s with Driver %s\n", | 195 | pr_debug("%s: Matched Device %s with Driver %s\n", |
207 | drv->bus->name, dev->bus_id, drv->name); | 196 | drv->bus->name, dev->bus_id, drv->name); |
208 | 197 | ||
209 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 198 | ret = really_probe(dev, drv); |
210 | if (!data) | ||
211 | return -ENOMEM; | ||
212 | data->drv = drv; | ||
213 | data->dev = dev; | ||
214 | |||
215 | if (drv->multithread_probe) { | ||
216 | probe_task = kthread_run(really_probe, data, | ||
217 | "probe-%s", dev->bus_id); | ||
218 | if (IS_ERR(probe_task)) | ||
219 | ret = really_probe(data); | ||
220 | } else | ||
221 | ret = really_probe(data); | ||
222 | 199 | ||
223 | done: | 200 | done: |
224 | return ret; | 201 | return ret; |
@@ -230,30 +207,57 @@ static int __device_attach(struct device_driver * drv, void * data) | |||
230 | return driver_probe_device(drv, dev); | 207 | return driver_probe_device(drv, dev); |
231 | } | 208 | } |
232 | 209 | ||
210 | static int device_probe_drivers(void *data) | ||
211 | { | ||
212 | struct device *dev = data; | ||
213 | int ret = 0; | ||
214 | |||
215 | if (dev->bus) { | ||
216 | down(&dev->sem); | ||
217 | ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); | ||
218 | up(&dev->sem); | ||
219 | } | ||
220 | return ret; | ||
221 | } | ||
222 | |||
233 | /** | 223 | /** |
234 | * device_attach - try to attach device to a driver. | 224 | * device_attach - try to attach device to a driver. |
235 | * @dev: device. | 225 | * @dev: device. |
236 | * | 226 | * |
237 | * Walk the list of drivers that the bus has and call | 227 | * Walk the list of drivers that the bus has and call |
238 | * driver_probe_device() for each pair. If a compatible | 228 | * driver_probe_device() for each pair. If a compatible |
239 | * pair is found, break out and return. | 229 | * pair is found, break out and return. If the bus specifies |
230 | * multithreaded probing, walking the list of drivers is done | ||
231 | * on a probing thread. | ||
240 | * | 232 | * |
241 | * Returns 1 if the device was bound to a driver; | 233 | * Returns 1 if the device was bound to a driver; |
242 | * 0 if no matching device was found; error code otherwise. | 234 | * 0 if no matching device was found or multithreaded probing is done; |
235 | * -ENODEV if the device is not registered. | ||
243 | * | 236 | * |
244 | * When called for a USB interface, @dev->parent->sem must be held. | 237 | * When called for a USB interface, @dev->parent->sem must be held. |
245 | */ | 238 | */ |
246 | int device_attach(struct device * dev) | 239 | int device_attach(struct device * dev) |
247 | { | 240 | { |
248 | int ret = 0; | 241 | int ret = 0; |
242 | struct task_struct *probe_task = ERR_PTR(-ENOMEM); | ||
249 | 243 | ||
250 | down(&dev->sem); | 244 | down(&dev->sem); |
251 | if (dev->driver) { | 245 | if (dev->driver) { |
252 | ret = device_bind_driver(dev); | 246 | ret = device_bind_driver(dev); |
253 | if (ret == 0) | 247 | if (ret == 0) |
254 | ret = 1; | 248 | ret = 1; |
255 | } else | 249 | else { |
256 | ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); | 250 | dev->driver = NULL; |
251 | ret = 0; | ||
252 | } | ||
253 | } else { | ||
254 | if (dev->bus->multithread_probe) | ||
255 | probe_task = kthread_run(device_probe_drivers, dev, | ||
256 | "probe-%s", dev->bus_id); | ||
257 | if(IS_ERR(probe_task)) | ||
258 | ret = bus_for_each_drv(dev->bus, NULL, dev, | ||
259 | __device_attach); | ||
260 | } | ||
257 | up(&dev->sem); | 261 | up(&dev->sem); |
258 | return ret; | 262 | return ret; |
259 | } | 263 | } |