重要:本文是自己根据经验而总结,如若理解不到位或错误,会继续修改更新,如与实物不符,概不负责,请慎重参考。
摘要:很多文章中都会提到设备驱动,他们通常把
soc外挂的设备的驱动称为设备驱动,也把集成在soc内部的设备的驱动称为设备驱动。而我一般将
集成在soc内部的设备的驱动认为是总线驱动的一部分,而且一般情况下这部分驱动
已由芯片提供商编写完成,通常不会再去修改。本文重在认识一下这2种设备驱动的最底层操作。
首先,需要知道的是,不管是soc外挂的设备,还是集成在soc内部的设备,这些设备的驱动的最底层,其实都是寄存器级驱动。为什么这么说?这是因为几乎每一种设备都是通过读写设备上的寄存器来进行的,这些寄存器通常包括控制寄存器、状态寄存器和数据寄存器三大类。
soc集成的外围设备
集成在soc内部的设备通常被称作
XX控制器,这些IO控制器的寄存器
通常被CPU连续地编址进行访问。这些连续编址我们称之为IO物理地址空间,
IO物理地址空间是已知的,
由硬件的设计决定,通常在芯片手册中搜索memory map即可找到。
事实上,由于通常系统启用MMU的原因,驱动程序并不能直接通过IO物理地址访问IO控制器,只能通过虚拟地址来访问,但是CPU通常并没有为这些已知的IO控制器的IO物理地址预定义虚拟地址,所以必须将IO物理地址映射到内核虚地址空间内(通过页表),然后才能根据映射所得到的内核虚地址,访问这些IO控制器。而通常做法是一次性映射,即IO物理地址空间只在单板对应的内核初始化过程中ioremap映射一次,这样在编写内核代码或者驱动时就不需要再ioremap映射,而是直接使用映射后的内核虚拟地址访问。【见:嵌入式驱动开发 虚拟地址 物理地址 IO地址】。
在将IO物理地址映射成内核虚拟地址后,理论上讲,我们就可以像读写内存那样直接读写IO控制器了。但实际上,我们在驱动程序(这里指总线驱动)开发中,为了保证驱动程序的跨平台的可移植性,我们应该使用Linux中特定的函数来访问IO物理地址空间,而不应该直接使用内核虚地址为指针来访问。这些函数有:__raw_readl/__raw_writel或ioread32/iowrite32等是原始的操作IO的方法,它们的区别关系见:http://blog.sina.com.cn/s/blog_6e5b342e0100m88z.html。
最终,在驱动程序(这里指设备驱动)中,通过read/write/ioctrl访问soc外挂的设备对应的字符设备文件(linux中设备即文件),其最最最底层终究是读写与其关联的IO控制器的寄存器,而IO控制器会按照某一协议规则,与soc外挂的设备进行通信,如按spi协议时序将写寄存器地址和写数据发送到soc外挂的设备。
另外,Linux内核为用户提供了一个/dev/mem的驱动程序,使应用程序通过mmap就可以在用户空间直接访问IO物理地址空间。如在gpio控制LED的应用程序中,如若不想关心linux内核关于gpio架构的实现,而想通过直接读写IO控制器的物理地址来控制,此时
/dev/mem不失为一种简单快捷的调试手段。
【见:嵌入式驱动开发 用户态 IO】。
soc外挂的外部设备
soc外挂的设备通常被称作外设,这些外设被外挂在IO控制器上,并通过IO控制器进行访问,见上:最终...。
阅读(2607) | 评论(0) | 转发(0) |