You are on page 1of 4

第七天笔记

一、应用程序和驱动程序的数据交互

Linux 系统下,应用程序和驱动程序之间的数据是不能直接传递,必须借助内核提供的函数
接口来实现数据的交互(本质就是内存拷贝),内核提供了两个函数,分别是
copy_to_user 和 copy_from_user。

 从用户空间获取数据

驱动程序想要从应用程序获取数据,需用调用 copy_from_user 函数,应用程序需要调用


write 函数把数据写入到文件对应的描述符,文件描述符是 open 函数打开设备文件的返回
值。该函数可以在 uaccess.h 头文件中找到。

函数原型
int copy_from_user(void *to, const void __user *from, int n)

函数参数
参数一:to 指的是内核空间的数据地址
参数二:from 指的是用户空间的数据地址
参数三:n 指的是打算拷贝的数据大小

返回值: 成功 返回 0 失败 返回不能拷贝的数据个数

 从内核空间获取数据

应用程序打算从驱动程序中获取数据,需要调用 copy_to_user 函数,应用程序需要调用


read 函数把数据写入到文件对应的描述符,文件描述符是 open 函数打开设备文件的返回值。
该函数可以在 uaccess.h 头文件中找到。
函数原型
int copy_to_user(void __user *to, const void *from, int n)

函数参数
参数一:to 指的是用户空间的数据地址
参数二:from 指的是内核空间的数据地址
参数三:n 指的是打算拷贝的数据大小

返回值: 成功 返回 0 失败 返回不能拷贝的数据个数

练习:编写程序,把驱动程序中的 led_read 函数设计出来,利用应用程序进行数据的读取,


把驱动程序的数据读取并打印出来。

二、物理地址与虚拟地址的转换

裸机程序是通过硬件的寄存器来控制硬件,硬件的寄存器的物理地址都可以在 CPU 的数据


手册中找到,但是驱动程序运行在内核空间,一旦 linux 系统运行,就会开启 MMU(内存
管理单元),驱动程序就不可以直接访问物理地址,必须利用 MMU 把物理地址转换为虚
拟地址,然后通过虚拟地址来控制硬件。

思考:如果已经计算出来硬件寄存器的物理地址,应该如何把物理地址转换为虚拟地址??

答案:一般在驱动程序中,常用的一种方案是先从内核空间中申请对应的一块物理内存区
然后把申请的物理内存区再转换为对应的虚拟地址。

 申请物理内存区

申请内核空间的物理内存区可以利用内核源码中提供的宏定义 request_mem_region 来实现


举个例子:比如想要设计一个 GPIO 的驱动程序,使用的引脚是 GPIOC 端口下的某个引脚,
想要利用这个引脚进行电平的输出,则需要利用 CPU 提供的外设寄存器来控制引脚的模式、
功能、输出的电平,使用的寄存器组就应该是 GPIOC 端口的寄存器组,GPIOC 端口的寄存
器组的基地址就是 0xC001C000,每个寄存器都是 32bit,占 4 个字节,通过查看 CPU 数据
手册可以知道 GPIOC 端口的最后一个寄存器的地址是 0xC001C064,所以可以计算出想要申
请的物理内存区的大小就是 64 字节。

 把物理内存区进行映射

申请的物理内存区是不可以直接访问的,需要把物理内存区的地址转换为对应的虚拟地址
可以利用内核源码中提供的 ioremap 函数接口来实现。记住:得到了虚拟地址,和 C 语言
中访问地址的方式一致。

 解除物理内存区的映射
 释放物理内存区的资源

练习:编写驱动程序,确保驱动程序可以驱动开发板的 4 个 LED,利用应用程序来控制硬
件的亮灭。

练习:编写驱动程序,确保驱动程序可以驱动开发板的蜂鸣器,利用应用程序来控制硬件
的鸣叫。

练习:编写驱动程序,确保驱动程序可以驱动开发板的 4 个按键,利用应用程序来控制硬
件。

注意:在卸载驱动的时候,应该在出口函数去归还申请的资源,顺序很重要,尝试自己编
写出口函数。

三、

You might also like