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\n"
        形式保存设备编号),并以包含该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!\n");

            /**
             * 通过名字匹配设备和驱动,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!\n");
                goto err0;
            }

            ret = device_register(&up_dev);
            if(ret)
            {
                printk("device_register FAILED!\n");
                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.\n");

            return 0;
        }

        static int up_remove(struct device *dev)
        {
            printk("Remove.\n");

            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!\n");

            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!\n");

            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\n",
                       pdev->resource[i].start,
                       pdev->resource[i].end);
            }
            printk("==========================\n");
            printk("platform data.\n");
            printk("width = %d, height = %d\n%s\n",
                    pdata->w, pdata->h, pdata->name);

            return 0;
        }

        static int up_remove(struct platform_device *pdev)
        {
            printk("In %s func.\n", __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!\n");

            return ret;
        }

        void __exit test_exit(void)
        {
            platform_driver_unregister(&pdrv);
        }

        module_init(test_init);
        module_exit(test_exit);
        MODULE_LICENSE("GPL");

 

时间: 2024-09-18 03:44:28

Samsung_tiny4412(驱动笔记10)----mdev,bus,device,driver,platform的相关文章

Samsung_tiny4412(驱动笔记01)----linux 3.5,U-Boot,Busybox,SD卡启动环境搭建

/*********************************************************************************** * * linux 3.5,U-Boot,Busybox,SD卡启动环境搭建 * * 声明: * 1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会 * 不对齐,从而影响阅读. * 2. 以下所有的shell命令都是在root权限下运行的; * 3. minicom(U-Boot)指的是用minico

Samsung_tiny4412(驱动笔记04)----volatile,container_of,file_operations,file,inode

/*********************************************************************************** * * volatile,container_of,file_operations,file,inode * * 声明: * 1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会 * 不对齐,从而影响阅读. * 2. 本文的结构体的注释主要是参考网络上的解释,几乎无任何个人理解,主要是为后续 * 代码编

Samsung_tiny4412(驱动笔记03)----字符设备驱动基本操作及调用流程

/*********************************************************************************** * * 字符设备驱动基本操作及调用流程 * * 声明: * 1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会 * 不对齐,从而影响阅读. * 2. 以下所有的shell命令都是在root权限下运行的; * * 2015-3-7 阴 深圳 尚观 Sbin 曾剑锋 *******************

Samsung_tiny4412(驱动笔记06)----list_head,proc file system,GPIO,ioremap

/**************************************************************************** * * list_head,proc file system,GPIO,ioremap * * 声明: * 1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会 * 不对齐,从而影响阅读. * 2. 本文中有些源代码没有全部帖出来,主要是因为篇幅太大的原因; * 3. 基于2中的原因,本文借鉴了python中的缩进代

Samsung_tiny4412(驱动笔记09)----alloc_pages,kmalloc,vmalloc,kmem_cache,class

/*********************************************************************************** * * alloc_pages,kmalloc,vmalloc,kmem_cache,class * * 声明: * 1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会 * 不对齐,从而影响阅读. * 2. 本文中有些源代码没有全部帖出来,主要是因为篇幅太大的原因; * 3. 基于2中的原因,本文借鉴

Samsung_tiny4412(驱动笔记02)----ASM with C,MMU,Exception,GIC

/**************************************************************************** * * ASM with C,MMU,Exception,GIC * * 声明: * 1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会 * 不对齐,从而影响阅读. * 2. 以下所有的shell命令都是在root权限下运行的; * 3. 文中在需要往文件中写入内容的时候使用了如下2方式: * 1.如果文件不存在,

Samsung_tiny4412(驱动笔记05)----Makefile,open,read,write,lseek,poll,ioctl,fasync

/*********************************************************************************** * * Makefile,open,read,write,lseek,poll,ioctl,fasync * * 声明: * 1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会 * 不对齐,从而影响阅读. * * * 2015-3-9 阴 深圳 尚观 Var 曾剑锋 *****************

I.MX6 Linux I2C device&amp; driver hacking

/******************************************************************************************* * I.MX6 Linux I2C device& driver hacking * 声明: * 1. 本文主要是对Linux I2C驱动进行代码跟踪,主要是为了能够对I2C驱动框架有个全面的了解: * 2. 本文源代码来自myzr_android4_2_2_1_1_0.tar.bz2: * 3. 如果你有兴趣,

I.MX6 ar1020 SPI device driver hacking

/************************************************************************************ * I.MX6 ar1020 SPI device driver hacking * 声明: * 1. 本文主要是解读I.MX6中ar1020 SPI设备注册,以及驱动调用流程: * 2. 本文主要使用了vim+ctags进行代码跟踪,所以几乎都是函数原型之间的调用: * * 2015-9-5 晴 深圳 南山平山村 曾剑锋 *