diff options
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 261 |
1 files changed, 226 insertions, 35 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 27c2176895d..b224bb43ff6 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -3,12 +3,13 @@ | |||
3 | * | 3 | * |
4 | * Copyright (c) 2002-3 Patrick Mochel | 4 | * Copyright (c) 2002-3 Patrick Mochel |
5 | * Copyright (c) 2002-3 Open Source Development Labs | 5 | * Copyright (c) 2002-3 Open Source Development Labs |
6 | * Copyright (c) 2006 Greg Kroah-Hartman <gregkh@suse.de> | ||
7 | * Copyright (c) 2006 Novell, Inc. | ||
6 | * | 8 | * |
7 | * This file is released under the GPLv2 | 9 | * This file is released under the GPLv2 |
8 | * | 10 | * |
9 | */ | 11 | */ |
10 | 12 | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/device.h> | 13 | #include <linux/device.h> |
13 | #include <linux/err.h> | 14 | #include <linux/err.h> |
14 | #include <linux/init.h> | 15 | #include <linux/init.h> |
@@ -93,6 +94,8 @@ static void device_release(struct kobject * kobj) | |||
93 | 94 | ||
94 | if (dev->release) | 95 | if (dev->release) |
95 | dev->release(dev); | 96 | dev->release(dev); |
97 | else if (dev->class && dev->class->dev_release) | ||
98 | dev->class->dev_release(dev); | ||
96 | else { | 99 | else { |
97 | printk(KERN_ERR "Device '%s' does not have a release() function, " | 100 | printk(KERN_ERR "Device '%s' does not have a release() function, " |
98 | "it is broken and must be fixed.\n", | 101 | "it is broken and must be fixed.\n", |
@@ -150,17 +153,21 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | |||
150 | "MINOR=%u", MINOR(dev->devt)); | 153 | "MINOR=%u", MINOR(dev->devt)); |
151 | } | 154 | } |
152 | 155 | ||
153 | /* add bus name of physical device */ | 156 | /* add bus name (same as SUBSYSTEM, deprecated) */ |
154 | if (dev->bus) | 157 | if (dev->bus) |
155 | add_uevent_var(envp, num_envp, &i, | 158 | add_uevent_var(envp, num_envp, &i, |
156 | buffer, buffer_size, &length, | 159 | buffer, buffer_size, &length, |
157 | "PHYSDEVBUS=%s", dev->bus->name); | 160 | "PHYSDEVBUS=%s", dev->bus->name); |
158 | 161 | ||
159 | /* add driver name of physical device */ | 162 | /* add driver name (PHYSDEV* values are deprecated)*/ |
160 | if (dev->driver) | 163 | if (dev->driver) { |
164 | add_uevent_var(envp, num_envp, &i, | ||
165 | buffer, buffer_size, &length, | ||
166 | "DRIVER=%s", dev->driver->name); | ||
161 | add_uevent_var(envp, num_envp, &i, | 167 | add_uevent_var(envp, num_envp, &i, |
162 | buffer, buffer_size, &length, | 168 | buffer, buffer_size, &length, |
163 | "PHYSDEVDRIVER=%s", dev->driver->name); | 169 | "PHYSDEVDRIVER=%s", dev->driver->name); |
170 | } | ||
164 | 171 | ||
165 | /* terminate, set to next free slot, shrink available space */ | 172 | /* terminate, set to next free slot, shrink available space */ |
166 | envp[i] = NULL; | 173 | envp[i] = NULL; |
@@ -178,6 +185,15 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | |||
178 | } | 185 | } |
179 | } | 186 | } |
180 | 187 | ||
188 | if (dev->class && dev->class->dev_uevent) { | ||
189 | /* have the class specific function add its stuff */ | ||
190 | retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); | ||
191 | if (retval) { | ||
192 | pr_debug("%s - dev_uevent() returned %d\n", | ||
193 | __FUNCTION__, retval); | ||
194 | } | ||
195 | } | ||
196 | |||
181 | return retval; | 197 | return retval; |
182 | } | 198 | } |
183 | 199 | ||
@@ -194,6 +210,72 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, | |||
194 | return count; | 210 | return count; |
195 | } | 211 | } |
196 | 212 | ||
213 | static int device_add_groups(struct device *dev) | ||
214 | { | ||
215 | int i; | ||
216 | int error = 0; | ||
217 | |||
218 | if (dev->groups) { | ||
219 | for (i = 0; dev->groups[i]; i++) { | ||
220 | error = sysfs_create_group(&dev->kobj, dev->groups[i]); | ||
221 | if (error) { | ||
222 | while (--i >= 0) | ||
223 | sysfs_remove_group(&dev->kobj, dev->groups[i]); | ||
224 | goto out; | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | out: | ||
229 | return error; | ||
230 | } | ||
231 | |||
232 | static void device_remove_groups(struct device *dev) | ||
233 | { | ||
234 | int i; | ||
235 | if (dev->groups) { | ||
236 | for (i = 0; dev->groups[i]; i++) { | ||
237 | sysfs_remove_group(&dev->kobj, dev->groups[i]); | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | static int device_add_attrs(struct device *dev) | ||
243 | { | ||
244 | struct class *class = dev->class; | ||
245 | int error = 0; | ||
246 | int i; | ||
247 | |||
248 | if (!class) | ||
249 | return 0; | ||
250 | |||
251 | if (class->dev_attrs) { | ||
252 | for (i = 0; attr_name(class->dev_attrs[i]); i++) { | ||
253 | error = device_create_file(dev, &class->dev_attrs[i]); | ||
254 | if (error) | ||
255 | break; | ||
256 | } | ||
257 | } | ||
258 | if (error) | ||
259 | while (--i >= 0) | ||
260 | device_remove_file(dev, &class->dev_attrs[i]); | ||
261 | return error; | ||
262 | } | ||
263 | |||
264 | static void device_remove_attrs(struct device *dev) | ||
265 | { | ||
266 | struct class *class = dev->class; | ||
267 | int i; | ||
268 | |||
269 | if (!class) | ||
270 | return; | ||
271 | |||
272 | if (class->dev_attrs) { | ||
273 | for (i = 0; attr_name(class->dev_attrs[i]); i++) | ||
274 | device_remove_file(dev, &class->dev_attrs[i]); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | |||
197 | static ssize_t show_dev(struct device *dev, struct device_attribute *attr, | 279 | static ssize_t show_dev(struct device *dev, struct device_attribute *attr, |
198 | char *buf) | 280 | char *buf) |
199 | { | 281 | { |
@@ -237,6 +319,32 @@ void device_remove_file(struct device * dev, struct device_attribute * attr) | |||
237 | } | 319 | } |
238 | } | 320 | } |
239 | 321 | ||
322 | /** | ||
323 | * device_create_bin_file - create sysfs binary attribute file for device. | ||
324 | * @dev: device. | ||
325 | * @attr: device binary attribute descriptor. | ||
326 | */ | ||
327 | int device_create_bin_file(struct device *dev, struct bin_attribute *attr) | ||
328 | { | ||
329 | int error = -EINVAL; | ||
330 | if (dev) | ||
331 | error = sysfs_create_bin_file(&dev->kobj, attr); | ||
332 | return error; | ||
333 | } | ||
334 | EXPORT_SYMBOL_GPL(device_create_bin_file); | ||
335 | |||
336 | /** | ||
337 | * device_remove_bin_file - remove sysfs binary attribute file | ||
338 | * @dev: device. | ||
339 | * @attr: device binary attribute descriptor. | ||
340 | */ | ||
341 | void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) | ||
342 | { | ||
343 | if (dev) | ||
344 | sysfs_remove_bin_file(&dev->kobj, attr); | ||
345 | } | ||
346 | EXPORT_SYMBOL_GPL(device_remove_bin_file); | ||
347 | |||
240 | static void klist_children_get(struct klist_node *n) | 348 | static void klist_children_get(struct klist_node *n) |
241 | { | 349 | { |
242 | struct device *dev = container_of(n, struct device, knode_parent); | 350 | struct device *dev = container_of(n, struct device, knode_parent); |
@@ -290,12 +398,20 @@ int device_add(struct device *dev) | |||
290 | { | 398 | { |
291 | struct device *parent = NULL; | 399 | struct device *parent = NULL; |
292 | char *class_name = NULL; | 400 | char *class_name = NULL; |
401 | struct class_interface *class_intf; | ||
293 | int error = -EINVAL; | 402 | int error = -EINVAL; |
294 | 403 | ||
295 | dev = get_device(dev); | 404 | dev = get_device(dev); |
296 | if (!dev || !strlen(dev->bus_id)) | 405 | if (!dev || !strlen(dev->bus_id)) |
297 | goto Error; | 406 | goto Error; |
298 | 407 | ||
408 | /* if this is a class device, and has no parent, create one */ | ||
409 | if ((dev->class) && (dev->parent == NULL)) { | ||
410 | error = virtual_device_parent(dev); | ||
411 | if (error) | ||
412 | goto Error; | ||
413 | } | ||
414 | |||
299 | parent = get_device(dev->parent); | 415 | parent = get_device(dev->parent); |
300 | 416 | ||
301 | pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); | 417 | pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); |
@@ -308,6 +424,10 @@ int device_add(struct device *dev) | |||
308 | if ((error = kobject_add(&dev->kobj))) | 424 | if ((error = kobject_add(&dev->kobj))) |
309 | goto Error; | 425 | goto Error; |
310 | 426 | ||
427 | /* notify platform of device entry */ | ||
428 | if (platform_notify) | ||
429 | platform_notify(dev); | ||
430 | |||
311 | dev->uevent_attr.attr.name = "uevent"; | 431 | dev->uevent_attr.attr.name = "uevent"; |
312 | dev->uevent_attr.attr.mode = S_IWUSR; | 432 | dev->uevent_attr.attr.mode = S_IWUSR; |
313 | if (dev->driver) | 433 | if (dev->driver) |
@@ -341,12 +461,17 @@ int device_add(struct device *dev) | |||
341 | "subsystem"); | 461 | "subsystem"); |
342 | sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, | 462 | sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, |
343 | dev->bus_id); | 463 | dev->bus_id); |
344 | 464 | if (parent) { | |
345 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); | 465 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); |
346 | class_name = make_class_name(dev->class->name, &dev->kobj); | 466 | class_name = make_class_name(dev->class->name, &dev->kobj); |
347 | sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name); | 467 | sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name); |
468 | } | ||
348 | } | 469 | } |
349 | 470 | ||
471 | if ((error = device_add_attrs(dev))) | ||
472 | goto AttrsError; | ||
473 | if ((error = device_add_groups(dev))) | ||
474 | goto GroupError; | ||
350 | if ((error = device_pm_add(dev))) | 475 | if ((error = device_pm_add(dev))) |
351 | goto PMError; | 476 | goto PMError; |
352 | if ((error = bus_add_device(dev))) | 477 | if ((error = bus_add_device(dev))) |
@@ -357,15 +482,16 @@ int device_add(struct device *dev) | |||
357 | klist_add_tail(&dev->knode_parent, &parent->klist_children); | 482 | klist_add_tail(&dev->knode_parent, &parent->klist_children); |
358 | 483 | ||
359 | if (dev->class) { | 484 | if (dev->class) { |
360 | /* tie the class to the device */ | ||
361 | down(&dev->class->sem); | 485 | down(&dev->class->sem); |
486 | /* tie the class to the device */ | ||
362 | list_add_tail(&dev->node, &dev->class->devices); | 487 | list_add_tail(&dev->node, &dev->class->devices); |
488 | |||
489 | /* notify any interfaces that the device is here */ | ||
490 | list_for_each_entry(class_intf, &dev->class->interfaces, node) | ||
491 | if (class_intf->add_dev) | ||
492 | class_intf->add_dev(dev, class_intf); | ||
363 | up(&dev->class->sem); | 493 | up(&dev->class->sem); |
364 | } | 494 | } |
365 | |||
366 | /* notify platform of device entry */ | ||
367 | if (platform_notify) | ||
368 | platform_notify(dev); | ||
369 | Done: | 495 | Done: |
370 | kfree(class_name); | 496 | kfree(class_name); |
371 | put_device(dev); | 497 | put_device(dev); |
@@ -373,6 +499,10 @@ int device_add(struct device *dev) | |||
373 | BusError: | 499 | BusError: |
374 | device_pm_remove(dev); | 500 | device_pm_remove(dev); |
375 | PMError: | 501 | PMError: |
502 | device_remove_groups(dev); | ||
503 | GroupError: | ||
504 | device_remove_attrs(dev); | ||
505 | AttrsError: | ||
376 | if (dev->devt_attr) { | 506 | if (dev->devt_attr) { |
377 | device_remove_file(dev, dev->devt_attr); | 507 | device_remove_file(dev, dev->devt_attr); |
378 | kfree(dev->devt_attr); | 508 | kfree(dev->devt_attr); |
@@ -450,6 +580,7 @@ void device_del(struct device * dev) | |||
450 | { | 580 | { |
451 | struct device * parent = dev->parent; | 581 | struct device * parent = dev->parent; |
452 | char *class_name = NULL; | 582 | char *class_name = NULL; |
583 | struct class_interface *class_intf; | ||
453 | 584 | ||
454 | if (parent) | 585 | if (parent) |
455 | klist_del(&dev->knode_parent); | 586 | klist_del(&dev->knode_parent); |
@@ -459,14 +590,23 @@ void device_del(struct device * dev) | |||
459 | sysfs_remove_link(&dev->kobj, "subsystem"); | 590 | sysfs_remove_link(&dev->kobj, "subsystem"); |
460 | sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id); | 591 | sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id); |
461 | class_name = make_class_name(dev->class->name, &dev->kobj); | 592 | class_name = make_class_name(dev->class->name, &dev->kobj); |
462 | sysfs_remove_link(&dev->kobj, "device"); | 593 | if (parent) { |
463 | sysfs_remove_link(&dev->parent->kobj, class_name); | 594 | sysfs_remove_link(&dev->kobj, "device"); |
595 | sysfs_remove_link(&dev->parent->kobj, class_name); | ||
596 | } | ||
464 | kfree(class_name); | 597 | kfree(class_name); |
465 | down(&dev->class->sem); | 598 | down(&dev->class->sem); |
599 | /* notify any interfaces that the device is now gone */ | ||
600 | list_for_each_entry(class_intf, &dev->class->interfaces, node) | ||
601 | if (class_intf->remove_dev) | ||
602 | class_intf->remove_dev(dev, class_intf); | ||
603 | /* remove the device from the class list */ | ||
466 | list_del_init(&dev->node); | 604 | list_del_init(&dev->node); |
467 | up(&dev->class->sem); | 605 | up(&dev->class->sem); |
468 | } | 606 | } |
469 | device_remove_file(dev, &dev->uevent_attr); | 607 | device_remove_file(dev, &dev->uevent_attr); |
608 | device_remove_groups(dev); | ||
609 | device_remove_attrs(dev); | ||
470 | 610 | ||
471 | /* Notify the platform of the removal, in case they | 611 | /* Notify the platform of the removal, in case they |
472 | * need to do anything... | 612 | * need to do anything... |
@@ -560,27 +700,27 @@ static void device_create_release(struct device *dev) | |||
560 | 700 | ||
561 | /** | 701 | /** |
562 | * device_create - creates a device and registers it with sysfs | 702 | * device_create - creates a device and registers it with sysfs |
563 | * @cs: pointer to the struct class that this device should be registered to. | 703 | * @class: pointer to the struct class that this device should be registered to |
564 | * @parent: pointer to the parent struct device of this new device, if any. | 704 | * @parent: pointer to the parent struct device of this new device, if any |
565 | * @dev: the dev_t for the char device to be added. | 705 | * @devt: the dev_t for the char device to be added |
566 | * @fmt: string for the class device's name | 706 | * @fmt: string for the device's name |
707 | * | ||
708 | * This function can be used by char device classes. A struct device | ||
709 | * will be created in sysfs, registered to the specified class. | ||
567 | * | 710 | * |
568 | * This function can be used by char device classes. A struct | ||
569 | * device will be created in sysfs, registered to the specified | ||
570 | * class. | ||
571 | * A "dev" file will be created, showing the dev_t for the device, if | 711 | * A "dev" file will be created, showing the dev_t for the device, if |
572 | * the dev_t is not 0,0. | 712 | * the dev_t is not 0,0. |
573 | * If a pointer to a parent struct device is passed in, the newly | 713 | * If a pointer to a parent struct device is passed in, the newly created |
574 | * created struct device will be a child of that device in sysfs. The | 714 | * struct device will be a child of that device in sysfs. |
575 | * pointer to the struct device will be returned from the call. Any | 715 | * The pointer to the struct device will be returned from the call. |
576 | * further sysfs files that might be required can be created using this | 716 | * Any further sysfs files that might be required can be created using this |
577 | * pointer. | 717 | * pointer. |
578 | * | 718 | * |
579 | * Note: the struct class passed to this function must have previously | 719 | * Note: the struct class passed to this function must have previously |
580 | * been created with a call to class_create(). | 720 | * been created with a call to class_create(). |
581 | */ | 721 | */ |
582 | struct device *device_create(struct class *class, struct device *parent, | 722 | struct device *device_create(struct class *class, struct device *parent, |
583 | dev_t devt, char *fmt, ...) | 723 | dev_t devt, const char *fmt, ...) |
584 | { | 724 | { |
585 | va_list args; | 725 | va_list args; |
586 | struct device *dev = NULL; | 726 | struct device *dev = NULL; |
@@ -588,10 +728,6 @@ struct device *device_create(struct class *class, struct device *parent, | |||
588 | 728 | ||
589 | if (class == NULL || IS_ERR(class)) | 729 | if (class == NULL || IS_ERR(class)) |
590 | goto error; | 730 | goto error; |
591 | if (parent == NULL) { | ||
592 | printk(KERN_WARNING "%s does not work yet for NULL parents\n", __FUNCTION__); | ||
593 | goto error; | ||
594 | } | ||
595 | 731 | ||
596 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 732 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
597 | if (!dev) { | 733 | if (!dev) { |
@@ -621,11 +757,11 @@ EXPORT_SYMBOL_GPL(device_create); | |||
621 | 757 | ||
622 | /** | 758 | /** |
623 | * device_destroy - removes a device that was created with device_create() | 759 | * device_destroy - removes a device that was created with device_create() |
624 | * @class: the pointer to the struct class that this device was registered * with. | 760 | * @class: pointer to the struct class that this device was registered with |
625 | * @dev: the dev_t of the device that was previously registered. | 761 | * @devt: the dev_t of the device that was previously registered |
626 | * | 762 | * |
627 | * This call unregisters and cleans up a class device that was created with a | 763 | * This call unregisters and cleans up a device that was created with a |
628 | * call to class_device_create() | 764 | * call to device_create(). |
629 | */ | 765 | */ |
630 | void device_destroy(struct class *class, dev_t devt) | 766 | void device_destroy(struct class *class, dev_t devt) |
631 | { | 767 | { |
@@ -645,3 +781,58 @@ void device_destroy(struct class *class, dev_t devt) | |||
645 | device_unregister(dev); | 781 | device_unregister(dev); |
646 | } | 782 | } |
647 | EXPORT_SYMBOL_GPL(device_destroy); | 783 | EXPORT_SYMBOL_GPL(device_destroy); |
784 | |||
785 | /** | ||
786 | * device_rename - renames a device | ||
787 | * @dev: the pointer to the struct device to be renamed | ||
788 | * @new_name: the new name of the device | ||
789 | */ | ||
790 | int device_rename(struct device *dev, char *new_name) | ||
791 | { | ||
792 | char *old_class_name = NULL; | ||
793 | char *new_class_name = NULL; | ||
794 | char *old_symlink_name = NULL; | ||
795 | int error; | ||
796 | |||
797 | dev = get_device(dev); | ||
798 | if (!dev) | ||
799 | return -EINVAL; | ||
800 | |||
801 | pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name); | ||
802 | |||
803 | if ((dev->class) && (dev->parent)) | ||
804 | old_class_name = make_class_name(dev->class->name, &dev->kobj); | ||
805 | |||
806 | if (dev->class) { | ||
807 | old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); | ||
808 | if (!old_symlink_name) | ||
809 | return -ENOMEM; | ||
810 | strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE); | ||
811 | } | ||
812 | |||
813 | strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); | ||
814 | |||
815 | error = kobject_rename(&dev->kobj, new_name); | ||
816 | |||
817 | if (old_class_name) { | ||
818 | new_class_name = make_class_name(dev->class->name, &dev->kobj); | ||
819 | if (new_class_name) { | ||
820 | sysfs_create_link(&dev->parent->kobj, &dev->kobj, | ||
821 | new_class_name); | ||
822 | sysfs_remove_link(&dev->parent->kobj, old_class_name); | ||
823 | } | ||
824 | } | ||
825 | if (dev->class) { | ||
826 | sysfs_remove_link(&dev->class->subsys.kset.kobj, | ||
827 | old_symlink_name); | ||
828 | sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, | ||
829 | dev->bus_id); | ||
830 | } | ||
831 | put_device(dev); | ||
832 | |||
833 | kfree(old_class_name); | ||
834 | kfree(new_class_name); | ||
835 | kfree(old_symlink_name); | ||
836 | |||
837 | return error; | ||
838 | } | ||