arm linux 按键实验,【记录】ARM-Linux开发之输入子系统还是用按键做例

【记录】ARM-Linux开发之输入子系统还是用按键做例

[复制链接]

本帖最后由 ywlzh 于 2016-8-5 13:04 编辑

这个记录还是要用按键做实验,只不过用了输入子系统的框架来写的程序,与先前的misc驱动程序有些许不同,但相同的地方就是两者都是字符设备驱动。input系统是别人把字符设备驱动程序拆成了两个部分,而input系统的核心层在源代码/derives/input/input.c 这就是别人写好的框架了。

简单分析这个input.c文件,入口函数有这两句:

class_register(&input_class);

register_chrdev(INPUT_MAJOR, "input", &input_fops);

对于字符设备驱动程序好像缺少一个函数,那就是创建设备节点!INPUT_MAJOR 为 13 ,查看input_fops,就一个open函数,可想而在,这个open函数要做很多事情,里面程序如果真要分析,会把自己搞晕!所以就分析一句:

new_fops->open(inode, file);  //重新分配fops结构,看你注册的什么设备了。

再回过头来:

linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler)、输入子系统核心层(InputCore)和输入子系统设备驱动层。对于输入子系统设备驱动层而言,主要实现对硬件设备的读写访问,中断设置,并把硬件产生的事件转换为核心层定义的规范提交给事件处理层。

对于核心层而言,为设备驱动层提供了规范和接口。设备驱动层只要关心如何驱动硬件并获得硬件数据(例如按下的按键数据),然后调用核心层提供的接口,核心层会自动把数据提交给事件处理层。

对于事件处理层而言,则是用户编程的接口(设备节点),并处理驱动层提交的数据处理。所以,对于开发者来说,我只需要往input系统注册设备,把input_dev结构体做好了,最后提交,那么初始化就完成了,至于怎么跳转的,那都是Linux内核做好了的。

好了,开始写程序:(在写之前,不妨看看源代码/Documentation/input/input-programming.txt,这个就是一个活生生的例子。)

按键怎么确定? 中断!

抖动怎么处理? 定时器消抖!

所以整个程序需要用到,中断,定时器,input系统框架。

程序入口函数:

1) 注册input设备

2) 设置input的哪类事件。(这里是作为键盘使用)

3) 初始化定时器,

4) 初始化中断(这个与自己板子有关了)

static int __init button_init(void)

{

unsigned char i ;

int irq_no;

int iRet;

button_dev = input_allocate_device();

if(!button_dev){

return -ENOMEM;

}

set_bit(EV_KEY, button_dev->evbit);

//set_bit(EV_REP, button_dev->evbit); 这句话是支持连按操作的。

set_bit(KEY_L, button_dev->keybit);

set_bit(KEY_S, button_dev->keybit);

set_bit(KEY_ENTER, button_dev->keybit);

input_register_device(button_dev);

init_timer(&button_timer);

button_timer.function = button_timer_function;

add_timer(&button_timer);

for(i=0;i<3;i++){

gpio_free(pins_desc[i].pin);

iRet = gpio_request(pins_desc[i].pin, DEVICE_NAME);

if(iRet != 0){

printk("request button failed \n");

return -EBUSY;

}

gpio_direction_input(pins_desc[i].pin);

printk("direction input OK \n");

irq_no  = gpio_to_irq(pins_desc[i].pin);

set_irq_type(irq_no, IRQF_TRIGGER_FALLING);        //下降沿中断

printk("IRQF_TRIGGER_FALLING \n");

//申请中断并设置中断处理函数

iRet = request_irq(irq_no, button_irq, IRQF_DISABLED,pins_desc[i].name , &pins_desc[i]);

if (iRet != 0){

printk("request irq failed!! ret: %d  irq:%d gpio:%d  \n", iRet, irq_no, pins_desc[i].pin);

return -EBUSY;

}

}

printk(DEVICE_NAME" up. \n");

return 0;

}复制代码

出口函数也要与之对应:

static void __exit button_exit(void)

{

unsigned char i ;

int irq_no;

for(i=0;i<3;i++){

gpio_free(pins_desc[i].pin);

irq_no  = gpio_to_irq(pins_desc[i].pin);

free_irq(irq_no, &pins_desc[i]);

}

del_timer(&button_timer);

input_unregister_device(button_dev);

input_free_device(button_dev);

printk(DEVICE_NAME " down.\n");

}复制代码

整个程序,就不需要自己在写file_ops结构了,所有的read,poll,open都是内核做好了,我只需要负责input_register_device 函数就行,然后系统就会休眠,等待唤醒,对于这次用的按键,就是中断唤醒,中断让定时器消抖,所以最后还是用定时器来唤醒的。

具体函数:

/*  中断程序  */

static irqreturn_t button_irq(int irq, void *dev_id)

{

printk("irq test \n");

irq_pd = (struct pin_desc *)dev_id;

//struct pin_des * pindesc = (struct pin_desc *)dev_id;

mod_timer(&button_timer,jiffies+HZ/100);   //10ms以后启动定时

return IRQ_RETVAL(IRQ_HANDLED);

}复制代码

static void button_timer_function(unsigned long data)

{

struct pin_des * pindesc = irq_pd;

if (!pindesc)

return;

unsigned int val;

val = (unsigned char)gpio_get_value(pindesc->pin);

if(val){

printk("anxia !\n");

/* 松开 : 最后一个参数: 0-松开, 1-按下 */

input_event(button_dev, EV_KEY, pindesc->key_val, 1);

input_sync(button_dev);

}else{

printk("songkai !\n");

/* 按下 */

input_event(button_dev, EV_KEY, pindesc->key_val, 0);

input_sync(button_dev);

}

}复制代码

编译好,make没事了后,就加载进板子里面去,怎么看效果呢?由于板子自动了加载了QT,所以,在终端上很难看到自己输入的键值,键值的确定在程序入口里写好了,我这确定的是"l""s"还有回车键。既然把按键当成了键盘,那只要在文本编辑框按下按键就会有输入的,所以,在这可以随便打开一个文本编辑,只要有光标提示,就可以按下按键了

a26d678767e8b431ecd7a25f1936bdc5.gif

QQ图片20160805125923.png (605.08 KB, 下载次数: 0)

2016-8-5 12:58 上传

你可能感兴趣的:(arm,linux,按键实验)