经过上篇blog的开头,接下来我们就通过对key的分析来大致看看input子系统。
文件位置:/drivers/input/keyboard/gpio_keys.c
(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()
图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 core,ws产生了wakeup event,且正在处理,因此不允许系统suspend(stay awake);
__pm_relax,通知PM core,ws没有正在处理的wakeup event,允许系统suspend(relax);
__pm_wakeup_event,为上边两个接口的功能组合,通知PM core,ws产生了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函数内)