Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1795471
  • 博文数量: 306
  • 博客积分: 3133
  • 博客等级: 中校
  • 技术积分: 3932
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-19 16:50
文章分类

全部博文(306)

文章存档

2018年(7)

2017年(18)

2016年(39)

2015年(35)

2014年(52)

2013年(39)

2012年(22)

2011年(29)

2010年(53)

2009年(12)

分类: LINUX

2011-07-20 14:15:03

输入子系统

linux系统提供了input子系统,按键,触摸屏,鼠标等输入型设备都可以利用input接口函数来实现设备驱动。

体系结构--

输入子系统由驱动层输入子系统核心层(input core)和事件处理层(event handler)三部分组成。一个输入事件,如鼠标移动,键盘按键按下,通过driver->inputcore->event handler->userspace的顺序到达用户空间的应用程序。

驱动层---

将底层的硬件输入转化为统一事件形式,向输入核心回报。


输入核心层---

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


事件处理层---

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


在 linux内核中,input设备用input_dev结构体描述,使用input子系统实现输入设备驱动的时候,驱动的核心工作是向系统报告按键,触摸 屏,键盘,鼠标,等输入事件(event,通过input_event结构体描述),不再需要关心文件操作接口,因为input子系统已经完成了文件操作 接口。驱动报告的事件经过inpoutcore和eventhandler最终到达用户空间。


struct input_dev {
    const char *name;
    const char *phys;
    const char *uniq;
    struct input_id id;

    unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
    unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
    unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
    unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
    unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
    unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
    unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
    unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
    unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

    unsigned int keycodemax;
    unsigned int keycodesize;
    void *keycode;
    int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
    int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);

    struct ff_device *ff;

    unsigned int repeat_key;
    struct timer_list timer;

    int sync;

    int abs[ABS_MAX + 1];
    int rep[REP_MAX + 1];

    unsigned long key[BITS_TO_LONGS(KEY_CNT)];
    unsigned long led[BITS_TO_LONGS(LED_CNT)];
    unsigned long snd[BITS_TO_LONGS(SND_CNT)];
    unsigned long sw[BITS_TO_LONGS(SW_CNT)];

    int absmax[ABS_MAX + 1];
    int absmin[ABS_MAX + 1];
    int absfuzz[ABS_MAX + 1];
    int absflat[ABS_MAX + 1];

    int (*open)(struct input_dev *dev);
    void (*close)(struct input_dev *dev);
    int (*flush)(struct input_dev *dev, struct file *file);
    int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);

    struct input_handle *grab;

    spinlock_t event_lock;
    struct mutex mutex;

    unsigned int users;
    int going_away;

    struct device dev;

    struct list_head    h_list;
    struct list_head    node;
};


注册,注销输入设备的函数---

int input_register_device(struct input_dev *dev)

int input_unregister_device(struct input_dev *dev)


驱动实现-----事件支持

设备驱动通过set_bit()告诉input子系统它支持哪些事件,哪些按键。例如:

set_bit(EV_KEY,button_dev.evbit)

struct input_dev中的两个成员:

evbit--事件类型

keybit--按键类型


事件类型:

EV_RST--reset

EV_REL--相对坐标

EV_MSC--其它

EV_SND--声音

EV_FF--力反馈

EV_KEY--按键

EV_ABS--绝对坐标

EV_LED--led

EV_REP--repeat


当事件类型为EV_KEY时,还需指明按键类型:

BTN_LEFT--鼠标左键

BTN_RIGHT--鼠标右键

BTN_MIDDLE--鼠标中键

BTN_0--数字0键

BTN_1--数字1键


用于报告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)


struct input_event {
    struct timeval time;
    __u16 type;
    __u16 code;
    __s32 value;
};


code--

事件的代码。如果事件类型是EV_KEY,该代码则为设备的键盘代码。例如:键盘上的按键代码值为0--127,鼠标按键代码为0x110---0x116,其中0x110(BTN_LEFT)为鼠标左键,0x111(BTN_RIGHT)为鼠标左键,其它代码含义参考include/linux/input.h文件。

value--

事件的值。若事件的类型是EV_KEY,当按键按下时值为1,松开值为0

input_sync()用于告诉input core:此次报告已结束。

实例:

在触摸屏设备驱动中,一次点击的整个报告过程如下:

input_report_abs(input_dev,ABS_X,x)

input_report_abs(input_dev,ABS_Y,x)

input_report_abs(input_dev,ABS_PRESSURE,1)

input_sync(input_dev)


实例分析==

在按键中断中报告事件---

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

{

input_report_key(&button_dev,BTN_0,inb(BUTTON_PORT0));

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

input_sync(&button_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设备


}




 应用程序--

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

int main(void)
{
    int buttons_fd;
    int key_value,i=0,count;

    struct input_event ev_key;

    buttons_fd = open("/dev/event0", 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,ev_key.value);

            if(EV_SYN==ev_key.type)
                printf("syn event\n\n");
    }

    close(buttons_fd);
    return 0;
}
阅读(1707) | 评论(0) | 转发(1) |
0

上一篇:SQLite

下一篇:gcc 编译内存控制

给主人留下些什么吧!~~