LDD3-与硬件通信

I/O端口和I/O内存

一些CPU厂商在它们的芯片中使用单一的地址空间,而另一些为外设保留了独立的地址空间。

一些处理器还为I/O端口的读写提供了独立的线路,并且使用特殊的CPU指令端口。

也就是说,对一些CPU来说,访问内存和外设需要不同的指令和地址空间。

但是也有使用统一地址空间,把外设地址映射到内存地址空间。

ISA设备普遍使用I/O端口,而大多数PCI设备则把寄存器映射到某个内存地址区段。这种I/O内存通常是首选方案,因为不需要特殊的处理器指令

I/O寄存器和常规内存

I/O寄存器和RAM的主要区别就是I/O操作具有边际效应,而内存操作没有。内存写操作的唯一结果就是

在指定位置存储一个数值;内存读操作则仅仅返回指定位置的数值。因为内存操作没有边际效应,可以使用多种方法进行优化,比如高速缓存保存数值,重新排序读写指令。

无论是编译器一级或是硬件一级,指令的重新排序都有可能发生在内存操作。

但是对I/O操作来说,这些优化可能造成致命错误。

处理器无法预料某些其他进程(在另一个处理器上运行,或在某个I/O控制器中发生的操作)是否会依赖于内存访问的顺序。编译器或CPU可能会自作聪明地重新排序所要求的操作,结果会发生奇怪的错误。

因此,驱动程序必须确保不使用高速缓存,并且在访问寄存器时不发生读或写指令的重新排序

使用I/O端口

I/O端口的分配

操作端口之前,需要对这些端口的独占访问。

struct resource *request_region(first, n, const char *name)----使用起始与first的n个端口

操作I/O端口

inb(unsigned port); outb(unsigned char byte, unsigned port);

----ARM:端口映射到内存,支持所有函数;串操作用C语言实现,端口类型是unsigned in----

使用I/O内存

除了I/O端口外,和设备通信的另一种主要机制是通过映射到内存的设备寄存器或设备内存,这两种都是I/O内存。

I/O内存只是类似RAM的一个区域,它们可以说存放视频数据,也可以是I/O端口设备寄存器的映射(此时,存在边际效应)。

I/O内存可能是,也可能不是通过页表访问的。如果访问经由页表进行,内核必须先安排物理地址使其对设备驱动程序可见(意味着进行任何I/O之前必须先调用ioremap)

记住,无论是否使用ioremap,都不鼓励直接使用指向I/O内存的指针,应该使用包装函数访问I/O内存。这些函数是安全的,并且经过优化。

/*

一般来说,在系统运行时,外设的I/O内存资源的物理地址是已知的,由硬件的设计决定。但是CPU通常并没有为这些已知的外设I/O内存资源的物理地址预定义虚拟地址范围,驱动程序并不能直接通过物理地址访问I/O内存资源,而必须将它们映射到核心虚地址空间内(通过页表),然后才能根据映射所得到的核心虚地址范围,通过访内指令访问这些I/O内存资源。Linux在io.h头文件中声明了函数ioremap(),用来将I/O内存资源的物理地址映射到核心虚地址空间
*/---https://blog.csdn.net/skyflying2012/article/details/8672011

 

devm_request_mem_region()--先申请所需访问的物理地址区域,以防止其他程序再去访问,外设一般都需要独占访问。这里其实并没有任何内存映射。
ioremap()--这里才是把外设的物理地址映射到虚拟地址空间,注意是外设的物理地址。

 

posted @ 2022-05-13 16:14  老胡同学  阅读(106)  评论(0编辑  收藏  举报