1. input子系统介绍
input 子系统分为 input 驱动层、input 核心层、input 事件处理层,最终给用户空间提供可访问的设备节点。
- 驱动层:输入设备的具体驱动程序,比如按键驱动程序,向内核层报告输入内容
- 核心层:承上启下,为驱动层提供输入设备注册和操作接口。通知事件层对输入事件进行处理。
- 事件层:主要和用户空间进行交互。
2. 重要结构体
2.1 struct input_dev
/*** struct input_dev - represents an input device* @name: name of the device* @phys: physical path to the device in the system hierarchy* @uniq: unique identification code for the device (if device has it)* @id: id of the device (struct input_id)* @propbit: bitmap of device properties and quirks* @evbit: bitmap of types of events supported by the device (EV_KEY,* EV_REL, etc.)* @keybit: bitmap of keys/buttons this device has* @relbit: bitmap of relative axes for the device* @absbit: bitmap of absolute axes for the device* @mscbit: bitmap of miscellaneous events supported by the device* @ledbit: bitmap of leds present on the device* @sndbit: bitmap of sound effects supported by the device* @ffbit: bitmap of force feedback effects supported by the device* @swbit: bitmap of switches present on the device* @hint_events_per_packet: average number of events generated by the* device in a packet (between EV_SYN/SYN_REPORT events). Used by* event handlers to estimate size of the buffer needed to hold* events.* @keycodemax: size of keycode table* @keycodesize: size of elements in keycode table* @keycode: map of scancodes to keycodes for this device* @getkeycode: optional legacy method to retrieve current keymap.* @setkeycode: optional method to alter current keymap, used to implement* sparse keymaps. If not supplied default mechanism will be used.* The method is being called while holding event_lock and thus must* not sleep* @ff: force feedback structure associated with the device if device* supports force feedback effects* @repeat_key: stores key code of the last key pressed; used to implement* software autorepeat* @timer: timer for software autorepeat* @rep: current values for autorepeat parameters (delay, rate)* @mt: pointer to multitouch state* @absinfo: array of &struct input_absinfo elements holding information* about absolute axes (current value, min, max, flat, fuzz,* resolution)* @key: reflects current state of device's keys/buttons* @led: reflects current state of device's LEDs* @snd: reflects current state of sound effects* @sw: reflects current state of device's switches* @open: this method is called when the very first user calls* input_open_device(). The driver must prepare the device* to start generating events (start polling thread,* request an IRQ, submit URB, etc.)* @close: this method is called when the very last user calls* input_close_device().* @flush: purges the device. Most commonly used to get rid of force* feedback effects loaded into the device when disconnecting* from it* @event: event handler for events sent _to_ the device, like EV_LED* or EV_SND. The device is expected to carry out the requested* action (turn on a LED, play sound, etc.) The call is protected* by @event_lock and must not sleep* @grab: input handle that currently has the device grabbed (via* EVIOCGRAB ioctl). When a handle grabs a device it becomes sole* recipient for all input events coming from the device* @event_lock: this spinlock is is taken when input core receives* and processes a new event for the device (in input_event()).* Code that accesses and/or modifies parameters of a device* (such as keymap or absmin, absmax, absfuzz, etc.) after device* has been registered with input core must take this lock.* @mutex: serializes calls to open(), close() and flush() methods* @users: stores number of users (input handlers) that opened this* device. It is used by input_open_device() and input_close_device()* to make sure that dev->open() is only called when the first* user opens device and dev->close() is called when the very* last user closes the device* @going_away: marks devices that are in a middle of unregistering and* causes input_open_device*() fail with -ENODEV.* @dev: driver model's view of this device* @h_list: list of input handles associated with the device. When* accessing the list dev->mutex must be held* @node: used to place the device onto input_dev_list* @num_vals: number of values queued in the current frame* @max_vals: maximum number of values queued in a frame* @vals: array of values queued in the current frame* @devres_managed: indicates that devices is managed with devres framework* and needs not be explicitly unregistered or freed.*/
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;
};
- evbit 表示输入事件类型,比如同步事件、按键事件等
#define EV_SYN 0x00 /* 同步事件 */
#define EV_KEY 0x01 /* 按键事件 */
#define EV_REL 0x02 /* 相对坐标事件 */
#define EV_ABS 0x03 /* 绝对坐标事件 */
#define EV_MSC 0x04 /* 杂项(其他)事件 */
#define EV_SW 0x05 /* 开关事件 */
#define EV_LED 0x11 /* LED */
#define EV_SND 0x12 /* sound(声音) */
#define EV_REP 0x14 /* 重复事件 */
#define EV_FF 0x15 /* 压力事件 */
#define EV_PWR 0x16 /* 电源事件 */
#define EV_FF_STATUS 0x17 /* 压力状态事件 */
- keybit、relbit 等等都是存放不同事件对应的值,比如keybit支持KEY_1、KEY_2等
#define KEY_RESERVED 0
#define KEY_ESC 1
#define KEY_1 2
#define KEY_2 3
#define KEY_3 4
#define KEY_4 5
#define KEY_5 6
#define KEY_6 7
#define KEY_7 8
#define KEY_8 9
#define KEY_9 10
#define KEY_0 11
......
#define BTN_TRIGGER_HAPPY39 0x2e6
#define BTN_TRIGGER_HAPPY40 0x2e7
2.2 struct input_handler
/*** struct input_handler - implements one of interfaces for input devices* @private: driver-specific data* @event: event handler. This method is being called by input core with* interrupts disabled and dev->event_lock spinlock held and so* it may not sleep* @events: event sequence handler. This method is being called by* input core with interrupts disabled and dev->event_lock* spinlock held and so it may not sleep* @filter: similar to @event; separates normal event handlers from* "filters".* @match: called after comparing device's id with handler's id_table* to perform fine-grained matching between device and handler* @connect: called when attaching a handler to an input device* @disconnect: disconnects a handler from input device* @start: starts handler for given handle. This function is called by* input core right after connect() method and also when a process* that "grabbed" a device releases it* @legacy_minors: set to %true by drivers using legacy minor ranges* @minor: beginning of range of 32 legacy minors for devices this driver* can provide* @name: name of the handler, to be shown in /proc/bus/input/handlers* @id_table: pointer to a table of input_device_ids this driver can* handle* @h_list: list of input handles associated with the handler* @node: for placing the driver onto input_handler_list** Input handlers attach to input devices and create input handles. There* are likely several handlers attached to any given input device at the* same time. All of them will get their copy of input event generated by* the device.** The very same structure is used to implement input filters. Input core* allows filters to run first and will not pass event to regular handlers* if any of the filters indicate that the event should be filtered (by* returning %true from their filter() method).** Note that input core serializes calls to connect() and disconnect()* methods.*/
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;
};
2.3 设备获取、上报数据:struct input_event
/** The event structure itself*/struct input_event {struct timeval time;__u16 type;__u16 code;__s32 value;
};struct timeval {__kernel_time_t tv_sec; /* seconds */__kernel_suseconds_t tv_usec; /* microseconds */
};
- time:事件发生时间
- type:事件类型,EV_KEY、EV_ABS等
- code:事件码,KEY_1、KEY_2等
- value:值,比如 EV_KEY 事件中 value 就是按键值,表示按键有没有被按下,如果为 1 的话说明按键按下,如果为 0 的话说明按键没有被按下或者按键松开了
3. input 内部实现
- 和platform总线驱动相似,左右两边依次比较,如果匹配,则调用input_handler结构体的connect函数
3.1 input 驱动编写流程
static int __init input_init(void)
{int err;err = class_register(&input_class);if (err) {pr_err("unable to register input_dev class\n");return err;}err = input_proc_init();if (err)goto fail1;err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0),INPUT_MAX_CHAR_DEVICES, "input");if (err) {pr_err("unable to register char major %d", INPUT_MAJOR);goto fail2;}return 0;fail2: input_proc_exit();fail1: class_unregister(&input_class);return err;
}static void __exit input_exit(void)
{input_proc_exit();unregister_chrdev_region(MKDEV(INPUT_MAJOR, 0),INPUT_MAX_CHAR_DEVICES);class_unregister(&input_class);
}subsys_initcall(input_init);
module_exit(input_exit);
- 注册一个 input 类,这样系统启动以后就会在/sys/class 目录下有一个 input 子目录
- 注册一个主设备号为INPUT_MAJOR(13)的字符驱动,后续在使用 input 子系统处理输入设备的时候就不需要去注册字符设备了,我们只需要向系统注册一个 input_device 即可