ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【openwrt】按键

2022-02-24 13:58:29  阅读:354  来源: 互联网

标签:MAP button BH ret 按键 gpio event openwrt


文章目录

1.原理

1.1.硬件电路

在这里插入图片描述在这里插入图片描述

1.2.管脚信息

在这里插入图片描述

1.3.GPIO内存映射图

在这里插入图片描述

1.4 管脚中断号

在这里插入图片描述

2.实现

2.1.设备树配置

2.1.1.mt7621.dtsi

gpio@600 {
	#address-cells = <1>;
	#size-cells = <0>;

	compatible = "mtk,mt7621-gpio";
	reg = <0x600 0x100>;

	interrupt-parent = <&gic>;
	interrupts = <GIC_SHARED 12 IRQ_TYPE_LEVEL_HIGH>;

	gpio0: bank@0 {
		reg = <0>;
		compatible = "mtk,mt7621-gpio-bank";
		gpio-controller;
		#gpio-cells = <2>;
	};

	gpio1: bank@1 {
		reg = <1>;
		compatible = "mtk,mt7621-gpio-bank";
		gpio-controller;
		#gpio-cells = <2>;
	};

	gpio2: bank@2 {
		reg = <2>;
		compatible = "mtk,mt7621-gpio-bank";
		gpio-controller;
		#gpio-cells = <2>;
	};
};

2.1.2 ctunite-t2.dts


/ {
	compatible = "mediatek,ctunite-t2", "mediatek,mt7621-soc";
	model = "Ctunite-T2";

	chosen {
		bootargs = "console=ttyS0,115200";
	};

	gpio-keys-polled {
		compatible = "gpio-keys-polled";
		#address-cells = <1>;
		#size-cells = <0>;
		poll-interval = <20>;

		reset {
			label = "reset";
			gpios = <&gpio0 18 1>;
			linux,code = <KEY_RESTART>;
		};
	};
};

2.2.配置

make menuconfig

1、开启按键热插拔驱动
在这里插入图片描述

2.3.驱动

2.3.1.mt7621 gpio驱动源码

linux-4.4.198/drivers/gpio/gpio-mt7621.c

static int
mediatek_gpio_probe(struct platform_device *pdev)
{
	struct device_node *bank, *np = pdev->dev.of_node;
	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

	mediatek_gpio_membase = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(mediatek_gpio_membase))
		return PTR_ERR(mediatek_gpio_membase);

	mediatek_gpio_irq = irq_of_parse_and_map(np, 0);
	if (mediatek_gpio_irq) {
		mediatek_gpio_irq_domain = irq_domain_add_linear(np,
			MTK_MAX_BANK * MTK_BANK_WIDTH,
			&irq_domain_ops, NULL);
		if (!mediatek_gpio_irq_domain)
			dev_notice(&pdev->dev, "irq_domain_add_linear failed\n");
	}

	for_each_child_of_node(np, bank)
		if (of_device_is_compatible(bank, "mtk,mt7621-gpio-bank"))
			mediatek_gpio_bank_probe(pdev, bank);

	if (mediatek_gpio_irq_domain)
		irq_set_chained_handler(mediatek_gpio_irq, mediatek_gpio_irq_handler);

	return 0;
}

static const struct of_device_id mediatek_gpio_match[] = {
	{ .compatible = "mtk,mt7621-gpio" },
	{},
};
MODULE_DEVICE_TABLE(of, mediatek_gpio_match);

static struct platform_driver mediatek_gpio_driver = {
	.probe = mediatek_gpio_probe,
	.driver = {
		.name = "mt7621_gpio",
		.owner = THIS_MODULE,
		.of_match_table = mediatek_gpio_match,
	},
};

static int __init
mediatek_gpio_init(void)
{
	return platform_driver_register(&mediatek_gpio_driver);
}

arch_initcall(mediatek_gpio_init);

static void
mediatek_gpio_irq_handler(struct irq_desc *desc)
{
	int i;

	for (i = 0; i < MTK_MAX_BANK; i++) {
		struct mtk_gc *rg = gc_map[i];
		unsigned long pending;
		int bit;

		if (!rg)
			continue;

		pending = mtk_gpio_r32(rg, GPIO_REG_STAT);

		for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) {
			u32 map = irq_find_mapping(mediatek_gpio_irq_domain, (MTK_BANK_WIDTH * i) + bit);

			generic_handle_irq(map);
			mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit));
		}
	}
}

2.3.2 按键热插拔驱动

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 struct platform_driver gpio_keys_polled_driver = {
	.probe	= gpio_keys_polled_probe,
	.remove	= gpio_keys_remove,
	.driver	= {
		.name	= "gpio-keys-polled",
		.owner	= THIS_MODULE,
		.of_match_table = of_match_ptr(gpio_keys_polled_of_match),
	},
};

static int __init gpio_button_init(void)
{
	int ret;

	ret = platform_driver_register(&gpio_keys_driver);
	if (ret)
		return ret;

	ret = platform_driver_register(&gpio_keys_polled_driver);
	if (ret)
		platform_driver_unregister(&gpio_keys_driver);

	return ret;
}

static void __exit gpio_button_exit(void)
{
	platform_driver_unregister(&gpio_keys_driver);
	platform_driver_unregister(&gpio_keys_polled_driver);
}

module_init(gpio_button_init);
module_exit(gpio_button_exit);

按键中断服务函数

static irqreturn_t button_handle_irq(int irq, void *_bdata)
{
	struct gpio_keys_button_data *bdata = (struct gpio_keys_button_data *) _bdata;

	button_hotplug_event(bdata, bdata->b->type ?: EV_KEY, gpio_button_get_value(bdata));

	return IRQ_HANDLED;
}

创建按键热插拔事件

static void button_hotplug_event(struct gpio_keys_button_data *data,
			   unsigned int type, int value)
{
	struct bh_priv *priv = &data->bh;
	unsigned long seen = jiffies;
	int btn;

	BH_DBG("event type=%u, code=%u, value=%d\n", type, data->b->code, value);

	if ((type != EV_KEY) && (type != EV_SW))
		return;

	btn = button_get_index(data->b->code);
	if (btn < 0)
		return;

	button_hotplug_create_event(button_map[btn].name, type,
			(seen - priv->seen) / HZ, value);
	priv->seen = seen;
}

热插拔事件类型

static struct bh_map button_map[] = {
	BH_MAP(BTN_0,			"BTN_0"),
	BH_MAP(BTN_1,			"BTN_1"),
	BH_MAP(BTN_2,			"BTN_2"),
	BH_MAP(BTN_3,			"BTN_3"),
	BH_MAP(BTN_4,			"BTN_4"),
	BH_MAP(BTN_5,			"BTN_5"),
	BH_MAP(BTN_6,			"BTN_6"),
	BH_MAP(BTN_7,			"BTN_7"),
	BH_MAP(BTN_8,			"BTN_8"),
	BH_MAP(BTN_9,			"BTN_9"),
	BH_MAP(KEY_BRIGHTNESS_ZERO,	"brightness_zero"),
	BH_MAP(KEY_CONFIG,		"config"),
	BH_MAP(KEY_COPY,		"copy"),
	BH_MAP(KEY_EJECTCD,		"eject"),
	BH_MAP(KEY_HELP,		"help"),
	BH_MAP(KEY_LIGHTS_TOGGLE,	"lights_toggle"),
	BH_MAP(KEY_PHONE,		"phone"),
	BH_MAP(KEY_POWER,		"power"),
	BH_MAP(KEY_RESTART,		"reset"),
	BH_MAP(KEY_RFKILL,		"rfkill"),
	BH_MAP(KEY_VIDEO,		"video"),
	BH_MAP(KEY_WIMAX,		"wwan"),
	BH_MAP(KEY_WLAN,		"wlan"),
	BH_MAP(KEY_WPS_BUTTON,		"wps"),
};

组装netlink报文,以广播形式发送netlink报文


static int button_hotplug_fill_event(struct bh_event *event)
{
	int ret;

	ret = bh_event_add_var(event, 0, "HOME=%s", "/");
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "PATH=%s",
					"/sbin:/bin:/usr/sbin:/usr/bin");
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "SUBSYSTEM=%s", "button");
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "ACTION=%s", event->action);
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "BUTTON=%s", event->name);
	if (ret)
		return ret;

	if (event->type == EV_SW) {
		ret = bh_event_add_var(event, 0, "TYPE=%s", "switch");
		if (ret)
			return ret;
	}

	ret = bh_event_add_var(event, 0, "SEEN=%ld", event->seen);
	if (ret)
		return ret;

	ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());

	return ret;
}

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);

 out_free_skb:
	if (ret) {
		BH_ERR("work error %d\n", ret);
		kfree_skb(event->skb);
	}
 out_free_event:
	kfree(event);
}

2.3.3.procd捕获按键热插拔驱动发送的netlink消息

procd在捕获到按键事件netlink消息后,解析出的数据,通过匹配/etc/hotplug.json中的json数据,进行相应脚本的调用。在/etc/hotplug.json中,包含对button事件的处理信息,其中%BUTTON%为reset,因此会执行/etc/rc.button/reset脚本。

[
	...
	[ "if",
		[ "and",
			[ "has", "BUTTON" ],
			[ "eq", "SUBSYSTEM", "button" ],
		],
		[ "button", "/etc/rc.button/%BUTTON%" ]
	],
	...
]

3.参考文档

MT7621A.PDF
MT7621_ProgrammingGuide_Preliminary_Platform.pdf

标签:MAP,button,BH,ret,按键,gpio,event,openwrt
来源: https://blog.csdn.net/weixin_42153394/article/details/123108783

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有