input_register_device()浅析

来源:互联网 发布:mac怎么玩英雄杀 编辑:程序博客网 时间:2024/05/19 19:58
/**input系统中,分为:                    设备驱动层                    核心层                    事件处理层    将 input_dev结构体(表示一个输入设备) 注册到 核心层.    注意:            1: 这个input_dev必需由input_allocate_device()函数来分配            2:  input_register_device()如果注册失败,必需调用input_free_device()来释放分配的空间            3:  如果注册成功,在卸载函数中应该调用input_unregister_device()来注销input_dev            input_dev = input_allocate_device();            if (!input_dev)            {                ret = -ENOMEM;                return ret;            }            .....            .....            ret = input_register_device(input_dev);            if (ret) {                printk("ts-if: Could not register input device(touchscreen)!\n");                input_free_device(input_dev);                return ret;            }    成功 : 返回 0     失败 : 返回非0值        */int input_register_device(struct input_dev * dev){    /**        为生成设备节点序号做准备。        下面的代码会调用dev_set_name()来设置设备节点的名字        会在sysfs系统中以input0、input1、input2.....出现    */    static atomic_t input_no = ATOMIC_INIT(0);    struct input_handler * handler;    const char *path;    /**        struct input_dev         {            ...            设备支持的事件类型            每一个事件的类型都用一个位来表示            如果某一位被置 1 ,表示该设备支持这类事件                      被值 0 ,表示该设备不支持这类事件            unsigned long evbit[BITS_TO_LONGS(EV_CNT)];        }       */    /*        将evbit的第0位置1 表示支持所有的事件      */    __set_bit(EV_SYN,dev->evbit);    /**        如果驱动预先设置了延时,自动重复被驱动处理,        核心层就不做这件事了    */    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;    }    /**        检查getkeycode函数有没有被定义。        如果没有定义,则使用默认的input_default_getkeycode.    */    if (!dev->getkeycode)        dev->getkeycode = input_default_getkeycode;//得到指定的键值    /**        检查setkeycode函数有没有被定义。        如果没有定义,则使用默认的input_default_setkeycode.    */    if (!dev->setkeycode)        dev->setkeycode = input_default_setkeycode;//设置键值    //设置input_dev中的device的名字    dev_set_name(&dev->dev, "input%ld",             (unsigned long) atomic_inc_return(&input_no) - 1);    /**        任何一个设备的注册都会经过这个函数,设备驱动模型中的核心函数    */               error = device_add(&dev->dev);    if (error)    {        return error;    }    /**        生成并返回设备的路径,调用者必需使用kfree()来释放结果        因为它的代码中有path = kzalloc(len, gfp_mask);    */    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);    /**        获取锁---访问临界区---释放锁        获取互斥锁且可以被信号打断,当正在等待锁的时信号到来了会返回EINTR    */    error = mutex_lock_interruptible(&input_mutex);    if (error) {        device_del(&dev->dev);        return error;    }    /**        input_dev维护了两条链表            1 : input_dev_list链表,该链表包含了系统中所有的input_dev。            2 : input_handle_list链表        将input_dev添加到input_dev_list链表       */    list_add_tail(&dev->node, &input_dev_list);    /**        遍历input_handler链表上,对链表中的每一个input_handler执行        input_attach_handler函数    */    list_for_each_entry(handler, &input_handler_list, node)    {        /**            匹配input_dev和input_handler。下面讲解。        */        input_attach_handler(dev, handler);     }    /**        当用户层调用poll()系统调用的时候,  input_proc_devices_poll函数会被调用         static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait){    poll_wait(file, &input_devices_poll_wait, wait);    ...    return 0;}                                                       唤醒读等待队列input_devices_poll_wait    */    input_wakeup_procfs_readers();    //释放互斥锁    mutex_unlock(&input_mutex);    return 0;}/**    用于匹配input_dev和input_handler    匹配成功的关键是 :                     handler中的blacklist、id_table    如果匹配成功,会调用handler的connect函数             */static int input_attach_handler(struct input_dev *dev, struct input_handler *handler){    /**        //设备的标识,存储了设备的信息        struct input_device_id        {            kernel_ulong_t flags;//要匹配的项            设备中的这些信息将要和input_handler中的id_table中定义的进行匹配            __u16 bustype;   //总线类型            __u16 vendor;    //制造商ID                __u16 product;   //产品ID            __u16 version;   //版本号            ....            ...        }           */    const struct input_device_id * id;    int error;    id = input_match_device(handler,dev);       if(!id)    {        return -ENODEV;    }    /**        一下是匹配成功后要执行的。        调用handler的connect函数    */    err = handler->connect(handler,dev,id);    if(error && error != -ENODEV)    {        pr_err("failed to attach handler %s to device %s, error: %d\n",               handler->name, kobject_name(&dev->dev.kobj), error);    }    return error;}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;    /**        id_table 表示驱动支持的设备列表        id_table的出现,让一个handler支持多个input_dev变成了可能。        evdev支持所有的设备        static const struct input_device_id evdev_ids[] = {            { .driver_info = 1 },    //匹配所有的设备            { },                    };        keyboard支持的设备        static const struct input_device_id kbd_ids[] = {            {   //比较evbit                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,                .evbit = { BIT_MASK(EV_KEY) },//只要能产生按键类事件,就支持            },            {                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,                .evbit = { BIT_MASK(EV_SND) },//主要能产生声音就支持            },            { },          };*/    for (id = handler->id_table; id->flags || id->driver_info; id++) {        //匹配总线类型        if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)            //如果id_table[i]中支持的总线类型 与设备的标识中的总线类型不相符            //就比较id_table[i+1]项            if (id->bustype != dev->id.bustype)                continue;        //匹配制造商id        if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)            if (id->vendor != dev->id.vendor)                continue;        //匹配产品id        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;        //这个宏 没有看明白         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;}       static bool joydev_match(struct input_handler *handler, struct input_dev *dev){    /**        evbit:设备支持哪些事件        EV_KEY : 0x01        evbit 是long类型             第0位被置1,表示支持所有事件。        某一位置1表示支持该事件        某一位为0标识不支持该事件        test_bit(EV_KEY, dev->evbit) : 测试是否支持按键类事件        test_bit(BTN_TOUCH, dev->keybit)测试是否支持按键类事件中是否支持触摸      */    if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))        return false;    .....    return true;}
0 0
原创粉丝点击