diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile --- a/drivers/base/Makefile Thu Jan 15 11:05:59 2004 +++ b/drivers/base/Makefile Thu Jan 15 11:05:59 2004 @@ -1,7 +1,7 @@ # Makefile for the Linux device tree obj-y := core.o sys.o interface.o bus.o \ - driver.o class.o platform.o \ + driver.o class.o class_simple.o platform.o \ cpu.o firmware.o init.o map.o obj-y += power/ obj-$(CONFIG_FW_LOADER) += firmware_class.o diff -Nru a/drivers/base/class.c b/drivers/base/class.c --- a/drivers/base/class.c Thu Jan 15 11:06:02 2004 +++ b/drivers/base/class.c Thu Jan 15 11:06:02 2004 @@ -46,6 +46,19 @@ return ret; } +static void class_release(struct kobject * kobj) +{ + struct class *class = to_class(kobj); + + pr_debug("class '%s': release.\n", class->name); + + if (class->class_release) + class->class_release(class); + else + pr_debug("class '%s' does not have a release() function, " + "be careful\n", class->name); +} + static struct sysfs_ops class_sysfs_ops = { .show = class_attr_show, .store = class_attr_store, @@ -53,6 +66,7 @@ static struct kobj_type ktype_class = { .sysfs_ops = &class_sysfs_ops, + .release = class_release, }; /* Hotplug events for classes go to the class_obj subsys */ diff -Nru a/drivers/base/class_simple.c b/drivers/base/class_simple.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/base/class_simple.c Thu Jan 15 11:06:03 2004 @@ -0,0 +1,201 @@ +/* + * class_simple.c - a "simple" interface for classes for simple char devices. + * + * Copyright (c) 2003-2004 Greg Kroah-Hartman + * Copyright (c) 2003-2004 IBM Corp. + * + * This file is released under the GPLv2 + * + */ + +#define DEBUG 1 + +#include +#include +#include + +struct class_simple { + struct class_device_attribute attr; + struct class class; +}; +#define to_class_simple(d) container_of(d, struct class_simple, class) + +struct simple_dev { + struct list_head node; + dev_t dev; + struct class_device class_dev; +}; +#define to_simple_dev(d) container_of(d, struct simple_dev, class_dev) + +static LIST_HEAD(simple_dev_list); +static spinlock_t simple_dev_list_lock = SPIN_LOCK_UNLOCKED; + +static void release_simple_dev(struct class_device *class_dev) +{ + struct simple_dev *s_dev = to_simple_dev(class_dev); + kfree(s_dev); +} + +static ssize_t show_dev(struct class_device *class_dev, char *buf) +{ + struct simple_dev *s_dev = to_simple_dev(class_dev); + return print_dev_t(buf, s_dev->dev); +} + +static void class_simple_release(struct class *class) +{ + struct class_simple *cs = to_class_simple(class); + kfree(cs); +} + +/** + * class_simple_create - create a struct class_simple structure + * @owner: pointer to the module that is to "own" this struct class_simple + * @name: pointer to a string for the name of this class. + * + * This is used to create a struct class_simple pointer that can then be used + * in calls to class_simple_device_add(). This is used when you do not wish to + * create a full blown class support for a type of char devices. + * + * Note, the pointer created here is to be destroyed when finished by making a + * call to class_simple_destroy(). + */ +struct class_simple *class_simple_create(struct module *owner, char *name) +{ + struct class_simple *cs; + int retval; + + cs = kmalloc(sizeof(*cs), GFP_KERNEL); + if (!cs) { + retval = -ENOMEM; + goto error; + } + memset(cs, 0x00, sizeof(*cs)); + + cs->class.name = name; + cs->class.class_release = class_simple_release; + cs->class.release = release_simple_dev; + + cs->attr.attr.name = "dev"; + cs->attr.attr.mode = S_IRUGO; + cs->attr.attr.owner = owner; + cs->attr.show = show_dev; + cs->attr.store = NULL; + + retval = class_register(&cs->class); + if (retval) + goto error; + + return cs; + +error: + kfree(cs); + return ERR_PTR(retval); +} +EXPORT_SYMBOL(class_simple_create); + +/** + * class_simple_destroy - destroys a struct class_simple structure + * @cs: pointer to the struct class_simple that is to be destroyed + * + * Note, the pointer to be destroyed must have been created with a call to + * class_simple_create(). + */ +void class_simple_destroy(struct class_simple *cs) +{ + if ((cs == NULL) || (IS_ERR(cs))) + return; + + class_unregister(&cs->class); +} +EXPORT_SYMBOL(class_simple_destroy); + +/** + * class_simple_device_add - adds a class device to sysfs for a character driver + * @cs: pointer to the struct class_simple that this device should be registered to. + * @dev: the dev_t for the device to be added. + * @device: a pointer to a struct device that is assiociated with this class device. + * @fmt: string for the class device's name + * + * This function can be used by simple char device classes that do not + * implement their own class device registration. A struct class_device will + * be created in sysfs, registered to the specified class. A "dev" file will + * be created, showing the dev_t for the device. The pointer to the struct + * class_device will be returned from the call. Any further sysfs files that + * might be required can be created using this pointer. + * Note: the struct class_device passed to this function must have previously been + * created with a call to class_simple_create(). + */ +struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev, struct device *device, const char *fmt, ...) +{ + va_list args; + struct simple_dev *s_dev = NULL; + int retval; + + if ((cs == NULL) || (IS_ERR(cs))) { + retval = -ENODEV; + goto error; + } + + s_dev = kmalloc(sizeof(*s_dev), GFP_KERNEL); + if (!s_dev) { + retval = -ENOMEM; + goto error; + } + memset(s_dev, 0x00, sizeof(*s_dev)); + + s_dev->dev = dev; + s_dev->class_dev.dev = device; + s_dev->class_dev.class = &cs->class; + + va_start(args,fmt); + vsnprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, fmt, args); + va_end(args); + retval = class_device_register(&s_dev->class_dev); + if (retval) + goto error; + + class_device_create_file(&s_dev->class_dev, &cs->attr); + + spin_lock(&simple_dev_list_lock); + list_add(&s_dev->node, &simple_dev_list); + spin_unlock(&simple_dev_list_lock); + + return &s_dev->class_dev; + +error: + kfree(s_dev); + return ERR_PTR(retval); +} +EXPORT_SYMBOL(class_simple_device_add); + +/** + * class_simple_device_remove - removes a class device that was created with class_simple_device_add() + * @dev: the dev_t of the device that was previously registered. + * + * This call unregisters and cleans up a class device that was created with a + * call to class_device_simple_add() + */ +void class_simple_device_remove(dev_t dev) +{ + struct simple_dev *s_dev = NULL; + struct list_head *tmp; + int found = 0; + + spin_lock(&simple_dev_list_lock); + list_for_each(tmp, &simple_dev_list) { + s_dev = list_entry(tmp, struct simple_dev, node); + if (s_dev->dev == dev) { + found = 1; + break; + } + } + if (found) { + list_del(&s_dev->node); + spin_unlock(&simple_dev_list_lock); + class_device_unregister(&s_dev->class_dev); + } else { + spin_unlock(&simple_dev_list_lock); + } +} +EXPORT_SYMBOL(class_simple_device_remove); diff -Nru a/include/linux/device.h b/include/linux/device.h --- a/include/linux/device.h Thu Jan 15 11:05:58 2004 +++ b/include/linux/device.h Thu Jan 15 11:05:58 2004 @@ -46,6 +46,7 @@ struct device_driver; struct class; struct class_device; +struct class_simple; struct bus_type { char * name; @@ -155,6 +156,7 @@ int num_envp, char *buffer, int buffer_size); void (*release)(struct class_device *dev); + void (*class_release)(struct class *class); }; extern int class_register(struct class *); @@ -246,6 +248,13 @@ extern int class_interface_register(struct class_interface *); extern void class_interface_unregister(struct class_interface *); +/* interface for class simple stuff */ +extern struct class_simple *class_simple_create(struct module *owner, char *name); +extern void class_simple_destroy(struct class_simple *cs); +extern struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev, struct device *device, const char *fmt, ...) + __attribute__((format(printf,4,5))); +extern void class_simple_device_remove(dev_t dev); + struct device { struct list_head node; /* node in sibling list */ diff -Nru a/include/sound/core.h b/include/sound/core.h --- a/include/sound/core.h Thu Jan 15 11:06:00 2004 +++ b/include/sound/core.h Thu Jan 15 11:06:00 2004 @@ -160,6 +160,7 @@ int shutdown; /* this card is going down */ wait_queue_head_t shutdown_sleep; struct work_struct free_workq; /* for free in workqueue */ + struct device *dev; #ifdef CONFIG_PM int (*set_power_state) (snd_card_t *card, unsigned int state); diff -Nru a/sound/core/sound.c b/sound/core/sound.c --- a/sound/core/sound.c Thu Jan 15 11:05:49 2004 +++ b/sound/core/sound.c Thu Jan 15 11:05:49 2004 @@ -38,9 +38,7 @@ static int major = CONFIG_SND_MAJOR; int snd_major; static int cards_limit = SNDRV_CARDS; -#ifdef CONFIG_DEVFS_FS static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO; -#endif MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); @@ -66,6 +64,7 @@ static DECLARE_MUTEX(sound_mutex); +extern struct class_simple *sound_class; #ifdef CONFIG_KMOD /** @@ -203,6 +202,7 @@ { int minor = snd_kernel_minor(type, card, dev); snd_minor_t *preg; + struct device *device = NULL; if (minor < 0) return minor; @@ -221,10 +221,14 @@ return -EBUSY; } list_add_tail(&preg->list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]); -#ifdef CONFIG_DEVFS_FS - if (strncmp(name, "controlC", 8)) /* created in sound.c */ + + if (strncmp(name, "controlC", 8)) { /* created in sound.c */ devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name); -#endif + if (card) + device = card->dev; + class_simple_device_add(sound_class, MKDEV(major, minor), device, name); + } + up(&sound_mutex); return 0; } @@ -252,10 +256,12 @@ up(&sound_mutex); return -EINVAL; } -#ifdef CONFIG_DEVFS_FS - if (strncmp(mptr->name, "controlC", 8)) /* created in sound.c */ + + if (strncmp(mptr->name, "controlC", 8)) { /* created in sound.c */ devfs_remove("snd/%s", mptr->name); -#endif + class_simple_device_remove(MKDEV(major, minor)); + } + list_del(&mptr->list); up(&sound_mutex); kfree(mptr); @@ -322,9 +328,7 @@ static int __init alsa_sound_init(void) { -#ifdef CONFIG_DEVFS_FS short controlnum; -#endif #ifdef CONFIG_SND_OSSEMUL int err; #endif @@ -358,10 +362,10 @@ #ifdef CONFIG_SND_OSSEMUL snd_info_minor_register(); #endif -#ifdef CONFIG_DEVFS_FS - for (controlnum = 0; controlnum < cards_limit; controlnum++) + for (controlnum = 0; controlnum < cards_limit; controlnum++) { devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum); -#endif + class_simple_device_add(sound_class, MKDEV(major, controlnum<<5), NULL, "controlC%d", controlnum); + } #ifndef MODULE printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); #endif @@ -372,8 +376,10 @@ { short controlnum; - for (controlnum = 0; controlnum < cards_limit; controlnum++) + for (controlnum = 0; controlnum < cards_limit; controlnum++) { devfs_remove("snd/controlC%d", controlnum); + class_simple_device_remove(MKDEV(major, controlnum<<5)); + } #ifdef CONFIG_SND_OSSEMUL snd_info_minor_unregister(); diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c --- a/sound/pci/intel8x0.c Thu Jan 15 11:05:58 2004 +++ b/sound/pci/intel8x0.c Thu Jan 15 11:05:58 2004 @@ -2591,6 +2591,7 @@ break; } } + card->dev = &pci->dev; if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, &chip)) < 0) { snd_card_free(card); diff -Nru a/drivers/char/lp.c b/drivers/char/lp.c --- a/drivers/char/lp.c Thu Jan 15 12:13:07 2004 +++ b/drivers/char/lp.c Thu Jan 15 12:13:07 2004 @@ -145,6 +145,7 @@ struct lp_struct lp_table[LP_NO]; static unsigned int lp_count = 0; +static struct class_simple *lp_class; #ifdef CONFIG_LP_CONSOLE static struct parport *console_registered; // initially NULL @@ -795,6 +796,8 @@ if (reset) lp_reset(nr); + class_simple_device_add(lp_class, MKDEV(LP_MAJOR, nr), NULL, + "lp%d", nr); devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO, "printers/%d", nr); @@ -897,6 +900,7 @@ } devfs_mk_dir("printers"); + lp_class = class_simple_create(THIS_MODULE, "printer"); if (parport_register_driver (&lp_driver)) { printk (KERN_ERR "lp: unable to register with parport\n"); @@ -958,8 +962,10 @@ continue; parport_unregister_device(lp_table[offset].dev); devfs_remove("printers/%d", offset); + class_simple_device_remove(MKDEV(LP_MAJOR, offset)); } devfs_remove("printers"); + class_simple_destroy(lp_class); } __setup("lp=", lp_setup); diff -Nru a/drivers/char/misc.c b/drivers/char/misc.c --- a/drivers/char/misc.c Thu Jan 15 11:05:56 2004 +++ b/drivers/char/misc.c Thu Jan 15 11:05:56 2004 @@ -47,7 +47,7 @@ #include #include #include - +#include #include #include @@ -180,6 +180,13 @@ return err; } +/* + * TODO for 2.7: + * - add a struct class_device to struct miscdevice and make all usages of + * them dynamic. + */ +static struct class_simple *misc_class; + static struct file_operations misc_fops = { .owner = THIS_MODULE, .open = misc_open, @@ -234,6 +241,8 @@ "misc/%s", misc->name); } + class_simple_device_add(misc_class, MKDEV(MISC_MAJOR, misc->minor), + misc->dev, misc->name); devfs_mk_cdev(MKDEV(MISC_MAJOR, misc->minor), S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, misc->devfs_name); @@ -265,6 +274,7 @@ down(&misc_sem); list_del(&misc->list); + class_simple_device_remove(MKDEV(MISC_MAJOR, misc->minor)); devfs_remove(misc->devfs_name); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); @@ -285,6 +295,9 @@ if (ent) ent->proc_fops = &misc_proc_fops; #endif + misc_class = class_simple_create(THIS_MODULE, "misc"); + if (IS_ERR(misc_class)) + return PTR_ERR(misc_class); #ifdef CONFIG_MVME16x rtc_MK48T08_init(); #endif @@ -319,4 +332,4 @@ } return 0; } -module_init(misc_init); +subsys_initcall(misc_init); diff -Nru a/include/linux/miscdevice.h b/include/linux/miscdevice.h --- a/include/linux/miscdevice.h Thu Jan 15 11:05:53 2004 +++ b/include/linux/miscdevice.h Thu Jan 15 11:05:53 2004 @@ -36,12 +36,15 @@ #define TUN_MINOR 200 +struct device; + struct miscdevice { int minor; const char *name; struct file_operations *fops; struct list_head list; + struct device *dev; char devfs_name[64]; }; This adds class/raw/ support for all raw devices. It also provides a symlink to the block device that the raw device is mapped to. For example: $ tree /sys/class/raw/ /sys/class/raw/ |-- raw1 | |-- dev | `-- device -> ../../../block/sda |-- raw2 | |-- dev | `-- device -> ../../../block/sda/sda2 `-- rawctl `-- dev Note, in order to get that symlink, I had to export get_gendisk() so that modules can use it. I hope this is ok with everyone. This is based on a patch originally written by Leann Ogasawara diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c --- a/drivers/block/genhd.c Thu Jan 15 11:05:57 2004 +++ b/drivers/block/genhd.c Thu Jan 15 11:05:57 2004 @@ -224,6 +224,8 @@ return kobj ? to_disk(kobj) : NULL; } +EXPORT_SYMBOL(get_gendisk); + #ifdef CONFIG_PROC_FS /* iterator */ static void *part_start(struct seq_file *part, loff_t *pos) diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c --- a/drivers/char/raw.c Thu Jan 15 11:05:47 2004 +++ b/drivers/char/raw.c Thu Jan 15 11:05:47 2004 @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include @@ -25,6 +27,7 @@ int inuse; }; +static struct class_simple *raw_class; static struct raw_device_data raw_devices[MAX_RAW_MINORS]; static DECLARE_MUTEX(raw_mutex); static struct file_operations raw_ctl_fops; /* forward declaration */ @@ -119,6 +122,29 @@ return ioctl_by_bdev(bdev, command, arg); } +static void bind_device(struct raw_config_request rq) +{ + int part; + struct gendisk *gen; + struct class_device *dev; + struct kobject *target = NULL; + + gen = get_gendisk(MKDEV(rq.block_major, rq.block_minor), &part); + if (gen) { + if (part && gen->part[part]) + target = &gen->part[part]->kobj; + else + target = &gen->kobj; + } + + class_simple_device_remove(MKDEV(RAW_MAJOR, rq.raw_minor)); + dev = class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, rq.raw_minor), + NULL, "raw%d", rq.raw_minor); + if (dev && target) { + sysfs_create_link(&dev->kobj, target, "device"); + } +} + /* * Deal with ioctls against the raw-device control interface, to bind * and unbind other raw devices. @@ -187,12 +213,15 @@ if (rq.block_major == 0 && rq.block_minor == 0) { /* unbind */ rawdev->binding = NULL; + class_simple_device_remove(MKDEV(RAW_MAJOR, rq.raw_minor)); } else { rawdev->binding = bdget(dev); if (rawdev->binding == NULL) err = -ENOMEM; - else + else { __module_get(THIS_MODULE); + bind_device(rq); + } } up(&raw_mutex); } else { @@ -262,6 +291,14 @@ int i; register_chrdev(RAW_MAJOR, "raw", &raw_fops); + + raw_class = class_simple_create(THIS_MODULE, "raw"); + if (IS_ERR(raw_class)) { + printk (KERN_ERR "Error creating raw class.\n"); + return PTR_ERR(raw_class); + } + class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); + devfs_mk_cdev(MKDEV(RAW_MAJOR, 0), S_IFCHR | S_IRUGO | S_IWUGO, "raw/rawctl"); @@ -280,6 +317,8 @@ devfs_remove("raw/raw%d", i); devfs_remove("raw/rawctl"); devfs_remove("raw"); + class_simple_device_remove(MKDEV(RAW_MAJOR, 0)); + class_simple_destroy(raw_class); unregister_chrdev(RAW_MAJOR, "raw"); } diff -Nru a/sound/oss/soundcard.c b/sound/oss/soundcard.c --- a/sound/oss/soundcard.c Thu Jan 15 11:06:01 2004 +++ b/sound/oss/soundcard.c Thu Jan 15 11:06:01 2004 @@ -73,6 +73,7 @@ unsigned long seq_time = 0; /* Time for /dev/sequencer */ +extern struct class_simple *sound_class; /* * Table for configurable mixer volume handling @@ -569,6 +570,9 @@ devfs_mk_cdev(MKDEV(SOUND_MAJOR, dev_list[i].minor), S_IFCHR | dev_list[i].mode, "sound/%s", dev_list[i].name); + class_simple_device_add(sound_class, + MKDEV(SOUND_MAJOR, dev_list[i].minor), + NULL, "%s", dev_list[i].name); if (!dev_list[i].num) continue; @@ -578,6 +582,10 @@ dev_list[i].minor + (j*0x10)), S_IFCHR | dev_list[i].mode, "sound/%s%d", dev_list[i].name, j); + class_simple_device_add(sound_class, + MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)), + NULL, + "%s%d", dev_list[i].name, j); } } @@ -593,10 +601,13 @@ for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) { devfs_remove("sound/%s", dev_list[i].name); + class_simple_device_remove(MKDEV(SOUND_MAJOR, dev_list[i].minor)); if (!dev_list[i].num) continue; - for (j = 1; j < *dev_list[i].num; j++) + for (j = 1; j < *dev_list[i].num; j++) { devfs_remove("sound/%s%d", dev_list[i].name, j); + class_simple_device_remove(MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10))); + } } unregister_sound_special(1); diff -Nru a/sound/sound_core.c b/sound/sound_core.c --- a/sound/sound_core.c Thu Jan 15 11:05:56 2004 +++ b/sound/sound_core.c Thu Jan 15 11:05:56 2004 @@ -65,6 +65,9 @@ extern int msnd_pinnacle_init(void); #endif +struct class_simple *sound_class; +EXPORT_SYMBOL(sound_class); + /* * Low level list operator. Scan the ordered list, find a hole and * join into it. Called with the lock asserted @@ -171,6 +174,8 @@ devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor), S_IFCHR | mode, s->name); + class_simple_device_add(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor), + NULL, s->name+6); return r; fail: @@ -193,6 +198,7 @@ spin_unlock(&sound_loader_lock); if (p) { devfs_remove(p->name); + class_simple_device_remove(MKDEV(SOUND_MAJOR, p->unit_minor)); kfree(p); } } @@ -556,6 +562,7 @@ empty */ unregister_chrdev(SOUND_MAJOR, "sound"); devfs_remove("sound"); + class_simple_destroy(sound_class); } static int __init init_soundcore(void) @@ -565,6 +572,9 @@ return -EBUSY; } devfs_mk_dir ("sound"); + sound_class = class_simple_create(THIS_MODULE, "sound"); + if (IS_ERR(sound_class)) + return PTR_ERR(sound_class); return 0; } diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c --- a/drivers/char/tty_io.c Thu Jan 15 11:05:50 2004 +++ b/drivers/char/tty_io.c Thu Jan 15 11:05:50 2004 @@ -2069,79 +2069,7 @@ tty->driver->write(tty, 0, &ch, 1); } -struct tty_dev { - struct list_head node; - dev_t dev; - struct class_device class_dev; -}; -#define to_tty_dev(d) container_of(d, struct tty_dev, class_dev) - -static void release_tty_dev(struct class_device *class_dev) -{ - struct tty_dev *tty_dev = to_tty_dev(class_dev); - kfree(tty_dev); -} - -static struct class tty_class = { - .name = "tty", - .release = &release_tty_dev, -}; - -static LIST_HEAD(tty_dev_list); -static spinlock_t tty_dev_list_lock = SPIN_LOCK_UNLOCKED; - -static ssize_t show_dev(struct class_device *class_dev, char *buf) -{ - struct tty_dev *tty_dev = to_tty_dev(class_dev); - return print_dev_t(buf, tty_dev->dev); -} -static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); - -static void tty_add_class_device(char *name, dev_t dev, struct device *device) -{ - struct tty_dev *tty_dev = NULL; - int retval; - - tty_dev = kmalloc(sizeof(*tty_dev), GFP_KERNEL); - if (!tty_dev) - return; - memset(tty_dev, 0x00, sizeof(*tty_dev)); - - tty_dev->class_dev.dev = device; - tty_dev->class_dev.class = &tty_class; - snprintf(tty_dev->class_dev.class_id, BUS_ID_SIZE, "%s", name); - retval = class_device_register(&tty_dev->class_dev); - if (retval) - goto error; - class_device_create_file (&tty_dev->class_dev, &class_device_attr_dev); - tty_dev->dev = dev; - spin_lock(&tty_dev_list_lock); - list_add(&tty_dev->node, &tty_dev_list); - spin_unlock(&tty_dev_list_lock); - return; -error: - kfree(tty_dev); -} - -static void tty_remove_class_device(dev_t dev) -{ - struct tty_dev *tty_dev = NULL; - struct list_head *tmp; - int found = 0; - - spin_lock(&tty_dev_list_lock); - list_for_each (tmp, &tty_dev_list) { - tty_dev = list_entry(tmp, struct tty_dev, node); - if (tty_dev->dev == dev) { - list_del(&tty_dev->node); - found = 1; - break; - } - } - spin_unlock(&tty_dev_list_lock); - if (found) - class_device_unregister(&tty_dev->class_dev); -} +static struct class_simple *tty_class; /** * tty_register_device - register a tty device @@ -2174,7 +2102,7 @@ if (driver->type != TTY_DRIVER_TYPE_PTY) { char name[64]; tty_line_name(driver, index, name); - tty_add_class_device(name, dev, device); + class_simple_device_add(tty_class, dev, device, name); } } @@ -2189,7 +2117,7 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) { devfs_remove("%s%d", driver->devfs_name, index + driver->name_base); - tty_remove_class_device(MKDEV(driver->major, driver->minor_start) + index); + class_simple_device_remove(MKDEV(driver->major, driver->minor_start) + index); } EXPORT_SYMBOL(tty_register_device); @@ -2406,7 +2334,10 @@ static int __init tty_class_init(void) { - return class_register(&tty_class); + tty_class = class_simple_create(THIS_MODULE, "tty"); + if (IS_ERR(tty_class)) + return PTR_ERR(tty_class); + return 0; } postcore_initcall(tty_class_init); @@ -2431,7 +2362,7 @@ register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); - tty_add_class_device ("tty", MKDEV(TTYAUX_MAJOR, 0), NULL); + class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); strcpy(console_cdev.kobj.name, "dev.console"); cdev_init(&console_cdev, &console_fops); @@ -2439,7 +2370,7 @@ register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); - tty_add_class_device ("console", MKDEV(TTYAUX_MAJOR, 1), NULL); + class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); tty_kobj.kset = tty_cdev.kobj.kset; kobject_register(&tty_kobj); @@ -2451,7 +2382,7 @@ register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); - tty_add_class_device ("ptmx", MKDEV(TTYAUX_MAJOR, 2), NULL); + class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); #endif #ifdef CONFIG_VT @@ -2461,7 +2392,7 @@ register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); - tty_add_class_device ("tty0", MKDEV(TTY_MAJOR, 0), NULL); + class_simple_device_add(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); vty_init(); #endif diff -Nru a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c --- a/drivers/char/vc_screen.c Thu Jan 15 11:05:48 2004 +++ b/drivers/char/vc_screen.c Thu Jan 15 11:05:48 2004 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -469,6 +470,8 @@ .open = vcs_open, }; +static struct class_simple *vc_class; + void vcs_make_devfs(struct tty_struct *tty) { devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 1), @@ -477,19 +480,26 @@ devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a%u", tty->index + 1); + class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1); + class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1); } void vcs_remove_devfs(struct tty_struct *tty) { devfs_remove("vcc/%u", tty->index + 1); devfs_remove("vcc/a%u", tty->index + 1); + class_simple_device_remove(MKDEV(VCS_MAJOR, tty->index + 1)); + class_simple_device_remove(MKDEV(VCS_MAJOR, tty->index + 129)); } int __init vcs_init(void) { if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) panic("unable to get major %d for vcs device", VCS_MAJOR); + vc_class = class_simple_create(THIS_MODULE, "vc"); devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0"); devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0"); + class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); + class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); return 0; } diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c --- a/drivers/char/vt.c Thu Jan 15 11:05:50 2004 +++ b/drivers/char/vt.c Thu Jan 15 11:05:50 2004 @@ -2539,6 +2539,8 @@ int __init vty_init(void) { + vcs_init(); + console_driver = alloc_tty_driver(MAX_NR_CONSOLES); if (!console_driver) panic("Couldn't allocate console driver\n"); @@ -2566,7 +2568,6 @@ #ifdef CONFIG_FRAMEBUFFER_CONSOLE fb_console_init(); #endif - vcs_init(); return 0; }