summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <greg@kroah.com>2004-05-14 01:44:08 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2004-05-14 01:44:08 -0700
commit3004c70f9036bbb74ea2842995edc8a21de9106e (patch)
treebe89c6ef4881d7749556bc63fb2fdc82d09ecadd
parent141baf80514374935d084c12f2f1e426e9cea5a0 (diff)
parent51c0c34c8f0ac464c97aaef4754e7dc163dd586e (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/bus.c32
-rw-r--r--drivers/base/class.c6
-rw-r--r--drivers/base/map.c7
-rw-r--r--drivers/base/platform.c5
-rw-r--r--drivers/base/sys.c5
-rw-r--r--drivers/block/paride/pg.c48
-rw-r--r--drivers/block/paride/pt.c54
-rw-r--r--drivers/char/ip2main.c46
-rw-r--r--drivers/char/ppdev.c45
-rw-r--r--drivers/char/tipar.c49
-rw-r--r--drivers/firmware/Kconfig8
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/smbios.c248
-rw-r--r--drivers/firmware/smbios.h53
-rw-r--r--drivers/macintosh/adb.c19
-rw-r--r--drivers/misc/Kconfig8
-rw-r--r--drivers/misc/ibmasm/module.c7
-rw-r--r--drivers/net/wan/cosa.c41
-rw-r--r--fs/sysfs/bin.c2
-rw-r--r--fs/sysfs/dir.c19
-rw-r--r--fs/sysfs/file.c2
-rw-r--r--fs/sysfs/sysfs.h13
-rw-r--r--include/linux/device.h2
-rw-r--r--include/linux/kobject.h2
-rw-r--r--include/linux/module.h25
-rw-r--r--include/linux/moduleparam.h4
-rw-r--r--include/linux/sysfs.h2
-rw-r--r--kernel/module.c160
-rw-r--r--kernel/params.c2
-rw-r--r--lib/kobject.c10
-rw-r--r--net/core/dev.c16
31 files changed, 861 insertions, 80 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index ebb0ec31fa41..b40af6a72afe 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -451,7 +451,11 @@ int bus_add_driver(struct device_driver * drv)
if (bus) {
pr_debug("bus %s: add driver %s\n",bus->name,drv->name);
- kobject_set_name(&drv->kobj,drv->name);
+ error = kobject_set_name(&drv->kobj,drv->name);
+ if (error) {
+ put_bus(bus);
+ return error;
+ }
drv->kobj.kset = &bus->drivers;
if ((error = kobject_register(&drv->kobj))) {
put_bus(bus);
@@ -555,21 +559,39 @@ struct bus_type * find_bus(char * name)
*/
int bus_register(struct bus_type * bus)
{
- kobject_set_name(&bus->subsys.kset.kobj,bus->name);
+ int retval;
+
+ retval = kobject_set_name(&bus->subsys.kset.kobj,bus->name);
+ if (retval)
+ goto out;
+
subsys_set_kset(bus,bus_subsys);
- subsystem_register(&bus->subsys);
+ retval = subsystem_register(&bus->subsys);
+ if (retval)
+ goto out;
kobject_set_name(&bus->devices.kobj, "devices");
bus->devices.subsys = &bus->subsys;
- kset_register(&bus->devices);
+ retval = kset_register(&bus->devices);
+ if (retval)
+ goto bus_devices_fail;
kobject_set_name(&bus->drivers.kobj, "drivers");
bus->drivers.subsys = &bus->subsys;
bus->drivers.ktype = &ktype_driver;
- kset_register(&bus->drivers);
+ retval = kset_register(&bus->drivers);
+ if (retval)
+ goto bus_drivers_fail;
pr_debug("bus type '%s' registered\n",bus->name);
return 0;
+
+bus_drivers_fail:
+ kset_unregister(&bus->devices);
+bus_devices_fail:
+ subsystem_unregister(&bus->subsys);
+out:
+ return retval;
}
diff --git a/drivers/base/class.c b/drivers/base/class.c
index b9fdce488e2c..ed13d9de0d1d 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -361,6 +361,8 @@ void class_device_unregister(struct class_device *class_dev)
int class_device_rename(struct class_device *class_dev, char *new_name)
{
+ int error = 0;
+
class_dev = class_device_get(class_dev);
if (!class_dev)
return -EINVAL;
@@ -370,11 +372,11 @@ int class_device_rename(struct class_device *class_dev, char *new_name)
strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN);
- kobject_rename(&class_dev->kobj, new_name);
+ error = kobject_rename(&class_dev->kobj, new_name);
class_device_put(class_dev);
- return 0;
+ return error;
}
struct class_device * class_device_get(struct class_device *class_dev)
diff --git a/drivers/base/map.c b/drivers/base/map.c
index 1effe3a303ee..aab93fc2a31b 100644
--- a/drivers/base/map.c
+++ b/drivers/base/map.c
@@ -138,6 +138,13 @@ struct kobj_map *kobj_map_init(kobj_probe_t *base_probe,
struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL);
int i;
+
+ if ((p == NULL) || (base == NULL)) {
+ kfree(p);
+ kfree(base);
+ return NULL;
+ }
+
memset(base, 0, sizeof(struct probe));
base->dev = 1;
base->range = ~0;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index e55900732f29..0d75909a4538 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -57,8 +57,9 @@ void platform_device_unregister(struct platform_device * pdev)
* type of device, like "pci" or "floppy", and <instance> is the
* enumerated instance of the device, like '0' or '42'.
* Driver IDs are simply "<name>".
- * So, extract the <name> from the device, and compare it against
- * the name of the driver. Return whether they match or not.
+ * So, extract the <name> from the platform_device structure,
+ * and compare it against the name of the driver. Return whether
+ * they match or not.
*/
static int platform_match(struct device * dev, struct device_driver * drv)
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 420cb3cf616f..b0d55a930855 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -180,8 +180,11 @@ int sysdev_register(struct sys_device * sysdev)
/* But make sure we point to the right type for sysfs translation */
sysdev->kobj.ktype = &ktype_sysdev;
- kobject_set_name(&sysdev->kobj,"%s%d",
+ error = kobject_set_name(&sysdev->kobj,"%s%d",
kobject_name(&cls->kset.kobj),sysdev->id);
+ if (error)
+ return error;
+
pr_debug("Registering sys device '%s'\n",kobject_name(&sysdev->kobj));
/* Register the object */
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index 506f982e5518..5ccc106fc89d 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -161,6 +161,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
#include <linux/slab.h>
#include <linux/mtio.h>
#include <linux/pg.h>
+#include <linux/device.h>
#include <asm/uaccess.h>
@@ -240,6 +241,8 @@ static int pg_identify(struct pg *dev, int log);
static char pg_scratch[512]; /* scratch block buffer */
+static struct class_simple *pg_class;
+
/* kernel glue structures */
static struct file_operations pg_fops = {
@@ -658,15 +661,19 @@ static ssize_t pg_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
static int __init pg_init(void)
{
- int unit;
+ int unit, err = 0;
- if (disable)
- return -1;
+ if (disable){
+ err = -1;
+ goto out;
+ }
pg_init_units();
- if (pg_detect())
- return -1;
+ if (pg_detect()) {
+ err = -1;
+ goto out;
+ }
if (register_chrdev(major, name, &pg_fops)) {
printk("pg_init: unable to get major number %d\n", major);
@@ -675,18 +682,37 @@ static int __init pg_init(void)
if (dev->present)
pi_release(dev->pi);
}
- return -1;
+ err = -1;
+ goto out;
+ }
+ pg_class = class_simple_create(THIS_MODULE, "pg");
+ if (IS_ERR(pg_class)) {
+ err = PTR_ERR(pg_class);
+ goto out_chrdev;
}
devfs_mk_dir("pg");
for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit];
if (dev->present) {
- devfs_mk_cdev(MKDEV(major, unit),
+ class_simple_device_add(pg_class, MKDEV(major, unit),
+ NULL, "pg%u", unit);
+ err = devfs_mk_cdev(MKDEV(major, unit),
S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u",
unit);
+ if (err)
+ goto out_class;
}
}
- return 0;
+ err = 0;
+ goto out;
+
+out_class:
+ class_simple_device_remove(MKDEV(major, unit));
+ class_simple_destroy(pg_class);
+out_chrdev:
+ unregister_chrdev(major, "pg");
+out:
+ return err;
}
static void __exit pg_exit(void)
@@ -695,10 +721,12 @@ static void __exit pg_exit(void)
for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit];
- if (dev->present)
+ if (dev->present) {
+ class_simple_device_remove(MKDEV(major, unit));
devfs_remove("pg/%u", unit);
+ }
}
-
+ class_simple_destroy(pg_class);
devfs_remove("pg");
unregister_chrdev(major, name);
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 7db4fc7584c0..81c4690cf4c4 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -145,6 +145,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mtio.h>
+#include <linux/device.h>
#include <asm/uaccess.h>
@@ -260,6 +261,9 @@ static struct file_operations pt_fops = {
.release = pt_release,
};
+/* sysfs class support */
+static struct class_simple *pt_class;
+
static inline int status_reg(struct pi_adapter *pi)
{
return pi_read_regr(pi, 1, 6);
@@ -959,33 +963,62 @@ static ssize_t pt_write(struct file *filp, const char *buf, size_t count, loff_t
static int __init pt_init(void)
{
- int unit;
+ int unit, err = 0;
- if (disable)
- return -1;
+ if (disable) {
+ err = -1;
+ goto out;
+ }
- if (pt_detect())
- return -1;
+ if (pt_detect()) {
+ err = -1;
+ goto out;
+ }
if (register_chrdev(major, name, &pt_fops)) {
printk("pt_init: unable to get major number %d\n", major);
for (unit = 0; unit < PT_UNITS; unit++)
if (pt[unit].present)
pi_release(pt[unit].pi);
- return -1;
+ err = -1;
+ goto out;
+ }
+ pt_class = class_simple_create(THIS_MODULE, "pt");
+ if (IS_ERR(pt_class)) {
+ err = PTR_ERR(pt_class);
+ goto out_chrdev;
}
devfs_mk_dir("pt");
for (unit = 0; unit < PT_UNITS; unit++)
if (pt[unit].present) {
- devfs_mk_cdev(MKDEV(major, unit),
+ class_simple_device_add(pt_class, MKDEV(major, unit),
+ NULL, "pt%d", unit);
+ err = devfs_mk_cdev(MKDEV(major, unit),
S_IFCHR | S_IRUSR | S_IWUSR,
"pt/%d", unit);
- devfs_mk_cdev(MKDEV(major, unit + 128),
+ if (err) {
+ class_simple_device_remove(MKDEV(major, unit));
+ goto out_class;
+ }
+ class_simple_device_add(pt_class, MKDEV(major, unit + 128),
+ NULL, "pt%dn", unit);
+ err = devfs_mk_cdev(MKDEV(major, unit + 128),
S_IFCHR | S_IRUSR | S_IWUSR,
"pt/%dn", unit);
+ if (err) {
+ class_simple_device_remove(MKDEV(major, unit + 128));
+ goto out_class;
+ }
}
- return 0;
+ goto out;
+
+out_class:
+ class_simple_destroy(pt_class);
+out_chrdev:
+ unregister_chrdev(major, "pt");
+out:
+ return err;
}
static void __exit pt_exit(void)
@@ -993,9 +1026,12 @@ static void __exit pt_exit(void)
int unit;
for (unit = 0; unit < PT_UNITS; unit++)
if (pt[unit].present) {
+ class_simple_device_remove(MKDEV(major, unit));
devfs_remove("pt/%d", unit);
+ class_simple_device_remove(MKDEV(major, unit + 128));
devfs_remove("pt/%dn", unit);
}
+ class_simple_destroy(pt_class);
devfs_remove("pt");
unregister_chrdev(major, name);
for (unit = 0; unit < PT_UNITS; unit++)
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index 043cff46fb74..d5c18535bbfa 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -99,6 +99,7 @@
#include <linux/slab.h>
#include <linux/major.h>
#include <linux/wait.h>
+#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -301,6 +302,9 @@ static int iindx;
static char rirqs[IP2_MAX_BOARDS];
static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0};
+/* for sysfs class support */
+static struct class_simple *ip2_class;
+
// Some functions to keep track of what irq's we have
static int __init
@@ -411,7 +415,9 @@ cleanup_module(void)
iiResetDelay( i2BoardPtrTable[i] );
/* free io addresses and Tibet */
release_region( ip2config.addr[i], 8 );
+ class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 4 * i));
devfs_remove("ip2/ipl%d", i);
+ class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
devfs_remove("ip2/stat%d", i);
}
/* Disable and remove interrupt handler. */
@@ -420,6 +426,7 @@ cleanup_module(void)
clear_requested_irq( ip2config.irq[i]);
}
}
+ class_simple_destroy(ip2_class);
devfs_remove("ip2");
if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) {
printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
@@ -494,7 +501,7 @@ int
ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
{
int i, j, box;
- int err;
+ int err = 0;
int status = 0;
static int loaded;
i2eBordStrPtr pB = NULL;
@@ -683,7 +690,14 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
/* Register the IPL driver. */
if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
- } else
+ } else {
+ /* create the sysfs class */
+ ip2_class = class_simple_create(THIS_MODULE, "ip2");
+ if (IS_ERR(ip2_class)) {
+ err = PTR_ERR(ip2_class);
+ goto out_chrdev;
+ }
+ }
/* Register the read_procmem thing */
if (!create_proc_info_entry("ip2mem",0,&proc_root,ip2_read_procmem)) {
printk(KERN_ERR "IP2: failed to register read_procmem\n");
@@ -700,13 +714,27 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
}
if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
- devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i),
+ class_simple_device_add(ip2_class, MKDEV(IP2_IPL_MAJOR,
+ 4 * i), NULL, "ipl%d", i);
+ err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i),
S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
"ip2/ipl%d", i);
+ if (err) {
+ class_simple_device_remove(MKDEV(IP2_IPL_MAJOR,
+ 4 * i));
+ goto out_class;
+ }
- devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
+ class_simple_device_add(ip2_class, MKDEV(IP2_IPL_MAJOR,
+ 4 * i + 1), NULL, "stat%d", i);
+ err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
"ip2/stat%d", i);
+ if (err) {
+ class_simple_device_remove(MKDEV(IP2_IPL_MAJOR,
+ 4 * i + 1));
+ goto out_class;
+ }
for ( box = 0; box < ABS_MAX_BOXES; ++box )
{
@@ -759,8 +787,14 @@ retry:
}
}
ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
-
- return 0;
+ goto out;
+
+out_class:
+ class_simple_destroy(ip2_class);
+out_chrdev:
+ unregister_chrdev(IP2_IPL_MAJOR, "ip2");
+out:
+ return err;
}
EXPORT_SYMBOL(ip2_loadmain);
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 525905c07435..56ae1f09db3a 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -59,6 +59,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
+#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/ioctl.h>
#include <linux/parport.h>
@@ -739,6 +740,8 @@ static unsigned int pp_poll (struct file * file, poll_table * wait)
return mask;
}
+static struct class_simple *ppdev_class;
+
static struct file_operations pp_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -750,23 +753,59 @@ static struct file_operations pp_fops = {
.release = pp_release,
};
+static void pp_attach(struct parport *port)
+{
+ class_simple_device_add(ppdev_class, MKDEV(PP_MAJOR, port->number),
+ NULL, "parport%d", port->number);
+}
+
+static void pp_detach(struct parport *port)
+{
+ class_simple_device_remove(MKDEV(PP_MAJOR, port->number));
+}
+
+static struct parport_driver pp_driver = {
+ .name = CHRDEV,
+ .attach = pp_attach,
+ .detach = pp_detach,
+};
+
static int __init ppdev_init (void)
{
- int i;
+ int i, err = 0;
if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
PP_MAJOR);
return -EIO;
}
+ ppdev_class = class_simple_create(THIS_MODULE, CHRDEV);
+ if (IS_ERR(ppdev_class)) {
+ err = PTR_ERR(ppdev_class);
+ goto out_chrdev;
+ }
devfs_mk_dir("parports");
for (i = 0; i < PARPORT_MAX; i++) {
devfs_mk_cdev(MKDEV(PP_MAJOR, i),
S_IFCHR | S_IRUGO | S_IWUGO, "parports/%d", i);
}
+ if (parport_register_driver(&pp_driver)) {
+ printk (KERN_WARNING CHRDEV ": unable to register with parport\n");
+ goto out_class;
+ }
printk (KERN_INFO PP_VERSION "\n");
- return 0;
+ goto out;
+
+out_class:
+ for (i = 0; i < PARPORT_MAX; i++)
+ devfs_remove("parports/%d", i);
+ devfs_remove("parports");
+ class_simple_destroy(ppdev_class);
+out_chrdev:
+ unregister_chrdev(PP_MAJOR, CHRDEV);
+out:
+ return err;
}
static void __exit ppdev_cleanup (void)
@@ -775,7 +814,9 @@ static void __exit ppdev_cleanup (void)
/* Clean up all parport stuff */
for (i = 0; i < PARPORT_MAX; i++)
devfs_remove("parports/%d", i);
+ parport_unregister_driver(&pp_driver);
devfs_remove("parports");
+ class_simple_destroy(ppdev_class);
unregister_chrdev (PP_MAJOR, CHRDEV);
}
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 3632e28648a5..8cbf15bb51ac 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -58,6 +58,7 @@
#include <asm/bitops.h>
#include <linux/devfs_fs_kernel.h> /* DevFs support */
#include <linux/parport.h> /* Our code depend on parport */
+#include <linux/device.h>
/*
* TI definitions
@@ -92,6 +93,8 @@ static int timeout = TIMAXTIME; /* timeout in tenth of seconds */
static unsigned int tp_count; /* tipar count */
static unsigned long opened; /* opened devices */
+static struct class_simple *tipar_class;
+
/* --- macros for parport access -------------------------------------- */
#define r_dtr(x) (parport_read_data(table[(x)].dev->port))
@@ -424,18 +427,26 @@ tipar_setup(char *str)
static int
tipar_register(int nr, struct parport *port)
{
+ int err = 0;
+
/* Register our module into parport */
table[nr].dev = parport_register_device(port, "tipar",
NULL, NULL, NULL, 0,
(void *) &table[nr]);
- if (table[nr].dev == NULL)
- return 1;
+ if (table[nr].dev == NULL) {
+ err = 1;
+ goto out;
+ }
+ class_simple_device_add(tipar_class, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr),
+ NULL, "par%d", nr);
/* Use devfs, tree: /dev/ticables/par/[0..2] */
- devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr),
+ err = devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr),
S_IFCHR | S_IRUGO | S_IWUGO,
"ticables/par/%d", nr);
+ if (err)
+ goto out_class;
/* Display informations */
printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name,
@@ -447,7 +458,14 @@ tipar_register(int nr, struct parport *port)
else
printk("tipar%d: link cable not found.\n", nr);
- return 0;
+ err = 0;
+ goto out;
+
+out_class:
+ class_simple_device_remove(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr));
+ class_simple_destroy(tipar_class);
+out:
+ return err;
}
static void
@@ -477,23 +495,38 @@ static struct parport_driver tipar_driver = {
int __init
tipar_init_module(void)
{
+ int err = 0;
+
printk("tipar: parallel link cable driver, version %s\n",
DRIVER_VERSION);
if (register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) {
printk("tipar: unable to get major %d\n", TIPAR_MAJOR);
- return -EIO;
+ err = -EIO;
+ goto out;
}
/* Use devfs with tree: /dev/ticables/par/[0..2] */
devfs_mk_dir("ticables/par");
+ tipar_class = class_simple_create(THIS_MODULE, "ticables");
+ if (IS_ERR(tipar_class)) {
+ err = PTR_ERR(tipar_class);
+ goto out_chrdev;
+ }
if (parport_register_driver(&tipar_driver)) {
printk("tipar: unable to register with parport\n");
- return -EIO;
+ err = -EIO;
+ goto out;
}
- return 0;
+ err = 0;
+ goto out;
+
+out_chrdev:
+ unregister_chrdev(TIPAR_MAJOR, "tipar");
+out:
+ return err;
}
void __exit
@@ -510,8 +543,10 @@ tipar_cleanup_module(void)
if (table[i].dev == NULL)
continue;
parport_unregister_device(table[i].dev);
+ class_simple_device_remove(MKDEV(TIPAR_MAJOR, i));
devfs_remove("ticables/par/%d", i);
}
+ class_simple_destroy(tipar_class);
devfs_remove("ticables/par");
printk("tipar: module unloaded !\n");
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 597bf5f04e6d..83575861bd21 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -34,4 +34,12 @@ 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 ca7745addd5c..694725046da7 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -3,3 +3,4 @@
#
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
new file mode 100644
index 000000000000..583ab0939c08
--- /dev/null
+++ b/drivers/firmware/smbios.c
@@ -0,0 +1,248 @@
+/*
+ * 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
new file mode 100644
index 000000000000..7d56a0a2f4cf
--- /dev/null
+++ b/drivers/firmware/smbios.h
@@ -0,0 +1,53 @@
+/*
+ * 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/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index f100c194be08..5916de82fbe8 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -10,7 +10,7 @@
*
* To do:
*
- * - /proc/adb to list the devices and infos
+ * - /sys/bus/adb to list the devices and infos
* - more /dev/adb to allow userland to receive the
* flow of auto-polling datas from a given device.
* - move bus probe to a kernel thread
@@ -23,7 +23,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
@@ -36,6 +35,7 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
+#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#ifdef CONFIG_PPC
@@ -75,6 +75,8 @@ static struct adb_driver *adb_driver_list[] = {
NULL
};
+static struct class_simple *adb_dev_class;
+
struct adb_driver *adb_controller;
struct notifier_block *adb_client_list = NULL;
static int adb_got_sleep;
@@ -883,6 +885,7 @@ out:
}
static struct file_operations adb_fops = {
+ .owner = THIS_MODULE,
.llseek = no_llseek,
.read = adb_read,
.write = adb_write,
@@ -893,9 +896,13 @@ static struct file_operations adb_fops = {
static void
adbdev_init(void)
{
- if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
+ if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) {
printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
- else
- devfs_mk_cdev(MKDEV(ADB_MAJOR, 0),
- S_IFCHR | S_IRUSR | S_IWUSR, "adb");
+ return;
+ }
+ adb_dev_class = class_simple_create(THIS_MODULE, "adb");
+ if (IS_ERR(adb_dev_class)) {
+ return;
+ }
+ class_simple_device_add(adb_dev_class, MKDEV(ADB_MAJOR, 0), NULL, "adb");
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 9fb3e65244f5..fdd0be1a8d5a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -6,7 +6,7 @@ menu "Misc devices"
config IBM_ASM
tristate "Device driver for IBM RSA service processor"
- depends on X86
+ depends on X86 && EXPERIMENTAL
default n
---help---
This option enables device driver support for in-band access to the
@@ -20,6 +20,12 @@ config IBM_ASM
this feature serial driver support (CONFIG_SERIAL_8250) must be
enabled.
+ WARNING: This software may not be supported or function
+ correctly on your IBM server. Please consult the IBM ServerProven
+ website http://www.pc.ibm/ww/eserver/xseries/serverproven for
+ information on the specific driver level and support statement
+ for your IBM server.
+
If unsure, say N.
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c
index 190349fbb36e..ee29ced8784b 100644
--- a/drivers/misc/ibmasm/module.c
+++ b/drivers/misc/ibmasm/module.c
@@ -126,6 +126,13 @@ static int __init ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_
ibmasm_register_uart(sp);
+ dev_printk(KERN_DEBUG, &pdev->dev, "WARNING: This software may not be supported or function\n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "correctly on your IBM server. Please consult the IBM\n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "ServerProven website\n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "http://www.pc.ibm.com/ww/eserver/xseries/serverproven\n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "for information on the specific driver level and support\n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "statement for your IBM server.\n");
+
return 0;
error_send_message:
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 00d0b751e827..a4d0452c3c97 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -93,6 +93,7 @@
#include <linux/netdevice.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
+#include <linux/device.h>
#undef COSA_SLOW_IO /* for testing purposes only */
#undef REALLY_SLOW_IO
@@ -233,6 +234,9 @@ static int dma[MAX_CARDS+1];
/* IRQ can be safely autoprobed */
static int irq[MAX_CARDS+1] = { -1, -1, -1, -1, -1, -1, 0, };
+/* for class stuff*/
+static struct class_simple *cosa_class;
+
#ifdef MODULE
MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
MODULE_PARM_DESC(io, "The I/O bases of the COSA or SRP cards");
@@ -359,7 +363,7 @@ static void debug_status_out(struct cosa_data *cosa, int status);
static int __init cosa_init(void)
{
- int i;
+ int i, err = 0;
printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");
#ifdef CONFIG_SMP
@@ -369,12 +373,14 @@ static int __init cosa_init(void)
if (register_chrdev(cosa_major, "cosa", &cosa_fops)) {
printk(KERN_WARNING "cosa: unable to get major %d\n",
cosa_major);
- return -EIO;
+ err = -EIO;
+ goto out;
}
} else {
if (!(cosa_major=register_chrdev(0, "cosa", &cosa_fops))) {
printk(KERN_WARNING "cosa: unable to register chardev\n");
- return -EIO;
+ err = -EIO;
+ goto out;
}
}
for (i=0; i<MAX_CARDS; i++)
@@ -384,15 +390,33 @@ static int __init cosa_init(void)
if (!nr_cards) {
printk(KERN_WARNING "cosa: no devices found.\n");
unregister_chrdev(cosa_major, "cosa");
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
devfs_mk_dir("cosa");
+ cosa_class = class_simple_create(THIS_MODULE, "cosa");
+ if (IS_ERR(cosa_class)) {
+ err = PTR_ERR(cosa_class);
+ goto out_chrdev;
+ }
for (i=0; i<nr_cards; i++) {
- devfs_mk_cdev(MKDEV(cosa_major, i),
+ class_simple_device_add(cosa_class, MKDEV(cosa_major, i),
+ NULL, "cosa%d", i);
+ err = devfs_mk_cdev(MKDEV(cosa_major, i),
S_IFCHR|S_IRUSR|S_IWUSR,
"cosa/%d", i);
+ if (err) {
+ class_simple_device_remove(MKDEV(cosa_major, i));
+ goto out_chrdev;
+ }
}
- return 0;
+ err = 0;
+ goto out;
+
+out_chrdev:
+ unregister_chrdev(cosa_major, "cosa");
+out:
+ return err;
}
module_init(cosa_init);
@@ -402,8 +426,11 @@ static void __exit cosa_exit(void)
int i;
printk(KERN_INFO "Unloading the cosa module\n");
- for (i=0; i<nr_cards; i++)
+ for (i=0; i<nr_cards; i++) {
+ class_simple_device_remove(MKDEV(cosa_major, i));
devfs_remove("cosa/%d", i);
+ }
+ class_simple_destroy(cosa_class);
devfs_remove("cosa");
for (cosa=cosa_cards; nr_cards--; cosa++) {
/* Clean up the per-channel data */
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 6b4c28844f3f..d455725102fb 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -94,7 +94,7 @@ static ssize_t write(struct file * file, const char __user * userbuf,
static int open(struct inode * inode, struct file * file)
{
- struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata);
+ struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
struct bin_attribute * attr = file->f_dentry->d_fsdata;
int error = -EINVAL;
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index add2045e8c25..91b06a20cd76 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -154,24 +154,33 @@ restart:
dput(dentry);
}
-void sysfs_rename_dir(struct kobject * kobj, const char *new_name)
+int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
{
+ int error = 0;
struct dentry * new_dentry, * parent;
if (!strcmp(kobject_name(kobj), new_name))
- return;
+ return -EINVAL;
if (!kobj->parent)
- return;
+ return -EINVAL;
parent = kobj->parent->dentry;
down(&parent->d_inode->i_sem);
new_dentry = sysfs_get_dentry(parent, new_name);
- d_move(kobj->dentry, new_dentry);
- kobject_set_name(kobj,new_name);
+ if (!IS_ERR(new_dentry)) {
+ if (!new_dentry->d_inode) {
+ error = kobject_set_name(kobj,new_name);
+ if (!error)
+ d_move(kobj->dentry, new_dentry);
+ }
+ dput(new_dentry);
+ }
up(&parent->d_inode->i_sem);
+
+ return error;
}
EXPORT_SYMBOL(sysfs_create_dir);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index cb1f3d9c7bf7..47c98d0224ef 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -238,7 +238,7 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t
static int check_perm(struct inode * inode, struct file * file)
{
- struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata);
+ struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
struct attribute * attr = file->f_dentry->d_fsdata;
struct sysfs_buffer * buffer;
struct sysfs_ops * ops = NULL;
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 96e390a7b99f..5976cc1aede0 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -11,3 +11,16 @@ 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 *);
+
+
+static inline struct kobject *sysfs_get_kobject(struct dentry *dentry)
+{
+ struct kobject * kobj = NULL;
+
+ spin_lock(&dentry->d_lock);
+ if (!d_unhashed(dentry))
+ kobj = kobject_get(dentry->d_fsdata);
+ spin_unlock(&dentry->d_lock);
+
+ return kobj;
+}
diff --git a/include/linux/device.h b/include/linux/device.h
index 9bc07b556eea..bd05cdfb326e 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -400,7 +400,7 @@ extern void firmware_unregister(struct subsystem *);
/* debugging and troubleshooting/diagnostic helpers. */
#define dev_printk(level, dev, format, arg...) \
- printk(level "%s %s: " format , (dev)->driver->name , (dev)->bus_id , ## arg)
+ printk(level "%s %s: " format , (dev)->driver ? (dev)->driver->name : "" , (dev)->bus_id , ## arg)
#ifdef DEBUG
#define dev_dbg(dev, format, arg...) \
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index f32f39b4cce6..6360d225884c 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -48,7 +48,7 @@ extern void kobject_cleanup(struct kobject *);
extern int kobject_add(struct kobject *);
extern void kobject_del(struct kobject *);
-extern void kobject_rename(struct kobject *, char *new_name);
+extern int kobject_rename(struct kobject *, char *new_name);
extern int kobject_register(struct kobject *);
extern void kobject_unregister(struct kobject *);
diff --git a/include/linux/module.h b/include/linux/module.h
index 0a86652fb1cb..9a3eb2f1f95d 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -16,6 +16,8 @@
#include <linux/kmod.h>
#include <linux/elf.h>
#include <linux/stringify.h>
+#include <linux/kobject.h>
+#include <linux/moduleparam.h>
#include <asm/local.h>
#include <asm/module.h>
@@ -207,6 +209,23 @@ enum module_state
MODULE_STATE_GOING,
};
+/* sysfs stuff */
+struct module_attribute
+{
+ struct attribute attr;
+ struct kernel_param *param;
+};
+
+struct module_kobject
+{
+ /* Everyone should have one of these. */
+ struct kobject kobj;
+
+ /* We always have refcnt, we may have others from module_param(). */
+ unsigned int num_attributes;
+ struct module_attribute attr[0];
+};
+
struct module
{
enum module_state state;
@@ -217,6 +236,9 @@ struct module
/* Unique handle for this module */
char name[MODULE_NAME_LEN];
+ /* Sysfs stuff. */
+ struct module_kobject *mkobj;
+
/* Exported symbols */
const struct kernel_symbol *syms;
unsigned int num_syms;
@@ -267,6 +289,9 @@ struct module
/* Destruction function. */
void (*exit)(void);
+
+ /* Fake kernel param for refcnt. */
+ struct kernel_param refcnt_param;
#endif
#ifdef CONFIG_KALLSYMS
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index e9d6a16d3fef..f63de16cdf54 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -50,7 +50,7 @@ struct kparam_array
not there, read bits mean it's readable, write bits mean it's
writable. */
#define __module_param_call(prefix, name, set, get, arg, perm) \
- static char __param_str_##name[] __initdata = prefix #name; \
+ static char __param_str_##name[] = prefix #name; \
static struct kernel_param const __param_##name \
__attribute_used__ \
__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
@@ -71,7 +71,7 @@ struct kparam_array
/* Actually copy string: maxlen param is usually sizeof(string). */
#define module_param_string(name, string, len, perm) \
- static struct kparam_string __param_string_##name __initdata \
+ static struct kparam_string __param_string_##name \
= { len, string }; \
module_param_call(name, param_set_copystring, param_get_charp, \
&__param_string_##name, perm)
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index de2083939b74..31f1c8b4428d 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -44,7 +44,7 @@ sysfs_create_dir(struct kobject *);
extern void
sysfs_remove_dir(struct kobject *);
-extern void
+extern int
sysfs_rename_dir(struct kobject *, const char *new_name);
extern int
diff --git a/kernel/module.c b/kernel/module.c
index 2ddd9697afcb..1781faa9a132 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -379,6 +379,22 @@ static inline void percpu_modcopy(void *pcpudst, const void *src,
}
#endif /* CONFIG_SMP */
+static int add_attribute(struct module *mod, struct kernel_param *kp)
+{
+ struct module_attribute *a;
+ int retval;
+
+ a = &mod->mkobj->attr[mod->mkobj->num_attributes];
+ a->attr.name = (char *)kp->name;
+ a->attr.owner = mod;
+ a->attr.mode = kp->perm;
+ a->param = kp;
+ retval = sysfs_create_file(&mod->mkobj->kobj, &a->attr);
+ if (!retval)
+ mod->mkobj->num_attributes++;
+ return retval;
+}
+
#ifdef CONFIG_MODULE_UNLOAD
/* Init the unload section of the module. */
static void module_unload_init(struct module *mod)
@@ -663,6 +679,23 @@ void symbol_put_addr(void *addr)
}
EXPORT_SYMBOL_GPL(symbol_put_addr);
+static int refcnt_get_fn(char *buffer, struct kernel_param *kp)
+{
+ struct module *mod = container_of(kp, struct module, refcnt_param);
+
+ /* sysfs holds one reference. */
+ return sprintf(buffer, "%u", module_refcount(mod)-1);
+}
+
+static inline int sysfs_unload_setup(struct module *mod)
+{
+ mod->refcnt_param.name = "refcnt";
+ mod->refcnt_param.perm = 0444;
+ mod->refcnt_param.get = refcnt_get_fn;
+
+ return add_attribute(mod, &mod->refcnt_param);
+}
+
#else /* !CONFIG_MODULE_UNLOAD */
static void print_unload_info(struct seq_file *m, struct module *mod)
{
@@ -689,6 +722,10 @@ sys_delete_module(const char *name_user, unsigned int flags)
return -ENOSYS;
}
+static inline int sysfs_unload_setup(struct module *mod)
+{
+ return 0;
+}
#endif /* CONFIG_MODULE_UNLOAD */
#ifdef CONFIG_OBSOLETE_MODPARM
@@ -944,6 +981,116 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
return ret;
}
+#define to_module_attr(n) container_of(n, struct module_attribute, attr);
+
+static ssize_t module_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ int count;
+ struct module_attribute *attribute = to_module_attr(attr);
+
+ if (!attribute->param->get)
+ return -EPERM;
+
+ count = attribute->param->get(buf, attribute->param);
+ if (count > 0) {
+ strcat(buf, "\n");
+ ++count;
+ }
+ return count;
+}
+
+/* sysfs always hands a nul-terminated string in buf. We rely on that. */
+static ssize_t module_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t len)
+{
+ int err;
+ struct module_attribute *attribute = to_module_attr(attr);
+
+ if (!attribute->param->set)
+ return -EPERM;
+
+ err = attribute->param->set(buf, attribute->param);
+ if (!err)
+ return len;
+ return err;
+}
+
+static struct sysfs_ops module_sysfs_ops = {
+ .show = module_attr_show,
+ .store = module_attr_store,
+};
+
+static void module_kobj_release(struct kobject *kobj)
+{
+ kfree(container_of(kobj, struct module_kobject, kobj));
+}
+
+static struct kobj_type module_ktype = {
+ .sysfs_ops = &module_sysfs_ops,
+ .release = &module_kobj_release,
+};
+static decl_subsys(module, &module_ktype, NULL);
+
+static int mod_sysfs_setup(struct module *mod,
+ struct kernel_param *kparam,
+ unsigned int num_params)
+{
+ unsigned int i;
+ int err;
+
+ /* We overallocate: not every param is in sysfs, and maybe no refcnt */
+ mod->mkobj = kmalloc(sizeof(*mod->mkobj)
+ + sizeof(mod->mkobj->attr[0]) * (num_params+1),
+ GFP_KERNEL);
+ if (!mod->mkobj)
+ return -ENOMEM;
+
+ memset(&mod->mkobj->kobj, 0, sizeof(mod->mkobj->kobj));
+ err = kobject_set_name(&mod->mkobj->kobj, mod->name);
+ if (err)
+ goto out;
+ kobj_set_kset_s(mod->mkobj, module_subsys);
+ err = kobject_register(&mod->mkobj->kobj);
+ if (err)
+ goto out;
+
+ mod->mkobj->num_attributes = 0;
+
+ for (i = 0; i < num_params; i++) {
+ if (kparam[i].perm) {
+ err = add_attribute(mod, &kparam[i]);
+ if (err)
+ goto out_unreg;
+ }
+ }
+ err = sysfs_unload_setup(mod);
+ if (err)
+ goto out_unreg;
+ return 0;
+
+out_unreg:
+ for (i = 0; i < mod->mkobj->num_attributes; i++)
+ sysfs_remove_file(&mod->mkobj->kobj,&mod->mkobj->attr[i].attr);
+ /* Calls module_kobj_release */
+ kobject_unregister(&mod->mkobj->kobj);
+ return err;
+out:
+ kfree(mod->mkobj);
+ return err;
+}
+
+static void mod_kobject_remove(struct module *mod)
+{
+ unsigned int i;
+ for (i = 0; i < mod->mkobj->num_attributes; i++)
+ sysfs_remove_file(&mod->mkobj->kobj,&mod->mkobj->attr[i].attr);
+ /* Calls module_kobj_release */
+ kobject_unregister(&mod->mkobj->kobj);
+}
+
/* Free a module, remove from lists, etc (must hold module mutex). */
static void free_module(struct module *mod)
{
@@ -952,6 +1099,8 @@ static void free_module(struct module *mod)
list_del(&mod->list);
spin_unlock_irq(&modlist_lock);
+ mod_kobject_remove(mod);
+
/* Arch-specific cleanup. */
module_arch_cleanup(mod);
@@ -1556,6 +1705,11 @@ static struct module *load_module(void __user *umod,
/ sizeof(struct kernel_param),
NULL);
}
+ err = mod_sysfs_setup(mod,
+ (struct kernel_param *)
+ sechdrs[setupindex].sh_addr,
+ sechdrs[setupindex].sh_size
+ / sizeof(struct kernel_param));
if (err < 0)
goto arch_cleanup;
@@ -1891,3 +2045,9 @@ struct module *module_text_address(unsigned long addr)
void struct_module(struct module *mod) { return; }
EXPORT_SYMBOL(struct_module);
#endif
+
+static int __init modules_init(void)
+{
+ return subsystem_register(&module_subsys);
+}
+__initcall(modules_init);
diff --git a/kernel/params.c b/kernel/params.c
index 59667bce9ce0..5f38ee74a637 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -161,7 +161,7 @@ int parse_args(const char *name,
\
if (!val) return -EINVAL; \
l = strtolfn(val, &endp, 0); \
- if (endp == val || *endp || ((type)l != l)) \
+ if (endp == val || ((type)l != l)) \
return -EINVAL; \
*((type *)kp->arg) = l; \
return 0; \
diff --git a/lib/kobject.c b/lib/kobject.c
index 5e8d1ed70716..5c2ade5739be 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -385,13 +385,17 @@ EXPORT_SYMBOL(kobject_set_name);
* @new_name: object's new name
*/
-void kobject_rename(struct kobject * kobj, char *new_name)
+int kobject_rename(struct kobject * kobj, char *new_name)
{
+ int error = 0;
+
kobj = kobject_get(kobj);
if (!kobj)
- return;
- sysfs_rename_dir(kobj, new_name);
+ return -EINVAL;
+ error = sysfs_rename_dir(kobj, new_name);
kobject_put(kobj);
+
+ return error;
}
/**
diff --git a/net/core/dev.c b/net/core/dev.c
index 02a254cd369c..0540421da57b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -792,6 +792,8 @@ int dev_alloc_name(struct net_device *dev, const char *name)
*/
int dev_change_name(struct net_device *dev, char *newname)
{
+ int err = 0;
+
ASSERT_RTNL();
if (dev->flags & IFF_UP)
@@ -801,7 +803,7 @@ int dev_change_name(struct net_device *dev, char *newname)
return -EINVAL;
if (strchr(newname, '%')) {
- int err = dev_alloc_name(dev, newname);
+ err = dev_alloc_name(dev, newname);
if (err < 0)
return err;
strcpy(newname, dev->name);
@@ -811,12 +813,14 @@ int dev_change_name(struct net_device *dev, char *newname)
else
strlcpy(dev->name, newname, IFNAMSIZ);
- hlist_del(&dev->name_hlist);
- hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
+ err = class_device_rename(&dev->class_dev, dev->name);
+ if (!err) {
+ hlist_del(&dev->name_hlist);
+ hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
+ notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+ }
- class_device_rename(&dev->class_dev, dev->name);
- notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
- return 0;
+ return err;
}
/**