✳驱动之input_dev输入系统框架

  • 输入系统框架:
  •  

     

  • 该框架包含 input_dev 结构体(设备相关),注册到input_dev_list中;input_handler 结构体(驱动相关),注册到input_handler_list中。input_dev 结构体 与 input_handler结构体 相匹配,匹配成功之后,就调用其中的 connect 函数,该函数中实现: register_chrdev等。
  • connect 函数连接过程
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);

1. 申请得到一个次设备号,2.分配一个 evdev 结构体,3.填充该结构体中的 input_handle 结构体,4. input_handle 结构体中有两个成员:input_dev 和 input_handler 结构体;5.注册file_operations。

最终实现过程就是 :通过次设备号minor 找到 evdev ,找到 handle ,找到 input_dev 和 input_handler ,实现两者的connect 。

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

    unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

    unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
    unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
    unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
    unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
    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 hint_events_per_packet;

    unsigned int keycodemax;
    unsigned int keycodesize;
    void *keycode;

    int (*setkeycode)(struct input_dev *dev,
              const struct input_keymap_entry *ke,
              unsigned int *old_keycode);
    int (*getkeycode)(struct input_dev *dev,
              struct input_keymap_entry *ke);

    struct ff_device *ff;

    unsigned int repeat_key;
    struct timer_list timer;

    int rep[REP_CNT];

    struct input_mt *mt;

    struct input_absinfo *absinfo;

    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 (*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 __rcu *grab;

    spinlock_t event_lock;
    struct mutex mutex;

    unsigned int users;
    bool going_away;

    struct device dev;

    struct list_head    h_list;
    struct list_head    node;

    unsigned int num_vals;
    unsigned int max_vals;
    struct input_value *vals;

    bool devres_managed;
};
struct input_handler {

    void *private;

    void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
    void (*events)(struct input_handle *handle,
               const struct input_value *vals, unsigned int count);
    bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
    bool (*match)(struct input_handler *handler, struct input_dev *dev);
    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);

    bool legacy_minors;
    int minor;
    const char *name;

    const struct input_device_id *id_table;

    struct list_head    h_list;
    struct list_head    node;
};
struct evdev {
    int open;
    struct input_handle handle;
    wait_queue_head_t wait;
    struct evdev_client __rcu *grab;
    struct list_head client_list;
    spinlock_t client_lock; /* protects client_list */
    struct mutex mutex;
    struct device dev;
    struct cdev cdev;
    bool exist;
};

 

struct input_handle {

    void *private;

    int open;
    const char *name;

    struct input_dev *dev;
    struct input_handler *handler;

    struct list_head    d_node;
    struct list_head    h_node;
};

 

  • 数据传输过程:

在probe函数中实现 框架左侧的分配(devm_input_allocate_device)、设置(__set_bit)、注册(input_register_device) input_dev结构体,通过中断函数或者其他方式使用 input_event 函数实现上报数据。

APP中的 open 函数通过调用驱动中的 evdev_open 函数,该函数实现:构造结构体 evdev_client(理解为应用程序的用户),结构体中包括环形缓冲区、头尾等,一个应用程序对应一个evdev_client ;应用程序读数据 read 的时候,调用驱动中的 evdev_read 函数,该函数实现:会分析是哪个应用程序也就是 evdev_client ,判断结构体中的环形缓冲区是否为空,为空就休眠,不为空就拷贝值返回用户空间 input_event_to_user,实质就是copy_to_user();

硬件通过 中断 实现上报数据 input_event() ,该函数实现:利用input_dev通过dereference找到 handle 结构体, 继而找到 handle.handler,也即是 evdev_handler 结构体,从而调用handler.event()

函数;改event()函数实现:填充 client 的环形缓冲区,并唤醒休眠,

 

 

 

struct evdev_client {
    unsigned int head;
    unsigned int tail;
    unsigned int packet_head; /* [future] position of the first element of next packet */
    spinlock_t buffer_lock; /* protects access to buffer, head and tail */
    struct fasync_struct *fasync;
    struct evdev *evdev;
    struct list_head node;
    unsigned int clk_type;
    bool revoked;
    unsigned long *evmasks[EV_CNT];
    unsigned int bufsize;
    struct input_event buffer[];
};

 

posted @ 2022-11-10 15:26  QianFa01  阅读(105)  评论(0)    收藏  举报