赞
踩
Linux 内核中的中断框架使用已经相当便捷,一般需要做三件事申请中断、实现中断服务函数、使能中断。对应的接口函数如下:( 一 ) 中断申请和释放函数1) 中断申请凼数 request_irq ,该凼数可能会导致睡眠,在申请成功后会使能中断,凼数原型:
int request_irq(unsignedintirq,irq_handler_t handler, unsigned long flags, const char*name,void*dev);
参数说明:irq :申请的中断号,中断号也可以叫中断线,是中断的唯一标识,也是内核找到对应中断服务函数的依据。handler :中断服务函数,中断触发后会执行的函数。flags :中断标志,用于设置中断的触发方式和其他特性,常用的标识有/* 无触发 */IRQF_TRIGGER_NONE/* 上升沿触发*/IRQF_TRIGGER_RISING/* 下降沿触发*/IRQF_TRIGGER_FALLING/* 高电平触发*/IRQF_TRIGGER_HIGH/* 低电平触发*/IRQF_TRIGGER_LOW/* 单次中断 */IRQF_ONESHOT/* 作为定时器中断 */IRQF_TIMER/* 共享中断,多个设备共享一个中断号时需要此标志 */IRQF_SHARED可在 /include/linux/interrupt.h 文件中可以查看全部的 flag 和 英文释义。中断标志可以使用 |号来组合,如 IRQF_TRIGGER_RISING|IRQF_ONESHOT 意为上升沿触发的单次中断。name :中断名称,申请中断成功后,在 /proc/interrupts 文件中可以找到这个名字。dev : flag 设 置 IRQF_SHARED 时,使用 dev 来区分不同的讴备, dev 的值会传递经中断服务函数的第二个参数。返回值 : 0- 申请成功, -EBUSY- 中断已被占用,其他值都表示申请失败。2) 和 中断申请相对的中断释放函数 free_irq ,如果目标中断不是共享中断,那么 free_irq凼数在释放中断后,会禁止中断并删除中断服务函数,原型如下:
void free_irq(unsigned int irq, void *dev);
参数说明:irq :需要释放的中断。dev :释放的中断如果是共享中断,用这个参数来区分具体的中断,只有共享中断下所有的dev 都被释放时, free_irq 函 数才会禁止中断并删除中断服务函数。
中断服务函数的格式为:
irqreturn_t (*irq_handler_t) (int, void *)
第一个参数 是int类型, 中断服务函数对应的中断号。第二个参数是通用指针,需要和 request_irq 函 数的参数 dev 一致。返回值 irqreturn_t 为枚举类型,一般在服务函数中用下面的方式返回值:return IRQ_RETVAL(IRQ_HANDLED);
中断使能和禁止函数
1) enable_irq(unsigned int irq) 、 disable_irq(unsigned int irq)和 disable_irq_nosync(unsigned int irq)enable_irq 和 disable_irq 分别是中断使能和禁止函数, irq 是目标中断号。 disable_irq 会等待目标中断的中断服务函数执行结束才会禁止中断,如果想要立即禁止中断则可以使用disable_irq_nosync()函 数。2) local_irq_enable()和 local_irq_disable()local_irq_enable()函 数用于使能当前处理器的中断系统。local_irq_disable()函 数用于禁止当前处理器的中断系统。3) local_irq_save(flags)和 local_irq_restore(flags)local_irq_save(flags)函 数也是用于禁止当前处理器中断,但是会把之前前的中断状态保存在输入参数 flags 中。而 local_irq_restore(flags)函 数则是把中断恢复到 flags 中记录的状态。
- struct tasklet_struct
- {
- struct tasklet_struct *next;
- unsigned long state;
- atomic_t count;
- void (*func)(unsigned long);
- unsigned long data;
- };
extern void tasklet_kill(struct tasklet_struct *t);
extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);
extern void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data);
static inline void tasklet_enable(struct tasklet_struct *t)
static inline void tasklet_disable(struct tasklet_struct *t)
static inline void tasklet_disable_nosync(struct tasklet_struct *t)static inline void tasklet_schedule(struct tasklet_struct *t)
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/cdev.h>
- #include <linux/slab.h>
- #include <linux/fs.h>
- #include <linux/device.h>
- #include <linux/kernel.h>
- #include <linux/types.h>
- #include <linux/kref.h>
- #include <linux/uaccess.h>
- #include <linux/ide.h>
- #include <linux/of.h>
- #include <linux/gpio/consumer.h>
- #include <linux/delay.h>
- #include <linux/timer.h>
- #include <linux/jiffies.h>
-
- #define DEBUG_INFO(format,...) printk(KERN_ERR"%s:%d"format"\n",\
- __func__,__LINE__,##__VA_ARGS__)
-
- struct ch7_private_data{
- struct timer_list timer;
- int count;
- long last_jiffies;
- struct tasklet_struct tasklet;
- };
-
- void tasklet_func(unsigned long arg)
- {
- struct ch7_private_data *p = (struct ch7_private_data*)arg;
- DEBUG_INFO("p->count = %d",p->count++);
- }
- void ch7_timer_function(struct timer_list *ptimer){
- struct ch7_private_data *p = (struct ch7_private_data*)container_of(ptimer,struct ch7_private_data,timer);
- if(p == NULL){
- DEBUG_INFO("container_of error");
- return ;
- }
- if(p->count >= 5){
-
- }else{
- mod_timer(&p->timer,jiffies + msecs_to_jiffies(1000));
- }
- tasklet_schedule(&p->tasklet);
- }
-
- struct ch7_private_data *ch7_02;
-
- static int __init ch7_init(void)
- {
- struct ch7_private_data *p = (struct ch7_private_data*)kmalloc(sizeof(struct ch7_private_data),GFP_KERNEL);
- if(p == NULL){
- DEBUG_INFO("kmalloc error");
- return -ENOMEM;
- }
- DEBUG_INFO("%ld" ,sizeof(jiffies));
- ch7_02 = p;
- p->count = 0;
-
- timer_setup(&p->timer,ch7_timer_function,0);
- tasklet_init(&p->tasklet, tasklet_func, (unsigned long)p);
- mod_timer(&p->timer,jiffies + msecs_to_jiffies(1000));
- DEBUG_INFO("init");
- return 0;
- }
-
- static void __exit ch7_exit(void)
- {
- struct ch7_private_data *p = ch7_02;
- del_timer_sync(&p->timer);
- DEBUG_INFO("exit");
- }
-
- // #define nodule_init(x) (x)
-
- module_init(ch7_init);
- module_exit(ch7_exit);
-
- MODULE_LICENSE("GPL");
makefile
- modname:=ch08-tasklet
- obj-m:=$(modname).o
- PWD :=$(shell pwd)
- KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
-
- # KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/ch6-petalinux/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
- CROSS_COMPILE=aarch64-linux-gnu-
- ARCH=arm64
- all:
- $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
- cp $(modname).ko ~/work/nfsroot/
- # aarch64-linux-gnu-gcc -o app app.c
- # cp app ~/work/nfsroot/
- clean:
- rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions
- .PHONY: all clean
测试结果:
- struct work_struct {
- atomic_long_t data;
- struct list_head entry;
- work_func_t func;
- #ifdef CONFIG_LOCKDEP
- struct lockdep_map lockdep_map;
- #endif
- };
初始化函数
#define INIT_WORK(_work, _func) \
__INIT_WORK((_work), (_func), 0)
_work: struct work_struct*指针。
_func:void (*func)(unsigned long)类型
调度函数
static inline bool schedule_work(struct work_struct *work)
测试代码:
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/cdev.h>
- #include <linux/slab.h>
- #include <linux/fs.h>
- #include <linux/device.h>
- #include <linux/kernel.h>
- #include <linux/types.h>
- #include <linux/kref.h>
- #include <linux/uaccess.h>
- #include <linux/ide.h>
- #include <linux/of.h>
- #include <linux/gpio/consumer.h>
- #include <linux/delay.h>
- #include <linux/timer.h>
- #include <linux/jiffies.h>
- #include <linux/workqueue.h>
-
-
- #define DEBUG_INFO(format,...) printk(KERN_ERR"%s:%d"format"\n",\
- __func__,__LINE__,##__VA_ARGS__)
-
- struct ch7_private_data{
- struct timer_list timer;
- int count;
- long last_jiffies;
- struct work_struct work;
- };
-
- void ch8_work_func_t(struct work_struct *pwork){
- struct ch7_private_data *p = (struct ch7_private_data*)container_of(pwork,struct ch7_private_data,work);
- DEBUG_INFO("p->count = %d",p->count++);
- }
-
- void ch7_timer_function(struct timer_list *ptimer){
- struct ch7_private_data *p = (struct ch7_private_data*)container_of(ptimer,struct ch7_private_data,timer);
- if(p == NULL){
- DEBUG_INFO("container_of error");
- return ;
- }
- if(p->count >= 5){
-
- }else{
- mod_timer(&p->timer,jiffies + msecs_to_jiffies(1000));
- }
- schedule_work(&p->work);
- }
-
- struct ch7_private_data *ch7_02;
-
- static int __init ch7_init(void)
- {
- struct ch7_private_data *p = (struct ch7_private_data*)kmalloc(sizeof(struct ch7_private_data),GFP_KERNEL);
- if(p == NULL){
- DEBUG_INFO("kmalloc error");
- return -ENOMEM;
- }
- DEBUG_INFO("%ld" ,sizeof(jiffies));
- ch7_02 = p;
- p->count = 0;
-
- timer_setup(&p->timer,ch7_timer_function,0);
- INIT_WORK(&p->work,ch8_work_func_t);
- mod_timer(&p->timer,jiffies + msecs_to_jiffies(1000));
- DEBUG_INFO("init");
- return 0;
- }
-
- static void __exit ch7_exit(void)
- {
- struct ch7_private_data *p = ch7_02;
- del_timer_sync(&p->timer);
- DEBUG_INFO("exit");
- }
-
- // #define nodule_init(x) (x)
-
- module_init(ch7_init);
- module_exit(ch7_exit);
-
- MODULE_LICENSE("GPL");
makefile
- modname:=ch8-workqueue
- obj-m:=$(modname).o
- PWD :=$(shell pwd)
- KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
-
- # KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/ch6-petalinux/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
- CROSS_COMPILE=aarch64-linux-gnu-
- ARCH=arm64
- all:
- $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
- cp $(modname).ko ~/work/nfsroot/
- # aarch64-linux-gnu-gcc -o app app.c
- # cp app ~/work/nfsroot/
- clean:
- rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions
- .PHONY: all clean
测试结果:
测试代码:
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/cdev.h>
- #include <linux/slab.h>
- #include <linux/fs.h>
- #include <linux/device.h>
- #include <linux/kernel.h>
- #include <linux/types.h>
- #include <linux/kref.h>
- #include <linux/uaccess.h>
- #include <linux/ide.h>
- #include <linux/of.h>
- #include <linux/gpio/consumer.h>
- #include <linux/delay.h>
- #include <linux/timer.h>
-
-
- #define _DEBUG_INFO
- #ifdef _DEBUG_INFO
- #define DEBUG_INFO(format,...) printk(KERN_ERR"%s:%d -- "format"\n",\
- __func__,__LINE__,##__VA_ARGS__)
- #else
- #define DEBUG_INFO(format,...)
- #endif
-
- #define CH2_DRIVER_NAME "ch8_key"
- #define CH2_CLASS_NAME "ch8_driver_class_name"
- #define CH2_BUF_MAX_LEN 20
-
- struct ch2_private_data{
- struct cdev cdev;
- dev_t devid;
- int dev_count;
- int major,minor;
- struct file_operations *fops;
- struct class *class;
- struct device *device;
- struct device_node *nd;
- struct gpio_desc *gpio_d;
- struct semaphore lock;
- unsigned int irq;
- struct timer_list timer;
- char key_state;
- };
-
- static irqreturn_t key_handler(int irq, void *dev)
- {
- struct ch2_private_data * cpd = (struct ch2_private_data*)dev;
- mod_timer(&cpd->timer, jiffies + msecs_to_jiffies(10));
- // DEBUG_INFO("key pressed");
- return IRQ_RETVAL(IRQ_HANDLED);
- }
-
- void timer_function(struct timer_list *ptimer)
- {
- struct ch2_private_data * cpd = (struct ch2_private_data*)container_of(ptimer,struct ch2_private_data,timer);
- cpd->key_state = 1;
- DEBUG_INFO("key up");
- }
-
- static int ch2_open(struct inode *inode, struct file *file){
- int ret = 0;
- struct ch2_private_data * cpd = (struct ch2_private_data*)container_of(inode->i_cdev,struct ch2_private_data,cdev);
- DEBUG_INFO("major = %d, minor = %d\n", cpd->major, cpd->minor);
- file->private_data = cpd;
- ret = down_interruptible(&cpd->lock);
- if(ret){
- DEBUG_INFO("open fail");
- ret = -EBUSY;
- }else{
- DEBUG_INFO("open ok");
- }
- return ret;
- }
-
- static ssize_t ch2_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
- {
- int ret = 0;
- char state[2] = {0x30,0x00};
- struct ch2_private_data * cpd = (struct ch2_private_data*)file->private_data;
-
- if(cpd->key_state == 1){
- state[0] = 0x31;
- }else{
- state[0] = 0x30;
- }
- cpd->key_state = 0;
- ret = copy_to_user(buf,state,1);
- if(ret){
- DEBUG_INFO("copy_to_user error");
- return 0;
- }
-
- if(*pos == 0){
- *pos = 1;
- ret = 1;
- return ret;
- }
- return 0;
- }
- static int ch2_release(struct inode *inode, struct file *file){
- struct ch2_private_data * cpd = (struct ch2_private_data*)container_of(inode->i_cdev,struct ch2_private_data,cdev);
- up(&cpd->lock);
- DEBUG_INFO("release");
- return 0;
- }
-
- struct file_operations ch2_fops={
- .owner = THIS_MODULE,
- .open = ch2_open,
- .release = ch2_release,
- .read = ch2_read,
- };
- struct ch2_private_data *global_chd = NULL;
- static int __init ps_led_init(void)
- {
- int res = 0;
- // u32 reg_data[6] = {0};
- struct ch2_private_data *chd = (struct ch2_private_data*)kmalloc(sizeof(struct ch2_private_data),GFP_KERNEL);
- if(chd == NULL){
- DEBUG_INFO("kmalloc");
- return -ENOMEM;
- }
- global_chd = chd;
- chd->dev_count = 1;
- chd->fops = &ch2_fops;
- cdev_init(&chd->cdev,chd->fops);
- res = alloc_chrdev_region(&chd->devid,1,chd->dev_count,CH2_DRIVER_NAME);
- if(res != 0){
- DEBUG_INFO("kmaalloc_chrdev_regionlloc");
- return -EINVAL;
- }
- chd->major = MAJOR(chd->devid);
- chd->minor = MINOR(chd->devid);
-
- cdev_add(&chd->cdev,chd->devid,chd->dev_count);
- chd->class = class_create(THIS_MODULE,CH2_CLASS_NAME);
- if(IS_ERR(chd->class)){
- DEBUG_INFO("class_create");
- return -EINVAL;
- }
-
- chd->device = device_create(chd->class,NULL,chd->devid,NULL,CH2_DRIVER_NAME"_%d",0);
- if(IS_ERR(chd->class)){
- DEBUG_INFO("device_create");
- return -EINVAL;
- }
-
- chd->nd = of_find_node_by_path("/alinxkeypl");
- if(chd->nd == NULL){
- DEBUG_INFO("of_find_node_by_path error");
- return 0;
- }
- chd->device->of_node = chd->nd;
- chd->gpio_d = gpiod_get_index(chd->device, "key", 0, GPIOD_IN);
- if(chd->gpio_d == NULL){
- DEBUG_INFO("gpiod_get_index error");
- return 0;
- }
- gpiod_direction_input(chd->gpio_d);
-
- sema_init(&chd->lock, 1);
- chd->key_state = 0;
- chd->irq = gpiod_to_irq(chd->gpio_d);
- res = request_irq(chd->irq, key_handler, IRQF_TRIGGER_RISING, "alinxkey", chd);
- if(res < 0){
- DEBUG_INFO("request_irq error");
- return 0;
- }
- timer_setup(&chd->timer, timer_function, 0);
- // add_timer(&chd->timer);
- DEBUG_INFO("init ok");
-
- return 0;
- }
-
- static void __exit ps_led_exit(void)
- {
- del_timer(&global_chd->timer);
- free_irq(global_chd->irq,global_chd);
- gpiod_put(global_chd->gpio_d);
- device_destroy(global_chd->class,global_chd->devid);
- class_destroy(global_chd->class);
- cdev_del(&global_chd->cdev);
- unregister_chrdev_region(global_chd->devid,global_chd->dev_count);
- kfree(global_chd);
- DEBUG_INFO("exit");
- }
-
- module_init(ps_led_init);
- module_exit(ps_led_exit);
-
- MODULE_LICENSE("GPL");
makefile:
- modname:=ch8-01
- obj-m:=$(modname).o
- PWD :=$(shell pwd)
- # KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/petalinux_bsp/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
-
- KERNELDIR = /home/lkmao/peta_prj/linuxPsBase/ch6-petalinux/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
- CROSS_COMPILE=aarch64-linux-gnu-
- ARCH=arm64
- all:
- $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
- cp $(modname).ko ~/work/nfsroot/
- # aarch64-linux-gnu-gcc -o app app.c
- # cp app ~/work/nfsroot/
- clean:
- rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions
- .PHONY: all clean
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。