platform_device与platform_driver

      做Linux方面也有三个多月了,对代码中的有些结构一直不是非常明确,比方platform_device与platform_driver一直分不清关系。在网上搜了下,做个总结。两者的工作顺序是先定义platform_device -> 注冊 platform_device->,再定义 platform_driver-> 注冊 platform_driver。

 (1)platform_device设备的注冊过程必须在对应设备驱动载入之前被调用,由于驱动注冊时须要匹配内核中所以已注冊的设备名。platform_device 是在系统启动时在init.c 里的s3c_arch_init() 函数里进行注冊的。这个函数申明为arch_initcall(s3c_arch_init); 会在系统初始化阶段被调用。arch_initcall 的优先级高于module_init,所以会在Platform 驱动注冊之前调用。如今内核中不是採用arch_initcall(s3c_arch_init) 注冊platform_device 结构体而是通过.init_machine成员将其保存在arch_initcall(customize_machine)等待调用(在mach-smdk6410.c中定义的MACHINE_START到MACHINE_END);事实上质是一样的均放在.initcall3.init等待调用。之后再定义结构体struct platform_driver,在驱动初始化函数中调用函数platform_driver_register() 注冊 platform_driver。具体过程描写叙述例如以下:

      Linux从2.6版本号開始引入了platform这个概念,在开发底层驱动程序时,首先要确认的就是设备的资源信息,在2.6内核中将每一个设备的资源用结构platform_device来描写叙述,该结构体定义在kernel/include/linux/platform_device.h中,

struct platform_device{const char * name;u32  id;struct device dev;u32  num_resources;struct resource * resource;
};


该结构一个重要的元素是resource,该元素存入了最为重要的设备资源信息,定义在kernel/include/linux/ioport.h中,
比方:

struct resource {const char *name;unsigned long start, end;unsigned long flags;struct resource *parent, *sibling, *child;
};

实比如:

static struct resource s3c_usb_resource[] = {[0] = {.start = S3C_PA_USBHOST,.end   = S3C_PA_USBHOST + S3C_SZ_USBHOST - 1,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_UHOST,.end   = IRQ_UHOST,.flags = IORESOURCE_IRQ,}
};


以上是6410的USB  HOST分配的资源信息。第1组描写叙述了这个usb host设备所占用的总线地址范围,起始地址和大小由硬件决定,IORESOURCE_MEM表示第1组描写叙述的是内存类型的资源信息;第2组描写叙述了这个usb host设备的中断号,也由硬件设定,IORESOURCE_IRQ表示第2组描写叙述的是中断资源信息。设备驱动会依据flags来获取对应的资源信息。

      有了resource信息,就能够定义platform_device了:

struct platform_device s3c_device_usb = {.name    = "s3c2410-ohci",  //s3c6410-usb.id    = -1,.num_resources   = ARRAY_SIZE(s3c_usb_resource),.resource   = s3c_usb_resource,.dev              = {.dma_mask = &s3c_device_usb_dmamask,.coherent_dma_mask = 0xffffffffUL}
};


有了platform_device就能够调用函数platform_add_devices向系统中加入该设备了。系统中的设备资源都能够採用这样的方式列举在一起,然后成一个指针数组,如:

static struct platform_device *smdk6410_devices[] __initdata = {

......

 &s3c_device_usbgadget,
 &s3c_device_usb,  //jeff add.

......

}

然后在6410的初始化函数smdk6410_machine_init()中运行:

platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));将全部的device加入进系统。platform_add_devices的优点在于它是一次性的运行多个platform_device_register。

(2) 至于驱动程序须要实现结构体struct platform_driver,也定义在kernel/include/linux/platform_device.h中:

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 (*suspend_late)(struct platform_device *, pm_message_t state);int (*resume_early)(struct platform_device *);int (*resume)(struct platform_device *);struct pm_ext_ops *pm;struct device_driver driver;
};


则该处的USB HOST实现是:

static struct platform_driver ohci_hcd_s3c2410_driver = {.probe  = ohci_hcd_s3c2410_drv_probe,.remove  = ohci_hcd_s3c2410_drv_remove,.shutdown = usb_hcd_platform_shutdown,/*.suspend = ohci_hcd_s3c2410_drv_suspend, *//*.resume = ohci_hcd_s3c2410_drv_resume, */.driver  = {.owner = THIS_MODULE,.name = "s3c2410-ohci",},
};


      在驱动初始化(ohci-hcd.c的1124行)函数中调用函数platform_driver_register()注冊该platform_driver,须要注意的是s3c_device_usb结构中name元素和ohci_hcd_s3c2410_driver 结构中driver.name必须是同样的,这样在platform_driver_register()注冊时会对全部已注冊的platform_device中元素的name和当前注冊的platform_driver的driver.name进行比較,仅仅有找到具备同样名称的platform_device存在后,platform_driver才干注冊成功。当注冊成功时会调用platform_driver结构元素probe函数指针,这里就是ohci_hcd_s3c2410_drv_probe開始探測载入。platform driver中的函数都是以platform device作为參数进入。

(3)为什么两个name的名字必须匹配才干实现device和driver的绑定?(1)在内核初始化时kernel_init()->do_basic_setup()->driver_init()->platform_bus_init()初始化platform_bus(虚拟总线);(2)设备注冊的时候platform_device_register()->platform_device_add()->(pdev->dev.bus = &platform_bus_type)把设备挂在虚拟的platform bus下;(3)驱动注冊的时候platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev(),对每一个挂在虚拟的platform bus的设备作__driver_attach()->driver_probe_device(),推断drv->bus->match()是否存在而且是否运行成功,此时通过指针运行platform_match,比較strncmp(pdev->name, drv->name, BUS_ID_SIZE),假设相符就调用really_probe(实际就是运行的对应设备的platform_driver->probe(platform_device),注意platform_drv_probe的_dev參数是由bus_for_each_dev的next_device获得)開始真正的探測载入,假设probe成功则绑定该设备到该驱动。

      当进入probe函数后,须要获取设备的资源信息,依据參数type所指定类型,比如IORESOURCE_MEM,来分别获取指定的资源。
struct resource * platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);当然,也能够固定资源类型,如获取资源中的中断号:struct int platform_get_irq(struct platform_device *dev, unsigned int num);

      probe函数一般完毕硬件设备使能,struct resource的获取以及虚拟地址的动态映射和详细类型设备的注冊(由于平台设备仅仅是一种虚拟的设备类型);remove函数完毕硬件设备的关闭,struct resource以及虚拟地址的动态映射的释放和详细类型设备的注销。仅仅要和内核本身执行依赖性不大的外围设备 ( 换句话说仅仅要不在内核执行所需的一个最小系统之内的设备 ), 相对独立的拥有各自独自的资源 (addresses and IRQs) ,都能够用platform_driver 实现。如:lcd,usb,uart 等,都能够用platfrom_driver 写,而timer,irq等最小系统之内的设备则最好不用platfrom_driver 机制,实际上内核实现也是这种。


 參考原文:http://blog.chinaunix.net/u1/49507/showart_494193.html

參考原文:http://blog.csdn.net/yd4330152763132/archive/2010/02/01/5275776.aspx

转载于:https://www.cnblogs.com/mengfanrong/p/3806244.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/258488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

复盘caffe安装

最近因之前的服务器上的caffe奔溃了,不得已重新安装这一古老的深度学习框架,之前也尝试了好几次,每次都失败,这次总算是成功了,因此及时地总结一下。 以下安装的caffe主要是针对之前虹膜分割和巩膜分割所需的caffe版本…

HP P2000 RAID-5两块盘离线的数据恢复报告

1. 故障描述本案例是HP P2000的存储vmware exsi虚拟化平台,由RAID-5由10块lT硬盘组成,其中6号盘是热备盘,由于故障导致RAID-5磁盘阵列的两块盘掉线,表现为两块硬盘亮黄灯。 经用户方维护人员检测,故障硬盘应为物理故障…

微智魔盒骗局_微智魔盒官宣

原标题:微智魔盒官宣微智魔盒官方宣传视频微达国际集团创建于2011年,是一家坚持创新的集科研、产销、服务为一体的智能化产业平台,致力于国际领先的专注人工智能领域的产业投资、项目孵化、教育培训,并提供终极解决方案。集团创新…

瑞柏匡丞_移动互联的发展现状与未来

互联网作为人类文明史上最伟大、最重要的科技发明之一,发展到今天,用翻天覆地来形容并不过分。而作为传统互联网的延伸和演进方向,移动互联网更是在近两年得到了迅猛的发展。如今,越来越多的用户得以通过高速的移动网络和强大的智…

android 进程间通信数据(一)------parcel的起源

关于parcel,我们先来讲讲它的“父辈” Serialize。 Serialize 是java提供的一套序列化机制。但是为什么要序列化,怎么序列化,序列化是怎么做到的,我们将在本文探讨下。 一:java 中的serialize 关于Serialize这个东东&a…

为什么torch.nn.Linear的表达形式为y=xA^T+b而不是常见的y=Ax+b?

今天看代码,对比了常见的公式表达与代码的表达,发觉torch.nn.Linear的数学表达与我想象的有点不同,于是思索了一番。 众多周知,torch.nn.Linear作为全连接层,将下一层的每个结点与上一层的每一节点相连,用…

Leetcode47: Palindrome Linked List

Given a singly linked list, determine if it is a palindrome. 推断一个链表是不是回文的,一个比較简单的办法是把链表每一个结点的值存在vector里。然后首尾比較。时间复杂度O(n)。空间复杂度O(n)。 /*** Definition for singly-linked list.* struct ListNode {…

内存颗粒位宽和容量_SDRAM的逻辑Bank与芯片容量表示方法

1、逻辑Bank与芯片位宽讲完SDRAM的外在形式,就该深入了解SDRAM的内部结构了。这里主要的概念就是逻辑Bank。简单地说,SDRAM的内部是一个存储阵列。因为如果是管道式存储(就如排队买票),就很难做到随机访问了。阵列就如同表格一样,…

[Unity菜鸟] Time

1. Time.deltaTime 增量时间 以秒计算,完成最后一帧的时间(秒)(只读) 帧数所用的时间不是你能控制的。每一帧都不一样,游戏一般都是每秒60帧,也就是updata方法调用60次(假如你按60帧来算 而真实情况是不到60帧 那么物体就不会运动…

【转】七个例子帮你更好地理解 CPU 缓存

我的大多数读者都知道缓存是一种快速、小型、存储最近已访问的内存的地方。这个描述相当准确,但是深入处理器缓存如何工作的“枯燥”细节,会对尝试理解程序性能有很大帮助。在这篇博文中,我将通过示例代码来说明缓存是如何工作的,…

Pytorch——对应点相乘和矩阵相乘

1. 点乘,对应元素相乘,不求和 import torcha torch.Tensor([[1,2], [3,4], [5,6]]) b1 a.mul(a)// b2a*a b1 Out[79]: tensor([[ 1., 4.],[ 9., 16.],[25., 36.]]) b2 Out[80]: tensor([[ 1., 4.],[ 9., 16.],[25., 36.]]) 以上两种方法都可以表…

mysql初始化错误【一】Can't find error-message file '/usr/local/mysql/errmsg.sys'

环境:CentOS 7.2MySQL 5.7.18从mysql官方网站下载rpm包到服务器本地,依次安装下面的RPM包:mysql-community-common-5.7.18-1.el7.x86_64.rpmmysql-community-server-5.7.18-1.el7.x86_64.rpmmysql-community-client-5.7.18-1.el7.x86_64.rpmm…

双极型adc与stm32_关于STM32 双ADC同步规则转换两路数据的问题?

因系统要求需升级ADC的采样方式(以前方式:扫描方式,TIMER2触发ADC软启动,2通道规则序列,DMA传完中断),为了进一步实现两路信号的同步性能,采样STM32 双ADC同步规则转换。(timer2触发ADC软启动,2…

面试金典--11.5

题目描述:给定排序后的字符串数组,中间有一些空串,要求找到给定字符串的位置 思路: (1)遍历,最慢的 (2)二分查找,当mid处为空串,就找到最近的非空…

win10 平台VS2019最简安装实现C++/C开发

这两天一直在安装vs2015,总是卡在visual studio 2015 出现安装包丢失或损坏的现象,尽管按照网上很多方法尝试解决,但是一直不行。算了。还是使用最新版的VS 2019安装,没想到很顺利。 下面总结一下在win10平台上最简安装VS2019,实…

Hook的两个小插曲

看完了前面三篇文章后,这里我们来一个小插曲~~~~ 第一个小插曲。是前面文章一个CM精灵的分析。我们这里使用hook代码来搞定。 第二个小插曲,是如今一些游戏,都有了支付上限,比如每天仅仅能花20块钱来购买。好了。以下我们分开叙述…

### C++总结-[类成员函数]

C类中的常见函数。 #author: gr #date: 2015-07-23 #email: forgeruigmail.com 一、constructor, copy constructor, copy assignment, destructor 1. copy constructor必须传引用,传值编译器会报错 2. operator 返回值为引用,为了…

微信小程序和vue双向绑定哪里不一样_个人理解Vue和React区别

本文转载自掘金,作者:binbinsilk,监听数据变化的实现原理不同Vue 通过 getter/setter 以及一些函数的劫持,能精确知道数据变化,不需要特别的优化就能达到很好的性能React 默认是通过比较引用的方式进行的,如…

JS 省,市,区

1 // 纯JS省市区三级联动2 // 2011-11-30 by http://www.cnblogs.com/zjfree3 var addressInit function (_cmbProvince, _cmbCity, _cmbArea, defaultProvince, defaultCity, defaultArea) {4 var cmbProvince document.getElementById(_cmbProvince);5 var cmbCity…

使用极链/AutoDL云服务器复盘caffe安装

继上一次倒腾caffe安装以后,因为博士毕业等原因,旧的服务器已经不能再使用,最近因论文等原因,不得不继续来安装一下我的caffe。这次运气比较好,经历了一晚上和一早上的痛苦之后,最终安装成功了,…