linux驱动开发:input子系统二
来源:互联网 发布:linux piwik安装 编辑:程序博客网 时间:2024/06/14 03:14
输入子系统:linux内核中将所有输入设备归为一个类:input子系统。里面实现了几乎所有输入设备的公共操作接口,相当于内核给我们搭建了一个输入子系统的框架,我们用它的框架开发驱动,会变得非常简单。因为一些公共的函数内核已经帮我们实现好了,我们只需要实现不同输入设备间的差异部分即可。
上篇文章 记录了在输入子系统的框架下实现一个按键的上报功能。一个输入设备,上报一种按键事件。
那么一个输入设备,也是可以上报多种按键事件的。
因为上一章的框架已经搭建好,我们只需要注册其他的按键中断并上报按键事件即可。所以整个代码就变得非常简单。
当然,如果作为模块:在模块卸载时,需要逆序消除对内核的影响。简单的讲: 在你的init函数中 register一个设备,那么在你的exit函数中就应该 unregister这个设备.
那么直接上代码:
#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/gpio.h>#include <asm/uaccess.h>#include <linux/input.h>#include <asm/io.h>#include <linux/kernel.h>#include <mach/gpio.h>#include <linux/irq.h>#include <asm/bitops.h>#define _HIGH 1#define _LOW 0#define _ZERO 0enum button_event { _EV_UP, _EV_DOWN,};struct buttons_desc{ int gpio; //PHY button Addr int keycode; // button keycode char *name; // button name};static struct buttons_desc buttons_array[] ={ {S5PV210_GPH2(0),KEY_LEFT,"LEFT"}, {S5PV210_GPH2(1),KEY_RIGHT,"RIGHT"}, {S5PV210_GPH2(2),KEY_UP,"UP"}, {S5PV210_GPH2(3),KEY_DOWN,"DOWN"}, {S5PV210_GPH3(0),KEY_MENU,"MENU"}, {S5PV210_GPH3(1),KEY_ENTER,"ENTER"}, {S5PV210_GPH3(2),KEY_BACKSPACE,"BACKSPACE"}, {S5PV210_GPH3(3),KEY_DELETE,"DELETE"},};/*****irq use****/volatile struct buttons_desc *g_buttons_desc_info = NULL;/*****input device use****/static struct input_dev *buttons_input_dev =NULL;/*****timer use****/static struct timer_list buttons_timer;/******func start******//******button irq******/static irqreturn_t smart210_buttons_irq(int irq, void* dev_id){ //get whitch key trigger the irq g_buttons_desc_info =(volatile struct buttons_desc*)dev_id; //Eliminate key jitter,delay 10 ms to get key value mod_timer(&buttons_timer,jiffies + HZ/100); return IRQ_HANDLED;}/******timer del func******/static void buttons_timer_func(unsigned long data){ int uc_keysta =0; struct buttons_desc *uc_buttons_desc =(struct buttons_desc *)g_buttons_desc_info; if(!uc_buttons_desc) { return; } //get the pin level :high /low //pree up 0,pree down 1 if(gpio_get_value(uc_buttons_desc->gpio) == _HIGH) { uc_keysta =_EV_UP; } else { uc_keysta =_EV_DOWN; } input_event(buttons_input_dev,EV_KEY, uc_buttons_desc->keycode,uc_keysta); input_event(buttons_input_dev,EV_SYN, _ZERO,_ZERO);}static int __init smart210_buttons_init(void){ int i; int ret=0; //1.alloc input dev device buttons_input_dev = input_allocate_device(); if (!buttons_input_dev) { ret = -ENOMEM; printk("1.error allocate input device!\n"); goto err_allocate_input_dev; } //2.set up the input dev param,Report event //EV_KEY :key event //EV_SYN: sync event set_bit(EV_KEY,buttons_input_dev->evbit); set_bit(EV_SYN,buttons_input_dev->evbit); set_bit(EV_REP,buttons_input_dev->evbit); //set EV_KEY key code for(i =0; i < ARRAY_SIZE(buttons_array);i++) { set_bit(buttons_array[i].keycode,buttons_input_dev->keybit); } //set input dev name buttons_input_dev->name = "buttons"; //3.register device ret = input_register_device(buttons_input_dev); if(ret) { printk("2.error to register input device!\n"); goto err_register_input_dev; }/******special func user add for different input device*********/ //4.irq request for(i =0; i < ARRAY_SIZE(buttons_array);i++) { ret =request_irq(gpio_to_irq(buttons_array[i].gpio),smart210_buttons_irq,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, buttons_array[i].name,&buttons_array[i]); if(ret) { break; } } if(ret) { i--; for(; i >0;i--) { if(!buttons_array[i].gpio) { continue; } disable_irq(gpio_to_irq(buttons_array[i].gpio)); free_irq(gpio_to_irq(buttons_array[i].gpio),&buttons_array[i]); } printk("3.error to request irq !\n"); goto err_request_irq; } //5.timer initial init_timer(&buttons_timer); buttons_timer.function =buttons_timer_func; add_timer(&buttons_timer); printk("4.success initial input device!\n"); return 0;err_request_irq: input_unregister_device(buttons_input_dev);err_register_input_dev:err_allocate_input_dev: input_free_device(buttons_input_dev); return ret;}static void __exit smart210_buttons_exit(void){ int i; del_timer(&buttons_timer); for(i=0;i< ARRAY_SIZE(buttons_array);i++) { disable_irq(gpio_to_irq(buttons_array[i].gpio)); free_irq(gpio_to_irq(buttons_array[i].gpio),&buttons_array[i]); } input_unregister_device(buttons_input_dev); input_free_device(buttons_input_dev); printk("5.success unload input device!\n");}module_init(smart210_buttons_init);module_exit(smart210_buttons_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("User");
实验现象:
input设备注册成功后,cat/proc/interrupts下面会有你的中断号:
第一列:中断号
第二列:响应的次数,没有响应中断就是0
第三列:中断类型
第四列:中断的name
同样,dev/input/目录下面会多一个event*设备文件,主设备号13,次设备号自动分配.
我们可以操作这个设备文件:
以16进制的格式显示event1中的数据。里面的数据含义如下:
同时,在 proc/bus/input/下面会有devices和 handlers两个文件
devices:
这里面两个输入设备,一个是TS的,一个是按键的.
handlers:
这里面有4个handlers,其中evdev是我们按键的,mousedev是鼠标的.其他的不清楚
整个input设备注册的流程:
input device register procedure:1.alloc input dev device/*****input device use****/static struct input_dev *buttons_input_dev =NULL;buttons_input_dev =input_allocate_device();2. fill in/ initial the struct buttons_input_dev //set up the input dev param,Report event //EV_KEY :key event //EV_SYN: sync event set_bit(EV_KEY,buttons_input_dev->evbit); set_bit(EV_SYN,buttons_input_dev->evbit); set_bit(EV_REP,buttons_input_dev->evbit); //set EV_KEY key code set_bit(buttons_array[0].keycode,buttons_input_dev->keybit); //set input dev name buttons_input_dev->name = "buttons";3.register input device ret = input_register_device(buttons_input_dev);/*****input device register end****/4. Report event: input_event(buttons_input_dev,EV_KEY, uc_buttons_desc->keycode,uc_keysta); input_event(buttons_input_dev,EV_SYN, _ZERO,_ZERO);//EV_SYN must have ,its finish end flag5. cancle /logout the device: input_unregister_device(buttons_input_dev);6. free the input dev: input_free_device(buttons_input_dev);all the above is the frame of input system.
标准的输入子系统的注册大概就是这样的。
测试程序:
#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include<linux/input.h>struct input__event{ struct timeval time; __u16 type; __u16 code; __s32 value;};int fd;int main(){ struct input__event ev_key; fd = open("/dev/input/event1",O_RDWR); printf("fd =%d,\n",fd); while(1) { read(fd,&ev_key,sizeof(ev_key)); if(ev_key.type == EV_KEY) { printf("time:%ld s,%ld us,type: %d,code:%d,vale:%d.\n",ev_key.time.tv_sec,ev_key.time.tv_usec,ev_key.type,ev_key.code,ev_key.value); } } return 0;}
用户空间调用open,read函数读按键值出来:
这样,按键的驱动和测试程序都已完成.
- linux驱动开发:input子系统二
- linux input子系统驱动(二)
- Linux驱动开发之input子系统
- linux驱动开发:input子系统一
- linux驱动开发:input子系统三
- input子系统——linux驱动学习笔记(二)
- input子系统——linux驱动学习笔记(二)
- Linux设备驱动 --- input子系统
- linux ------ input 子系统设备驱动
- Linux驱动之input子系统
- linux驱动---Input 输入子系统
- Linux驱动 之 input子系统--input.h
- linux input 子系统分析 二
- linux input 子系统分析 二
- linux input 子系统分析 二
- linux input 子系统分析 二
- linux input子系统(二)- input event drivers evdev 驱动分析
- input子系统驱动学习之二
- 使用Spark分析拉勾网招聘信息(二): 获取数据
- plotly.js
- 深度学习中的 Batch_Size的作用
- C++STL的next_permutation
- 分布式session共享
- linux驱动开发:input子系统二
- 圆形里面写字
- WebSocket(壹) 握手连接
- asynchttpclien使用Post数据上传
- java 类加载器
- hdu 4762 Cut the Cake (概率 + java大数)
- java进程的代码。
- 微信企业号第三方应用开发[三]——授权应用
- SqlMapClientFactoryBean为什么能转为SqlMapClient