zoukankan      html  css  js  c++  java
  • 【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)

  • 相关阅读:
    query and join operation after sharding
    Windows Phone中的几种集合控件
    什么是SOPA SOPA的危害
    自动刷新人人网API session_key方法
    Windows Phone XNA创建简单局域网游戏
    static 修饰MySqlConnection引发的异常
    $Dsu$ $on$ $Tree$ 复习
    $Noip$前的小总结哦
    $NOIP2018$ 暴踩全场计划实施方案
    $NOIP2018$ 爆踩全场记
  • 原文地址:https://www.cnblogs.com/lcw/p/3802579.html
Copyright © 2011-2022 走看看