From 0bf42c80884fbe98349645304d5949ef0fd2e95a Mon Sep 17 00:00:00 2001 From: xiphmont Date: Fri, 19 Jan 2007 17:13:16 +0000 Subject: [PATCH] Add code to crawl sysfs to find preexisting classes; now we can register multiple devices of the same type for classes other than just 'sound' git-svn-id: http://svn.xiph.org/trunk/fusd@12352 0101bb08-14d6-0310-b084-bc0e0c8e3800 --- kfusd/kfusd.c | 222 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 147 insertions(+), 75 deletions(-) diff --git a/kfusd/kfusd.c b/kfusd/kfusd.c index 1a020ec..aa32752 100755 --- a/kfusd/kfusd.c +++ b/kfusd/kfusd.c @@ -37,6 +37,7 @@ * Jeremy Elson * Copyright (c) 2001, Sensoria Corporation * Copyright (c) 2002-2003, Regents of the University of California + * Copyright (c) 2007 Monty and Xiph.Org * * $Id$ */ @@ -127,14 +128,25 @@ #endif +static inline struct kobject * to_kobj(struct dentry * dentry) +{ + struct sysfs_dirent * sd = dentry->d_fsdata; + if(sd) + return ((struct kobject *) sd->s_element); + else + return NULL; +} + +#define to_class(obj) container_of(obj, struct class, subsys.kset.kobj) + /**************************************************************************/ #include "fusd.h" #include "fusd_msg.h" #include "kfusd.h" -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) -# error "***FUSD doesn't work before Linux Kernel v2.6.0" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) +# error "***FUSD doesn't work before Linux Kernel v2.6.13" #endif STATIC struct cdev* fusd_control_device; @@ -1908,6 +1920,11 @@ STATIC int fusd_polldiff_reply(fusd_dev_t *fusd_dev, fusd_msg_t *msg) return 0; } +STATIC int systest (struct super_block *sb,void *data){ + return 1; + +} + STATIC int fusd_register_device(fusd_dev_t *fusd_dev, register_msg_t register_msg) { @@ -1921,10 +1938,6 @@ STATIC int fusd_register_device(fusd_dev_t *fusd_dev, return -EINVAL; } - /* user can only register one device per instance */ -// if (fusd_dev->handle != 0) -// return -EBUSY; - register_msg.name[FUSD_MAX_NAME_LENGTH] = '\0'; /* make sure that there isn't already a device by this name */ @@ -1958,83 +1971,143 @@ STATIC int fusd_register_device(fusd_dev_t *fusd_dev, return -ENOMEM; } - strcpy(fusd_dev->class_name, register_msg.clazz); + strcpy(fusd_dev->class_name, register_msg.clazz); /* allocate memory for the class name, and copy */ if ((fusd_dev->dev_name = KMALLOC(strlen(register_msg.devname)+1, GFP_KERNEL)) == NULL) { RDEBUG(1, "yikes! kernel can't allocate memory"); return -ENOMEM; } - - strcpy(fusd_dev->dev_name, register_msg.devname); + + strcpy(fusd_dev->dev_name, register_msg.devname); + + dev_id = 0; + + if((error = alloc_chrdev_region(&dev_id, 0, 1, fusd_dev->name)) < 0) + { + printk(KERN_ERR "alloc_chrdev_region failed status: %d\n", error); + goto register_failed; + } + + fusd_dev->dev_id = dev_id; + + fusd_dev->handle = cdev_alloc(); + if(fusd_dev->handle == NULL) + { + printk(KERN_ERR "cdev_alloc() failed\n"); + error = -ENOMEM; + goto register_failed3; + } + + fusd_dev->handle->owner = THIS_MODULE; + fusd_dev->handle->ops = &fusd_client_fops; + + kobject_set_name(&fusd_dev->handle->kobj, fusd_dev->name); + + if((error = cdev_add(fusd_dev->handle, dev_id, 1)) < 0) + { + printk(KERN_ERR "cdev_add failed status: %d\n", error); + kobject_put(&fusd_dev->handle->kobj); + goto register_failed3; + } - dev_id = 0; + /* look up class in sysfs */ - if((error = alloc_chrdev_region(&dev_id, 0, 1, fusd_dev->name)) < 0) - { - printk(KERN_ERR "alloc_chrdev_region failed status: %d\n", error); - goto register_failed; + { + struct CLASS *sys_class = NULL; + struct file_system_type *sysfs = get_fs_type("sysfs"); + struct dentry *classdir = NULL; + struct dentry *classdir2 = NULL; + struct super_block *sb = NULL; + + if(sysfs){ + sb = sget (sysfs, systest, NULL,NULL); + + /* because put_filesystem isn't exported */ + module_put(sysfs->owner); + + if(sb){ + struct dentry *root = sb->s_root; + + if(root){ + struct qstr name; + + name.name = "class"; + name.len = 5; + name.hash = full_name_hash(name.name, name.len); + classdir = d_lookup(root, &name); + + if(classdir){ + name.name = register_msg.clazz; + name.len = strlen(name.name); + name.hash = full_name_hash(name.name, name.len); + classdir2 = d_lookup(classdir, &name); + + if(classdir2){ + // jackpot. extract the class. + struct kobject *ko = to_kobj(classdir2); + sys_class = (ko?to_class(ko):NULL); + + if(!sys_class) + RDEBUG(2, "WARNING: sysfs entry for %s has no kobject!\n",register_msg.clazz); + } + }else{ + RDEBUG(2, "WARNING: sysfs does not list a class directory!\n"); + } + }else{ + RDEBUG(2, "WARNING: unable to access root firectory in sysfs!\n"); } - - fusd_dev->dev_id = dev_id; - - fusd_dev->handle = cdev_alloc(); - if(fusd_dev->handle == NULL) + }else{ + RDEBUG(2, "WARNING: unable to access superblock for sysfs!\n"); + } + }else{ + RDEBUG(2, "WARNING: sysfs not mounted or unavailable!\n"); + } + + if(sys_class){ + RDEBUG(3, "Found entry for class '%s' in sysfs\n",register_msg.clazz); + fusd_dev->clazz = sound_class; + fusd_dev->owns_class = 0; + }else{ + RDEBUG(3, "Sysfs has no entry for '%s'; registering new class\n",register_msg.clazz); + fusd_dev->clazz = class_create(THIS_MODULE, fusd_dev->class_name); + if(IS_ERR(fusd_dev->clazz)) { - printk(KERN_ERR "cdev_alloc() failed\n"); - error = -ENOMEM; - goto register_failed3; + error = PTR_ERR(fusd_dev->clazz); + printk(KERN_ERR "class_create failed status: %d\n", error); + goto register_failed4; } + fusd_dev->owns_class = 1; + } - fusd_dev->handle->owner = THIS_MODULE; - fusd_dev->handle->ops = &fusd_client_fops; - - kobject_set_name(&fusd_dev->handle->kobj, fusd_dev->name); - - if((error = cdev_add(fusd_dev->handle, dev_id, 1)) < 0) - { - printk(KERN_ERR "cdev_add failed status: %d\n", error); - kobject_put(&fusd_dev->handle->kobj); - goto register_failed3; - } - - // Hack to add my class to the sound class - if(strcmp("sound", register_msg.clazz) == 0) - { - fusd_dev->clazz = sound_class; - fusd_dev->owns_class = 0; - } - else - { - fusd_dev->clazz = class_create(THIS_MODULE, fusd_dev->class_name); - if(IS_ERR(fusd_dev->clazz)) - { - error = PTR_ERR(fusd_dev->clazz); - printk(KERN_ERR "class_create failed status: %d\n", error); - goto register_failed4; - } - fusd_dev->owns_class = 1; - } - - fusd_dev->class_device = CLASS_DEVICE_CREATE(fusd_dev->clazz, NULL, fusd_dev->dev_id, NULL, fusd_dev->dev_name); - if(fusd_dev->class_device == NULL) - { - error = PTR_ERR(fusd_dev->class_device); - printk(KERN_ERR "class_device_create failed status: %d\n", error); - goto register_failed5; - } - - /* make sure the registration was successful */ - /* + if(classdir) + dput(classdir); + if(classdir2) + dput(classdir2); + + if(sb){ + up_write(&sb->s_umount); + deactivate_super(sb); + } + } + + fusd_dev->class_device = CLASS_DEVICE_CREATE(fusd_dev->clazz, NULL, fusd_dev->dev_id, NULL, fusd_dev->dev_name); + if(fusd_dev->class_device == NULL) + { + error = PTR_ERR(fusd_dev->class_device); + printk(KERN_ERR "class_device_create failed status: %d\n", error); + goto register_failed5; + } + + /* make sure the registration was successful */ if (fusd_dev->handle == 0) { error = -EIO; goto register_failed; } - */ - + /* remember the user's private data so we can pass it back later */ fusd_dev->private_data = register_msg.device_info; - + /* everything ok */ fusd_dev->version = atomic_inc_and_ret(&last_version); RDEBUG(3, "pid %d registered /dev/%s v%ld", fusd_dev->pid, NAME(fusd_dev), @@ -2133,16 +2206,15 @@ STATIC int fusd_release(struct inode *inode, struct file *file) } #endif - if(fusd_dev->handle) - { - class_device_destroy(fusd_dev->clazz, fusd_dev->dev_id); - if(fusd_dev->owns_class) - { - class_destroy(fusd_dev->clazz); - } - cdev_del(fusd_dev->handle); - unregister_chrdev_region(fusd_dev->dev_id, 1); - } + if(fusd_dev->handle){ + class_device_destroy(fusd_dev->clazz, fusd_dev->dev_id); + if(fusd_dev->owns_class) + { + class_destroy(fusd_dev->clazz); + } + cdev_del(fusd_dev->handle); + unregister_chrdev_region(fusd_dev->dev_id, 1); + } /* mark the driver as being gone */ zombify_dev(fusd_dev);