4067|2

1234

帖子

4

TA的资源

纯净的硅(高级)

楼主
 

【记录】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) 初始化中断(这个与自己板子有关了)
  1. static int __init button_init(void)
  2. {
  3.         unsigned char i ;
  4.         int irq_no;
  5.         int iRet;
  6.         
  7.         button_dev = input_allocate_device();
  8.         if(!button_dev){
  9.                 return -ENOMEM;
  10.         }
  11.         set_bit(EV_KEY, button_dev->evbit);
  12. //set_bit(EV_REP, button_dev->evbit); 这句话是支持连按操作的。
  13.         
  14.         set_bit(KEY_L, button_dev->keybit);
  15.         set_bit(KEY_S, button_dev->keybit);
  16.         set_bit(KEY_ENTER, button_dev->keybit);
  17.         
  18.         input_register_device(button_dev);
  19.         
  20.         init_timer(&button_timer);
  21.         button_timer.function = button_timer_function;
  22.         add_timer(&button_timer);
  23.         
  24.         for(i=0;i<3;i++){
  25.                 gpio_free(pins_desc[i].pin);
  26.                 iRet = gpio_request(pins_desc[i].pin, DEVICE_NAME);
  27.                 if(iRet != 0){
  28.                         printk("request button failed \n");
  29.                 return -EBUSY;
  30.                 }
  31.                 gpio_direction_input(pins_desc[i].pin);
  32.                 printk("direction input OK \n");
  33.                 irq_no  = gpio_to_irq(pins_desc[i].pin);
  34.             set_irq_type(irq_no, IRQF_TRIGGER_FALLING);        //下降沿中断
  35.                 printk("IRQF_TRIGGER_FALLING \n");
  36.                 //申请中断并设置中断处理函数
  37.             iRet = request_irq(irq_no, button_irq, IRQF_DISABLED,pins_desc[i].name , &pins_desc[i]);
  38.             if (iRet != 0){
  39.                          printk("request irq failed!! ret: %d  irq:%d gpio:%d  \n", iRet, irq_no, pins_desc[i].pin);
  40.                          return -EBUSY;
  41.             }
  42.         }
  43.         printk(DEVICE_NAME" up. \n");
  44.         return 0;
  45. }
复制代码


出口函数也要与之对应:

  1. static void __exit button_exit(void)
  2. {
  3.         unsigned char i ;
  4.         int irq_no;
  5.         for(i=0;i<3;i++){
  6.                 gpio_free(pins_desc[i].pin);
  7.                 irq_no  = gpio_to_irq(pins_desc[i].pin);
  8.                 free_irq(irq_no, &pins_desc[i]);
  9.         }
  10.         del_timer(&button_timer);
  11.         input_unregister_device(button_dev);
  12.         input_free_device(button_dev);
  13.         printk(DEVICE_NAME " down.\n");
  14. }
复制代码

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

  1. /*  中断程序  */
  2. static irqreturn_t button_irq(int irq, void *dev_id)
  3. {
  4.         printk("irq test \n");        
  5.         irq_pd = (struct pin_desc *)dev_id;
  6.         //struct pin_des * pindesc = (struct pin_desc *)dev_id;
  7.         mod_timer(&button_timer,jiffies+HZ/100);   //10ms以后启动定时
  8.         
  9.         return IRQ_RETVAL(IRQ_HANDLED);
  10. }
复制代码
  1. static void button_timer_function(unsigned long data)
  2. {
  3.     struct pin_des * pindesc = irq_pd;
  4.         if (!pindesc)
  5.                 return;
  6.    unsigned int val;
  7.         val = (unsigned char)gpio_get_value(pindesc->pin);
  8.         if(val){
  9.                 printk("anxia !\n");
  10.                 /* 松开 : 最后一个参数: 0-松开, 1-按下 */
  11.                 input_event(button_dev, EV_KEY, pindesc->key_val, 1);
  12.                 input_sync(button_dev);
  13.         }else{
  14.                 printk("songkai !\n");
  15.                 /* 按下 */
  16.                 input_event(button_dev, EV_KEY, pindesc->key_val, 0);
  17.                 input_sync(button_dev);
  18.         }
  19.    
  20. }
复制代码


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





此帖出自Linux开发论坛

最新回复

写的真不错  学习一下  详情 回复 发表于 2016-8-5 14:07
点赞 关注
个人签名天地庄周马;江湖范蠡船。
个性签名还是放QQ号吧,2060347305,添加说明EEworld好友

回复
举报

1234

帖子

4

TA的资源

纯净的硅(高级)

沙发
 
上面只是实现了把按键当成键盘来使用,但输入子系统可不仅仅是有键盘啊


这里记录下来几点补充的东西:
  在入口函数set_bit函数可不只只有EV_KEY
EV_SYN     0x00    同步事件

EV_KEY     0x01    按键事件

EV_REL     0x02    相对坐标(如:鼠标移动,报告相对最后一次位置的偏移)

EV_ABS     0x03    绝对坐标(如:触摸屏或操作杆,报告绝对的坐标位置)

EV_MSC     0x04    其它

EV_SW      0x05    开关

EV_LED     0x11    按键/设备灯

EV_SND     0x12    声音/警报

EV_REP     0x14    重复

EV_FF      0x15    力反馈

EV_PWR    0x16    电源

EV_FF_STATUS    0x17   力反馈状态

EV_MAX    0x1f    事件类型最大个数和提供位掩码支持

上报输入事件不只只有input_event(button_dev, EV_KEY, pindesc->key_val, 1);

void input_report_key(struct input_dev *dev, unsigned int code, int value);      //上报按键事件

void input_report_rel(struct input_dev *dev, unsigned int code, int value);       //上报相对坐标事件

void input_report_abs(struct input_dev *dev, unsigned int code, int value);              //上报绝对坐标事件

此帖出自Linux开发论坛
 
个人签名天地庄周马;江湖范蠡船。
个性签名还是放QQ号吧,2060347305,添加说明EEworld好友
 

回复

10

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
写的真不错  学习一下
此帖出自Linux开发论坛
 
个人签名敢富网sayings
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表