zoukankan      html  css  js  c++  java
  • linux 输入子系统(2)----简单实例分析系统结构(input_dev层)

    实例代码如下:

    #include <linux/input.h>
    #include <linux/module.h>
    #include <linux/init.h>
     
    #include <asm/irq.h>
    #include <asm/io.h>
    
    #define BUTTON_IRQ 123
    static struct input_dev *button_dev ;/*输入设备结构体*/
    static irqreturn_t button_interrupt(int irq, void *dummy)  /*中断处理函数*/
    {
        input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1);/*向输入子系统报告产生按键事件*/   ===========》》》》》【3】
        input_sync(button_dev);/*通知接受者,一个报告发送完毕*/
        return IRQ_HANDLED;
    }
     
    static int __init button_init(void)
    {
        int error;
        if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {   /*申请中断*/
                    printk(KERN_ERR "button.c: Can't allocate irq %d
    ", BUTTON_IRQ);
                    return -EBUSY;
          }
         button_dev=input_allocate_device();/*分配一个设备结构体*/  ===========》》》》》》【1】
        if(!button_dev)
            {
                printk(KERN_ERR"button.c:Not enough memory
    ");
                error= -ENOMEM;
                goto err_free_irq;
            }
        button_dev.evbit[0] = BIT_MASK(EV_KEY);/*设置按键信息*/    设置输入设备所支持的事件类型
        button_dev.keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
     
        error=input_register_device(button_dev);/*注册一个输入设备*/ ===========》》》》》》【2】
        if(error)
            {
                printk(KERN_ERR"failed to register device
    ");
                goto err_free_dev;
            }
        return 0;
        
        err_free_dev:
            input_free_device(button_dev);
        err_free_irq:
            free_irq(BUTTON_IRQ,button_interrupt);
        return error;
    }
     
    static void __exit button_exit(void)
    {
            input_unregister_device(button_dev);/*注销按键设备*/
            free_irq(BUTTON_IRQ, button_interrupt);/*释放按键占用的中断*/
    }
     
    module_init(button_init);
    module_exit(button_exit);

    【1】input_allocate_device()函数分配一个input_dev结构体,输入设备用input_dev结构体描述。
    struct input_dev *input_allocate_device(void)
    {
        struct input_dev *dev;
    
        dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);/*分配一个input_dev结构体,并初始化为0*/
        if (dev) {
            dev->dev.type = &input_dev_type;/*初始化设备类型*/
            dev->dev.class = &input_class;/*设置为输入设备类*/
            device_initialize(&dev->dev);/*初始化device结构*/
            mutex_init(&dev->mutex);/*初始化互斥锁*/
            spin_lock_init(&dev->event_lock);/*初始化事件自旋锁*/
            INIT_LIST_HEAD(&dev->h_list);/*初始化链表*/
            INIT_LIST_HEAD(&dev->node);/*初始化链表*/
    
            __module_get(THIS_MODULE);
        }
    
        return dev;
    }

      【2】input_register_device()将input_dev结构体注册到输入子系统核心中。

    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;
    
        /* Every input device generates EV_SYN/SYN_REPORT events. */
        __set_bit(EV_SYN, dev->evbit);/*设置input_dev所支持的事件类型,由input_dev的evbit成员来表示*/
    
        /* KEY_RESERVED is not supposed to be transmitted to userspace. */
        __clear_bit(KEY_RESERVED, dev->keybit);
    
        /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
        input_cleanse_bitmasks(dev);
    
        /*
         * If delay and period are pre-set by the driver, then autorepeating
         * is handled by the driver itself and we don't do it in input.c.
         */
        init_timer(&dev->timer);/*初始化一个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 的名字,以input0/1/2出现在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
    ",
            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;
        }
    
        list_add_tail(&dev->node, &input_dev_list);/*加入链表*/
    
        list_for_each_entry(handler, &input_handler_list, node)
            input_attach_handler(dev, handler);/*调用input_attach_handler来匹配input_dev和handler*/===========》》》》》》【2.1】
    
        input_wakeup_procfs_readers();
    
        mutex_unlock(&input_mutex);
    
        return 0;
    }
      其中input_dev所支持的事件类型在include/linux/input.h中定义,如下:
     
     【2.1】input_attach_handler()
    匹配input_dev和handler。
    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);/*handler 与dev之间的匹配*/
        if (!id)
            return -ENODEV;
    
        error = handler->connect(handler, dev, id);/*匹配成功,则调用connect将handler与dev连接起来*/
        if (error && error != -ENODEV)
            printk(KERN_ERR
                "input: failed to attach handler %s to device %s, "
                "error: %d
    ",
                handler->name, kobject_name(&dev->dev.kobj), error);
    
        return error;
    }

    总结【2】:注册input device 就是为input device 设置默认值,并将其挂接到input_dev_list中,并且与挂载在input_handler_list中的handler相匹配,如果匹配成功,则调用connect。

    【3】input_report_key()向输入子系统报告发生的事件:

    static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
    {
        input_event(dev, EV_KEY, code, !!value);
    }
    input_event()报告指定type、value的输入事件:
    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);
        }
    }
     
  • 相关阅读:
    做SQL解析时遇到的问题
    SqlAnalyzer1.00源码
    用于测试SqlAnalyzer1.00的十七个测试用例
    XmlAnalyzer1.00 源码
    用于测试XmlAnalyzer 1.00版的八个测试用例
    JsonAnalyzer2 1.01版
    用于测试 JsonAnalyzer2 1.01版的测试用例
    按照BNF语法重新写就的JsonAnalyzer2
    递归向下解析算术表达式(四)
    允许Sublime编辑器在Ubuntu上输入中文
  • 原文地址:https://www.cnblogs.com/hello2mhb/p/3366628.html
Copyright © 2011-2022 走看看