@[TOC](嵌入式LINUX驱动学习之10物理地址-内核虚拟地址映射 ioremap()/iounmap())
一、头文件、函数及说明
//源码位置:arch/arm/include/asm/io.h
#define MT_DEVICE 0
#define MT_DEVICE_NONSHARED 1
#define MT_DEVICE_CACHED 2
#define MT_DEVICE_WC
#define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)//实现源码见附A.1
/*
ioremap(unsigned long pyh,size_t size);
参数说明:
cookie : 类型:unsigned long ,用于保存保存物理地址
size : 类型:size_t , 用于保存数据大小,单位Byte;
功 能:
将物理地址映射成内核区的虚拟地址,将来操作内核空间的虚拟地址,就相当于操作物理地址;
返回值 :
成功:void * 类型的内核空间虚拟址
失败:NULL;
*/
#define iounmap __arm_iounmap
extern void __arm_iounmap(volatile void __iomem *addr);
/*
iounmap(void * addr);
参数说明:
addr: ioremap()的返回值;
功 能:
释放形参内核虚拟地址和对应的物理地址的映射关系。
*/
二、代码举例
功能:
通过按键k1控制蜂鸣器的开和关
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <cfg_type.h>
#include <linux/io.h>
/*定义按键信息,通过数组形式目的是为后续可以扩充其它功能键*/
struct btn_src {
char * name ;
int gpio;
};
struct btn_src btn_info[] = {
{
.name = "BTN_BEEP",
.gpio = PAD_GPIO_A + 28
}
};
static spinlock_t lock;//定义一个锁结构体对象
void * v_beep_base;//保存ioremap分配的基础地址
unsigned long *beep_base;//转换为整形的基础地址
unsigned long *beep_outenb;//GPIO模式:0:输入,1:输出
unsigned long *beep_altfn;//GPIO复用功能选择器
int beep_state;//用于记录蜂鸣器状态
/*控制蜂鸣器开和ud */
static void beep_func(void){
/*使用衍生自旋锁保护寄存器和全局变量操作过程,使得执行过程不被中断*/
unsigned long flags;
spin_lock_irqsave(&lock,flags);
if(beep_state){
*beep_base &= ~(0x1 << 14);//低电平关闭蜂鸣器
}
else {
*beep_base |= (1 << 14);//高电平时打开蜂鸣器
}
beep_state = 1-beep_state;//将蜂鸣器状态反转;
spin_unlock_irqrestore(&lock,flags);//释放锁
}
/*中断处理函数:
当发生中断时调用beep_func()函数 ,并且打印中断号信息
*/
static irqreturn_t btn_irq(int irq,void * args){
struct btn_src *btn_ = (struct btn_src *) args;
beep_func();
printk("%s,%s , irq: %d\n",__func__,btn_ -> name,irq);
return IRQ_HANDLED;
}
static int btn_beep_init(void){
int i = 0;
for(; i<ARRAY_SIZE(btn_info); i++){
gpio_request(btn_info[i].gpio,btn_info[i].name);
gpio_direction_input(btn_info[i].gpio);
request_irq(gpio_to_irq(btn_info[i].gpio),btn_irq,\
IRQF_TRIGGER_RISING,btn_info[i].name,\
&btn_info[i]);
}
spin_lock_init(&lock);//初始化一个自旋锁对象
v_beep_base = ioremap((unsigned long) 0xC001C000,0x24);//基础地址
beep_base = (unsigned long *) v_beep_base;//转换为整形的基础地址
beep_outenb = (unsigned long *) (v_beep_base + 0x04);//GPIO模式:0:输入,1:输出
beep_altfn = (unsigned long *) (v_beep_base + 0x20);//GPIO复用功能选择器
beep_state = 0;//用于记录蜂鸣器状态
*beep_outenb |= (0x1 << 14);//设置GPIOC14为输出口
*beep_base &= ~(0X1 << 14);//设置GPIOC14为低电平,即蜂鸣器为关闭状态
*beep_altfn &= ~(0x11 << 28);/*功能复用选择寄存器,设置为GPIO功能*/
*beep_altfn |= (0x1 << 28);
printk("加载模块完成\n");
return 0;
}
static void btn_beep_exit(void){
int i = 0;
for(; i < ARRAY_SIZE(btn_info);i ++){
free_irq(gpio_to_irq(btn_info[i].gpio),&btn_info[i]);
gpio_free(btn_info[i].gpio);
}
*beep_base &= ~(0x1 << 14);//模块卸载前,将GPIOC14电平设置为低电平
iounmap(v_beep_base);//释放映射的虚拟地址空间
printk("卸载模块完成\n");
}
module_init(btn_beep_init);
module_exit(btn_beep_exit);
MODULE_LICENSE("GPL");
附A.1
//头文件位置:arch/arm/include/asm/io.h
//实现源码位置:arch/arm/mm/ioremap.c
void __iomem *
__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
{
return arch_ioremap_caller(phys_addr, size, mtype,
__builtin_return_address(0));
}