Linux驱动开发、17-输入子系统浅析

输入子系统

1、概念:内核对分散的,多种不同类别的输入设备进行统一处理的驱动程序。

2、输入子系统的好处:

a) 统一物理形态各异的相似的输入设备的处理功能

b) 提供了用于分发输入报告给用户应用程序的简单事件(event)接口。驱动程序不必创建、管理/dev节点以及相关的访问方法,因此它能方便地被调用输入API以发送鼠标移动,键盘按键或者触摸事件给用户空间

c) 抽取了输入驱动程序的通用部分,简化驱动程序并引入一致性

 

3、输入子系统架构图

 Linux驱动开发、17-输入子系统浅析_第1张图片

图解:

设备驱动层:将底层的硬件输入转化成统一事件形式,向输入核心汇报

输入核心层:为设备驱动层提供输入设备注册与操作接口

事件驱动层:主要作用是和用户空间层进行数据交互

 

4、输入设备驱动程序: /driver/input 目录下

a) serio:该层提供了访问老式输入硬件的库例程。为了与serio提供服务的硬件通讯,如发送命令给PS/2鼠标,需要用到:

serio_register_driver():向serio注册规定的回调例程

serio_register_port():注册open/close/write/stop/start入口函数

 

 

b) 键盘(EV_KEY/0X01:键盘驱动程序的独特之处在于它传送数据给另外一个内核子系统(TTY层),而不是通过 /dev目录下的节点传送给用户空间。驱动文件在/dev/char目录下

 

可以通过以下命令查看矩阵键盘的扫描码:showkey -s 或者 showkey

 

根据加载的键盘映射,键盘事件驱动程序进行键值翻译(查看loadkeys的操作帮助和/lib/kbd/keymaps中提供的映射文件)

 

 

c) 鼠标:鼠标输入事件驱动称为 mousedev, 通过/dev/input/mice报告鼠标事件给用户

 

d) 指点杆(EV_REL/0X02Trackpoint):是一个指定设备

详细配置选项:/sys/devices/platform/i8042/serioX/serioY

 

e) 触摸板(EV_ABS/0x03)

f) 触摸驱动控制器:以N_TCH线路规程的形式实现了串行触摸控制器的设备驱动程序。由于制造过程的细微差别,同一款触摸板可能会产生略有不同的坐标范围,为了使应用程序不受影响,在使用之前一般通过GUI发起校准,如果支持自校准就不用了。

 

 

5、Evdev 接口:Evdev是一个通用的输入事件驱动程序。Evdev产生的每个事件包都有如下格式:

<linux/input.h>头文件中

struct input_event {

struct timeval time;

__u16 type; /*事件类型*/

__u16 code; /*事件编码*/

__s32 value; /*事件的数值*/

};

 

6、调试

编写输入驱动程序时,可以使用evbug模块辅助调试。它dump输入子系统产生的事件对应的type,code,value元组,

7、输入事件驱动程序的使用

 Linux驱动开发、17-输入子系统浅析_第2张图片

初始化:

1、定义结构体:struct input_dev  *xxx;

2、结构分配:xxx = input_allocate_device();

3、申明所支持的事件类型:set_bit(事件类型,xxx->evbit);

4、申明该事件类型有可能产生的事件编码:set_bit(事件编码,xxx->keybit/relbit/absbit/...)

注册: input_register_device(xxx);

注销: input_unregister_device(xxx);

 

事件上报: input_report_key(keyinput,KEY_3,1);

事件上报结束: input_sync(keyinput);

 

 

输入事件驱动注册完成会在 /dev 目录下创建 eventx设备文件,

同时在 sys/devices/virtual/input/input3 也会创建设备文件...具体要进一步分析

 

按键输入事件驱动程序设计

/************************************

作者:hntea

时间:2016/3/16

函数功能:平台总线测试

问题1input: Unspecified device as /devices/virtual/input/input3

问题2:应用软件只能接受一次事件上报

************************************/

 

#include<linux/init.h>

#include<linux/module.h>

#include<linux/device.h>

#include<linux/platform_device.h>

#include<linux/interrupt.h>

#include<linux/fs.h>

#include<linux/miscdevice.h>

#include<linux/mm.h>

#include<linux/io.h>

#include<linux/input.h>

 

struct input_dev *keyinput;

 

/***********************************

函数名:

函数功能:中断处理

函数参数

***********************************/

static irqreturn_t key1_hander (int irq, void *dev_id)

{

// printk("key1 down!\n");

input_report_key(keyinput,KEY_1,1);

input_sync(keyinput);

return 0;

}

static irqreturn_t key2_hander (int irq, void *dev_id)

{

// printk("key2 down!\n");

input_report_key(keyinput,KEY_2,1);

input_sync(keyinput);

return 0;

}

static irqreturn_t key3_hander (int irq, void *dev_id)

{

// printk("key3 down!\n");

input_report_key(keyinput,KEY_3,1);

input_sync(keyinput);

return 0;

}

static irqreturn_t key4_hander (int irq, void *dev_id)

{

input_report_key(keyinput,KEY_4,1);

input_sync(keyinput);

// printk("key4 down!\n");

return 0;

}

/***********************************

函数名:

函数功能:定义平台驱动

函数参数:

***********************************/

struct resource* res_irq;

struct resource* res_iomem;

unsigned int* key_ioconfig;

int key_probe(struct platform_device *pdev)

{

/*初始化事就交到这里*/

int ret = 0;

int size = 0;

unsigned int temdata=0;

 

printk("Probe  Devices Success!\n");

 

/*1、硬件初始化*/

   res_iomem =  platform_get_resource(pdev, IORESOURCE_MEM, 0); /*最后一个参数是索引*/

   size = (res_iomem->end - res_iomem->start); /*8个字节*/

key_ioconfig = ioremap(res_iomem->start,size);  

temdata = ioread32(key_ioconfig);

temdata &= (~0xfffff);

temdata |= 0xfffff;

iowrite32(temdata,key_ioconfig);

/*注册中断*/

 

res_irq =  platform_get_resource(pdev, IORESOURCE_IRQ, 0);

    ret = request_irq(res_irq->start + 0,key1_hander,IRQF_TRIGGER_FALLING,"key1",0);

ret = request_irq(res_irq->start + 1,key2_hander,IRQF_TRIGGER_FALLING,"key2",0);

ret = request_irq(res_irq->start + 2,key3_hander,IRQF_TRIGGER_FALLING,"key3",0);

ret = request_irq(res_irq->start + 3,key4_hander,IRQF_TRIGGER_FALLING,"key4",0);

 

  

return ret;

}

int key_remove(struct platform_device *pdev)

{

/*释放中断*/

free_irq(res_irq->start + 0, 0);

free_irq(res_irq->start + 1, 0);

free_irq(res_irq->start + 2, 0);

free_irq(res_irq->start + 3, 0);

/*注销内存*/

iounmap(key_ioconfig);

return 0;

}

 

/*平台驱动可以有多个*/

static struct platform_driver key_driver = {

.probe = key_probe,

.remove = key_remove,

.driver = {

.owner = THIS_MODULE,

.name = "keydevices",

},

};

 

 

 

/***********************************

函数名:

函数功能:

函数参数

***********************************/

static int keyPlatformDriverInit(void)

{

int ret = 0;

/*平台驱动注册*/

if( (ret = platform_driver_register(&key_driver))<0)

printk("platform_driver_register err!\n");

/*输入事件驱动注册*/

if(!(keyinput = input_allocate_device()))

{

printk("input devices allocate err!");

}

 

set_bit(EV_KEY,keyinput->evbit);

set_bit(KEY_1,keyinput->keybit);

set_bit(KEY_2,keyinput->keybit);

set_bit(KEY_3,keyinput->keybit);

set_bit(KEY_4,keyinput->keybit);

if ((ret = input_register_device(keyinput)) <0 )

{

printk("input devices register err!");

}

return ret;

}

 

static void keyPlatformDriverExit(void)

{

/*平台驱动注销*/

platform_driver_unregister(&key_driver);

/*注销输入设备*/

input_unregister_device(keyinput);

}

 

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Hntea");

 

module_init(keyPlatformDriverInit);

module_exit(keyPlatformDriverExit);

 

测试APP

/*

 *      Buttons Example for Matrix V

 *

 *      Copyright (C) 2004 capbily - friendly-arm

 * [email protected]

 */

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/ioctl.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <sys/select.h>

#include <sys/time.h>

#include <errno.h>

#include <linux/input.h>

int main(void)

{

int buttons_fd;

int key_value,i=0,count;

 

struct input_event ev_key;

buttons_fd = open("/dev/event2", O_RDWR);

if (buttons_fd < 0) {

perror("open device buttons");

exit(1);

}

 

for (;;)

{

count = read(buttons_fd,&ev_key,sizeof(struct input_event));

for(i=0; i<(int)count/sizeof(struct input_event); i++)

{

if(EV_KEY==ev_key.type)

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

if(EV_SYN==ev_key.type)

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

}

i=0;

}

 

close(buttons_fd);

return 0;

}

 

 

 

你可能感兴趣的:(linux,嵌入式,TQ210,Linux驱动开发,Linux总线模型)