ioremap()地址映射
ioremap 函数用于将设备的物理地址映射到内核的虚拟地址空间,这样内核就可以通过普通的指针访问硬件寄存器。
void *regGPGCON = ioremap(0x00000000, 4);
这里的 0x00000000 是 物理地址,而 regGPGCON 指向的是 虚拟地址。
void *regGPGCON;
regGPGCON = ioremap(GPGCON, 4);
GPGCON 是 物理地址,即硬件寄存器的实际地址。
regGPGCON 是 虚拟地址,即通过 ioremap 映射后的地址,用于内核访问硬件寄存器。
等待队列 Wait Queue 处理内核中断
等待队列:是一个数据结构,用于跟踪一组等待特定事件发生的进程。
等待队列条目:每个进程都会在等待队列中有一个对应的条目,记录着进程的状态和其他相关信息。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/irqreturn.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <mach/irqs.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define GPGCON (0x56000060) //端口控制寄存器 用来设置端口的引脚功能 将来配为 外部中断EINT模式
#define GPGDAT (0X56000064) //数据寄存器 在EINT模式下 如果检测到外部中断 就会改变这个寄存器的电平 读取引脚的电平
#define GPGUP (0x56000068) // 上拉使能寄存器
static unsigned int *regGPGCON; // 物理地址映射到虚拟地址 所指向的指针
static unsigned int *regGPGDAT;
static unsigned int *regGPGUP;
static wait_queue_head_t wq; // 等待队列队头
static int condition; // 等待条件
int fire = 0;
irqreturn_t fire_handler(int irq_num,void *dev)
{
if(irq_num == IRQ_EINT15)
{
fire = 1;
}
condition = 1;
wake_up(&wq);
return IRQ_HANDLED;
}
int fire_open(struct inode *p_node,struct file *fp)
{
return 0;
}
int fire_release(struct inode *p_node,struct file *fp)
{
return 0;
}
ssize_t fire_write(struct file *fp,const char __user *user_buffer,size_t n,loff_t *offset)
{
return 0;
}
ssize_t fire_read(struct file *fp,char __user *user_buffer,size_t n,loff_t *offset)
{
condition = 0;
wait_event_interruptible(wq,condition);
copy_to_user(user_buffer,&fire,4);
fire = 0;
return sizeof(fire);
}
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = fire_open,
.release = fire_release,
.read = fire_read,
};
//定义了一个杂项设备,用于注册设备节点。
static struct miscdevice fire_device =
{
.minor = MISC_DYNAMIC_MINOR,
.fops = &fops,
.name = "fire"
};
static int __init fire_driver_init(void)
{
int ret;
ret = misc_register(&fire_device);
if(ret)
{
printk("misc_register is error");
return ret;
}
ret = request_irq(IRQ_EINT15,fire_handler,IRQF_TRIGGER_RISING | IRQF_DISABLED,"fire_irq",&fire_device);
if(ret)
{
printk("request_irq is error\n");
misc_deregister(&fire_device);
}
init_waitqueue_head(&wq);
regGPGCON = ioremap(GPGCON,4);
regGPGDAT = ioremap(GPGDAT,4);
regGPGUP = ioremap(GPGUP,4);
return 0;
}
void __exit fire_exit(void)
{
iounmap(regGPGCON);
iounmap(regGPGDAT);
iounmap(regGPGUP);
disable_irq(IRQ_EINT15);
free_irq(IRQ_EINT15,&fire_device);
misc_deregister(&fire_device);
}
module_init(fire_driver_init);
module_exit(fire_exit);
MODULE_LICENSE("GPL");