QSDK reset按键

内核配置

image-20241022163758908

dts配置

qcom-ipq6018-cp02-c1.dts为例说明

  • pinctrl配置

    &tlnm{
    	button_pins: button_pins {
    		reset_button {
    			pins = "gpio18";
    			function = "gpio";
    			drive-strength = <8>;
    			bias-pull-down;
    		};
    	};
    };
    
  • reset按键配置

    &soc{
    	gpio_keys {
    		compatible = "gpio-keys";
    		pinctrl-0 = <&button_pins>;
    		pinctrl-names = "default";
    
    		reset {
    			label = "reset";
    			linux,code = <KEY_POWER>;
    			gpios = <&tlmm 18 GPIO_ACTIVE_LOW>;
    			linux,input-type = <1>;
    			debounce-interval = <60>;
    		};
    	};
    };
    

从上面的信息可以看出io使用的是gpio18,驱动使用的是compatible = "gpio-keys";

平台驱动

static struct platform_driver gpio_keys_driver = {
	.probe	= gpio_keys_probe,
	.remove	= gpio_keys_remove,
	.driver	= {
		.name	= "gpio-keys",
		.owner	= THIS_MODULE,
		.of_match_table = of_match_ptr(gpio_keys_of_match),
	},
};
static int __init gpio_button_init(void)
{
	int ret;
	ret = platform_driver_register(&gpio_keys_driver);
	if (ret)
		return ret;

	return ret;
}
gpio_keys_probe
	gpio_keys_button_probe(pdev, &bdev, 0); // 启动工作队列和定时器
		INIT_WORK(&bdata->work_irq, gpio_keys_gpio_work_func);
		setup_timer(&bdata->timer, gpio_keys_gpio_timer,);
	devm_request_irq						// 申请中断
	button_hotplug_event					// 创建hotplug事件
  • gpio_keys_gpio_work_fun函数

    	bdata->last_state = gpio_button_get_value(bdata);
    	button_hotplug_event(bdata, bdata->b->type ?: EV_KEY, bdata->last_state);
    
  • gpio_keys_gpio_timer函数

    struct gpio_keys_button_data *bdata = (struct gpio_keys_button_data *)_data;
    
    schedule_work(&bdata->work_irq); //启动
    
  • button_hotplug_event函数

    	button_hotplug_create_event(button_map[btn].name, type,
    			(seen - priv->seen) / HZ, value);
    
  • button_hotplug_create_event函数

    static int button_hotplug_create_event(const char *name, unsigned int type,
    		unsigned long seen, int pressed)
    {
    	struct bh_event *event;
    
    	BH_DBG("create event, name=%s, seen=%lu, pressed=%d\n",
    		name, seen, pressed);
    
    	event = kzalloc(sizeof(*event), GFP_KERNEL);
    	if (!event)
    		return -ENOMEM;
    
    	event->name = name;
    	event->type = type;
    	event->seen = seen;
    	event->action = pressed ? "pressed" : "released";
    
    	INIT_WORK(&event->work, (void *)(void *)button_hotplug_work);
    	schedule_work(&event->work);
    
    	return 0;
    }
    
  • button_hotplug_work函数

    static void button_hotplug_work(struct work_struct *work)
    {
    	struct bh_event *event = container_of(work, struct bh_event, work);
    	int ret = 0;
    
    	event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
    	if (!event->skb)
    		goto out_free_event;
    
    	ret = bh_event_add_var(event, 0, "%s@", event->action);
    	if (ret)
    		goto out_free_skb;
    
    	ret = button_hotplug_fill_event(event);
    	if (ret)
    		goto out_free_skb;
    
    	NETLINK_CB(event->skb).dst_group = 1;
    	broadcast_uevent(event->skb, 0, 1, GFP_KERNEL); //通过broadcast_uevent发到用户层。
    
     out_free_skb:
    	if (ret) {
    		BH_ERR("work error %d\n", ret);
    		kfree_skb(event->skb);
    	}
     out_free_event:
    	kfree(event);
    }
    

驱动程序参见reset按键和ipget按键在openwrt中的处理逻辑 - 轻轻的吻 - 博客园

reset按键应用层处理

#!/bin/sh

[ "${ACTION}" = "released" ] || exit 0

. /lib/functions.sh

logger "$BUTTON pressed for $SEEN seconds"

if [ "$SEEN" -lt 1 ]
then
	echo "REBOOT" > /dev/console
	sync
	reboot
elif [ "$SEEN" -gt 5 ]
then
	echo "FACTORY RESET" > /dev/console
	jffs2reset -y && reboot &
fi

return 0

jffs2reset原理