Linux学习_驱动编写方案与总线驱动模型
创始人
2024-06-02 09:12:58
0

Linux学习_驱动编写方案与总线驱动模型

  • 驱动编写的三种方法
    • 传统写法
    • 改进写法
    • 总线设备驱动模型
      • platform总线模型platform_bus_type
      • platform_match函数
      • 注册平台设备流程
      • 注册平台驱动
      • 常用函数
  • 具体程序在D:\6ull\git仓库\01_all_series_quickstart\05_嵌入式Linux驱动开发基础知识\source\02_led_drv\04_led_drv_template_bus_dev_drv

驱动编写的三种方法

传统写法

在这里插入图片描述
使用哪个引脚,怎么操作引脚,都写死在代码中。最简单,不考虑扩展性,可以快速实现功能。但是修改引脚时,需要重新编译。

改进写法

利用面向对象的设计思想,对驱动进行分层、分离等操作,将驱动整体依据通用性上下分层,上层注册驱动,下层实现硬件操作,如图所示
在这里插入图片描述
这样我们在更换硬件时,只需要更改board_xxx.c函数即可,提高了代码的复用性,而在下层的硬件操作中,我们可以再做细分,将硬件资源与引脚选取、初始化进行“分离”这一操作,如图所示
在这里插入图片描述
图中led_resource实现led资源的定义,board_xxx实现引脚的选用,chip_gpio实现了对led资源的init和ctrl函数

总线设备驱动模型

在这里插入图片描述
这里直接构建了一个总的device结构体platform_device,把整个板子上所有的硬件资源和初始化模板都塞进去,构建成一个庞大又臃肿的资源结合体。
在这里插入图片描述

platform总线模型platform_bus_type

struct bus_type platform_bus_type = {.name		= "platform",.dev_groups	= platform_dev_groups,.match		= platform_match,	//bind platform device to platform driver..uevent		= platform_uevent,.dma_configure	= platform_dma_configure,.pm		= &platform_dev_pm_ops,
};

这个结构体里面有个platform_match成员,在外部有该成员函数的定义,负责为BUS比较DeviceDriver是否匹配,在注册驱动时,整个driver_match_device(drv, dev)函数把platform_match(drv, dev)塞进去,比较的顺序如下。

  1. platform_device. driver_override(device指定要这个名字的driver)和 platform_driver.driver.name(driver的名字)/不太常用
  2. 设备树
  3. platform_device. name(device的名字)和 platform_driver.id_table[i].name(idtable里面存放着本driver支持的device名)/常用
  4. platform_device.name(device的名字)和 platform_driver.driver.name(driver的名字)//常用

platform_match函数

platform_match函数代码如下:

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);
}

注册平台设备流程

总体的递归调用流程就是这样的,一层一层的追溯到最底层就是一个probe

int platform_device_register(struct platform_device *pdev)platform_device_add(pdev);device_add(&pdev->dev);				//struct deviceerror = bus_add_device(dev);	//放入链表bus_probe_device(dev);			//probe drivers for a new devicedevice_initial_probe(dev);__device_attach(dev, true);bus_for_each_drv(dev->bus, NULL, &data,__device_attach_driver);	//在drv链表中, bus_type->subsys_private->klist_drivers__device_attach_driver				//attempt to bind device & driver together.			struct device_driver和struct devicedriver_match_device(drv, dev);	//查看drv和dev是否匹配,drv->bus->match ? drv->bus->match(dev, drv) : 1;在这里会调用bus里面的match函数,指向了platform_matchdriver_probe_device(drv, dev);	//attempt to bind device & driver together,调用drv的probe函数really_probe(dev, drv);dev->driver = drv;		//dev里面的driver = drv。将两者联系起来了。dev->bus->probe(dev);	//在platform_bus_type中没有定义probe函数,所以会调用drv->probe(dev)函数//或者drv->probe(dev);

注册平台驱动

platform_driver_register(drv) int __platform_driver_register(struct platform_driver *drv, struct module *owner)drv->driver.owner = owner;drv->driver.bus = &platform_bus_type;drv->driver.probe = platform_drv_probe;drv->driver.remove = platform_drv_remove;drv->driver.shutdown = platform_drv_shutdown;driver_register(&drv->driver);	//register driver with busbus_add_driver(drv);		//放入链表,这种bus type的驱动列表driver_attach(drv);		//try to bind driver to devices.bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);__driver_attachdriver_match_device(drv, dev);	//查看drv和dev是否匹配,drv->bus->match ? drv->bus->match(dev, drv) : 1;在这里会调用bus里面的match函数,指向了platform_matchdevice_driver_attach(drv, dev);	//attach a specific driver to a specific devicedriver_probe_device(drv, dev);really_probe(dev, drv);dev->driver = drv;		//dev里面的driver = drv。将两者联系起来了。dev->bus->probe(dev);	//在platform_bus_type中没有定义probe函数,所以会调用drv->probe(dev)函数//或者drv->probe(dev);

常用函数

注册/注销

platform_device_register/ platform_device_unregister
platform_driver_register/ platform_driver_unregister
platform_add_devices // 注册多个 device

查询函数
返回该 dev 中某类型(type)资源中的第 n 个

struct resource *platform_get_resource(struct platform_device *dev, unsigned int type,unsigned int n)

返回该 dev 所用的第 n 个中断

int platform_get_irq(struct platform_device *dev, unsigned int n)

通过名字(name)返回该 dev 的某类型(type)资源

struct resource *platform_get_resource_byname(struct platform_device *dev, unsigned int type, const char *name)

通过名字(name)返回该 dev 的中断号

int platform_get_irq_byname(struct platform_device *dev, const char *name)

具体程序在D:\6ull\git仓库\01_all_series_quickstart\05_嵌入式Linux驱动开发基础知识\source\02_led_drv\04_led_drv_template_bus_dev_drv

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...