输入子系统由驱动层、输入子系统核心、事件处理层三部分组成。一个输入事件,如鼠标移动、键盘按下等通过Driver->Inputcore->Event handler->userspace的顺序到达用户控件的应用程序。

其中核心层提供一些设备层与事件层公用的函数,比如说注册函数、反注册函数、事件到来的处理函数等等;事件层其实在Linux内核里面已经帮我们写好了很多有关的事件;而设备层就跟我们新添加到输入系统的具体设备相关了。这里以JZ2440开发板上的4个按键作为输入子系统的按键:它定义的功能分别为:KEY_L、KEY_S、KEY_ENTER、KEY_LEFTSHIFT。这几个值是在include\linux\input.h中被定义的。

button_drv.c文件:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <asm/io.h> 
#include <asm/uaccess.h>
#include <linux/device.h>/
#include <asm/arch/regs-gpio.h>
#include <linux/irq.h>
#include <asm-arm/irq.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <asm-generic/errno-base.h>
#include <linux/input.h>

struct pin_desc
{
  char * name;            //名称
  unsigned int pin;       //管脚定义
  unsigned int irq;       //中断号
  unsigned int key_val;   //按键值
};

static struct pin_desc pins_desc[4] = 
{
  {"S1",S3C2410_GPF0,IRQ_EINT0,KEY_L},
  {"S2",S3C2410_GPF2,IRQ_EINT2,KEY_S},
  {"S3",S3C2410_GPG3,IRQ_EINT11,KEY_ENTER},
  {"S4",S3C2410_GPG11,IRQ_EINT19,KEY_LEFTSHIFT}
};

static struct pin_desc *pinss_desc=NULL;

static struct timer_list timer_button;                //新建一个定时器

static struct input_dev *buttons_input;               //新建一个输入子系统的设备层结构

static irqreturn_t buttons_irq(int irq, void *dev_id)
{
  pinss_desc = (struct pin_desc *)dev_id;            //取得哪个按键被按下的状态
  mod_timer(&inputbuttons_timer, jiffies+HZ/100);    //10ms之后调用定时器处理函数
  return IRQ_HANDLED;
}

static void timer_button_timeout(unsigned long a)
{
  unsigned int pin_val;

  if(pinss_desc==NULL)
    return;
  else
  {
    pin_val = s3c2410_gpio_getpin(pinss_desc->pin);

    if(pin_val)
    {
      input_event(buttons_input,EV_KEY, pinss_desc->key_val, 0);
    }
    else
    {
      input_event(buttons_input,EV_KEY, pinss_desc->key_val, 1);
    }
  }
}

static int button_drv_init(void)
{
  unsigned char i;
  int ret;
  buttons_input = input_allocate_device();        //分配input_dev结构体
  if (!buttons_input)
    return -ENOMEM;

  set_bit(EV_KEY, buttons_input->evbit);          //按键事件
  set_bit(EV_REP, buttons_input->evbit);          //重复事件类型
  set_bit(KEY_L, buttons_input->keybit);
  set_bit(KEY_S, buttons_input->keybit);
  set_bit(KEY_ENTER, buttons_input->keybit);
  set_bit(KEY_LEFTSHIFT, buttons_input->keybit);

  input_register_device(buttons_input);           //注册设备驱动

  init_timer(&timer_button);
  inputbuttons_timer.expires = 0;
  inputbuttons_timer.function = timer_button_timeout;
  add_timer(&timer_button);
                                                                                                                                     //注意这里没有创建设备类和设备文件(设备节点)

                                                              //因为输入子系统的设备文件本来就存在为/dev/event0
  for(i=0;i<4;i++)
  {
    ret = request_irq(pins_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pins_desc[i].name, (void * )&pins_desc[i]);
    if(ret)
    {
      printk("open failed %d\n",i);
      return -(i+1);
    }
  }
  return 0;
}

static void button_drv_exit(void)
{
  unsigned char i;

  input_unregister_device(buttons_input);
  input_free_device(buttons_input);
  del_timer(&timer_button);

  for(i=0;i<4;i++)
  {
    free_irq(pins_desc[i].irq, (void * )&pins_desc[i]);
  }
}

module_init(seven_drv_init);
module_exit(seven_drv_exit);

MODULE_LICENSE("GPL");

Makefile文件:

obj-m += button_drv.o

KERN_DIR = /work/system/linux-2.6.22.6

all:
make -C $(KERN_DIR) M=`pwd` modules 
clean:
rm -rf *.o *.ko *.order *.symvers *.mod.c

button_app.c文件:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>

static int fd;

int main(int argc, char **argv)
{
  char* filename = argv[1];
  int oflags, ret=0;
  unsigned char key_val[16];

  fd = open(filename, O_RDWR);//打开设备文件,阻塞方式打开
  if (fd < 0)
  {
    printf("error, can't open %s\n", filename);
    return 0;
  }
  while(1)
  {
    ret = read(fd, key_val, 16);
    printf("ret: %d, code: %02d, value: %d \n", ret, key_val[10], key_val[12]);
  }
  return 0;
}

app_read->evdev_read->kbtab_irq->input_report_key->input_event->evdev_event->evdev_read

应用层      事件层        设备层        核心层               核心层          事件层          事件层

应用函数最终会通过事件层的evdev_event调用evdev_read

而在linux中evdev_event结构体共16字节,所以app中的read函数也应该读取16字节

编译生成button_drv.ko和button_app文件,运行./button_app /dev/event0

Linux 驱动——Button8(输入子系统)的更多相关文章

  1. linux驱动模型<输入子系统>

    在linux中提供一种输入子系统的驱动模型,其主要是实现在input.c中. 在输入子系统这套模型中,他把驱动分层分类.首先分为上下两层,上层为input.c .下层为驱动的实现,下层分为两部分,一部 ...

  2. Linux驱动之输入子系统简析

    输入子系统由驱动层.输入子系统核心.事件处理层三部分组成.一个输入事件,如鼠标移动.键盘按下等通过Driver->Inputcore->Event handler->userspac ...

  3. Linux 驱动框架---input子系统框架

    前面从具体(Linux 驱动框架---input子系统)的工作过程学习了Linux的input子系统相关的架构知识,但是前面的学习比较实际缺少总结,所以今天就来总结一下输入子系统的架构分层,站到远处来 ...

  4. Linux 驱动框架---input子系统

    input 子系统也是作为内核的一个字符设备模块存在的,所以他也是字符设备自然也会有字符设备的文件接口.input子系统的注册过程主要分为两步,先注册了一个input class然后再注册一个字符设备 ...

  5. ARM Linux内核Input输入子系统浅解

    --以触摸屏驱动为例 第一章.了解linux input子系统         Linux输入设备总类繁杂,常见的包括有按键.键盘.触摸屏.鼠标.摇杆等等,他们本身就是字符设备,而linux内核将这些 ...

  6. Linux驱动之一个简单的输入子系统程序编写

    的在Linux驱动之输入子系统简析已经分析过了输入子系统的构成,它是由设备层.核心层.事件层共同组成的.其中核心层提供一些设备层与事件层公用的函数,比如说注册函数.反注册函数.事件到来的处理函数等等: ...

  7. Linux输入子系统 转载

    NQian 记录成长~ 首页 新随笔 联系 订阅 管理 随笔 - 305  文章 - 0  评论 - 254 12.Linux之输入子系统分析(详解)   在此节之前,我们学的都是简单的字符驱动,涉及 ...

  8. Linux驱动之触摸屏程序编写

    本篇博客分以下几部分讲解 1.介绍电阻式触摸屏的原理 2.介绍触摸屏驱动的框架(输入子系统) 3.介绍程序用到的结构体 4.介绍程序用到的函数 5.编写程序 6.测试程序 1.介绍电阻式触摸屏的原理 ...

  9. linux 输入子系统之电阻式触摸屏驱动

    一.输入子系统情景回忆ING...... 在Linux中,输入子系统是由输入子系统设备驱动层.输入子系统核心层(Input Core)和输入子系统事件处理层(Event Handler)组成.其中设备 ...

随机推荐

  1. 一、Git简介

    由于工作需要,代码版本控制工具由SVN换为了Git.Git对于我来说,很陌生,不清楚其工作原理,所以查询了一些资料,将自己所得知的内容来汇总一下,梳理一下这方面的知识,同时也给其他想了解Git的童鞋们 ...

  2. STL 小白学习(8) set 二叉树

    #include <iostream> using namespace std; #include <set> void printSet(set<int> s) ...

  3. PlantUML + Chrome 联合使用

    之前都是本地下载安装一个PlantUML,安装过程有点复杂,涉及到的其他插件也有些多. 后面发现Chrome浏览器上提供了相关插件,整个过程简直太流畅了.记录下. 安装: 打开Chrome的线上应用商 ...

  4. php 查询mysql数据批量转为PDF文件二(批量使用wkhtmltopdf html导出PDF)

    上节讲到配置wkhtmltopdf,这节讲下如何批量操作 首先讲下wkhtmltopdf如何使用 直接命令行输入: wkhtmltopdf http://www.baidu.com/  baidu.p ...

  5. Android中的Context(一)

    Android中的Context(一) 在Android开发中,Context可以说是我们接触地非常多的一个概念了,也译作"上下文",但是这个上下文到底是什么却并不好理解. 通俗的 ...

  6. centos6.8安装mysql5.5

    在使用阿里云的时候发现centos6.8系统自带的源当中没有mysql5.5,在网易这些源里面也是5.1的版本.这里安装mysql5.5的话需要另外添加一个源. 1.查看是否已经安装了MySQL rp ...

  7. Go 基础 坑

    1.字符串空为"" 2. 传递的数组是原数组的拷贝,所以是无法通过传递数组的方法去修改原地址的数据的.在GO语言中除了切片(slice).集合(map).通道(channel)和接 ...

  8. git版本控制系统更新

    版本控制系统: 一.概念: 版本控制系统(Version Control System):是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统. 二.版本控制系统分类 1.本地版本控制 ...

  9. Ubuntu17.04 安装搜狗中文输入法

    http://blog.csdn.net/ydyang1126/article/details/76223656

  10. JavaScript js 引入CDN 不生效 注意事项

    [博客园cnblogs笔者m-yb原创,转载请加本文博客链接,笔者github: https://github.com/mayangbo666,公众号aandb7,QQ群927113708]https ...