zoukankan      html  css  js  c++  java
  • 8、linux下输入子系统

     input_sync(button_dev);    /*通知接收者,一个报告发送完毕*/

    参考:http://www.51hei.com/bbs/dpj-27652-1.html  很详细说明

    input.c是输入子系统驱动程序顶层框架文件,是一个通用的文件

    在connect函数中

    for (minor = 0; minor < EVDEV_MINORS; minor++)
      if (!evdev_table[minor])
        break;

    找一个空的evdev_table用来存放evdev,其中minor就是/dev/input/evnetx访问时的x

    drivers/input/input.c:

    class_register(&input_class)//创建一个类,作用和class_create等价,class_create内部就是调用class_register来实现的

    //device_create是在input_handler的connect函数中通过device_add实现的,因为device_create实际上就是调用device_add

    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分为左右两边,一遍调用input_register_handler ,一遍调用input_register_device

    调用input_register_handler 的主要有evdev、键盘、鼠标、触摸屏等输入设备,这部分写好了纯软件代码,硬件相关的在input_register_device中,比如触摸屏驱动程序:s3c2410_ts.c


    注册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

      input_handle_event(dev, type, code, value);

        input_pass_event(dev, type, code, value);

          list_for_each_entry_rcu(handle, &dev->h_list, d_node) 

            handler->event(handle, type, code, value);
              wake_up_interruptible(&evdev->wait);


    evdev_event被谁调用?
    猜:应该是硬件相关的代码,input_dev那层调用的
    在设备的中断服务程序里,确定事件是什么,然后调用相应的input_handler的event处理函数
    gpio_keys_isr
    // 上报事件
    input_event(input, type, button->code, !!state);(上报的时候是从input_handle链表取出handle,在调用handler的event,因此可能有多个支持的handle,在input_pass_event函数中)

    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);//evdev_event


    怎么写符合输入子系统框架的驱动程序?
    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)]; // 表示能产生哪类事件,可以看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(在copy_to_user中拷贝input_event结构体数据)

    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

    2. 如果没有启动QT:
    cat /dev/tty1   (原因是在tty下会包括keyboard.c,其也调用了input_register_handler,因此在注册驱动的时候除了和evdev关联起来,还和keyboard关联起来了,而keyboard.c的上层是tty)
    按:s2,s3,s4
    就可以得到ls

    或者:
    exec 0</dev/tty1(0表示标准输入,将标准输入文件改为tty1,即从tty1得到输入,以前0是从sh文件得到输入,sh是从串口得到输入)
    然后可以使用按键来输入

    (ps指令可以看到-sh程序的PID,在执行ls -l /proc/PID/fd可以看到-sh程序将标准输入、标准输出、标准错误都指向了窗口)


    3. 如果已经启动了QT:
    可以点开记事本
    然后按:s2,s3,s4

    如果可以参数重复类事件,input_event会启动定时器(通过input_start_autorepeat函数),调用定时器函数input_repeat_key继续上报时间,定时器在input_register_device中注册

  • 相关阅读:
    浏览器HTML5支持程度测试
    Unit testing Cmockery 简单使用
    Linux likely unlikely
    Android development tools line_endings hacking
    Linux C enum
    Android 系统内置App JNI
    Android Broadcast Receiver
    Android获取SharedPreferences失败,且App无法启动
    Sublime-text markdown with Vim mode and auto preview
    遍历Map key-value的两种方法
  • 原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/8552648.html
Copyright © 2011-2022 走看看