linux输入子系统概述,Linux输入子系统详解

导读

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

9442ea6115e1d1f2de543112d3bad91a.png

驱动层

将底层的硬件输入转化为统一事件形式,想输入核心(Input Core)汇报。

输入子系统核心层

它承上启下为驱动层提供输入设备注册与操作接口,如:input_register_device;通知事件处理层对事件进行处理;在/Proc下产生相应的设备信息。

事件处理层

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

设备描述

input_dev结构是实现设备驱动核心工作:向系统报告按键、触摸屏等输入事件(event,通过input_event结构描述),不再需要关心文件操作接口。驱动报告事件经过inputCore和Eventhandler到达用户空间。

注册输入设备函数:

int input_register_device(struct input_dev *dev)

注销输入设备函数:

void input_unregister_device(struct input_dev *dev)

驱动实现——初始化(事件支持)set_bit()告诉input输入子系统支持哪些事件,哪些按键。例如:

set_bit(EV_KEY,button_dev.evbit)  (其中button_dev是struct input_dev类型)

struct input_dev中有两个成员为:

1)evbit事件类型(包括EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等)。

2)keybit按键类型(当事件类型为EV_KEY时包括BTN_LEFT,BTN_0,BTN_1,BTN_MIDDLE等)。

驱动实现——报告事件用于报告EV_KEY,EV_REL,EV_ABS事件的函数分别为:

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)

驱动实现——报告结束input_sync()同步用于告诉input core子系统报告结束,触摸屏设备驱动中,一次点击的整个报告过程如下:

input_reprot_abs(input_dev,ABS_X,x);   //x坐标

input_reprot_abs(input_dev,ABS_Y,y);   // y坐标

input_reprot_abs(input_dev,ABS_PRESSURE,1);

input_sync(input_dev);//同步结束

实例分析(按键中断程序):

//按键初始化

static int __init button_init(void)

{//申请中断

if(request_irq(BUTTON_IRQ,button_interrupt,0,”button”,NUll))

return –EBUSY;

set_bit(EV_KEY,button_dev.evbit); //支持EV_KEY事件

set_bit(BTN_0,button_dev.keybit); //支持设备两个键

set_bit(BTN_1,button_dev.keybit); //

input_register_device(&button_dev);//注册input设备

}

/*在按键中断中报告事件*/

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

{

input_report_key(&button_dev,BTN_0,inb(BUTTON_PORT0));//读取寄存器BUTTON_PORT0的值

input_report_key(&button_dev,BTN_1,inb(BUTTON_PORT1));

input_sync(&button_dev);

}

总结:input子系统仍然是字符设备驱动程序,但是代码量减少很多,input子系统只需要完成两个工作:初始化和事件报告(这里在linux中是通过中断来实现的)。

实例

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

struct input_dev *button_dev;

struct button_irq_desc {

int irq;

int pin;

int pin_setting;

int number;

char *name;

};

/*定义一个结构体数组*/

static struct button_irq_desc button_irqs [] = {

{IRQ_EINT8 , S3C2410_GPG0 , S3C2410_GPG0_EINT8 , 0, "KEY0"},

{IRQ_EINT11, S3C2410_GPG3 , S3C2410_GPG3_EINT11 , 1, "KEY1"},

{IRQ_EINT13, S3C2410_GPG5 , S3C2410_GPG5_EINT13 , 2, "KEY2"},

{IRQ_EINT14, S3C2410_GPG6 , S3C2410_GPG6_EINT14 , 3, "KEY3"},

{IRQ_EINT15, S3C2410_GPG7 , S3C2410_GPG7_EINT15 , 4, "KEY4"},

{IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, 5, "KEY5"},

};

static int key_values = 0;

static irqreturn_t buttons_interrupt(int irq, void *dev_id)

{

struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;

int down;

udelay(0);

/*获取按键值*/

down = !s3c2410_gpio_getpin(button_irqs->pin); //down: 1(按下),0(弹起)

if (!down) {

/*报告事件*/

key_values = button_irqs->number;

//printk("====>rising key_values=%d\n",key_values);

if(key_values==0)

input_report_key(button_dev, KEY_1, 0);

if(key_values==1)

input_report_key(button_dev, KEY_2, 0);

if(key_values==2)

input_report_key(button_dev, KEY_3, 0);

if(key_values==3)

input_report_key(button_dev, KEY_4, 0);

if(key_values==4)

input_report_key(button_dev, KEY_5, 0);

if(key_values==5)

input_report_key(button_dev, KEY_6, 0);

/*报告结束*/

input_sync(button_dev);

}

else {

key_values = button_irqs->number;

//printk("====>falling key_values=%d\n",key_values);

if(key_values==0)

input_report_key(button_dev, KEY_1, 1);

if(key_values==1)

input_report_key(button_dev, KEY_2, 1);

if(key_values==2)

input_report_key(button_dev, KEY_3, 1);

if(key_values==3)

input_report_key(button_dev, KEY_4, 1);

if(key_values==4)

input_report_key(button_dev, KEY_5, 1);

if(key_values==5)

input_report_key(button_dev, KEY_6, 1);

input_sync(button_dev);

}

return IRQ_RETVAL(IRQ_HANDLED);

}

static int s3c24xx_request_irq(void)

{

int i;

int err = 0;

for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {

if (button_irqs[i].irq < 0) {

continue;

}

/* IRQ_TYPE_EDGE_FALLING,IRQ_TYPE_EDGE_RISING,IRQ_TYPE_EDGE_BOTH */

err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,

button_irqs[i].name, (void *)&button_irqs[i]);

if (err)

break;

}

/*错误处理*/

if (err) {

i--;

for (; i >= 0; i--) {

if (button_irqs[i].irq < 0) {

continue;

}

disable_irq(button_irqs[i].irq);

free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);

}

return -EBUSY;

}

return 0;

}

static int __init dev_init(void)

{

/*request irq*/

s3c24xx_request_irq();

/* Initialise input stuff */

button_dev = input_allocate_device();

if (!button_dev) {

printk(KERN_ERR "Unable to allocate the input device !!\n");

return -ENOMEM;

}

button_dev->name = "s3c2440_button";

button_dev->id.bustype = BUS_RS232;

button_dev->id.vendor = 0xDEAD;

button_dev->id.product = 0xBEEF;

button_dev->id.version = 0x0100;

button_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT(EV_SYN);

//set_bit(EV_KEY, button_dev->evbit)//支持EV_KEY事件

/*设置支持哪些按键*/

set_bit(KEY_1, button_dev->keybit);

set_bit(KEY_2, button_dev->keybit);

set_bit(KEY_3, button_dev->keybit);

set_bit(KEY_4, button_dev->keybit);

set_bit(KEY_5, button_dev->keybit);

set_bit(KEY_6, button_dev->keybit);

//printk("KEY_RESERVED=%d ,KEY_1=%d",KEY_RESERVED,KEY_1);

input_register_device(button_dev); //注册input设备

printk ("initialized\n");

return 0;

}

static void __exit dev_exit(void)

{

int i;

for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {

if (button_irqs[i].irq < 0) {

continue;

}

free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);

}

input_unregister_device(button_dev);

}

module_init(dev_init);

module_exit(dev_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("David Xie");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值