天天看点

音频之耳机按键事件上报流程(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]

继续阅读