Linux下的一个使用中断的按键驱动程序v

合集下载

基于嵌入式Linux的中断驱动程序设计

基于嵌入式Linux的中断驱动程序设计

图像・编码与软件电子科技2009年第22卷第10期收稿日期:2009201215作者简介:常赟杰(1980-),男,硕士研究生,助教。

研究方向:嵌入式系统。

刘连浩(1959-),男,博士,教授。

研究方向:信息安全与嵌入式系统。

基于嵌入式L inux 的中断驱动程序设计常赟杰1,2,刘连浩1(11中南大学信息科学与工程学院,湖南长沙 410083;21湖南工学院计算机科学系,湖南衡阳 421002)摘 要 首先阐述了嵌入式L inux 操作系统下,设备驱动程序的实现原理和编写方法,然后说明了中断处理在设备驱动程序中的应用,并详细论述了中断方式下,编写设备驱动程序的具体开发流程,进一步分析了编写中断处理程序时所用到一些数据结构。

应用证明,在编写L inux 设备驱动程序的时候,采用中断方式的程序效率会更高。

关键词 AR M;L inux;设备驱动;中断中图分类号 TP316 文献标识码 A 文章编号 1007-7820(2009)10-074-03D esi gn of I n terrupt D ev i ce D r i vers Ba sed onE m bedded L i n uxChang Yunjie1,2,L iu L ianhao2(11School of Infor mati on Science and Engineer,Central South University,Changsha 410083,China;21Depart m ent of Computer Science,Hunan I nstitute of Technol ogy,Hengyang 421002,China )Abstract First,the p rincip le of i m p lementation and p r ogramm ing method of device drivers on embedded L inux operati on system is intr oduced .Then,the app lication of interrup t handling in device drivers is p resen 2ted,with a detailed discussi on of the devel opment p r ocesses of device drivers under interrup t .Finally,s omei m portant data structures used in interrup t handling p r ogramm ing are further analyzed .Practical app lication in 2dicates that higher p r ogram efficiency is achieved with the use of interrup t in the L inux device driver p rogram 2m ing .Keywords ARM;L inux;devices drivers;interrup t 随着电子技术的飞速发展,嵌入式L inux 有着广泛的适用硬件平台,高效稳定的内核代码、丰富的应用软件、良好的网络接口等特点,已经成为嵌入式系统领域中的研究热点。

键盘中断驱动实验

键盘中断驱动实验

(6)实现键盘驱动非阻塞访问操作函数
static int Emdoor_kbd_fasync(int fd, struct file * file, int mode) { return fasync_helper(fd, file, mode, &(fasync) ); }
(7)键盘驱动文件结构体定义
(4)实现键盘驱动设备打开操作函数
static int Emdoor_kbd_open(struct inode *inode, struct file *filp) { int ret; printk(KERN_EMERG " Emdoor_kbd_open!\n"); KBD_DEV * kbd; kbd =(KBD_DEV *) kmalloc(sizeof(KBD_DEV ), GFP_KERNEL); KPC=KPC_ASACT | (3<<26) | (7<<23 ) | KPC_IMKP | KPC_MS6 | KPC_MS5 |KPC_MS4 | KPC_MS3 | KPC_MS2 | KPC_MS1 | KPC_MS0 | KPC_ME |KPC_MIE | (7<<6) | KPC_DE | KPC_DIE; init_waitqueue_head(&(kbd->wq)); pxa_gpio_mode(94 | GPIO_ALT_FN_1_IN);//KP_DKIN<1> pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN);//KP_DKIN<2> pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT);//KP_MKOUT<0> pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT);//KP_MKOUT<1> pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT);//KP_MKOUT<2> pxa_gpio_mode(108 | GPIO_ALT_FN_2_OUT);//KP_MKOUT<5> kbd->kbd_status=KEYVALUE_NO; filp->private_data=kbd;

Linux中断-简单中断,以GPIO中断为例

Linux中断-简单中断,以GPIO中断为例

Linux中断-简单中断,以GPIO中断为例Linux中断基础概念中断上下⽂Linux内核的中断回调可以有两部分,即上下⽂。

当中断⽐较简单时,可以只有上⽂。

⼀般中断上⽂是指由中断产⽣的回调函数直接执⾏的部分;中断下⽂在上⽂中启⽤调度,再由内核调度。

中断上⽂:处理尽可能少的任务,特点是响应速度快中断下⽂:处理耗时任务,可以被新的中断打断中断嵌套Linux中断现在不能嵌套,之前可以中断相关的函数及命令获取中断号如果是有设备树的内核,⼀般通过节点的interrupt-parent和interrupt属性来描述中断对GPIO来说,GPIO的节点可以作为中断控制器,⼀般由BSP⼚家编写<linux/of_irq.h>//从设备树的设备节点中获取中断号unsigned int irq_of_parse_and_map(struct device_node *dev, int index);//参数:dev设备节点,index索引(节点中interrupts属性可能包含多条中断信息,通过index确认)//返回值:中断号//如果是GPIO的话,可以不从设备树中获取int gpio_to_irq(unsigned int gpio);//参数:gpio的编号//返回值:gpio对应的中断号申请中断申请中断的函数int request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags,const char *name,void *dev);//参数://irq:要申请中断的中断号//handler:中断处理函数//flags:中断标志//name:中断名字,可在/proc/interrupts⽂件中看到对应的名字//dev:flags为IRQF_SHARED时,dev⽤来区分不同的中断。

⼀般将dev设置为设备结构体,传递给irq_handler_t的第⼆个参数//返回值:0申请成功,其他负值申请失败;如果返回-EBUSY标识已经被申请中断标志(申请中断函数的flags参数)定义在 include/linux/interrupt.h中常见的中断标志:标志功能IRQF_SHARED多个设备共享⼀个中断线,申请中断函数的dev参数是区分它们的唯⼀标志IRQF_ONESHOT单次中断,中断执⾏⼀次就结束IRQF_TRIGGER_NONE⽆触发IRQF_TRIGGER_RISING上升沿触发IRQF_TRIGGER_FALLING下降沿触发IRQF_TRIGGER_HIGH⾼电平触发IRQF_TRIGGER_LOW低电平触发中断处理函数使⽤request_irq申请中断的时候需要中断处理函数irq_handler_t来做参数,这⾥的irq_handler_t函数可以理解为中断上⽂的回调函数,发⽣中断时内核会调⽤处理函数。

linux gpio中断应用实例

linux gpio中断应用实例

linux gpio中断应用实例Linux GPIO(General Purpose Input/Output,通用输入输出)中断是一种用于处理外部设备事件的方式。

当外部设备产生一个事件时,它会向CPU发送一个信号,这个信号被称为中断。

CPU在接收到中断信号后,会暂停当前的任务,转而去处理这个中断事件。

处理完中断事件后,CPU会返回到被暂停的任务继续执行。

这种机制使得CPU 可以高效地处理多个任务,而不会被某个任务阻塞。

在Linux系统中,GPIO中断主要应用于以下场景:1. 按键事件处理:当用户按下或松开一个按键时,会产生一个中断事件。

通过配置GPIO中断,可以实现对按键事件的实时响应。

2. 传感器数据采集:许多传感器设备(如温度传感器、湿度传感器等)会周期性地产生数据。

通过配置GPIO中断,可以实现对这些数据的实时采集和处理。

3. 马达控制:通过配置GPIO中断,可以实现对马达的启动、停止和速度控制。

下面是一个使用Linux GPIO中断的简单实例:实现一个LED灯的闪烁控制。

首先,我们需要配置GPIO中断。

在这个例子中,我们将使用GPIO 4作为中断引脚,连接到一个按钮开关。

当按下按钮时,LED灯会闪烁。

1. 配置GPIO 4为输入模式:bashecho "4" > /sys/class/gpio/exportecho "in" > /sys/class/gpio/gpio4/direction2. 配置GPIO中断:bashecho "4" > /sys/class/gpio/gpio4/irqecho "1000" > /sys/class/gpio/gpio4/edgeecho "1" > /sys/class/gpio/gpio4/debounce这里,我们设置了GPIO 4的中断触发方式为上升沿触发(edge),并设置了去抖动时间(debounce)。

linux驱动之中断

linux驱动之中断

Linux设备驱动程序学-中断处理可以让设备在产生某个事件时通知处理器的方法就是中断。

一个“中断”仅是一个信号,当硬件需要获得处理器对它的关注时,就可以发送这个信号。

Linux 处理中断的方式非常类似在用户空间处理信号的方式。

大多数情况下,一个驱动只需要为它的设备的中断注册一个处理例程,并当中断到来时进行正确的处理。

本质上来讲,中断处理例程和其他的代码并行运行。

因此,它们不可避免地引起并发问题,并竞争数据结构和硬件。

透彻地理解并发控制技术对中断来讲非常重要。

安装中断处理例程内核维护了一个中断信号线的注册表,类似于I/O 端口的注册表。

模块在使用中断前要先请求一个中断通道(或者IRQ中断请求),并在使用后释放它。

所用的函数声明在<linux/interrupt.h> (在此文件中并未真正包含,是通过它include的文件间接包含的,函数在/kernel/irq/Manage.h中),中断注册和释放的函数接口如下:表示另一个驱动已经占用了你所请求的中断线。

函数的参数如下:unsigned int irq:请求的中断号irqreturn_t (*handler):安装的处理函数指针。

unsigned long flags:一个与中断管理相关的位掩码选项。

const char *dev_name:传递给request_irq 的字符串,用来在/proc/interrupts 来显示中断的拥有者。

void *dev_id:用于共享中断信号线的指针。

它是唯一的标识,在中断线空闲时可以使用它,驱动程序也可以用它来指向自己的私有数据区(来标识哪个设备产生中断)。

若中断没有被共享,dev_id 可以设置为NULL,但推荐用它指向设备的数据结构。

flags 中可以设置的位如下:SA_INTERRUPT:快速中断标志。

快速中断处理例程运行在当前处理器禁止中断的状态下。

SA_SHIRQ : 在设备间共享中断标志。

iTOP-4412实现中断驱动例程

iTOP-4412实现中断驱动例程
return platform_driver_register(&irq_driver); } 该函数想内核注册一个 irq_driver 类型的设备,irq_driver 定义如下: static struct platform_driver irq_driver = {
static void __exit irq_test_exit(void) {
platform_driver_unregister(&irq_driver); }
static int __init irq_test_init(void) {
return platform_driver_register(&irq_driver); }
module_init(irq_test_init); module_exit(irq_test_exit);
iTOP-4412 开发板
驱动例程
9 日期:2015-4-27

北京迅为电子有限公司
iTOP-4412 开发板
MODULE_LICENSE("Dual BSD/GPL"); 首先我们来看下这个驱动的入口函数 irq_test_init,定义如下: static int __init irq_test_init(void) {
#include <linux/kernel.h> #include <linux/fs.h>
#include <linux/interrupt.h> #include <linux/irq.h>
#include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/miscdevice.h> #include <linux/platform_device.h> #include <mach/regs-gpio.h> #include <asm/io.h>

uClinux下中断驱动的I/O方式

uClinux下中断驱动的I/O方式

uClinux下中断驱动的I/O方式在32位微处理器逐渐成为系统主流的同时,嵌入式应用也变得越来越复杂。

许多嵌入式系统都不得不借助于专用的操作系统来支撑自己的应用。

作为类Unix操作系统,继承了的各种优秀的品质,成为首选的嵌入式系统的操作系统。

为自己的设备在操作系统下添加驱动程序,是嵌入式设计必不行少的部分。

针对不同的设备类型,挑选合适的驱动程序的模式,同样也是非常重要的。

通常的设备驱动采纳挺直I/O的方式,如存储器、等;而对于象网络这样的数据流设备的驱动,则应当用到中断机制。

本文以uClinux为背景,以一种数据流设备为目标,介绍中断驱动的I /O设备驱动的开发。

1 应用背景1.1 硬件描述本文介绍的驱动程序是应用在一种电信E1线路和以太网互联设备上的。

它是旁路接收E1数据并将其发送到以太网的某一台服务器上,在服务器上对E1的话路和信令时隙分析。

该设备中的处理器是采纳三星公司出品的网络型处理器S3C4510B。

E1线路接口采纳Dallas公司的专用El接口单元(LIU)芯片DS2148,它完成波形收拾、时钟复原和HDB3解码。

DS2148将收拾后的E1数据流送给一片公司的Cyclone系列的(EPlC3T144C8),它将串行的E1数据流存入到FIFO,再通过ARM的32位外部将数据传送给ARM。

ARM将数据打包通过以太网发送到服务器上。

图l所示是本系统的硬件框图。

本文主要介绍接在ARM的外部总线上的FPGA,在uClinux下的驱动程序中断机制的设计。

1.2硬件衔接S3C4510B处理器和FPGA的衔接2所示。

第1页共10页。

linux driver中断处理实例-概述说明以及解释

linux driver中断处理实例-概述说明以及解释

linux driver中断处理实例-概述说明以及解释1.引言概述部分的内容可以如下所示:1.1 概述Linux驱动程序是操作系统内核的核心组成部分之一。

它负责与硬件设备进行交互,并提供给用户空间的应用程序访问硬件的接口。

中断处理是Linux驱动程序中非常重要的组成部分,它允许硬件设备在需要注意的情况下主动向CPU发送信号。

这些信号需要被驱动程序捕获并处理,以执行相应的操作。

中断处理的高效与否直接影响着系统的整体性能和响应能力。

本文将围绕Linux驱动程序中的中断处理展开讨论。

我们将首先介绍Linux驱动程序的基本概念,包括其作用、类型和加载方式等。

然后我们将详细探讨中断处理的基本概念,包括中断的定义、传统中断与异常中断的区别等。

接下来,我们将深入分析在Linux驱动程序中实现中断处理的关键技术和策略,包括中断处理程序的注册、上下文切换、共享中断、中断处理的顺序、中断处理线程和底半部等。

通过对Linux驱动程序中断处理实例的分析,我们将展示如何正确地设计和实现中断处理程序,以提高系统的可靠性、稳定性和性能。

同时,我们也将深入思考中断处理的重要性,并展望未来中断处理的发展方向。

在本系列文章中,我们希望为读者提供全面的Linux驱动程序中断处理知识,并为相关领域的开发者和研究者提供有价值的参考和指导。

1.2 文章结构文章结构部分的内容可以包括以下内容:文章结构部分旨在介绍本文的整体结构,让读者对文章的脉络有一个大致的了解。

本文主要围绕着Linux驱动程序中的中断处理展开,共分为引言、正文和结论三个部分。

引言部分首先对本文的背景和主题进行一个概述,介绍了本文主要讨论的内容是Linux驱动程序中的中断处理实例。

接着介绍了文章的结构,包括引言、正文和结论三个部分。

通过明确的结构,读者可以清楚地了解到本文的整体框架。

正文部分是本文的主体部分,也是最核心的部分。

在正文中,我们将逐步展开对Linux驱动程序中的中断处理的讲解。

linux驱动之中断处理过程C程序部分

linux驱动之中断处理过程C程序部分

linux驱动之中断处理过程C程序部分当发生中断之后,linux系统在汇编阶段经过一系列跳转,最终跳转到asm_do_IRQ()函数,开始C程序阶段的处理。

在汇编阶段,程序已经计算出发生中断的中断号irq,这个关键参数最终传递给asm_do_IRQ()。

linux驱动中断处理C程序部分,主要涉及linux中断系统数据结构的初始化和C程序的具体执行跳转。

一、中断处理数据结构linux内核将所有的中断统一编号,使用一个irq_desc[NR_IRQS]的结构体数组来描述这些中断:每个数组项对应着一个中断源(可能是一个中断,也可能是一组中断),记录了中断的入口处理函数(不是用户注册的处理函数)、中断标记,并提供了中断的底层硬件访问函数(中断清除、屏蔽、使能)。

另外,通过这个结构体数组项成员action,能够找到用户注册的中断处理函数。

结构体irq_desc的数据类型在include/linux/irq.h中定义,内容如下:struct irq_desc { irq_flow_handler_t handle_irq; /* 当前中断的处理函数入口*/ struct irq_chip *chip; /* 低层的硬件访问*/ struct msi_desc *msi_desc; void *handler_data; void *chip_data; struct irqacTIon *acTIon; /* 用户提供的中断处理函数链表*/ unsigned int status; /* IRQ状态*/ unsigned int depth; /* nested irq disables */ unsigned int wake_depth; /* nested wake enables */ unsigned int irq_count; /* For detecTIng broken IRQs */ unsigned int irqs_unhandled; spinlock_t lock; const char *name; /* 中断名称*/} ____cacheline_internodealigned_in_smp;irq_desc成员变量handle_irq是这个或这组中断的入口处理函数,成员变量chip结构体包含了这个中断的清除、屏蔽或者使能等底层函数,结构体类型irq_chip的定义也在include/linux/irq.h中,内容如下:struct irq_chip { const char *name; unsigned int (*startup)(unsigned int irq); void。

linux gpio key中断触发方式

linux gpio key中断触发方式

linux gpio key中断触发方式题目:Linux GPIO Key中断触发方式解析与应用引言:在嵌入式系统和物联网应用中,我们经常需要与外部设备进行交互。

GPIO (General Purpose Input Output)被广泛使用以实现对外设的控制和监测。

其中,利用中断触发方式读取GPIO输入状态,可以大大降低资源占用和响应时间。

本文将详细介绍Linux中GPIO Key的中断触发方式,以及如何在应用中应用和配置。

一、GPIO Key的基本概念GPIO Key是指将GPIO引脚配置为按键输入,并通过中断方式来检测按键的状态变化。

与轮询方式相比,中断触发可以实现即时响应和降低系统资源占用。

在Linux系统中,GPIO Key由内核的input子系统和keyboard 子系统来处理。

二、中断触发模式在Linux中,GPIO Key的中断触发模式主要有下列几种:1. 无触发:GPIO按键输入不产生中断,只能通过轮询方式读取输入状态。

2. 下降沿触发:只有在GPIO由高电平变为低电平时才会产生中断。

3. 上升沿触发:只有在GPIO由低电平变为高电平时才会产生中断。

4. 边沿触发:GPIO在电平转变时都会产生中断,包括上升沿和下降沿。

5. 按键触发:GPIO按键按下和释放各自产生中断。

三、配置GPIO Key中断触发方式1. 准备工作:(1) 确认GPIO管脚号和对应的GPIO控制器。

(2) 确认使用的GPIO按键的中断触发方式。

(3) 确认所使用的开发板或单板计算机上是否已经加载了GPIO对应的驱动。

2. 创建GPIO Key设备:(1) 打开设备树文件,找到GPIO节点(一般位于/arch/arm/boot/dts/目录下)。

(2) 在GPIO节点中添加GPIO Key设备信息,包括GPIO管脚号、中断触发方式等。

(3) 编译设备树文件,生成设备树二进制文件(.dtb文件)。

(4) 将生成的设备树二进制文件拷贝到/boot目录下,并在引导过程中加载。

Linux下的中断(interrupt)简介

Linux下的中断(interrupt)简介

Linux下的中断(interrupt)简介中断其实就是由硬件或软件所发送的一种称为IRQ(中断请求)的信号。

中断允许让设备,如键盘,串口卡,并口等设备表明它们需要CPU。

一旦CPU接收了中断请求,CPU就会暂时停止执行正在运行的程序,并且调用一个称为中断处理器或中断服务程序(interrupt service routine)的特定程序。

中断服务程序或中断处理器可以在中断向量表中找到,而这个中断向量表位于内存中的固定地址中。

中断被CPU处理后,就会恢复执行之前被中断的程序。

其实,在机器启动的时候,系统就已经识别了所有设备,并且也把相应的中断处理器加载到中断表中。

下面是请求CPU关注的两种方式:1. 基于中断2. 基于轮询所有的linux操作系统都是基于中断驱动的。

当我们在键盘上按下一个按键时,键盘就会对CPU说,一个键已经被按下。

在这种情况下,键盘的IRQ线路中的电压就会发生一次变化,而这种电压的变化就是来自设备的请求,就相当于说这个设备有一个请求需要处理。

/proc/interrupts 文件在linux的机器上,/proc/interrupts这个文件包含有关于哪些中断正在使用和每个处理器各被中断了多少次的信息。

# cat /proc/interruptsCPU0 CPU1 CPU2 CPU30: 3710374484 0 0 0 IO-APIC-edge timer1: 20 0 0 0 IO-APIC-edge i80426: 5 0 0 0 IO-APIC-edge floppy7: 0 0 0 0 IO-APIC-edge parport08: 0 0 0 0 IO-APIC-edge rtc9: 0 0 0 0 IO-APIC-level acpi12: 240 0 0 0 IO-APIC-edge i804214: 11200026 0 0 0 IO-APIC-edge ide051: 61281329 0 0 0 IO-APIC-level ioc059: 1 0 0 0 IO-APIC-level vmci67: 19386473 0 0 0 IO-APIC-level eth075: 94595340 0 0 0 IO-APIC-level eth1NMI: 0 0 0 0LOC: 3737150067 3737142382 3737145101 3737144204ERR: 0MIS: 0对上面文件的输出,解释如下:● 第一列表示IRQ号● 第二、三、四列表示相应的CPU核心被中断的次数。

Linux中断处理驱动程序编写

Linux中断处理驱动程序编写

Linux中断处理驱动程序编写中断处理是操作系统必须具备的上要功能之一,下面我们一起来探讨一下Linux中的中断处理。

1.什么是中断中断就是CPU正常运行期间,由于内、外部事件引起的CPU暂时停止正在运行的程序,去执行该内部事件或外部事件的引起的服务中去,服务执行完毕后再返回断点处继续执行的情形。

这样的中断机制极大的提高了CPU运行效率。

1.1.中断的分类:1)根据中断的来源可分为内部中断和外部中断,内部中断的中断源来自于CPU内部(软件中断指令、溢出、除法错误等),例如操作系统从用户态切换到内核态需要借助CPU 内部的软件中断,外部中断的中断源来自于CPU外部,由外设触发。

2)根据中断是否可以被屏蔽,中断可分为可屏蔽中断和不可屏蔽中断,可屏蔽中断可以通过设置中断控制器寄存器等方法被屏蔽,屏蔽后,该中断不再得到响应,而不可屏蔽中断不能被屏蔽。

3)根据中断入口跳转方式的不同,中断可分为向量中断和非向量中断。

采用向量中断的CPU通常为不同的中断分配不同的中断号,当检测到中断的中断号到来时,就自动跳转到该中断对应的地址处去执行程序。

不同的中断号对应不同的中断入口地址。

非向量中断的多个中断共享一个入口程序处理入口地址,中断程序跳转到该入口地址执行时,再通过中断程序来判断中断标志来识别具体是哪一个中断,也就是说向量中断由硬件提供中断服务程序入口地址,非向量中断由软件提供中断服务程序入口地址。

4)非向量中断处理流程:/*典型的非向量中断首先会判断中断源,然后调用不同中断源的中断处理程序*/irq_handler(){...int int_src = read_int_status();/*读硬件的中断相关寄存器*/switch(int_src){//判断中断标志case DEV_A:dev_a_handler();break;case DEV_B:dev_b_handler();break;...default:break;}...}2.linux中断顶部、底部概念为保证系统实时性,中断服务程序必须足够简短,但实际应用中某些时候发生中断时必须处理大量的工作,这时候如果都在中断服务程序中完成,则会严重降低中断的实时性,基于这个原因,linux系统提出了一个概念:把中断服务程序分为两部分:顶半部、底半部。

Linux0.01键盘中断的C语言实现

Linux0.01键盘中断的C语言实现
ln u c o gfn

2 键 盘中断设 计与实现
由于 c语言程序无法直接实现诸 如 ps 、o 、 uh pp
it r 等汇 编语 言指令 , 以键 盘 中断 的主 框架仍 用 汇 e 所
编语 言 实现 , 将其 键 盘处理 功 能用 C语 言 编程实 现 .
2 1 A CI . S I 码映射 表
Vo . 2 № 8 13
Au . 2 1 g 01
Ln x0 O iu . 1键 盘 中 断的 C语 言 实现
于 江 涛 曲 波 ,
(. 1 通化 师范学 院 计算机科学系 , 吉林 通化 14 0 ;. 3 0 2 2 南京 晓庄学院 数学与信息技术 学院, 江苏 南京 2 17 ) 11 1
以适 当改 造 , 在 当前 Ln x平 台编 译 运行 , 常 可于按 键 的 扫 描码 , 标 变 量 下
对应 于 A CI . S I码 例如 按下 “ S ” , E C 键 该键 的扫描 码
为 “ ” 其对应 的 A CI 1, S I码为 “7 . 2” 由于 Lns iu 是芬 兰人 , 以 当初 Ln x .1的键 所 iu O 0 盘 映射是按 芬 兰键 盘 设计 的. 笔者 在 本程 序 中使 用 通用 的美 国键盘 映射 . Si 组 合键 及 At 合 键 的 映 射 表 与 此类 似 , hf t l组

要 : 阐述了用 c语 言改写 L u . 1 文章 i x 0 键盘模块的技术要 点 , n 0 包括 A CI S I码映射表 、 盘处理子程 序跳转表 、 盘处理 键 键
程序、 键盘 中断程序 的编程 方法及 关键代码. 关键词 :iu . 1键 盘 中断 ; Ln x 0 ; 0 C语言编程 中图分类号 :P 1 文献标志码 : 文章编号 :0 8— 9 4 2 1 )8— 0 4—0 T 36 A 10 7 7 (0 10 0 1 3

(整理)键盘中断

(整理)键盘中断

一个嵌入式Linux系统的键盘驱动实现2006-10-09 10:04来源:天极博客作者:赵彪责任编辑:原野·yesky评论(0)更多Linux文章请看:Linux操作系统应用专区1、引言Linux由于其具有内核强大且稳定,易于扩展和裁减,丰富的硬件支持等诸多优点,在嵌入式系统中得到了广泛的应用。

很多嵌入式Linux系统,特别是一些具有与用户强交互的嵌入式系统,往往需要配备一个特殊键盘,此时开发者需要根据实际情况,为自己的特殊键盘编写驱动程序。

2、Linux键盘驱动简介Linux中的大多数驱动程序都采用了层次型的体系结构,键盘驱动程序也不例外。

在Linux中,键盘驱动被划分成两层来实现。

其中,上层是一个通用的键盘抽象层,完成键盘驱动中不依赖于底层具体硬件的一些功能,并且负责为底层提供服务;下层则是硬件处理层,与具体硬件密切相关,主要负责对硬件进行直接操作。

键盘驱动程序的上层公共部分都在driver/keyboard.c中。

该文件中最重要的就是内核用EXPORT_SYMBOL这个宏导出的handle_scancode函数。

handle_scancode完成的功能是:首先将扫描码转换成键码,接着根据shift, alt等扩展键的按下情况将键码转换成目标码,一般情况下是ASCII码,最后将该ASCII码放到终端设备的缓冲区中,并且调度一个tasklet负责将其在显示器上回显出来。

可以看出,这个函数完成的是键盘驱动程序中最核心的一些工作,而这些核心的逻辑功能是不依赖于底层硬件的,所以可以将其独立出来,并且导出给底层的硬件处理函数调用。

在这个文件中还定义了其它几个回调函数,它们由键盘驱动程序中的上层公共部分调用,并由底层硬件处理函数实现。

比如kbd_init_hw,kbd_translate, kbd_unexpected_up等等。

其中kbd_translate由handle_scancode调用,负责将扫描码转换成键码;键盘驱动程序的底层硬件处理部分则根据不同的硬件有不同的实现。

sc按键驱动完整版

sc按键驱动完整版

/ 2410 中断按键驱动基于s3c2410的16个按键驱动;采用中断的方式;实现了阻塞和非阻塞;并用定时器进行了消抖处理消抖;也实现的异步通知;POLL机制;每个源文件我都加了比较详细的注释..各位刚刚学习ARM/Linux 驱动的同学可以参考../// button_irq_driver .c 驱动源文件// button_irq_test.c 应用程序---按键测试open可实现阻塞和非阻塞// button_poll_test.c 应用程序---poll机制按键测试// button_fasync.c 应用程序---异步通知方式按键测试/ button_irq_driver .c /include<linux/module.h>include<linux/init.h>include<linux/fs.h>include<linux/device.h>include<linux/cdev.h>include<asm/uaccess.h>include<linux/io.h>include<linux/interrupt.h>include<asm/arch/regs-gpio.h>include<linux/poll.h>static unsigned int buttons_major = 0;//本地结构体;表示一个按键struct fsbuttons_cdev{struct cdev buttons_cdev; //按键设备结构体struct class buttons_class;//所属类unsigned int key_buttons; //按键管脚电1 /0wait_queue_head_t buttons_wq;struct timer_list button_timer;};static struct fsbuttons_cdev fs_buttons ;//构建一个结构体;用来描述中断管脚struct fspin{int irq;int pin;char name;int num;int row_input;int row_output;int int_put;int key_val;};static struct fspin fspin_desc4={{IRQ_EINT0; S3C2410_GPF0; "row0"; 0;S3C2410_GPF0_INP; S3C2410_GPF0_OUTP;S3C2410_GPF0_EINT0};{IRQ_EINT2; S3C2410_GPF2; "row1"; 1;S3C2410_GPF2_INP; S3C2410_GPF2_OUTP;S3C2410_GPF2_EINT2};{IRQ_EINT11; S3C2410_GPG3; "row2"; 2;S3C2410_GPG3_INP; S3C2410_GPG3_OUTP;S3C2410_GPG3_EINT11};{IRQ_EINT19; S3C2410_GPG11; "row3"; 3;S3C2410_GPG11_INP; S3C2410_GPG11_OUTP;S3C2410_GPG11_EINT19};};struct pin_col {int pin;int col_input;int col_output;};static struct pin_col col_line4 = {{S3C2410_GPE11; S3C2410_GPE11_INP; S3C2410_GPE11_OUTP};{S3C2410_GPG6; S3C2410_GPG6_INP; S3C2410_GPG6_OUTP};{S3C2410_GPE13; S3C2410_GPE13_INP; S3C2410_GPE13_OUTP};{S3C2410_GPG2; S3C2410_GPG2_INP; S3C2410_GPG2_OUTP}; };static int key_comfirm44={{10;11;12;16};{7;8;9;15};{4;5;6;14};{1;2;3;13};};/构建异步通知注册函数用到的结构体/struct fasync_struct fsbuttons_fasync;struct fspin cur_pin;static void set_col_outputvoid{int i;fori = 0;i<4;i++{s3c2410_gpio_cfgpincol_linei.pin;col_linei.col_output;s3c2410_gpio_setpincol_linei.pin;0;}}static void set_col_inputvoid{int i;fori = 0;i<4;i++{s3c2410_gpio_cfgpincol_linei.pin;col_linei.col_input;s3c2410_gpio_pullupcol_linei.pin; 0;//上拉}}//void functionunsigned long;static irqreturn_t button_timer_fununsigned long data{int i;unsigned int val_sec;int row;int col =-1;ifcur_pinreturn IRQ_NONE;val_sec = s3c2410_gpio_getpincur_pin->pin;ifval_sec = cur_pin->key_valreturn IRQ_NONE;row = cur_pin->num;/将发生中断的引脚配置为输出低电平/s3c2410_gpio_cfgpincur_pin->pin; cur_pin->row_output;s3c2410_gpio_setpincur_pin->pin; 0;/将kscan0-kscan3设为输入并拉高/set_col_input;/ 轮询列线;看哪个管脚为0;为0的那列保存起来/fori = 0;i<4;i++{ifs3c2410_gpio_getpincol_linei.pin == 0col = i;}/根据列线与行线保存键值/fs_buttons->key_buttons= key_comfirmrowcol;/恢复//将列线恢复为输出;并且输出为0/set_col_output;/将产生中断的管脚;再次恢复为中断功能/s3c2410_gpio_cfgpincur_pin->pin;cur_pin->int_put;/唤醒休眠的进程/wake_up_interruptible&fs_buttons->buttons_wq;/异步通知;发信号/kill_fasync&fsbuttons_fasync; SIGIO; POLLIN;return IRQ_HANDLED;}//typedef int irqreturn_t;//define IRQ_NONE 0 //处理失败//define IRQ_HANDLED 1 //处理成功//define IRQ_RETVALx x = 0 //无效的static irqreturn_t buttons_irq_handler_funint irq; void dev_id{cur_pin = struct fspin dev_id;/获取管脚状态/cur_pin->key_val= s3c2410_gpio_getpincur_pin->pin;/有键按键按下/ifcur_pin->key_val== 0/重载定时器/mod_timer&fs_buttons->button_timer; jiffies +5;return IRQ_HANDLED ;}static int buttons_openstruct inode inode; struct file file{int i ;int ret = -1;/初始化设备//设置 kscan0 引脚为输出..输出为0/set_col_output;/注册中断 ;下降沿触发;中断名;中断id/fori =0 ;i<4;i++ret = request_irqfspin_desci.irq;buttons_irq_handler_fun; IRQF_TRIGGER_FALLING; fspin_; &fspin_desci;/初始化定时器/init_timer&fs_buttons->button_timer;fs_buttons->button_timer.expires = jiffies +5;fs_buttons->button_timer.function =voidbutton_timer_fun;/加载定时器/add_timer&fs_buttons->button_timer;/初始化等待队列头/init_waitqueue_head&fs_buttons->buttons_wq;return 0;}static ssize_t buttons_readstruct file filp; char __user buf; size_t count; loff_t opps{int ret;/1.如果没有按键;而且应用程序是以非阻塞方式打开;就直接返回/iffs_buttons->key_buttons == 0 && filp->f_flags &O_NONBLOCKreturn 0;/1.如果没有键值key_buttons = 0 ;则休眠/wait_event_interruptiblefs_buttons->buttons_wq;fs_buttons->key_buttons;/2.如果有键值;将键值返回用户空间//如果拷贝成功则返回0;否则返回剩下的没有拷贝完的字节数/ret = copy_to_userbuf; &fs_buttons->key_buttons; count;fs_buttons->key_buttons = 0; //键值清0return 1;}static ssize_t buttons_writestruct file file; const char __user buf; size_t count; loff_t opps{}/异步通知/int buttons_fasyncint fd; struct file file ; int on{int error = 0;/想办法将file中的某些参数拿出来;实际上就是在设置fsbuttons_fasync结构体/error = fasync_helperfd; file; on; &fsbuttons_fasync;return error;}static unsigned int buttons_pollstruct file file; struct poll_table_struct wait{int mask = 0;/1.将进程挂入等待队列;但是并不休眠/poll_waitfile; &fs_buttons->buttons_wq; wait;/2.查看是否有事件/iffs_buttons->key_buttonsmask |= POLLIN;return mask;}int buttons_closestruct inode inode; struct file file{int i;fori = 0;i<4;i++free_irqfspin_desci.irq; &fspin_desci;}struct file_operations buttons_fops={.owner =THIS_MODULE;.open =buttons_open;.read =buttons_read;.write =buttons_write;.poll =buttons_poll;.release =buttons_close;.fasync =buttons_fasync;};/构建和初始化fsbuttons_cdev结构体/static void setup_fsbuttons_cdevvoid{/给cdev结构体分配空间/fs_buttons->buttons_cdev = cdev_alloc;/初始化/cdev_initfs_buttons->buttons_cdev; &buttons_fops;/加载cdev/cdev_addfs_buttons->buttons_cdev; MKDEVbuttons_major;0; 1; }static int __init buttons_initvoid{int devno;/申请设备号;注册/ifbuttons_major{/静态方式/devno = MKDEVbuttons_major;0;register_chrdev_regiondevno; 1; "buttons_driver";}else{/动态方式/alloc_chrdev_region&devno; 0; 1; "buttons_driver";buttons_major = MAJORdevno;}/2.分配空间;GFP_KERNEL:如果分配空间不成功;则会休眠/fs_buttons =kmallocsizeoffs_buttons; GFP_KERNEL;/构建cdev/setup_fsbuttons_cdev;/创建设备文件/fs_buttons->buttons_class =class_createTHIS_MODULE;"buttons";class_device_createfs_buttons->buttons_class; NULL; MKDEVbuttons_major;0; NULL; "buttons";return 0;}static void __exit buttons_exitvoid{unregister_chrdev_regionMKDEVbuttons_major;0; 1;kfreefs_buttons;cdev_delfs_buttons->buttons_cdev;class_device_destroyfs_buttons->buttons_class; MKDEVbuttons_major;0;class_destroyfs_buttons->buttons_class;}module_initbuttons_init;module_exitbuttons_exit;MODULE_LICENSE"GPL";/ button_irq_test.c /include<stdio.h>include<string.h>include <sys/types.h>include <sys/stat.h>include <fcntl.h>int mainvoid{int fd = -1;int val = -1;int ret = -1;// fd = open"/dev/buttons";O_RDWR|O_NONBLOCK;fd = open"/dev/buttons";O_RDWR;iffd < 0{perror"open";exit-1;}while1{ret = readfd;&val;4;ifret < 0{perror"read";exit-1;}printf"val = %d\n";val;}return 0;}/ button_poll_test.c /include<stdio.h>include<string.h>include <sys/types.h>include <sys/stat.h>include <fcntl.h>include<poll.h>int mainvoid{int fd = -1;int val = -1;int ret = -1;struct pollfd poll_fd1;// fd = open"/dev/buttons";O_RDWR|O_NONBLOCK;fd = open"/dev/buttons";O_RDWR;iffd < 0{perror"open";exit-1;}poll_fd0.fd = fd;poll_fd0.events = POLLIN;while1{ret =pollpoll_fd;1;5000;ifret>0{readpoll_fd0.fd;&val;4;printf"val =%d\n";val;}else ifret ==0{printf"timeout\n";}else{printf"error\n";}}return 0;}/ button_fasync.c /include <stdio.h>include <string.h>include <sys/types.h>include <sys/stat.h>include <fcntl.h>include <poll.h>include <unistd.h>include <fcntl.h>include <signal.h>int fd;/1.实现信号处理函数/void signal_functionint signum{unsigned int val;static int cnt = 0;printf"get singal %d; cnt = %d\n"; signum; cnt++;readfd;&val;4;printf"val =%d\n";val;}int mainint argc; charargv{int flags;fd =open"/dev/buttons";O_RDWR;iffd<0{printf"cannot open /dev/buttons\n";return -1;}/2.将信号与信号处理函数绑定/signalSIGIO; signal_function;/3.设置信号的拥有者为本进程/fcntlfd;F_SETOWN;getpid; //filp->f_owner.pid =get_pidpid;/4.设置为异步通知的模式/flags |=FASYNC;fcntlfd;F_SETFL;flags; //调用到驱动中的fasync功能函数while1{/做自己的事情/sleep3;}return 0;}。

基于设备树编写按键中断驱动程序

基于设备树编写按键中断驱动程序

基于设备树编写按键中断驱动程序 Linux内核版本:4.14.2 本⽂基于itop4412开发板,编写驱动程序响应HOME按键中断,编写这个按键驱动程序需要做如下⼏个⼯作: 1. 在原理图中确定HOME按键的引脚 2. 在设备树⽂件中添加节点描述HOME引脚 3. 重新编译烧写设备树 4. 编写驱动程序,调⽤设备树接⼝函数获取HOME引脚的中断号,使⽤中断号注册按键中断处理程序1. 在原理图中确定HOME按键的引脚 在原理图中找到HOME按键对应的引脚是GPX1_12. 在设备树⽂件中添加节点描述HOME引脚 itop4412开发板中将GPIO分成多个组,GPX1_1在gpx1组中,设备树⽂件exynos4412-pinctrl.dtsi中⽤如下节点描述gpx1组: 我们需要在设备树⽂件exynos4412-itop-elite.dts中,根据exynos4412-pinctrl.dtsi⽂件对gpx1组的描述添加HOME引脚的描述节点,如下3. 重新编译烧写设备树4. 编写驱动程序,调⽤设备树接⼝函数获取HOME引脚的中断号,使⽤中断号注册按键中断处理程序 驱动程序按照平台总线的架构编写,⽤platform_driver_register注册驱动; 4.1 设备和驱动匹配实现过程 在设备树⽂件中添加了HOME按键的描述节点后,内核在解析设备树时,就会将上述节点转换成⼀个平台设备platform_device;在struct platform_driver结构体中,将compatible属性设置为”irq-keys”,那么,加载驱动后,就会和内核⽣成的这个平台设备platform_device 匹配,从⽽进⼊probe函数中驱动程序中指定compatible的程序如下:static const struct of_device_id irq_test_of_match[] = {{ .compatible = "irq-keys", },{ },};MODULE_DEVICE_TABLE(of, irq_test_of_match);static struct platform_driver irq_test_device_driver = {.probe = irq_test_probe,.driver = {.name = "irqtest_keys",.of_match_table = irq_test_of_match,}}; 4.2 HOME引脚信息读取过程 上述驱动和设备匹配后,程序就进⼊probe函数中,在probe函数中,可以使⽤设备树相关的接⼝读取HOME引脚的信息: 读取⼦节点的个数,irqtest_keys只有⼀个⼦节点key-home device_get_child_node_count 获取每个⼦节点的结构体 device_for_each_child_node(dev, child) 获取⼦节点中引脚的虚拟中断号,这个虚拟中断号是内核⾃动⽣成的 irq_of_parse_and_map(to_of_node(child), 0) 获取⼦节点gpio描述符gpiod devm_fwnode_get_gpiod_from_child 使⽤虚拟中断号注册中断处理函数 devm_request_any_context_irq测试驱动程序如下:1 #include <linux/module.h>2 #include <linux/init.h>3 #include <linux/fs.h>4 #include <linux/interrupt.h>5 #include <linux/irq.h>6 #include <linux/sched.h>7 #include <linux/pm.h>8 #include <linux/slab.h>9 #include <linux/sysctl.h>10 #include <linux/proc_fs.h>11 #include <linux/delay.h>12 #include <linux/platform_device.h>13 #include <linux/input.h>14 #include <linux/gpio_keys.h>15 #include <linux/workqueue.h>16 #include <linux/gpio.h>17 #include <linux/gpio/consumer.h>18 #include <linux/of.h>19 #include <linux/of_irq.h>20 #include <linux/spinlock.h>2122/* 设备树节点 */23#if 024 irqtest_keys {25 compatible = "irq-keys";26 key-home {27 label = "GPIO key-home";28 gpios = <&gpx1 1 GPIO_ACTIVE_LOW>;29 pinctrl-0 = <&my_irq_key>;30 pinctrl-names = "default";31 };32 };3334 my_irq_key: my-irq-key {35 samsung,pins = "gpx1-1";36 samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;37// samsung,pin-drv = <EXYNOS4_PIN_DRV_LV4>;38 };39#endif4041struct my_gpio_keys_button {42 unsigned int code;43int gpio;44int active_low;45const char *desc;46 unsigned int type;47int wakeup;48int debounce_interval;49bool can_disable;50int value;51 unsigned int irq;52struct gpio_desc *gpiod;53 };5455static char *label[2];56static struct device *dev;57static struct my_gpio_keys_button *button;5859static irqreturn_t irq_test_irq_isr(int irq, void *dev_id)60 {61 printk(KERN_INFO "get irq --> irq_test_irq_isr.\n");6263return IRQ_HANDLED;64 }6566static int irq_test_probe(struct platform_device *pdev)67 {68/* 获取节点信息,注册中断 */69 dev = &pdev->dev;70struct fwnode_handle *child = NULL;71int nbuttons;72int irq, error;73 irq_handler_t isr;74 unsigned long irqflags;7576 nbuttons = device_get_child_node_count(dev);77if (nbuttons == 0) {78 printk(KERN_INFO "no child exist, return\n");79return ERR_PTR(-ENODEV);80 }8182 printk(KERN_INFO "child num is %d.\n", nbuttons);83 button = devm_kzalloc(dev, sizeof(struct my_gpio_keys_button) * nbuttons, GFP_KERNEL); 8485/* 获取lable参数,⽗节点没有lable属性 */86 device_property_read_string(dev, "label", label[0]);87 printk(KERN_INFO "parent lable %s\n", label[0]);8889/* 扫描处理每个⼦节点 */90 device_for_each_child_node(dev, child) {91/* 获取虚拟中断号virq */92if (is_of_node(child)) {93 button->irq = irq_of_parse_and_map(to_of_node(child), 0);94 }9596 fwnode_property_read_string(child, "label", &button->desc);97/* 获取gpio描述符gpiod */98 button->gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL,99 child,100 GPIOD_IN,101 button->desc);102if (IS_ERR(button->gpiod)) {103 printk(KERN_INFO "get gpiod failed, return.\n");104return -ENOENT;105 }106107/* 检查虚拟中断号,可不使⽤ */108if (!button->irq) {109 irq = gpiod_to_irq(button->gpiod);110if (irq < 0) {111 error = irq;112 dev_err(dev,113"Unable to get irq number for GPIO %d, error %d\n",114 button->gpio, error);115return error;116 }117 button->irq = irq;118 }119120 printk(KERN_INFO "get virq %d for key.\n", button->irq);121 isr = irq_test_irq_isr;122 irqflags = 0;123 irqflags |= IRQF_SHARED;124//devm_request_any_context_irq(class_dev, data->irq,int26_irq, IRQF_TRIGGER_FALLING, data->name, data); 125126/* 设置引脚为输⼊模式 */127 gpiod_set_value(button->gpiod, 1);128 gpiod_direction_input(button->gpiod);129130/* 注册中断 */131/* 最后⼀个参数是传给中断函数的参数 */132 error = devm_request_any_context_irq(dev, button->irq, isr, IRQF_TRIGGER_FALLING, button->desc, NULL); 133if (error < 0) {134 dev_err(dev, "Unable to claim irq %d; error %d\n", button->irq, error);135return error;136 }137 }138139return0;140 }141142static const struct of_device_id irq_test_of_match[] = {143 { .compatible = "irq-keys", },144 { },145 };146147 MODULE_DEVICE_TABLE(of, irq_test_of_match);148149static struct platform_driver irq_test_device_driver = {150 .probe = irq_test_probe,151 .driver = {152 .name = "irqtest_keys",153 .of_match_table = irq_test_of_match,154 }155 };156157static int __init irq_test_init(void)158 {159return platform_driver_register(&irq_test_device_driver);160 }161162static void __exit irq_test_exit(void)163 {164 devm_free_irq(dev, button->irq, NULL);165 platform_driver_unregister(&irq_test_device_driver);166 }167168 module_init(irq_test_init);169 module_exit(irq_test_exit);170171 MODULE_LICENSE("GPL");。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Linux下的一个使用中断的按键驱动程序(S3C2440)#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/irq.h>#include <asm/irq.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <mach/regs-gpio.h>#include <mach/hardware.h>#include <linux/platform_device.h>#include <linux/cdev.h>#include <linux/miscdevice.h>#include <linux/sched.h>#include <linux/gpio.h>#include <linux/timer.h> /*timer*/#define BUTTON_IRQ IRQ_EINT8 //申请的中断号#define DEVICE_NAME "button" //设备名字#define BUTTONMINOR 0#define DELAY (HZ/100) //延时100MSDECLARE_WAIT_QUEUE_HEAD(wq); //申请一个wq等待队列并初始化,//wait_queue_heat_t wq; //也可用两句来替换(申请初始化一个等待队列)//int_waitqueue_heat(&wq);static unsigned char key_down_cnt=0; //中断计数static int ev_press=0; //唤醒等待的条件static int button_Major;struct timer_list timer; //定时器链表void timer_function()//定时产生后的处理函数{int down;if(down = !s3c2410_gpio_getpin(BUTTON_IRQ)) //如果按键按下执行以下程序{ key_down_cnt++; //来一次,中断计数加一ev_press = 1; //表示中断发生了wake_up_interruptible(&wq); } //唤醒休眠的进程return 0;}static irqreturn_t button_irq_ser(int irq,void *dev_id,struct pt_regs *regs) //中断服务程序{//初始化定时器链表init_timer(&timer);timer.data=0;timer.expires=jiffies+DELAY;timer.function=timer_function;add_timer(&timer);}static int s3c2410_button_open(struct inode *inode,struct file *filp) //open 函数{int ret;ret=request_irq(BUTTON_IRQ,button_irq_ser,IRQF_DISABLED,DEVICE_NAME,NU LL); //注册中断,button_irq_ser中断函数,成功返回0if(ret<0){printk("could not register interrupt !");return ret;}printk("interrupt register successed");return 0;}static int s3c2410_button_release(struct inode *inode,struct file *filp) //关闭设备{free_irq(BUTTON_IRQ,NULL); //释放中断return 0;}//读设备static ssize_t s3c2410_button_read(struct file *filp,char __user *buff,size_t count,loff_t *offp){//printk("sleep\n");//如果ev_press = 0,则继续休眠wait_event_interruptible(wq,ev_press);//若执行到这儿,ev_press = 1printk("wake up \n");//清除ev_pressev_press = 0;//拷贝key_down_cnt 到用户空间copy_to_user(buff,(const void *)&key_down_cnt,sizeof(char));printk("process is waked up after");// key_down_cnt = 0;return sizeof(unsigned char);}static struct file_operations s3c2410_button_flops = {.owner = THIS_MODULE,.open = s3c2410_button_open,.read = s3c2410_button_read,.release = s3c2410_button_release,};//模块初始化static int __init s3c2410_button_init(void){int ret;//set_irq_type(BUTTON_IRQ,IRQT_FALLING); //设置触发中断的类型,下降沿触发ev_press = 0; //初始化ev_press//注册设备,返回主设备号ret=register_chrdev(0,DEVICE_NAME,&s3c2410_button_flops);if(ret<0){printk(DEVICE_NAME"can not register the number!");return ret;}button_Major = ret;//建立设备节点#ifdef CONFIG_DEVFS_FSdevfs_mk_cdev(MKDEV(button_Major,BUTTONMINOR),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME);#endifprintk("button_init initialized successed! major=%d\n",ret);return 0;}//卸载模块static void __exit s3c2410_button_exit(void){#ifdef CONFIG_DEVFS_FSdevfs_remove(DEVICE_NAME);#endifunregister_chrdev(button_Major,DEVICE_NAME);}MODULE_LICENSE("GPL");MODULE_AUTHOR("YUAF");MODULE_DESCRIPTION("the s3c2410 key interrupt driver");module_init(s3c2410_button_init);module_exit(s3c2410_button_exit);在使用等待队列的时候,必须得初始化。

Init_waitqueue_head(&(buttondev.wq);也可以用DECLARE_WAIT_QUEUE_HEAD(buttondev.wq),初始化和申明都在这条语句里面。

若不初始化,则会出现:测试程序如下:#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>int main(){int retval;int fileno;int ts, maxfd;int ret= 0,i,j;int number=0;fileno = open("/dev/button",O_RDWR);if (fileno == -1) {printf("open device led errr!\n");return 0;}printf("open success\n");while(1) {read(fileno,&number,1);printf("key=%d\n",number);}close(fileno);return 0;}仍需解决的问题:按键消抖的问题,这个程序,按一下,有时会出现多次中断。

int request_irq(unsigned int irq, irq_handler_t handler, unsigned lo ng irqflags, const char *devname, void *dev_id)irq是要申请的硬件中断号。

handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。

irqflags是中断处理的属性,若设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED (老版本中的SA_SHIRQ),则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。

相关文档
最新文档