输入子系统---按键

来源:互联网 发布:java classloader级别 编辑:程序博客网 时间:2024/04/30 22:25

一、

linux输入子系统——基础知识  

1、首先我们要知道什么时候我们可以用到input输入子系统,以及为什么我们要用input输入子系统?

像按键、触摸屏、鼠标等输入设备我们都可以采用input接口函数来实现设备驱动。那么采用input输入子系统有什么优点呢?其实一句话,采用input输入子系统可以使驱动程序变得异常简单。

2、input输入子系统体系结构

 

 

我们看到输入子系统体系结构大概包括三部分:drivers、inputcore、handlers,其中input core、handlers是由内核来实现的,程序员要做的就是利用inputcore提供的接口函数来实现drivers。下面我们来具体说一下这三层的功能:

驱动层(drivers):将底层的硬件输入转化为统一事件形式,向输入核心层(inputcore)汇报。

输入核心层(inputcore):为驱动层提供输入设备注册与操作接口,如input_register_device;通知事件处理层对事件进行处理;在/proc下产生相应的设备信息;

事件处理层(handlers):主要作用是和用户空间交互,我们知道linux在用户空间将所有设备当成文件来处理,在一般的驱动程序中都有提供fops接口,以及在/dev下生成相应的设备文件节点,而在输入子系统中,这些工作由事件处理层来完成。

3、驱动的实现

(1)事件支持:

set_bit(EV_KEY,button_dev.evbit)

参数button_dev.bit是structinput_dev类型的,它有两个成员evbit(事件类型)和keybit(按键类型)(但并非只有这两个成员),关于具体的事件类型和按键类型请看下图:

 

 

 比如当我们要支持按键1的话需要一下两条语句:

set_bit(EV_KEY,button_dev.bit)//事件为按键

set_bit(BTN_1,button_dev.keybit)//按键类型为按键一

(2)注册

当input设备支持了相应的事件之后,就可以将设备注册进内核:input_register_device(&button_dev);

(3)报告事件与完成报告

那么当在底层发生了中断(比如按键中断)时候,用户空间如何知道呢?这就需要inputcore提供的接口函数来向input_core报告。由于报告事件是在中断函数中完成的,所以需要在开始处注册中断:request_irq(BUTTON_IRQ,button_interrupt,0,"button",NULL)

然后在中断处理函数中完成报告事件:

static void button_interrupt(int irq,void*dummy,struct pt_regs *fp)

{

 input_report_key(&button_dev,BTN_0,inb(BUTTON_PORT1));//报告事件

                                                        input_sync(&button_dev);//完成报告

}

注释:inb(BUTTON_PORT1)用于读取按键1的状态,并报告给input core

         input_report_key():用于报告EV_KEY事件状态

         input_report_rel():用于报告EV_REL事件状态

         input_report_abs():用于报告EV_ABS事件状态

(4)用户空间怎样获取驱动操作硬件获取的原始数据

输入设备产生的原始数据经输入设备子系统处理后,最后会被保存在struct input _event 的结构体中,它也是应用程序从input_event接口读取到的数据所用的数据结构。该结构体定义如下:

           Struct   input_event {

                  Struct  timeval  time ;//表示事件发生的时间

                   Unsigned short   type;//事件的类型

                    Unsigned short   code;//事件的子类型代号

                  Unsigned   int value;//事件产生的具体数据

};

 

 

二、驱动程序和测试

 

static struct input_dev *buttons_dev;  //定义一个设备结构体

 

 

static int buttons_open(struct input_dev*dev);

static void buttons_close(struct intput_dev*dev);

static struct timer_list buttons_timer;//定义一个定时器

 

struct pin_desc{

int irq; //中断号

char *name;//按键名称

unsigned int pin;//按键引脚

unsigned int key_val; //按键值

int pin_set;//按键引脚设置(中断)

};

 

struct pin_desc pins_desc[4] = {

{IRQ_EINT0,  "Key1",S3C2410_GPF(0) ,BTN_0 ,S3C2410_GPF2_EINT2},

//{IRQ_EINT11, "Key2", S3C2410_GPG(3),KEY_S,S3C2410_GPG3_EINT11},

//  {IRQ_EINT13, "Key3", S3C2410_GPG(5),KEY_ENTER,S3C2410_GPG5_EINT13},

//{IRQ_EINT14, "Key4", S3C2410_GPG(6),KEY_LEFTSHIFT,S3C2410_GPG6_EINT14},

};

 

static irqreturn_t buttons_irq(int irq, void*dev_id)

{

mod_timer(&buttons_timer,jiffies+HZ/100);

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

return IRQ_RETVAL(IRQ_HANDLED);

}

static void buttons_timer_function(unsigned longdata)

{

unsigned int pinval;

pinval =s3c2410_gpio_getpin(pins_desc[0].pin);

if(pinval)

{    

    input_report_key(buttons_dev, BTN_0, 0);

    input_sync(buttons_dev);   

}

else

    input_report_key(buttons_dev, BTN_0, 1);

    input_sync(buttons_dev);

}

   //copy_to_user(buff, pinval, 1);

}

 

static int buttons_init(void)

{

int err;

//s3c2410_gpio_cfgpin(pins_desc[0].pin,2<<0);

 

buttons_dev = input_allocate_device();;

 

if(!buttons_dev)

{

    printk("unable to allocate the input dev\n");

    return -ENOMEM;

}

   

//s3c2410_gpio_cfgpin(S3C2410_GPF(0),);配置为中断

 

buttons_dev->name = "buttonsinput";//初始化设备的名字

//buttons_dev->id.bustype =BUS_HOST; //初始化设备ID。在注册设备之前,名字和ID是必须初始化的。

   //buttons_dev->id.vendor = 0xDEAD;

//buttons_dev->id.product =0xBEEF;

//buttons_dev->id.version =0x0100;

 

   buttons_dev->dev.init_name ="buttons_input";

set_bit(EV_KEY,buttons_dev->evbit);//按键事件

set_bit(EV_REP,buttons_dev->evbit);//连击事件

//  for(j=0; j<4; j++)

//  {

    set_bit(BTN_0, buttons_dev->keybit);

//  }

//set_bit(KEY_L,buttons_dev->keybit);

//set_bit(KEY_S,buttons_dev->keybit);

//set_bit(KEY_ENTER,buttons_dev->keybit);

//set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);

err=input_register_device(buttons_dev);

if(err)

    goto err1;

//DPRINTK("buttons_dev initalized ok!\n");

 

init_timer(&buttons_timer);

buttons_timer.function =buttons_timer_function;

add_timer(&buttons_timer);

//for (i = 0; i < 4;i++)

//  {

//      request_irq(pins_desc[i].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH,pins_desc[i].name, &pins_desc[i]);

//  }

    request_irq(pins_desc[0].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH,pins_desc[0].name, &pins_desc[0]);

return 0;

 

err1:

//DPRINTK("buttons_dev initalizederror\n");

input_free_device(buttons_dev);

   return err;

}

 

static void buttons_exit(void)

{

//int i;

//for (i = 0; i < 4;i++)

//{

    free_irq(pins_desc[0].irq,&pins_desc[0]);

//}

 

del_timer(&buttons_timer);

input_unregister_device(buttons_dev);//注销设备

input_free_device(buttons_dev);//释放已分配设备结构体空间

}

 

module_init(buttons_init);

module_exit(buttons_exit);

MODULE_LICENSE("GPL");

测试程序:

 

int main(void)

{

   intfd;

   intkey_value,i=0,count;

  struct input_event ev_key; //定义一个按键键值数据缓存区,也是用户获取驱动层数据的结构体

 

 fd= open("/dev/input/event1", O_RDWR);//根据实际情况来设置文件,文件名根据/sys/class/input目录下的设备号来确定

 if(fd < 0)

 {

  perror("open device buttons");

  exit(1);

 }

 

 for (;;)

 {

  count = read(fd,&ev_key,sizeof(structinput_event));

  //if(EV_KEY==ev_key.type)

      printf("type:%d,code:%d,value:%d\n",ev_key.type,ev_key.code,ev_key.value);

  //if(EV_SYN==ev_key.type)

      printf("syn event\n\n");

 }

 close(fd);

 return 0;

}


转自http://blog.sina.com.cn/s/blog_b20e901301018yk9.html

0 0
原创粉丝点击