此篇是驱动分离(总线、驱动和设备模型)的应用扩展,主要简述platform虚拟总线平台

  • 一个现实的Linux设备和驱动通常挂接在一种总线上,对于本身依附于PCI、USB、I2C、SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC内存空间的外设等却不依附于此类总线。基于这个背景,Linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform device,驱动称为platform driver。

  • 从Linux 2.6起引入了一套新的驱动管理和注册机制,platform_device和platform_driver,Linux中大部分的设备驱动都可以使用这套机制。

  • platform是一条虚拟的总线。设备用platform_device表示,驱动用platform_driver进行注册,Linux platform driver机制和传统的device driver机制(通过driver_register进行注册)相比,一个明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动中使用这些资源时通过platform device提供的标准结构进行申请并使用。这样提高了驱动和资源的独立性,并且具有较好的可移植性和安全性。

  • pltform机制本身使用并不复杂,由两部分组成:platform_device和platform_driver。不用设备树的时候通过platform机制开发底层驱动的大致流程为:定义platform_deive->注册platform_device->定义platform_driver->注册platform_driver。

  • 再使用设备树的时候,设备的描述被放到了设备树中,因此platform_device就不需要我去编写了,只需要实现platform_driver即可。

1. platform总线

总线(IIC、SPI、USB等),platform应该叫做虚拟总线

  • platfom总线的目的就是当我们将设备和驱动注册到虚拟总线上(内核)时,如果该设备是该驱动的设备,该驱动是该设备的驱动,在他们注册时,会互相寻找一次对方(只在注册的时候寻找一次,找完了就玩了)。
  • 注意:设备和驱动的关系是多对一的关系,即多个相同设备可使用一个driver,靠device(设备)中的id号来,好处是总线驱动是通用的
/******************************
***bus_type结构体表示总线*******
******************************/struct bus_type { const char      *name;                         /* 总线名字   */ const char      *dev_name;                   struct device       *dev_root; struct device_attribute *dev_attrs;  const struct attribute_group **bus_groups;    /* 总线属性 */ const struct attribute_group **dev_groups;    /* 设备属性   */ const struct attribute_group **drv_groups;    /* 驱动属性   */ int (*match)(struct device *dev, struct device_driver *drv); //很重要*******int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); int (*online)(struct device *dev); int (*offline)(struct device *dev); /*
@  platform总线是bus_type的一个具体实例
@  platform_bus_type就是platform平台总线
*/
struct bus_type platform_bus_type = { .name         = "platform", .dev_groups   = platform_dev_groups, .match        = platform_match, .uevent       = platform_uevent, .pm           = &platform_dev_pm_ops,
}/*****************************************
@  匹配函数的四种方式
@  第一种:OF类型的匹配(设备树采用的匹配方式)
@  第二种:ACPI匹配方式
@  第三种:id_table匹配
@  第四种:比较驱动和设备的name字段,看看是不是相等(用的最多)
********************************************/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); /*When driver_override is set,only bind to the matching driver*/ if (pdev->driver_override)  return !strcmp(pdev->driver_override, drv->name); /* Attempt an OF style match first */ if (of_driver_match_device(dev, drv))     return 1; /* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; /* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; /* fall-back to driver name match */ return (strcmp(pdev->name, drv->name) == 0);
}

2.platform_device

  • 如果内核支持设备树的话,我们就直接用设备树去描述,就可以不再使用platform_device来描述设备了
/*
@  platform_device 结构体
*/
struct platform_device { const char  *name;   //保证device和driver的name is sameint     id;              bool        id_auto; struct device   dev; u32     num_resources;   struct resource *resource; const struct platform_device_id *id_entry; char *driver_override; /* Driver name to force a match */ /* MFD cell pointer */ struct mfd_cell *mfd_cell; /* arch specific additions */ struct pdev_archdata    archdata;
}; /******************
@  resource结构体
@  即是设备信息,比如外设寄存器等
@  start和end为资源的起始和终止信息,对于内存类资源就是起始和终止的地址
*******************/resource_size_t   start; resource_size_t   end; const char     *name; unsigned long     flags; struct resource   *parent, *sibling, *child; }; /************
@  资源类型
@  上面的flag
***********/#define IORESOURCE_BITS         0x000000ff  /* Bus-specific bits */ #define IORESOURCE_TYPE_BITS  0x00001f00  /* Resource type   */ #define IORESOURCE_IO          0x00000100  /* PCI/ISA I/O ports */ #define IORESOURCE_MEM         0x00000200 #define IORESOURCE_REG         0x00000300  /* Register offsets */ #define IORESOURCE_IRQ         0x00000400 #define IORESOURCE_DMA         0x00000800 #define IORESOURCE_BUS         0x00001000
... /* PCI control bits.  Shares IORESOURCE_BITS with above PCI ROM.  */#define IORESOURCE_PCI_FIXED     (1<<4)  /* Do not move resource */
  • 下面是platform_device设备信息框架不支持设备树
  • 放在文件里描述了
/* 寄存器地址定义*/
#define PERIPH1_REGISTER_BASE    (0X20000000) /* 外设 1 寄存器首地址 */
#define PERIPH2_REGISTER_BASE    (0X020E0068) /* 外设 2 寄存器首地址 */
#define REGISTER_LENGTH           4 /* 资源 */
static struct resource xxx_resources[] = { [0] = { .start  = PERIPH1_REGISTER_BASE, .end    = (PERIPH1_REGISTER_BASE + REGISTER_LENGTH - 1), .flags  = IORESOURCE_MEM, },   [1] = { .start  = PERIPH2_REGISTER_BASE, .end    = (PERIPH2_REGISTER_BASE + REGISTER_LENGTH - 1), .flags  = IORESOURCE_MEM, },
}; /* platform 设备结构体 */
static struct platform_device xxxdevice = { .name = "xxx-gpio", .id = -1, .num_resources = ARRAY_SIZE(xxx_resources), .resource = xxx_resources,
}; /* 设备模块加载 */
static int __init xxxdevice_init(void)
{ return platform_device_register(&xxxdevice);
} /* 设备模块注销 */
static void __exit xxx_resourcesdevice_exit(void)
{ platform_device_unregister(&xxxdevice);
} module_init(xxxdevice_init);
module_exit(xxxdevice_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");

3. platform_driver

  • 总的来说,platform驱动还是传统的字符设备、块设备驱动或者网络设备驱动。
  • 只是套上了一张“platform的皮”
  • 目的是为了是使用总线、驱动和设备这个驱动模型来实现驱动的分离和分层。
/**************************************
@  platform_driver结构体表示platform驱动
***************************************/struct platform_driver { int (*probe)(struct platform_device *); //非常主要,只要匹配就会立即执行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; //第三种匹配方式bool prevent_deferred_probe; };/**************************
@  platform_device_id结构体
***************************/struct platform_device_id { char name[PLATFORM_NAME_SIZE]; kernel_ulong_t driver_data; }; /*********************
@  device_driver结构体
**********************/struct device_driver { const char          *name; struct bus_type       *bus; struct module         *owner; const char          *mod_name;  /* used for built-in modules */ bool suppress_bind_attrs;   /* disables bind/unbind via sysfs */ const struct of_device_id       *of_match_table; //用设备树的时候驱动使用的匹配表,同样是数组,const struct acpi_device_id     *acpi_match_table; int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); const struct attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; }; /**********************
@  of_device_id 结构体
**********************/struct of_device_id { char        name[32]; char        type[32]; char        compatible[128]; //非常重要,设备树相关const void   *data; };

下面是platform驱动框架

/* 设备结构体 */ struct xxx_dev{ struct cdev cdev; /* 设备结构体其他具体内容 */ }; struct xxx_dev xxxdev;   /* 定义个设备结构体变量 */ static int xxx_open(struct inode *inode, struct file *filp) {     /* 函数具体内容 */ return 0; } static ssize_t xxx_write(struct file *filp, const char __user *buf,
size_t cnt, loff_t *offt) { /* 函数具体内容 */ return 0; } /* * 字符设备驱动操作集 */ static struct file_operations xxx_fops = { .owner = THIS_MODULE, .open = xxx_open, .write = xxx_write, }; /* * platform 驱动的 probe 函数 * 驱动与设备匹配成功以后此函数就会执行 */ static int xxx_probe(struct platform_device *dev) {     ...... cdev_init(&xxxdev.cdev, &xxx_fops); /* 注册字符设备驱动 */ /* 函数具体内容 */ return 0; } static int xxx_remove(struct platform_device *dev) { ...... cdev_del(&xxxdev.cdev);/*  删除 cdev */ /* 函数具体内容 */ return 0; } static int xxx_remove(struct platform_device *dev) { ...... cdev_del(&xxxdev.cdev);/*  删除 cdev */ /* 函数具体内容 */ return 0; } /* 匹配列表 */
static const struct of_device_id xxx_of_match[] = { { .compatible = "xxx-gpio" }, { /* Sentinel */ }
}; /*  * platform 平台驱动结构体 */ static struct platform_driver xxx_driver = { .driver = { .name       = "xxx", .of_match_table = xxx_of_match, }, .probe      = xxx_probe,   .remove     = xxx_remove, }; /* 驱动模块加载 */ static int __init xxxdriver_init(void) { return platform_driver_register(&xxx_driver); } /* 驱动模块卸载 */ static void __exit xxxdriver_exit(void) {  platform_driver_unregister(&xxx_driver); } module_init(xxxdriver_init); module_exit(xxxdriver_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("zuozhongkai");

platform平台驱动模型简述(linux驱动开发篇)相关推荐

  1. Linux驱动模型之注册驱动

    前言 驱动的话我们关心几个点: 驱动是怎么添加到总线管理的设备链表上的? 注册驱动后,它是怎么和设备匹配,并最终调用驱动中的probe()函数的? 数据结构 首先看下数据结构: struct devi ...

  2. 【Kernel】驱动开发学习之Platform平台总线模型

    Platform平台总线模型 一.前言 二.注册Device文件 三.注册Driver文件 四.编写Probe函数 五.完整代码示例 驱动部分 应用部分 一.前言 平台总线模型也交platform总线 ...

  3. 正点原子linux阿尔法开发板使用——platform平台总线模型

    Linux驱动分离与分层 目的:为了提高软件的重用,跨平台性能!!! 控制器驱动和设备驱动分离!!! 将驱动分离:主机控制器驱动和设备驱动,主机控制器驱动一般是半导体厂家写的.在linux驱动框架下编 ...

  4. Linux设备驱动模型概述(Linux device driver model overview)

    平台(platform)设备和平台驱动是连接到平台总线(bus)的linux驱动模型接口,总线将设备和驱动绑定,这个伪总线(platform bus)以最小的基础结构被用来连接设备到总线上.在系统每注 ...

  5. 基于DSP/BIoS设备驱动模型的视频驱动程序开发

    作者:天津科技大学 电子信息与自动化学院 严新忠,刘 喆 通过给外部设备编写驱动程序是一种有效的控制外设的方法.随着DSP的应用越来越广泛,DSP实时系统的日趋复杂及新技术的出现,DSP处理器所连接的 ...

  6. Linux驱动 简单的Linux驱动基础知识

    Linux驱动 简单的Linux驱动基础知识 一.简述         记--Linux驱动学习笔记. Linux驱动程序初始化硬件设备,并提供硬件控制接口给更上一层的应用调用. 例如使用QT应用程序 ...

  7. STM32MP157系列教程连载-Linux应用开发篇1:STM32MP1微处理器之Ubuntu安装与体验

    STM32MP157系列教程连载-Linux应用开发篇1:STM32MP1微处理器之Ubuntu安装与体验 截至目前上传的博文已经有6篇了(硬件4篇,安装环境2篇),最近手头在搞STM32MP157C ...

  8. 使用O2OA二次开发搭建企业办公平台(十五)流程开发篇:创建报销审批流程

    本博客为O2OA系列教程.O2OA使用手册,教程目录和各章节天梯将在连载完后更新. 使用O2OA二次开发搭建企业办公平台(一)平台部署篇:平台下载和部署 使用O2OA二次开发搭建企业办公平台(二)平台 ...

  9. 使用O2OA二次开发搭建企业办公平台(十二)流程开发篇:报销审批流程需求和应用创建

    本博客为O2OA系列教程.O2OA使用手册,教程目录和各章节天梯将在连载完后更新. 使用O2OA二次开发搭建企业办公平台(一)平台部署篇:平台下载和部署 使用O2OA二次开发搭建企业办公平台(二)平台 ...

最新文章

  1. 征服围棋之后 谷歌DeepMind宣布利用AI对抗乳腺癌
  2. vue数据源转json问题
  3. 拓扑排序--关键路径
  4. 注册,WEB2.0应用的小门槛
  5. 守护进程和inetd守护进程
  6. jquery weui 中alert弹出框在ios中跳动问题
  7. Unity/UE读取OPC UA和OPC DA数据(UE4)
  8. Angular2开发拙见——组件规划篇
  9. IEC 60335 全系列- 家用和类似用途电器 - 包含全部106份最新英文版标准文件
  10. mysql语句大全及例子_SQL语句大全实例教程.pdf
  11. 查询央行征信的APP有哪些?
  12. Windows socket之IOCP实例----IOCP开发驾照理论考试系统
  13. 聚焦存储即平台,浪潮存储迎来发展新机遇
  14. Pytorch学习——池化层
  15. 从12306帐号泄漏谈用户密码安全
  16. 端口映射工具网络通-个人电脑也能作为服务器
  17. 70G内存的手机,比8G内存的电脑快吗?
  18. 场内基金和场外基金区别
  19. 使用YMIR生产基于yolov5的头盔检测模型
  20. 芯片的单双电源供电问题

热门文章

  1. hardware用u盘起动_Mac 老设备如何利用U盘启动 Apple Hardware Test (AHT) 硬件检测工具...
  2. Python游戏开发,pygame模块,Python实现超级玛丽100%真实版
  3. 渲染预览PDF文档,轻松搞定,这方案真香!
  4. 修改2012服务器的默认端口,请问如何开启2012R2系统对外访问445等端口。
  5. YOLOv5的损失函数
  6. 适用于多类移动场景的融合认证机制设计
  7. 【ITOO 5】启用MSDTC后的各种问题,以及解决方案
  8. matlab 获取文件毫秒时间,matlab - Matlab中的高精度毫秒计时器 - SO中文参考 - www.soinside.com...
  9. VS2008在升级到SP1后即可支持tr1
  10. 给IDEA换一个酷炫的主题