加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

android内核驱动之input输入驱动分析

(2013-04-25 11:46:03)
分类: androidinput设备

android内核驱动之input输入驱动分析  

Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反正这个是没变的,在android的底层开发中对于Linux的基本驱动程序设计还是没变的,当然Android底层机制也增加几个属于android自己的机制。 

输入子系统由 驱动层、输入子系统核心、事件处理层 三部分组成。一个输入事件,如鼠标移动、键盘按下等通过Driver->Inputcore->Event handler->userspace的顺序到达用户控件的应用程序。Android中的input设备驱动主要包括:游戏杆(joystick)、鼠标(mouse)和事件设备(Event)。

1、Input输入子系统的构架,在网上找到两幅灰常漂亮的图。

    http://img.bimg.126.net/photo/1TeCklSJocgPn7pnoTOkCA==/4539909899383022522.jpg

 

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

 

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

 

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


    下面这幅更漂亮,更直观的能看出input型输入子系统究竟是什么咚咚,更能够体现出,用户空间,内核空间,驱动程序是怎么关联起来的。。。

    http://img.bimg.126.net/photo/49zQIrojuLb2jSl5HQ5LZw==/4539909899383022523.jpg

Input驱动同样也是字符设备,主设备号是13,次设备号是64~95之间自动生成的,这个Input驱动程序那是相当相当的复杂。在android内核中主要需要关注一下几个文件

    a)include/linux/input.h(驱动头文件)

    b)driver/input/input.c (驱动核心实现,包含大量的操作接口)

   c)driver/input/event.c (event机制)

   d)driver/input/joydev.c (joystick驱动)

   e)driver/input/mousedev.c(鼠标驱动)

其实上面这些东西都不要我们自己去实现内核已经帮我们实现好了,不过我们在写硬件驱动的时候需要和Inputcore交互,所以需要用到上面这些函数中的接口,也就是说上面这些函数是透明的

2、Event事件驱动原理及其实现

+++++++++Event事件驱动原理

在内核中,用input_dev来描述一个Input设备,该结构的定义如下,其中内核中使用input_register_device(struct input_dev *dev)来注册一个input设备

这个结构体好长,所以就列了几个。。。。它的定义在input.h当中

struct input_dev {

 。。。。。。。。。。。
    struct input_id id;
    bool sync;             
 
    struct device dev;
    struct list_head    h_list; //
    struct list_head    node;  //input_handle链表的list节点
};

=======================

input_handler表示input设备的接口,使用input_register_handler(structinput_handler *handler)注册设备接口

struct input_handler {

    void *private;

。。。。。。。。。。
    int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
    void (*disconnect)(struct input_handle *handle);
    void (*start)(struct input_handle *handle);

    const struct file_operations *fops;
    int minor;
    const char *name;

    const struct input_device_id *id_table;

    struct list_head    h_list;
    struct list_head    node;
};

+++++++++Event事件驱动实现过程

1) Input设备注册

int input_register_device(struct input_dev *dev)
{
    static atomic_t input_no = ATOMIC_INIT(0);
    struct input_handler *handler;
    const char *path;
    int error;
    
    __set_bit(EV_SYN, dev->evbit);//see to inpu.h

    
    __clear_bit(KEY_RESERVED, dev->keybit);
    
    input_cleanse_bitmasks(dev);
    
    init_timer(&dev->timer);
    //处理重复按键.如果没赋值则为其赋默认的值
    if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
        dev->timer.data = (long) dev;
        dev->timer.function = input_repeat_key;
        dev->rep[REP_DELAY] = 250;
        dev->rep[REP_PERIOD] = 33;
    }
    if (!dev->getkeycode)//获取键的扫描码
        dev->getkeycode = input_default_getkeycode;
    if (!dev->setkeycode)//设置键值
        dev->setkeycode = input_default_setkeycode;
    dev_set_name(&dev->dev, "input%ld",
             (unsigned long) atomic_inc_return(&input_no) - 1);
    //将input_dev中封装的device注册到sysfs
    error = device_add(&dev->dev);
    if (error)
        return error;
    path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
    printk(KERN_INFO "input: %s as %s\n",
        dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
    kfree(path);

    error = mutex_lock_interruptible(&input_mutex);
    if (error) {
        device_del(&dev->dev);
        return error;
    }
    //将input_device挂到input_dev_list链表中
    list_add_tail(&dev->node, &input_dev_list);
    //对挂载在input_dev_list中的每一个handler调用input_attach_handler(dev, handler);
    list_for_each_entry(handler, &input_handler_list, node)
        input_attach_handler(dev, handler);
    input_wakeup_procfs_readers();
    mutex_unlock(&input_mutex);
    return 0;
}

上述函数首先将input_device挂接到input_dev_list链表上,然后对挂载在input_dev_list中的每一个handler调用input_attach_handler(dev, handler)来进行匹配,举个例子,设备模型中的device和driver的匹配,所有的input device都挂载在input_dev_list上而所有的handler都挂载在input_handler_list上,那么它们是怎么联系起来的?匹配过程如下

static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{
    const struct input_device_id *id;
    int error;
    id = input_match_device(handler, dev);
    if (!id)
        return -ENODEV;
    error = handler->connect(handler, dev, id);
    if (error && error != -ENODEV)
        printk(KERN_ERR
            "input: failed to attach handler %s to device %s, "
            "error: %d\n",
            handler->name, kobject_name(&dev->dev.kobj), error);
    return error;
}

上面函数调用input_match_device来对handler, dev通过input_device_id *id来进行匹配如果匹配成功则调用handler->connect来关联struct input_dev *dev, 和struct input_handler *handler结构。下面看看input_match_device(handler, dev)的过程

#define MATCH_BIT(bit, max) \
        for (i = 0; i < BITS_TO_LONGS(max); i++) \
            if ((id->bit & dev->bit) != id->bit) \
                break; \
        if (i != BITS_TO_LONGS(max)) \
            continue;

static const struct input_device_id *input_match_device(struct input_handler *handler,struct input_dev *dev)
{
    const struct input_device_id *id;
    int i;
    for (id = handler->id_table; id->flags || id->driver_info; id++) {//flags配置匹配的类型
        if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)//匹配总线类型
            if (id->bustype != dev->id.bustype)
               continue;
        if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)//匹配厂商
            if (id->vendor != dev->id.vendor)
                continue;
        if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)//匹配制造商
            if (id->product != dev->id.product)
                continue;
        if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)//匹配版本号
            if (id->version != dev->id.version)
                continue;
      //如果上面的id->flags匹配成功或者是id->flags没有定义则执行下面的函数
        MATCH_BIT(evbit,  EV_MAX);
        MATCH_BIT(keybit, KEY_MAX);
        MATCH_BIT(relbit, REL_MAX);
        MATCH_BIT(absbit, ABS_MAX);
        MATCH_BIT(mscbit, MSC_MAX);
        MATCH_BIT(ledbit, LED_MAX);
        MATCH_BIT(sndbit, SND_MAX);
        MATCH_BIT(ffbit,  FF_MAX);
        MATCH_BIT(swbit,  SW_MAX);
        if (!handler->match || handler->match(handler, dev))
            return id;
    }
    return NULL;
}

 

驱动层只是把输入设备注册到输入子系统中,驱动层的代码本身是没有创建设备节点的,而是由EventHander层调用InputCore中的函数来实现,当某个事件触发时都将通过input _event()来将input event传送到input.c中,再由input.c分配事件到每一个"input handler"

2)input _event是怎么实现的

void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)
{
    unsigned long flags;
    if (is_event_supported(type, dev->evbit, EV_MAX)) {
        spin_lock_irqsave(&dev->event_lock, flags);
        add_input_randomness(type, code, value);
        input_handle_event(dev, type, code, value);
        spin_unlock_irqrestore(&dev->event_lock, flags);
    }
}

static void input_handle_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)
{
    int disposition = INPUT_IGNORE_EVENT;
    switch (type) {
    case EV_SYN:
        switch (code) {
        case SYN_CONFIG:
            disposition = INPUT_PASS_TO_ALL;
            break;
        case SYN_REPORT:
            if (!dev->sync) {
                dev->sync = true;
                disposition = INPUT_PASS_TO_HANDLERS;
            }
            break;
        case SYN_MT_REPORT:
            dev->sync = false;
            disposition = INPUT_PASS_TO_HANDLERS;
            break;
        }
        break;
    case EV_KEY:
        if (is_event_supported(code, dev->keybit, KEY_MAX) &&
            !!test_bit(code, dev->key) != value) {
            if (value != 2) {
                __change_bit(code, dev->key);
                if (value)
                    input_start_autorepeat(dev, code);
                else
                    input_stop_autorepeat(dev);
            }
            disposition = INPUT_PASS_TO_HANDLERS;
        }
        break;
    case EV_SW:
        if (is_event_supported(code, dev->swbit, SW_MAX) &&
            !!test_bit(code, dev->sw) != value) {
            __change_bit(code, dev->sw);
            disposition = INPUT_PASS_TO_HANDLERS;
        }
        break;

    case EV_ABS:
        if (is_event_supported(code, dev->absbit, ABS_MAX))
            disposition = input_handle_abs_event(dev, code, &value);
        break;
    case EV_REL:
        if (is_event_supported(code, dev->relbit, REL_MAX) && value)
            disposition = INPUT_PASS_TO_HANDLERS;
        break;
    case EV_MSC:
        if (is_event_supported(code, dev->mscbit, MSC_MAX))
            disposition = INPUT_PASS_TO_ALL;
        break;
    case EV_LED:
        if (is_event_supported(code, dev->ledbit, LED_MAX) &&
            !!test_bit(code, dev->led) != value) {
            __change_bit(code, dev->led);
            disposition = INPUT_PASS_TO_ALL;
        }
        break;
    case EV_SND:
        if (is_event_supported(code, dev->sndbit, SND_MAX)) {
            if (!!test_bit(code, dev->snd) != !!value)
                __change_bit(code, dev->snd);
            disposition = INPUT_PASS_TO_ALL;
        }
        break;
    case EV_REP:
        if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
            dev->rep[code] = value;
            disposition = INPUT_PASS_TO_ALL;
        }
        break;
    case EV_FF:
        if (value >= 0)
            disposition = INPUT_PASS_TO_ALL;
        break;
    case EV_PWR:
        disposition = INPUT_PASS_TO_ALL;
        break;
    }
    if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
        dev->sync = false;
    if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
        dev->event(dev, type, code, value);
    if (disposition & INPUT_PASS_TO_HANDLERS)
        input_pass_event(dev, type, code, value);
}

============================================

实例解剖:

实际上,上述的很多函数都是输入子系统的原始函数,都位于input.c文件中,然而实际使用的时候,会使用二次封装后的函数:如input_reprot_abs(坐标)input_report_key(按键)input_sync(用于报告输入子系统报告已结束),他们底层都由input_event处理。

第一步:初始化input设备,并分配空间。input_allocate_device

第二步:设置按键的类型和所支持的键及事件类型等,从include/linux/input.h中可以查询相关的宏!

 

__set_bit()告诉input输入子系统支持哪些事件,哪些按键。例如:

__set_bit(EV_KEY,button_dev.evbit)  (其中button_devstruct input_dev类型)


struct input_dev中有两个成员为:

evbit:

事件类型(包括

EV_RST,EV_REL,EV_MSC,EV_KEY,EV_ABS,EV_REP等)

keybit:

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


第三步: 设置设备值,填充信息

 
 button_dev->name = "buttons_yzx";
 
 button_dev->dev.init_name = "input_yzx";
 
 
 button_dev->open = button_open;
 button_dev->close = button_close;
 
 printk("input device has allocated/n");
 
 
 error = input_register_device(button_dev);


第四步: 注册设备,input_register_device

第五步: 事件上报,input_event。


 

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

//按键初始化

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);

}

=========================

补充,关于上层如何调用底层的驱动,一般会在文件系统/dev/下产生相应的设备。然后当作文件操作。

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

操作设备: read / write

关闭设备: close


至于设备文件如何产生,待继续深入 ???  mknod  ? 51  125  产生字符设备 ? 还是编译产生设备 ?

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有