(九)linux中断编程

(一)linux中断的介绍

linux内核中的中断通过中断子系统来管理。linux系统中有专门的中断子系统,原理很复杂,驱动开发者不需要知道具体细节,只需要知道如何应用该子系统提供的api来编写中断驱动代码即可
在linux内核中,文件大多以功能命名,内核中提供了一个interrupt.h的文件用来进行中断先关接口及数据结构的声明,内核使用struct irqaction结构体描述一个中断,编写中断程序终极目标就是实现这个结构体

 * struct irqaction - per interrupt action descriptor
 * @handler:	interrupt handler function
 * @name:	name of the device
 * @dev_id:	cookie to identify the device-----------是否是一个共享中断
 * @percpu_dev_id:	cookie to identify the device
 * @next:	pointer to the next irqaction for shared interrupts
 * @irq:	interrupt number
 * @flags:	flags (see IRQF_* above)
 * @thread_fn:	interrupt handler function for threaded interrupts
 * @thread:	thread pointer for threaded interrupts
 * @thread_flags:	flags related to @thread
 * @thread_mask:	bitmask for keeping track of @thread activity
 * @dir:	pointer to the proc/irq/NN/name entry
 * @flags:	flags (see IRQF_* above)
 */
struct irqaction {
	irq_handler_t		handler;    //用户注册的中断处理函数 
	void			*dev_id;//可以是用户传递的参数或者用来区分共享中断
	void __percpu		*percpu_dev_id;
	struct irqaction	*next;		//irqaction结构链,一个共享中断可以有多个中断处理函数 
	irq_handler_t		thread_fn;
	struct task_struct	*thread;
	unsigned int		irq;	//中断号
	unsigned int		flags;	//中断标识
	unsigned long		thread_flags;
	unsigned long		thread_mask;
	const char		*name;	//用户注册的中断名字,cat/proc/interrupts时可以看到 
	struct proc_dir_entry	*dir;
} ____cacheline_internodealigned_in_smp;

flags :

IRQF_DISABLED:私有中断,即一个中断请求对应一个中断服务函数
IRQF_SHARED:共享中断,多个中断请求对应一个中断服务函数
(二)内核中断的操作过程
  1. 向内核提出中断申请
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
	    const char *name, void *dev)//dev   ---若是独占(共享)中断--直接赋值为空(用来区分哪一个中断占用服务函数)
{
	return request_threaded_irq(irq, handler, NULL, flags, name, dev);
}
unsigned int irq:中断号(线)
       中断线号是处理器生产厂商指定的,在内核对应的文件中有相应声明,在内核的内部有一个与
       架构匹配的irqs.h的文件,该文件对中中断线进行了声明
       硬件规定好的 
irq_handler_t handler:中断服务函数
unsigned long flags:中断标志
     *  IRQF_SHARED		    Interrupt is shared
     *	IRQF_SAMPLE_        RANDOM	The interrupt can be used for entropy
     *	IRQF_TRIGGER_*		Specify active edge(s) or level
const char *name:设备名
void *dev:设备标识,只有在共享中断中此参数此参数才有效,因为私有中断不共享服务函数,无需判断是哪一个设备触发的中断
私有中断中可有直接赋值NULL

cpu给中断的一个编号,一个IRQ number是一个虚拟的interrupt ID,和硬件无关.
查找中断线比较费时,所以内核中提供了一个操作接口来获取指定引脚的中中断号

static inline int gpio_to_irq(unsigned int gpio)
{
	return __gpio_to_irq(gpio);
}

参数为gpio口:
在内核中生产厂商提供了先关的gpio口的声明,分别存放在指定架构目录下的gpio.h

#define EXYNOS_GPIO_NEXT(__gpio) \
	((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)

/* EXYNOS4 GPIO bank sizes */
标识每一组引脚的个数,如#define EXYNOS4_GPIO_A0_NR	(8)就表示
GPAO组一共有8个引脚
#define EXYNOS4_GPIO_A0_NR	(8)
  1. 释放中断 free_irq(unsigned int, void *)
void free_irq(unsigned int irq, void *dev_id)

其他相关函数:

 void disable_irq(unsigned int irq);//失能
 void enable_irq(unsigned int irq);//使能
int  gpio_get_value(unsigned int gpio);// 获取设备gpio口的值:
void gpio_set_value(unsigned int gpio, int value);//设置设备的gpio的值

(三)实例代码
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>

irqreturn_t key1_handler(int irq, void *dev)
{
  int value=gpio_get_value(EXYNOS4_GPX3(2));
  printk("key1 value is %d\n",value);
  return IRQ_HANDLED;
}
irqreturn_t key2_handler(int irq, void *dev)
{
  int value=gpio_get_value(EXYNOS4_GPX3(3));
  printk("key2 value is %d\n",value);
  return IRQ_HANDLED;
}
irqreturn_t key3_handler(int irq, void *dev)
{
  int value=gpio_get_value(EXYNOS4_GPX3(4));
  printk("key3 value is %d\n",value);
  return IRQ_HANDLED;
}
irqreturn_t key4_handler(int irq, void *dev)
{
  int value=gpio_get_value(EXYNOS4_GPX3(5));
  printk("key4 value is %d\n",value);
  return IRQ_HANDLED;
}

static int __init handler_module_init(void)
{
	int ret=0;
  unsigned long flags=IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING|IRQF_DISABLED;
  unsigned int irq=gpio_to_irq(EXYNOS4_GPX3(2)); //获取K1的irq
  ret=request_irq(irq,key1_handler,flags, "key0", NULL);
  irq=gpio_to_irq(EXYNOS4_GPX3(3)); //获取K1的irq
  ret=request_irq(irq,key2_handler,flags, "key0", NULL);
  irq=gpio_to_irq(EXYNOS4_GPX3(4)); //获取K1的irq
  ret=request_irq(irq,key3_handler,flags, "key0", NULL);
  irq=gpio_to_irq(EXYNOS4_GPX3(5)); //获取K1的irq
  ret=request_irq(irq,key4_handler,flags, "key0", NULL);
  return 0;
}
static void __exit handler_module_cleanup(void)
{
  unsigned int irq=gpio_to_irq(EXYNOS4_GPX3(2)); //获取K1的irq
  free_irq(irq, NULL);
  irq=gpio_to_irq(EXYNOS4_GPX3(3)); //获取K2的irq
  free_irq(irq, NULL);
  irq=gpio_to_irq(EXYNOS4_GPX3(4)); //获取K3的irq
  free_irq(irq, NULL);
  irq=gpio_to_irq(EXYNOS4_GPX3(5)); //获取K4的irq
  free_irq(irq, NULL);
}
module_init(handler_module_init);
module_exit(handler_module_cleanup);
MODULE_LICENSE("GPL");

Makefile

CFLAG=-C
TARGET=cdev
#APP=cdev_app
KERNEL=/driver/linux-3.5
obj-m +=$(TARGET).o
all:
	make $(CFLAG) $(KERNEL) M=$(PWD)
#arm-linux-gcc -o $(APP) $(APP).c
clean:
	make $(CFLAG) $(KERNEL) M=$(PWD) clean
#rm $(APP)

本文章仅供学习交流用禁止用作商业用途,文中内容来水枂编辑,如需转载请告知,谢谢合作

微信公众号:zhjj0729

微博:文艺to青年

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值