diff options
-rw-r--r-- | drivers/base/core.c | 2 | ||||
-rw-r--r-- | drivers/base/dd.c | 34 | ||||
-rw-r--r-- | drivers/base/driver.c | 27 | ||||
-rw-r--r-- | include/linux/device.h | 3 |
4 files changed, 37 insertions, 29 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 93440824b800..bc5bec61a01a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -209,8 +209,8 @@ void device_initialize(struct device *dev) | |||
209 | kobject_init(&dev->kobj); | 209 | kobject_init(&dev->kobj); |
210 | INIT_LIST_HEAD(&dev->node); | 210 | INIT_LIST_HEAD(&dev->node); |
211 | INIT_LIST_HEAD(&dev->children); | 211 | INIT_LIST_HEAD(&dev->children); |
212 | INIT_LIST_HEAD(&dev->driver_list); | ||
213 | INIT_LIST_HEAD(&dev->bus_list); | 212 | INIT_LIST_HEAD(&dev->bus_list); |
213 | INIT_LIST_HEAD(&dev->driver_list); | ||
214 | INIT_LIST_HEAD(&dev->dma_pools); | 214 | INIT_LIST_HEAD(&dev->dma_pools); |
215 | init_MUTEX(&dev->sem); | 215 | init_MUTEX(&dev->sem); |
216 | } | 216 | } |
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index b709b1e0cb2a..47cbb5641235 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
@@ -40,7 +40,7 @@ void device_bind_driver(struct device * dev) | |||
40 | { | 40 | { |
41 | pr_debug("bound device '%s' to driver '%s'\n", | 41 | pr_debug("bound device '%s' to driver '%s'\n", |
42 | dev->bus_id, dev->driver->name); | 42 | dev->bus_id, dev->driver->name); |
43 | list_add_tail(&dev->driver_list, &dev->driver->devices); | 43 | klist_add_tail(&dev->driver->klist_devices, &dev->knode_driver); |
44 | sysfs_create_link(&dev->driver->kobj, &dev->kobj, | 44 | sysfs_create_link(&dev->driver->kobj, &dev->kobj, |
45 | kobject_name(&dev->kobj)); | 45 | kobject_name(&dev->kobj)); |
46 | sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver"); | 46 | sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver"); |
@@ -164,31 +164,35 @@ void driver_attach(struct device_driver * drv) | |||
164 | */ | 164 | */ |
165 | void device_release_driver(struct device * dev) | 165 | void device_release_driver(struct device * dev) |
166 | { | 166 | { |
167 | struct device_driver * drv; | 167 | struct device_driver * drv = dev->driver; |
168 | |||
169 | if (!drv) | ||
170 | return; | ||
171 | |||
172 | sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); | ||
173 | sysfs_remove_link(&dev->kobj, "driver"); | ||
174 | klist_remove(&dev->knode_driver); | ||
168 | 175 | ||
169 | down(&dev->sem); | 176 | down(&dev->sem); |
170 | drv = dev->driver; | 177 | if (drv->remove) |
171 | if (drv) { | 178 | drv->remove(dev); |
172 | sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); | 179 | dev->driver = NULL; |
173 | sysfs_remove_link(&dev->kobj, "driver"); | ||
174 | list_del_init(&dev->driver_list); | ||
175 | if (drv->remove) | ||
176 | drv->remove(dev); | ||
177 | dev->driver = NULL; | ||
178 | } | ||
179 | up(&dev->sem); | 180 | up(&dev->sem); |
180 | } | 181 | } |
181 | 182 | ||
183 | static int __remove_driver(struct device * dev, void * unused) | ||
184 | { | ||
185 | device_release_driver(dev); | ||
186 | return 0; | ||
187 | } | ||
188 | |||
182 | /** | 189 | /** |
183 | * driver_detach - detach driver from all devices it controls. | 190 | * driver_detach - detach driver from all devices it controls. |
184 | * @drv: driver. | 191 | * @drv: driver. |
185 | */ | 192 | */ |
186 | void driver_detach(struct device_driver * drv) | 193 | void driver_detach(struct device_driver * drv) |
187 | { | 194 | { |
188 | while (!list_empty(&drv->devices)) { | 195 | driver_for_each_device(drv, NULL, NULL, __remove_driver); |
189 | struct device * dev = container_of(drv->devices.next, struct device, driver_list); | ||
190 | device_release_driver(dev); | ||
191 | } | ||
192 | } | 196 | } |
193 | 197 | ||
194 | 198 | ||
diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 484fed1985aa..34bd38aa7eb8 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c | |||
@@ -19,6 +19,12 @@ | |||
19 | #define to_drv(obj) container_of(obj, struct device_driver, kobj) | 19 | #define to_drv(obj) container_of(obj, struct device_driver, kobj) |
20 | 20 | ||
21 | 21 | ||
22 | static struct device * next_device(struct klist_iter * i) | ||
23 | { | ||
24 | struct klist_node * n = klist_next(i); | ||
25 | return n ? container_of(n, struct device, knode_driver) : NULL; | ||
26 | } | ||
27 | |||
22 | /** | 28 | /** |
23 | * driver_for_each_device - Iterator for devices bound to a driver. | 29 | * driver_for_each_device - Iterator for devices bound to a driver. |
24 | * @drv: Driver we're iterating. | 30 | * @drv: Driver we're iterating. |
@@ -32,21 +38,18 @@ | |||
32 | int driver_for_each_device(struct device_driver * drv, struct device * start, | 38 | int driver_for_each_device(struct device_driver * drv, struct device * start, |
33 | void * data, int (*fn)(struct device *, void *)) | 39 | void * data, int (*fn)(struct device *, void *)) |
34 | { | 40 | { |
35 | struct list_head * head; | 41 | struct klist_iter i; |
36 | struct device * dev; | 42 | struct device * dev; |
37 | int error = 0; | 43 | int error = 0; |
38 | 44 | ||
39 | down_read(&drv->bus->subsys.rwsem); | 45 | if (!drv) |
40 | head = &drv->devices; | 46 | return -EINVAL; |
41 | dev = list_prepare_entry(start, head, driver_list); | 47 | |
42 | list_for_each_entry_continue(dev, head, driver_list) { | 48 | klist_iter_init_node(&drv->klist_devices, &i, |
43 | get_device(dev); | 49 | start ? &start->knode_driver : NULL); |
50 | while ((dev = next_device(&i)) && !error) | ||
44 | error = fn(dev, data); | 51 | error = fn(dev, data); |
45 | put_device(dev); | 52 | klist_iter_exit(&i); |
46 | if (error) | ||
47 | break; | ||
48 | } | ||
49 | up_read(&drv->bus->subsys.rwsem); | ||
50 | return error; | 53 | return error; |
51 | } | 54 | } |
52 | 55 | ||
@@ -120,7 +123,7 @@ void put_driver(struct device_driver * drv) | |||
120 | */ | 123 | */ |
121 | int driver_register(struct device_driver * drv) | 124 | int driver_register(struct device_driver * drv) |
122 | { | 125 | { |
123 | INIT_LIST_HEAD(&drv->devices); | 126 | klist_init(&drv->klist_devices); |
124 | init_completion(&drv->unloaded); | 127 | init_completion(&drv->unloaded); |
125 | return bus_add_driver(drv); | 128 | return bus_add_driver(drv); |
126 | } | 129 | } |
diff --git a/include/linux/device.h b/include/linux/device.h index ea9ab33dfe71..96c71b59fdef 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
@@ -105,7 +105,7 @@ struct device_driver { | |||
105 | 105 | ||
106 | struct completion unloaded; | 106 | struct completion unloaded; |
107 | struct kobject kobj; | 107 | struct kobject kobj; |
108 | struct list_head devices; | 108 | struct klist klist_devices; |
109 | struct klist_node knode_bus; | 109 | struct klist_node knode_bus; |
110 | 110 | ||
111 | struct module * owner; | 111 | struct module * owner; |
@@ -266,6 +266,7 @@ struct device { | |||
266 | struct list_head bus_list; /* node in bus's list */ | 266 | struct list_head bus_list; /* node in bus's list */ |
267 | struct list_head driver_list; | 267 | struct list_head driver_list; |
268 | struct list_head children; | 268 | struct list_head children; |
269 | struct klist_node knode_driver; | ||
269 | struct klist_node knode_bus; | 270 | struct klist_node knode_bus; |
270 | struct device * parent; | 271 | struct device * parent; |
271 | 272 | ||