Commit 3004c70f authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleed-2.6

into kroah.com:/home/greg/linux/BK/driver-2.6
parents 141baf80 51c0c34c
...@@ -451,7 +451,11 @@ int bus_add_driver(struct device_driver * drv) ...@@ -451,7 +451,11 @@ int bus_add_driver(struct device_driver * drv)
if (bus) { if (bus) {
pr_debug("bus %s: add driver %s\n",bus->name,drv->name); 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; drv->kobj.kset = &bus->drivers;
if ((error = kobject_register(&drv->kobj))) { if ((error = kobject_register(&drv->kobj))) {
put_bus(bus); put_bus(bus);
...@@ -555,21 +559,39 @@ struct bus_type * find_bus(char * name) ...@@ -555,21 +559,39 @@ struct bus_type * find_bus(char * name)
*/ */
int bus_register(struct bus_type * bus) 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); 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"); kobject_set_name(&bus->devices.kobj, "devices");
bus->devices.subsys = &bus->subsys; 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"); kobject_set_name(&bus->drivers.kobj, "drivers");
bus->drivers.subsys = &bus->subsys; bus->drivers.subsys = &bus->subsys;
bus->drivers.ktype = &ktype_driver; 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); pr_debug("bus type '%s' registered\n",bus->name);
return 0; return 0;
bus_drivers_fail:
kset_unregister(&bus->devices);
bus_devices_fail:
subsystem_unregister(&bus->subsys);
out:
return retval;
} }
......
...@@ -361,6 +361,8 @@ void class_device_unregister(struct class_device *class_dev) ...@@ -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 class_device_rename(struct class_device *class_dev, char *new_name)
{ {
int error = 0;
class_dev = class_device_get(class_dev); class_dev = class_device_get(class_dev);
if (!class_dev) if (!class_dev)
return -EINVAL; return -EINVAL;
...@@ -370,11 +372,11 @@ int class_device_rename(struct class_device *class_dev, char *new_name) ...@@ -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); 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); class_device_put(class_dev);
return 0; return error;
} }
struct class_device * class_device_get(struct class_device *class_dev) struct class_device * class_device_get(struct class_device *class_dev)
......
...@@ -138,6 +138,13 @@ struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, ...@@ -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 kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL);
struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL); struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL);
int i; int i;
if ((p == NULL) || (base == NULL)) {
kfree(p);
kfree(base);
return NULL;
}
memset(base, 0, sizeof(struct probe)); memset(base, 0, sizeof(struct probe));
base->dev = 1; base->dev = 1;
base->range = ~0; base->range = ~0;
......
...@@ -57,8 +57,9 @@ void platform_device_unregister(struct platform_device * pdev) ...@@ -57,8 +57,9 @@ void platform_device_unregister(struct platform_device * pdev)
* type of device, like "pci" or "floppy", and <instance> is the * type of device, like "pci" or "floppy", and <instance> is the
* enumerated instance of the device, like '0' or '42'. * enumerated instance of the device, like '0' or '42'.
* Driver IDs are simply "<name>". * Driver IDs are simply "<name>".
* So, extract the <name> from the device, and compare it against * So, extract the <name> from the platform_device structure,
* the name of the driver. Return whether they match or not. * 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) static int platform_match(struct device * dev, struct device_driver * drv)
......
...@@ -180,8 +180,11 @@ int sysdev_register(struct sys_device * sysdev) ...@@ -180,8 +180,11 @@ int sysdev_register(struct sys_device * sysdev)
/* But make sure we point to the right type for sysfs translation */ /* But make sure we point to the right type for sysfs translation */
sysdev->kobj.ktype = &ktype_sysdev; 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); kobject_name(&cls->kset.kobj),sysdev->id);
if (error)
return error;
pr_debug("Registering sys device '%s'\n",kobject_name(&sysdev->kobj)); pr_debug("Registering sys device '%s'\n",kobject_name(&sysdev->kobj));
/* Register the object */ /* Register the object */
......
...@@ -161,6 +161,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; ...@@ -161,6 +161,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mtio.h> #include <linux/mtio.h>
#include <linux/pg.h> #include <linux/pg.h>
#include <linux/device.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -240,6 +241,8 @@ static int pg_identify(struct pg *dev, int log); ...@@ -240,6 +241,8 @@ static int pg_identify(struct pg *dev, int log);
static char pg_scratch[512]; /* scratch block buffer */ static char pg_scratch[512]; /* scratch block buffer */
static struct class_simple *pg_class;
/* kernel glue structures */ /* kernel glue structures */
static struct file_operations pg_fops = { 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) ...@@ -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) static int __init pg_init(void)
{ {
int unit; int unit, err = 0;
if (disable) if (disable){
return -1; err = -1;
goto out;
}
pg_init_units(); pg_init_units();
if (pg_detect()) if (pg_detect()) {
return -1; err = -1;
goto out;
}
if (register_chrdev(major, name, &pg_fops)) { if (register_chrdev(major, name, &pg_fops)) {
printk("pg_init: unable to get major number %d\n", major); printk("pg_init: unable to get major number %d\n", major);
...@@ -675,18 +682,37 @@ static int __init pg_init(void) ...@@ -675,18 +682,37 @@ static int __init pg_init(void)
if (dev->present) if (dev->present)
pi_release(dev->pi); 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"); devfs_mk_dir("pg");
for (unit = 0; unit < PG_UNITS; unit++) { for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit]; struct pg *dev = &devices[unit];
if (dev->present) { 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", S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u",
unit); 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) static void __exit pg_exit(void)
...@@ -695,10 +721,12 @@ static void __exit pg_exit(void) ...@@ -695,10 +721,12 @@ static void __exit pg_exit(void)
for (unit = 0; unit < PG_UNITS; unit++) { for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit]; struct pg *dev = &devices[unit];
if (dev->present) if (dev->present) {
class_simple_device_remove(MKDEV(major, unit));
devfs_remove("pg/%u", unit); devfs_remove("pg/%u", unit);
} }
}
class_simple_destroy(pg_class);
devfs_remove("pg"); devfs_remove("pg");
unregister_chrdev(major, name); unregister_chrdev(major, name);
......
...@@ -145,6 +145,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; ...@@ -145,6 +145,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mtio.h> #include <linux/mtio.h>
#include <linux/device.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -260,6 +261,9 @@ static struct file_operations pt_fops = { ...@@ -260,6 +261,9 @@ static struct file_operations pt_fops = {
.release = pt_release, .release = pt_release,
}; };
/* sysfs class support */
static struct class_simple *pt_class;
static inline int status_reg(struct pi_adapter *pi) static inline int status_reg(struct pi_adapter *pi)
{ {
return pi_read_regr(pi, 1, 6); 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 ...@@ -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) static int __init pt_init(void)
{ {
int unit; int unit, err = 0;
if (disable) if (disable) {
return -1; err = -1;
goto out;
}
if (pt_detect()) if (pt_detect()) {
return -1; err = -1;
goto out;
}
if (register_chrdev(major, name, &pt_fops)) { if (register_chrdev(major, name, &pt_fops)) {
printk("pt_init: unable to get major number %d\n", major); printk("pt_init: unable to get major number %d\n", major);
for (unit = 0; unit < PT_UNITS; unit++) for (unit = 0; unit < PT_UNITS; unit++)
if (pt[unit].present) if (pt[unit].present)
pi_release(pt[unit].pi); 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"); devfs_mk_dir("pt");
for (unit = 0; unit < PT_UNITS; unit++) for (unit = 0; unit < PT_UNITS; unit++)
if (pt[unit].present) { 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, S_IFCHR | S_IRUSR | S_IWUSR,
"pt/%d", unit); "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, S_IFCHR | S_IRUSR | S_IWUSR,
"pt/%dn", unit); "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) static void __exit pt_exit(void)
...@@ -993,9 +1026,12 @@ static void __exit pt_exit(void) ...@@ -993,9 +1026,12 @@ static void __exit pt_exit(void)
int unit; int unit;
for (unit = 0; unit < PT_UNITS; unit++) for (unit = 0; unit < PT_UNITS; unit++)
if (pt[unit].present) { if (pt[unit].present) {
class_simple_device_remove(MKDEV(major, unit));
devfs_remove("pt/%d", unit); devfs_remove("pt/%d", unit);
class_simple_device_remove(MKDEV(major, unit + 128));
devfs_remove("pt/%dn", unit); devfs_remove("pt/%dn", unit);
} }
class_simple_destroy(pt_class);
devfs_remove("pt"); devfs_remove("pt");
unregister_chrdev(major, name); unregister_chrdev(major, name);
for (unit = 0; unit < PT_UNITS; unit++) for (unit = 0; unit < PT_UNITS; unit++)
......
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/major.h> #include <linux/major.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/device.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
...@@ -301,6 +302,9 @@ static int iindx; ...@@ -301,6 +302,9 @@ static int iindx;
static char rirqs[IP2_MAX_BOARDS]; static char rirqs[IP2_MAX_BOARDS];
static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0}; 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 // Some functions to keep track of what irq's we have
static int __init static int __init
...@@ -411,7 +415,9 @@ cleanup_module(void) ...@@ -411,7 +415,9 @@ cleanup_module(void)
iiResetDelay( i2BoardPtrTable[i] ); iiResetDelay( i2BoardPtrTable[i] );
/* free io addresses and Tibet */ /* free io addresses and Tibet */
release_region( ip2config.addr[i], 8 ); release_region( ip2config.addr[i], 8 );
class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 4 * i));
devfs_remove("ip2/ipl%d", i); devfs_remove("ip2/ipl%d", i);
class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
devfs_remove("ip2/stat%d", i); devfs_remove("ip2/stat%d", i);
} }
/* Disable and remove interrupt handler. */ /* Disable and remove interrupt handler. */
...@@ -420,6 +426,7 @@ cleanup_module(void) ...@@ -420,6 +426,7 @@ cleanup_module(void)
clear_requested_irq( ip2config.irq[i]); clear_requested_irq( ip2config.irq[i]);
} }
} }
class_simple_destroy(ip2_class);
devfs_remove("ip2"); devfs_remove("ip2");
if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) { if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) {
printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
...@@ -494,7 +501,7 @@ int ...@@ -494,7 +501,7 @@ int
ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
{ {
int i, j, box; int i, j, box;
int err; int err = 0;
int status = 0; int status = 0;
static int loaded; static int loaded;
i2eBordStrPtr pB = NULL; i2eBordStrPtr pB = NULL;
...@@ -683,7 +690,14 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) ...@@ -683,7 +690,14 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
/* Register the IPL driver. */ /* Register the IPL driver. */
if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) { if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err ); 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 */ /* Register the read_procmem thing */
if (!create_proc_info_entry("ip2mem",0,&proc_root,ip2_read_procmem)) { if (!create_proc_info_entry("ip2mem",0,&proc_root,ip2_read_procmem)) {
printk(KERN_ERR "IP2: failed to register read_procmem\n"); 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) ...@@ -700,13 +714,27 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
} }
if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { 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, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
"ip2/ipl%d", i); "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, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
"ip2/stat%d", i); "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 ) for ( box = 0; box < ABS_MAX_BOXES; ++box )
{ {
...@@ -759,8 +787,14 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) ...@@ -759,8 +787,14 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
} }
} }
ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 ); ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
goto out;
return 0;
out_class:
class_simple_destroy(ip2_class);
out_chrdev:
unregister_chrdev(IP2_IPL_MAJOR, "ip2");
out:
return err;
} }
EXPORT_SYMBOL(ip2_loadmain); EXPORT_SYMBOL(ip2_loadmain);
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/parport.h> #include <linux/parport.h>
...@@ -739,6 +740,8 @@ static unsigned int pp_poll (struct file * file, poll_table * wait) ...@@ -739,6 +740,8 @@ static unsigned int pp_poll (struct file * file, poll_table * wait)
return mask; return mask;
} }
static struct class_simple *ppdev_class;
static struct file_operations pp_fops = { static struct file_operations pp_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
...@@ -750,23 +753,59 @@ static struct file_operations pp_fops = { ...@@ -750,23 +753,59 @@ static struct file_operations pp_fops = {
.release = pp_release, .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) static int __init ppdev_init (void)
{ {
int i; int i, err = 0;
if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) { if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
printk (KERN_WARNING CHRDEV ": unable to get major %d\n", printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
PP_MAJOR); PP_MAJOR);
return -EIO; 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"); devfs_mk_dir("parports");
for (i = 0; i < PARPORT_MAX; i++) { for (i = 0; i < PARPORT_MAX; i++) {
devfs_mk_cdev(MKDEV(PP_MAJOR, i), devfs_mk_cdev(MKDEV(PP_MAJOR, i),
S_IFCHR | S_IRUGO | S_IWUGO, "parports/%d", 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"); 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) static void __exit ppdev_cleanup (void)
...@@ -775,7 +814,9 @@ static void __exit ppdev_cleanup (void) ...@@ -775,7 +814,9 @@ static void __exit ppdev_cleanup (void)
/* Clean up all parport stuff */ /* Clean up all parport stuff */
for (i = 0; i < PARPORT_MAX; i++) for (i = 0; i < PARPORT_MAX; i++)
devfs_remove("parports/%d", i); devfs_remove("parports/%d", i);
parport_unregister_driver(&pp_driver);
devfs_remove("parports"); devfs_remove("parports");
class_simple_destroy(ppdev_class);
unregister_chrdev (PP_MAJOR, CHRDEV); unregister_chrdev (PP_MAJOR, CHRDEV);
} }
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include <asm/bitops.h> #include <asm/bitops.h>
#include <linux/devfs_fs_kernel.h> /* DevFs support */ #include <linux/devfs_fs_kernel.h> /* DevFs support */
#include <linux/parport.h> /* Our code depend on parport */ #include <linux/parport.h> /* Our code depend on parport */
#include <linux/device.h>
/* /*
* TI definitions * TI definitions
...@@ -92,6 +93,8 @@ static int timeout = TIMAXTIME; /* timeout in tenth of seconds */ ...@@ -92,6 +93,8 @@ static int timeout = TIMAXTIME; /* timeout in tenth of seconds */
static unsigned int tp_count; /* tipar count */ static unsigned int tp_count; /* tipar count */
static unsigned long opened; /* opened devices */ static unsigned long opened; /* opened devices */
static struct class_simple *tipar_class;
/* --- macros for parport access -------------------------------------- */ /* --- macros for parport access -------------------------------------- */
#define r_dtr(x) (parport_read_data(table[(x)].dev->port)) #define r_dtr(x) (parport_read_data(table[(x)].dev->port))
...@@ -424,18 +427,26 @@ tipar_setup(char *str) ...@@ -424,18 +427,26 @@ tipar_setup(char *str)
static int static int
tipar_register(int nr, struct parport *port) tipar_register(int nr, struct parport *port)
{ {
int err = 0;
/* Register our module into parport */ /* Register our module into parport */
table[nr].dev = parport_register_device(port, "tipar", table[nr].dev = parport_register_device(port, "tipar",
NULL, NULL, NULL, 0, NULL, NULL, NULL, 0,
(void *) &table[nr]); (void *) &table[nr]);
if (table[nr].dev == NULL) if (table[nr].dev == NULL) {
return 1; 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] */ /* 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, S_IFCHR | S_IRUGO | S_IWUGO,
"ticables/par/%d", nr); "ticables/par/%d", nr);
if (err)
goto out_class;
/* Display informations */ /* Display informations */
printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name, printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name,
...@@ -447,7 +458,14 @@ tipar_register(int nr, struct parport *port) ...@@ -447,7 +458,14 @@ tipar_register(int nr, struct parport *port)
else else
printk("tipar%d: link cable not found.\n", nr); 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 static void
...@@ -477,23 +495,38 @@ static struct parport_driver tipar_driver = { ...@@ -477,23 +495,38 @@ static struct parport_driver tipar_driver = {
int __init int __init
tipar_init_module(void) tipar_init_module(void)
{ {
int err = 0;
printk("tipar: parallel link cable driver, version %s\n", printk("tipar: parallel link cable driver, version %s\n",
DRIVER_VERSION); DRIVER_VERSION);
if (register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) { if (register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) {
printk("tipar: unable to get major %d\n", TIPAR_MAJOR); 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] */ /* Use devfs with tree: /dev/ticables/par/[0..2] */
devfs_mk_dir("ticables/par"); 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)) { if (parport_register_driver(&tipar_driver)) {
printk("tipar: unable to register with parport\n"); 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 void __exit
...@@ -510,8 +543,10 @@ tipar_cleanup_module(void) ...@@ -510,8 +543,10 @@ tipar_cleanup_module(void)
if (table[i].dev == NULL) if (table[i].dev == NULL)
continue; continue;
parport_unregister_device(table[i].dev); parport_unregister_device(table[i].dev);
class_simple_device_remove(MKDEV(TIPAR_MAJOR, i));
devfs_remove("ticables/par/%d", i); devfs_remove("ticables/par/%d", i);
} }
class_simple_destroy(tipar_class);
devfs_remove("ticables/par"); devfs_remove("ticables/par");
printk("tipar: module unloaded !\n"); printk("tipar: module unloaded !\n");
......
...@@ -34,4 +34,12 @@ config EFI_VARS ...@@ -34,4 +34,12 @@ config EFI_VARS
Subsequent efibootmgr releases may be found at: Subsequent efibootmgr releases may be found at:
http://linux.dell.com/efibootmgr 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 endmenu
...@@ -3,3 +3,4 @@ ...@@ -3,3 +3,4 @@
# #
obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_EDD) += edd.o
obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_SMBIOS) += smbios.o
/*
* 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);
/*
* 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 */
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* To do: * 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 * - more /dev/adb to allow userland to receive the
* flow of auto-polling datas from a given device. * flow of auto-polling datas from a given device.
* - move bus probe to a kernel thread * - move bus probe to a kernel thread
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
...@@ -36,6 +35,7 @@ ...@@ -36,6 +35,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/device.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#ifdef CONFIG_PPC #ifdef CONFIG_PPC
...@@ -75,6 +75,8 @@ static struct adb_driver *adb_driver_list[] = { ...@@ -75,6 +75,8 @@ static struct adb_driver *adb_driver_list[] = {
NULL NULL
}; };
static struct class_simple *adb_dev_class;
struct adb_driver *adb_controller; struct adb_driver *adb_controller;
struct notifier_block *adb_client_list = NULL; struct notifier_block *adb_client_list = NULL;
static int adb_got_sleep; static int adb_got_sleep;
...@@ -883,6 +885,7 @@ static ssize_t adb_write(struct file *file, const char __user *buf, ...@@ -883,6 +885,7 @@ static ssize_t adb_write(struct file *file, const char __user *buf,
} }
static struct file_operations adb_fops = { static struct file_operations adb_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek, .llseek = no_llseek,
.read = adb_read, .read = adb_read,
.write = adb_write, .write = adb_write,
...@@ -893,9 +896,13 @@ static struct file_operations adb_fops = { ...@@ -893,9 +896,13 @@ static struct file_operations adb_fops = {
static void static void
adbdev_init(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); printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
else return;
devfs_mk_cdev(MKDEV(ADB_MAJOR, 0), }
S_IFCHR | S_IRUSR | S_IWUSR, "adb"); 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");
} }
...@@ -6,7 +6,7 @@ menu "Misc devices" ...@@ -6,7 +6,7 @@ menu "Misc devices"
config IBM_ASM config IBM_ASM
tristate "Device driver for IBM RSA service processor" tristate "Device driver for IBM RSA service processor"
depends on X86 depends on X86 && EXPERIMENTAL
default n default n
---help--- ---help---
This option enables device driver support for in-band access to the This option enables device driver support for in-band access to the
...@@ -20,6 +20,12 @@ config IBM_ASM ...@@ -20,6 +20,12 @@ config IBM_ASM
this feature serial driver support (CONFIG_SERIAL_8250) must be this feature serial driver support (CONFIG_SERIAL_8250) must be
enabled. 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. If unsure, say N.
......
...@@ -126,6 +126,13 @@ static int __init ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_ ...@@ -126,6 +126,13 @@ static int __init ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_
ibmasm_register_uart(sp); 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; return 0;
error_send_message: error_send_message:
......
...@@ -93,6 +93,7 @@ ...@@ -93,6 +93,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/device.h>
#undef COSA_SLOW_IO /* for testing purposes only */ #undef COSA_SLOW_IO /* for testing purposes only */
#undef REALLY_SLOW_IO #undef REALLY_SLOW_IO
...@@ -233,6 +234,9 @@ static int dma[MAX_CARDS+1]; ...@@ -233,6 +234,9 @@ static int dma[MAX_CARDS+1];
/* IRQ can be safely autoprobed */ /* IRQ can be safely autoprobed */
static int irq[MAX_CARDS+1] = { -1, -1, -1, -1, -1, -1, 0, }; static int irq[MAX_CARDS+1] = { -1, -1, -1, -1, -1, -1, 0, };
/* for class stuff*/
static struct class_simple *cosa_class;
#ifdef MODULE #ifdef MODULE
MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i"); MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
MODULE_PARM_DESC(io, "The I/O bases of the COSA or SRP cards"); 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); ...@@ -359,7 +363,7 @@ static void debug_status_out(struct cosa_data *cosa, int status);
static int __init cosa_init(void) 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"); printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -369,12 +373,14 @@ static int __init cosa_init(void) ...@@ -369,12 +373,14 @@ static int __init cosa_init(void)
if (register_chrdev(cosa_major, "cosa", &cosa_fops)) { if (register_chrdev(cosa_major, "cosa", &cosa_fops)) {
printk(KERN_WARNING "cosa: unable to get major %d\n", printk(KERN_WARNING "cosa: unable to get major %d\n",
cosa_major); cosa_major);
return -EIO; err = -EIO;
goto out;
} }
} else { } else {
if (!(cosa_major=register_chrdev(0, "cosa", &cosa_fops))) { if (!(cosa_major=register_chrdev(0, "cosa", &cosa_fops))) {
printk(KERN_WARNING "cosa: unable to register chardev\n"); printk(KERN_WARNING "cosa: unable to register chardev\n");
return -EIO; err = -EIO;
goto out;
} }
} }
for (i=0; i<MAX_CARDS; i++) for (i=0; i<MAX_CARDS; i++)
...@@ -384,15 +390,33 @@ static int __init cosa_init(void) ...@@ -384,15 +390,33 @@ static int __init cosa_init(void)
if (!nr_cards) { if (!nr_cards) {
printk(KERN_WARNING "cosa: no devices found.\n"); printk(KERN_WARNING "cosa: no devices found.\n");
unregister_chrdev(cosa_major, "cosa"); unregister_chrdev(cosa_major, "cosa");
return -ENODEV; err = -ENODEV;
goto out;
} }
devfs_mk_dir("cosa"); 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++) { 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, S_IFCHR|S_IRUSR|S_IWUSR,
"cosa/%d", i); "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); module_init(cosa_init);
...@@ -402,8 +426,11 @@ static void __exit cosa_exit(void) ...@@ -402,8 +426,11 @@ static void __exit cosa_exit(void)
int i; int i;
printk(KERN_INFO "Unloading the cosa module\n"); 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); devfs_remove("cosa/%d", i);
}
class_simple_destroy(cosa_class);
devfs_remove("cosa"); devfs_remove("cosa");
for (cosa=cosa_cards; nr_cards--; cosa++) { for (cosa=cosa_cards; nr_cards--; cosa++) {
/* Clean up the per-channel data */ /* Clean up the per-channel data */
......
...@@ -94,7 +94,7 @@ static ssize_t write(struct file * file, const char __user * userbuf, ...@@ -94,7 +94,7 @@ static ssize_t write(struct file * file, const char __user * userbuf,
static int open(struct inode * inode, struct file * file) 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; struct bin_attribute * attr = file->f_dentry->d_fsdata;
int error = -EINVAL; int error = -EINVAL;
......
...@@ -154,24 +154,33 @@ void sysfs_remove_dir(struct kobject * kobj) ...@@ -154,24 +154,33 @@ void sysfs_remove_dir(struct kobject * kobj)
dput(dentry); 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; struct dentry * new_dentry, * parent;
if (!strcmp(kobject_name(kobj), new_name)) if (!strcmp(kobject_name(kobj), new_name))
return; return -EINVAL;
if (!kobj->parent) if (!kobj->parent)
return; return -EINVAL;
parent = kobj->parent->dentry; parent = kobj->parent->dentry;
down(&parent->d_inode->i_sem); down(&parent->d_inode->i_sem);
new_dentry = sysfs_get_dentry(parent, new_name); new_dentry = sysfs_get_dentry(parent, 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); d_move(kobj->dentry, new_dentry);
kobject_set_name(kobj,new_name); }
dput(new_dentry);
}
up(&parent->d_inode->i_sem); up(&parent->d_inode->i_sem);
return error;
} }
EXPORT_SYMBOL(sysfs_create_dir); EXPORT_SYMBOL(sysfs_create_dir);
......
...@@ -238,7 +238,7 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t ...@@ -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) 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 attribute * attr = file->f_dentry->d_fsdata;
struct sysfs_buffer * buffer; struct sysfs_buffer * buffer;
struct sysfs_ops * ops = NULL; struct sysfs_ops * ops = NULL;
......
...@@ -11,3 +11,16 @@ extern void sysfs_hash_and_remove(struct dentry * dir, const char * name); ...@@ -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 int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
extern void sysfs_remove_subdir(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;
}
...@@ -400,7 +400,7 @@ extern void firmware_unregister(struct subsystem *); ...@@ -400,7 +400,7 @@ extern void firmware_unregister(struct subsystem *);
/* debugging and troubleshooting/diagnostic helpers. */ /* debugging and troubleshooting/diagnostic helpers. */
#define dev_printk(level, dev, format, arg...) \ #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 #ifdef DEBUG
#define dev_dbg(dev, format, arg...) \ #define dev_dbg(dev, format, arg...) \
......
...@@ -48,7 +48,7 @@ extern void kobject_cleanup(struct kobject *); ...@@ -48,7 +48,7 @@ extern void kobject_cleanup(struct kobject *);
extern int kobject_add(struct kobject *); extern int kobject_add(struct kobject *);
extern void kobject_del(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 int kobject_register(struct kobject *);
extern void kobject_unregister(struct kobject *); extern void kobject_unregister(struct kobject *);
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/kobject.h>
#include <linux/moduleparam.h>
#include <asm/local.h> #include <asm/local.h>
#include <asm/module.h> #include <asm/module.h>
...@@ -207,6 +209,23 @@ enum module_state ...@@ -207,6 +209,23 @@ enum module_state
MODULE_STATE_GOING, 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 struct module
{ {
enum module_state state; enum module_state state;
...@@ -217,6 +236,9 @@ struct module ...@@ -217,6 +236,9 @@ struct module
/* Unique handle for this module */ /* Unique handle for this module */
char name[MODULE_NAME_LEN]; char name[MODULE_NAME_LEN];
/* Sysfs stuff. */
struct module_kobject *mkobj;
/* Exported symbols */ /* Exported symbols */
const struct kernel_symbol *syms; const struct kernel_symbol *syms;
unsigned int num_syms; unsigned int num_syms;
...@@ -267,6 +289,9 @@ struct module ...@@ -267,6 +289,9 @@ struct module
/* Destruction function. */ /* Destruction function. */
void (*exit)(void); void (*exit)(void);
/* Fake kernel param for refcnt. */
struct kernel_param refcnt_param;
#endif #endif
#ifdef CONFIG_KALLSYMS #ifdef CONFIG_KALLSYMS
......
...@@ -50,7 +50,7 @@ struct kparam_array ...@@ -50,7 +50,7 @@ struct kparam_array
not there, read bits mean it's readable, write bits mean it's not there, read bits mean it's readable, write bits mean it's
writable. */ writable. */
#define __module_param_call(prefix, name, set, get, arg, perm) \ #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 \ static struct kernel_param const __param_##name \
__attribute_used__ \ __attribute_used__ \
__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
...@@ -71,7 +71,7 @@ struct kparam_array ...@@ -71,7 +71,7 @@ struct kparam_array
/* Actually copy string: maxlen param is usually sizeof(string). */ /* Actually copy string: maxlen param is usually sizeof(string). */
#define module_param_string(name, string, len, perm) \ #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 }; \ = { len, string }; \
module_param_call(name, param_set_copystring, param_get_charp, \ module_param_call(name, param_set_copystring, param_get_charp, \
&__param_string_##name, perm) &__param_string_##name, perm)
......
...@@ -44,7 +44,7 @@ sysfs_create_dir(struct kobject *); ...@@ -44,7 +44,7 @@ sysfs_create_dir(struct kobject *);
extern void extern void
sysfs_remove_dir(struct kobject *); sysfs_remove_dir(struct kobject *);
extern void extern int
sysfs_rename_dir(struct kobject *, const char *new_name); sysfs_rename_dir(struct kobject *, const char *new_name);
extern int extern int
......
...@@ -379,6 +379,22 @@ static inline void percpu_modcopy(void *pcpudst, const void *src, ...@@ -379,6 +379,22 @@ static inline void percpu_modcopy(void *pcpudst, const void *src,
} }
#endif /* CONFIG_SMP */ #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 #ifdef CONFIG_MODULE_UNLOAD
/* Init the unload section of the module. */ /* Init the unload section of the module. */
static void module_unload_init(struct module *mod) static void module_unload_init(struct module *mod)
...@@ -663,6 +679,23 @@ void symbol_put_addr(void *addr) ...@@ -663,6 +679,23 @@ void symbol_put_addr(void *addr)
} }
EXPORT_SYMBOL_GPL(symbol_put_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 */ #else /* !CONFIG_MODULE_UNLOAD */
static void print_unload_info(struct seq_file *m, struct module *mod) 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) ...@@ -689,6 +722,10 @@ sys_delete_module(const char *name_user, unsigned int flags)
return -ENOSYS; return -ENOSYS;
} }
static inline int sysfs_unload_setup(struct module *mod)
{
return 0;
}
#endif /* CONFIG_MODULE_UNLOAD */ #endif /* CONFIG_MODULE_UNLOAD */
#ifdef CONFIG_OBSOLETE_MODPARM #ifdef CONFIG_OBSOLETE_MODPARM
...@@ -944,6 +981,116 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, ...@@ -944,6 +981,116 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
return ret; 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). */ /* Free a module, remove from lists, etc (must hold module mutex). */
static void free_module(struct module *mod) static void free_module(struct module *mod)
{ {
...@@ -952,6 +1099,8 @@ static void free_module(struct module *mod) ...@@ -952,6 +1099,8 @@ static void free_module(struct module *mod)
list_del(&mod->list); list_del(&mod->list);
spin_unlock_irq(&modlist_lock); spin_unlock_irq(&modlist_lock);
mod_kobject_remove(mod);
/* Arch-specific cleanup. */ /* Arch-specific cleanup. */
module_arch_cleanup(mod); module_arch_cleanup(mod);
...@@ -1556,6 +1705,11 @@ static struct module *load_module(void __user *umod, ...@@ -1556,6 +1705,11 @@ static struct module *load_module(void __user *umod,
/ sizeof(struct kernel_param), / sizeof(struct kernel_param),
NULL); NULL);
} }
err = mod_sysfs_setup(mod,
(struct kernel_param *)
sechdrs[setupindex].sh_addr,
sechdrs[setupindex].sh_size
/ sizeof(struct kernel_param));
if (err < 0) if (err < 0)
goto arch_cleanup; goto arch_cleanup;
...@@ -1891,3 +2045,9 @@ struct module *module_text_address(unsigned long addr) ...@@ -1891,3 +2045,9 @@ struct module *module_text_address(unsigned long addr)
void struct_module(struct module *mod) { return; } void struct_module(struct module *mod) { return; }
EXPORT_SYMBOL(struct_module); EXPORT_SYMBOL(struct_module);
#endif #endif
static int __init modules_init(void)
{
return subsystem_register(&module_subsys);
}
__initcall(modules_init);
...@@ -161,7 +161,7 @@ int parse_args(const char *name, ...@@ -161,7 +161,7 @@ int parse_args(const char *name,
\ \
if (!val) return -EINVAL; \ if (!val) return -EINVAL; \
l = strtolfn(val, &endp, 0); \ l = strtolfn(val, &endp, 0); \
if (endp == val || *endp || ((type)l != l)) \ if (endp == val || ((type)l != l)) \
return -EINVAL; \ return -EINVAL; \
*((type *)kp->arg) = l; \ *((type *)kp->arg) = l; \
return 0; \ return 0; \
......
...@@ -385,13 +385,17 @@ EXPORT_SYMBOL(kobject_set_name); ...@@ -385,13 +385,17 @@ EXPORT_SYMBOL(kobject_set_name);
* @new_name: object's new 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); kobj = kobject_get(kobj);
if (!kobj) if (!kobj)
return; return -EINVAL;
sysfs_rename_dir(kobj, new_name); error = sysfs_rename_dir(kobj, new_name);
kobject_put(kobj); kobject_put(kobj);
return error;
} }
/** /**
......
...@@ -792,6 +792,8 @@ int dev_alloc_name(struct net_device *dev, const char *name) ...@@ -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 dev_change_name(struct net_device *dev, char *newname)
{ {
int err = 0;
ASSERT_RTNL(); ASSERT_RTNL();
if (dev->flags & IFF_UP) if (dev->flags & IFF_UP)
...@@ -801,7 +803,7 @@ int dev_change_name(struct net_device *dev, char *newname) ...@@ -801,7 +803,7 @@ int dev_change_name(struct net_device *dev, char *newname)
return -EINVAL; return -EINVAL;
if (strchr(newname, '%')) { if (strchr(newname, '%')) {
int err = dev_alloc_name(dev, newname); err = dev_alloc_name(dev, newname);
if (err < 0) if (err < 0)
return err; return err;
strcpy(newname, dev->name); strcpy(newname, dev->name);
...@@ -811,12 +813,14 @@ int dev_change_name(struct net_device *dev, char *newname) ...@@ -811,12 +813,14 @@ int dev_change_name(struct net_device *dev, char *newname)
else else
strlcpy(dev->name, newname, IFNAMSIZ); strlcpy(dev->name, newname, IFNAMSIZ);
err = class_device_rename(&dev->class_dev, dev->name);
if (!err) {
hlist_del(&dev->name_hlist); hlist_del(&dev->name_hlist);
hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
class_device_rename(&dev->class_dev, dev->name);
notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
return 0; }
return err;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment