From 775b64d2b6ca37697de925f70799c710aab5849a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 12 Jan 2008 20:40:46 +0100 Subject: PM: Acquire device locks on suspend This patch reorganizes the way suspend and resume notifications are sent to drivers. The major changes are that now the PM core acquires every device semaphore before calling the methods, and calls to device_add() during suspends will fail, while calls to device_del() during suspends will block. It also provides a way to safely remove a suspended device with the help of the PM core, by using the device_pm_schedule_removal() callback introduced specifically for this purpose, and updates two drivers (msr and cpuid) that need to use it. Signed-off-by: Alan Stern Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- include/linux/device.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/linux/device.h') diff --git a/include/linux/device.h b/include/linux/device.h index 2e15822fe40..cf4ae5c5d19 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -521,6 +521,14 @@ extern struct device *device_create(struct class *cls, struct device *parent, dev_t devt, const char *fmt, ...) __attribute__((format(printf,4,5))); extern void device_destroy(struct class *cls, dev_t devt); +#ifdef CONFIG_PM_SLEEP +extern void destroy_suspended_device(struct class *cls, dev_t devt); +#else /* !CONFIG_PM_SLEEP */ +static inline void destroy_suspended_device(struct class *cls, dev_t devt) +{ + device_destroy(cls, devt); +} +#endif /* !CONFIG_PM_SLEEP */ /* * Platform "fixup" functions - allow the platform to have their say -- cgit v1.2.3-70-g09d2 From 7b8712e563df4fefc25d3107fa3fb3abb7331ff4 Mon Sep 17 00:00:00 2001 From: Emil Medve Date: Tue, 30 Oct 2007 14:37:14 -0500 Subject: driver core: Make the dev_*() family of macros in device.h complete Removed duplicates defined elsewhere Signed-off-by: Emil Medve Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/isp1301_omap.c | 6 ------ drivers/isdn/gigaset/gigaset.h | 6 ------ include/linux/device.h | 24 +++++++++++++++--------- 3 files changed, 15 insertions(+), 21 deletions(-) (limited to 'include/linux/device.h') diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index b767603a07b..ebfbb2947ae 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -259,12 +259,6 @@ static inline const char *state_name(struct isp1301 *isp) return state_string(isp->otg.state); } -#ifdef VERBOSE -#define dev_vdbg dev_dbg -#else -#define dev_vdbg(dev, fmt, arg...) do{}while(0) -#endif - /*-------------------------------------------------------------------------*/ /* NOTE: some of this ISP1301 setup is specific to H2 boards; diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index a0317abaeb1..02bdaf22d7e 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -106,12 +106,6 @@ enum debuglevel { activated */ }; -/* missing from linux/device.h ... */ -#ifndef dev_notice -#define dev_notice(dev, format, arg...) \ - dev_printk(KERN_NOTICE , dev , format , ## arg) -#endif - /* Kernel message macros for situations where dev_printk and friends cannot be * used for lack of reliable access to a device structure. * linux/usb.h already contains these but in an obsolete form which clutters diff --git a/include/linux/device.h b/include/linux/device.h index cf4ae5c5d19..dbbbe89e726 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -565,6 +565,21 @@ extern const char *dev_driver_string(struct device *dev); #define dev_printk(level, dev, format, arg...) \ printk(level "%s %s: " format , dev_driver_string(dev) , (dev)->bus_id , ## arg) +#define dev_emerg(dev, format, arg...) \ + dev_printk(KERN_EMERG , dev , format , ## arg) +#define dev_alert(dev, format, arg...) \ + dev_printk(KERN_ALERT , dev , format , ## arg) +#define dev_crit(dev, format, arg...) \ + dev_printk(KERN_CRIT , dev , format , ## arg) +#define dev_err(dev, format, arg...) \ + dev_printk(KERN_ERR , dev , format , ## arg) +#define dev_warn(dev, format, arg...) \ + dev_printk(KERN_WARNING , dev , format , ## arg) +#define dev_notice(dev, format, arg...) \ + dev_printk(KERN_NOTICE , dev , format , ## arg) +#define dev_info(dev, format, arg...) \ + dev_printk(KERN_INFO , dev , format , ## arg) + #ifdef DEBUG #define dev_dbg(dev, format, arg...) \ dev_printk(KERN_DEBUG , dev , format , ## arg) @@ -586,15 +601,6 @@ dev_vdbg(struct device * dev, const char * fmt, ...) } #endif -#define dev_err(dev, format, arg...) \ - dev_printk(KERN_ERR , dev , format , ## arg) -#define dev_info(dev, format, arg...) \ - dev_printk(KERN_INFO , dev , format , ## arg) -#define dev_warn(dev, format, arg...) \ - dev_printk(KERN_WARNING , dev , format , ## arg) -#define dev_notice(dev, format, arg...) \ - dev_printk(KERN_NOTICE , dev , format , ## arg) - /* Create alias, so I can be autoloaded. */ #define MODULE_ALIAS_CHARDEV(major,minor) \ MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) -- cgit v1.2.3-70-g09d2 From 3d8995963dfec66ef6270e729bf75903e9043f9d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 1 Nov 2007 13:31:26 -0700 Subject: kset: convert struct bus_device->devices to use kset_create Dynamically create the kset instead of declaring it statically. Having 3 static kobjects in one structure is not only foolish, but ripe for nasty race conditions if handled improperly. We also rename the field to catch any potential users of it (not that there should be outside of the driver core...) Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 19 ++++++++++--------- include/linux/device.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index e3b10107780..b23eeb2d4ea 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -449,7 +449,7 @@ int bus_add_device(struct device * dev) error = device_add_attrs(bus, dev); if (error) goto out_put; - error = sysfs_create_link(&bus->devices.kobj, + error = sysfs_create_link(&bus->devices_kset->kobj, &dev->kobj, dev->bus_id); if (error) goto out_id; @@ -466,7 +466,7 @@ int bus_add_device(struct device * dev) out_deprecated: sysfs_remove_link(&dev->kobj, "subsystem"); out_subsys: - sysfs_remove_link(&bus->devices.kobj, dev->bus_id); + sysfs_remove_link(&bus->devices_kset->kobj, dev->bus_id); out_id: device_remove_attrs(bus, dev); out_put: @@ -512,7 +512,7 @@ void bus_remove_device(struct device * dev) if (dev->bus) { sysfs_remove_link(&dev->kobj, "subsystem"); remove_deprecated_bus_links(dev); - sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); + sysfs_remove_link(&dev->bus->devices_kset->kobj, dev->bus_id); device_remove_attrs(dev->bus, dev); if (dev->is_registered) { dev->is_registered = 0; @@ -862,11 +862,12 @@ int bus_register(struct bus_type * bus) if (retval) goto bus_uevent_fail; - kobject_set_name(&bus->devices.kobj, "devices"); - bus->devices.kobj.parent = &bus->subsys.kobj; - retval = kset_register(&bus->devices); - if (retval) + bus->devices_kset = kset_create_and_add("devices", NULL, + &bus->subsys.kobj); + if (!bus->devices_kset) { + retval = -ENOMEM; goto bus_devices_fail; + } kobject_set_name(&bus->drivers.kobj, "drivers"); bus->drivers.kobj.parent = &bus->subsys.kobj; @@ -894,7 +895,7 @@ bus_attrs_fail: bus_probe_files_fail: kset_unregister(&bus->drivers); bus_drivers_fail: - kset_unregister(&bus->devices); + kset_unregister(bus->devices_kset); bus_devices_fail: bus_remove_file(bus, &bus_attr_uevent); bus_uevent_fail: @@ -916,7 +917,7 @@ void bus_unregister(struct bus_type * bus) bus_remove_attrs(bus); remove_probe_files(bus); kset_unregister(&bus->drivers); - kset_unregister(&bus->devices); + kset_unregister(bus->devices_kset); bus_remove_file(bus, &bus_attr_uevent); subsystem_unregister(&bus->subsys); } diff --git a/include/linux/device.h b/include/linux/device.h index dbbbe89e726..82c27777137 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -55,7 +55,7 @@ struct bus_type { struct kset subsys; struct kset drivers; - struct kset devices; + struct kset *devices_kset; struct klist klist_devices; struct klist klist_drivers; -- cgit v1.2.3-70-g09d2 From 6dcec2511ff55b4abaca7ad3433011a7c04c2430 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 1 Nov 2007 13:31:26 -0700 Subject: kset: convert struct bus_device->drivers to use kset_create Dynamically create the kset instead of declaring it statically. Having 3 static kobjects in one structure is not only foolish, but ripe for nasty race conditions if handled improperly. We also rename the field to catch any potential users of it (not that there should be outside of the driver core...) Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 15 ++++++++------- drivers/base/driver.c | 2 +- include/linux/device.h | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index b23eeb2d4ea..6796d3e4605 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -638,7 +638,7 @@ int bus_add_driver(struct device_driver *drv) error = kobject_set_name(&drv->kobj, "%s", drv->name); if (error) goto out_put_bus; - drv->kobj.kset = &bus->drivers; + drv->kobj.kset = bus->drivers_kset; drv->kobj.ktype = &driver_ktype; error = kobject_register(&drv->kobj); if (error) @@ -869,11 +869,12 @@ int bus_register(struct bus_type * bus) goto bus_devices_fail; } - kobject_set_name(&bus->drivers.kobj, "drivers"); - bus->drivers.kobj.parent = &bus->subsys.kobj; - retval = kset_register(&bus->drivers); - if (retval) + bus->drivers_kset = kset_create_and_add("drivers", NULL, + &bus->subsys.kobj); + if (!bus->drivers_kset) { + retval = -ENOMEM; goto bus_drivers_fail; + } klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); klist_init(&bus->klist_drivers, NULL, NULL); @@ -893,7 +894,7 @@ int bus_register(struct bus_type * bus) bus_attrs_fail: remove_probe_files(bus); bus_probe_files_fail: - kset_unregister(&bus->drivers); + kset_unregister(bus->drivers_kset); bus_drivers_fail: kset_unregister(bus->devices_kset); bus_devices_fail: @@ -916,7 +917,7 @@ void bus_unregister(struct bus_type * bus) pr_debug("bus %s: unregistering\n", bus->name); bus_remove_attrs(bus); remove_probe_files(bus); - kset_unregister(&bus->drivers); + kset_unregister(bus->drivers_kset); kset_unregister(bus->devices_kset); bus_remove_file(bus, &bus_attr_uevent); subsystem_unregister(&bus->subsys); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index eb11475293e..1c9770dfb80 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -185,7 +185,7 @@ void driver_unregister(struct device_driver * drv) */ struct device_driver *driver_find(const char *name, struct bus_type *bus) { - struct kobject *k = kset_find_obj(&bus->drivers, name); + struct kobject *k = kset_find_obj(bus->drivers_kset, name); if (k) return to_drv(k); return NULL; diff --git a/include/linux/device.h b/include/linux/device.h index 82c27777137..110ace0dec3 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -54,7 +54,7 @@ struct bus_type { struct module * owner; struct kset subsys; - struct kset drivers; + struct kset *drivers_kset; struct kset *devices_kset; struct klist klist_devices; struct klist klist_drivers; -- cgit v1.2.3-70-g09d2 From 15f2f9b3a9db65aaf908fe7ee17bbe262ae3550f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 2 Nov 2007 16:19:59 -0700 Subject: firmware: remove firmware_(un)register() These functions are no longer called or needed, so we can remove them. As I rewrote the whole firmware.c file, add my copyright. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware.c | 19 ++----------------- include/linux/device.h | 5 ----- 2 files changed, 2 insertions(+), 22 deletions(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c index c7f635b11df..9efff481f5d 100644 --- a/drivers/base/firmware.c +++ b/drivers/base/firmware.c @@ -3,11 +3,11 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman + * Copyright (c) 2007 Novell Inc. * * This file is released under the GPLv2 - * */ - #include #include #include @@ -18,18 +18,6 @@ struct kset *firmware_kset; EXPORT_SYMBOL_GPL(firmware_kset); -int firmware_register(struct kset *s) -{ - s->kobj.kset = firmware_kset; - s->kobj.ktype = NULL; - return subsystem_register(s); -} - -void firmware_unregister(struct kset *s) -{ - subsystem_unregister(s); -} - int __init firmware_init(void) { firmware_kset = kset_create_and_add("firmware", NULL, NULL); @@ -37,6 +25,3 @@ int __init firmware_init(void) return -ENOMEM; return 0; } - -EXPORT_SYMBOL_GPL(firmware_register); -EXPORT_SYMBOL_GPL(firmware_unregister); diff --git a/include/linux/device.h b/include/linux/device.h index 110ace0dec3..a3b3ff15fc8 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -555,11 +555,6 @@ extern void device_shutdown(void); /* drivers/base/sys.c */ extern void sysdev_shutdown(void); - -/* drivers/base/firmware.c */ -extern int __must_check firmware_register(struct kset *); -extern void firmware_unregister(struct kset *); - /* debugging and troubleshooting/diagnostic helpers. */ extern const char *dev_driver_string(struct device *dev); #define dev_printk(level, dev, format, arg...) \ -- cgit v1.2.3-70-g09d2 From cc972e896b303f453f5893ecf8eca0d0e395ab64 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 1 Nov 2007 13:31:26 -0700 Subject: driver core: remove owner field from struct bus_type This isn't used by anything in the driver core, and by no one in the 204 different usages of it in the kernel tree. Remove this field so no one gets any idea that it is needed to be used. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- include/linux/device.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux/device.h') diff --git a/include/linux/device.h b/include/linux/device.h index a3b3ff15fc8..313e0b32bc0 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -51,7 +51,6 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *); struct bus_type { const char * name; - struct module * owner; struct kset subsys; struct kset *drivers_kset; -- cgit v1.2.3-70-g09d2 From 0fed80f7a63abd7168907267af69ee31f6bcf301 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 1 Nov 2007 19:41:16 -0700 Subject: driver core: add way to get to bus kset This allows an easier way to get to the kset associated with a struct bus_type (you have three to choose from...) This will make it easier to move these fields to be dynamic in a future patch. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 6 ++++++ drivers/pci/hotplug/pci_hotplug_core.c | 5 ++++- include/linux/device.h | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 871607b7c87..8335a1079b0 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -935,6 +935,12 @@ int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb) } EXPORT_SYMBOL_GPL(bus_unregister_notifier); +struct kset *bus_get_kset(struct bus_type *bus) +{ + return &bus->subsys; +} +EXPORT_SYMBOL_GPL(bus_get_kset); + int __init buses_init(void) { bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 0f05e6a68b3..3606d5b52a7 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -699,9 +699,12 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, static int __init pci_hotplug_init (void) { int result; + struct kset *pci_bus_kset; + + pci_bus_kset = bus_get_kset(&pci_bus_type); pci_hotplug_slots_kset = kset_create_and_add("slots", NULL, - &pci_bus_type.subsys.kobj); + &pci_bus_kset->kobj); if (!pci_hotplug_slots_kset) { result = -ENOMEM; err("Register subsys error\n"); diff --git a/include/linux/device.h b/include/linux/device.h index 313e0b32bc0..3cc13c32314 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -117,6 +117,8 @@ extern int bus_unregister_notifier(struct bus_type *bus, #define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be unbound */ +extern struct kset *bus_get_kset(struct bus_type *bus); + struct device_driver { const char * name; struct bus_type * bus; -- cgit v1.2.3-70-g09d2 From b249072ee6897fe4f8d461c7bb4b926223263c28 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 1 Nov 2007 19:41:16 -0700 Subject: driver core: add way to get to bus device klist This allows an easier way to get to the device klist associated with a struct bus_type (you have three to choose from...) This will make it easier to move these fields to be dynamic in a future patch. The only user of this is the PCI core which horribly abuses this interface to rearrange the order of the pci devices. This should be done using the existing bus device walking functions, but that's left for future patches. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 6 ++++++ drivers/pci/probe.c | 11 +++++++---- include/linux/device.h | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 8335a1079b0..9c9027b2c44 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -941,6 +941,12 @@ struct kset *bus_get_kset(struct bus_type *bus) } EXPORT_SYMBOL_GPL(bus_get_kset); +struct klist *bus_get_device_klist(struct bus_type *bus) +{ + return &bus->klist_devices; +} +EXPORT_SYMBOL_GPL(bus_get_device_klist); + int __init buses_init(void) { bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c5ca3134513..5fd585293e7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1210,16 +1210,19 @@ static void __init pci_sort_breadthfirst_klist(void) struct klist_node *n; struct device *dev; struct pci_dev *pdev; + struct klist *device_klist; - spin_lock(&pci_bus_type.klist_devices.k_lock); - list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) { + device_klist = bus_get_device_klist(&pci_bus_type); + + spin_lock(&device_klist->k_lock); + list_for_each_safe(pos, tmp, &device_klist->k_list) { n = container_of(pos, struct klist_node, n_node); dev = container_of(n, struct device, knode_bus); pdev = to_pci_dev(dev); pci_insertion_sort_klist(pdev, &sorted_devices); } - list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list); - spin_unlock(&pci_bus_type.klist_devices.k_lock); + list_splice(&sorted_devices, &device_klist->k_list); + spin_unlock(&device_klist->k_lock); } static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list) diff --git a/include/linux/device.h b/include/linux/device.h index 3cc13c32314..62e695bd3c9 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -118,6 +118,7 @@ extern int bus_unregister_notifier(struct bus_type *bus, unbound */ extern struct kset *bus_get_kset(struct bus_type *bus); +extern struct klist *bus_get_device_klist(struct bus_type *bus); struct device_driver { const char * name; -- cgit v1.2.3-70-g09d2 From c6f7e72a3f4641095ade9ded287d910c980c6148 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 1 Nov 2007 19:41:16 -0700 Subject: driver core: remove fields from struct bus_type struct bus_type is static everywhere in the kernel. This moves the kobject in the structure out of it, and a bunch of other private only to the driver core fields are now moved to a private structure. This lets us dynamically create the backing kobject properly and gives us the chance to be able to document to users exactly how to use the struct bus_type as there are no fields they can improperly access. Thanks to Kay for the build fixes on this patch. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 30 ++++++++++++- drivers/base/bus.c | 116 +++++++++++++++++++++++++++--------------------- drivers/base/core.c | 6 +-- drivers/base/dd.c | 4 +- drivers/base/driver.c | 2 +- drivers/base/platform.c | 4 +- include/linux/device.h | 12 +---- 7 files changed, 104 insertions(+), 70 deletions(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/base.h b/drivers/base/base.h index 7e309a49a71..ca6d273064f 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -1,6 +1,34 @@ -/* initialisation functions */ +/** + * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure. + * + * @subsys - the struct kset that defines this bus. This is the main kobject + * @drivers_kset - the list of drivers associated with this bus + * @devices_kset - the list of devices associated with this bus + * @klist_devices - the klist to iterate over the @devices_kset + * @klist_drivers - the klist to iterate over the @drivers_kset + * @bus_notifier - the bus notifier list for anything that cares about things + * on this bus. + * @bus - pointer back to the struct bus_type that this structure is associated + * with. + * + * This structure is the one that is the actual kobject allowing struct + * bus_type to be statically allocated safely. Nothing outside of the driver + * core should ever touch these fields. + */ +struct bus_type_private { + struct kset subsys; + struct kset *drivers_kset; + struct kset *devices_kset; + struct klist klist_devices; + struct klist klist_drivers; + struct blocking_notifier_head bus_notifier; + unsigned int drivers_autoprobe:1; + struct bus_type *bus; +}; + +/* initialisation functions */ extern int devices_init(void); extern int buses_init(void); extern int classes_init(void); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 9c9027b2c44..04d3850ff4b 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -17,7 +17,7 @@ #include "power/power.h" #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) -#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj) +#define to_bus(obj) container_of(obj, struct bus_type_private, subsys.kobj) /* * sysfs bindings for drivers @@ -32,13 +32,17 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, static struct bus_type *bus_get(struct bus_type *bus) { - return bus ? container_of(kset_get(&bus->subsys), - struct bus_type, subsys) : NULL; + if (bus) { + kset_get(&bus->p->subsys); + return bus; + } + return NULL; } static void bus_put(struct bus_type *bus) { - kset_put(&bus->subsys); + if (bus) + kset_put(&bus->p->subsys); } static ssize_t @@ -104,11 +108,11 @@ static ssize_t bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { struct bus_attribute * bus_attr = to_bus_attr(attr); - struct bus_type * bus = to_bus(kobj); + struct bus_type_private *bus_priv = to_bus(kobj); ssize_t ret = 0; if (bus_attr->show) - ret = bus_attr->show(bus, buf); + ret = bus_attr->show(bus_priv->bus, buf); return ret; } @@ -117,11 +121,11 @@ bus_attr_store(struct kobject * kobj, struct attribute * attr, const char * buf, size_t count) { struct bus_attribute * bus_attr = to_bus_attr(attr); - struct bus_type * bus = to_bus(kobj); + struct bus_type_private *bus_priv = to_bus(kobj); ssize_t ret = 0; if (bus_attr->store) - ret = bus_attr->store(bus, buf, count); + ret = bus_attr->store(bus_priv->bus, buf, count); return ret; } @@ -134,7 +138,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) { int error; if (bus_get(bus)) { - error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); + error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr); bus_put(bus); } else error = -EINVAL; @@ -144,7 +148,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) { if (bus_get(bus)) { - sysfs_remove_file(&bus->subsys.kobj, &attr->attr); + sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr); bus_put(bus); } } @@ -237,16 +241,16 @@ static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf) { - return sprintf(buf, "%d\n", bus->drivers_autoprobe); + return sprintf(buf, "%d\n", bus->p->drivers_autoprobe); } static ssize_t store_drivers_autoprobe(struct bus_type *bus, const char *buf, size_t count) { if (buf[0] == '0') - bus->drivers_autoprobe = 0; + bus->p->drivers_autoprobe = 0; else - bus->drivers_autoprobe = 1; + bus->p->drivers_autoprobe = 1; return count; } @@ -300,7 +304,7 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start, if (!bus) return -EINVAL; - klist_iter_init_node(&bus->klist_devices, &i, + klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->knode_bus : NULL)); while ((dev = next_device(&i)) && !error) error = fn(dev, data); @@ -333,7 +337,7 @@ struct device * bus_find_device(struct bus_type *bus, if (!bus) return NULL; - klist_iter_init_node(&bus->klist_devices, &i, + klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->knode_bus : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) @@ -379,7 +383,7 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, if (!bus) return -EINVAL; - klist_iter_init_node(&bus->klist_drivers, &i, + klist_iter_init_node(&bus->p->klist_drivers, &i, start ? &start->knode_bus : NULL); while ((drv = next_driver(&i)) && !error) error = fn(drv, data); @@ -420,7 +424,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev) static int make_deprecated_bus_links(struct device *dev) { return sysfs_create_link(&dev->kobj, - &dev->bus->subsys.kobj, "bus"); + &dev->bus->p->subsys.kobj, "bus"); } static void remove_deprecated_bus_links(struct device *dev) @@ -449,12 +453,12 @@ int bus_add_device(struct device * dev) error = device_add_attrs(bus, dev); if (error) goto out_put; - error = sysfs_create_link(&bus->devices_kset->kobj, + error = sysfs_create_link(&bus->p->devices_kset->kobj, &dev->kobj, dev->bus_id); if (error) goto out_id; error = sysfs_create_link(&dev->kobj, - &dev->bus->subsys.kobj, "subsystem"); + &dev->bus->p->subsys.kobj, "subsystem"); if (error) goto out_subsys; error = make_deprecated_bus_links(dev); @@ -466,7 +470,7 @@ int bus_add_device(struct device * dev) out_deprecated: sysfs_remove_link(&dev->kobj, "subsystem"); out_subsys: - sysfs_remove_link(&bus->devices_kset->kobj, dev->bus_id); + sysfs_remove_link(&bus->p->devices_kset->kobj, dev->bus_id); out_id: device_remove_attrs(bus, dev); out_put: @@ -488,11 +492,11 @@ void bus_attach_device(struct device * dev) if (bus) { dev->is_registered = 1; - if (bus->drivers_autoprobe) + if (bus->p->drivers_autoprobe) ret = device_attach(dev); WARN_ON(ret < 0); if (ret >= 0) - klist_add_tail(&dev->knode_bus, &bus->klist_devices); + klist_add_tail(&dev->knode_bus, &bus->p->klist_devices); else dev->is_registered = 0; } @@ -512,7 +516,7 @@ void bus_remove_device(struct device * dev) if (dev->bus) { sysfs_remove_link(&dev->kobj, "subsystem"); remove_deprecated_bus_links(dev); - sysfs_remove_link(&dev->bus->devices_kset->kobj, dev->bus_id); + sysfs_remove_link(&dev->bus->p->devices_kset->kobj, dev->bus_id); device_remove_attrs(dev->bus, dev); if (dev->is_registered) { dev->is_registered = 0; @@ -638,18 +642,18 @@ int bus_add_driver(struct device_driver *drv) error = kobject_set_name(&drv->kobj, "%s", drv->name); if (error) goto out_put_bus; - drv->kobj.kset = bus->drivers_kset; + drv->kobj.kset = bus->p->drivers_kset; drv->kobj.ktype = &driver_ktype; error = kobject_register(&drv->kobj); if (error) goto out_put_bus; - if (drv->bus->drivers_autoprobe) { + if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } - klist_add_tail(&drv->knode_bus, &bus->klist_drivers); + klist_add_tail(&drv->knode_bus, &bus->p->klist_drivers); module_add_driver(drv->owner, drv); error = driver_create_file(drv, &driver_attr_uevent); @@ -828,7 +832,7 @@ static ssize_t bus_uevent_store(struct bus_type *bus, enum kobject_action action; if (kobject_action_type(buf, count, &action) == 0) - kobject_uevent(&bus->subsys.kobj, action); + kobject_uevent(&bus->p->subsys.kobj, action); return count; } static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); @@ -844,17 +848,26 @@ static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); int bus_register(struct bus_type * bus) { int retval; + struct bus_type_private *priv; + + priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->bus = bus; + bus->p = priv; - BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier); + BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); - retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name); + retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); if (retval) goto out; - bus->subsys.kobj.kset = bus_kset; - bus->subsys.kobj.ktype = &bus_ktype; + priv->subsys.kobj.kset = bus_kset; + priv->subsys.kobj.ktype = &bus_ktype; + priv->drivers_autoprobe = 1; - retval = kset_register(&bus->subsys); + retval = kset_register(&priv->subsys); if (retval) goto out; @@ -862,24 +875,23 @@ int bus_register(struct bus_type * bus) if (retval) goto bus_uevent_fail; - bus->devices_kset = kset_create_and_add("devices", NULL, - &bus->subsys.kobj); - if (!bus->devices_kset) { + priv->devices_kset = kset_create_and_add("devices", NULL, + &priv->subsys.kobj); + if (!priv->devices_kset) { retval = -ENOMEM; goto bus_devices_fail; } - bus->drivers_kset = kset_create_and_add("drivers", NULL, - &bus->subsys.kobj); - if (!bus->drivers_kset) { + priv->drivers_kset = kset_create_and_add("drivers", NULL, + &priv->subsys.kobj); + if (!priv->drivers_kset) { retval = -ENOMEM; goto bus_drivers_fail; } - klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); - klist_init(&bus->klist_drivers, NULL, NULL); + klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); + klist_init(&priv->klist_drivers, NULL, NULL); - bus->drivers_autoprobe = 1; retval = add_probe_files(bus); if (retval) goto bus_probe_files_fail; @@ -894,13 +906,14 @@ int bus_register(struct bus_type * bus) bus_attrs_fail: remove_probe_files(bus); bus_probe_files_fail: - kset_unregister(bus->drivers_kset); + kset_unregister(bus->p->drivers_kset); bus_drivers_fail: - kset_unregister(bus->devices_kset); + kset_unregister(bus->p->devices_kset); bus_devices_fail: bus_remove_file(bus, &bus_attr_uevent); bus_uevent_fail: - kset_unregister(&bus->subsys); + kset_unregister(&bus->p->subsys); + kfree(bus->p); out: return retval; } @@ -917,33 +930,34 @@ void bus_unregister(struct bus_type * bus) pr_debug("bus %s: unregistering\n", bus->name); bus_remove_attrs(bus); remove_probe_files(bus); - kset_unregister(bus->drivers_kset); - kset_unregister(bus->devices_kset); + kset_unregister(bus->p->drivers_kset); + kset_unregister(bus->p->devices_kset); bus_remove_file(bus, &bus_attr_uevent); - kset_unregister(&bus->subsys); + kset_unregister(&bus->p->subsys); + kfree(bus->p); } int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb) { - return blocking_notifier_chain_register(&bus->bus_notifier, nb); + return blocking_notifier_chain_register(&bus->p->bus_notifier, nb); } EXPORT_SYMBOL_GPL(bus_register_notifier); int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb) { - return blocking_notifier_chain_unregister(&bus->bus_notifier, nb); + return blocking_notifier_chain_unregister(&bus->p->bus_notifier, nb); } EXPORT_SYMBOL_GPL(bus_unregister_notifier); struct kset *bus_get_kset(struct bus_type *bus) { - return &bus->subsys; + return &bus->p->subsys; } EXPORT_SYMBOL_GPL(bus_get_kset); struct klist *bus_get_device_klist(struct bus_type *bus) { - return &bus->klist_devices; + return &bus->p->klist_devices; } EXPORT_SYMBOL_GPL(bus_get_device_klist); diff --git a/drivers/base/core.c b/drivers/base/core.c index beb35160067..414a480e10a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -769,7 +769,7 @@ int device_add(struct device *dev) /* notify clients of device entry (new way) */ if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev); error = device_create_file(dev, &uevent_attr); @@ -820,7 +820,7 @@ int device_add(struct device *dev) dpm_sysfs_remove(dev); PMError: if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); device_remove_attrs(dev); AttrsError: @@ -999,7 +999,7 @@ void device_del(struct device * dev) if (platform_notify_remove) platform_notify_remove(dev); if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); kobject_uevent(&dev->kobj, KOBJ_REMOVE); kobject_del(&dev->kobj); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 7ac474db88c..7bf0e674c97 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -38,7 +38,7 @@ static void driver_bound(struct device *dev) dev->bus_id, dev->driver->name); if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); @@ -296,7 +296,7 @@ static void __device_release_driver(struct device * dev) klist_remove(&dev->knode_driver); if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_UNBIND_DRIVER, dev); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 1c9770dfb80..f94be40646d 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -185,7 +185,7 @@ void driver_unregister(struct device_driver * drv) */ struct device_driver *driver_find(const char *name, struct bus_type *bus) { - struct kobject *k = kset_find_obj(bus->drivers_kset, name); + struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); if (k) return to_drv(k); return NULL; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index fb560924148..d56a05f94f6 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -497,12 +497,12 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv, * if the probe was successful, and make sure any forced probes of * new devices fail. */ - spin_lock(&platform_bus_type.klist_drivers.k_lock); + spin_lock(&platform_bus_type.p->klist_drivers.k_lock); drv->probe = NULL; if (code == 0 && list_empty(&drv->driver.klist_devices.k_list)) retval = -ENODEV; drv->driver.probe = platform_drv_probe_fail; - spin_unlock(&platform_bus_type.klist_drivers.k_lock); + spin_unlock(&platform_bus_type.p->klist_drivers.k_lock); if (code != retval) platform_driver_unregister(drv); diff --git a/include/linux/device.h b/include/linux/device.h index 62e695bd3c9..3f24bf46d29 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -35,6 +35,7 @@ struct device_driver; struct class; struct class_device; struct bus_type; +struct bus_type_private; struct bus_attribute { struct attribute attr; @@ -51,15 +52,6 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *); struct bus_type { const char * name; - - struct kset subsys; - struct kset *drivers_kset; - struct kset *devices_kset; - struct klist klist_devices; - struct klist klist_drivers; - - struct blocking_notifier_head bus_notifier; - struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; struct driver_attribute * drv_attrs; @@ -75,7 +67,7 @@ struct bus_type { int (*resume_early)(struct device * dev); int (*resume)(struct device * dev); - unsigned int drivers_autoprobe:1; + struct bus_type_private *p; }; extern int __must_check bus_register(struct bus_type * bus); -- cgit v1.2.3-70-g09d2 From 57c745340a60c51d2b9af3d4dcf7e0ede284855b Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 5 Dec 2007 12:50:23 +0100 Subject: driver core: Introduce default attribute groups. This is lot like default attributes for devices (and indeed, a lot of the code is lifted from there). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/driver.c | 42 +++++++++++++++++++++++++++++++++++++++++- include/linux/device.h | 1 + 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/driver.c b/drivers/base/driver.c index f94be40646d..e3b58407fed 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -142,6 +142,37 @@ void put_driver(struct device_driver * drv) kobject_put(&drv->kobj); } +static int driver_add_groups(struct device_driver *drv, + struct attribute_group **groups) +{ + int error = 0; + int i; + + if (groups) { + for (i = 0; groups[i]; i++) { + error = sysfs_create_group(&drv->kobj, groups[i]); + if (error) { + while (--i >= 0) + sysfs_remove_group(&drv->kobj, + groups[i]); + break; + } + } + } + return error; +} + +static void driver_remove_groups(struct device_driver *drv, + struct attribute_group **groups) +{ + int i; + + if (groups) + for (i = 0; groups[i]; i++) + sysfs_remove_group(&drv->kobj, groups[i]); +} + + /** * driver_register - register driver with bus * @drv: driver to register @@ -152,13 +183,21 @@ void put_driver(struct device_driver * drv) */ int driver_register(struct device_driver * drv) { + int ret; + if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || (drv->bus->shutdown && drv->shutdown)) { printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name); } klist_init(&drv->klist_devices, NULL, NULL); - return bus_add_driver(drv); + ret = bus_add_driver(drv); + if (ret) + return ret; + ret = driver_add_groups(drv, drv->groups); + if (ret) + bus_remove_driver(drv); + return ret; } /** @@ -170,6 +209,7 @@ int driver_register(struct device_driver * drv) void driver_unregister(struct device_driver * drv) { + driver_remove_groups(drv, drv->groups); bus_remove_driver(drv); } diff --git a/include/linux/device.h b/include/linux/device.h index 3f24bf46d29..d974dda4aa5 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -129,6 +129,7 @@ struct device_driver { void (*shutdown) (struct device * dev); int (*suspend) (struct device * dev, pm_message_t state); int (*resume) (struct device * dev); + struct attribute_group **groups; }; -- cgit v1.2.3-70-g09d2 From cbe9c595f1de2e2a98403be2c14bfbc2486e84c4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 19 Dec 2007 15:54:39 -0400 Subject: Driver: add driver_add_kobj for looney iseries_veth driver The iseries driver wants to hang kobjects off of its driver, so, to preserve backwards compatibility, we need to add a call to the driver core to allow future changes to work properly. Hopefully no one uses this function in the future and the iseries_veth driver authors come to their senses so I can remove this hack... Cc: Dave Larson Cc: Santiago Leon Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/driver.c | 24 ++++++++++++++++++++++++ drivers/net/iseries_veth.c | 2 +- include/linux/device.h | 4 ++++ 3 files changed, 29 insertions(+), 1 deletion(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/driver.c b/drivers/base/driver.c index e3b58407fed..633ae1d70e1 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -123,6 +123,30 @@ void driver_remove_file(struct device_driver * drv, struct driver_attribute * at } +/** + * driver_add_kobj - add a kobject below the specified driver + * + * You really don't want to do this, this is only here due to one looney + * iseries driver, go poke those developers if you are annoyed about + * this... + */ +int driver_add_kobj(struct device_driver *drv, struct kobject *kobj, + const char *fmt, ...) +{ + va_list args; + char *name; + + va_start(args, fmt); + name = kvasprintf(GFP_KERNEL, fmt, args); + va_end(args); + + if (!name) + return -ENOMEM; + + return kobject_add_ng(kobj, &drv->kobj, "%s", name); +} +EXPORT_SYMBOL_GPL(driver_add_kobj); + /** * get_driver - increment driver reference count. * @drv: driver. diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 90ff4ec5f6f..1a8299acd3f 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1705,7 +1705,7 @@ static int __init veth_module_init(void) kobj = &veth_cnx[i]->kobject; /* If the add failes, complain but otherwise continue */ - if (0 != kobject_add_ng(kobj, &veth_driver.driver.kobj, + if (0 != driver_add_kobj(&veth_driver.driver, kobj, "cnx%.2d", veth_cnx[i]->remote_lp)) veth_error("cnx %d: Failed adding to sysfs.\n", i); } diff --git a/include/linux/device.h b/include/linux/device.h index d974dda4aa5..721ee318d57 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -156,6 +156,10 @@ extern int __must_check driver_create_file(struct device_driver *, struct driver_attribute *); extern void driver_remove_file(struct device_driver *, struct driver_attribute *); +extern int __must_check driver_add_kobj(struct device_driver *drv, + struct kobject *kobj, + const char *fmt, ...); + extern int __must_check driver_for_each_device(struct device_driver * drv, struct device *start, void *data, int (*fn)(struct device *, void *)); -- cgit v1.2.3-70-g09d2 From e5dd12784617f0f1fae5f96a7fac1ec4c49fadbe Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 28 Nov 2007 15:59:15 -0800 Subject: Driver core: move the static kobject out of struct driver This patch removes the kobject, and a few other driver-core-only fields out of struct driver and into the driver core only. Now drivers can be safely create on the stack or statically (like they currently are.) Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 8 ++++++ drivers/base/bus.c | 71 +++++++++++++++++++++++++++---------------------- drivers/base/dd.c | 24 ++++++++--------- drivers/base/driver.c | 40 ++++++++++++++++++---------- drivers/base/module.c | 12 ++++----- drivers/base/platform.c | 2 +- include/linux/device.h | 16 +++++------ 7 files changed, 99 insertions(+), 74 deletions(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/base.h b/drivers/base/base.h index 05472360f6a..3b0f395552d 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -27,6 +27,14 @@ struct bus_type_private { struct bus_type *bus; }; +struct driver_private { + struct kobject kobj; + struct klist klist_devices; + struct klist_node knode_bus; + struct module_kobject *mkobj; + struct device_driver *driver; +}; +#define to_driver(obj) container_of(obj, struct driver_private, kobj) /* initialisation functions */ extern int devices_init(void); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 04d3850ff4b..aa0c986c323 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -3,6 +3,8 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman + * Copyright (c) 2007 Novell Inc. * * This file is released under the GPLv2 * @@ -24,7 +26,6 @@ */ #define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr) -#define to_driver(obj) container_of(obj, struct device_driver, kobj) static int __must_check bus_rescan_devices_helper(struct device *dev, @@ -49,11 +50,11 @@ static ssize_t drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) { struct driver_attribute * drv_attr = to_drv_attr(attr); - struct device_driver * drv = to_driver(kobj); + struct driver_private *drv_priv = to_driver(kobj); ssize_t ret = -EIO; if (drv_attr->show) - ret = drv_attr->show(drv, buf); + ret = drv_attr->show(drv_priv->driver, buf); return ret; } @@ -62,11 +63,11 @@ drv_attr_store(struct kobject * kobj, struct attribute * attr, const char * buf, size_t count) { struct driver_attribute * drv_attr = to_drv_attr(attr); - struct device_driver * drv = to_driver(kobj); + struct driver_private *drv_priv = to_driver(kobj); ssize_t ret = -EIO; if (drv_attr->store) - ret = drv_attr->store(drv, buf, count); + ret = drv_attr->store(drv_priv->driver, buf, count); return ret; } @@ -75,22 +76,12 @@ static struct sysfs_ops driver_sysfs_ops = { .store = drv_attr_store, }; - -static void driver_release(struct kobject * kobj) +static void driver_release(struct kobject *kobj) { - /* - * Yes this is an empty release function, it is this way because struct - * device is always a static object, not a dynamic one. Yes, this is - * not nice and bad, but remember, drivers are code, reference counted - * by the module count, not a device, which is really data. And yes, - * in the future I do want to have all drivers be created dynamically, - * and am working toward that goal, but it will take a bit longer... - * - * But do not let this example give _anyone_ the idea that they can - * create a release function without any code in it at all, to do that - * is almost always wrong. If you have any questions about this, - * please send an email to - */ + struct driver_private *drv_priv = to_driver(kobj); + + pr_debug("%s: freeing %s\n", __FUNCTION__, kobject_name(kobj)); + kfree(drv_priv); } static struct kobj_type driver_ktype = { @@ -350,7 +341,13 @@ struct device * bus_find_device(struct bus_type *bus, static struct device_driver * next_driver(struct klist_iter * i) { struct klist_node * n = klist_next(i); - return n ? container_of(n, struct device_driver, knode_bus) : NULL; + struct driver_private *drv_priv; + + if (n) { + drv_priv = container_of(n, struct driver_private, knode_bus); + return drv_priv->driver; + } + return NULL; } /** @@ -384,7 +381,7 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, return -EINVAL; klist_iter_init_node(&bus->p->klist_drivers, &i, - start ? &start->knode_bus : NULL); + start ? &start->p->knode_bus : NULL); while ((drv = next_driver(&i)) && !error) error = fn(drv, data); klist_iter_exit(&i); @@ -620,7 +617,7 @@ static ssize_t driver_uevent_store(struct device_driver *drv, enum kobject_action action; if (kobject_action_type(buf, count, &action) == 0) - kobject_uevent(&drv->kobj, action); + kobject_uevent(&drv->p->kobj, action); return count; } static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); @@ -632,19 +629,29 @@ static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); */ int bus_add_driver(struct device_driver *drv) { - struct bus_type * bus = bus_get(drv->bus); + struct bus_type *bus; + struct driver_private *priv; int error = 0; + bus = bus_get(drv->bus); if (!bus) return -EINVAL; pr_debug("bus %s: add driver %s\n", bus->name, drv->name); - error = kobject_set_name(&drv->kobj, "%s", drv->name); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + error = kobject_set_name(&priv->kobj, "%s", drv->name); if (error) goto out_put_bus; - drv->kobj.kset = bus->p->drivers_kset; - drv->kobj.ktype = &driver_ktype; - error = kobject_register(&drv->kobj); + priv->kobj.kset = bus->p->drivers_kset; + priv->kobj.ktype = &driver_ktype; + klist_init(&priv->klist_devices, NULL, NULL); + priv->driver = drv; + drv->p = priv; + error = kobject_register(&priv->kobj); if (error) goto out_put_bus; @@ -653,7 +660,7 @@ int bus_add_driver(struct device_driver *drv) if (error) goto out_unregister; } - klist_add_tail(&drv->knode_bus, &bus->p->klist_drivers); + klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); module_add_driver(drv->owner, drv); error = driver_create_file(drv, &driver_attr_uevent); @@ -676,7 +683,7 @@ int bus_add_driver(struct device_driver *drv) return error; out_unregister: - kobject_unregister(&drv->kobj); + kobject_unregister(&priv->kobj); out_put_bus: bus_put(bus); return error; @@ -699,11 +706,11 @@ void bus_remove_driver(struct device_driver * drv) remove_bind_files(drv); driver_remove_attrs(drv->bus, drv); driver_remove_file(drv, &driver_attr_uevent); - klist_remove(&drv->knode_bus); + klist_remove(&drv->p->knode_bus); pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); module_remove_driver(drv); - kobject_unregister(&drv->kobj); + kobject_unregister(&drv->p->kobj); bus_put(drv->bus); } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 7bf0e674c97..87a348ce818 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -11,6 +11,8 @@ * * Copyright (c) 2002-5 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman + * Copyright (c) 2007 Novell Inc. * * This file is released under the GPLv2 */ @@ -23,8 +25,6 @@ #include "base.h" #include "power/power.h" -#define to_drv(node) container_of(node, struct device_driver, kobj.entry) - static void driver_bound(struct device *dev) { @@ -41,20 +41,20 @@ static void driver_bound(struct device *dev) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); - klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); + klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices); } static int driver_sysfs_add(struct device *dev) { int ret; - ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, + ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj, kobject_name(&dev->kobj)); if (ret == 0) { - ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj, + ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj, "driver"); if (ret) - sysfs_remove_link(&dev->driver->kobj, + sysfs_remove_link(&dev->driver->p->kobj, kobject_name(&dev->kobj)); } return ret; @@ -65,7 +65,7 @@ static void driver_sysfs_remove(struct device *dev) struct device_driver *drv = dev->driver; if (drv) { - sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); + sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&dev->kobj, "driver"); } } @@ -339,15 +339,15 @@ void driver_detach(struct device_driver * drv) struct device * dev; for (;;) { - spin_lock(&drv->klist_devices.k_lock); - if (list_empty(&drv->klist_devices.k_list)) { - spin_unlock(&drv->klist_devices.k_lock); + spin_lock(&drv->p->klist_devices.k_lock); + if (list_empty(&drv->p->klist_devices.k_list)) { + spin_unlock(&drv->p->klist_devices.k_lock); break; } - dev = list_entry(drv->klist_devices.k_list.prev, + dev = list_entry(drv->p->klist_devices.k_list.prev, struct device, knode_driver.n_node); get_device(dev); - spin_unlock(&drv->klist_devices.k_lock); + spin_unlock(&drv->p->klist_devices.k_lock); if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 633ae1d70e1..5aacff208f2 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -3,6 +3,8 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman + * Copyright (c) 2007 Novell Inc. * * This file is released under the GPLv2 * @@ -15,7 +17,6 @@ #include "base.h" #define to_dev(node) container_of(node, struct device, driver_list) -#define to_drv(obj) container_of(obj, struct device_driver, kobj) static struct device * next_device(struct klist_iter * i) @@ -44,7 +45,7 @@ int driver_for_each_device(struct device_driver * drv, struct device * start, if (!drv) return -EINVAL; - klist_iter_init_node(&drv->klist_devices, &i, + klist_iter_init_node(&drv->p->klist_devices, &i, start ? &start->knode_driver : NULL); while ((dev = next_device(&i)) && !error) error = fn(dev, data); @@ -80,7 +81,7 @@ struct device * driver_find_device(struct device_driver *drv, if (!drv) return NULL; - klist_iter_init_node(&drv->klist_devices, &i, + klist_iter_init_node(&drv->p->klist_devices, &i, (start ? &start->knode_driver : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) @@ -100,7 +101,7 @@ int driver_create_file(struct device_driver * drv, struct driver_attribute * att { int error; if (get_driver(drv)) { - error = sysfs_create_file(&drv->kobj, &attr->attr); + error = sysfs_create_file(&drv->p->kobj, &attr->attr); put_driver(drv); } else error = -EINVAL; @@ -117,7 +118,7 @@ int driver_create_file(struct device_driver * drv, struct driver_attribute * att void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr) { if (get_driver(drv)) { - sysfs_remove_file(&drv->kobj, &attr->attr); + sysfs_remove_file(&drv->p->kobj, &attr->attr); put_driver(drv); } } @@ -143,7 +144,7 @@ int driver_add_kobj(struct device_driver *drv, struct kobject *kobj, if (!name) return -ENOMEM; - return kobject_add_ng(kobj, &drv->kobj, "%s", name); + return kobject_add_ng(kobj, &drv->p->kobj, "%s", name); } EXPORT_SYMBOL_GPL(driver_add_kobj); @@ -153,7 +154,15 @@ EXPORT_SYMBOL_GPL(driver_add_kobj); */ struct device_driver * get_driver(struct device_driver * drv) { - return drv ? to_drv(kobject_get(&drv->kobj)) : NULL; + if (drv) { + struct driver_private *priv; + struct kobject *kobj; + + kobj = kobject_get(&drv->p->kobj); + priv = to_driver(kobj); + return priv->driver; + } + return NULL; } @@ -163,7 +172,7 @@ struct device_driver * get_driver(struct device_driver * drv) */ void put_driver(struct device_driver * drv) { - kobject_put(&drv->kobj); + kobject_put(&drv->p->kobj); } static int driver_add_groups(struct device_driver *drv, @@ -174,10 +183,10 @@ static int driver_add_groups(struct device_driver *drv, if (groups) { for (i = 0; groups[i]; i++) { - error = sysfs_create_group(&drv->kobj, groups[i]); + error = sysfs_create_group(&drv->p->kobj, groups[i]); if (error) { while (--i >= 0) - sysfs_remove_group(&drv->kobj, + sysfs_remove_group(&drv->p->kobj, groups[i]); break; } @@ -193,7 +202,7 @@ static void driver_remove_groups(struct device_driver *drv, if (groups) for (i = 0; groups[i]; i++) - sysfs_remove_group(&drv->kobj, groups[i]); + sysfs_remove_group(&drv->p->kobj, groups[i]); } @@ -214,7 +223,6 @@ int driver_register(struct device_driver * drv) (drv->bus->shutdown && drv->shutdown)) { printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name); } - klist_init(&drv->klist_devices, NULL, NULL); ret = bus_add_driver(drv); if (ret) return ret; @@ -250,8 +258,12 @@ void driver_unregister(struct device_driver * drv) struct device_driver *driver_find(const char *name, struct bus_type *bus) { struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); - if (k) - return to_drv(k); + struct driver_private *priv; + + if (k) { + priv = to_driver(k); + return priv->driver; + } return NULL; } diff --git a/drivers/base/module.c b/drivers/base/module.c index cad07be5de1..103be9cacb0 100644 --- a/drivers/base/module.c +++ b/drivers/base/module.c @@ -50,7 +50,7 @@ void module_add_driver(struct module *mod, struct device_driver *drv) if (mkobj) { mk = container_of(mkobj, struct module_kobject, kobj); /* remember our module structure */ - drv->mkobj = mk; + drv->p->mkobj = mk; /* kset_find_obj took a reference */ kobject_put(mkobj); } @@ -60,11 +60,11 @@ void module_add_driver(struct module *mod, struct device_driver *drv) return; /* Don't check return codes; these calls are idempotent */ - no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module"); + no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); driver_name = make_driver_name(drv); if (driver_name) { module_create_drivers_dir(mk); - no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj, + no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, driver_name); kfree(driver_name); } @@ -78,12 +78,12 @@ void module_remove_driver(struct device_driver *drv) if (!drv) return; - sysfs_remove_link(&drv->kobj, "module"); + sysfs_remove_link(&drv->p->kobj, "module"); if (drv->owner) mk = &drv->owner->mkobj; - else if (drv->mkobj) - mk = drv->mkobj; + else if (drv->p->mkobj) + mk = drv->p->mkobj; if (mk && mk->drivers_dir) { driver_name = make_driver_name(drv); if (driver_name) { diff --git a/drivers/base/platform.c b/drivers/base/platform.c index d56a05f94f6..bdd59e8358f 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -499,7 +499,7 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv, */ spin_lock(&platform_bus_type.p->klist_drivers.k_lock); drv->probe = NULL; - if (code == 0 && list_empty(&drv->driver.klist_devices.k_list)) + if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) retval = -ENODEV; drv->driver.probe = platform_drv_probe_fail; spin_unlock(&platform_bus_type.p->klist_drivers.k_lock); diff --git a/include/linux/device.h b/include/linux/device.h index 721ee318d57..92ba3a87462 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -32,6 +32,7 @@ struct device; struct device_driver; +struct driver_private; struct class; struct class_device; struct bus_type; @@ -113,16 +114,11 @@ extern struct kset *bus_get_kset(struct bus_type *bus); extern struct klist *bus_get_device_klist(struct bus_type *bus); struct device_driver { - const char * name; - struct bus_type * bus; - - struct kobject kobj; - struct klist klist_devices; - struct klist_node knode_bus; + const char *name; + struct bus_type *bus; - struct module * owner; - const char * mod_name; /* used for built-in modules */ - struct module_kobject * mkobj; + struct module *owner; + const char *mod_name; /* used for built-in modules */ int (*probe) (struct device * dev); int (*remove) (struct device * dev); @@ -130,6 +126,8 @@ struct device_driver { int (*suspend) (struct device * dev, pm_message_t state); int (*resume) (struct device * dev); struct attribute_group **groups; + + struct driver_private *p; }; -- cgit v1.2.3-70-g09d2 From fd04897bb20be29d60f7e426a053545aebeaa61a Mon Sep 17 00:00:00 2001 From: Dave Young Date: Tue, 22 Jan 2008 15:27:08 +0800 Subject: Driver Core: add class iteration api Add the following class iteration functions for driver use: class_for_each_device class_find_device class_for_each_child class_find_child Signed-off-by: Dave Young Acked-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/device.h | 9 +++- 2 files changed, 140 insertions(+), 2 deletions(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/class.c b/drivers/base/class.c index b962a76875d..9f737ff0fc7 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -809,6 +809,139 @@ void class_device_put(struct class_device *class_dev) kobject_put(&class_dev->kobj); } +/** + * class_for_each_device - device iterator + * @class: the class we're iterating + * @data: data for the callback + * @fn: function to be called for each device + * + * Iterate over @class's list of devices, and call @fn for each, + * passing it @data. + * + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. + * + * Note, we hold class->sem in this function, so it can not be + * re-acquired in @fn, otherwise it will self-deadlocking. For + * example, calls to add or remove class members would be verboten. + */ +int class_for_each_device(struct class *class, void *data, + int (*fn)(struct device *, void *)) +{ + struct device *dev; + int error = 0; + + if (!class) + return -EINVAL; + down(&class->sem); + list_for_each_entry(dev, &class->devices, node) { + dev = get_device(dev); + if (dev) { + error = fn(dev, data); + put_device(dev); + } else + error = -ENODEV; + if (error) + break; + } + up(&class->sem); + + return error; +} +EXPORT_SYMBOL_GPL(class_for_each_device); + +/** + * class_find_device - device iterator for locating a particular device + * @class: the class we're iterating + * @data: data for the match function + * @match: function to check device + * + * This is similar to the class_for_each_dev() function above, but it + * returns a reference to a device that is 'found' for later use, as + * determined by the @match callback. + * + * The callback should return 0 if the device doesn't match and non-zero + * if it does. If the callback returns non-zero, this function will + * return to the caller and not iterate over any more devices. + + * Note, you will need to drop the reference with put_device() after use. + * + * We hold class->sem in this function, so it can not be + * re-acquired in @match, otherwise it will self-deadlocking. For + * example, calls to add or remove class members would be verboten. + */ +struct device *class_find_device(struct class *class, void *data, + int (*match)(struct device *, void *)) +{ + struct device *dev; + int found = 0; + + if (!class) + return NULL; + + down(&class->sem); + list_for_each_entry(dev, &class->devices, node) { + dev = get_device(dev); + if (dev) { + if (match(dev, data)) { + found = 1; + break; + } else + put_device(dev); + } else + break; + } + up(&class->sem); + + return found ? dev : NULL; +} +EXPORT_SYMBOL_GPL(class_find_device); + +/** + * class_find_child - device iterator for locating a particular class_device + * @class: the class we're iterating + * @data: data for the match function + * @match: function to check class_device + * + * This function returns a reference to a class_device that is 'found' for + * later use, as determined by the @match callback. + * + * The callback should return 0 if the class_device doesn't match and non-zero + * if it does. If the callback returns non-zero, this function will + * return to the caller and not iterate over any more class_devices. + * + * Note, you will need to drop the reference with class_device_put() after use. + * + * We hold class->sem in this function, so it can not be + * re-acquired in @match, otherwise it will self-deadlocking. For + * example, calls to add or remove class members would be verboten. + */ +struct class_device *class_find_child(struct class *class, void *data, + int (*match)(struct class_device *, void *)) +{ + struct class_device *dev; + int found = 0; + + if (!class) + return NULL; + + down(&class->sem); + list_for_each_entry(dev, &class->children, node) { + dev = class_device_get(dev); + if (dev) { + if (match(dev, data)) { + found = 1; + break; + } else + class_device_put(dev); + } else + break; + } + up(&class->sem); + + return found ? dev : NULL; +} +EXPORT_SYMBOL_GPL(class_find_child); int class_interface_register(struct class_interface *class_intf) { diff --git a/include/linux/device.h b/include/linux/device.h index 92ba3a87462..cdaf57bf4d1 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -177,8 +177,7 @@ struct class { struct list_head devices; struct list_head interfaces; struct kset class_dirs; - struct semaphore sem; /* locks both the children and interfaces lists */ - + struct semaphore sem; /* locks children, devices, interfaces */ struct class_attribute * class_attrs; struct class_device_attribute * class_dev_attrs; struct device_attribute * dev_attrs; @@ -196,6 +195,12 @@ struct class { extern int __must_check class_register(struct class *); extern void class_unregister(struct class *); +extern int class_for_each_device(struct class *class, void *data, + int (*fn)(struct device *dev, void *data)); +extern struct device *class_find_device(struct class *class, void *data, + int (*match)(struct device *, void *)); +extern struct class_device *class_find_child(struct class *class, void *data, + int (*match)(struct class_device *, void *)); struct class_attribute { -- cgit v1.2.3-70-g09d2 From d462943afee8bff610258a82dba666e8ab72c9c8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 24 Jan 2008 21:04:46 -0800 Subject: Driver core: fix coding style issues in device.h Finally clean up the odd spaces and other mess in device.h Signed-off-by: Greg Kroah-Hartman --- include/linux/device.h | 283 +++++++++++++++++++++++++------------------------ 1 file changed, 145 insertions(+), 138 deletions(-) (limited to 'include/linux/device.h') diff --git a/include/linux/device.h b/include/linux/device.h index cdaf57bf4d1..1880208964d 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -25,7 +25,8 @@ #include #define DEVICE_NAME_SIZE 50 -#define DEVICE_NAME_HALF __stringify(20) /* Less than half to accommodate slop */ +/* DEVICE_NAME_HALF is really less than half to accommodate slop */ +#define DEVICE_NAME_HALF __stringify(20) #define DEVICE_ID_SIZE 32 #define BUS_ID_SIZE KOBJ_NAME_LEN @@ -40,52 +41,53 @@ struct bus_type_private; struct bus_attribute { struct attribute attr; - ssize_t (*show)(struct bus_type *, char * buf); - ssize_t (*store)(struct bus_type *, const char * buf, size_t count); + ssize_t (*show)(struct bus_type *bus, char *buf); + ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count); }; -#define BUS_ATTR(_name,_mode,_show,_store) \ -struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store) +#define BUS_ATTR(_name, _mode, _show, _store) \ +struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store) extern int __must_check bus_create_file(struct bus_type *, struct bus_attribute *); extern void bus_remove_file(struct bus_type *, struct bus_attribute *); struct bus_type { - const char * name; - struct bus_attribute * bus_attrs; - struct device_attribute * dev_attrs; - struct driver_attribute * drv_attrs; - - int (*match)(struct device * dev, struct device_driver * drv); - int (*uevent)(struct device *dev, struct kobj_uevent_env *env); - int (*probe)(struct device * dev); - int (*remove)(struct device * dev); - void (*shutdown)(struct device * dev); - - int (*suspend)(struct device * dev, pm_message_t state); - int (*suspend_late)(struct device * dev, pm_message_t state); - int (*resume_early)(struct device * dev); - int (*resume)(struct device * dev); + const char *name; + struct bus_attribute *bus_attrs; + struct device_attribute *dev_attrs; + struct driver_attribute *drv_attrs; + + int (*match)(struct device *dev, struct device_driver *drv); + int (*uevent)(struct device *dev, struct kobj_uevent_env *env); + int (*probe)(struct device *dev); + int (*remove)(struct device *dev); + void (*shutdown)(struct device *dev); + + int (*suspend)(struct device *dev, pm_message_t state); + int (*suspend_late)(struct device *dev, pm_message_t state); + int (*resume_early)(struct device *dev); + int (*resume)(struct device *dev); struct bus_type_private *p; }; -extern int __must_check bus_register(struct bus_type * bus); -extern void bus_unregister(struct bus_type * bus); +extern int __must_check bus_register(struct bus_type *bus); +extern void bus_unregister(struct bus_type *bus); -extern int __must_check bus_rescan_devices(struct bus_type * bus); +extern int __must_check bus_rescan_devices(struct bus_type *bus); /* iterator helpers for buses */ -int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, - int (*fn)(struct device *, void *)); -struct device * bus_find_device(struct bus_type *bus, struct device *start, - void *data, int (*match)(struct device *, void *)); +int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, + int (*fn)(struct device *dev, void *data)); +struct device *bus_find_device(struct bus_type *bus, struct device *start, + void *data, + int (*match)(struct device *dev, void *data)); int __must_check bus_for_each_drv(struct bus_type *bus, - struct device_driver *start, void *data, - int (*fn)(struct device_driver *, void *)); + struct device_driver *start, void *data, + int (*fn)(struct device_driver *, void *)); /* * Bus notifiers: Get notified of addition/removal of devices @@ -120,57 +122,63 @@ struct device_driver { struct module *owner; const char *mod_name; /* used for built-in modules */ - int (*probe) (struct device * dev); - int (*remove) (struct device * dev); - void (*shutdown) (struct device * dev); - int (*suspend) (struct device * dev, pm_message_t state); - int (*resume) (struct device * dev); + int (*probe) (struct device *dev); + int (*remove) (struct device *dev); + void (*shutdown) (struct device *dev); + int (*suspend) (struct device *dev, pm_message_t state); + int (*resume) (struct device *dev); struct attribute_group **groups; struct driver_private *p; }; -extern int __must_check driver_register(struct device_driver * drv); -extern void driver_unregister(struct device_driver * drv); +extern int __must_check driver_register(struct device_driver *drv); +extern void driver_unregister(struct device_driver *drv); -extern struct device_driver * get_driver(struct device_driver * drv); -extern void put_driver(struct device_driver * drv); -extern struct device_driver *driver_find(const char *name, struct bus_type *bus); +extern struct device_driver *get_driver(struct device_driver *drv); +extern void put_driver(struct device_driver *drv); +extern struct device_driver *driver_find(const char *name, + struct bus_type *bus); extern int driver_probe_done(void); /* sysfs interface for exporting driver attributes */ struct driver_attribute { - struct attribute attr; - ssize_t (*show)(struct device_driver *, char * buf); - ssize_t (*store)(struct device_driver *, const char * buf, size_t count); + struct attribute attr; + ssize_t (*show)(struct device_driver *driver, char *buf); + ssize_t (*store)(struct device_driver *driver, const char *buf, + size_t count); }; -#define DRIVER_ATTR(_name,_mode,_show,_store) \ -struct driver_attribute driver_attr_##_name = __ATTR(_name,_mode,_show,_store) +#define DRIVER_ATTR(_name, _mode, _show, _store) \ +struct driver_attribute driver_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) -extern int __must_check driver_create_file(struct device_driver *, - struct driver_attribute *); -extern void driver_remove_file(struct device_driver *, struct driver_attribute *); +extern int __must_check driver_create_file(struct device_driver *driver, + struct driver_attribute *attr); +extern void driver_remove_file(struct device_driver *driver, + struct driver_attribute *attr); extern int __must_check driver_add_kobj(struct device_driver *drv, struct kobject *kobj, const char *fmt, ...); -extern int __must_check driver_for_each_device(struct device_driver * drv, - struct device *start, void *data, - int (*fn)(struct device *, void *)); -struct device * driver_find_device(struct device_driver *drv, - struct device *start, void *data, - int (*match)(struct device *, void *)); +extern int __must_check driver_for_each_device(struct device_driver *drv, + struct device *start, + void *data, + int (*fn)(struct device *dev, + void *)); +struct device *driver_find_device(struct device_driver *drv, + struct device *start, void *data, + int (*match)(struct device *dev, void *data)); /* * device classes */ struct class { - const char * name; - struct module * owner; + const char *name; + struct module *owner; struct kset subsys; struct list_head children; @@ -178,23 +186,23 @@ struct class { struct list_head interfaces; struct kset class_dirs; struct semaphore sem; /* locks children, devices, interfaces */ - struct class_attribute * class_attrs; - struct class_device_attribute * class_dev_attrs; - struct device_attribute * dev_attrs; + struct class_attribute *class_attrs; + struct class_device_attribute *class_dev_attrs; + struct device_attribute *dev_attrs; - int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); - int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); + int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); + int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); - void (*release)(struct class_device *dev); - void (*class_release)(struct class *class); - void (*dev_release)(struct device *dev); + void (*release)(struct class_device *dev); + void (*class_release)(struct class *class); + void (*dev_release)(struct device *dev); - int (*suspend)(struct device *, pm_message_t state); - int (*resume)(struct device *); + int (*suspend)(struct device *dev, pm_message_t state); + int (*resume)(struct device *dev); }; -extern int __must_check class_register(struct class *); -extern void class_unregister(struct class *); +extern int __must_check class_register(struct class *class); +extern void class_unregister(struct class *class); extern int class_for_each_device(struct class *class, void *data, int (*fn)(struct device *dev, void *data)); extern struct device *class_find_device(struct class *class, void *data, @@ -204,27 +212,28 @@ extern struct class_device *class_find_child(struct class *class, void *data, struct class_attribute { - struct attribute attr; - ssize_t (*show)(struct class *, char * buf); - ssize_t (*store)(struct class *, const char * buf, size_t count); + struct attribute attr; + ssize_t (*show)(struct class *class, char *buf); + ssize_t (*store)(struct class *class, const char *buf, size_t count); }; -#define CLASS_ATTR(_name,_mode,_show,_store) \ -struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store) +#define CLASS_ATTR(_name, _mode, _show, _store) \ +struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store) -extern int __must_check class_create_file(struct class *, - const struct class_attribute *); -extern void class_remove_file(struct class *, const struct class_attribute *); +extern int __must_check class_create_file(struct class *class, + const struct class_attribute *attr); +extern void class_remove_file(struct class *class, + const struct class_attribute *attr); struct class_device_attribute { - struct attribute attr; - ssize_t (*show)(struct class_device *, char * buf); - ssize_t (*store)(struct class_device *, const char * buf, size_t count); + struct attribute attr; + ssize_t (*show)(struct class_device *, char *buf); + ssize_t (*store)(struct class_device *, const char *buf, size_t count); }; -#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \ +#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store) \ struct class_device_attribute class_device_attr_##_name = \ - __ATTR(_name,_mode,_show,_store) + __ATTR(_name, _mode, _show, _store) extern int __must_check class_device_create_file(struct class_device *, const struct class_device_attribute *); @@ -257,26 +266,24 @@ struct class_device { struct list_head node; struct kobject kobj; - struct class * class; /* required */ - dev_t devt; /* dev_t, creates the sysfs "dev" */ - struct device * dev; /* not necessary, but nice to have */ - void * class_data; /* class-specific data */ - struct class_device *parent; /* parent of this child device, if there is one */ - struct attribute_group ** groups; /* optional groups */ - - void (*release)(struct class_device *dev); - int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); - char class_id[BUS_ID_SIZE]; /* unique to this class */ + struct class *class; + dev_t devt; + struct device *dev; + void *class_data; + struct class_device *parent; + struct attribute_group **groups; + + void (*release)(struct class_device *dev); + int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env); + char class_id[BUS_ID_SIZE]; }; -static inline void * -class_get_devdata (struct class_device *dev) +static inline void *class_get_devdata(struct class_device *dev) { return dev->class_data; } -static inline void -class_set_devdata (struct class_device *dev, void *data) +static inline void class_set_devdata(struct class_device *dev, void *data) { dev->class_data = data; } @@ -288,10 +295,10 @@ extern void class_device_initialize(struct class_device *); extern int __must_check class_device_add(struct class_device *); extern void class_device_del(struct class_device *); -extern struct class_device * class_device_get(struct class_device *); +extern struct class_device *class_device_get(struct class_device *); extern void class_device_put(struct class_device *); -extern void class_device_remove_file(struct class_device *, +extern void class_device_remove_file(struct class_device *, const struct class_device_attribute *); extern int __must_check class_device_create_bin_file(struct class_device *, struct bin_attribute *); @@ -318,7 +325,7 @@ extern struct class_device *class_device_create(struct class *cls, dev_t devt, struct device *device, const char *fmt, ...) - __attribute__((format(printf,5,6))); + __attribute__((format(printf, 5, 6))); extern void class_device_destroy(struct class *cls, dev_t devt); /* @@ -335,8 +342,8 @@ struct device_type { struct attribute_group **groups; int (*uevent)(struct device *dev, struct kobj_uevent_env *env); void (*release)(struct device *dev); - int (*suspend)(struct device * dev, pm_message_t state); - int (*resume)(struct device * dev); + int (*suspend)(struct device *dev, pm_message_t state); + int (*resume)(struct device *dev); }; /* interface for exporting device attributes */ @@ -348,18 +355,19 @@ struct device_attribute { const char *buf, size_t count); }; -#define DEVICE_ATTR(_name,_mode,_show,_store) \ -struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store) +#define DEVICE_ATTR(_name, _mode, _show, _store) \ +struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) extern int __must_check device_create_file(struct device *device, - struct device_attribute * entry); -extern void device_remove_file(struct device * dev, struct device_attribute * attr); + struct device_attribute *entry); +extern void device_remove_file(struct device *dev, + struct device_attribute *attr); extern int __must_check device_create_bin_file(struct device *dev, struct bin_attribute *attr); extern void device_remove_bin_file(struct device *dev, struct bin_attribute *attr); extern int device_schedule_callback_owner(struct device *dev, - void (*func)(struct device *), struct module *owner); + void (*func)(struct device *dev), struct module *owner); /* This is a macro to avoid include problems with THIS_MODULE */ #define device_schedule_callback(dev, func) \ @@ -370,21 +378,21 @@ typedef void (*dr_release_t)(struct device *dev, void *res); typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data); #ifdef CONFIG_DEBUG_DEVRES -extern void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp, +extern void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp, const char *name); #define devres_alloc(release, size, gfp) \ __devres_alloc(release, size, gfp, #release) #else -extern void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp); +extern void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp); #endif extern void devres_free(void *res); extern void devres_add(struct device *dev, void *res); -extern void * devres_find(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); -extern void * devres_get(struct device *dev, void *new_res, +extern void *devres_find(struct device *dev, dr_release_t release, dr_match_t match, void *match_data); -extern void * devres_remove(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); +extern void *devres_get(struct device *dev, void *new_res, + dr_match_t match, void *match_data); +extern void *devres_remove(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data); extern int devres_destroy(struct device *dev, dr_release_t release, dr_match_t match, void *match_data); @@ -401,7 +409,7 @@ extern void devm_kfree(struct device *dev, void *p); struct device { struct klist klist_children; - struct klist_node knode_parent; /* node in sibling list */ + struct klist_node knode_parent; /* node in sibling list */ struct klist_node knode_driver; struct klist_node knode_bus; struct device *parent; @@ -416,7 +424,7 @@ struct device { * its driver. */ - struct bus_type * bus; /* type of bus device is on */ + struct bus_type *bus; /* type of bus device is on */ struct device_driver *driver; /* which driver has allocated this device */ void *driver_data; /* data private to the driver */ @@ -447,10 +455,10 @@ struct device { /* class_device migration path */ struct list_head node; struct class *class; - dev_t devt; /* dev_t, creates the sysfs "dev" */ + dev_t devt; /* dev_t, creates the sysfs "dev" */ struct attribute_group **groups; /* optional groups */ - void (*release)(struct device * dev); + void (*release)(struct device *dev); }; #ifdef CONFIG_NUMA @@ -472,14 +480,12 @@ static inline void set_dev_node(struct device *dev, int node) } #endif -static inline void * -dev_get_drvdata (struct device *dev) +static inline void *dev_get_drvdata(struct device *dev) { return dev->driver_data; } -static inline void -dev_set_drvdata (struct device *dev, void *data) +static inline void dev_set_drvdata(struct device *dev, void *data) { dev->driver_data = data; } @@ -494,15 +500,15 @@ void driver_init(void); /* * High level routines for use by the bus drivers */ -extern int __must_check device_register(struct device * dev); -extern void device_unregister(struct device * dev); -extern void device_initialize(struct device * dev); -extern int __must_check device_add(struct device * dev); -extern void device_del(struct device * dev); -extern int device_for_each_child(struct device *, void *, - int (*fn)(struct device *, void *)); -extern struct device *device_find_child(struct device *, void *data, - int (*match)(struct device *, void *)); +extern int __must_check device_register(struct device *dev); +extern void device_unregister(struct device *dev); +extern void device_initialize(struct device *dev); +extern int __must_check device_add(struct device *dev); +extern void device_del(struct device *dev); +extern int device_for_each_child(struct device *dev, void *data, + int (*fn)(struct device *dev, void *data)); +extern struct device *device_find_child(struct device *dev, void *data, + int (*match)(struct device *dev, void *data)); extern int device_rename(struct device *dev, char *new_name); extern int device_move(struct device *dev, struct device *new_parent); @@ -511,8 +517,8 @@ extern int device_move(struct device *dev, struct device *new_parent); * for information on use. */ extern int __must_check device_bind_driver(struct device *dev); -extern void device_release_driver(struct device * dev); -extern int __must_check device_attach(struct device * dev); +extern void device_release_driver(struct device *dev); +extern int __must_check device_attach(struct device *dev); extern int __must_check driver_attach(struct device_driver *drv); extern int __must_check device_reprobe(struct device *dev); @@ -521,7 +527,7 @@ extern int __must_check device_reprobe(struct device *dev); */ extern struct device *device_create(struct class *cls, struct device *parent, dev_t devt, const char *fmt, ...) - __attribute__((format(printf,4,5))); + __attribute__((format(printf, 4, 5))); extern void device_destroy(struct class *cls, dev_t devt); #ifdef CONFIG_PM_SLEEP extern void destroy_suspended_device(struct class *cls, dev_t devt); @@ -538,17 +544,17 @@ static inline void destroy_suspended_device(struct class *cls, dev_t devt) * know about. */ /* Notify platform of device discovery */ -extern int (*platform_notify)(struct device * dev); +extern int (*platform_notify)(struct device *dev); -extern int (*platform_notify_remove)(struct device * dev); +extern int (*platform_notify_remove)(struct device *dev); /** * get_device - atomically increment the reference count for the device. * */ -extern struct device * get_device(struct device * dev); -extern void put_device(struct device * dev); +extern struct device *get_device(struct device *dev); +extern void put_device(struct device *dev); /* drivers/base/power/shutdown.c */ @@ -560,7 +566,8 @@ extern void sysdev_shutdown(void); /* debugging and troubleshooting/diagnostic helpers. */ extern const char *dev_driver_string(struct device *dev); #define dev_printk(level, dev, format, arg...) \ - printk(level "%s %s: " format , dev_driver_string(dev) , (dev)->bus_id , ## arg) + printk(level "%s %s: " format , dev_driver_string(dev) , \ + (dev)->bus_id , ## arg) #define dev_emerg(dev, format, arg...) \ dev_printk(KERN_EMERG , dev , format , ## arg) @@ -582,7 +589,7 @@ extern const char *dev_driver_string(struct device *dev); dev_printk(KERN_DEBUG , dev , format , ## arg) #else static inline int __attribute__ ((format (printf, 2, 3))) -dev_dbg(struct device * dev, const char * fmt, ...) +dev_dbg(struct device *dev, const char *fmt, ...) { return 0; } @@ -592,7 +599,7 @@ dev_dbg(struct device * dev, const char * fmt, ...) #define dev_vdbg dev_dbg #else static inline int __attribute__ ((format (printf, 2, 3))) -dev_vdbg(struct device * dev, const char * fmt, ...) +dev_vdbg(struct device *dev, const char *fmt, ...) { return 0; } -- cgit v1.2.3-70-g09d2 From 1f9ffc049d7a88c8489b883b6fc0a25185062002 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 27 Jan 2008 10:29:20 -0800 Subject: Driver core: add bus_find_device_by_name function The driver core, and some other parts of the kernel just want to find a device based on a name for a specific bus. Give them a simple wrapper to prevent them from having to always roll their own. This will be used in the PPC patch later in this series. Cc: Paul Mackerras Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 41 +++++++++++++++++++++++++++++------------ include/linux/device.h | 3 +++ 2 files changed, 32 insertions(+), 12 deletions(-) (limited to 'include/linux/device.h') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index f484495b2ad..055989e9479 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -163,15 +163,6 @@ static struct kset *bus_kset; #ifdef CONFIG_HOTPLUG /* Manually detach a device from its associated driver. */ -static int driver_helper(struct device *dev, void *data) -{ - const char *name = data; - - if (strcmp(name, dev->bus_id) == 0) - return 1; - return 0; -} - static ssize_t driver_unbind(struct device_driver *drv, const char *buf, size_t count) { @@ -179,7 +170,7 @@ static ssize_t driver_unbind(struct device_driver *drv, struct device *dev; int err = -ENODEV; - dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); + dev = bus_find_device_by_name(bus, NULL, buf); if (dev && dev->driver == drv) { if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); @@ -206,7 +197,7 @@ static ssize_t driver_bind(struct device_driver *drv, struct device *dev; int err = -ENODEV; - dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); + dev = bus_find_device_by_name(bus, NULL, buf); if (dev && dev->driver == NULL) { if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); @@ -250,7 +241,7 @@ static ssize_t store_drivers_probe(struct bus_type *bus, { struct device *dev; - dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); + dev = bus_find_device_by_name(bus, NULL, buf); if (!dev) return -ENODEV; if (bus_rescan_devices_helper(dev, NULL) != 0) @@ -338,6 +329,32 @@ struct device *bus_find_device(struct bus_type *bus, } EXPORT_SYMBOL_GPL(bus_find_device); +static int match_name(struct device *dev, void *data) +{ + const char *name = data; + + if (strcmp(name, dev->bus_id) == 0) + return 1; + return 0; +} + +/** + * bus_find_device_by_name - device iterator for locating a particular device of a specific name + * @bus: bus type + * @start: Device to begin with + * @name: name of the device to match + * + * This is similar to the bus_find_device() function above, but it handles + * searching by a name automatically, no need to write another strcmp matching + * function. + */ +struct device *bus_find_device_by_name(struct bus_type *bus, + struct device *start, const char *name) +{ + return bus_find_device(bus, start, (void *)name, match_name); +} +EXPORT_SYMBOL_GPL(bus_find_device_by_name); + static struct device_driver *next_driver(struct klist_iter *i) { struct klist_node *n = klist_next(i); diff --git a/include/linux/device.h b/include/linux/device.h index 1880208964d..db375be333c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -84,6 +84,9 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, struct device *bus_find_device(struct bus_type *bus, struct device *start, void *data, int (*match)(struct device *dev, void *data)); +struct device *bus_find_device_by_name(struct bus_type *bus, + struct device *start, + const char *name); int __must_check bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, -- cgit v1.2.3-70-g09d2