• Samsung_tiny4412(驱动笔记10)----mdev,bus,device,driver,platform


    /***********************************************************************************
     *                    
     *                           mdev,bus,device,driver,platform
     *
     *   声明:
     *       1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会
     *          不对齐,从而影响阅读.
     *       2. 由于本人水平有限,很难阐述清楚bus device driver platform的关系
     *          所以强烈要求您详细参考本次提供的预热文章.
     *
     *
     *                                          2015-3-21 晴 深圳 尚观 Opt 曾剑锋
     **********************************************************************************/
    
                            \\\\\--*目录*--//////////
                            |  一. 预热文章:              
                            |  二. mdev 原理及配置:       
                            |  三. bus device driver接口: 
                            |  四. platform bus接口       
                            \\\\\\\////////////////
    
    一. 预热文章:
        1. linux设备驱动模型(上):
            http://m.blog.csdn.net/blog/zhuzongwei1988/5785461
        2. [嵌入式Linux学习七步曲之第四篇 Linux内核移植]详解Linux2.6内核中
            基于platform机制的驱动模型:
            http://blog.csdn.net/sailor_8318/article/details/5267698
        3. [嵌入式Linux学习七步曲之第五篇 Linux内核移植]PowerPC+Linux2.6.25平台
            下的I2C驱动架构分析:
            http://blog.csdn.net/sailor_8318/article/details/5905988
        4. [嵌入式Linux学习七步曲之第五篇 Linux内核移植]PowerPC+Linux2.6.25平台
            下的SPI驱动架构分析:
            http://blog.csdn.net/sailor_8318/article/details/5977733
    
    二. mdev 原理及配置:
        1. 在/etc/init.d/rcS中最后执行命令:
            #采用设备模型进行创建设备节点的必须加上,热插拔处理
            echo "/sbin/mdev" > /proc/sys/kernel/hotplug
            mdev -s
        2. mdev扫描/sys/lock(块设备保存在/sys/block目录下,2.6.25版本以后,块设备也保存在
            /sys/class/block目录下.mdev扫描/sys/block是为了实现向后兼容和/sys/class两个
            目录下的dev属性文件,从该dev属性文件中获取设备编号(dev属性文件以"major:minor
    "
            形式保存设备编号),并以包含该dev属性文件的目录名称作为设备名device_name(即包含
            dev属性文件的目录为device_name,而/sys/class和/device_name之间的那部分目录称为
            subsystem,也就是每个dev属性文件所在的路径都可表示/sys/class/subsystem/device_name/dev),
        3. 并在/dev目录下创建相应的设备文件.例如:
            cat /sys/class/tty/tty0/dev会得到4:0,subsystem为tty,device_name为tty0.
        4. 系统运行起来以后,每次创建新的节点的时候都会调用mdev,并根据/etc/mdev.conf文件
            做相应的事,如果配置中没有对应的配置,那就按常规处理:
            cat > /etc/mdev.conf << EOF
            misc_dev            0:0     0600    =test/my_device
            event.*             0:0     0600    =input/
            mice                0:0     0600    =input/
            mouse0              0:0     0600    =input/
            dsp                 0:0     0600    =sound/
            sdb[0-9]            0:0     0644    * /sbin/auto_mount
            EOF
            配置解析:
            1. 格式: <device regex> <uid>:<gid> <octal permissins> [<@|$|*> <command>]
                1. @在创建设备节点后运行命令;
                2. $在删除设备节点前运行命令;
                3. *创建设备节点后和创建设干杯节点前都会运行命令;
            2. =input: 表示将mice放在/dev/input目录下;
            3. =test/my_device: 表示将misc_dev改名字为my_device,并放在/dev/test目录下;
        5. 按照上面的操作,可以实现U盘的自动挂载.
    
    三. bus device driver接口:
        1. 总线注册:
            struct bus_type bus;
            bus_register(&bus);
        2. 总线注销:
            bus_unregister(&bus);
        3. 设备注册:
            struct device dev;
            device_register(&dev);
        4. 设备注销:
            device_unregister(&dev);
        5. 驱动注册:
            struct device_driver drv;
            driver_register(&drv);
        6. 驱动注销:
            driver_unregister(&drv);
        7. bus device接口实例Demo:
            ...
            //总线通过match函数决定总线匹配规则,返回0代表匹配失败
            int up_match(struct device *dev, struct device_driver *drv)
            {
                printk("try to match!
    ");
            
                /** 
                 * 通过名字匹配设备和驱动,init_name中的值会赋给kobj.name
                 * 并且init_name中的值会变成NULL,所以如果要通过名字匹配
                 * 设备驱动,需要比较的是dev->kobj.name和drv->name的值.
                 * 如下方式是错误的:
                 *     return !strcmp(dev->init_name, drv->name);
                 */
                return !strcmp(dev->kobj.name, drv->name);
            }
            
            struct bus_type up_bus = {
                .name   = "niubi_bus",
                .match  = up_match,
            };
            EXPORT_SYMBOL(up_bus);
            
            void test_release(struct device *dev)
            {
            }
            
            struct device up_dev = {
                .init_name  = "bus_device",
                .release    = test_release,
            };
            EXPORT_SYMBOL(up_dev);
            
            int __init test_init(void)
            {
                int ret;
            
                ret = bus_register(&up_bus);
                if(ret)
                {
                    printk("bus_register FAILED!
    ");
                    goto err0;
                }
            
                ret = device_register(&up_dev);
                if(ret)
                {
                    printk("device_register FAILED!
    ");
                    goto err1;
                }
            
                return ret;
            
            err1:
                bus_unregister(&up_bus);
            err0:
                return ret;
            }
            
            void __exit test_exit(void)
            {
                bus_unregister(&up_bus);
            }
            ...
        
        8. device_driver接口实例Demo:
            ...
            extern struct bus_type up_bus;
            
            //dev指向匹配的设备结构
            static int up_probe(struct device *dev)
            {
                printk("Probe.
    ");
            
                return 0;
            }
            
            static int up_remove(struct device *dev)
            {
                printk("Remove.
    ");
            
                return 0;
            }
            
            struct device_driver drv = {
                .owner  = THIS_MODULE,
                .name   = "niubi_dev", //match的时候要用到
                .bus    = &up_bus,
                .probe  = up_probe,
                .remove = up_remove,
            };
            
            int __init test_init(void)
            {
                int ret;
                ret = driver_register(&drv);
                if(ret)
                    printk("driver_register FAILED!
    ");
            
                return ret;
            }
            
            void __exit test_exit(void)
            {
                driver_unregister(&drv);
            }
            ...
    
    四. platform bus接口
        1. 注册平台设备:
            struct platform_device pdev;
            platform_device_register(&dev);
        2. 注销平台设备:
            platform_device_unregister(&dev);
        3. 注册平台驱动:
            struct platform_driver pdrv;
            platform_driver_register(&pdrv);
        4. 注销平台驱动:
            platform_driver_unregister(&pdrv);
    
        5. platform_device接口Demo:
    
            #include <linux/module.h>
            #include <linux/platform_device.h>
            
            //定义自己的平台数据结构
            struct my_platform_data {
                int w;
                int h;
                char name[20];
            };
            
            struct my_platform_data pdata = {
                .w      = 800,
                .h      = 480,
                .name   = "lcd_screen",
            };
            
            struct resource res[] = {
                [0] = {
                    .start  = 0x10000000,
                    .end    = 0x10000000 + SZ_128 - 1,
                    .flags  = IORESOURCE_MEM,
                },
                [1] = {
                    .start  = 0x20000000,
                    .end    = 0x20000000 + SZ_128 - 1,
                    .flags  = IORESOURCE_MEM,
                },
                [2] = {
                    .start  = 0x30,
                    .end    = 0x30,
                    .flags  = IORESOURCE_IRQ,
                },
            };
            
            void test_release(struct device *dev)
            {
            }
            
            //设备的resource保存在设备结构里
            struct platform_device pdev = {
                .name   = "device_v3",
                .id     = -1,
                .dev    = {
                    .release        = test_release,
                    .platform_data  = &pdata,
                },
                .num_resources  = ARRAY_SIZE(res),
                .resource       = res,
            };
            
            int __init test_init(void)
            {
                int ret;
                ret = platform_device_register(&pdev);
                if(ret)
                    printk("platform_device_register FAILED!
    ");
            
                return ret;
            }
            
            void __exit test_exit(void)
            {
                platform_device_unregister(&pdev);
            }
            
            module_init(test_init);
            module_exit(test_exit);
            MODULE_LICENSE("GPL");
    
        6. platform_device接口Demo:
    
            #include <linux/module.h>
            #include <linux/platform_device.h>
            
            //定义自己的平台数据结构
            struct my_platform_data {
                int w;
                int h;
                char name[20];
            };
            
            static int up_probe(struct platform_device *pdev)
            {
                int i;
                struct my_platform_data *pdata = pdev->dev.platform_data;
            
                for(i = 0; i < pdev->num_resources; i++)
                {
                    printk("start = %x, end = %x
    ",
                           pdev->resource[i].start,
                           pdev->resource[i].end);
                }
                printk("==========================
    ");
                printk("platform data.
    ");
                printk("width = %d, height = %d
    %s
    ",
                        pdata->w, pdata->h, pdata->name);
            
                return 0;
            }
            
            static int up_remove(struct platform_device *pdev)
            {
                printk("In %s func.
    ", __func__);
            
                return 0;
            }
            
            //最后一个元素清0
            struct platform_device_id up_ids[] = {
                {"device_v1", 1},
                {"device_v2", 2},
                {"device_v3", 3},
                {"device_v4", 4},
                {"device_v5", 5},
                {},
            };
            
            //使用id_table和设备匹配
            struct platform_driver pdrv = {
                .probe  = up_probe,
                .remove = up_remove,
                .driver = {
                    .name   = "xxxxxxx",
                    .owner  = THIS_MODULE,
                },
                .id_table = up_ids,
            };
            
            int __init test_init(void)
            {
                int ret;
                ret = platform_driver_register(&pdrv);
                if(ret)
                    printk("platform_driver_register FAILED!
    ");
            
                return ret;
            }
            
            void __exit test_exit(void)
            {
                platform_driver_unregister(&pdrv);
            }
            
            module_init(test_init);
            module_exit(test_exit);
            MODULE_LICENSE("GPL");
  • 相关阅读:
    JSP脚本及指令
    Servlet处理请求业务
    JSP隐式对象
    JavaWeb HttpSession应用
    【刷题】排队接水(水题妙解)
    【刷题】【cf】B. Card Constructions
    【刷题】【cf】D1. Game on Sum (Easy Version)
    【刷题】【stl】最大(连续)子序列之和
    【笔记】STL的七种武器(一)顺序容器
    【刷题】【stl】扑克游戏
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/4356744.html
Copyright © 2020-2023  润新知