免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 974 | 回复: 0
打印 上一主题 下一主题

linux驱动设备注册 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-07-01 11:06 |只看该作者 |倒序浏览
driver_register
               
               
               
                platform_add_devices
misc_registerlinux驱动程序常用的几个设备注册函数,详细解析待续.driver_register:
int driver_register(struct device_driver * drv){    if ((drv->bus->probe && drv->probe) ||//drv和drv所属的bus之中只要1个提供该函数即可,否则也只能调用bus的函数,而不理会drv的     (drv->bus->remove && drv->remove) ||     (drv->bus->shutdown && drv->shutdown)) {        printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);    }    klist_init(&drv->klist_devices, NULL, NULL);//将drv驱动上的设备链表清空    return bus_add_driver(drv);//将本drv驱动注册登记到drv->bus所在的总线上}
void klist_init(struct klist * k, void (*get)(struct klist_node *),        void (*put)(struct klist_node *)){    INIT_LIST_HEAD(&k->k_list);//链表初始化    spin_lock_init(&k->k_lock);//锁初始化    k->get = get;//引用计数操作自定义函数    k->put = put;}
int bus_add_driver(struct device_driver *drv){    struct bus_type * bus = get_bus(drv->bus);    int error = 0;    if (!bus)        return -EINVAL;    pr_debug("bus %s: add driver %s\n", bus->name, drv->name);    //kboj->name[KOBJ_NAME_LEN],如果KOBJ_NAME_LEN长度不够,会调用kmalloc申请    //之后kobj->k_name指针或者指向kboj->name或者指向kmalloc返回地址    error = kobject_set_name(&drv->kobj, "%s", drv->name);    if (error)        goto out_put_bus;    //bus->drivers为kset集合类型,也正是管理本drv->kobj的kset集合    drv->kobj.kset = &bus->drivers;    //gliethttp_20071025 kobject_register()简单理解    //把drv的kobj大张旗鼓的登记到管理它的kset集合上去,同时再根据层级关系创建相应的目录文件    //gliethttp_20071026    //注册登记该kobj,如果该kobj属于某个kset,那么将自己的entry节点挂接到该kset的list链表上,    //以示自己需要该kset的滋润,同时kobj->parent=&kset->kobj,parent指向kset用来管理自己的kobj    //如果该kobj不属于kset,而属于parent,那么简单的将parent的引用计数加1    //对于kobj属于某个kset的情况,可以实现kset向下查找kobj,也可以实现kobj向上查找kset    //对于kobj属于某个parent的情况,查找只能是单向的,只能kobj找到parent,parent不能查找    //该parent挂接的kobj们    //parent是用来明显建立亲子关系图的标志性变量,当然在kset也能若隐若现的显露出这种关系,    //但总不如parent正宗和高效    //之后调用create_dir()创建该kobj在sysfs中的目录文件    //最后调用kobject_uevent()将KOBJ_ADD事件通知到用户空间的守护进程    error = kobject_register(&drv->kobj);    if (error)        goto out_put_bus;    if (drv->bus->drivers_autoprobe) {    //gliethttp_20071025    //driver提供自动匹配函数,那么现在就遍历所有设备    //尝试将本driver匹配到相应设备上去        error = driver_attach(drv);        if (error)            goto out_unregister;    }    //将本driver链接到bus总线上的klist_drivers的klist链表结尾处    klist_add_tail(&drv->knode_bus, &bus->klist_drivers);    module_add_driver(drv->owner, drv);//gliethttp_20071026//所以一个驱动需要维持住1个klist链条和一个kobj层次结构--驱动drv->kobj对象,内核一方面使用该kobj在sysfs中建立//统一的与该kobj对应的目录对象供用户空间访问,另一方面使用该kobj的引用计数来获悉该kobj设备的繁忙与空闲情况,//当本kobj对象的引用计数到达0时,只要其他条件允许,那么说明集成本kobj的结构体对象不再使用,内核得知这个情况很重要,//因为这对内核进行进一步的决策提供了详细的证据资料,进而对物理设备进行细致的电源管理成了可能,//如:当hub1上的所有端口设备都被拔掉之后,hub1就可以安全的进入省电模式了,而这个功能在2.4内核中是找不到的.//如果从面向对象的角度来看待kset、kobj和driver的话,并不能清晰的说明问题,因为面向对象本身提供的封装、继承和多态//并不能很好的说明kset、kobj和driver之间存在的实际关系,多少都有一些出入,因为linux毕竟不是用c++写的,不像eCos那样,//虽然大家都努力借鉴面向对象的光辉思想来设计自己的程序,但是面向对象固有的若干弊端因素也是我们必须要剔除的,//所以剥丝抽茧之后,呈现出来的东西,大多将处于中间态,当然不排除走极端的少数,所以我觉得使用单纯的面向对象思想来理解//kset、kobj和driver这3者,最终都会带来理解上的麻烦,因为渗透在他们3者之间的设计思想与封装、继承、多态、类、//虚函数、属性、方法、类属性和类方法等只是相似,而且"仅仅相似,有些影子,但并不是!"//因此对于正常理解,最好抛弃单纯的面向对象方式(开始我就使用单纯的面向对象方式来理解,结果在若干单元上卡了壳儿,//现在想来很是可笑,因为那些单元根本就不是面向对象所具有的,硬是要用面向对象来解决,那完全是在牵强)//而是采用面向对象和c数据结构相结合的方式,//而且在结合过程中,为了减少麻烦,最好偏向c数据结构多一点(gliethttp_20071026小感).    //创建属性目录文件    error = driver_add_attrs(bus, drv);    if (error) {        /* How the hell do we get out of this pickle? Give up */        printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",            __FUNCTION__, drv->name);    }    error = add_bind_files(drv);    if (error) {        /* Ditto */        printk(KERN_ERR "%s: add_bind_files(%s) failed\n",            __FUNCTION__, drv->name);    }    return error;out_unregister:    kobject_unregister(&drv->kobj);out_put_bus:    put_bus(bus);    return error;}
platform_add_devices:
/**
*      platform_add_devices - add a numbers of platform devices
*      @devs: array of platform devices to add
*      @num: number of platform devices in array
*/
int platform_add_devices(struct platform_device **devs, int num)
{
        int i, ret = 0;
        for (i = 0; i                 ret = platform_device_register(devs);
                if (ret) {
                        while (--i >= 0)
                                platform_device_unregister(devs);
                        break;
                }
        }
        return ret;
}/**
*      platform_device_register - add a platform-level device
*      @pdev:  platform device we're adding
*
*/
int platform_device_register(struct platform_device * pdev)
{
        int i, ret = 0;
        if (!pdev)
                return -EINVAL;
        if (!pdev->dev.parent)
                pdev->dev.parent = &platform_bus;
        pdev->dev.bus = &platform_bus_type;
        if (pdev->id != -1)
                snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
        else
                strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
        for (i = 0; i num_resources; i++) {
                struct resource *p, *r = &pdev->resource;
                if (r->name == NULL)
                        r->name = pdev->dev.bus_id;
                p = r->parent;
                if (!p) {
                        if (r->flags & IORESOURCE_MEM)
                                p = &iomem_resource;
                        else if (r->flags & IORESOURCE_IO)
                                p = &ioport_resource;
                }
                if (p && request_resource(p, r)) {
                        printk(KERN_ERR
                               "%s: failed to claim resource %d\n",
                               pdev->dev.bus_id, i);
                        ret = -EBUSY;
                        goto failed;
                }
        }
        pr_debug("Registering platform device '%s'. Parent at %s\n",
                 pdev->dev.bus_id, pdev->dev.parent->bus_id);
        ret = device_register(&pdev->dev);
        if (ret == 0)
                return ret;
failed:
        while (--i >= 0)
                if (pdev->resource.flags & (IORESOURCE_MEM|IORESOURCE_IO))
                        release_resource(&pdev->resource);
        return ret;
}
/**
*      platform_device_unregister - remove a platform-level device
*      @pdev:  platform device we're removing
*
*      Note that this function will also release all memory- and port-based
*      resources owned by the device (@dev->resource).
*/
void platform_device_unregister(struct platform_device * pdev)
{
        int i;
        if (pdev) {
                for (i = 0; i num_resources; i++) {
                        struct resource *r = &pdev->resource;
                        if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO))
                                release_resource(r);
                }
                device_unregister(&pdev->dev);
        }
}
misc_register:
/**
*      misc_register   -       register a miscellaneous device
*      @misc: device structure
*
*      Register a miscellaneous device with the kernel. If the minor
*      number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
*      and placed in the minor field of the structure. For other cases
*      the minor number requested is used.
*
*      The structure passed is linked into the kernel and may not be
*      destroyed until it has been unregistered.
*
*      A zero is returned on success and a negative errno code for
*      failure.
*/
int misc_register(struct miscdevice * misc)
{
        static devfs_handle_t devfs_handle, dir;
        struct miscdevice *c;
        if (misc->next || misc->prev)
                return -EBUSY;
        down(&misc_sem);
        c = misc_list.next;
        while ((c != &misc_list) && (c->minor != misc->minor))
                c = c->next;
        if (c != &misc_list) {
                up(&misc_sem);
                return -EBUSY;
        }
        if (misc->minor == MISC_DYNAMIC_MINOR) {
                int i = DYNAMIC_MINORS;
                while (--i >= 0)
                        if ( (misc_minors[i>>3] & (1 7))) == 0)
                                break;
                if (i0)
                {
                        up(&misc_sem);
                        return -EBUSY;
                }
                misc->minor = i;
        }
        if (misc->minor                 misc_minors[misc->minor >> 3] |= 1 minor & 7);
        if (!devfs_handle)
                devfs_handle = devfs_mk_dir (NULL, "misc", NULL);
        dir = strchr (misc->name, '/') ? NULL : devfs_handle;
        misc->devfs_handle =
                devfs_register (dir, misc->name, DEVFS_FL_NONE,
                                MISC_MAJOR, misc->minor,
                                S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
                                misc->fops, NULL);
        /*
         * Add it to the front, so that later devices can "override"
         * earlier defaults
         */
        misc->prev = &misc_list;
        misc->next = misc_list.next;
        misc->prev->next = misc;
        misc->next->prev = misc;
        up(&misc_sem);
        return 0;
}/**
*      misc_deregister - unregister a miscellaneous device
*      @misc: device to unregister
*
*      Unregister a miscellaneous device that was previously
*      successfully registered with misc_register(). Success
*      is indicated by a zero return, a negative errno code
*      indicates an error.
*/
int misc_deregister(struct miscdevice * misc)
{
        int i = misc->minor;
        if (!misc->next || !misc->prev)
                return -EINVAL;
        down(&misc_sem);
        misc->prev->next = misc->next;
        misc->next->prev = misc->prev;
        misc->next = NULL;
        misc->prev = NULL;
        devfs_unregister (misc->devfs_handle);
        if (i 0) {
                misc_minors[i>>3] &= ~(1 minor & 7));
        }
        up(&misc_sem);
        return 0;
}
/**
*      devfs_register - Register a device entry.
*      @dir: The handle to the parent devfs directory entry. If this is %NULL the
*              new name is relative to the root of the devfs.
*      @name: The name of the entry.
*      @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
*      @major: The major number. Not needed for regular files.
*      @minor: The minor number. Not needed for regular files.
*      @mode: The default file mode.
*      @ops: The &file_operations or &block_device_operations structure.
*              This must not be externally deallocated.
*      @info: An arbitrary pointer which will be written to the @private_data
*              field of the &file structure passed to the device driver. You can set
*              this to whatever you like, and change it once the file is opened (the next
*              file opened will not see this change).
*
*      Returns a handle which may later be used in a call to devfs_unregister().
*      On failure %NULL is returned.
*/
devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
                               unsigned int flags,
                               unsigned int major, unsigned int minor,
                               umode_t mode, void *ops, void *info)
{
    char devtype = S_ISCHR (mode) ? DEVFS_SPECIAL_CHR : DEVFS_SPECIAL_BLK;
    int err;
    kdev_t devnum = NODEV;
    struct devfs_entry *de;
    if (name == NULL)
    {
        PRINTK ("(): NULL name pointer\n");
        return NULL;
    }
    if (ops == NULL)
    {
        if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major);
        if (ops == NULL)
        {
            PRINTK ("(%s): NULL ops pointer\n", name);
            return NULL;
        }
        PRINTK ("(%s): NULL ops, got %p from major table\n", name, ops);
    }
    if ( S_ISDIR (mode) )
    {
        PRINTK ("(%s): creating directories is not allowed\n", name);
        return NULL;
    }
    if ( S_ISLNK (mode) )
    {
        PRINTK ("(%s): creating symlinks is not allowed\n", name);
        return NULL;
    }
    if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) &&
         (flags & DEVFS_FL_AUTO_DEVNUM) )
    {
        if ( kdev_none ( devnum = devfs_alloc_devnum (devtype) ) )
        {
            PRINTK ("(%s): exhausted %s device numbers\n",
                    name, S_ISCHR (mode) ? "char" : "block");
            return NULL;
        }
        major = major (devnum);
        minor = minor (devnum);
    }
    if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
    {
        PRINTK ("(%s): could not prepare leaf\n", name);
        if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
        return NULL;
    }
    if ( S_ISCHR (mode) || S_ISBLK (mode) )
    {
        de->u.fcb.u.device.major = major;
        de->u.fcb.u.device.minor = minor;
        de->u.fcb.autogen = kdev_none (devnum) ? FALSE : TRUE;
    }
    else if ( !S_ISREG (mode) )
    {
        PRINTK ("(%s): illegal mode: %x\n", name, mode);
        devfs_put (de);
        devfs_put (dir);
        return (NULL);
    }
    de->info = info;
    if (flags & DEVFS_FL_CURRENT_OWNER)
    {
        de->inode.uid = current->uid;
        de->inode.gid = current->gid;
    }
    else
    {
        de->inode.uid = 0;
        de->inode.gid = 0;
    }
    de->u.fcb.ops = ops;
    de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
    de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE : FALSE;
    de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
    if (flags & DEVFS_FL_REMOVABLE) de->u.fcb.removable = TRUE;
    if ( ( err = _devfs_append_entry (dir, de, de->u.fcb.removable, NULL) )
         != 0 )
    {
        PRINTK ("(%s): could not append to parent, err: %d\n", name, err);
        devfs_put (dir);
        if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);
        return NULL;
    }
    DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"  pp: %p\n",
             name, de, dir, dir->name, dir->parent);
    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);
    devfs_put (dir);
    return de;
}   /*  End Function devfs_register  */


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/54524/showart_1982570.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP