1驱动程序
/*************************************************************************
> File Name: key_enit.c
> Author: yas
> Mail: rage_yas@hotmail.com
> Created Time: 2024年04月22日 星期一 20时20分42秒
************************************************************************/
#if 1
/*=========================The key_enit driver=========================*/
/*==========头文件包含==========*/
#include <linux/init.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/irqreturn.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <mach/irqs.h>
#include <linux/fs.h>
#include <asm/io.h>
/*==========函数声明==========*/
static int __init key_driver_init(void);
static int key_driver_open(struct inode *node, struct file *fp);
static ssize_t key_driver_read(struct file *fp, char __user *user_buffer, size_t len, loff_t *offset);
static ssize_t key_driver_write(struct file *fp, const char __user *user_buffer, size_t len, loff_t *offset);
static int key_driver_close(struct inode *node, struct file *fp);
void disable_irq_r(void);
void free_irq_r(void);
static void __exit key_driver_exit(void);
/*==========全局变量==========*/
/*保存键值*/
u8 key = 0;
/*字符设备文件操作结构体*/
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = key_driver_open,
.read = key_driver_read,
.write = key_driver_write,
.release = key_driver_close
};
/*杂项设备结构体*/
static struct miscdevice key_dev =
{
.minor = MISC_DYNAMIC_MINOR,
.name = "key_r",
.fops = &fops,
};
/*******************************************************************************
* 函 数 名 : key_interrupt
* 函数功能 : 处理中断任务
* 输 入 :
* irq : 中断号
* *p :中断处理函数传参,一般传【NULL】
* 输 出 :
* irqreturn_t :表示中断由该设备处理,是一个枚举类型
*******************************************************************************/
irqreturn_t key_interrupt(int irq, void *p)
{
printk("key_interrupt\n");
if(irq == IRQ_EINT8)
{
key = 1;
}
else if(irq == IRQ_EINT11)
{
key = 2;
}
return IRQ_HANDLED;
}
/*******************************************************************************
* 函 数 名 : key_driver_init
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static int __init key_driver_init(void)
{
int ret;
/* 1 注册杂项设备*/
ret = misc_register(&key_dev);
if(ret < 0)
{
printk("misc_register is failed\n");
goto misc_register_err;
}
/* 2 注册中断-【中断号】-【中断处理函数指针】-【中断产生的条件和系统处理中断时的行为(这里处理中断时不响应其他中断)】-【给中断名命名】-【中断服务函数传参-NULL】*/
ret = request_irq(IRQ_EINT8, key_interrupt, IRQF_TRIGGER_FALLING | IRQF_DISABLED, "key1", NULL);//中断名查看:【/proc/interrupts】
if(ret < 0)
{
printk("request_irq is failed\n");
goto request_irq_err;
}
return 0;
request_irq_err:
misc_deregister(&key_dev);
misc_register_err:
return -1;
}
/*******************************************************************************
* 函 数 名 : key_driver_open
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static int key_driver_open(struct inode *node, struct file *fp)
{
return 0;
}
/*******************************************************************************
* 函 数 名 : key_driver_read
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static ssize_t key_driver_read(struct file *fp, char __user *user_buffer, size_t len, loff_t *offset)
{
copy_to_user(user_buffer, &key, 4);
key = 0;//下降沿触发,没有按键按下时清0
return sizeof(key);
}
/*******************************************************************************
* 函 数 名 : key_driver_write
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static ssize_t key_driver_write(struct file *fp, const char __user *user_buffer, size_t len, loff_t *offset)
{
return 0;
}
/*******************************************************************************
* 函 数 名 : key_driver_close
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static int key_driver_close(struct inode *node, struct file *fp)
{
return 0;
}
/*******************************************************************************
* 函 数 名 : disable_irq_r
* 函数功能 : 禁止中断
* 输 入 :
* 输 出 :
*******************************************************************************/
void disable_irq_r(void)
{
/*禁止中断,如果中断正在执行,则等待中断执行结束后再禁止它*/
disable_irq(IRQ_EINT8);
}
/*******************************************************************************
* 函 数 名 : free_irq_r
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
void free_irq_r(void)
{
/*注销中断*/
free_irq(IRQ_EINT8, NULL);
}
/*******************************************************************************
* 函 数 名 : key_interrupt
* 函数功能 :
* 输 入 :
* 输 出 :
*******************************************************************************/
static void __exit key_driver_exit(void)
{
disable_irq_r();//禁止中断
free_irq_r();//注销中断
misc_deregister(&key_dev);//
}
module_init(key_driver_init);
module_exit(key_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("XXX");
/*=========================The key_enit driver=========================*/
#endif
/*=========================The key_enit driver=========================
* 总结:
* 1 中断原理:
* 注册中断,通过函数传参的方式将中断的重要信息(中断号-中断服务函数-中断触发方式)传给内核,
*从而达到调用内核中断的目的。
* 我觉得这与裸机驱动最大不同的是,作为开发者,我不需要直接接触硬件,我只需要*知道: 用什么工具(哪个中断)做什么事情(中断服务函数),就OK了;抛开外部中断这个具体的项目,我想这是一名内核驱动工程师应当具备的最基本的意识!
*
* 2 按键中断基本流程:
* 在字符设备驱动的基本架构下->采用杂项驱动方式:
* 驱动初始化(注册杂项设备->注册中断->配置中断)->中断响应流程(硬件的工作)
* 驱动卸载(禁止中断->注销中断->注销杂项设备)
*
*
* 3 问题:
* (1)问题1:
* 问题描述:
* 运行应用程序时,应用程序不间地断读取按键状态,即使是没有按键按下
* 问题溯源:
* 应用程序中【read】函数是非阻塞的
* 解决方式:
* 方式1 :驱动层用一个【while】死循环来等待按键按下触发中断,不足之处是
*死循环等待中断触发的方式会造成CPU资源的浪费
方式2 :在驱动层使用等待队列以及poll机制
* */
2应用程序
/*************************************************************************
> File Name: main.c
> Author: yas
> Mail: rage_yas@hotmail.com
> Created Time: 2024年04月21日 星期日 15时56分47秒
************************************************************************/
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main(void)
{
#if 1
/*====================key-r====================*/
int fd=0;
int n=0;
fd=open("dev/key_r",O_RDWR);//这里路径一定要对,尤其是手动创建设备结点的时候
if(fd<0)
{
printf("opening is failed\n");
return -1;
}
while(1)
{
read(fd,&n,4);
printf("%d\n",n);
sleep(1);
}
return 0;
/*========================================*/
#endif
}
3关于内核中断
/*=========================The key_enit driver=========================
* 总结:
* 1 中断原理:
* 注册中断,通过函数传参的方式将中断的重要信息(中断号-中断服务函数-中断触发方式)传给内核,
*从而达到调用内核中断的目的。
* 我觉得这与裸机驱动最大不同的是,作为开发者,我不需要直接接触硬件,我只需要*知道: 用什么工具(哪个中断)做什么事情(中断服务函数),就OK了;抛开外部中断这个具体的项目,我想这是一名内核驱动工程师应当具备的最基本的意识!
*
* 2 按键中断基本流程:
* 在字符设备驱动的基本架构下->采用杂项驱动方式:
* 驱动初始化(注册杂项设备->注册中断->配置中断)->中断响应流程(硬件的工作)
* 驱动卸载(禁止中断->注销中断->注销杂项设备)
*
*
* 3 问题:
* (1)问题1:
* 问题描述:
* 运行应用程序时,应用程序不间地断读取按键状态,即使是没有按键按下
* 问题溯源:
* 应用程序中【read】函数是非阻塞的
* 解决方式:
* 方式1 :驱动层用一个【while】死循环来等待按键按下触发中断,不足之处是
*死循环等待中断触发的方式会造成CPU资源的浪费
方式2 :在驱动层使用等待队列以及poll机制
* */