【记录】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"还有回车键。既然把按键当成了键盘,那只要在文本编辑框按下按键就会有输入的,所以,在这可以随便打开一个文本编辑,只要有光标提示,就可以按下按键了
QQ图片20160805125923.png (605.08 KB, 下载次数: 0)
2016-8-5 12:58 上传