将特殊功能寄存器物理地址进行映射
通过映射之后的虚拟地址访问特殊功能寄存器
统一编址:将内存和外设(特殊功能寄存器)
使用同一套地址编号去编址,称作统一编址
ARM处理器
访问内存 ldr/str
访问外设 ldr/str
独立编址:将内存和外设(特殊功能寄存器)
各自使用一套独立的编号去编址,称作独立编址
X86处理器
访问内存 mov
访问外设 in / out
linux内核中将使用统一编址的外设称为I/O内存
独立编址的外设称为I/O端口
Linux内核中访问特殊功能寄存器(外设)的步骤:
1)申请I/O内存
request_mem_region(start,n,name)
start,要申请的I/O内存起始地址
n, 要连续申请的字节数
name,名称
2)映射I/O内存
void __iomem *ioremap(phys_addr_t start, unsigned long n)
start,要映射的起始物理地址
n, 要连续映射的字节数
返回值,映射后的起始虚拟地址
例如:start=0xc001c00 n=0x100 返回值=0xf0000000
意味着: 虚拟地址 物理地址
0xf0000000 0xc001c000
3)访问I/O内存
方法一:
*((volatile unsigned int *)0xf0000000) = var;
var = *(volatile unsigned int *)0xf0000000;
方法二:
#define readl(addr) __le32_to_cpu(__raw_readl(addr))
readl(addr); // l,long
#define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
writel(val,addr);
4)取消映射
void iounmap(void __iomem *addr)
addr,ioremap时返回的起始虚拟地址
5)释放I/O内存
#define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n))
release_mem_region(start,n)
start,要释放的起始物理地址
n,要连续释放的字节数
注意:步骤1)、5)是可选的
练习:希望安装内核模块时LED1亮
卸载内核模块时LED1灭
通过直接访问特殊功能寄存器实现,而不用GPIO库函数
cpu datasheet:
GPIOCALTFN0 0xc001c020
[25:24] 01
GPIOCOUTENB 0xc001c004
[12] 1,输出模式
GPIOCOUT 0xc001c000
[12] 0/1 输出低/高电平