Linux火焰传感器驱动程序
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");