zoukankan      html  css  js  c++  java
  • input子系统

    drivers/input/input.c:
    input_init > err = register_chrdev(INPUT_MAJOR, "input", &input_fops);

    static const struct file_operations input_fops = {
    .owner = THIS_MODULE,
    .open = input_open_file,
    };

    问:怎么读按键?

    input_open_file
    struct input_handler *handler = input_table[iminor(inode) >> 5];
    new_fops = fops_get(handler->fops) // =>&evdev_fops
    file->f_op = new_fops;
    err = new_fops->open(inode, file);

    app: read > ... > file->f_op->read

    input_table数组由谁构造?

    input_register_handler

    注册input_handler:
    input_register_handler
    // 放入数组
    input_table[handler->minor >> 5] = handler;

    // 放入链表
    list_add_tail(&handler->node, &input_handler_list);
    
    // 对于每个input_dev,调用input_attach_handler
    list_for_each_entry(dev, &input_dev_list, node)
    	input_attach_handler(dev, handler); // 根据input_handler的id_table判断能否支持这个input_dev
    

    注册输入设备:
    input_register_device
    // 放入链表
    list_add_tail(&dev->node, &input_dev_list);

    // 对于每一个input_handler,都调用input_attach_handler
    list_for_each_entry(handler, &input_handler_list, node)
    	input_attach_handler(dev, handler); // 根据input_handler的id_table判断能否支持这个input_dev
    

    input_attach_handler
    id = input_match_device(handler->id_table, dev);

    error = handler->connect(handler, dev, id);
    

    注册input_dev或input_handler时,会两两比较左边的input_dev和右边的input_handler,
    根据input_handler的id_table判断这个input_handler能否支持这个input_dev,
    如果能支持,则调用input_handler的connect函数建立"连接"

    怎么建立连接?

    1. 分配一个input_handle结构体
    2. input_handle.dev = input_dev; // 指向左边的input_dev
      input_handle.handler = input_handler; // 指向右边的input_handler
    3. 注册:
      input_handler->h_list = &input_handle;
      inpu_dev->h_list = &input_handle;

    evdev_connect
    evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); // 分配一个input_handle

    // 设置
    evdev->handle.dev = dev;  // 指向左边的input_dev
    evdev->handle.name = evdev->name;
    evdev->handle.handler = handler;  // 指向右边的input_handler
    evdev->handle.private = evdev;
    
    // 注册
    error = input_register_handle(&evdev->handle);
    

    怎么读按键?
    app: read

    .......
    evdev_read
    // 无数据并且是非阻塞方式打开,则立刻返回
    if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
    return -EAGAIN;

    		// 否则休眠
    		retval = wait_event_interruptible(evdev->wait,
    			client->head != client->tail || !evdev->exist);
    

    谁来唤醒?
    evdev_event
    wake_up_interruptible(&evdev->wait);

    evdev_event被谁调用?
    猜:应该是硬件相关的代码,input_dev那层调用的
    在设备的中断服务程序里,确定事件是什么,然后调用相应的input_handler的event处理函数
    gpio_keys_isr
    // 上报事件
    input_event(input, type, button->code, !!state);
    input_sync(input);

    input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
    struct input_handle *handle;

    list_for_each_entry(handle, &dev->h_list, d_node)
    	if (handle->open)
    		handle->handler->event(handle, type, code, value);
    

    怎么写符合输入子系统框架的驱动程序?

    1. 分配一个input_dev结构体
    2. 设置
    3. 注册
    4. 硬件相关的代码,比如在中断服务程序里上报事件

    struct input_dev {

    void *private;
    
    const char *name;
    const char *phys;
    const char *uniq;
    struct input_id id;
    
    unsigned long evbit[NBITS(EV_MAX)];   // 表示能产生哪类事件
    unsigned long keybit[NBITS(KEY_MAX)]; // 表示能产生哪些按键
    unsigned long relbit[NBITS(REL_MAX)]; // 表示能产生哪些相对位移事件, x,y,滚轮
    unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y
    unsigned long mscbit[NBITS(MSC_MAX)];
    unsigned long ledbit[NBITS(LED_MAX)];
    unsigned long sndbit[NBITS(SND_MAX)];
    unsigned long ffbit[NBITS(FF_MAX)];
    unsigned long swbit[NBITS(SW_MAX)];
    

    测试:
    1.
    hexdump /dev/event1 (open(/dev/event1), read(), )
    秒 微秒 类 code value
    0000000 0bb2 0000 0e48 000c 0001 0026 0001 0000
    0000010 0bb2 0000 0e54 000c 0000 0000 0000 0000
    0000020 0bb2 0000 5815 000e 0001 0026 0000 0000
    0000030 0bb2 0000 581f 000e 0000 0000 0000 0000

    1. 如果没有启动QT:
      cat /dev/tty1
      按:s2,s3,s4
      就可以得到ls

    或者:
    exec 0</dev/tty1
    然后可以使用按键来输入

    1. 如果已经启动了QT:
      可以点开记事本
      然后按:s2,s3,s4
    版权声明:本文为博主原创文章,转载请注明文章来源,有需要帮忙可加QQ:871263854
  • 相关阅读:
    软件开的目录规范+sys,os,time模块
    模块与包
    匿名函数+函数递归+二分法+面向过程编程
    快捷键
    补充叠加多个装饰器:加载顺序与执行顺序+迭代器+自定义迭代器的方式:生成器+三元表达式
    闭包函数的应用+内置函数
    函数对象+函数嵌套+名称空间与作用域+闭包函数
    SP15637 Mr Youngs Picture Permutations 高维动态规划
    LG3825/BZOJ4945/LOJ2305 「NOI2017」游戏 dfs+2-SAT
    LG1198/BZOJ1012 「JSOI2008」最大数 线段树+离线
  • 原文地址:https://www.cnblogs.com/Dream998/p/8540738.html
Copyright © 2011-2022 走看看