Linux驱动之输入子系统

一. 概述

1. 输入子系统的概念

   输入子系统是对分散的、多种不同类别的输入设备(键盘、鼠标、触摸屏、加速计、跟踪球、操纵杆等)进行统一处理的驱动程序。

2. 输入子系统的优点

    抽象底层形态各异的硬件(鼠标,键盘,触摸屏,游戏杆等)输入设备,为上层提供了统一的操作接口。

二. 输入子系统的分层结构

1.三层结构

事件驱动层:负责和应用程序的接口。
核心层:   提供事件驱动层和设备驱动层所需的函数接口
设备驱动层:负责和底层设备驱动通信

2.层次框架图

这里写图片描述

三. 设备驱动

1. 设备驱动的数据结构

对于系统的每个输入设备硬件,在输入子系统都要实现一个设备驱动。每个设备驱动都由input_dev的数据结构描述,部分成员定义如:
    struct input_dev{
            const char *name;
            const char *phys;
            const char *uniq;
            struct input_id id;
            unsigned longevbit[BITS_TO_LONGS(EV_CNT)];
            unsigned longkeybit[BITS_TO_LONGS(KEY_CNT)];
}

name: 该成员的设备驱动名字。但与对于的设备文件名无任何关系。
id : 该成员的输入设备身份。
evbit :该成员会产生的输入事件类型。事件类型定义如下:

1.  #define EV_SYN          0x00    /*表示设备支持所有的事件*/  
2.  #define EV_KEY          0x01    /*键盘或者按键,表示一个键码*/  
3.  #define EV_REL          0x02    /*鼠标设备,表示一个相对的光标位置结果*/  
4.  #define EV_ABS          0x03    /*手写板产生的值,其是一个绝对整数值*/  
5.  #define EV_MSC          0x04    /*其他类型*/  
6.  #define EV_LED          0x11    /*LED灯设备*/  
7.  #define EV_SND          0x12    /*蜂鸣器,输入声音*/  
8.  #define EV_REP          0x14    /*允许重复按键类型*/  
9.  #define EV_PWR          0x16    /*电源管理事件*/ 

把指定的位置1,可以使用set_bit()函数:
set_bit( EV_KEY, input_dev->evbit);

keybit : 当设备驱动可以产生按键事件时,keybit成员表示设备驱动支持按键的键值。键值的定义:

    #define     KEY_RESERVED    0
    #define     KEY_ESC         1
    #define     KEY_1           2
    #define     KEY_2           3
    ......

2. 注册/注销设备驱动

当一个input_dev结构体被初始化完成后,就可以调用input_register_device()函数注册到输入子系统:

int input_register_device(struct input_dev *);
注销:
void input_unregister_device(struct input_dev *);

3. 报告按键值

void input_report_key(struct input_dev*dev,unsigned int code,int value);
value : 1为按下,0为提起;

4. 提交同步事件,防止数据混乱

void input_sync(struct input_dev *dev);

四. 驱动实现

1. 驱动函数event_drv.c

/*
 *   event_drv.c
 *
 *   Program:   Key input event 
 *
 *   Author:  Lin Xubin
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/input.h>
#include <linux/interrupt.h>

struct input_dev *key_event_dev;

typedef struct 
{
    int irq;
    char *devname;
    unsigned int gpio_pin;
    unsigned int key_val;   
}KeyEvent_TypeDef;

KeyEvent_TypeDef KeyEvent[4]={
        {IRQ_EINT0,  "S2", S3C2410_GPF0,  KEY_A},
        {IRQ_EINT2,  "S3", S3C2410_GPF2,  KEY_B},
        {IRQ_EINT11, "S4", S3C2410_GPG3,  KEY_C},
        {IRQ_EINT19, "S5", S3C2410_GPG11, KEY_D},
};

static irqreturn_t key_drv_irq(int irq,void *dev_id)
{   
    KeyEvent_TypeDef *KeyPin = (KeyEvent_TypeDef *)dev_id;
    static int PinState;
    PinState = s3c2410_gpio_getpin(KeyPin->gpio_pin);

    if(PinState)
    {
        input_event(key_event_dev, EV_KEY, KeyPin->key_val, 1);
        input_sync(key_event_dev);
    }
    else
    {
        input_event(key_event_dev, EV_KEY, KeyPin->key_val, 0);
        input_sync(key_event_dev);
    }   
    return IRQ_RETVAL(IRQ_HANDLED);
}

int key_drv_init(void)
{
    int i;
    key_event_dev = input_allocate_device();  //分配input_dev结构体

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

    for(i=0; i<4; i++)
    {
        set_bit(KeyEvent[i].key_val , key_event_dev->keybit);
    }
    input_register_device(key_event_dev);   //注册input事件

    for(i=0; i<4; i++)
    {
        request_irq(KeyEvent[i].irq , key_drv_irq, IRQT_BOTHEDGE, KeyEvent[i].devname, &KeyEvent[i]);
    }   
    return 0;
}

void key_drv_exit(void)
{
    int i;
    for(i=0; i<4; i++)
    {
        free_irq(KeyEvent[i].irq, &KeyEvent[i]);
    }
    input_unregister_device(key_event_dev);
    input_free_device(key_event_dev);
}

module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");

2. 应用测试程序 event_drv_test.c

/*
 *   event_drv_test.c
 *
 *   Author: Lin Xubin
 */

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

int main(char argc, char *argv[])
{
    int fd,val;
    struct input_event key_event_val;
    fd = open("/dev/event1", O_RDWR);
    if(fd < 0)
    {
        printf("open device failed\n");
        return 0;
    }
    while(1)
    {
        val = read(fd,&key_event_val, sizeof(struct input_event));
        if( val < 0)
        {
            printf("read input err\n");
            return 0;
        }
        switch(val) 
        printf("%d,%d,%d\n", key_event_val.type, key_event_val.code, key_event_val.value);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值