linux驱动之中断方式获取键值

------------------------------------------------------------------------------------------------------------------------------------------------------

回想在单片机下的中断处理

  1. 分辨是哪个中断
  2. 调用处理函数
  3. 清中断

-------------------------------------------------------------------------------------------------------------------------------------------------------

1、中断框架

trap_int  中构造

trap_int函数就是一些跳转指令

b...

b...

b  vector_irq + stubs_offset   ;vector_irq是链接地址    stubs_offset 是偏移地址

vector_irq:

  1. 保存被中断的现场
  2. asm_do_IRQ
  3. 恢复现场
  4. 。。

asm_do_IRQ:

对中断的处理。

request_irq  注冊中断

request_irq(irq,handle,irqflags,devname,dev_id)

1、分配irqaction 结构

2、setup_irq(irq,action)

0、分配一个irqaction 结构

a、在irq_desc[irq]   -> action

b、desc -> chip ->settype

c、desc -> chip -> startup /enable

irq 要申请的硬件中断号 +
handle 是向系统登记的中断处理函数 是一个回调函数,主哦功能短发生时,系统将调用这个函数,并将dev_id传递给它
irqflags 是中断处理属性  

free_irq   卸载中断

free_irq(irq, dev_id)

1、出链

2、禁止中断

2、代码编写

1、申请IRQ

这里我要特殊说明下:(向我这样的小白在使用request_irq这个函数时遇到了一个问题就是  IRQ_EINT1、IRQ_EINT4、IRQ_EINT2、IRQ_EINT0这四个宏找不到,终于原因找到了 。我配置eclipse的时候内核树的路径有些小问题。

irqs.h这个文件是在 /linux-2.6.30.4/arch/arm/mach-s3c2410/include
这个路径下。我以为这个在mach-s3c2440也会有这个路径呢。事实上不然。另一些引脚的定义也在2410的路径里面,这里要注意一下 )。

	request_irq(IRQ_EINT1,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key1",&pins_desc[0]);
request_irq(IRQ_EINT4,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key2",&pins_desc[1]);
request_irq(IRQ_EINT2,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key3",&pins_desc[2]);
request_irq(IRQ_EINT0,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key4",&pins_desc[3]);

这里的pins_desc 是一个结构体数组

struct pin_desc pins_desc[4] =
{
{S3C2410_GPF1,0x01},
{S3C2410_GPF4,0x02},
{S3C2410_GPF2,0x03},
{S3C2410_GPF0,0x04},
};

这个数组里面包括了这四个中断引脚和该引脚的键值。

结构体原型是这种:

struct pin_desc{
unsigned int pin;
unsigned int key_value;
};

2、写中断处理函数

static irqreturn_t buttons_irq(int irq,void *dev_id)
{
struct pin_desc * pindesc = (struct pin_desc *) dev_id;
unsigned int pinval;
pinval = s3c2410_gpio_getpin(pindesc -> pin);
if(pinval)//松开
{
keyval = 0x80|pindesc->key_value;
}
else
{
keyval = pindesc->key_value;
}
ev_press =1;//中断发生
wake_up_interruptible(&button_wait_q);
printk("button is pressed : %d \n",irq);
return IRQ_HANDLED;
}

说明:

pindesc :这个结构体会得知是哪个按键按下了

s3c2410_gpio_getpin:这个函数是内核提供的函数,能够获得当前引脚的高低电平

ev_press:中断事件标志。中断服务程序将他置1,read函数将他置0

wake_up_interruptible(&button_wait_q);  会唤醒休眠的进程,唤醒注冊到等待队列上的进程,当中 button_wait_q是通过例如以下方式获得的:

static DECLARE_WAIT_QUEUE_HEAD(button_wait_q);  
生成一个等待队列头wait_queue_head_t,名字为 button_wait_q

3、改动read函数

ssize_t button_dev_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
{
if(size !=1)
{
return -EINVAL;
}
/*假设没有按键动作发生 就休眠*/
wait_event_interruptible(button_wait_q,ev_press);
/*假设有按键动作发生,直接返回*/
copy_to_user(buf,&keyval,1);
ev_press = 0;
return 0;
}

当中:

wait_event_interruptible(button_wait_q,ev_press);   假设ev_press是假的话。就会休眠

ev_press =0; 每次读完,都将中断事件标志清零。

4、填充file_operations结构体

static struct file_operations button_sdv_fops =
{
.owner = THIS_MODULE,
.open = button_dev_open,
.read = button_dev_read,
.release = button_dev_close,
};

当中button_dev_close函数为:

int button_dev_close(struct inode* inode ,struct file *file)
{
free_irq(IRQ_EINT1,&pins_desc[0]);
free_irq(IRQ_EINT4,&pins_desc[1]);
free_irq(IRQ_EINT2,&pins_desc[2]);
free_irq(IRQ_EINT0,&pins_desc[3]); return 0;
}

free_irq为释放中断。当中须要两个參数。

本代码在上一篇按键的博文基础上改动。

完整的驱动代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/irqs.h>//这个在/opt/EmbedSky/linux-2.6.30.4/arch/arm/mach-s3c2410/include/mach 路径
#include <linux/interrupt.h> MODULE_LICENSE("Dual BSD/GPL"); static struct class *buttondrv_class;
static struct class_devices *buttondrv_class_dev; /* */
static DECLARE_WAIT_QUEUE_HEAD(button_wait_q);
/*中断事件标志,中断服务程序将他置1,read函数将他置0*/
static volatile int ev_press =0; volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL; static unsigned keyval; struct pin_desc{
unsigned int pin;
unsigned int key_value;
};
/*按键按下时是:0x01 0x02 0x03 0x04*/
/*按键松开时是:0x81 0x82 0x83 0x84*/
struct pin_desc pins_desc[4] =
{
{S3C2410_GPF1,0x01},
{S3C2410_GPF4,0x02},
{S3C2410_GPF2,0x03},
{S3C2410_GPF0,0x04},
};
/*
* 确定按键值
*/
static irqreturn_t buttons_irq(int irq,void *dev_id)
{
struct pin_desc * pindesc = (struct pin_desc *) dev_id;
unsigned int pinval;
pinval = s3c2410_gpio_getpin(pindesc -> pin);
if(pinval)//松开
{
keyval = 0x80|pindesc->key_value;
}
else
{
keyval = pindesc->key_value;
}
ev_press =1;//中断发生
wake_up_interruptible(&button_wait_q);
printk("button is pressed : %d \n",irq);
return IRQ_HANDLED;
}
static int button_dev_open(struct inode *inode ,struct file* file)
{
//配置按键的引脚 GPF0,1,2,4为输入引脚
request_irq(IRQ_EINT1,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key1",&pins_desc[0]);
request_irq(IRQ_EINT4,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key2",&pins_desc[1]);
request_irq(IRQ_EINT2,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key3",&pins_desc[2]);
request_irq(IRQ_EINT0,buttons_irq, IRQ_TYPE_EDGE_BOTH,"key4",&pins_desc[3]); return 0;
}
ssize_t button_dev_read(struct file *file,char __user *buf,size_t size,loff_t *ppos)
{
if(size !=1)
{
return -EINVAL;
}
/*假设没有按键动作发生 就休眠*/
wait_event_interruptible(button_wait_q,ev_press);
/*假设有按键动作发生,直接返回*/
copy_to_user(buf,&keyval,1);
ev_press = 0;
return 0;
}
int button_dev_close(struct inode* inode ,struct file *file)
{
free_irq(IRQ_EINT1,&pins_desc[0]);
free_irq(IRQ_EINT4,&pins_desc[1]);
free_irq(IRQ_EINT2,&pins_desc[2]);
free_irq(IRQ_EINT0,&pins_desc[3]); return 0;
}
static struct file_operations button_sdv_fops =
{
.owner = THIS_MODULE,
.open = button_dev_open,
.read = button_dev_read,
.release = button_dev_close,
};
int major;
static int button_dev_init(void)//入口函数
{
major = register_chrdev(0,"button_drv",&button_sdv_fops); buttondrv_class = class_create(THIS_MODULE,"button_drv");
if(IS_ERR(buttondrv_class))
return PTR_ERR(buttondrv_class);
buttondrv_class_dev= device_create(buttondrv_class,NULL,MKDEV(major,0),NULL,"wq_button");
if(unlikely(IS_ERR(buttondrv_class_dev)))
return PTR_ERR(buttondrv_class_dev); /*映射物理地址*/
gpfcon = (volatile unsigned long *) ioremap(0x56000050 ,16);
gpfdat = gpfcon + 1; return 0;
}
static void button_dev_exit(void)
{
unregister_chrdev(major,"button_drv");
device_unregister(buttondrv_class_dev);
class_destroy(buttondrv_class); iounmap(gpfcon);
}
module_init(button_dev_init);
module_exit(button_dev_exit);

測试代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/*
* wq_device <dev> <on|off>
*/
int main(int argc, char **argv)
{
int cnt=0;
int fd;
unsigned char key_val;
fd = open("/dev/wq_button", O_RDWR);
if(fd<0)
{
printf("can't open \n");
}
while(1)
{
read(fd,&key_val,1);
printf("key_val = 0x%x\n",key_val);
}
return 0;
}

linux驱动之中断方式获取键值的更多相关文章

  1. 字符设备驱动笔记——中断方式按键驱动之linux异常处理结构(四)

    .中断方式获取按键值 单片机: )按键按下 )cup发生中断,跳转到异常向量入口执行 )b 函数 a.保存被中断的现场 b.执行中断处理函数 c.恢复 linux: )trap_init()函数构造异 ...

  2. 在Linux下的中断方式读取按键驱动程序

    // 在Linux下的中断方式读取按键驱动程序 //包含外部中断 休眠 加入poll机制 // 采用异步通知的方式 // 驱动程序发 ---> app接收 (通过kill_fasync()发送) ...

  3. Linux驱动设计—— 中断与时钟

    中断和时钟技术可以提升驱动程序的效率 中断 中断在Linux中的实现 通常情况下,一个驱动程序只需要申请中断,并添加中断处理函数就可以了,中断的到达和中断函数的调用都是内核实现框架完成的.所以程序员只 ...

  4. C语言定义从URL中获取键值的接口

    环境:centos7下,对客户端http请求进行解析,来获取有效键值(包括汉字). 头文件 /* 这是一份关于从Http请求信息中提取键值的接口声明的头文件 */ #ifndef _HEAD_H_ # ...

  5. 字符设备驱动笔记——中断方式按键驱动之linux中断处理结构(五)

    一.单片机下的中断处理 )分辨是哪一个中断 )调用处理函数 )清中断 二.linux下的中断处理 1)/arch/arm/kernel/irq.c asmlinkage void __exceptio ...

  6. Linux驱动设计—— 中断与时钟@request_irq参数详解

    request_irq函数定义 /*include <linux/interrupt.h>*/ int request_irq(unsigned int irq, irq_handler_ ...

  7. java程序(一)----HashMap同时获取键值

    快速会用: HashMap<Integer,String> maps=new HashMap<Integer,String>(); maps.put(1,"xiaom ...

  8. Map获取键值,Map的几种遍历方法

    Map 类提供了一个称为entrySet()的方法,这个方法返回一个Map.Entry实例化后的对象集.接着,Map.Entry类提供了一个 getKey()方法和一个getValue()方法,Map ...

  9. Map获取键值,Map的几种遍历方法 (转载)

    Map类提供了一个称为entrySet()的方法,这个方法返回一个Map.Entry实例化后的对象集.接着,Map.Entry类提供了一个getKey()方法和一个getValue()方法,Map.E ...

随机推荐

  1. Android(java)学习笔记187:多媒体之SurfaceView

    1. SurfaceView:     完成单位时间内界面的快速切换(游戏界面流畅感). 我们之前知道一般的View,只能在主线程里面显示,主线程中更新UI.但是SurfaceView可以在子线程中里 ...

  2. 一起来学SpringBoot(十七)优雅的参数校验

    参数校验在开发中经常需要写一些字段校验的代码,比如字段非空,字段长度限制,邮箱格式验证等等,写这些与业务逻辑关系不大的代码个人感觉有两个麻烦: 验证代码繁琐,重复劳动方法内代码显得冗长每次要看哪些参数 ...

  3. Linux——网络编程线程池机制

    #include <stdlib.h>#include <pthread.h>#include <unistd.h>#include <assert.h> ...

  4. [bzoj4816][Sdoi2017]数字表格 (反演+逆元)

    (真不想做莫比乌斯了) 首先根据题意写出式子 ∏(i=1~n)∏(j=1~m)f[gcd(i,j)] 很明显的f可以预处理出来,解决 根据套路分析,我们可以先枚举gcd(i,j)==d ∏(d=1~n ...

  5. webservice和一般处理程序

    一丶WebService 1.新建项目 2.选择Web窗体 3.添加新建项 二丶一般处理程序 前台访问: $.ajax({ type: "post", url: "Han ...

  6. 全国绿色计算大赛 模拟赛第二阶段 (Python)

    第1关气温预测 def dailyTemps(temp_list): result = [] for ca in range(0, len(temp_list)-1): for i in range( ...

  7. SpringBoot Banner 图片定制修改

    启动Spring Boot项目的时候,在控制台会默认输出一个启动图案 这个图案如果你需要的话是可以自己修改的,修改方式很简单: 1. 在src/main/resources下新建一个banner.tx ...

  8. Spring核心技术(八)——Spring自动装载的注解

    本文针对自动装载的一些注解进行描述. 基于注解的容器配置 @Required注解 @Required注解需要应用到Bean的属性的setter方法上面,如下面的例子: public class Sim ...

  9. Spring 事物注解属性

    @Transactional属性 . propagation 事物的传播属性 . isolation 事物的隔离属性 . readonly 设置只读属性 . timeout 设置超时属性 . roll ...

  10. Unity 3D 使用Relief Terrain Pack(RTP) 问题

    Unity3D 5.2 RTP 3.2d -------------------------------------------------------------------- 使用RTP编译sha ...