✳驱动之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[]; };
浙公网安备 33010602011771号