aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/dd.c108
-rw-r--r--include/linux/device.h3
-rw-r--r--init/do_mounts.c5
3 files changed, 89 insertions, 27 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 9f6f11ca0ab6..319a73be4180 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -17,6 +17,7 @@
17 17
18#include <linux/device.h> 18#include <linux/device.h>
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/kthread.h>
20 21
21#include "base.h" 22#include "base.h"
22#include "power/power.h" 23#include "power/power.h"
@@ -63,44 +64,35 @@ int device_bind_driver(struct device *dev)
63 return ret; 64 return ret;
64} 65}
65 66
66/** 67struct stupid_thread_structure {
67 * driver_probe_device - attempt to bind device & driver. 68 struct device_driver *drv;
68 * @drv: driver. 69 struct device *dev;
69 * @dev: device. 70};
70 * 71
71 * First, we call the bus's match function, if one present, which 72static atomic_t probe_count = ATOMIC_INIT(0);
72 * should compare the device IDs the driver supports with the 73static int really_probe(void *void_data)
73 * device IDs of the device. Note we don't do this ourselves
74 * because we don't know the format of the ID structures, nor what
75 * is to be considered a match and what is not.
76 *
77 * This function returns 1 if a match is found, an error if one
78 * occurs (that is not -ENODEV or -ENXIO), and 0 otherwise.
79 *
80 * This function must be called with @dev->sem held. When called
81 * for a USB interface, @dev->parent->sem must be held as well.
82 */
83int driver_probe_device(struct device_driver * drv, struct device * dev)
84{ 74{
75 struct stupid_thread_structure *data = void_data;
76 struct device_driver *drv = data->drv;
77 struct device *dev = data->dev;
85 int ret = 0; 78 int ret = 0;
86 79
87 if (drv->bus->match && !drv->bus->match(dev, drv)) 80 atomic_inc(&probe_count);
88 goto Done; 81 pr_debug("%s: Probing driver %s with device %s\n",
82 drv->bus->name, drv->name, dev->bus_id);
89 83
90 pr_debug("%s: Matched Device %s with Driver %s\n",
91 drv->bus->name, dev->bus_id, drv->name);
92 dev->driver = drv; 84 dev->driver = drv;
93 if (dev->bus->probe) { 85 if (dev->bus->probe) {
94 ret = dev->bus->probe(dev); 86 ret = dev->bus->probe(dev);
95 if (ret) { 87 if (ret) {
96 dev->driver = NULL; 88 dev->driver = NULL;
97 goto ProbeFailed; 89 goto probe_failed;
98 } 90 }
99 } else if (drv->probe) { 91 } else if (drv->probe) {
100 ret = drv->probe(dev); 92 ret = drv->probe(dev);
101 if (ret) { 93 if (ret) {
102 dev->driver = NULL; 94 dev->driver = NULL;
103 goto ProbeFailed; 95 goto probe_failed;
104 } 96 }
105 } 97 }
106 if (device_bind_driver(dev)) { 98 if (device_bind_driver(dev)) {
@@ -111,9 +103,9 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
111 ret = 1; 103 ret = 1;
112 pr_debug("%s: Bound Device %s to Driver %s\n", 104 pr_debug("%s: Bound Device %s to Driver %s\n",
113 drv->bus->name, dev->bus_id, drv->name); 105 drv->bus->name, dev->bus_id, drv->name);
114 goto Done; 106 goto done;
115 107
116 ProbeFailed: 108probe_failed:
117 if (ret == -ENODEV || ret == -ENXIO) { 109 if (ret == -ENODEV || ret == -ENXIO) {
118 /* Driver matched, but didn't support device 110 /* Driver matched, but didn't support device
119 * or device not found. 111 * or device not found.
@@ -126,7 +118,69 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
126 "%s: probe of %s failed with error %d\n", 118 "%s: probe of %s failed with error %d\n",
127 drv->name, dev->bus_id, ret); 119 drv->name, dev->bus_id, ret);
128 } 120 }
129 Done: 121done:
122 kfree(data);
123 atomic_dec(&probe_count);
124 return ret;
125}
126
127/**
128 * driver_probe_done
129 * Determine if the probe sequence is finished or not.
130 *
131 * Should somehow figure out how to use a semaphore, not an atomic variable...
132 */
133int driver_probe_done(void)
134{
135 pr_debug("%s: probe_count = %d\n", __FUNCTION__,
136 atomic_read(&probe_count));
137 if (atomic_read(&probe_count))
138 return -EBUSY;
139 return 0;
140}
141
142/**
143 * driver_probe_device - attempt to bind device & driver together
144 * @drv: driver to bind a device to
145 * @dev: device to try to bind to the driver
146 *
147 * First, we call the bus's match function, if one present, which should
148 * compare the device IDs the driver supports with the device IDs of the
149 * device. Note we don't do this ourselves because we don't know the
150 * format of the ID structures, nor what is to be considered a match and
151 * what is not.
152 *
153 * This function returns 1 if a match is found, an error if one occurs
154 * (that is not -ENODEV or -ENXIO), and 0 otherwise.
155 *
156 * This function must be called with @dev->sem held. When called for a
157 * USB interface, @dev->parent->sem must be held as well.
158 */
159int driver_probe_device(struct device_driver * drv, struct device * dev)
160{
161 struct stupid_thread_structure *data;
162 struct task_struct *probe_task;
163 int ret = 0;
164
165 if (drv->bus->match && !drv->bus->match(dev, drv))
166 goto done;
167
168 pr_debug("%s: Matched Device %s with Driver %s\n",
169 drv->bus->name, dev->bus_id, drv->name);
170
171 data = kmalloc(sizeof(*data), GFP_KERNEL);
172 data->drv = drv;
173 data->dev = dev;
174
175 if (drv->multithread_probe) {
176 probe_task = kthread_run(really_probe, data,
177 "probe-%s", dev->bus_id);
178 if (IS_ERR(probe_task))
179 ret = PTR_ERR(probe_task);
180 } else
181 ret = really_probe(data);
182
183done:
130 return ret; 184 return ret;
131} 185}
132 186
diff --git a/include/linux/device.h b/include/linux/device.h
index b3da9a870cfc..74246efba931 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -106,6 +106,8 @@ struct device_driver {
106 void (*shutdown) (struct device * dev); 106 void (*shutdown) (struct device * dev);
107 int (*suspend) (struct device * dev, pm_message_t state); 107 int (*suspend) (struct device * dev, pm_message_t state);
108 int (*resume) (struct device * dev); 108 int (*resume) (struct device * dev);
109
110 unsigned int multithread_probe:1;
109}; 111};
110 112
111 113
@@ -115,6 +117,7 @@ extern void driver_unregister(struct device_driver * drv);
115extern struct device_driver * get_driver(struct device_driver * drv); 117extern struct device_driver * get_driver(struct device_driver * drv);
116extern void put_driver(struct device_driver * drv); 118extern void put_driver(struct device_driver * drv);
117extern struct device_driver *driver_find(const char *name, struct bus_type *bus); 119extern struct device_driver *driver_find(const char *name, struct bus_type *bus);
120extern int driver_probe_done(void);
118 121
119/* driverfs interface for exporting driver attributes */ 122/* driverfs interface for exporting driver attributes */
120 123
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 94aeec7aa917..b290aadb1d3f 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -8,6 +8,7 @@
8#include <linux/security.h> 8#include <linux/security.h>
9#include <linux/delay.h> 9#include <linux/delay.h>
10#include <linux/mount.h> 10#include <linux/mount.h>
11#include <linux/device.h>
11 12
12#include <linux/nfs_fs.h> 13#include <linux/nfs_fs.h>
13#include <linux/nfs_fs_sb.h> 14#include <linux/nfs_fs_sb.h>
@@ -403,6 +404,10 @@ void __init prepare_namespace(void)
403 ssleep(root_delay); 404 ssleep(root_delay);
404 } 405 }
405 406
407 /* wait for the known devices to complete their probing */
408 while (driver_probe_done() != 0)
409 msleep(100);
410
406 md_run_setup(); 411 md_run_setup();
407 412
408 if (saved_root_name[0]) { 413 if (saved_root_name[0]) {