linux驱动开发--I/O内存的访问流程

设备通常会提供一组寄存器来用于控制设备、读写设备和获取设备状态,既控制寄存器、数据寄存器和状态寄存器、这些寄存器可能位于I/O空间,也可能位于内存空间。当位于I/O空间时,通常被称为I/O端口,位于内存空间时,对应的内存空间被称为I/O内存(现在一般都是统一编址)

1、对于I/O端口

有专门的函数提供读取端口上的数据,例如读写字节端口(8字节宽)

Unsigned inb(unsigned port);

Unsigned outb(unsigned char byte,unsignedport);

2、对于I/O内存

在内核中访问I/O内存之前,需首先使用ioremap()函数将设备所处的物理地址映射到虚拟地址,ioremap()的原型如下:

Void* ioremap(unsigned long offset,unsignedlong size);

Ioremap()与vmalloc()类似,也需要建立新的页表,但是它并不进行vmalloc()中所执行的内存分配行为。Ioremap()返回一个特殊的虚拟地址,该地址可用来存取特定的物理地址范围。通过ioremap()获得的虚拟地址应该被iounmap()函数释放,

Void iounmap(void* addr);

在设备的物理地址被映射到虚拟地址之后,尽管可以直接通过指针访问这些地址,但是可以使用Linux内核的如下一组函数来完成设备内存映射的虚拟地址的读写,这些函数如下:

a)      读I/O内存

Unsigned intioread8(void* addr);

Unsigned intioread16(void* addr);

Unsigned intioread32(void* addr);

b)      写I/O内存

Void iowrite8(u8value ,void * addr);

Void iowrite16(u16value ,void * addr);

Void iowrite32(u32value ,void * addr);

3、把I/O端口映射到内存空间

Void*ioport_map(unsigned long port,unsigned int count);

通过这个函数,可以把port开始的count个连续的I/O端口重映射为一段“内存空间“。然后就可以在其返回的地址上像访问I/O内存一样访问这些I/O端口。当不需要这种映射时,需要调用下面的函数来撤销

Voidioport_unmap(void* addr);

Ioport_map()映射到内存空间行为实际上是给开发人员制造一个假象,并没有映射到内核虚拟地址,仅仅是为了让工程师可使用同一的I/O内存访问接口访问I/O端口

4、申请与释放设备I/O端口和I/O内存

I/O端口申请

Struct resource* request_region(unsignedlong first,unsigned long n,const char* name);

这个函数向内核申请n个端口,这些端口从first开始,name参数为设备的名称,如果分配成功返回值非NULL

Void relese_region(unsigned longstart,unsigned long n);

I/O内存申请

Struct resoutce* request_mem_region(unsignedlong start,unsigned long len,char* name);

向内核申请n个内存地址,这些地址从first开始,name参数为设备的名称

Void relese_mem_region(unsigned longstart,unsigned long len);

5、设备I/O端口和I/O内存访问流程

a) I/O端口访问方法:

直接使用I/O端口操作函数,在设备打开或驱动模块被加载时申请I/O端口,之后使用inb() outb()进行访问,最后再设备关闭或驱动被卸载时释放I/O端口范围

另一个途径就是将I/O端口映射为内存进行访问,在设备打开或驱动模块被加载时,申请I/O端口区域并使用ioport_map()映射到内存,之后使用I/O内存的函数进行端口访问。最后,在设备关闭或驱动被卸载时释放I/O并使用映射

c)      I/O内存的访问方法

首先使用request_mem_region()申请资源,接着将寄存器地址通过ioremap()映射到内核空间虚拟地址,之后就可以通过linux设备访问编程接口访问这些设备的寄存器了,访问完成后,使用ioremap()申请的虚拟地址进行释放,并释放relese_mem_region()申请的I/O内存资源

6、将设备地址映射到用户空间

一般情况用户空间不可能也不应该直接访问设备,但是,设备驱动程序中可实现mmap()函数,这个函数可是的用户空间能直接访问设备的物理地址,mmap()实现了将用户空间的一段内存与设备内存关联,当用户访问用户空间的这段地址实际上转化为对设备的访问。如果用户空间可直接通过内存映射访问显存的话,屏幕帧的各点的像素将不再需要一个从用户空间到内核空间的复制过程,mmap()必须以PAGE_SIZE为单位进行映射

从file_operatoions文件操作结构体可以看出,驱动中mmap()函数的原型:

Int (*mmap) (struct file*,structvm_area_struct*);

用户的调用为:

Caddr_t mmap(caddr_t addr,size_t len,intport, int flags,int fd,off_t offset);

当用户调用mmap()的时候,内核会进行如下处理:

在进程的虚拟空间查找一块VMA

将这块VMA进行映射

如果设备驱动程序或文件系统的file_operations定义了mmap()操作,则调用它

将这个vma插入进程的VMA链表中

File_operations中mmap()函数的第一个参数就是步骤1中找到的VMA

至于file_operations中的mmap()需要别的系统调用remap_pfn_range()

大多数设备驱动都不需要提供设备内存到用户空间的映射能力,因为,对于串口等面向流的设备而言,实现这种映射毫无意义,而对于显示、视频等设备,建立映射可减少用户空间和内核空间之间的内存拷贝

参考:linux设备驱动开发详解

时间: 2024-10-16 02:57:07

linux驱动开发--I/O内存的访问流程的相关文章

linux 驱动开发-模块的构建

1.模块的含义 linux 是采用模块化的方式构建的,允许内核在运行时动态地向其中插入或从中删除代码,这些代码(包扩函数,数据,模块入口函数,模块出口函数)被一并组合 在一个单独的二进制镜像,就是所谓的可装载内核模块. 模块可以是基本的内核镜像尽可能小,同时可以方便地对新功能进行调试,还可以实现热插拔(后续会学习如何实现设备的热插拔功能,暂时无需深究),和内核的核心子系统不一样,模块文件需要有入口点和出口点. 模块与应用程序的区别: a.模块和库函数类似,一个模块通常包含若干函数和数据,每个函数

Linux驱动开发之 三 (那些必须要了解的硬件知识 之 存储器篇)

Linux驱动开发之 三 (那些必须要了解的硬件知识 之 存储器篇) 本文重点学习存储器相关的基本知识,网络上对RAM,ROM,FLASH等有非常详细的介绍,老谢将这些知识点摘抄整理并加以注释如下.这个整理的过程也是加深记忆的过程. 1.什么是内存 在计算机的组成结构中,有一个很重要的部分,就是存储器.存储器是用来存储程序和数据的部件,对于计算机来说,有了存储器,才有记忆功能,才能保证正常工作.存储器的种类很多,按其用途可分为主存储器和辅助存储器,主存储器又称内存储器(简称内存),辅助存储器又称

【转】linux驱动开发的经典书籍

原文网址:http://www.cnblogs.com/xmphoenix/archive/2012/03/27/2420044.html Linux驱动学习的最大困惑在于书籍的缺乏,市面上最常见的书为<linux_device_driver 3rd Edition>,这是一本很经典的书,无奈Linux的东东还是过于庞大,这本侧重于实战的书籍也只能停留在基本的接口介绍上,更深入的东东只能靠我们自己摸索了.但万事总有一个开头,没有对Linux驱动整体框架的把握是很难做一个优秀的驱动开发者的.除了

Linux 驱动开发笔记(一)

1.查看printk函数日记输出 (1)使用字符终端:通常使用ctrl+alt+f1切换查看: (2)使用cat /proc/kmsg命令:(在Linux系统启动后,/proc/kmsg文件可以查看内核对外所用的符号表,可以用cat命令查看器内容.) (3)使用dmesg命令查看. linux/kernel.h文件定义的printk函数的Log Level: 常数定义语句 意义 #define KERN_EMERG "<0>"/*系统不运行*/ #define KERN_A

Linux 驱动开发索引

1.嵌入开发环境搭建 Telnet 在 mini2440 上的移植 Opencv-2.4.9 在 mini2440 上的移植 搭建嵌入式开发环境总结 2.Linux 设备驱动 Linux 驱动程序头文件 一步一步学习Linux驱动之驱动模块MakeFile解析 一步一步学习 Linux 驱动之(Kconfig.Makefile) 一步一步学习 Linux 驱动之字符设备 LED 静态编译进 Linux 内核 内核怎么通过主设备号找驱动.次设备号找设备 Linux 驱动之内核空间分配内存 一步一步

linux驱动开发流程

嵌入式linux驱动开发流程嵌入式系统中,操作系统是通过各种驱动程序来驾驭硬件设备的.设备驱动程序是操作系统内核和硬件设备之间的接口,它为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,可以像操作普通文件一样对硬件设备进行操作.设备驱动程序是内核的一部分,完成以下功能:◇ 驱动程序的注册和注销.◇ 设备的打开和释放.◇ 设备的读写操作.◇ 设备的控制操作.◇ 设备的中断和轮询处理.Linux主要将设备分为三类:字符设备.块设备和网络设备.字符设备是指发送和接收数据以字符的

嵌入式Linux驱动开发实战视频教程

嵌入式Linux驱动开发实战教程(内核驱动.看门狗技术.触摸屏.视频采集系统)适合人群:高级课时数量:109课时用到技术:嵌入式 Linux涉及项目:驱动开发.看门狗技术.触摸屏.视频采集咨询qq:1840215592 课程介绍:本课程即是针对有兴趣学习嵌入式linux驱动开发又不知道从何处着实开始学习嵌入式linux驱动开发的在校同学以及社会在职人员.本课程采用理论教学与实验相结合的方式,软件与硬件相结合的方式,重点给大家讲解嵌入式linux驱动开发的方法,系统地介绍嵌入式linux驱动开发的

嵌入式linux驱动开发之给你的linux系统添加温度传感器模块

忙了几天,终于可以让ds18b20在自己的开发板的linux系统上跑了!虽然ds18b20不是什么新鲜玩意,但是想想知己可以给linux系统添加模块了还是有点小鸡冻呢! 虽然说现在硬件的资源非常丰富而且剩余很多,可以用软件资源来代替硬件资源,比如说可以用视频编解码软件取代硬件来工作.但有很多模块需要实时的采集数据这都是软件永远无法代替的,而且随着互联网的进一步发展,智能化也是一个必然的趋势,因此大量的传感器和控制芯片将被应用到生产生活中,所以个人觉得驱动开发还是个不错的方向.同时,作为学习者,再

嵌入式Linux驱动开发实战教程

嵌入式Linux驱动开发实战教程(内核驱动.看门狗技术.触摸屏.视频采集系统) http://www.ibeifeng.com/goods-475.html 咨询QQ2110053820 课程讲师:韩老师 课程分类:Linux 适合人群:高级 课时数量:109课时 更新程度:完成 用到技术:嵌入式 Linux 涉及项目:驱动开发.看门狗技术.触摸屏.视频采集 课程简介:    嵌入式软件开发无疑是当今最热门的行业,嵌入式软件工程师的薪资比普通的软件工 程师的薪资平均高50%以上.随着智能控制.物