bk://kernel.bkbits.net/gregkh/linux/driver-2.6 greg@kroah.com|ChangeSet|20040507212249|39399 greg # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/05/07 14:22:49-07:00 greg@kroah.com # Add modules to sysfs # # This patch adds basic kobject support to struct module, and it creates a # /sys/module directory which contains all of the individual modules. Each # module currently exports the refcount (if they are unloadable) and any # module paramaters that are marked exportable in sysfs. # # Was written by me and Rusty over and over many times during the past 6 months. # # kernel/params.c # 2004/05/07 14:22:37-07:00 greg@kroah.com +1 -1 # Add modules to sysfs # # This patch adds basic kobject support to struct module, and it creates a # /sys/module directory which contains all of the individual modules. Each # module currently exports the refcount (if they are unloadable) and any # module paramaters that are marked exportable in sysfs. # # Was written by me and Rusty over and over many times during the past 6 months. # # kernel/module.c # 2004/05/07 14:22:37-07:00 greg@kroah.com +160 -0 # Add modules to sysfs # # This patch adds basic kobject support to struct module, and it creates a # /sys/module directory which contains all of the individual modules. Each # module currently exports the refcount (if they are unloadable) and any # module paramaters that are marked exportable in sysfs. # # Was written by me and Rusty over and over many times during the past 6 months. # # include/linux/moduleparam.h # 2004/05/07 14:22:37-07:00 greg@kroah.com +2 -2 # Add modules to sysfs # # This patch adds basic kobject support to struct module, and it creates a # /sys/module directory which contains all of the individual modules. Each # module currently exports the refcount (if they are unloadable) and any # module paramaters that are marked exportable in sysfs. # # Was written by me and Rusty over and over many times during the past 6 months. # # include/linux/module.h # 2004/05/07 14:22:37-07:00 greg@kroah.com +25 -0 # Add modules to sysfs # # This patch adds basic kobject support to struct module, and it creates a # /sys/module directory which contains all of the individual modules. Each # module currently exports the refcount (if they are unloadable) and any # module paramaters that are marked exportable in sysfs. # # Was written by me and Rusty over and over many times during the past 6 months. # # ChangeSet # 2004/05/05 15:10:00-07:00 bellucda@tiscali.it # [PATCH] missing audit in bus_register() # # |How about using a goto on the error path to clean up properly # |instead of the different return sections. # # .. here goes Take 2: # # drivers/base/bus.c # 2004/04/28 11:45:19-07:00 bellucda@tiscali.it +18 -3 # missing audit in bus_register() # # ChangeSet # 2004/05/05 14:40:43-07:00 greg@kroah.com # Driver core: handle error if we run out of memory in kmap code # # drivers/base/map.c # 2004/05/05 07:39:44-07:00 greg@kroah.com +7 -0 # Driver core: handle error if we run out of memory in kmap code # # ChangeSet # 2004/05/04 14:16:58-07:00 olh@suse.de # [PATCH] add simple class for adb # # This adds /sys/class/adb/, removes unused devfs lines and updates a # comment to match reality. # # drivers/macintosh/adb.c # 2004/05/01 10:58:08-07:00 olh@suse.de +13 -6 # add simple class for adb # # ChangeSet # 2004/05/02 20:30:19-07:00 kenn@linux.ie # [PATCH] Re: Platform device matching # # On Mon, Apr 26, 2004 at 12:27:33AM +0100, Russell King wrote: # > So, this comment needs updating: # > # > * So, extract the from the device, and compare it against # > * the name of the driver. Return whether they match or not. # # Want a patch? # # drivers/base/platform.c # 2004/04/25 16:33:43-07:00 kenn@linux.ie +3 -2 # Re: Platform device matching # # ChangeSet # 2004/05/02 20:29:59-07:00 hannal@us.ibm.com # [PATCH] add class support to drivers/char/tipar.c # # This patch adds class support to the Texas Instruments graphing calculators # with a parallel link cable. # # I have verified it compiles. If someone has the hardware please verify it works. # # drivers/char/tipar.c # 2004/04/28 13:48:10-07:00 hannal@us.ibm.com +42 -7 # add class support to drivers/char/tipar.c # # ChangeSet # 2004/05/02 20:29:41-07:00 hannal@us.ibm.com # [PATCH] add class support to drivers/block/paride/pt.c # # This patch adds class support to pt.c which "the high-level driver for parallel # port ATAPI tape drives based on chips supported by the paride module." Which I # dont have in order to test. # # I have verified it compiles but can not test it. If someone who has the # hardware could I would appreciate it. # # drivers/block/paride/pt.c # 2004/04/16 16:09:52-07:00 hannal@us.ibm.com +45 -9 # add class support to drivers/block/paride/pt.c # # ChangeSet # 2004/05/02 20:29:22-07:00 hannal@us.ibm.com # [PATCH] add class support to drivers/block/paride/pg.c # # This patch adds class support to pg.c, the parallel port generic ATAPI device driver. # # I have verified it compiles but do not have the hardware. If someone does and # could test that would be helpful. # # drivers/block/paride/pg.c # 2004/04/21 14:50:32-07:00 hannal@us.ibm.com +38 -10 # add class support to drivers/block/paride/pg.c # # ChangeSet # 2004/05/02 20:28:58-07:00 hannal@us.ibm.com # [PATCH] Add class support to drivers/char/ip2main.c # # drivers/char/ip2main.c # 2004/04/14 10:08:00-07:00 hannal@us.ibm.com +39 -5 # Add class support to drivers/char/ip2main.c # # ChangeSet # 2004/05/02 20:28:38-07:00 sebek64@post.cz # [PATCH] Class support for ppdev.c # # drivers/char/ppdev.c # 2004/04/13 10:25:50-07:00 sebek64@post.cz +43 -2 # Class support for ppdev.c # # ChangeSet # 2004/04/28 13:21:19-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core # # drivers/isdn/capi/capi.c # 2004/04/28 13:21:16-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/28 11:51:03-07:00 greg@kroah.com # My cleanups to the smbios driver. # # drivers/firmware/smbios.c # 2004/04/28 04:50:49-07:00 greg@kroah.com +13 -31 # My cleanups to the smbios driver. # # ChangeSet # 2004/04/28 11:50:29-07:00 Michael_E_Brown@Dell.com # [PATCH] add SMBIOS tables to sysfs -- UPDATED # # drivers/firmware/smbios.h # 2004/04/28 04:43:56-07:00 Michael_E_Brown@Dell.com +53 -0 # [PATCH] add SMBIOS tables to sysfs -- UPDATED # # drivers/firmware/smbios.h # 2004/04/28 04:43:56-07:00 Michael_E_Brown@Dell.com +0 -0 # BitKeeper file /home/greg/linux/BK/driver-2.6/drivers/firmware/smbios.h # # drivers/firmware/Makefile # 2004/04/28 04:43:56-07:00 Michael_E_Brown@Dell.com +1 -0 # [PATCH] add SMBIOS tables to sysfs -- UPDATED # # drivers/firmware/Kconfig # 2004/04/28 04:43:56-07:00 Michael_E_Brown@Dell.com +8 -0 # [PATCH] add SMBIOS tables to sysfs -- UPDATED # # drivers/firmware/smbios.c # 2004/04/28 04:43:56-07:00 Michael_E_Brown@Dell.com +266 -0 # [PATCH] add SMBIOS tables to sysfs -- UPDATED # # drivers/firmware/smbios.c # 2004/04/28 04:43:56-07:00 Michael_E_Brown@Dell.com +0 -0 # BitKeeper file /home/greg/linux/BK/driver-2.6/drivers/firmware/smbios.c # # ChangeSet # 2004/04/26 18:13:55-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core # # drivers/isdn/capi/capi.c # 2004/04/26 18:13:52-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/21 21:55:11-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core # # drivers/video/fbmem.c # 2004/04/21 21:55:09-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/19 19:27:32-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core # # drivers/video/fbmem.c # 2004/04/19 19:27:29-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/isdn/capi/capi.c # 2004/04/19 19:27:29-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/char/vt.c # 2004/04/19 19:27:29-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/09 13:19:25-07:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/driver-2.6 # into bix.(none):/usr/src/bk-driver-core # # drivers/isdn/capi/capi.c # 2004/04/09 13:19:23-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/31 12:15:48-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core # # drivers/char/vt.c # 2004/03/31 12:15:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/26 12:12:33-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core # # drivers/video/fbmem.c # 2004/03/26 12:12:31-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/char/vt.c # 2004/03/26 12:12:31-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/24 02:37:20-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core # # drivers/video/fbmem.c # 2004/03/24 02:37:18-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/20 13:16:54-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-driver-core # # drivers/char/vt.c # 2004/03/20 13:16:51-08:00 akpm@bix.(none) +0 -0 # Auto merged # diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c --- a/drivers/base/bus.c Sun May 9 21:13:02 2004 +++ b/drivers/base/bus.c Sun May 9 21:13:02 2004 @@ -555,21 +555,36 @@ */ int bus_register(struct bus_type * bus) { + int retval; + kobject_set_name(&bus->subsys.kset.kobj,bus->name); 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 -Nru a/drivers/base/map.c b/drivers/base/map.c --- a/drivers/base/map.c Sun May 9 21:13:02 2004 +++ b/drivers/base/map.c Sun May 9 21:13:02 2004 @@ -138,6 +138,13 @@ 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 -Nru a/drivers/base/platform.c b/drivers/base/platform.c --- a/drivers/base/platform.c Sun May 9 21:13:02 2004 +++ b/drivers/base/platform.c Sun May 9 21:13:02 2004 @@ -57,8 +57,9 @@ * type of device, like "pci" or "floppy", and is the * enumerated instance of the device, like '0' or '42'. * Driver IDs are simply "". - * So, extract the from the device, and compare it against - * the name of the driver. Return whether they match or not. + * So, extract the 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 -Nru a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c --- a/drivers/block/paride/pg.c Sun May 9 21:13:02 2004 +++ b/drivers/block/paride/pg.c Sun May 9 21:13:02 2004 @@ -161,6 +161,7 @@ #include #include #include +#include #include @@ -240,6 +241,8 @@ 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 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 @@ 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 @@ 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 -Nru a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c --- a/drivers/block/paride/pt.c Sun May 9 21:13:02 2004 +++ b/drivers/block/paride/pt.c Sun May 9 21:13:02 2004 @@ -145,6 +145,7 @@ #include #include #include +#include #include @@ -260,6 +261,9 @@ .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 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 @@ 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 -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c --- a/drivers/char/ip2main.c Sun May 9 21:13:02 2004 +++ b/drivers/char/ip2main.c Sun May 9 21:13:02 2004 @@ -99,6 +99,7 @@ #include #include #include +#include #include #include @@ -301,6 +302,9 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ } 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 @@ } } 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); diff -Nru a/drivers/char/ppdev.c b/drivers/char/ppdev.c --- a/drivers/char/ppdev.c Sun May 9 21:13:02 2004 +++ b/drivers/char/ppdev.c Sun May 9 21:13:02 2004 @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -739,6 +740,8 @@ return mask; } +static struct class_simple *ppdev_class; + static struct file_operations pp_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -750,23 +753,59 @@ .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 @@ /* 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 -Nru a/drivers/char/tipar.c b/drivers/char/tipar.c --- a/drivers/char/tipar.c Sun May 9 21:13:02 2004 +++ b/drivers/char/tipar.c Sun May 9 21:13:02 2004 @@ -58,6 +58,7 @@ #include #include /* DevFs support */ #include /* Our code depend on parport */ +#include /* * TI definitions @@ -92,6 +93,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -Nru a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig --- a/drivers/firmware/Kconfig Sun May 9 21:13:02 2004 +++ b/drivers/firmware/Kconfig Sun May 9 21:13:02 2004 @@ -34,4 +34,12 @@ 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 -Nru a/drivers/firmware/Makefile b/drivers/firmware/Makefile --- a/drivers/firmware/Makefile Sun May 9 21:13:02 2004 +++ b/drivers/firmware/Makefile Sun May 9 21:13:02 2004 @@ -3,3 +3,4 @@ # obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_EFI_VARS) += efivars.o +obj-$(CONFIG_SMBIOS) += smbios.o diff -Nru a/drivers/firmware/smbios.c b/drivers/firmware/smbios.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/firmware/smbios.c Sun May 9 21:13:02 2004 @@ -0,0 +1,248 @@ +/* + * linux/drivers/firmware/smbios.c + * Copyright (C) 2004 Dell Inc. + * by Michael Brown + * 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 +#include +#include +#include +#include +#include "smbios.h" + +MODULE_AUTHOR("Michael Brown "); +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 -Nru a/drivers/firmware/smbios.h b/drivers/firmware/smbios.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/firmware/smbios.h Sun May 9 21:13:02 2004 @@ -0,0 +1,53 @@ +/* + * linux/drivers/firmware/smbios.c + * Copyright (C) 2002, 2003, 2004 Dell Inc. + * by Michael Brown + * 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 + +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 -Nru a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c --- a/drivers/macintosh/adb.c Sun May 9 21:13:02 2004 +++ b/drivers/macintosh/adb.c Sun May 9 21:13:02 2004 @@ -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 #include #include -#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_PPC @@ -75,6 +75,8 @@ 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 @@ } static struct file_operations adb_fops = { + .owner = THIS_MODULE, .llseek = no_llseek, .read = adb_read, .write = adb_write, @@ -893,9 +896,13 @@ 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 -Nru a/include/linux/module.h b/include/linux/module.h --- a/include/linux/module.h Sun May 9 21:13:02 2004 +++ b/include/linux/module.h Sun May 9 21:13:02 2004 @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -207,6 +209,23 @@ 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 @@ /* 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 @@ /* Destruction function. */ void (*exit)(void); + + /* Fake kernel param for refcnt. */ + struct kernel_param refcnt_param; #endif #ifdef CONFIG_KALLSYMS diff -Nru a/include/linux/moduleparam.h b/include/linux/moduleparam.h --- a/include/linux/moduleparam.h Sun May 9 21:13:02 2004 +++ b/include/linux/moduleparam.h Sun May 9 21:13:02 2004 @@ -50,7 +50,7 @@ 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 @@ /* 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 -Nru a/kernel/module.c b/kernel/module.c --- a/kernel/module.c Sun May 9 21:13:02 2004 +++ b/kernel/module.c Sun May 9 21:13:02 2004 @@ -504,6 +504,22 @@ return stop_machine_run(__try_stop_module, &sref, NR_CPUS); } +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; +} + unsigned int module_refcount(struct module *mod) { unsigned int i, total = 0; @@ -663,6 +679,23 @@ } 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 @@ 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 @@ 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 @@ list_del(&mod->list); spin_unlock_irq(&modlist_lock); + mod_kobject_remove(mod); + /* Arch-specific cleanup. */ module_arch_cleanup(mod); @@ -1556,6 +1705,11 @@ / 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 @@ 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 -Nru a/kernel/params.c b/kernel/params.c --- a/kernel/params.c Sun May 9 21:13:02 2004 +++ b/kernel/params.c Sun May 9 21:13:02 2004 @@ -161,7 +161,7 @@ \ 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; \