input_register_device()浅析


/**
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
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值