diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Kconfig | 4 | ||||
-rw-r--r-- | drivers/base/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/attribute_container.c | 8 | ||||
-rw-r--r-- | drivers/base/base.h | 9 | ||||
-rw-r--r-- | drivers/base/bus.c | 28 | ||||
-rw-r--r-- | drivers/base/class.c | 112 | ||||
-rw-r--r-- | drivers/base/core.c | 200 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 22 | ||||
-rw-r--r-- | drivers/base/hypervisor.c | 19 | ||||
-rw-r--r-- | drivers/base/init.c | 1 | ||||
-rw-r--r-- | drivers/base/isa.c | 180 | ||||
-rw-r--r-- | drivers/base/platform.c | 35 | ||||
-rw-r--r-- | drivers/base/power/Makefile | 3 | ||||
-rw-r--r-- | drivers/base/power/suspend.c | 17 | ||||
-rw-r--r-- | drivers/base/sys.c | 51 |
15 files changed, 622 insertions, 69 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index f0eff3dac58d..80502dc6ed66 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig | |||
@@ -38,3 +38,7 @@ config DEBUG_DRIVER | |||
38 | If you are unsure about this, say N here. | 38 | If you are unsure about this, say N here. |
39 | 39 | ||
40 | endmenu | 40 | endmenu |
41 | |||
42 | config SYS_HYPERVISOR | ||
43 | bool | ||
44 | default n | ||
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index e99471d3232b..b539e5e75b56 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile | |||
@@ -5,10 +5,12 @@ obj-y := core.o sys.o bus.o dd.o \ | |||
5 | cpu.o firmware.o init.o map.o dmapool.o \ | 5 | cpu.o firmware.o init.o map.o dmapool.o \ |
6 | attribute_container.o transport_class.o | 6 | attribute_container.o transport_class.o |
7 | obj-y += power/ | 7 | obj-y += power/ |
8 | obj-$(CONFIG_ISA) += isa.o | ||
8 | obj-$(CONFIG_FW_LOADER) += firmware_class.o | 9 | obj-$(CONFIG_FW_LOADER) += firmware_class.o |
9 | obj-$(CONFIG_NUMA) += node.o | 10 | obj-$(CONFIG_NUMA) += node.o |
10 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o | 11 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o |
11 | obj-$(CONFIG_SMP) += topology.o | 12 | obj-$(CONFIG_SMP) += topology.o |
13 | obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o | ||
12 | 14 | ||
13 | ifeq ($(CONFIG_DEBUG_DRIVER),y) | 15 | ifeq ($(CONFIG_DEBUG_DRIVER),y) |
14 | EXTRA_CFLAGS += -DDEBUG | 16 | EXTRA_CFLAGS += -DDEBUG |
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 2a7d7ae83e1e..22220733f76f 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c | |||
@@ -236,7 +236,6 @@ attribute_container_remove_device(struct device *dev, | |||
236 | } | 236 | } |
237 | up(&attribute_container_mutex); | 237 | up(&attribute_container_mutex); |
238 | } | 238 | } |
239 | EXPORT_SYMBOL_GPL(attribute_container_remove_device); | ||
240 | 239 | ||
241 | /** | 240 | /** |
242 | * attribute_container_device_trigger - execute a trigger for each matching classdev | 241 | * attribute_container_device_trigger - execute a trigger for each matching classdev |
@@ -276,7 +275,6 @@ attribute_container_device_trigger(struct device *dev, | |||
276 | } | 275 | } |
277 | up(&attribute_container_mutex); | 276 | up(&attribute_container_mutex); |
278 | } | 277 | } |
279 | EXPORT_SYMBOL_GPL(attribute_container_device_trigger); | ||
280 | 278 | ||
281 | /** | 279 | /** |
282 | * attribute_container_trigger - trigger a function for each matching container | 280 | * attribute_container_trigger - trigger a function for each matching container |
@@ -304,7 +302,6 @@ attribute_container_trigger(struct device *dev, | |||
304 | } | 302 | } |
305 | up(&attribute_container_mutex); | 303 | up(&attribute_container_mutex); |
306 | } | 304 | } |
307 | EXPORT_SYMBOL_GPL(attribute_container_trigger); | ||
308 | 305 | ||
309 | /** | 306 | /** |
310 | * attribute_container_add_attrs - add attributes | 307 | * attribute_container_add_attrs - add attributes |
@@ -333,7 +330,6 @@ attribute_container_add_attrs(struct class_device *classdev) | |||
333 | 330 | ||
334 | return 0; | 331 | return 0; |
335 | } | 332 | } |
336 | EXPORT_SYMBOL_GPL(attribute_container_add_attrs); | ||
337 | 333 | ||
338 | /** | 334 | /** |
339 | * attribute_container_add_class_device - same function as class_device_add | 335 | * attribute_container_add_class_device - same function as class_device_add |
@@ -352,7 +348,6 @@ attribute_container_add_class_device(struct class_device *classdev) | |||
352 | return error; | 348 | return error; |
353 | return attribute_container_add_attrs(classdev); | 349 | return attribute_container_add_attrs(classdev); |
354 | } | 350 | } |
355 | EXPORT_SYMBOL_GPL(attribute_container_add_class_device); | ||
356 | 351 | ||
357 | /** | 352 | /** |
358 | * attribute_container_add_class_device_adapter - simple adapter for triggers | 353 | * attribute_container_add_class_device_adapter - simple adapter for triggers |
@@ -367,7 +362,6 @@ attribute_container_add_class_device_adapter(struct attribute_container *cont, | |||
367 | { | 362 | { |
368 | return attribute_container_add_class_device(classdev); | 363 | return attribute_container_add_class_device(classdev); |
369 | } | 364 | } |
370 | EXPORT_SYMBOL_GPL(attribute_container_add_class_device_adapter); | ||
371 | 365 | ||
372 | /** | 366 | /** |
373 | * attribute_container_remove_attrs - remove any attribute files | 367 | * attribute_container_remove_attrs - remove any attribute files |
@@ -389,7 +383,6 @@ attribute_container_remove_attrs(struct class_device *classdev) | |||
389 | for (i = 0; attrs[i]; i++) | 383 | for (i = 0; attrs[i]; i++) |
390 | class_device_remove_file(classdev, attrs[i]); | 384 | class_device_remove_file(classdev, attrs[i]); |
391 | } | 385 | } |
392 | EXPORT_SYMBOL_GPL(attribute_container_remove_attrs); | ||
393 | 386 | ||
394 | /** | 387 | /** |
395 | * attribute_container_class_device_del - equivalent of class_device_del | 388 | * attribute_container_class_device_del - equivalent of class_device_del |
@@ -405,7 +398,6 @@ attribute_container_class_device_del(struct class_device *classdev) | |||
405 | attribute_container_remove_attrs(classdev); | 398 | attribute_container_remove_attrs(classdev); |
406 | class_device_del(classdev); | 399 | class_device_del(classdev); |
407 | } | 400 | } |
408 | EXPORT_SYMBOL_GPL(attribute_container_class_device_del); | ||
409 | 401 | ||
410 | /** | 402 | /** |
411 | * attribute_container_find_class_device - find the corresponding class_device | 403 | * attribute_container_find_class_device - find the corresponding class_device |
diff --git a/drivers/base/base.h b/drivers/base/base.h index 5735b38582d0..c3b8dc98b8a7 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h | |||
@@ -5,13 +5,21 @@ extern int devices_init(void); | |||
5 | extern int buses_init(void); | 5 | extern int buses_init(void); |
6 | extern int classes_init(void); | 6 | extern int classes_init(void); |
7 | extern int firmware_init(void); | 7 | extern int firmware_init(void); |
8 | #ifdef CONFIG_SYS_HYPERVISOR | ||
9 | extern int hypervisor_init(void); | ||
10 | #else | ||
11 | static inline int hypervisor_init(void) { return 0; } | ||
12 | #endif | ||
8 | extern int platform_bus_init(void); | 13 | extern int platform_bus_init(void); |
9 | extern int system_bus_init(void); | 14 | extern int system_bus_init(void); |
10 | extern int cpu_dev_init(void); | 15 | extern int cpu_dev_init(void); |
11 | extern int attribute_container_init(void); | 16 | extern int attribute_container_init(void); |
12 | 17 | ||
13 | extern int bus_add_device(struct device * dev); | 18 | extern int bus_add_device(struct device * dev); |
19 | extern void bus_attach_device(struct device * dev); | ||
14 | extern void bus_remove_device(struct device * dev); | 20 | extern void bus_remove_device(struct device * dev); |
21 | extern struct bus_type *get_bus(struct bus_type * bus); | ||
22 | extern void put_bus(struct bus_type * bus); | ||
15 | 23 | ||
16 | extern int bus_add_driver(struct device_driver *); | 24 | extern int bus_add_driver(struct device_driver *); |
17 | extern void bus_remove_driver(struct device_driver *); | 25 | extern void bus_remove_driver(struct device_driver *); |
@@ -34,4 +42,5 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) | |||
34 | return container_of(_attr, struct class_device_attribute, attr); | 42 | return container_of(_attr, struct class_device_attribute, attr); |
35 | } | 43 | } |
36 | 44 | ||
45 | extern char *make_class_name(const char *name, struct kobject *kobj); | ||
37 | 46 | ||
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 76656acd00d4..050d86d0b872 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
@@ -362,8 +362,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev) | |||
362 | * @dev: device being added | 362 | * @dev: device being added |
363 | * | 363 | * |
364 | * - Add the device to its bus's list of devices. | 364 | * - Add the device to its bus's list of devices. |
365 | * - Try to attach to driver. | 365 | * - Create link to device's bus. |
366 | * - Create link to device's physical location. | ||
367 | */ | 366 | */ |
368 | int bus_add_device(struct device * dev) | 367 | int bus_add_device(struct device * dev) |
369 | { | 368 | { |
@@ -372,11 +371,10 @@ int bus_add_device(struct device * dev) | |||
372 | 371 | ||
373 | if (bus) { | 372 | if (bus) { |
374 | pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); | 373 | pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); |
375 | device_attach(dev); | ||
376 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); | ||
377 | error = device_add_attrs(bus, dev); | 374 | error = device_add_attrs(bus, dev); |
378 | if (!error) { | 375 | if (!error) { |
379 | sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); | 376 | sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); |
377 | sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "subsystem"); | ||
380 | sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus"); | 378 | sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus"); |
381 | } | 379 | } |
382 | } | 380 | } |
@@ -384,6 +382,22 @@ int bus_add_device(struct device * dev) | |||
384 | } | 382 | } |
385 | 383 | ||
386 | /** | 384 | /** |
385 | * bus_attach_device - add device to bus | ||
386 | * @dev: device tried to attach to a driver | ||
387 | * | ||
388 | * - Try to attach to driver. | ||
389 | */ | ||
390 | void bus_attach_device(struct device * dev) | ||
391 | { | ||
392 | struct bus_type * bus = dev->bus; | ||
393 | |||
394 | if (bus) { | ||
395 | device_attach(dev); | ||
396 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); | ||
397 | } | ||
398 | } | ||
399 | |||
400 | /** | ||
387 | * bus_remove_device - remove device from bus | 401 | * bus_remove_device - remove device from bus |
388 | * @dev: device to be removed | 402 | * @dev: device to be removed |
389 | * | 403 | * |
@@ -395,6 +409,7 @@ int bus_add_device(struct device * dev) | |||
395 | void bus_remove_device(struct device * dev) | 409 | void bus_remove_device(struct device * dev) |
396 | { | 410 | { |
397 | if (dev->bus) { | 411 | if (dev->bus) { |
412 | sysfs_remove_link(&dev->kobj, "subsystem"); | ||
398 | sysfs_remove_link(&dev->kobj, "bus"); | 413 | sysfs_remove_link(&dev->kobj, "bus"); |
399 | sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); | 414 | sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); |
400 | device_remove_attrs(dev->bus, dev); | 415 | device_remove_attrs(dev->bus, dev); |
@@ -732,14 +747,9 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev); | |||
732 | EXPORT_SYMBOL_GPL(bus_find_device); | 747 | EXPORT_SYMBOL_GPL(bus_find_device); |
733 | EXPORT_SYMBOL_GPL(bus_for_each_drv); | 748 | EXPORT_SYMBOL_GPL(bus_for_each_drv); |
734 | 749 | ||
735 | EXPORT_SYMBOL_GPL(bus_add_device); | ||
736 | EXPORT_SYMBOL_GPL(bus_remove_device); | ||
737 | EXPORT_SYMBOL_GPL(bus_register); | 750 | EXPORT_SYMBOL_GPL(bus_register); |
738 | EXPORT_SYMBOL_GPL(bus_unregister); | 751 | EXPORT_SYMBOL_GPL(bus_unregister); |
739 | EXPORT_SYMBOL_GPL(bus_rescan_devices); | 752 | EXPORT_SYMBOL_GPL(bus_rescan_devices); |
740 | EXPORT_SYMBOL_GPL(get_bus); | ||
741 | EXPORT_SYMBOL_GPL(put_bus); | ||
742 | EXPORT_SYMBOL_GPL(find_bus); | ||
743 | 753 | ||
744 | EXPORT_SYMBOL_GPL(bus_create_file); | 754 | EXPORT_SYMBOL_GPL(bus_create_file); |
745 | EXPORT_SYMBOL_GPL(bus_remove_file); | 755 | EXPORT_SYMBOL_GPL(bus_remove_file); |
diff --git a/drivers/base/class.c b/drivers/base/class.c index b1ea4df85c7d..9aa127460262 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
@@ -91,14 +91,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) | |||
91 | sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr); | 91 | sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr); |
92 | } | 92 | } |
93 | 93 | ||
94 | struct class * class_get(struct class * cls) | 94 | static struct class *class_get(struct class *cls) |
95 | { | 95 | { |
96 | if (cls) | 96 | if (cls) |
97 | return container_of(subsys_get(&cls->subsys), struct class, subsys); | 97 | return container_of(subsys_get(&cls->subsys), struct class, subsys); |
98 | return NULL; | 98 | return NULL; |
99 | } | 99 | } |
100 | 100 | ||
101 | void class_put(struct class * cls) | 101 | static void class_put(struct class * cls) |
102 | { | 102 | { |
103 | if (cls) | 103 | if (cls) |
104 | subsys_put(&cls->subsys); | 104 | subsys_put(&cls->subsys); |
@@ -142,6 +142,7 @@ int class_register(struct class * cls) | |||
142 | pr_debug("device class '%s': registering\n", cls->name); | 142 | pr_debug("device class '%s': registering\n", cls->name); |
143 | 143 | ||
144 | INIT_LIST_HEAD(&cls->children); | 144 | INIT_LIST_HEAD(&cls->children); |
145 | INIT_LIST_HEAD(&cls->devices); | ||
145 | INIT_LIST_HEAD(&cls->interfaces); | 146 | INIT_LIST_HEAD(&cls->interfaces); |
146 | init_MUTEX(&cls->sem); | 147 | init_MUTEX(&cls->sem); |
147 | error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); | 148 | error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); |
@@ -504,22 +505,21 @@ void class_device_initialize(struct class_device *class_dev) | |||
504 | INIT_LIST_HEAD(&class_dev->node); | 505 | INIT_LIST_HEAD(&class_dev->node); |
505 | } | 506 | } |
506 | 507 | ||
507 | static char *make_class_name(struct class_device *class_dev) | 508 | char *make_class_name(const char *name, struct kobject *kobj) |
508 | { | 509 | { |
509 | char *name; | 510 | char *class_name; |
510 | int size; | 511 | int size; |
511 | 512 | ||
512 | size = strlen(class_dev->class->name) + | 513 | size = strlen(name) + strlen(kobject_name(kobj)) + 2; |
513 | strlen(kobject_name(&class_dev->kobj)) + 2; | ||
514 | 514 | ||
515 | name = kmalloc(size, GFP_KERNEL); | 515 | class_name = kmalloc(size, GFP_KERNEL); |
516 | if (!name) | 516 | if (!class_name) |
517 | return ERR_PTR(-ENOMEM); | 517 | return ERR_PTR(-ENOMEM); |
518 | 518 | ||
519 | strcpy(name, class_dev->class->name); | 519 | strcpy(class_name, name); |
520 | strcat(name, ":"); | 520 | strcat(class_name, ":"); |
521 | strcat(name, kobject_name(&class_dev->kobj)); | 521 | strcat(class_name, kobject_name(kobj)); |
522 | return name; | 522 | return class_name; |
523 | } | 523 | } |
524 | 524 | ||
525 | int class_device_add(struct class_device *class_dev) | 525 | int class_device_add(struct class_device *class_dev) |
@@ -535,18 +535,22 @@ int class_device_add(struct class_device *class_dev) | |||
535 | return -EINVAL; | 535 | return -EINVAL; |
536 | 536 | ||
537 | if (!strlen(class_dev->class_id)) | 537 | if (!strlen(class_dev->class_id)) |
538 | goto register_done; | 538 | goto out1; |
539 | 539 | ||
540 | parent_class = class_get(class_dev->class); | 540 | parent_class = class_get(class_dev->class); |
541 | if (!parent_class) | 541 | if (!parent_class) |
542 | goto register_done; | 542 | goto out1; |
543 | |||
543 | parent_class_dev = class_device_get(class_dev->parent); | 544 | parent_class_dev = class_device_get(class_dev->parent); |
544 | 545 | ||
545 | pr_debug("CLASS: registering class device: ID = '%s'\n", | 546 | pr_debug("CLASS: registering class device: ID = '%s'\n", |
546 | class_dev->class_id); | 547 | class_dev->class_id); |
547 | 548 | ||
548 | /* first, register with generic layer. */ | 549 | /* first, register with generic layer. */ |
549 | kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id); | 550 | error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id); |
551 | if (error) | ||
552 | goto out2; | ||
553 | |||
550 | if (parent_class_dev) | 554 | if (parent_class_dev) |
551 | class_dev->kobj.parent = &parent_class_dev->kobj; | 555 | class_dev->kobj.parent = &parent_class_dev->kobj; |
552 | else | 556 | else |
@@ -554,41 +558,58 @@ int class_device_add(struct class_device *class_dev) | |||
554 | 558 | ||
555 | error = kobject_add(&class_dev->kobj); | 559 | error = kobject_add(&class_dev->kobj); |
556 | if (error) | 560 | if (error) |
557 | goto register_done; | 561 | goto out2; |
558 | 562 | ||
559 | /* add the needed attributes to this device */ | 563 | /* add the needed attributes to this device */ |
564 | sysfs_create_link(&class_dev->kobj, &parent_class->subsys.kset.kobj, "subsystem"); | ||
560 | class_dev->uevent_attr.attr.name = "uevent"; | 565 | class_dev->uevent_attr.attr.name = "uevent"; |
561 | class_dev->uevent_attr.attr.mode = S_IWUSR; | 566 | class_dev->uevent_attr.attr.mode = S_IWUSR; |
562 | class_dev->uevent_attr.attr.owner = parent_class->owner; | 567 | class_dev->uevent_attr.attr.owner = parent_class->owner; |
563 | class_dev->uevent_attr.store = store_uevent; | 568 | class_dev->uevent_attr.store = store_uevent; |
564 | class_device_create_file(class_dev, &class_dev->uevent_attr); | 569 | error = class_device_create_file(class_dev, &class_dev->uevent_attr); |
570 | if (error) | ||
571 | goto out3; | ||
565 | 572 | ||
566 | if (MAJOR(class_dev->devt)) { | 573 | if (MAJOR(class_dev->devt)) { |
567 | struct class_device_attribute *attr; | 574 | struct class_device_attribute *attr; |
568 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | 575 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); |
569 | if (!attr) { | 576 | if (!attr) { |
570 | error = -ENOMEM; | 577 | error = -ENOMEM; |
571 | kobject_del(&class_dev->kobj); | 578 | goto out4; |
572 | goto register_done; | ||
573 | } | 579 | } |
574 | attr->attr.name = "dev"; | 580 | attr->attr.name = "dev"; |
575 | attr->attr.mode = S_IRUGO; | 581 | attr->attr.mode = S_IRUGO; |
576 | attr->attr.owner = parent_class->owner; | 582 | attr->attr.owner = parent_class->owner; |
577 | attr->show = show_dev; | 583 | attr->show = show_dev; |
578 | class_device_create_file(class_dev, attr); | 584 | error = class_device_create_file(class_dev, attr); |
585 | if (error) { | ||
586 | kfree(attr); | ||
587 | goto out4; | ||
588 | } | ||
589 | |||
579 | class_dev->devt_attr = attr; | 590 | class_dev->devt_attr = attr; |
580 | } | 591 | } |
581 | 592 | ||
582 | class_device_add_attrs(class_dev); | 593 | error = class_device_add_attrs(class_dev); |
594 | if (error) | ||
595 | goto out5; | ||
596 | |||
583 | if (class_dev->dev) { | 597 | if (class_dev->dev) { |
584 | class_name = make_class_name(class_dev); | 598 | class_name = make_class_name(class_dev->class->name, |
585 | sysfs_create_link(&class_dev->kobj, | 599 | &class_dev->kobj); |
586 | &class_dev->dev->kobj, "device"); | 600 | error = sysfs_create_link(&class_dev->kobj, |
587 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | 601 | &class_dev->dev->kobj, "device"); |
588 | class_name); | 602 | if (error) |
603 | goto out6; | ||
604 | error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | ||
605 | class_name); | ||
606 | if (error) | ||
607 | goto out7; | ||
589 | } | 608 | } |
590 | 609 | ||
591 | class_device_add_groups(class_dev); | 610 | error = class_device_add_groups(class_dev); |
611 | if (error) | ||
612 | goto out8; | ||
592 | 613 | ||
593 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); | 614 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); |
594 | 615 | ||
@@ -601,11 +622,28 @@ int class_device_add(struct class_device *class_dev) | |||
601 | } | 622 | } |
602 | up(&parent_class->sem); | 623 | up(&parent_class->sem); |
603 | 624 | ||
604 | register_done: | 625 | goto out1; |
605 | if (error) { | 626 | |
606 | class_put(parent_class); | 627 | out8: |
628 | if (class_dev->dev) | ||
629 | sysfs_remove_link(&class_dev->kobj, class_name); | ||
630 | out7: | ||
631 | if (class_dev->dev) | ||
632 | sysfs_remove_link(&class_dev->kobj, "device"); | ||
633 | out6: | ||
634 | class_device_remove_attrs(class_dev); | ||
635 | out5: | ||
636 | if (class_dev->devt_attr) | ||
637 | class_device_remove_file(class_dev, class_dev->devt_attr); | ||
638 | out4: | ||
639 | class_device_remove_file(class_dev, &class_dev->uevent_attr); | ||
640 | out3: | ||
641 | kobject_del(&class_dev->kobj); | ||
642 | out2: | ||
643 | if(parent_class_dev) | ||
607 | class_device_put(parent_class_dev); | 644 | class_device_put(parent_class_dev); |
608 | } | 645 | class_put(parent_class); |
646 | out1: | ||
609 | class_device_put(class_dev); | 647 | class_device_put(class_dev); |
610 | kfree(class_name); | 648 | kfree(class_name); |
611 | return error; | 649 | return error; |
@@ -695,10 +733,12 @@ void class_device_del(struct class_device *class_dev) | |||
695 | } | 733 | } |
696 | 734 | ||
697 | if (class_dev->dev) { | 735 | if (class_dev->dev) { |
698 | class_name = make_class_name(class_dev); | 736 | class_name = make_class_name(class_dev->class->name, |
737 | &class_dev->kobj); | ||
699 | sysfs_remove_link(&class_dev->kobj, "device"); | 738 | sysfs_remove_link(&class_dev->kobj, "device"); |
700 | sysfs_remove_link(&class_dev->dev->kobj, class_name); | 739 | sysfs_remove_link(&class_dev->dev->kobj, class_name); |
701 | } | 740 | } |
741 | sysfs_remove_link(&class_dev->kobj, "subsystem"); | ||
702 | class_device_remove_file(class_dev, &class_dev->uevent_attr); | 742 | class_device_remove_file(class_dev, &class_dev->uevent_attr); |
703 | if (class_dev->devt_attr) | 743 | if (class_dev->devt_attr) |
704 | class_device_remove_file(class_dev, class_dev->devt_attr); | 744 | class_device_remove_file(class_dev, class_dev->devt_attr); |
@@ -760,14 +800,16 @@ int class_device_rename(struct class_device *class_dev, char *new_name) | |||
760 | new_name); | 800 | new_name); |
761 | 801 | ||
762 | if (class_dev->dev) | 802 | if (class_dev->dev) |
763 | old_class_name = make_class_name(class_dev); | 803 | old_class_name = make_class_name(class_dev->class->name, |
804 | &class_dev->kobj); | ||
764 | 805 | ||
765 | strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); | 806 | strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); |
766 | 807 | ||
767 | error = kobject_rename(&class_dev->kobj, new_name); | 808 | error = kobject_rename(&class_dev->kobj, new_name); |
768 | 809 | ||
769 | if (class_dev->dev) { | 810 | if (class_dev->dev) { |
770 | new_class_name = make_class_name(class_dev); | 811 | new_class_name = make_class_name(class_dev->class->name, |
812 | &class_dev->kobj); | ||
771 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | 813 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, |
772 | new_class_name); | 814 | new_class_name); |
773 | sysfs_remove_link(&class_dev->dev->kobj, old_class_name); | 815 | sysfs_remove_link(&class_dev->dev->kobj, old_class_name); |
@@ -858,8 +900,6 @@ EXPORT_SYMBOL_GPL(class_create_file); | |||
858 | EXPORT_SYMBOL_GPL(class_remove_file); | 900 | EXPORT_SYMBOL_GPL(class_remove_file); |
859 | EXPORT_SYMBOL_GPL(class_register); | 901 | EXPORT_SYMBOL_GPL(class_register); |
860 | EXPORT_SYMBOL_GPL(class_unregister); | 902 | EXPORT_SYMBOL_GPL(class_unregister); |
861 | EXPORT_SYMBOL_GPL(class_get); | ||
862 | EXPORT_SYMBOL_GPL(class_put); | ||
863 | EXPORT_SYMBOL_GPL(class_create); | 903 | EXPORT_SYMBOL_GPL(class_create); |
864 | EXPORT_SYMBOL_GPL(class_destroy); | 904 | EXPORT_SYMBOL_GPL(class_destroy); |
865 | 905 | ||
diff --git a/drivers/base/core.c b/drivers/base/core.c index 6b355bd7816d..27c2176895de 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
18 | #include <linux/kdev_t.h> | ||
18 | 19 | ||
19 | #include <asm/semaphore.h> | 20 | #include <asm/semaphore.h> |
20 | 21 | ||
@@ -28,6 +29,22 @@ int (*platform_notify_remove)(struct device * dev) = NULL; | |||
28 | * sysfs bindings for devices. | 29 | * sysfs bindings for devices. |
29 | */ | 30 | */ |
30 | 31 | ||
32 | /** | ||
33 | * dev_driver_string - Return a device's driver name, if at all possible | ||
34 | * @dev: struct device to get the name of | ||
35 | * | ||
36 | * Will return the device's driver's name if it is bound to a device. If | ||
37 | * the device is not bound to a device, it will return the name of the bus | ||
38 | * it is attached to. If it is not attached to a bus either, an empty | ||
39 | * string will be returned. | ||
40 | */ | ||
41 | const char *dev_driver_string(struct device *dev) | ||
42 | { | ||
43 | return dev->driver ? dev->driver->name : | ||
44 | (dev->bus ? dev->bus->name : ""); | ||
45 | } | ||
46 | EXPORT_SYMBOL_GPL(dev_driver_string); | ||
47 | |||
31 | #define to_dev(obj) container_of(obj, struct device, kobj) | 48 | #define to_dev(obj) container_of(obj, struct device, kobj) |
32 | #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) | 49 | #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) |
33 | 50 | ||
@@ -98,6 +115,8 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) | |||
98 | struct device *dev = to_dev(kobj); | 115 | struct device *dev = to_dev(kobj); |
99 | if (dev->bus) | 116 | if (dev->bus) |
100 | return 1; | 117 | return 1; |
118 | if (dev->class) | ||
119 | return 1; | ||
101 | } | 120 | } |
102 | return 0; | 121 | return 0; |
103 | } | 122 | } |
@@ -106,7 +125,11 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) | |||
106 | { | 125 | { |
107 | struct device *dev = to_dev(kobj); | 126 | struct device *dev = to_dev(kobj); |
108 | 127 | ||
109 | return dev->bus->name; | 128 | if (dev->bus) |
129 | return dev->bus->name; | ||
130 | if (dev->class) | ||
131 | return dev->class->name; | ||
132 | return NULL; | ||
110 | } | 133 | } |
111 | 134 | ||
112 | static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | 135 | static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, |
@@ -117,6 +140,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | |||
117 | int length = 0; | 140 | int length = 0; |
118 | int retval = 0; | 141 | int retval = 0; |
119 | 142 | ||
143 | /* add the major/minor if present */ | ||
144 | if (MAJOR(dev->devt)) { | ||
145 | add_uevent_var(envp, num_envp, &i, | ||
146 | buffer, buffer_size, &length, | ||
147 | "MAJOR=%u", MAJOR(dev->devt)); | ||
148 | add_uevent_var(envp, num_envp, &i, | ||
149 | buffer, buffer_size, &length, | ||
150 | "MINOR=%u", MINOR(dev->devt)); | ||
151 | } | ||
152 | |||
120 | /* add bus name of physical device */ | 153 | /* add bus name of physical device */ |
121 | if (dev->bus) | 154 | if (dev->bus) |
122 | add_uevent_var(envp, num_envp, &i, | 155 | add_uevent_var(envp, num_envp, &i, |
@@ -161,6 +194,12 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, | |||
161 | return count; | 194 | return count; |
162 | } | 195 | } |
163 | 196 | ||
197 | static ssize_t show_dev(struct device *dev, struct device_attribute *attr, | ||
198 | char *buf) | ||
199 | { | ||
200 | return print_dev_t(buf, dev->devt); | ||
201 | } | ||
202 | |||
164 | /* | 203 | /* |
165 | * devices_subsys - structure to be registered with kobject core. | 204 | * devices_subsys - structure to be registered with kobject core. |
166 | */ | 205 | */ |
@@ -231,6 +270,7 @@ void device_initialize(struct device *dev) | |||
231 | klist_init(&dev->klist_children, klist_children_get, | 270 | klist_init(&dev->klist_children, klist_children_get, |
232 | klist_children_put); | 271 | klist_children_put); |
233 | INIT_LIST_HEAD(&dev->dma_pools); | 272 | INIT_LIST_HEAD(&dev->dma_pools); |
273 | INIT_LIST_HEAD(&dev->node); | ||
234 | init_MUTEX(&dev->sem); | 274 | init_MUTEX(&dev->sem); |
235 | device_init_wakeup(dev, 0); | 275 | device_init_wakeup(dev, 0); |
236 | } | 276 | } |
@@ -249,6 +289,7 @@ void device_initialize(struct device *dev) | |||
249 | int device_add(struct device *dev) | 289 | int device_add(struct device *dev) |
250 | { | 290 | { |
251 | struct device *parent = NULL; | 291 | struct device *parent = NULL; |
292 | char *class_name = NULL; | ||
252 | int error = -EINVAL; | 293 | int error = -EINVAL; |
253 | 294 | ||
254 | dev = get_device(dev); | 295 | dev = get_device(dev); |
@@ -274,23 +315,69 @@ int device_add(struct device *dev) | |||
274 | dev->uevent_attr.store = store_uevent; | 315 | dev->uevent_attr.store = store_uevent; |
275 | device_create_file(dev, &dev->uevent_attr); | 316 | device_create_file(dev, &dev->uevent_attr); |
276 | 317 | ||
277 | kobject_uevent(&dev->kobj, KOBJ_ADD); | 318 | if (MAJOR(dev->devt)) { |
319 | struct device_attribute *attr; | ||
320 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | ||
321 | if (!attr) { | ||
322 | error = -ENOMEM; | ||
323 | goto PMError; | ||
324 | } | ||
325 | attr->attr.name = "dev"; | ||
326 | attr->attr.mode = S_IRUGO; | ||
327 | if (dev->driver) | ||
328 | attr->attr.owner = dev->driver->owner; | ||
329 | attr->show = show_dev; | ||
330 | error = device_create_file(dev, attr); | ||
331 | if (error) { | ||
332 | kfree(attr); | ||
333 | goto attrError; | ||
334 | } | ||
335 | |||
336 | dev->devt_attr = attr; | ||
337 | } | ||
338 | |||
339 | if (dev->class) { | ||
340 | sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj, | ||
341 | "subsystem"); | ||
342 | sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, | ||
343 | dev->bus_id); | ||
344 | |||
345 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); | ||
346 | class_name = make_class_name(dev->class->name, &dev->kobj); | ||
347 | sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name); | ||
348 | } | ||
349 | |||
278 | if ((error = device_pm_add(dev))) | 350 | if ((error = device_pm_add(dev))) |
279 | goto PMError; | 351 | goto PMError; |
280 | if ((error = bus_add_device(dev))) | 352 | if ((error = bus_add_device(dev))) |
281 | goto BusError; | 353 | goto BusError; |
354 | kobject_uevent(&dev->kobj, KOBJ_ADD); | ||
355 | bus_attach_device(dev); | ||
282 | if (parent) | 356 | if (parent) |
283 | klist_add_tail(&dev->knode_parent, &parent->klist_children); | 357 | klist_add_tail(&dev->knode_parent, &parent->klist_children); |
284 | 358 | ||
359 | if (dev->class) { | ||
360 | /* tie the class to the device */ | ||
361 | down(&dev->class->sem); | ||
362 | list_add_tail(&dev->node, &dev->class->devices); | ||
363 | up(&dev->class->sem); | ||
364 | } | ||
365 | |||
285 | /* notify platform of device entry */ | 366 | /* notify platform of device entry */ |
286 | if (platform_notify) | 367 | if (platform_notify) |
287 | platform_notify(dev); | 368 | platform_notify(dev); |
288 | Done: | 369 | Done: |
370 | kfree(class_name); | ||
289 | put_device(dev); | 371 | put_device(dev); |
290 | return error; | 372 | return error; |
291 | BusError: | 373 | BusError: |
292 | device_pm_remove(dev); | 374 | device_pm_remove(dev); |
293 | PMError: | 375 | PMError: |
376 | if (dev->devt_attr) { | ||
377 | device_remove_file(dev, dev->devt_attr); | ||
378 | kfree(dev->devt_attr); | ||
379 | } | ||
380 | attrError: | ||
294 | kobject_uevent(&dev->kobj, KOBJ_REMOVE); | 381 | kobject_uevent(&dev->kobj, KOBJ_REMOVE); |
295 | kobject_del(&dev->kobj); | 382 | kobject_del(&dev->kobj); |
296 | Error: | 383 | Error: |
@@ -362,9 +449,23 @@ void put_device(struct device * dev) | |||
362 | void device_del(struct device * dev) | 449 | void device_del(struct device * dev) |
363 | { | 450 | { |
364 | struct device * parent = dev->parent; | 451 | struct device * parent = dev->parent; |
452 | char *class_name = NULL; | ||
365 | 453 | ||
366 | if (parent) | 454 | if (parent) |
367 | klist_del(&dev->knode_parent); | 455 | klist_del(&dev->knode_parent); |
456 | if (dev->devt_attr) | ||
457 | device_remove_file(dev, dev->devt_attr); | ||
458 | if (dev->class) { | ||
459 | sysfs_remove_link(&dev->kobj, "subsystem"); | ||
460 | sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id); | ||
461 | class_name = make_class_name(dev->class->name, &dev->kobj); | ||
462 | sysfs_remove_link(&dev->kobj, "device"); | ||
463 | sysfs_remove_link(&dev->parent->kobj, class_name); | ||
464 | kfree(class_name); | ||
465 | down(&dev->class->sem); | ||
466 | list_del_init(&dev->node); | ||
467 | up(&dev->class->sem); | ||
468 | } | ||
368 | device_remove_file(dev, &dev->uevent_attr); | 469 | device_remove_file(dev, &dev->uevent_attr); |
369 | 470 | ||
370 | /* Notify the platform of the removal, in case they | 471 | /* Notify the platform of the removal, in case they |
@@ -449,3 +550,98 @@ EXPORT_SYMBOL_GPL(put_device); | |||
449 | 550 | ||
450 | EXPORT_SYMBOL_GPL(device_create_file); | 551 | EXPORT_SYMBOL_GPL(device_create_file); |
451 | EXPORT_SYMBOL_GPL(device_remove_file); | 552 | EXPORT_SYMBOL_GPL(device_remove_file); |
553 | |||
554 | |||
555 | static void device_create_release(struct device *dev) | ||
556 | { | ||
557 | pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id); | ||
558 | kfree(dev); | ||
559 | } | ||
560 | |||
561 | /** | ||
562 | * device_create - creates a device and registers it with sysfs | ||
563 | * @cs: 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. | ||
565 | * @dev: the dev_t for the char device to be added. | ||
566 | * @fmt: string for the class device's name | ||
567 | * | ||
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 | ||
572 | * the dev_t is not 0,0. | ||
573 | * If a pointer to a parent struct device is passed in, the newly | ||
574 | * created struct device will be a child of that device in sysfs. The | ||
575 | * pointer to the struct device will be returned from the call. Any | ||
576 | * further sysfs files that might be required can be created using this | ||
577 | * pointer. | ||
578 | * | ||
579 | * Note: the struct class passed to this function must have previously | ||
580 | * been created with a call to class_create(). | ||
581 | */ | ||
582 | struct device *device_create(struct class *class, struct device *parent, | ||
583 | dev_t devt, char *fmt, ...) | ||
584 | { | ||
585 | va_list args; | ||
586 | struct device *dev = NULL; | ||
587 | int retval = -ENODEV; | ||
588 | |||
589 | if (class == NULL || IS_ERR(class)) | ||
590 | 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 | |||
596 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
597 | if (!dev) { | ||
598 | retval = -ENOMEM; | ||
599 | goto error; | ||
600 | } | ||
601 | |||
602 | dev->devt = devt; | ||
603 | dev->class = class; | ||
604 | dev->parent = parent; | ||
605 | dev->release = device_create_release; | ||
606 | |||
607 | va_start(args, fmt); | ||
608 | vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); | ||
609 | va_end(args); | ||
610 | retval = device_register(dev); | ||
611 | if (retval) | ||
612 | goto error; | ||
613 | |||
614 | return dev; | ||
615 | |||
616 | error: | ||
617 | kfree(dev); | ||
618 | return ERR_PTR(retval); | ||
619 | } | ||
620 | EXPORT_SYMBOL_GPL(device_create); | ||
621 | |||
622 | /** | ||
623 | * 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. | ||
625 | * @dev: the dev_t of the device that was previously registered. | ||
626 | * | ||
627 | * This call unregisters and cleans up a class device that was created with a | ||
628 | * call to class_device_create() | ||
629 | */ | ||
630 | void device_destroy(struct class *class, dev_t devt) | ||
631 | { | ||
632 | struct device *dev = NULL; | ||
633 | struct device *dev_tmp; | ||
634 | |||
635 | down(&class->sem); | ||
636 | list_for_each_entry(dev_tmp, &class->devices, node) { | ||
637 | if (dev_tmp->devt == devt) { | ||
638 | dev = dev_tmp; | ||
639 | break; | ||
640 | } | ||
641 | } | ||
642 | up(&class->sem); | ||
643 | |||
644 | if (dev) | ||
645 | device_unregister(dev); | ||
646 | } | ||
647 | EXPORT_SYMBOL_GPL(device_destroy); | ||
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 0c99ae6a3407..5d6c011183f5 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/vmalloc.h> | 15 | #include <linux/vmalloc.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/bitops.h> | 17 | #include <linux/bitops.h> |
18 | #include <asm/semaphore.h> | 18 | #include <linux/mutex.h> |
19 | 19 | ||
20 | #include <linux/firmware.h> | 20 | #include <linux/firmware.h> |
21 | #include "base.h" | 21 | #include "base.h" |
@@ -36,7 +36,7 @@ static int loading_timeout = 10; /* In seconds */ | |||
36 | 36 | ||
37 | /* fw_lock could be moved to 'struct firmware_priv' but since it is just | 37 | /* fw_lock could be moved to 'struct firmware_priv' but since it is just |
38 | * guarding for corner cases a global lock should be OK */ | 38 | * guarding for corner cases a global lock should be OK */ |
39 | static DECLARE_MUTEX(fw_lock); | 39 | static DEFINE_MUTEX(fw_lock); |
40 | 40 | ||
41 | struct firmware_priv { | 41 | struct firmware_priv { |
42 | char fw_id[FIRMWARE_NAME_MAX]; | 42 | char fw_id[FIRMWARE_NAME_MAX]; |
@@ -142,9 +142,9 @@ firmware_loading_store(struct class_device *class_dev, | |||
142 | 142 | ||
143 | switch (loading) { | 143 | switch (loading) { |
144 | case 1: | 144 | case 1: |
145 | down(&fw_lock); | 145 | mutex_lock(&fw_lock); |
146 | if (!fw_priv->fw) { | 146 | if (!fw_priv->fw) { |
147 | up(&fw_lock); | 147 | mutex_unlock(&fw_lock); |
148 | break; | 148 | break; |
149 | } | 149 | } |
150 | vfree(fw_priv->fw->data); | 150 | vfree(fw_priv->fw->data); |
@@ -152,7 +152,7 @@ firmware_loading_store(struct class_device *class_dev, | |||
152 | fw_priv->fw->size = 0; | 152 | fw_priv->fw->size = 0; |
153 | fw_priv->alloc_size = 0; | 153 | fw_priv->alloc_size = 0; |
154 | set_bit(FW_STATUS_LOADING, &fw_priv->status); | 154 | set_bit(FW_STATUS_LOADING, &fw_priv->status); |
155 | up(&fw_lock); | 155 | mutex_unlock(&fw_lock); |
156 | break; | 156 | break; |
157 | case 0: | 157 | case 0: |
158 | if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) { | 158 | if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) { |
@@ -185,7 +185,7 @@ firmware_data_read(struct kobject *kobj, | |||
185 | struct firmware *fw; | 185 | struct firmware *fw; |
186 | ssize_t ret_count = count; | 186 | ssize_t ret_count = count; |
187 | 187 | ||
188 | down(&fw_lock); | 188 | mutex_lock(&fw_lock); |
189 | fw = fw_priv->fw; | 189 | fw = fw_priv->fw; |
190 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { | 190 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { |
191 | ret_count = -ENODEV; | 191 | ret_count = -ENODEV; |
@@ -200,7 +200,7 @@ firmware_data_read(struct kobject *kobj, | |||
200 | 200 | ||
201 | memcpy(buffer, fw->data + offset, ret_count); | 201 | memcpy(buffer, fw->data + offset, ret_count); |
202 | out: | 202 | out: |
203 | up(&fw_lock); | 203 | mutex_unlock(&fw_lock); |
204 | return ret_count; | 204 | return ret_count; |
205 | } | 205 | } |
206 | 206 | ||
@@ -253,7 +253,7 @@ firmware_data_write(struct kobject *kobj, | |||
253 | if (!capable(CAP_SYS_RAWIO)) | 253 | if (!capable(CAP_SYS_RAWIO)) |
254 | return -EPERM; | 254 | return -EPERM; |
255 | 255 | ||
256 | down(&fw_lock); | 256 | mutex_lock(&fw_lock); |
257 | fw = fw_priv->fw; | 257 | fw = fw_priv->fw; |
258 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { | 258 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { |
259 | retval = -ENODEV; | 259 | retval = -ENODEV; |
@@ -268,7 +268,7 @@ firmware_data_write(struct kobject *kobj, | |||
268 | fw->size = max_t(size_t, offset + count, fw->size); | 268 | fw->size = max_t(size_t, offset + count, fw->size); |
269 | retval = count; | 269 | retval = count; |
270 | out: | 270 | out: |
271 | up(&fw_lock); | 271 | mutex_unlock(&fw_lock); |
272 | return retval; | 272 | return retval; |
273 | } | 273 | } |
274 | 274 | ||
@@ -436,14 +436,14 @@ _request_firmware(const struct firmware **firmware_p, const char *name, | |||
436 | } else | 436 | } else |
437 | wait_for_completion(&fw_priv->completion); | 437 | wait_for_completion(&fw_priv->completion); |
438 | 438 | ||
439 | down(&fw_lock); | 439 | mutex_lock(&fw_lock); |
440 | if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) { | 440 | if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) { |
441 | retval = -ENOENT; | 441 | retval = -ENOENT; |
442 | release_firmware(fw_priv->fw); | 442 | release_firmware(fw_priv->fw); |
443 | *firmware_p = NULL; | 443 | *firmware_p = NULL; |
444 | } | 444 | } |
445 | fw_priv->fw = NULL; | 445 | fw_priv->fw = NULL; |
446 | up(&fw_lock); | 446 | mutex_unlock(&fw_lock); |
447 | class_device_unregister(class_dev); | 447 | class_device_unregister(class_dev); |
448 | goto out; | 448 | goto out; |
449 | 449 | ||
diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c new file mode 100644 index 000000000000..0c85e9d6a448 --- /dev/null +++ b/drivers/base/hypervisor.c | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * hypervisor.c - /sys/hypervisor subsystem. | ||
3 | * | ||
4 | * This file is released under the GPLv2 | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <linux/kobject.h> | ||
9 | #include <linux/device.h> | ||
10 | |||
11 | #include "base.h" | ||
12 | |||
13 | decl_subsys(hypervisor, NULL, NULL); | ||
14 | EXPORT_SYMBOL_GPL(hypervisor_subsys); | ||
15 | |||
16 | int __init hypervisor_init(void) | ||
17 | { | ||
18 | return subsystem_register(&hypervisor_subsys); | ||
19 | } | ||
diff --git a/drivers/base/init.c b/drivers/base/init.c index c648914b9cde..37138154f9e8 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c | |||
@@ -27,6 +27,7 @@ void __init driver_init(void) | |||
27 | buses_init(); | 27 | buses_init(); |
28 | classes_init(); | 28 | classes_init(); |
29 | firmware_init(); | 29 | firmware_init(); |
30 | hypervisor_init(); | ||
30 | 31 | ||
31 | /* These are also core pieces, but must come after the | 32 | /* These are also core pieces, but must come after the |
32 | * core core pieces. | 33 | * core core pieces. |
diff --git a/drivers/base/isa.c b/drivers/base/isa.c new file mode 100644 index 000000000000..d2222397a401 --- /dev/null +++ b/drivers/base/isa.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * ISA bus. | ||
3 | */ | ||
4 | |||
5 | #include <linux/device.h> | ||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/slab.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/isa.h> | ||
11 | |||
12 | static struct device isa_bus = { | ||
13 | .bus_id = "isa" | ||
14 | }; | ||
15 | |||
16 | struct isa_dev { | ||
17 | struct device dev; | ||
18 | struct device *next; | ||
19 | unsigned int id; | ||
20 | }; | ||
21 | |||
22 | #define to_isa_dev(x) container_of((x), struct isa_dev, dev) | ||
23 | |||
24 | static int isa_bus_match(struct device *dev, struct device_driver *driver) | ||
25 | { | ||
26 | struct isa_driver *isa_driver = to_isa_driver(driver); | ||
27 | |||
28 | if (dev->platform_data == isa_driver) { | ||
29 | if (!isa_driver->match || | ||
30 | isa_driver->match(dev, to_isa_dev(dev)->id)) | ||
31 | return 1; | ||
32 | dev->platform_data = NULL; | ||
33 | } | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static int isa_bus_probe(struct device *dev) | ||
38 | { | ||
39 | struct isa_driver *isa_driver = dev->platform_data; | ||
40 | |||
41 | if (isa_driver->probe) | ||
42 | return isa_driver->probe(dev, to_isa_dev(dev)->id); | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static int isa_bus_remove(struct device *dev) | ||
48 | { | ||
49 | struct isa_driver *isa_driver = dev->platform_data; | ||
50 | |||
51 | if (isa_driver->remove) | ||
52 | return isa_driver->remove(dev, to_isa_dev(dev)->id); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static void isa_bus_shutdown(struct device *dev) | ||
58 | { | ||
59 | struct isa_driver *isa_driver = dev->platform_data; | ||
60 | |||
61 | if (isa_driver->shutdown) | ||
62 | isa_driver->shutdown(dev, to_isa_dev(dev)->id); | ||
63 | } | ||
64 | |||
65 | static int isa_bus_suspend(struct device *dev, pm_message_t state) | ||
66 | { | ||
67 | struct isa_driver *isa_driver = dev->platform_data; | ||
68 | |||
69 | if (isa_driver->suspend) | ||
70 | return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int isa_bus_resume(struct device *dev) | ||
76 | { | ||
77 | struct isa_driver *isa_driver = dev->platform_data; | ||
78 | |||
79 | if (isa_driver->resume) | ||
80 | return isa_driver->resume(dev, to_isa_dev(dev)->id); | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static struct bus_type isa_bus_type = { | ||
86 | .name = "isa", | ||
87 | .match = isa_bus_match, | ||
88 | .probe = isa_bus_probe, | ||
89 | .remove = isa_bus_remove, | ||
90 | .shutdown = isa_bus_shutdown, | ||
91 | .suspend = isa_bus_suspend, | ||
92 | .resume = isa_bus_resume | ||
93 | }; | ||
94 | |||
95 | static void isa_dev_release(struct device *dev) | ||
96 | { | ||
97 | kfree(to_isa_dev(dev)); | ||
98 | } | ||
99 | |||
100 | void isa_unregister_driver(struct isa_driver *isa_driver) | ||
101 | { | ||
102 | struct device *dev = isa_driver->devices; | ||
103 | |||
104 | while (dev) { | ||
105 | struct device *tmp = to_isa_dev(dev)->next; | ||
106 | device_unregister(dev); | ||
107 | dev = tmp; | ||
108 | } | ||
109 | driver_unregister(&isa_driver->driver); | ||
110 | } | ||
111 | EXPORT_SYMBOL_GPL(isa_unregister_driver); | ||
112 | |||
113 | int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) | ||
114 | { | ||
115 | int error; | ||
116 | unsigned int id; | ||
117 | |||
118 | isa_driver->driver.bus = &isa_bus_type; | ||
119 | isa_driver->devices = NULL; | ||
120 | |||
121 | error = driver_register(&isa_driver->driver); | ||
122 | if (error) | ||
123 | return error; | ||
124 | |||
125 | for (id = 0; id < ndev; id++) { | ||
126 | struct isa_dev *isa_dev; | ||
127 | |||
128 | isa_dev = kzalloc(sizeof *isa_dev, GFP_KERNEL); | ||
129 | if (!isa_dev) { | ||
130 | error = -ENOMEM; | ||
131 | break; | ||
132 | } | ||
133 | |||
134 | isa_dev->dev.parent = &isa_bus; | ||
135 | isa_dev->dev.bus = &isa_bus_type; | ||
136 | |||
137 | snprintf(isa_dev->dev.bus_id, BUS_ID_SIZE, "%s.%u", | ||
138 | isa_driver->driver.name, id); | ||
139 | |||
140 | isa_dev->dev.platform_data = isa_driver; | ||
141 | isa_dev->dev.release = isa_dev_release; | ||
142 | isa_dev->id = id; | ||
143 | |||
144 | error = device_register(&isa_dev->dev); | ||
145 | if (error) { | ||
146 | put_device(&isa_dev->dev); | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | if (isa_dev->dev.platform_data) { | ||
151 | isa_dev->next = isa_driver->devices; | ||
152 | isa_driver->devices = &isa_dev->dev; | ||
153 | } else | ||
154 | device_unregister(&isa_dev->dev); | ||
155 | } | ||
156 | |||
157 | if (!error && !isa_driver->devices) | ||
158 | error = -ENODEV; | ||
159 | |||
160 | if (error) | ||
161 | isa_unregister_driver(isa_driver); | ||
162 | |||
163 | return error; | ||
164 | } | ||
165 | EXPORT_SYMBOL_GPL(isa_register_driver); | ||
166 | |||
167 | static int __init isa_bus_init(void) | ||
168 | { | ||
169 | int error; | ||
170 | |||
171 | error = bus_register(&isa_bus_type); | ||
172 | if (!error) { | ||
173 | error = device_register(&isa_bus); | ||
174 | if (error) | ||
175 | bus_unregister(&isa_bus_type); | ||
176 | } | ||
177 | return error; | ||
178 | } | ||
179 | |||
180 | device_initcall(isa_bus_init); | ||
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 83f5c5984d1a..2b8755db76c6 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -275,7 +275,7 @@ int platform_device_add(struct platform_device *pdev) | |||
275 | pr_debug("Registering platform device '%s'. Parent at %s\n", | 275 | pr_debug("Registering platform device '%s'. Parent at %s\n", |
276 | pdev->dev.bus_id, pdev->dev.parent->bus_id); | 276 | pdev->dev.bus_id, pdev->dev.parent->bus_id); |
277 | 277 | ||
278 | ret = device_register(&pdev->dev); | 278 | ret = device_add(&pdev->dev); |
279 | if (ret == 0) | 279 | if (ret == 0) |
280 | return ret; | 280 | return ret; |
281 | 281 | ||
@@ -452,6 +452,37 @@ void platform_driver_unregister(struct platform_driver *drv) | |||
452 | EXPORT_SYMBOL_GPL(platform_driver_unregister); | 452 | EXPORT_SYMBOL_GPL(platform_driver_unregister); |
453 | 453 | ||
454 | 454 | ||
455 | /* modalias support enables more hands-off userspace setup: | ||
456 | * (a) environment variable lets new-style hotplug events work once system is | ||
457 | * fully running: "modprobe $MODALIAS" | ||
458 | * (b) sysfs attribute lets new-style coldplug recover from hotplug events | ||
459 | * mishandled before system is fully running: "modprobe $(cat modalias)" | ||
460 | */ | ||
461 | static ssize_t | ||
462 | modalias_show(struct device *dev, struct device_attribute *a, char *buf) | ||
463 | { | ||
464 | struct platform_device *pdev = to_platform_device(dev); | ||
465 | int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name); | ||
466 | |||
467 | return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; | ||
468 | } | ||
469 | |||
470 | static struct device_attribute platform_dev_attrs[] = { | ||
471 | __ATTR_RO(modalias), | ||
472 | __ATTR_NULL, | ||
473 | }; | ||
474 | |||
475 | static int platform_uevent(struct device *dev, char **envp, int num_envp, | ||
476 | char *buffer, int buffer_size) | ||
477 | { | ||
478 | struct platform_device *pdev = to_platform_device(dev); | ||
479 | |||
480 | envp[0] = buffer; | ||
481 | snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name); | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | |||
455 | /** | 486 | /** |
456 | * platform_match - bind platform device to platform driver. | 487 | * platform_match - bind platform device to platform driver. |
457 | * @dev: device. | 488 | * @dev: device. |
@@ -496,7 +527,9 @@ static int platform_resume(struct device * dev) | |||
496 | 527 | ||
497 | struct bus_type platform_bus_type = { | 528 | struct bus_type platform_bus_type = { |
498 | .name = "platform", | 529 | .name = "platform", |
530 | .dev_attrs = platform_dev_attrs, | ||
499 | .match = platform_match, | 531 | .match = platform_match, |
532 | .uevent = platform_uevent, | ||
500 | .suspend = platform_suspend, | 533 | .suspend = platform_suspend, |
501 | .resume = platform_resume, | 534 | .resume = platform_resume, |
502 | }; | 535 | }; |
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index c0219ad94aca..ceeeba2c56c7 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile | |||
@@ -4,3 +4,6 @@ obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o | |||
4 | ifeq ($(CONFIG_DEBUG_DRIVER),y) | 4 | ifeq ($(CONFIG_DEBUG_DRIVER),y) |
5 | EXTRA_CFLAGS += -DDEBUG | 5 | EXTRA_CFLAGS += -DDEBUG |
6 | endif | 6 | endif |
7 | ifeq ($(CONFIG_PM_DEBUG),y) | ||
8 | EXTRA_CFLAGS += -DDEBUG | ||
9 | endif | ||
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 2a769cc6f5f9..1a1fe43a3057 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c | |||
@@ -29,6 +29,15 @@ | |||
29 | * lists. This way, the ancestors will be accessed before their descendents. | 29 | * lists. This way, the ancestors will be accessed before their descendents. |
30 | */ | 30 | */ |
31 | 31 | ||
32 | static inline char *suspend_verb(u32 event) | ||
33 | { | ||
34 | switch (event) { | ||
35 | case PM_EVENT_SUSPEND: return "suspend"; | ||
36 | case PM_EVENT_FREEZE: return "freeze"; | ||
37 | default: return "(unknown suspend event)"; | ||
38 | } | ||
39 | } | ||
40 | |||
32 | 41 | ||
33 | /** | 42 | /** |
34 | * suspend_device - Save state of one device. | 43 | * suspend_device - Save state of one device. |
@@ -57,7 +66,13 @@ int suspend_device(struct device * dev, pm_message_t state) | |||
57 | dev->power.prev_state = dev->power.power_state; | 66 | dev->power.prev_state = dev->power.power_state; |
58 | 67 | ||
59 | if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) { | 68 | if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) { |
60 | dev_dbg(dev, "suspending\n"); | 69 | dev_dbg(dev, "%s%s\n", |
70 | suspend_verb(state.event), | ||
71 | ((state.event == PM_EVENT_SUSPEND) | ||
72 | && device_may_wakeup(dev)) | ||
73 | ? ", may wakeup" | ||
74 | : "" | ||
75 | ); | ||
61 | error = dev->bus->suspend(dev, state); | 76 | error = dev->bus->suspend(dev, state); |
62 | suspend_report_result(dev->bus->suspend, error); | 77 | suspend_report_result(dev->bus->suspend, error); |
63 | } | 78 | } |
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 6fc23ab127bd..6858178b3aff 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
@@ -80,10 +80,59 @@ void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a) | |||
80 | EXPORT_SYMBOL_GPL(sysdev_create_file); | 80 | EXPORT_SYMBOL_GPL(sysdev_create_file); |
81 | EXPORT_SYMBOL_GPL(sysdev_remove_file); | 81 | EXPORT_SYMBOL_GPL(sysdev_remove_file); |
82 | 82 | ||
83 | #define to_sysdev_class(k) container_of(k, struct sysdev_class, kset.kobj) | ||
84 | #define to_sysdev_class_attr(a) container_of(a, \ | ||
85 | struct sysdev_class_attribute, attr) | ||
86 | |||
87 | static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr, | ||
88 | char *buffer) | ||
89 | { | ||
90 | struct sysdev_class * class = to_sysdev_class(kobj); | ||
91 | struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr); | ||
92 | |||
93 | if (class_attr->show) | ||
94 | return class_attr->show(class, buffer); | ||
95 | return -EIO; | ||
96 | } | ||
97 | |||
98 | static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr, | ||
99 | const char *buffer, size_t count) | ||
100 | { | ||
101 | struct sysdev_class * class = to_sysdev_class(kobj); | ||
102 | struct sysdev_class_attribute * class_attr = to_sysdev_class_attr(attr); | ||
103 | |||
104 | if (class_attr->store) | ||
105 | return class_attr->store(class, buffer, count); | ||
106 | return -EIO; | ||
107 | } | ||
108 | |||
109 | static struct sysfs_ops sysfs_class_ops = { | ||
110 | .show = sysdev_class_show, | ||
111 | .store = sysdev_class_store, | ||
112 | }; | ||
113 | |||
114 | static struct kobj_type ktype_sysdev_class = { | ||
115 | .sysfs_ops = &sysfs_class_ops, | ||
116 | }; | ||
117 | |||
118 | int sysdev_class_create_file(struct sysdev_class *c, | ||
119 | struct sysdev_class_attribute *a) | ||
120 | { | ||
121 | return sysfs_create_file(&c->kset.kobj, &a->attr); | ||
122 | } | ||
123 | EXPORT_SYMBOL_GPL(sysdev_class_create_file); | ||
124 | |||
125 | void sysdev_class_remove_file(struct sysdev_class *c, | ||
126 | struct sysdev_class_attribute *a) | ||
127 | { | ||
128 | sysfs_remove_file(&c->kset.kobj, &a->attr); | ||
129 | } | ||
130 | EXPORT_SYMBOL_GPL(sysdev_class_remove_file); | ||
131 | |||
83 | /* | 132 | /* |
84 | * declare system_subsys | 133 | * declare system_subsys |
85 | */ | 134 | */ |
86 | static decl_subsys(system, &ktype_sysdev, NULL); | 135 | static decl_subsys(system, &ktype_sysdev_class, NULL); |
87 | 136 | ||
88 | int sysdev_class_register(struct sysdev_class * cls) | 137 | int sysdev_class_register(struct sysdev_class * cls) |
89 | { | 138 | { |