diff options
| author | Greg Kroah-Hartman <greg@kroah.com> | 2004-05-27 22:57:58 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2004-05-27 22:57:58 -0700 |
| commit | 5bb8ea44561b68f63ca01a24dce5e7506d158d32 (patch) | |
| tree | cd2a7405a389a4f6fc73aac6f9e092017343085f | |
| parent | e743bea22dc98c9a63fe625fc82d262f32ecc97d (diff) | |
| parent | 3eb68d243b32d27362d63fe9a0ce4c1a03a73f7c (diff) | |
Merge kroah.com:/home/greg/linux/BK/bleed-2.6
into kroah.com:/home/greg/linux/BK/driver-2.6
| -rw-r--r-- | drivers/base/power/resume.c | 5 | ||||
| -rw-r--r-- | drivers/base/power/runtime.c | 4 | ||||
| -rw-r--r-- | drivers/base/power/suspend.c | 28 | ||||
| -rw-r--r-- | drivers/firmware/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/firmware/Makefile | 1 | ||||
| -rw-r--r-- | drivers/firmware/smbios.c | 248 | ||||
| -rw-r--r-- | drivers/firmware/smbios.h | 53 | ||||
| -rw-r--r-- | fs/sysfs/dir.c | 12 | ||||
| -rw-r--r-- | fs/sysfs/inode.c | 7 | ||||
| -rw-r--r-- | fs/sysfs/symlink.c | 135 | ||||
| -rw-r--r-- | fs/sysfs/sysfs.h | 7 |
11 files changed, 138 insertions, 370 deletions
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 637c52ad6ec6..90632b9ea95f 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -35,7 +35,10 @@ void dpm_resume(void) struct list_head * entry = dpm_off.next; struct device * dev = to_device(entry); list_del_init(entry); - resume_device(dev); + + if (!dev->power.power_state) + resume_device(dev); + list_add_tail(entry,&dpm_active); } } diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index d901a6fd6dc4..4ff5340e90fb 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -12,9 +12,11 @@ static void runtime_resume(struct device * dev) { + dev_dbg(dev, "resuming\n"); if (!dev->power.power_state) return; - resume_device(dev); + if (!resume_device(dev)) + dev->power.power_state = 0; } diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 19e660a21ecf..b48016dc5737 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -39,16 +39,11 @@ int suspend_device(struct device * dev, u32 state) { int error = 0; - if (dev->bus && dev->bus->suspend) + dev_dbg(dev, "suspending\n"); + + if (dev->bus && dev->bus->suspend && !dev->power.power_state) error = dev->bus->suspend(dev,state); - if (!error) { - list_del(&dev->power.entry); - list_add(&dev->power.entry,&dpm_off); - } else if (error == -EAGAIN) { - list_del(&dev->power.entry); - list_add(&dev->power.entry,&dpm_off_irq); - } return error; } @@ -81,11 +76,18 @@ int device_suspend(u32 state) while(!list_empty(&dpm_active)) { struct list_head * entry = dpm_active.prev; struct device * dev = to_device(entry); - if ((error = suspend_device(dev,state))) { - if (error != -EAGAIN) - goto Error; - else - error = 0; + error = suspend_device(dev,state); + + if (!error) { + list_del(&dev->power.entry); + list_add(&dev->power.entry,&dpm_off); + } else if (error == -EAGAIN) { + list_del(&dev->power.entry); + list_add(&dev->power.entry,&dpm_off_irq); + } else { + printk(KERN_ERR "Could not suspend device %s: " + "error %d\n", kobject_name(&dev->kobj), error); + goto Error; } } Done: diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 83575861bd21..597bf5f04e6d 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -34,12 +34,4 @@ config EFI_VARS Subsequent efibootmgr releases may be found at: http://linux.dell.com/efibootmgr -config SMBIOS - tristate "BIOS SMBIOS table access driver." - help - Say Y or M here if you want to enable access to the SMBIOS table - via driverfs. It exposes /sys/firmware/smbios/ subdirectory tree - containing a binary dump of the SMBIOS table header as well as the SMBIOS - table. - endmenu diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 694725046da7..ca7745addd5c 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -3,4 +3,3 @@ # obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_EFI_VARS) += efivars.o -obj-$(CONFIG_SMBIOS) += smbios.o diff --git a/drivers/firmware/smbios.c b/drivers/firmware/smbios.c deleted file mode 100644 index 583ab0939c08..000000000000 --- a/drivers/firmware/smbios.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * linux/drivers/firmware/smbios.c - * Copyright (C) 2004 Dell Inc. - * by Michael Brown <Michael_E_Brown@dell.com> - * vim:noet:ts=8:sw=8:filetype=c:textwidth=80: - * - * BIOS SMBIOS Table access - * conformant to DMTF SMBIOS definition - * at http://www.dmtf.org/standards/smbios - * - * This code takes information provided by SMBIOS tables - * and presents it in sysfs as: - * /sys/firmware/smbios - * |--> /table_entry_point - * |--> /table - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2.0 as published by - * the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/device.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include "smbios.h" - -MODULE_AUTHOR("Michael Brown <Michael_E_Brown@Dell.com>"); -MODULE_DESCRIPTION("sysfs interface to SMBIOS information"); -MODULE_LICENSE("GPL"); - -#define SMBIOS_VERSION "1.0 2004-04-19" - -struct smbios_device { - struct smbios_table_entry_point table_eps; - unsigned int smbios_table_real_length; -}; - -/* there shall be only one */ -static struct smbios_device the_smbios_device; - -#define to_smbios_device(obj) container_of(obj,struct smbios_device,kobj) - -/* don't currently have any "normal" attributes, so we don't need a way to - * show them. */ -static struct sysfs_ops smbios_attr_ops = { }; - -static __init int -checksum_eps(struct smbios_table_entry_point *table_eps) -{ - u8 *p = (u8 *)table_eps; - u8 checksum = 0; - int i=0; - for (i=0; i < table_eps->eps_length && i < sizeof(*table_eps); ++i) { - checksum += p[i]; - } - return( checksum == 0 ); -} - -static __init int -find_table_entry_point(struct smbios_device *sdev) -{ - struct smbios_table_entry_point *table_eps = &(sdev->table_eps); - u32 fp = 0xF0000; - while (fp < 0xFFFFF) { - isa_memcpy_fromio(table_eps, fp, sizeof(*table_eps)); - if (memcmp(table_eps->anchor, "_SM_", 4)==0 && - checksum_eps(table_eps)) { - return 0; - } - fp += 16; - } - - printk(KERN_INFO "SMBIOS table entry point not found in " - "0xF0000 - 0xFFFFF\n"); - return -ENODEV; -} - -static __init int -find_table_max_address(struct smbios_device *sdev) -{ - /* break out on one of three conditions: - * -- hit table_eps.table_length - * -- hit number of items that table claims we have - * -- hit structure type 127 - */ - - u8 *buf = ioremap(sdev->table_eps.table_address, - sdev->table_eps.table_length); - u8 *ptr = buf; - int count = 0, keep_going = 1; - int max_count = sdev->table_eps.table_num_structs; - int max_length = sdev->table_eps.table_length; - while(keep_going && ((ptr - buf) <= max_length) && count < max_count){ - if( ptr[0] == 0x7F ) /* ptr[0] is type */ - keep_going = 0; - - ptr += ptr[1]; /* ptr[1] is length, skip structure */ - /* skip strings at end of structure */ - while((ptr-buf) < max_length && (ptr[0] || ptr[1])) - ++ptr; - - /* string area ends in double-null. skip it. */ - ptr += 2; - ++count; - } - sdev->smbios_table_real_length = (ptr - buf); - iounmap(buf); - - if( count != max_count ) - printk(KERN_INFO "Warning: SMBIOS table structure count" - " does not match count specified in the" - " table entry point.\n" - " Table entry point count: %d\n" - " Actual count: %d\n", - max_count, count ); - - if(keep_going != 0) - printk(KERN_INFO "Warning: SMBIOS table does not end with a" - " structure type 127. This may indicate a" - " truncated table."); - - if(sdev->smbios_table_real_length != max_length) - printk(KERN_INFO "Warning: BIOS specified SMBIOS table length" - " does not match calculated length.\n" - " BIOS specified: %d\n" - " calculated length: %d\n", - max_length, sdev->smbios_table_real_length); - - return sdev->smbios_table_real_length; -} - -static ssize_t -smbios_read_table_entry_point(struct kobject *kobj, char *buffer, - loff_t pos, size_t size) -{ - struct smbios_device *sdev = &the_smbios_device; - const char *p = (const char *)&(sdev->table_eps); - unsigned int count = - size > sizeof(sdev->table_eps) ? - sizeof(sdev->table_eps) : size; - memcpy( buffer, p, count ); - return count; -} - -static ssize_t -smbios_read_table(struct kobject *kobj, char *buffer, - loff_t pos, size_t size) -{ - struct smbios_device *sdev = &the_smbios_device; - u8 *buf; - unsigned int count = sdev->smbios_table_real_length - pos; - int i = 0; - count = count < size ? count : size; - - if (pos > sdev->smbios_table_real_length) - return 0; - - buf = ioremap(sdev->table_eps.table_address, sdev->smbios_table_real_length); - if (buf == NULL) - return -ENXIO; - - /* memcpy( buffer, buf+pos, count ); */ - for (i = 0; i < count; ++i) { - buffer[i] = readb( buf+pos+i ); - } - - iounmap(buf); - - return count; -} - -static struct bin_attribute tep_attr = { - .attr = {.name = "table_entry_point", .owner = THIS_MODULE, .mode = 0444}, - .size = sizeof(struct smbios_table_entry_point), - .read = smbios_read_table_entry_point, - /* not writeable */ -}; - -static struct bin_attribute table_attr = { - .attr = { .name = "table", .owner = THIS_MODULE, .mode = 0444 }, - /* size set later, we don't know it here. */ - .read = smbios_read_table, - /* not writeable */ -}; - -/* no default attributes yet. */ -static struct attribute * def_attrs[] = { NULL, }; - -static struct kobj_type ktype_smbios = { - .sysfs_ops = &smbios_attr_ops, - .default_attrs = def_attrs, - /* statically allocated, no release method necessary */ -}; - -static decl_subsys(smbios,&ktype_smbios,NULL); - -static void smbios_device_unregister(void) -{ - sysfs_remove_bin_file(&smbios_subsys.kset.kobj, &tep_attr ); - sysfs_remove_bin_file(&smbios_subsys.kset.kobj, &table_attr ); -} - -static void __init smbios_device_register(void) -{ - sysfs_create_bin_file(&smbios_subsys.kset.kobj, &tep_attr ); - sysfs_create_bin_file(&smbios_subsys.kset.kobj, &table_attr ); -} - -static int __init -smbios_init(void) -{ - int rc=0; - - printk(KERN_INFO "SMBIOS facility v%s\n", SMBIOS_VERSION ); - - rc = find_table_entry_point(&the_smbios_device); - if (rc) - return rc; - - table_attr.size = find_table_max_address(&the_smbios_device); - - rc = firmware_register(&smbios_subsys); - if (rc) - return rc; - - smbios_device_register(); - - return rc; -} - -static void __exit -smbios_exit(void) -{ - smbios_device_unregister(); - firmware_unregister(&smbios_subsys); -} - -late_initcall(smbios_init); -module_exit(smbios_exit); diff --git a/drivers/firmware/smbios.h b/drivers/firmware/smbios.h deleted file mode 100644 index 7d56a0a2f4cf..000000000000 --- a/drivers/firmware/smbios.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * linux/drivers/firmware/smbios.c - * Copyright (C) 2002, 2003, 2004 Dell Inc. - * by Michael Brown <Michael_E_Brown@dell.com> - * vim:noet:ts=8:sw=8:filetype=c:textwidth=80: - * - * BIOS SMBIOS Table access - * conformant to DMTF SMBIOS definition - * at http://www.dmtf.org/standards/smbios - * - * This code takes information provided by SMBIOS tables - * and presents it in sysfs. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2.0 as published by - * the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _LINUX_SMBIOS_H -#define _LINUX_SMBIOS_H - -#include <linux/types.h> - -struct smbios_table_entry_point { - u8 anchor[4]; - u8 checksum; - u8 eps_length; - u8 major_ver; - u8 minor_ver; - u16 max_struct_size; - u8 revision; - u8 formatted_area[5]; - u8 dmi_anchor[5]; - u8 intermediate_checksum; - u16 table_length; - u32 table_address; - u16 table_num_structs; - u8 smbios_bcd_revision; -} __attribute__ ((packed)); - -struct smbios_structure_header { - u8 type; - u8 length; - u16 handle; -} __attribute__ ((packed)); - -#endif /* _LINUX_SMBIOS_H */ diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 91b06a20cd76..d688117ba029 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -10,6 +10,8 @@ #include <linux/kobject.h> #include "sysfs.h" +DECLARE_RWSEM(sysfs_rename_sem); + static int init_dir(struct inode * inode) { inode->i_op = &simple_dir_inode_operations; @@ -134,8 +136,14 @@ restart: /** * Unlink and unhash. */ + __d_drop(d); spin_unlock(&dcache_lock); - d_delete(d); + /* release the target kobject in case of + * a symlink + */ + if (S_ISLNK(d->d_inode->i_mode)) + kobject_put(d->d_fsdata); + simple_unlink(dentry->d_inode,d); dput(d); pr_debug(" done\n"); @@ -165,6 +173,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) if (!kobj->parent) return -EINVAL; + down_write(&sysfs_rename_sem); parent = kobj->parent->dentry; down(&parent->d_inode->i_sem); @@ -179,6 +188,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) dput(new_dentry); } up(&parent->d_inode->i_sem); + up_write(&sysfs_rename_sem); return error; } diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 6309cd83b6c3..ac5c0b962ba9 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -96,7 +96,12 @@ void sysfs_hash_and_remove(struct dentry * dir, const char * name) pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name, atomic_read(&victim->d_count)); - d_delete(victim); + d_drop(victim); + /* release the target kobject in case of + * a symlink + */ + if (S_ISLNK(victim->d_inode->i_mode)) + kobject_put(victim->d_fsdata); simple_unlink(dir->d_inode,victim); } /* diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 6216e946e326..c8bfec6b7428 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -8,27 +8,17 @@ #include "sysfs.h" +static struct inode_operations sysfs_symlink_inode_operations = { + .readlink = sysfs_readlink, + .follow_link = sysfs_follow_link, +}; static int init_symlink(struct inode * inode) { - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &sysfs_symlink_inode_operations; return 0; } -static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) -{ - int error; - - error = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink); - if (!error) { - int l = strlen(symname)+1; - error = page_symlink(dentry->d_inode, symname, l); - if (error) - iput(dentry->d_inode); - } - return error; -} - static int object_depth(struct kobject * kobj) { struct kobject * p = kobj; @@ -74,37 +64,20 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * nam struct dentry * dentry = kobj->dentry; struct dentry * d; int error = 0; - int size; - int depth; - char * path; - char * s; - - depth = object_depth(kobj); - size = object_path_length(target) + depth * 3 - 1; - if (size > PATH_MAX) - return -ENAMETOOLONG; - pr_debug("%s: depth = %d, size = %d\n",__FUNCTION__,depth,size); - - path = kmalloc(size,GFP_KERNEL); - if (!path) - return -ENOMEM; - memset(path,0,size); - - for (s = path; depth--; s += 3) - strcpy(s,"../"); - - fill_object_path(target,path,size); - pr_debug("%s: path = '%s'\n",__FUNCTION__,path); down(&dentry->d_inode->i_sem); d = sysfs_get_dentry(dentry,name); - if (!IS_ERR(d)) - error = sysfs_symlink(dentry->d_inode,d,path); - else + if (!IS_ERR(d)) { + error = sysfs_create(d, S_IFLNK|S_IRWXUGO, init_symlink); + if (!error) + /* + * associate the link dentry with the target kobject + */ + d->d_fsdata = kobject_get(target); + dput(d); + } else error = PTR_ERR(d); - dput(d); up(&dentry->d_inode->i_sem); - kfree(path); return error; } @@ -120,6 +93,86 @@ void sysfs_remove_link(struct kobject * kobj, char * name) sysfs_hash_and_remove(kobj->dentry,name); } +static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target, + char *path) +{ + char * s; + int depth, size; + + depth = object_depth(kobj); + size = object_path_length(target) + depth * 3 - 1; + if (size > PATH_MAX) + return -ENAMETOOLONG; + + pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size); + + for (s = path; depth--; s += 3) + strcpy(s,"../"); + + fill_object_path(target, path, size); + pr_debug("%s: path = '%s'\n", __FUNCTION__, path); + + return 0; +} + +static int sysfs_getlink(struct dentry *dentry, char * path) +{ + struct kobject *kobj, *target_kobj; + int error = 0; + + kobj = sysfs_get_kobject(dentry->d_parent); + if (!kobj) + return -EINVAL; + + target_kobj = sysfs_get_kobject(dentry); + if (!target_kobj) { + kobject_put(kobj); + return -EINVAL; + } + + down_read(&sysfs_rename_sem); + error = sysfs_get_target_path(kobj, target_kobj, path); + up_read(&sysfs_rename_sem); + + kobject_put(kobj); + kobject_put(target_kobj); + return error; + +} + +int sysfs_readlink(struct dentry *dentry, char __user *buffer, int buflen) +{ + int error = 0; + unsigned long page = get_zeroed_page(GFP_KERNEL); + + if (!page) + return -ENOMEM; + + error = sysfs_getlink(dentry, (char *) page); + if (!error) + error = vfs_readlink(dentry, buffer, buflen, (char *) page); + + free_page(page); + + return error; +} + +int sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + int error = 0; + unsigned long page = get_zeroed_page(GFP_KERNEL); + + if (!page) + return -ENOMEM; + + error = sysfs_getlink(dentry, (char *) page); + if (!error) + error = vfs_follow_link(nd, (char *) page); + + free_page(page); + + return error; +} EXPORT_SYMBOL(sysfs_create_link); EXPORT_SYMBOL(sysfs_remove_link); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 5976cc1aede0..ff5d1478a9fa 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -12,15 +12,18 @@ extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **); extern void sysfs_remove_subdir(struct dentry *); +extern int sysfs_readlink(struct dentry *, char __user *, int ); +extern int sysfs_follow_link(struct dentry *, struct nameidata *); +extern struct rw_semaphore sysfs_rename_sem; static inline struct kobject *sysfs_get_kobject(struct dentry *dentry) { struct kobject * kobj = NULL; - spin_lock(&dentry->d_lock); + spin_lock(&dcache_lock); if (!d_unhashed(dentry)) kobj = kobject_get(dentry->d_fsdata); - spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); return kobj; } |
