手把手教你写Linux设备驱动---中断(一)(基于友善之臂4412开发板)

今天,我们要来实现一个基于tiny4412开发板上的最简本的按键中断驱动程序,那么,写这个程序之前,我们先来了解下Linux中断的基本知识。

在Linux内核中,每一个能够发出中断请求的硬件设备控制器都有一条名为IRQ的输出线。所有现在存在的IRQ线都与一个名为可编程中断控制器的硬件电路的输入引脚相连,我们可以来看下4412上与板子上相连的按键。

下面这张电路图,也就是4412板子上按键的电路图和CPU的连接关系图:

我们明显可以看到,4个按键分别接在GPX3这几个引脚上,对应着引脚,接下来我们就可以看数据手册,配置寄存器了

在4412的板级文件配置中,已经提供了IO口的定义,在以下文件中可以找到,这样我们就不用去配置寄存器了,内核已经帮我们配好了:

找到这个文件:

arch/arm/mach-exynos/include/mach/gpio.h

然后找到我们要配置按键的宏:

#define EXYNOS4_GPX3(_nr) (EXYNOS4_GPIO_X3_START + (_nr))

对应的,我们的按键nr就是2,3,4,5 。 因为板子上有4个按键。

那么如何来写一个按键中断程序?Linux内核为我们提供了大量的有关编写中断驱动程序的API函数,我们只需要会使用就行了,不用去看着手册一个个配置,很方便,API列表如下:

#include <linux/interrupt.h>
int request_irq(unsigned int irq, irq_handler_t handler,
		unsigned long irqflags, const char *devname, void *dev_id)
	irq:
		中断号 arch/arm/plat-s3c64xx/include/plat/irqs.h
	handler:
		中断处理函数 irqreturn_t handler(int irq, void *dev_id);
		irqreturn_t:
			See include/linux/irqreturn.h
	irqflags:
		See line 21-59 in include/linux/interrupt.h
		使用IRQF_SHARED共享irq时, irqflags必须相同
		如:  	request_irq(IRQ_EINT(0), handler1,
				IRQF_TRIGGER_FALLING | IRQF_SHARED, "dev1", &dev1);
			request_irq(IRQ_EINT(0), handler2,
				IRQF_TRIGGER_FALLING | IRQF_SHARED, "dev2", &dev2);
	devname:
		设备名, cat /proc/interrupts
	dev_id:
		发生中断时将dev_id传递给handler函数,
	       	irqflags含有IRQF_SHARED时dev_id不能为NULL, 并且要保证唯一
		dev_id一般采用当前设备的结构体指针

void free_irq (	unsigned int irq, void * dev_id);
	释放匹配irq和dev_id的中断, 如果irq有多个相同的dev_id, 将释放第一个
	So, 共享中断的dev_id不是唯一时, 可能会释放到其它设备的中断

void disable_irq(unsigned int irq);
	关闭irq号中断	

void enable_irq(unsigned int irq);
	开启irq号中断
void local_irq_save(unsigned long flags);
	关闭当前CPU中断并保存当前状态到flags
void local_irq_restore(unsigned long flags);
	恢复flags到当前CPU
void local_irq_disable(void);
	关闭当前CPU中断
void local_irq_enable(void);
	开启当前CPU中断
注: 没有关闭和开启所有CPU中断的函数(没必要)

而申请中断号,需要使用这个函数来实现:

static inline int gpio_to_irq(unsigned int gpio)

只要往里面传一个参数,这个参数就是我们上面说的板级文件里的那个宏,它就用自动帮你申请中断号。

接下来,我们就来实现这个简单的按键驱动程序:
步骤:

1、申请中断号

2、注册中断服务

代码:

/*
 * linux/drivers/char/tiny4412_pwm.c
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/err.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/timer.h>  /*timer*/
#include <asm/uaccess.h>  /*jiffies*/
#include <linux/delay.h>

#include <linux/interrupt.h>

//中断服务函数
static irqreturn_t irq_fuction(int irq, void *dev_id)
{
	printk("key_irq:%d\n",irq);
	return IRQ_HANDLED ;
}

static int __init tiny4412_Key_irq_test_init(void)
{
	int err = 0 ;
	int irq_num1 ;
	int irq_num2 ;
	int irq_num3 ;
	int irq_num4 ;
	printk("irq_key init\n");
	//为4个按键都申请中断号
	irq_num1 = gpio_to_irq(EXYNOS4_GPX3(2));
	irq_num2 = gpio_to_irq(EXYNOS4_GPX3(3));
	irq_num3 = gpio_to_irq(EXYNOS4_GPX3(4));
	irq_num4 = gpio_to_irq(EXYNOS4_GPX3(5));
	//请求中断
	request_irq(irq_num1,irq_fuction,IRQF_TRIGGER_FALLING,"tiny4412_key1",(void *)"key1");
	request_irq(irq_num2,irq_fuction,IRQF_TRIGGER_FALLING,"tiny4412_key2",(void *)"key2");
	request_irq(irq_num3,irq_fuction,IRQF_TRIGGER_FALLING,"tiny4412_key3",(void *)"key3");
	request_irq(irq_num4,irq_fuction,IRQF_TRIGGER_FALLING,"tiny4412_key4",(void *)"key4");
	return 0 ;
}

static void __exit tiny4412_Key_irq_test_exit(void)
{
	//释放中断irq
	int irq_num1 ;
	int irq_num2 ;
	int irq_num3 ;
	int irq_num4 ;
	printk("irq_key init\n");
	irq_num1 = gpio_to_irq(EXYNOS4_GPX3(2));
	irq_num2 = gpio_to_irq(EXYNOS4_GPX3(3));
	irq_num3 = gpio_to_irq(EXYNOS4_GPX3(4));
	irq_num4 = gpio_to_irq(EXYNOS4_GPX3(5));
	free_irq(irq_num1,(void *)"key1");
	free_irq(irq_num2,(void *)"key2");
	free_irq(irq_num3,(void *)"key3");
	free_irq(irq_num4,(void *)"key4");
}

module_init(tiny4412_Key_irq_test_init);
module_exit(tiny4412_Key_irq_test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("YYX");
MODULE_DESCRIPTION("Exynos4 KEY Driver");

编译好下zImage到开发板上,按下对应的按键可以看到Log信息:

还要注意一点,内核里,要将原先友善之臂实现的对应的按键驱动程序给屏蔽掉。

如果是配置android的内核,就需要将板级文件配置中的下面这个初始化给干掉,这个按键驱动才能够注册成功,才能够看到以上效果:

板级驱动文件位于:

arch/arm/mach/exynos/mach-tiny4412.c

找到这个结构体:

static struct platform_device *smdk4x12_devices[] __initdata = {

。。。。。

#ifdef CONFIG_SAMSUNG_DEV_KEYPAD
&samsung_device_keypad,
#endif
&tiny4412_device_1wire,
&tiny4412_device_adc,
#ifdef CONFIG_INPUT_GPIO
&tiny4412_input_device,
#endif

};

将以上的&tiny4412_input_device,注释,再重新编译即可。

时间: 2024-11-02 12:06:45

手把手教你写Linux设备驱动---中断(一)(基于友善之臂4412开发板)的相关文章

手把手教你写Linux设备驱动---定时器(一)(基于友善之臂4412开发板)

这个专题我们来说下Linux中的定时器. 在Linux内核中,有这样的一个定时器,叫做内核定时器,内核定时器用于控制某个函数,也就是定时器将要处理的函数在未来的某个特定的时间内执行.内核定时器注册的处理函数只执行一次,即不是循环执行的. 如果对延迟的精度要求不高的话,最简单的实现方法如下---忙等待: Unsigned long j = jiffies + jit_delay * HZ; While(jiffies < j) { -- } 下面来说下具体的参数代表的含义: jiffies:全局变

手把手教你写Linux设备驱动---中断(二)--tasklet实现(基于友善之臂4412开发板)

上节:http://blog.csdn.net/morixinguan/article/details/68958185 在上一节博文中,教会了大家如何来写一个Linux设备的中断程序,实现也非常简单,我们来回顾一下具体的操作流程,只要遵循以下几个步骤即可实现最简单的中断处理程序: 使用中断相关的API和定义时要包含以下头文件: #include <linux/interrupt.h> 然后写中断需要以下步骤 1.申请中断号 使用gpio_to_irq函数,可以从返回值获取到对应的中断号 2.

手把手教你写Linux设备驱动---input子系统(二)--按键驱动实现(一)(基于友善之臂4412开发板)

在上一节里,我们用一个应用程序实现了鼠标的控制,并控制鼠标用相对位移不断的画一个正方形,感觉非常有意思,这一节,我们将通过一个简单按键实例来真正的实现一个input设备驱动程序. http://blog.csdn.net/morixinguan/article/details/69808832 在写Input驱动之前,我们要了解下这个结构体,在此,我们要包含相应的头文件: #include <linux/input.h> 我们在这个头文件中找到了以下结构体,它就是input设备的核心: //用

手把手教你写Linux设备驱动---中断(三)--workqueue实现(基于友善之臂4412开发板)

上节,我们讲到如何来实现tasklet小任务机制 http://blog.csdn.net/morixinguan/article/details/69666935 这节,我们来实现一下中断下半部的工作队列: 在写这个demo之前,我们要了解一下工作队列的相关数据结构还有API. 需要包含的头文件: #include <linux/workqueue.h> 基本的数据结构: //工作队列结构 struct work_struct { atomic_long_t data; //链表处理 str

手把手教你写Linux设备驱动---input子系统(三)--电容屏事件坐标读取(基于友善之臂4412开发板)

前面我们学习了鼠标是如何如何通过应用程序来读取事件和坐标值的,后面也写了一个简单的input系统的按键驱动程序. 博文如下,讲的内容非常清楚,给小白来入手当然是非常容易的: http://blog.csdn.net/morixinguan/article/details/69808832 这节,我们来学习一下触摸屏事件获取,然后上一个基于4412开发板ft5x0x型号的x,y坐标值读取,后面我们将从零开始实现这款触摸屏的驱动程序: 首先,我们要明白一个概念,触摸屏在input系统中是一类什么事件

手把手教你写Linux设备驱动---input子系统(四)--电容屏驱动ft5x06编写(一)(基于友善之臂4412开发板)

这一节,我们将从零开始写tiny4412的触摸屏驱动ft5x06,写这节博客之前,先了解下需要什么知识: 1.i2c驱动相关的知识 2.输入子系统 3.中断 4.工作队列 关于i2c驱动相关的知识,在后期的博文里会专门写几篇博文来进行总结,这里就不再说i2c相关的知识,我们先知道怎么用就行了. 首先,我在ts.h构造了一个ts_info_st结构体,用来存放触摸屏的中断线,x坐标,y坐标,压力值. 用ts_st构造了该触摸屏的设备结构体. 我们还是直接看点实际的东西,上代码: ts.h #ifn

手把手教你从零实现Linux misc设备驱动二(基于友善之臂4412开发板)

上一节,我教大家实现了一个最简单的MISC设备驱动,那么这节,我们将用一个实例来驱动蜂鸣器,这里为了方便,我就不再写应用程序进行测试,直接在驱动里调用open函数,这个程序是在Android系统里跑起来,后面我会教大家如何在Android下写应用测试程序. 我们参考以前写的蜂鸣器驱动程序,将它移植到我们这个程序里,让它成为一个MISC设备. 参考以前写的文章: http://blog.csdn.net/morixinguan/article/details/50628588 接下来,看看代码:

手把手教你从零实现Linux misc设备驱动一(基于友善之臂4412开发板)

关于如何来写一个misc设备,在前面有篇文章已经介绍了大致的流程,现在就让我们来实现一个最简单的misc设备驱动. http://blog.csdn.net/morixinguan/article/details/52700146 关于前面的字符设备有以下四篇文章,可以做参考: http://blog.csdn.net/morixinguan/article/details/55002774 http://blog.csdn.net/morixinguan/article/details/550

手把手教你写Linux设备驱动---input子系统(一)--input事件应用程序的读写实现(基于友善之臂4412开发板)

     这节,我们来说下input子系统,什么是input子系统? input子系统就是输入子系统.      输入子系统是 Linux内核用于管理各种输入设备 (键盘,鼠标,遥控杆,书写板等等 )的部分,用户通过输入子系统进行内核,命令行,图形接口之间的交换.输入子系统在内核里实现,因为设备经常要通过特定的硬件接口被访问 (例如串口, ps/2, usb等等 ),这些硬件接口由内核保护和管理.内核给用户导出一套固定的硬件无关的 input API,供用户空间程序使用. 输入子系统分为三块: