input输入子系统

推荐一款app应用——"印度爱经",木蚂蚁下载点击打开链接

输入子系统核心linux-2.6.29\drivers\input\input.c



1、输入子系统核心初始化
input_init
    //注册了主设备号为13字符设备,fops为input_fops。app调用open打开设备时会调用input_fops.open
    register_chrdev    
    
2、输入子系统核向外提供了函数接口
input_register_device
input_register_handler
input_register_handle
input_event

2.1 input_register_handler向系统注册处理者
input_register_handler
    input_table[handler->minor >> 5] = handler//将每一个注册的handler放入input_table数组(最多支持8个)
    list_add_tail//将每一个注册的handler插入input_handler_list链表的尾部
    list_for_each_entry(dev, &input_dev_list, node)//遍历input_dev_list链表的每一个dev
        input_attach_handler(dev, handler);
        
2.2 input_register_device向系统注册输入设备
input_register_device
    __set_bit(EV_SYN, dev->evbit);//设备支持SYN事件
    list_add_tail(&dev->node, &input_dev_list);//将每一个注册的dev插入input_dev_list链表的尾部
    list_for_each_entry(handler, &input_handler_list, node)//遍历input_handler_list链表的每一个handler
        input_attach_handler(dev, handler);
    
2.3    分析input_attach_handler
handler->blacklist && input_match_device(handler->blacklist, dev)//查看设备是否是handler->blacklist指定需要忽略的设备
    input_match_device//匹配dev和handler中的id
        //从MATCH_BIT宏的定义可以看出。只有当iput device和input handler的ID成员在evbit、keybit、
        //… swbit项相同才会匹配成功。而且匹配的顺序是从evbit、keybit到swbit。只要有一项不同,
        //就会循环到ID中的下一项进行比较。
        MATCH_BIT(evbit,  EV_MAX);//展开如下:
        #define MATCH_BIT(evbit,  EV_MAX) \
        for (i = 0; i < BITS_TO_LONGS(EV_MAX); i++) \
            if ((id->evbit[i] & dev->evbit[i]) != id->evbit[i]) \
                break; \
        if (i != BITS_TO_LONGS(EV_MAX)) \
            continue;
    handler->connect(handler, dev, id);//调用handler中的connect函数
    
2.4 向子系统上报事件linux-2.6.29\include\linux\input.h
    input_report_key
    input_report_rel
    input_report_abs
    input_report_ff_status
    input_report_switch
    input_sync
        input_event
            is_event_supported(type, dev->evbit, EV_MAX)//判断dev是否支持type事件
            input_handle_event
                if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)//调用dev->event
                    dev->event(dev, type, code, value);
                input_pass_event//参考<linux驱动开发入门与实战>327页
                    //调用所有打开的handler->event(一个dev可能对应多个handler)
                    list_for_each_entry_rcu(handle, &dev->h_list, d_node)
                        if (handle->open)//4.4中设置了打开标记
                            handle->handler->event(handle, type, code, value);
    
3、app调用open打开设备时会调用input_fops.open
input_open_file
    handler = input_table[iminor(inode) >> 5];//在此input_table数组中根据此设备号,找到对应的handler
    old_fops = file->f_op;//偷龙转凤换掉了主设备号13所对应的file_operations
    file->f_op = new_fops;
    new_fops->open(inode, file);//调用具体handler的open函数
    
4、实例分析drivers\input\mousedev.c和drivers\hid\usbhid\usbmouse.c
4.1 usb_mouse_init
        usb_register(&usb_mouse_driver);//注册mouse驱动
            usb_mouse_probe//当mouse设备接入usb会在usb总线上查找匹配的驱动,并调用驱动的probe
                input_register_device//先初始化input_dev,再向input子系统注册input_dev,并寻找匹配的handler
                usb_mouse_irq//urb完成处理函数,判断urb状态,上报事件
                    input_report_key//参考2.4会调用相对应的handler->event
                    input_report_rel
                        mousedev_event//很多具体主要的工作在这里完成
                            mousedev_touchpad_touch
                                mousedev_notify_readers//唤醒在队列mousedev->wait上面的等待

4.2 mousedev_init
    input_register_handler(&mousedev_handler);//注册handler,并寻找匹配的dev

4.3 根据2.3匹配成功,调用handler->connect
    mousedev_create//创建了结构体struct mousedev,建立input_dev和handler的handle被封装在struct mousedev中
        input_register_handle//input_handler.h_list指向handle->h_node
            list_add_tail_rcu(&handle->d_node, &dev->h_list);//handle->d_node添加到链表input_dev->h_list尾部(此链表在2.4中会使用)
            list_add_tail(&handle->h_node, &handler->h_list);//handle->h_node添加到链表handler->h_list尾部
        dev_set_name(&mousedev->dev, mousedev->name);//创建设备节点
        device_add(&mousedev->dev);    
    mixdev_add_device
        list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);添加mousedev->mixdev_node到链表mousedev_mix_list
    
4.4 app打开设备节点时,根据3会调用mousedev_open
    mousedev_open
        mousedev_open_device
            input_open_device
                handle->open++;//增加每一个handle的打开标记,2.4中会用到
                dev->open(dev);//调用相对应的input_dev的open函数
                    usb_mouse_open//usbmouse.c中
                        usb_submit_urb//提交urb,调用4.1中的urb完成处理函数usb_mouse_irq
                        
4.5 app读设备节点,根据3中的偷龙转凤会调用具体handler的read
    mousedev_read
        wait_event_interruptible//在mousedev->wait队列上等待,它被4.1中上报事件唤醒
    
                        
    
struct input_device_id {

    kernel_ulong_t flags;//定义要匹配的项

    __u16 bustype;/*总线类型*/
    __u16 vendor;/*制造商ID*/
    __u16 product;/*产品ID*/
    __u16 version;/*版本号*/

    kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];

    kernel_ulong_t driver_info;/*驱动额外的信息*/
};    
    
    
struct input_handler {
    void *private;
    
    void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
    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;//可以处理那些设备
    const struct input_device_id *blacklist;//忽略那些设备的处理

    struct list_head    h_list;//指向将input_handler和input_dev建立联系的input_handle的h_node
    struct list_head    node;//指向下一个input_handler.node
};

所有时间类型:
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 /*电源管理事件*/


struct input_dev {
    const char *name;
    const char *phys;
    const char *uniq;
    struct input_id id;

    unsigned long evbit[BITS_TO_LONGS(EV_CNT)];// 表示能产生哪类事件
    unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];// 表示能产生哪些按键
    unsigned long relbit[BITS_TO_LONGS(REL_CNT)];// 表示能产生哪些相对位移事件, x,y,滚轮
    unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];// 表示能产生哪些绝对位移事件, x,y
    unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
    unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
    unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
    unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
    unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

    unsigned int keycodemax;
    unsigned int keycodesize;
    void *keycode;
    int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
    int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);

    struct ff_device *ff;

    unsigned int repeat_key;
    struct timer_list timer;

    int sync;

    int abs[ABS_MAX + 1];
    int rep[REP_MAX + 1];

    unsigned long key[BITS_TO_LONGS(KEY_CNT)];
    unsigned long led[BITS_TO_LONGS(LED_CNT)];
    unsigned long snd[BITS_TO_LONGS(SND_CNT)];
    unsigned long sw[BITS_TO_LONGS(SW_CNT)];

    int absmax[ABS_MAX + 1];
    int absmin[ABS_MAX + 1];
    int absfuzz[ABS_MAX + 1];
    int absflat[ABS_MAX + 1];

    int (*open)(struct input_dev *dev);
    void (*close)(struct input_dev *dev);
    int (*flush)(struct input_dev *dev, struct file *file);
    int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);

    struct input_handle *grab;

    spinlock_t event_lock;
    struct mutex mutex;

    unsigned int users;
    int going_away;

    struct device dev;

    struct list_head    h_list;//指向将input_handler和input_dev建立联系的input_handle的d_node
    struct list_head    node;//指向下一个input_dev.node
};

你可能感兴趣的:(input输入子系统)