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

简介:

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

转自:http://www.cnblogs.com/lcw/p/3802579.html
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)










本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/5066557.html,如需转载请自行联系原作者

目录
打赏
0
0
0
0
64
分享
相关文章
Linux平台Oracle开机自启动设置
【11月更文挑战第8天】在 Linux 平台设置 Oracle 开机自启动有多种方法,本文以 CentOS 为例,介绍了两种常见方法:使用 `rc.local` 文件(较简单但不推荐用于生产环境)和使用 `systemd` 服务(推荐)。具体步骤包括编写启动脚本、赋予执行权限、配置 `rc.local` 或创建 `systemd` 服务单元文件,并设置开机自启动。通过 `systemd` 方式可以更好地与系统启动过程集成,更规范和可靠。
322 2
Linux平台Oracle开机自启动设置
【11月更文挑战第7天】本文介绍了 Linux 系统中服务管理机制,并详细说明了如何在使用 systemd 和 System V 的系统上设置 Oracle 数据库的开机自启动。包括创建服务单元文件、编辑启动脚本、设置开机自启动和启动服务的具体步骤。最后建议重启系统验证设置是否成功。
102 1
Linux平台安装MongoDB
10月更文挑战第11天
137 5
|
5月前
|
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
160 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
7月前
|
Linux设备驱动开发详解2
Linux设备驱动开发详解
75 6
Linux设备驱动开发详解1
Linux设备驱动开发详解
97 5
Linux平台x86_64|aarch64架构RTMP推送|轻量级RTSP服务模块集成说明
支持x64_64架构、aarch64架构(需要glibc-2.21及以上版本的Linux系统, 需要libX11.so.6, 需要GLib–2.0, 需安装 libstdc++.so.6.0.21、GLIBCXX_3.4.21、 CXXABI_1.3.9)。
162 0
|
6月前
|
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
|
1月前
|
Linux系统之whereis命令的基本使用
Linux系统之whereis命令的基本使用
73 24
Linux系统之whereis命令的基本使用
|
4天前
|
Linux od命令
本文详细介绍了Linux中的 `od`命令,包括其基本语法、常用选项和示例。通过这些内容,你可以灵活地使用 `od`命令查看文件内容,提高分析和调试效率。确保理解每一个选项和示例的实现细节,应用到实际工作中时能有效地处理各种文件查看需求。
41 19
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等