input之key(二)

  经过上篇blog的开头,接下来我们就通过对key的分析来大致看看input子系统。

  文件位置:/drivers/input/keyboard/gpio_keys.c

     (1)

     input之key(二)_第1张图片

图1

gpio_keys_get_devtree_pdata:获取平台总线数据

input_allocate_device:分配input_dev结构体,并在后面进行注册和初始化

devm_pinctrl_get:根据设备获取pin的操作句柄

gpio_keys_setup_key:按键相关配置,如中断,时钟等

sysfs_create_group:创建文件节点,可以在/sys/devices/platform/gpio-keys/下面看到。

input_register_device:注册input设备,并进行匹配。

device_init_wakeup:用来设置是否可以唤醒设备


  (2)

  ddata->key_pinctrl = devm_pinctrl_get(dev);

  if (ddata->key_pinctrl) {
        error = gpio_keys_pinctrl_configure(ddata, true);
        if (error) {
            dev_err(dev, "cannot set ts pinctrl active state\n");
            goto fail2;
        }
    }

  解析pinctrl,让我们看一下gpio_keys_pinctrl_configure()这个函数

static int gpio_keys_pinctrl_configure(struct gpio_keys_drvdata *ddata,
                            bool active)
{
    struct pinctrl_state *set_state;
    int retval;

    if (active) {
        set_state =
            pinctrl_lookup_state(ddata->key_pinctrl,
                        "tlmm_gpio_key_active");
        if (IS_ERR(set_state)) {
            dev_err(&ddata->input->dev,
                "cannot get ts pinctrl active state\n");
            return PTR_ERR(set_state);
        }
    } else {
        set_state =
            pinctrl_lookup_state(ddata->key_pinctrl,
                        "tlmm_gpio_key_suspend");
        if (IS_ERR(set_state)) {
            dev_err(&ddata->input->dev,
                "cannot get gpiokey pinctrl sleep state\n");
            return PTR_ERR(set_state);
        }
    }
    retval = pinctrl_select_state(ddata->key_pinctrl, set_state);
    if (retval) {
        dev_err(&ddata->input->dev,
                "cannot set ts pinctrl active state\n");
        return retval;
    }

    return 0;
}

  这个函数主要是对应pingctrl中的gpio_key_active和gpio_key_suspend,如下:

        tlmm_gpio_key {                                                                          
   1             qcom,pins = <&gp 107>, <&gp 108>, <&gp 109>;
   2             qcom,pin-func = <0>;
   3             qcom,num-grp-pins = <3>;
   4             label = "tlmm_gpio_key";
   5             gpio_key_active: gpio_key_active {
   6                 drive-strength = <2>;
   7                 bias-pull-up;
   8             };
   9             gpio_key_suspend: gpio_key_suspend {
  10                 drive-strength = <2>;
  11                 bias-pull-up;
  12             };
  13         };


     (3)接下来看一下:gpio_keys_setup_key()

input之key(二)_第2张图片

图2按键设置流程

gpio_is_valid:gpio是否可用

gpio_request_ong:申请gpio

gpio_set_debounce:按键消抖

gpio_keys_gpio_work_func:上报键值函数

input_event:上报键值

input_sync:进行同步,表示一次键值上报结束

gpio_keys_gpio_isr:按键中断函数

该中断函数即为中断机制的前半部,它主要思想是在按键去抖间隔时间内不执行中断后半部分内容,只有在经过去抖间隔时间达到以后,才执行工作队列中的内容&bdata->work,即执行gpio_keys_gpio_work_func函数。

中断后半部函数gpio_keys_gpio_work_func调用的是gpio_keys_gpio_report_event函数,而gpio_keys_gpio_report_event函数调用的是input_event函数,该函数的功能是把输入事件上报给系统。


pm_stay_awake

__pm_stay_awake,通知PM corews产生了wakeup event,且正在处理,因此不允许系统suspendstay awake);

__pm_relax,通知PM corews没有正在处理的wakeup event,允许系统suspendrelax);

__pm_wakeup_event,为上边两个接口的功能组合,通知PM corews产生了wakeup event,会在msec毫秒内处理结束(wakeup events framework自动relax)。

mod_timer:当一个定时器已经被插入到内核动态定时器链表中后,我们利用这个函数还可以修改该定时器的expires

 

input_set_capability:设置输入设备所支持的事件类型和事件代码,也就是输入设备对哪些事件具有处理能力,通常我们使用set_bit函数来设置

设置支持的事件类型(支持按键事件)

set_bit(EV_KEY, input_dev->evbit);

设置支持的事件代码(支持按键1)

set_bit(KEY_1, input_dev->keybit);

 

request_any_context_irq(bdata->irq, isr, irqflags, desc, bdata):

分配一条中断线,即当按键中断(bdata->irq)发生时,进入中断函数(isr,即gpio_keys_irq_isr函数内)





















你可能感兴趣的:(input之key(二))