diff options
| author | Patrick Mochel <mochel@osdl.org> | 2002-12-04 06:07:19 -0600 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2002-12-04 06:07:19 -0600 |
| commit | 8bed75c80972fbfb09c93dbbfcc79d8d0377263c (patch) | |
| tree | 658a16e9a42bd6b7fe79768a7592717a19928f8a | |
| parent | 2becf2fd04bdad4a7d0acb94fef355a0b3febfdb (diff) | |
| parent | 6f614c99601d8d5f2b67a186806bbd21e5108fc5 (diff) | |
Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core
| -rw-r--r-- | drivers/base/base.h | 12 | ||||
| -rw-r--r-- | drivers/base/bus.c | 90 | ||||
| -rw-r--r-- | drivers/base/class.c | 12 | ||||
| -rw-r--r-- | drivers/base/core.c | 24 | ||||
| -rw-r--r-- | drivers/base/intf.c | 275 | ||||
| -rw-r--r-- | drivers/base/node.c | 4 | ||||
| -rw-r--r-- | drivers/base/power.c | 22 | ||||
| -rw-r--r-- | drivers/block/genhd.c | 4 | ||||
| -rw-r--r-- | drivers/pci/probe.c | 1 | ||||
| -rw-r--r-- | fs/partitions/check.c | 6 | ||||
| -rw-r--r-- | fs/sysfs/inode.c | 60 | ||||
| -rw-r--r-- | include/linux/device.h | 26 | ||||
| -rw-r--r-- | include/linux/kobject.h | 9 | ||||
| -rw-r--r-- | lib/kobject.c | 37 |
14 files changed, 460 insertions, 122 deletions
diff --git a/drivers/base/base.h b/drivers/base/base.h index 6194d88242ec..ab31ff74207c 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -1,13 +1,5 @@ #undef DEBUG -#ifdef DEBUG -# define DBG(x...) printk(x) -#else -# define DBG(x...) -#endif - -extern struct list_head global_device_list; -extern spinlock_t device_lock; extern struct semaphore device_sem; extern int bus_add_device(struct device * dev); @@ -22,8 +14,8 @@ extern void devclass_remove_device(struct device *); extern int devclass_add_driver(struct device_driver *); extern void devclass_remove_driver(struct device_driver *); -extern int interface_add(struct device_class *, struct device *); -extern void interface_remove(struct device_class *, struct device *); +extern int interface_add_dev(struct device *); +extern void interface_remove_dev(struct device *); #ifdef CONFIG_HOTPLUG diff --git a/drivers/base/bus.c b/drivers/base/bus.c index d18effa7f981..ca5ef19aa4a9 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -133,6 +133,91 @@ struct subsystem bus_subsys = { /** + * bus_for_each_dev - device iterator. + * @bus: bus type. + * @start: device to start iterating from. + * @data: data for the callback. + * @fn: function to be called for each device. + * + * Iterate over @bus's list of devices, and call @fn for each, + * passing it @data. If @start is not NULL, we use that device to + * begin iterating from. + * + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. + * + * NOTE: The device that returns a non-zero value is not retained + * in any way, nor is its refcount incremented. If the caller needs + * to retain this data, it should do, and increment the reference + * count in the supplied callback. + */ +int bus_for_each_dev(struct bus_type * bus, struct device * start, + void * data, int (*fn)(struct device *, void *)) +{ + struct list_head * head, * entry; + int error = 0; + + if (!(bus = get_bus(bus))) + return -EINVAL; + + head = start ? &start->bus_list : &bus->devices; + + down_read(&bus->subsys.rwsem); + list_for_each(entry,head) { + struct device * dev = get_device(to_dev(entry)); + error = fn(dev,data); + put_device(dev); + if (error) + break; + } + up_read(&bus->subsys.rwsem); + return error; +} + +/** + * bus_for_each_drv - driver iterator + * @bus: bus we're dealing with. + * @start: driver to start iterating on. + * @data: data to pass to the callback. + * @fn: function to call for each driver. + * + * This is nearly identical to the device iterator above. + * We iterate over each driver that belongs to @bus, and call + * @fn for each. If @fn returns anything but 0, we break out + * and return it. If @start is not NULL, we use it as the head + * of the list. + * + * NOTE: we don't return the driver that returns a non-zero + * value, nor do we leave the reference count incremented for that + * driver. If the caller needs to know that info, it must set it + * in the callback. It must also be sure to increment the refcount + * so it doesn't disappear before returning to the caller. + */ + +int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, + void * data, int (*fn)(struct device_driver *, void *)) +{ + struct list_head * head, * entry; + int error = 0; + + if(!(bus = get_bus(bus))) + return -EINVAL; + + head = start ? &start->bus_list : &bus->drivers; + + down_read(&bus->subsys.rwsem); + list_for_each(entry,head) { + struct device_driver * drv = get_driver(to_drv(entry)); + error = fn(drv,data); + put_driver(drv); + if(error) + break; + } + up_read(&bus->subsys.rwsem); + return error; +} + +/** * attach - add device to driver. * @dev: device. * @@ -190,7 +275,7 @@ static int bus_match(struct device * dev, struct device_driver * drv) */ static int device_attach(struct device * dev) { - struct bus_type * bus = dev->bus; + struct bus_type * bus = dev->bus; struct list_head * entry; int error = 0; @@ -455,6 +540,9 @@ static int __init bus_subsys_init(void) core_initcall(bus_subsys_init); +EXPORT_SYMBOL(bus_for_each_dev); +EXPORT_SYMBOL(bus_for_each_drv); + EXPORT_SYMBOL(bus_add_device); EXPORT_SYMBOL(bus_remove_device); EXPORT_SYMBOL(bus_register); diff --git a/drivers/base/class.c b/drivers/base/class.c index fbc6326312d8..86c7775c42bd 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -2,7 +2,7 @@ * class.c - basic device class management */ -#undef DEBUG +#define DEBUG #include <linux/device.h> #include <linux/module.h> @@ -98,7 +98,6 @@ void devclass_remove_file(struct device_class * cls, struct devclass_attribute * } - int devclass_add_driver(struct device_driver * drv) { struct device_class * cls = get_devclass(drv->devclass); @@ -172,9 +171,11 @@ int devclass_add_device(struct device * dev) error = cls->add_device(dev); if (!error) { enum_device(cls,dev); - interface_add(cls,dev); + interface_add_dev(dev); } + list_add_tail(&dev->class_list,&cls->devices); + /* notify userspace (call /sbin/hotplug) */ class_hotplug (dev, "add"); @@ -196,9 +197,11 @@ void devclass_remove_device(struct device * dev) down_write(&cls->subsys.rwsem); pr_debug("device class %s: removing device %s\n", cls->name,dev->name); - interface_remove(cls,dev); + interface_remove_dev(dev); unenum_device(cls,dev); + list_del(&dev->class_list); + /* notify userspace (call /sbin/hotplug) */ class_hotplug (dev, "remove"); @@ -224,6 +227,7 @@ void put_devclass(struct device_class * cls) int devclass_register(struct device_class * cls) { INIT_LIST_HEAD(&cls->drivers); + INIT_LIST_HEAD(&cls->devices); pr_debug("device class '%s': registering\n",cls->name); strncpy(cls->subsys.kobj.name,cls->name,KOBJ_NAME_LEN); diff --git a/drivers/base/core.c b/drivers/base/core.c index 6425fc8e0634..a5ab807d9f49 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -18,15 +18,11 @@ #include "base.h" -LIST_HEAD(global_device_list); - int (*platform_notify)(struct device * dev) = NULL; int (*platform_notify_remove)(struct device * dev) = NULL; DECLARE_MUTEX(device_sem); -spinlock_t device_lock = SPIN_LOCK_UNLOCKED; - #define to_dev(obj) container_of(obj,struct device,kobj) @@ -146,11 +142,10 @@ void device_initialize(struct device *dev) kobject_init(&dev->kobj); INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->children); - INIT_LIST_HEAD(&dev->g_list); INIT_LIST_HEAD(&dev->driver_list); INIT_LIST_HEAD(&dev->bus_list); + INIT_LIST_HEAD(&dev->class_list); INIT_LIST_HEAD(&dev->intf_list); -// spin_lock_init(&dev->lock); } /** @@ -188,13 +183,11 @@ int device_add(struct device *dev) goto register_done; /* now take care of our own registration */ - down(&device_sem); if (parent) { - list_add_tail(&dev->g_list,&dev->parent->g_list); + down(&device_sem); list_add_tail(&dev->node,&parent->children); - } else - list_add_tail(&dev->g_list,&global_device_list); - up(&device_sem); + up(&device_sem); + } bus_add_device(dev); @@ -276,10 +269,11 @@ void device_del(struct device * dev) { struct device * parent = dev->parent; - down(&device_sem); - list_del_init(&dev->node); - list_del_init(&dev->g_list); - up(&device_sem); + if (parent) { + down(&device_sem); + list_del_init(&dev->node); + up(&device_sem); + } /* Notify the platform of the removal, in case they * need to do anything... diff --git a/drivers/base/intf.c b/drivers/base/intf.c index d31ad38bf3d2..63c5a4d12cd4 100644 --- a/drivers/base/intf.c +++ b/drivers/base/intf.c @@ -2,7 +2,7 @@ * intf.c - class-specific interface management */ -#undef DEBUG +#define DEBUG #include <linux/device.h> #include <linux/module.h> @@ -10,98 +10,267 @@ #include "base.h" -#define to_intf(node) container_of(node,struct device_interface,kobj.entry) +#define to_intf(node) container_of(node,struct device_interface,subsys.kobj.entry) + +#define to_data(e) container_of(e,struct intf_data,kobj.entry) + +#define intf_from_data(d) container_of(d->kobj.subsys,struct device_interface, subsys); + /** - * intf_dev_link - symlink from interface's directory to device's directory + * intf_dev_link - create sysfs symlink for interface. + * @data: interface data descriptor. * + * Create a symlink 'phys' in the interface's directory to */ + static int intf_dev_link(struct intf_data * data) { - char linkname[16]; - - snprintf(linkname,16,"%u",data->intf_num); - return sysfs_create_link(&data->intf->kobj,&data->dev->kobj,linkname); + char name[16]; + snprintf(name,16,"%d",data->intf_num); + return sysfs_create_link(&data->intf->subsys.kobj,&data->dev->kobj,name); } +/** + * intf_dev_unlink - remove symlink for interface. + * @intf: interface data descriptor. + * + */ + static void intf_dev_unlink(struct intf_data * data) { - char linkname[16]; - snprintf(linkname,16,"%u",data->intf_num); - sysfs_remove_link(&data->intf->kobj,linkname); + char name[16]; + snprintf(name,16,"%d",data->intf_num); + sysfs_remove_link(&data->intf->subsys.kobj,name); +} + + +/** + * interface_add_data - attach data descriptor + * @data: interface data descriptor. + * + * This attaches the per-instance interface object to the + * interface (by registering its kobject) and the device + * itself (by inserting it into the device's list). + * + * Note that there is no explicit protection done in this + * function. This should be called from the interface's + * add_device() method, which is called under the protection + * of the class's rwsem. + */ + +int interface_add_data(struct intf_data * data) +{ + struct device_interface * intf = intf_from_data(data); + + data->intf_num = data->intf->devnum++; + data->kobj.subsys = &intf->subsys; + kobject_register(&data->kobj); + + list_add_tail(&data->dev_entry,&data->dev->intf_list); + intf_dev_link(data); + return 0; +} + + +/** + * interface_remove_data - detach data descriptor. + * @data: interface data descriptor. + * + * This detaches the per-instance data descriptor by removing + * it from the device's list and unregistering the kobject from + * the subsystem. + */ + +void interface_remove_data(struct intf_data * data) +{ + intf_dev_unlink(data); + list_del_init(&data->dev_entry); + kobject_unregister(&data->kobj); } +/** + * add - attach device to interface + * @intf: interface. + * @dev: device. + * + * This is just a simple helper. Check the interface's interface + * helper and call it. This is called when adding an interface + * the class's devices, or a device to the class's interfaces. + */ + +static int add(struct device_interface * intf, struct device * dev) +{ + int error = 0; + + if (intf->add_device) + error = intf->add_device(dev); + pr_debug(" -> %s (%d)\n",dev->bus_id,error); + return error; +} + +/** + * del - detach device from interface. + * @data: interface data descriptor. + * + * Another simple helper. Remove the data descriptor from + * the device and the interface, then call the interface's + * remove_device() method. + */ + +static void del(struct intf_data * data) +{ + struct device_interface * intf = intf_from_data(data); + + pr_debug(" -> %s ",data->intf->name); + interface_remove_data(data); + if (intf->remove_device) + intf->remove_device(data); +} + +#define to_dev(entry) container_of(entry,struct device,class_list) + + +/** + * add_intf - add class's devices to interface. + * @intf: interface. + * + * Loop over the devices registered with the class, and call + * the interface's add_device() method for each. + * + * On an error, we won't break, but we will print debugging info. + */ +static void add_intf(struct device_interface * intf) +{ + struct device_class * cls = intf->devclass; + struct list_head * entry; + + down_write(&cls->subsys.rwsem); + list_for_each(entry,&cls->devices) + add(intf,to_dev(entry)); + up_write(&cls->subsys.rwsem); +} + +/** + * interface_register - register an interface with a device class. + * @intf: interface. + * + * An interface may be loaded after drivers and devices have been + * added to the class. So, we must add each device already known to + * the class to the interface as its registered. + */ + int interface_register(struct device_interface * intf) { struct device_class * cls = get_devclass(intf->devclass); - int error = 0; if (cls) { pr_debug("register interface '%s' with class '%s'\n", intf->name,cls->name); - strncpy(intf->kobj.name,intf->name,KOBJ_NAME_LEN); - intf->kobj.subsys = &cls->subsys; - kobject_register(&intf->kobj); - } else - error = -EINVAL; - return error; + + strncpy(intf->subsys.kobj.name,intf->name,KOBJ_NAME_LEN); + intf->subsys.kobj.subsys = &cls->subsys; + subsystem_register(&intf->subsys); + add_intf(intf); + } + return 0; } + +/** + * del_intf - remove devices from interface. + * @intf: interface being unloaded. + * + * This loops over the devices registered with a class and + * calls the interface's remove_device() method for each. + * This is called when an interface is being unregistered. + */ + +static void del_intf(struct device_interface * intf) +{ + struct list_head * entry; + + down_write(&intf->devclass->subsys.rwsem); + list_for_each(entry,&intf->subsys.list) { + struct intf_data * data = to_data(entry); + del(data); + } + up_write(&intf->devclass->subsys.rwsem); +} + +/** + * interface_unregister - remove interface from class. + * @intf: interface. + * + * This is called when an interface in unloaded, giving it a + * chance to remove itself from devicse that have been added to + * it. + */ + void interface_unregister(struct device_interface * intf) { - pr_debug("unregistering interface '%s' from class '%s'\n", - intf->name,intf->devclass->name); - kobject_unregister(&intf->kobj); + struct device_class * cls = intf->devclass; + if (cls) { + pr_debug("unregistering interface '%s' from class '%s'\n", + intf->name,cls->name); + del_intf(intf); + subsystem_unregister(&intf->subsys); + put_devclass(cls); + } } -int interface_add(struct device_class * cls, struct device * dev) + +/** + * interface_add_dev - add device to interfaces. + * @dev: device. + * + * This is a helper for the class driver core. When a + * device is being added to a class, this is called to add + * the device to all the interfaces in the class. + * + * The operation is simple enough: loop over the interfaces + * and call add() [above] for each. The class rwsem is assumed + * to be held. + */ + +int interface_add_dev(struct device * dev) { + struct device_class * cls = dev->driver->devclass; struct list_head * node; - int error = 0; - pr_debug("adding '%s' to %s class interfaces\n",dev->name,cls->name); + pr_debug("interfaces: adding device %s\n",dev->name); list_for_each(node,&cls->subsys.list) { struct device_interface * intf = to_intf(node); - if (intf->add_device) { - error = intf->add_device(dev); - if (error) - pr_debug("%s:%s: adding '%s' failed: %d\n", - cls->name,intf->name,dev->name,error); - } - + add(intf,dev); } return 0; } -void interface_remove(struct device_class * cls, struct device * dev) -{ - struct list_head * node; - struct list_head * next; - pr_debug("remove '%s' from %s class interfaces: ",dev->name,cls->name); +/** + * interface_remove_dev - remove device from interfaces. + * @dev: device. + * + * This is another helper for the class driver core, and called + * when the device is being removed from the class. + * + * We iterate over the list of interface data descriptors attached + * to the device, and call del() [above] for each. Again, the + * class's rwsem is assumed to be held during this. + */ - list_for_each_safe(node,next,&dev->intf_list) { - struct intf_data * intf_data = container_of(node,struct intf_data,node); - list_del_init(&intf_data->node); +void interface_remove_dev(struct device * dev) +{ + struct list_head * entry, * next; - intf_dev_unlink(intf_data); - pr_debug("%s ",intf_data->intf->name); - if (intf_data->intf->remove_device) - intf_data->intf->remove_device(intf_data); - } - pr_debug("\n"); -} + pr_debug("interfaces: removing device %s\n",dev->name); -int interface_add_data(struct intf_data * data) -{ - down_write(&data->intf->devclass->subsys.rwsem); - list_add_tail(&data->node,&data->dev->intf_list); - data->intf_num = data->intf->devnum++; - intf_dev_link(data); - up_write(&data->intf->devclass->subsys.rwsem); - return 0; + list_for_each_safe(entry,next,&dev->intf_list) { + struct intf_data * intf_data = to_data(entry); + del(intf_data); + } } EXPORT_SYMBOL(interface_register); diff --git a/drivers/base/node.c b/drivers/base/node.c index 631cdc395e05..815567bd72fe 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -93,7 +93,7 @@ int __init register_node(struct node *node, int num, struct node *parent) static int __init register_node_type(void) { - driver_register(&node_driver); - return devclass_register(&node_devclass); + devclass_register(&node_devclass); + return driver_register(&node_driver); } postcore_initcall(register_node_type); diff --git a/drivers/base/power.c b/drivers/base/power.c index 594a793e24f9..9e38aa766ef1 100644 --- a/drivers/base/power.c +++ b/drivers/base/power.c @@ -15,7 +15,9 @@ #include <asm/semaphore.h> #include "base.h" -#define to_dev(node) container_of(node,struct device,g_list) +#define to_dev(node) container_of(node,struct device,kobj.entry) + +extern struct subsystem device_subsys; /** * device_suspend - suspend/remove all devices on the device ree @@ -35,8 +37,8 @@ int device_suspend(u32 state, u32 level) printk(KERN_EMERG "Suspending devices\n"); - down(&device_sem); - list_for_each(node,&global_device_list) { + down_write(&device_subsys.rwsem); + list_for_each(node,&device_subsys.list) { struct device * dev = to_dev(node); if (dev->driver && dev->driver->suspend) { pr_debug("suspending device %s\n",dev->name); @@ -45,7 +47,7 @@ int device_suspend(u32 state, u32 level) printk(KERN_ERR "%s: suspend returned %d\n",dev->name,error); } } - up(&device_sem); + up_write(&device_subsys.rwsem); return error; } @@ -61,15 +63,15 @@ void device_resume(u32 level) { struct list_head * node; - down(&device_sem); - list_for_each_prev(node,&global_device_list) { + down_write(&device_subsys.rwsem); + list_for_each_prev(node,&device_subsys.list) { struct device * dev = to_dev(node); if (dev->driver && dev->driver->resume) { pr_debug("resuming device %s\n",dev->name); dev->driver->resume(dev,level); } } - up(&device_sem); + up_write(&device_subsys.rwsem); printk(KERN_EMERG "Devices Resumed\n"); } @@ -83,15 +85,15 @@ void device_shutdown(void) printk(KERN_EMERG "Shutting down devices\n"); - down(&device_sem); - list_for_each(entry,&global_device_list) { + down_write(&device_subsys.rwsem); + list_for_each(entry,&device_subsys.list) { struct device * dev = to_dev(entry); if (dev->driver && dev->driver->shutdown) { pr_debug("shutting down %s\n",dev->name); dev->driver->shutdown(dev); } } - up(&device_sem); + up_write(&device_subsys.rwsem); } EXPORT_SYMBOL(device_suspend); diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index f51a2cdb1c9d..98a62d7c7a6b 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -410,11 +410,11 @@ struct gendisk *alloc_disk(int minors) disk->minors = minors; while (minors >>= 1) disk->minor_shift++; - kobject_init(&disk->kobj); disk->kobj.subsys = &block_subsys; + kobject_init(&disk->kobj); INIT_LIST_HEAD(&disk->full_list); + rand_initialize_disk(disk); } - rand_initialize_disk(disk); return disk; } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5135fdde0d4d..118611ea603f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -448,6 +448,7 @@ struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp) /* now put in global tree */ strcpy(dev->dev.bus_id,dev->slot_name); + dev->dev.dma_mask = &dev->dma_mask; device_register(&dev->dev); return dev; diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 102e9f1f651b..797343c18942 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -377,7 +377,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) p->start_sect = start; p->nr_sects = len; devfs_register_partition(disk, part); - kobject_init(&p->kobj); snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part); p->kobj.parent = &disk->kobj; p->kobj.subsys = &part_subsys; @@ -406,7 +405,7 @@ void register_disk(struct gendisk *disk) s = strchr(disk->kobj.name, '/'); if (s) *s = '!'; - kobject_register(&disk->kobj); + kobject_add(&disk->kobj); disk_sysfs_symlinks(disk); if (disk->flags & GENHD_FL_CD) @@ -529,8 +528,7 @@ void del_gendisk(struct gendisk *disk) sysfs_remove_link(&disk->driverfs_dev->kobj, "block"); put_device(disk->driverfs_dev); } - kobject_get(&disk->kobj); /* kobject model is fucked in head */ - kobject_unregister(&disk->kobj); + kobject_del(&disk->kobj); } struct dev_name { diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 73633052e993..684038810f77 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -96,9 +96,10 @@ static int sysfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t if (!dentry->d_inode) { inode = sysfs_get_inode(dir->i_sb, mode, dev); - if (inode) + if (inode) { d_instantiate(dentry, inode); - else + dget(dentry); + } else error = -ENOSPC; } else error = -EEXIST; @@ -135,14 +136,52 @@ static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * if (inode) { int l = strlen(symname)+1; error = page_symlink(inode, symname, l); - if (!error) + if (!error) { d_instantiate(dentry, inode); - else + dget(dentry); + } else iput(inode); } return error; } +#define to_subsys(k) container_of(k,struct subsystem,kobj) +#define to_sattr(a) container_of(a,struct subsys_attribute,attr) + +/** + * Subsystem file operations. + * These operations allow subsystems to have files that can be + * read/written. + */ +ssize_t subsys_attr_show(struct kobject * kobj, struct attribute * attr, + char * page, size_t count, loff_t off) +{ + struct subsystem * s = to_subsys(kobj); + struct subsys_attribute * sattr = to_sattr(attr); + ssize_t ret = 0; + + if (sattr->show) + ret = sattr->show(s,page,count,off); + return ret; +} + +ssize_t subsys_attr_store(struct kobject * kobj, struct attribute * attr, + const char * page, size_t count, loff_t off) +{ + struct subsystem * s = to_subsys(kobj); + struct subsys_attribute * sattr = to_sattr(attr); + ssize_t ret = 0; + + if (sattr->store) + ret = sattr->store(s,page,count,off); + return ret; +} + +static struct sysfs_ops subsys_sysfs_ops = { + .show = subsys_attr_show, + .store = subsys_attr_store, +}; + /** * sysfs_read_file - read an attribute. * @file: file pointer. @@ -263,9 +302,14 @@ static int check_perm(struct inode * inode, struct file * file) if (!kobj || !attr) goto Einval; - + + /* if the kobject has no subsystem, then it is a subsystem itself, + * so give it the subsys_sysfs_ops. + */ if (kobj->subsys) ops = kobj->subsys->sysfs_ops; + else + ops = &subsys_sysfs_ops; /* No sysfs operations, either from having no subsystem, * or the subsystem have no operations. @@ -571,8 +615,8 @@ static void hash_and_remove(struct dentry * dir, const char * name) /* make sure dentry is really there */ if (victim->d_inode && (victim->d_parent->d_inode == dir->d_inode)) { - d_invalidate(victim); simple_unlink(dir->d_inode,victim); + d_delete(victim); } } up(&dir->d_inode->i_sem); @@ -631,15 +675,15 @@ void sysfs_remove_dir(struct kobject * kobj) struct dentry * d = list_entry(node,struct dentry,d_child); /* make sure dentry is still there */ if (d->d_inode) { - d_invalidate(d); simple_unlink(dentry->d_inode,d); + d_delete(dentry); } } up(&dentry->d_inode->i_sem); d_invalidate(dentry); simple_rmdir(parent->d_inode,dentry); - + d_delete(dentry); up(&parent->d_inode->i_sem); dput(parent); } diff --git a/include/linux/device.h b/include/linux/device.h index a88c4c7a3433..48612267bd65 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -85,6 +85,15 @@ extern struct bus_type * get_bus(struct bus_type * bus); extern void put_bus(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 *)); + +int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, + void * data, int (*fn)(struct device_driver *, void *)); + + /* driverfs interface for exporting bus attributes */ struct bus_attribute { @@ -159,6 +168,7 @@ struct device_class { struct subsystem devsubsys; struct subsystem drvsubsys; struct list_head drivers; + struct list_head devices; int (*add_device)(struct device *); void (*remove_device)(struct device *); @@ -207,9 +217,7 @@ struct device_interface { char * name; struct device_class * devclass; - struct kobject kobj; - struct list_head devices; - + struct subsystem subsys; u32 devnum; int (*add_device) (struct device *); @@ -230,10 +238,11 @@ extern void interface_unregister(struct device_interface *); * and create a driverfs symlink for it. */ struct intf_data { - struct list_head node; struct device_interface * intf; struct device * dev; u32 intf_num; + struct list_head dev_entry; + struct kobject kobj; }; extern int interface_add_data(struct intf_data *); @@ -241,9 +250,9 @@ extern int interface_add_data(struct intf_data *); struct device { - struct list_head g_list; /* node in depth-first order list */ struct list_head node; /* node in sibling list */ struct list_head bus_list; /* node in bus's list */ + struct list_head class_list; struct list_head driver_list; struct list_head children; struct list_head intf_list; @@ -270,6 +279,7 @@ struct device { being off. */ unsigned char *saved_state; /* saved device state */ + u64 *dma_mask; /* dma mask (if dma'able device) */ void (*release)(struct device * dev); }; @@ -280,12 +290,6 @@ list_to_dev(struct list_head *node) return list_entry(node, struct device, node); } -static inline struct device * -g_list_to_dev(struct list_head *g_list) -{ - return list_entry(g_list, struct device, g_list); -} - static inline void * dev_get_drvdata (struct device *dev) { diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 7b3157a78f7e..6b528c5a61cb 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -60,4 +60,13 @@ static inline void subsys_put(struct subsystem * s) kobject_put(&s->kobj); } +struct subsys_attribute { + struct attribute attr; + ssize_t (*show)(struct subsystem *, char *, size_t, loff_t); + ssize_t (*store)(struct subsystem *, const char *, size_t, loff_t); +}; + +extern int subsys_create_file(struct subsystem * , struct subsys_attribute *); +extern void subsys_remove_file(struct subsystem * , struct subsys_attribute *); + #endif /* _KOBJECT_H_ */ diff --git a/lib/kobject.c b/lib/kobject.c index 33e4f8c9ce58..04b1fd760d45 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -110,8 +110,7 @@ int kobject_register(struct kobject * kobj) if (kobj) { kobject_init(kobj); error = kobject_add(kobj); - if (error) - kobject_cleanup(kobj); + WARN_ON(error); } else error = -EINVAL; return error; @@ -229,6 +228,38 @@ void subsystem_unregister(struct subsystem * s) } +/** + * subsystem_create_file - export sysfs attribute file. + * @s: subsystem. + * @a: subsystem attribute descriptor. + */ + +int subsys_create_file(struct subsystem * s, struct subsys_attribute * a) +{ + int error = 0; + if (subsys_get(s)) { + error = sysfs_create_file(&s->kobj,&a->attr); + subsys_put(s); + } + return error; +} + + +/** + * subsystem_remove_file - remove sysfs attribute file. + * @s: subsystem. + * @a: attribute desciptor. + */ + +void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a) +{ + if (subsys_get(s)) { + sysfs_remove_file(&s->kobj,&a->attr); + subsys_put(s); + } +} + + EXPORT_SYMBOL(kobject_init); EXPORT_SYMBOL(kobject_register); EXPORT_SYMBOL(kobject_unregister); @@ -238,3 +269,5 @@ EXPORT_SYMBOL(kobject_put); EXPORT_SYMBOL(subsystem_init); EXPORT_SYMBOL(subsystem_register); EXPORT_SYMBOL(subsystem_unregister); +EXPORT_SYMBOL(subsys_create_file); +EXPORT_SYMBOL(subsys_remove_file); |
