本章开始编写第一个真正的 Linux 字符设备驱动。
LED 灯驱动最终也是对 I.MX6ULL 的 IO 口进行配置,并配置相应的硬件寄存器,与裸机实验不同的是,在 Linux 下编写驱动要符合 Linux的驱动框架。
MMU 全称叫做 MemoryManage Unit,也就是内存管理单元。 MMU 主要完成的功能如下: ①、完成虚拟空间到物理空间的映射。 ②、内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性。
物理地址:真实存在的地址,如 512MB 的 DDR3; 虚拟地址:MMU映射的地址,如32 位的处理器,虚拟地址范围是 2^32=4GB。 MMU就是将少的物理地址映射到更多的虚拟地址,之前裸机开发用到的都是物理内存,直接往寄存器写数据;有了MMU之后,就需要向寄存器所在的物理地址映射的虚拟地址写数据。
如下图:
物理内存和虚拟内存之间的转换,需要用到两个函数: ioremap 和 iounmap。
1、 ioremap 函数 ioremap 函 数 用 于 获 取 指 定 物 理 地 址 空 间 对 应 的 虚 拟 地 址 空 间 , 定 义 在arch/arm/include/asm/io.h
1 #define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE) 2 3 void __iomem * __arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype) 4 { 5 return arch_ioremap_caller(phys_addr, size, mtype, __builtin_return_address(0)); 6 } phys_addr:要映射给的物理起始地址。 size:要映射的内存空间大小。 mtype: ioremap 的类型,可以选择 MT_DEVICE、 MT_DEVICE_NONSHARED、MT_DEVICE_CACHED 和 MT_DEVICE_WC, ioremap 函数选择 MT_DEVICE。 返回值: __iomem 类型的指针,指向映射后的虚拟空间首地址。2、 iounmap 函数 卸载驱动的时候需要使用 iounmap 函数释放掉 ioremap 函数所做的映射:
void iounmap (volatile void __iomem *addr)3、加载/卸载驱动
SW_MUX_GPIO1_IO03 就是一个__iomem类型的指针。
//加载 #define SW_MUX_GPIO1_IO03_BASE (0X020E0068) static void __iomem* SW_MUX_GPIO1_IO03; SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4); //卸载 iounmap(SW_MUX_GPIO1_IO03);I/O 端口:当外部寄存器或内存映射到 IO 空间时; I/O 内存:当外部寄存器或内存映射到内存空间时。
对于 ARM 来说没有 I/O 空间这个概念,因此 ARM 体系下只有 I/O 内存(可以直接理解为内存)。
Linux 内核不建议直接通过指针访问这些地址,而是推荐使用一组操作函数来对映射后的内存进行读写操作。
1、读操作函数
1 u8 readb(const volatile void __iomem *addr) 2 u16 readw(const volatile void __iomem *addr) 3 u32 readl(const volatile void __iomem *addr)2、写操作函数
1 void writeb(u8 value, volatile void __iomem *addr) 2 void writew(u16 value, volatile void __iomem *addr) 3 void writel(u32 value, volatile void __iomem *addr)以上函数不做太多说明,有眼就行。
程序的编写和上一章虚拟设备驱动的编写类似,不用写注释了,自己能看懂就行了,理解大概意思就行,后边儿还会学习新字符设备驱动。
led.c
在这里插入代码片ledApp.c
在这里插入代码片Makefile
KERNELDIR := /home/zxy/linux/kernel_lib/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek CURRENT_PATH := $(shell pwd) obj-m := led.o build: kernel_modules kernel_modules: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules clean: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean没啥好说,没啥新知识。 就是原子出厂的设备树中内置了led的设备树,里边儿有心跳灯功能,进入到设备树文件.dts中,将其中的led设备树相关的状态"on"改为"off",然后在内核目录make dtbs即可重新编译设备树,mfgtool烧写即可。