天天看点

Android中Input型输入设备驱动原理分析(一)

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

Android中的input设备驱动主要包括:游戏杆(joystick)、鼠标(mouse)和事件设备(Event)。

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

Android中Input型输入设备驱动原理分析(一)

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

Android中Input型输入设备驱动原理分析(一)

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事件驱动原理及其实现

在内核中,用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[i] & dev->bit[i]) != id->bit[i]) \

                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;

}

其中handler的注册和上述类似,感兴趣的朋友可以读linux内核源码

继续阅读