天天看點

音頻之耳機按鍵事件上報流程(Exynos7872)

(本文僅用于本人學習記錄,僅供參考)

耳機按鍵檢測到動作後事件上報,涉及到輸入子系統。

Input_report_key(cod3034x->input,jd->button,) //向輸入子系統報告産生按鍵事件
    |-- input_event(dev,EV_KEY,code,!!value)
        |-- is_event_supported(type,dev->evbit,EV_MAX)
        |-- input_handle_event(dev,type,code,value)
            |-- input_get_disposition(dev,type,code,&value)
            |-- input_pass_values(dev,dev->vals,dev->num_vals)
                |-- input_to_handler(handle,vals,count)
           

Input_sync(cod3034x->input);//通知接收者,一個報告發送完畢。

Static inline void Input_report_key(struct input_dev *dev,unsigned int code,int value)
{
    input_event(dev,EV_KEY,code,!!value);
}
           

Input_report_key函數的參數1是産生事件的輸入裝置,參數2是産生的事件,參數3是事件的值。

注:C語言中的感歎号(!)是邏輯運算操作符,經過該操作符運算後的值隻有2種情況,要麼為1,即True,要麼為0,即False。在進行邏輯運算時,所有非0的值都會被認為是 True,而隻有 0 值會被認為是False。是以對變量進行2次非運算(!!)就能将其轉化成 1 或者0,且變量原本的邏輯值保持不變。

void input_event(struct input_dev *dev,unsigned int type,unsigned int code,int value)
{
    unsigned long flag;
    if(is_event_supported(type,dev->evbit,EV_MAX))
    {
        input_handle_event(dev,type,code,value);
    }
}
           

input_event函數的參數1是input_device裝置,參數2是事件的類型,參數3是産生的事件,參數4是事件的值。該函數裡面用到了is_event_supported()函數,用于檢查輸入裝置是否支援該事件。支援傳回1,不支援傳回0。

static void input_handle_event(struct input_dev *dev,unsigned int type,unsigned int code,int value)
{
    int disposition;
    disposition = input_get_disposition(dev,type,code,&value);
    if(disposition&INPUT_PASS_TO_HANDLERS)
    {
        struct input_value *v;
        v=&dev->vals[dev->num_vals++];
        v->type=type;
        v->code=code;
        v->value=value;
    }
    input_pass_values(dev,dev->vals,dev->num_vals);
}
           

input_handle_event函數向輸入子系統傳送事件資訊,參數1是輸入裝置input_dev,參數2是事件類型,參數3是鍵碼,參數4是鍵值。input_get_disposition()确定事件的處理方式,傳回值主要有以下幾種:

INPUT_IGNORE_EVENT:表示忽略事件,不進行處理。

INPUT_PASS_TO_HANDLERS:表示事件交給handler處理。

INPUT_PASS_TO_DEVICE:表示将事件交給input_dev處理。

INPUT_PASS_TO_ALL:表示将事件交給handler和 input_dev共同處理。

static void input_pass_values(struct input_dev *dev,struct input_value *vals,unsigned int count)
{
    struct input_handle *handle;
    struct input_value *v;

    handle=rcu_dereference(dev->grab);
    if(handle)
        count=input_to_handler(handle,vals,count);
    else
        list_for_each_entry_rcu(handle,&dev->h_list,d_node)
            if(handle->open)
                {
                    count=input_to_handler(handle,vals,count);
                        if(!count)
                            break;
                }           
}
           

input_pass_values()函數用于确定input_dev的handler,并通過input_to_handler()調用handler的event函數。在上述代碼中,rcu_dereference(),該接口用來擷取RCU protected pointer。reader要通路RCU保護的共享資料,當然要擷取RCU protected pointer,然後通過該指針進行dereference的操作。dev->grab是強制為input device的handler,如果rcu_dereference()函數傳回值不為空,說明有為input_device強制指定handler,就直接調用handler的event函數。如果為NULL,表示沒有為input_device強制指定handler,就會通過周遊input device->h_list上的handle成員。如果該handle被打開,表示該裝置已經被一個使用者程序使用,就會調用與輸入裝置對應的handler的event函數。

注:隻有在handle被打開的情況下才會接收到事件,這就是說,隻有裝置被使用者程式使用時,才有必要向使用者空間導出資訊。

static unsigned int input_to_handler(struct input_handle *handle,struct input_value *vals,unsigned int count)
{
    struct input_handler *handler=handle->handler;
    struct input_value *end=vals;
    struct input_value *v;
    if(handler->filter)
    {
        for(v=vals;v!=vals+count;v++)
        {
            if(handler->filter(handle,v->type,v->code,v->value))
                continue;
            if(end!=v)
                *end=*v;        
            end++;
        }
        count=end-vals;
    }
    if(!count)
        return ;
    if(handler->events)
        handler->event(handle,vals,count);
    else if(handler->event)
        for(v=vals;v!=vals+count;v++)
            handler->event(handle,v->type,v->code,v->value);
    return count;
}
           

首先通過所有過濾器傳遞事件,然後,如果事件未被過濾掉,則通過所有打開的句柄。該函數被調用,而dev-> event_lock被禁止并且中斷被禁用。

[samsung][Z205]

繼續閱讀