网上有好多的关于linux driver gpio_keys.c的分析,这里就不多赘述了。
在这里主要写一下自己遇到的思路问题,看了一遍代码深知自己基础太薄弱了。
感觉学了这么长时间的代码,基础都不会了。。。。。。反思中
下面就遇到的问题分析:
gpio_keys_probe 函数刚入口就会调用解析设备树的函数:
gpio_keys_get_devtree_pdata.
static struct gpio_keys_platform_data *
gpio_keys_get_devtree_pdata(struct device *dev)
{
struct device_node *node, *pp;
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
int error;
int nbuttons;
int i;
node = dev->of_node;
if (!node)
return ERR_PTR(-ENODEV);
nbuttons = of_get_child_count(node);
if (nbuttons == 0)
return ERR_PTR(-ENODEV);
pdata = devm_kzalloc(dev,
sizeof(*pdata) + nbuttons * sizeof(*button),
GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
pdata->nbuttons = nbuttons;
pdata->rep = !!of_get_property(node, "autorepeat", NULL);
i = 0;
for_each_child_of_node(node, pp) {
enum of_gpio_flags flags;
button = &pdata->buttons[i++];
button->gpio = of_get_gpio_flags(pp, 0, &flags);
if (button->gpio < 0) {
error = button->gpio;
if (error != -ENOENT) {
if (error != -EPROBE_DEFER)
dev_err(dev,
"Failed to get gpio flags, error: %d\n",
error);
return ERR_PTR(error);
}
} else {
button->active_low = flags & OF_GPIO_ACTIVE_LOW;
}
button->irq = irq_of_parse_and_map(pp, 0);
if (!gpio_is_valid(button->gpio) && !button->irq) {
dev_err(dev, "Found button without gpios or irqs\n");
return ERR_PTR(-EINVAL);
}
if (of_property_read_u32(pp, "linux,code", &button->code)) {
dev_err(dev, "Button without keycode: 0x%x\n",
button->gpio);
return ERR_PTR(-EINVAL);
}
button->desc = of_get_property(pp, "label", NULL);
/* 判断当前设备节点是否设置input子系统类型, 如果设置,跳过赋值button type为 key类型*/
if (of_property_read_u32(pp, "linux,input-type", &button->type))
button->type = EV_KEY;
/* 判断当前设备节点是否设置(gpio-key,wakeup),
在指定gpio-key,wakeup查找是否有指定gpio-key,wakeup的value,
如果存在这gpio-key,wakeup,则返回这个gpio-key,wakeup中的value
gpio-key,wakeup:布尔值,按钮可唤醒系统
由于取了 !! 操作,即 button->wakeup 只有bool值类型,
button->can_disable 同样如此
*/
button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
if (of_property_read_u32(pp, "debounce-interval",
&button->debounce_interval))
button->debounce_interval = 5;
}
if (pdata->nbuttons == 0)
return ERR_PTR(-EINVAL);
return pdata;
}
if (of_property_read_u32(pp, "linux,input-type", &button->type))
of_property_read_u32,这个函数当匹配到:
linux,input-type时候函数返回0,其他返回错误值,关键我们dts里面就没有配置,所以of_property_read_u32 这个返回值是负值。但是if 条件的语句是判断真假的条件,只有if (0) 不进入循环,其他的比如 :if (-23) 也是会进去的。所以这个判断就是没有设置input 子系统的type类型,则直接赋值为 KEY。
button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
of_get_property,这个函数使用:
当时理解成获取到gpio-key,wakeup 这个不应该先返回0,然后两次去非,不就还是0吗???
这个理解是错误的,因为这个函数的返回类型和上面是不一样的,他返回的类型是相当于返回
gpio-key,wakeup这个属性的值,就是他的value,但是我们dts并没有配置value额,这个怎么理解?
通过打印,发现: 只要这个属性值配置上,后面的value有没有值, 然后取!,都是为0的,
这个意思就很明显了。
Linux code 当中 如果想要设置某个dts的bool变量值,只需要加上这个属性值,不管设不设置value值,直接在of_get_property 取两次!,就可以配置相应的值了。
关于这个函数的理解有错误,望指正。
gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio_key>;
user {
label = "User Button";
gpios = <&gpio5 0 GPIO_ACTIVE_HIGH>;
gpio-key,wakeup;
linux,code = <KEY_1>;
};
};