• 【Linux高级驱动】linux设备驱动模型之平台设备驱动机制


    【1:引言: linux字符设备驱动的基本编程流程】


    1.实现模块加载函数
      a.申请主设备号
        register_chrdev(major,name,file_operations);
      b.创建字符设备cdev,注册字符设备
        cdev_alloc cdev_init cdev_add
      c.创建设备文件
        class_create device_create
      d.注册中断
        ret =request_irq(中断号,...,...,...,...);
      e.映射
        虚拟地址=ioremap(物理地址,大小)
      f.初始化(初始化等待队列头,初始化tasklet,初始化工作队列)
      ...
    2.实现模块卸载函数
    3.构建file_operations结构体变量
    4.实现操作硬件的方法
      xxx_open xxx_write xxx_read



        为了提高驱动的可移植性,减少驱动开发周期,最好将跟硬件/平台相关的东西分离出来,以便增强驱动的可移植性

        中断号,物理地址----->归为设备资源

        最好将设备资源与设备驱动分离开来

                           平台设备驱动机制
    platform_device                             platform_driver
    设备资源(设备)           <------>            设备驱动

    【2:设备总线驱动模型:内核用来管理设备与驱动的一种方式】

        设备总线驱动模型:以对象的思想来实现的
        每一个设备对应唯一的一个驱动
        每个驱动则可能服务多个设备
        系统中有很多总线:1)实际的物理总线(如:i2c总线,usb总线,SDIO总线,SPI总线...)
                         2)虚拟总线(只有一条:平台总线)

    【对象思想】

    /*1.在系统用来表示一个设备*/
    struct device {
     struct device_driver *driver;  //设备驱动
     struct bus_type *bus;     //所属总线
     struct device  *parent;   //父设备
     dev_t   devt;     //设备号
     void  *platform_data;    //私有数据
     ....
    }

    /*2.在系统中用来表示设备驱动*/
    struct device_driver {
     const char  *name;   //驱动名字
     struct bus_type  *bus;  //所属总线
     struct module  *owner;  //拥有者
     int (*probe) (struct device *dev); //probe函数
    }

    /*3.在系统中用来表示总线*/
    struct bus_type {
     const char  *name;   //总线名字
     /*mach函数,匹配函数,每条总线里面都会有自己的
      *mach,但不同总线的mach的匹配方法可能会不同
      */

     int (*match)(struct device *dev, struct device_driver *drv);  
     
     /*当设备与驱动匹配成功的时候,便会调用probe函数
      *不过,一般总线中不会实现probe函数,在匹配成功
      *的时候,会直接调用设备驱动中的probe函数
      */

     int (*probe)(struct device *dev);
     int (*remove)(struct device *dev);
    }

    【设备总线驱动模型里面的操作函数】

    /*1.总线注册*/
    int bus_register(struct bus_type *bus)
    void bus_unregister(struct bus_type *bus)
    /*2.设备注册*/
    int device_register(struct device *dev)
    void device_unregister(struct device *dev)
    /*3.设备驱动注册*/
    int driver_register(struct device_driver *drv)
    void driver_unregister(struct device_driver *drv)

    【3:平台设备驱动机制】

    借助于设备总线驱动模型,虚拟出一条总线,用来实现设备资源与设备驱动的匹配
    ===============================================
    平台设备驱动机制采用了:分离的思想,对象的思想

                           分离的思想:设备资源与设备驱动分离开

    【对象思想】

    /*1.平台设备结构体*/
    struct platform_device {
     const char * name;     //名字
     int  id;
     struct device dev;    //设备结构体
     u32  num_resources;    //资源数量
     struct resource * resource;      //设备资源
     const struct platform_device_id *id_entry;
     /* arch specific additions */
     struct pdev_archdata archdata;
    };

    /*2.平台驱动结构体*/
    struct platform_driver {
     int (*probe)(struct platform_device *);  //probe函数
     int (*remove)(struct platform_device *);
     void (*shutdown)(struct platform_device *);
     int (*suspend)(struct platform_device *, pm_message_t state);
     int (*resume)(struct platform_device *);
     struct device_driver driver;  //设备驱动
     const struct platform_device_id *id_table;
    };

    /*3.虚拟总线:平台总线结构体*/
    struct bus_type platform_bus_type = {
     .name  = "platform",   //总线名字
     .dev_attrs = platform_dev_attrs,
     .match  = platform_match,  //匹配函数
     .uevent  = platform_uevent,
     .pm   = &platform_dev_pm_ops,
    };

    /*4.资源结构体*/
    struct resource {
     resource_size_t start;   //起始
     resource_size_t end;   //结束
     const char *name;    //名字
     unsigned long flags;   //标号
     struct resource *parent, *sibling, *child;
    };

    //平台设备驱动机制中如何来实现设备与驱动的匹配
    static int platform_match(struct device *dev, struct device_driver *drv)
    {
     struct platform_device *pdev = to_platform_device(dev);
     struct platform_driver *pdrv = to_platform_driver(drv);
     /* match against the id table first :可能支持多个设备*/
     if (pdrv->id_table)
      return platform_match_id(pdrv->id_table, pdev) != NULL;
     /*平台设备里面的名字,与设备驱动里面的名字匹配*/
     return (strcmp(pdev->name, drv->name) == 0);
    }

     

    【总线注册】

    /*内核启动时的第一个C语言入口函数*/
    start_kernel     //init/main.c
         rest_init
         /*创建一个内核线程*/
         kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);  
         kernel_init
              do_basic_setup   //init/main.c
               driver_init
                platform_bus_init
             /*1.注册平台总线*/
             bus_register(&platform_bus_type);

     

    【平台设备驱动模型的关键接口函数】

    /*1.注册平台设备*/
    int platform_device_register(struct platform_device *pdev)
    void platform_device_unregister(struct platform_device *pdev)

    /*2.注册平台驱动*/
    int platform_driver_register(struct platform_driver *drv)
    void platform_driver_unregister(struct platform_driver *drv)

    /*3.获取平台资源*/
    platform_get_resource(struct platform_device * dev, unsigned int type, unsigned int num)

    【linux设备驱动之设备总线驱动模型】

    【设备总线驱动模型】


    @成鹏致远(wwwlllll@126.com)

  • 相关阅读:
    JS BOM对象 History对象 Location对象
    JS 字符串对象 数组对象 函数对象 函数作用域
    JS 引入方式 基本数据类型 运算符 控制语句 循环 异常
    Pycharm Html CSS JS 快捷方式创建元素
    CSS 内外边距 float positio属性
    CSS 颜色 字体 背景 文本 边框 列表 display属性
    【Android】RxJava的使用(三)转换——map、flatMap
    【Android】RxJava的使用(二)Action
    【Android】RxJava的使用(一)基本用法
    【Android】Retrofit 2.0 的使用
  • 原文地址:https://www.cnblogs.com/lcw/p/3802579.html
Copyright © 2020-2023  润新知