天天看點

【輸入子系統02】輸入子系統Input_event 傳遞

【輸入子系統02】輸入子系統Input_event 傳遞

    • 一、input_dev
    • 二、input_event
    • 三、input_handle_event

在前文 《【輸入子系統01】USB觸摸屏驅動》中記錄了如何在kernel中添加input device 類型為touchscreen的驅動,

這在整個輸入體系中是最下層的裝置驅動部分,往上一層就是linux核心的管理驅動input系統,kernel中的源碼位置:/kernel/drivers/input/input.c

到目前已經完全調通,可以正常使用了,現在記錄一下這段時間接觸到的Android 輸入input 系統,先看一張網上的層次圖,蠻不錯的:

【輸入子系統02】輸入子系統Input_event 傳遞

這個結構體表述的是一個輸入裝置的相關資訊,在usbtouchscreen 驅動中的 usbtouch_probe 會初始化input_dev,作為usbtouch裝置的一部分.

會對 input_dev 做一系列的初始化,設定參數之類的,具體可參考之前部落格

input_dev 結構原型如下,/kernel/include/linux/input.h中定義:

/**
 * 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 array of struct input_mt_slot holding current values of tracked contacts
 * @mtsize: number of MT slots the device uses
 * @slot: MT slot currently being transmitted
 * @trkid: stores MT tracking ID for the current contact
 * @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.
 * @sync: set to %true when there were no new events since last EV_SYN
 * @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
 */
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_slot *mt;
	int mtsize;
	int slot;
	int trkid;
 
	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;
 
	bool sync;
	struct device dev;
	struct list_head	h_list;
	struct list_head	node;
};

           

每一個input裝置,都需要初始化一個這樣的input_dev結構來描述記錄此裝置的一些特性,然後通過input_register_device 注冊到裝置總線上以供後續使用

可以到系統運作目錄的/proc/bus/input下 cat devices 檢視總線上的已經注冊上的input device

裝置驅動部分往上傳遞的就是觸發的event事件了,還以usbtouchscreen的為例,回調函數為:

/*****************************************************************************
 * Generic Part */
static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
                                 unsigned char *pkt, int len)
{
    struct usbtouch_device_info *type = usbtouch->type; 
 
    if (!type->read_data(usbtouch, pkt))
            return;
 
    input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch); // 上報觸摸類型 。touch為按下
 
    if (swap_xy) {
        input_report_abs(usbtouch->input, ABS_X, usbtouch->y);
        input_report_abs(usbtouch->input, ABS_Y, usbtouch->x);
    } else {
        input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
        input_report_abs(usbtouch->input, ABS_Y, usbtouch->y); // 上報絕對坐标值
    }
    if (type->max_press)
        input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
    input_sync(usbtouch->input);   // 同步操作
}
           

可以看到通過 input_report_* 上報事件到input.c中,這也就是上面層次圖中的箭頭 9 ,初始在/kernel/include/linux/input.h:

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
	input_event(dev, EV_KEY, code, !!value);
}
 
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
	input_event(dev, EV_REL, code, value);
}
 
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
	input_event(dev, EV_ABS, code, value);
}

           

可以看到不同的report 都調用進了input_event,隻是傳參不同,接下來的事就全交由input.c 來做了!

/**
 * input_event() - report new input event
 * @dev: device that generated the event
 * @type: type of the event
 * @code: event code
 * @value: value of the event
 *
 * This function should be used by drivers implementing various input
 * devices to report input events. See also input_inject_event().
 *
 * NOTE: input_event() may be safely used right after input device was
 * allocated with input_allocate_device(), even before it is registered
 * with input_register_device(), but the event will not reach any of the
 * input handlers. Such early invocation of input_event() may be used
 * to 'seed' initial state of a switch or initial position of absolute
 * axis, etc.
 */
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
    unsigned long flags;
 
    if (is_event_supported(type, dev->evbit, EV_MAX)) { 
    	 //判斷是否是注冊時的event類型,驅動probe時注冊input_dev時設定了能響應的event類型
 
        spin_lock_irqsave(&dev->event_lock, flags); //自旋鎖枷鎖
 
       	add_input_randomness(type, code, value);
        input_handle_event(dev, type, code, value);  //進一步處理傳上來的這個 event
        spin_unlock_irqrestore(&dev->event_lock, flags);//解鎖
    }
}
 

           

可以看到在這裡首先就是過濾了事件類型,這個也是在usbtouchscreen中的probe中初始化過的!

類型有如下幾種:

/*
 * Event types
 */
#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
#define EV_SND			0x12
#define EV_REP			0x14
#define EV_FF			0x15
#define EV_PWR			0x16
#define EV_FF_STATUS	0x17
#define EV_MAX			0x1f
#define EV_CNT			(EV_MAX+1)

           

由上面的input_event 調入進這個handle處理。這裡會根據type進行分類處理:

static void input_handle_event(struct input_dev *dev,
                   unsigned int type, unsigned int code, int value)
{
    int disposition = INPUT_IGNORE_EVENT; //初始為不做處理
 
    switch (type) {
    case EV_SYN:
        switch (code) {
        case SYN_CONFIG:
            disposition = INPUT_PASS_TO_ALL; break;
 
        case SYN_REPORT:
            if (!dev->sync) {
                dev->sync = true;
                disposition = INPUT_PASS_TO_HANDLERS;
            }
            break;
...
    case EV_KEY:
 
        if (is_event_supported(code, dev->keybit, KEY_MAX) &&  //按鍵code是否被keybit支援
            !!test_bit(code, dev->key) != value) {  
            //key是鍵盤目前所有鍵狀态,測試code對應鍵狀态,value傳來事件的按鍵狀态。此句表示按鍵狀态應有變化
 
            if (value != 2) {
                __change_bit(code, dev->key);  
                //改變key的值以改變按鍵狀态。
                if (value)
                    input_start_autorepeat(dev, code); 
                    //如果按鍵值為按下,則開始重複按鍵操作。具體會不會重複,input_start_autorepeat還會根據evbit中有沒有置位重複事件等判斷。
                else
                    input_stop_autorepeat(dev); //如果是松開按鍵則應停止重複按鍵相關操作。
            }
 
            disposition = INPUT_PASS_TO_HANDLERS;
        }
        break;
 
...
 
    case EV_ABS:
        if (is_event_supported(code, dev->absbit, ABS_MAX))  //同上面一樣看是否支援
            disposition = input_handle_abs_event(dev, code, &value);  //這個函數可以跟進去看,是做為篩選的,第一次是不會傳回INPUT_IGNORE_EVENT ,後面如果有跟上次相同的ABS坐标就會被過濾掉,傳回IGNORE
//        err("jscese display disposition vlue ==0x%x,code==0x%x, value== 0x%x\n",disposition,code,value);
        break;
 
...
 
   }
 
    if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
        dev->sync = false;
 
    if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
        dev->event(dev, type, code, value); 
 
    if (disposition & INPUT_PASS_TO_HANDLERS)
        input_pass_event(dev, type, code, value);  //更深一步調用 ,最終都是 調用到 event(**)方法
 
}