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;//下降沿触发,没有按键按下时清0return 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机制
* */