152 lines
3.6 KiB
C
152 lines
3.6 KiB
C
/*
|
|
* bh_thread.c - 起始部分和后续部分中断处理
|
|
*
|
|
* 基于 Stefan Wendler(devnull@kaltpost.de)的 RPi 示例
|
|
* 来源于:
|
|
* https://github.com/wendlers/rpi-kmod-samples
|
|
*
|
|
* 按下一个按钮打开 LED,另一个按钮关闭 LED
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/interrupt.h>
|
|
|
|
static int button_irqs[] = { -1, -1 };
|
|
|
|
/* 定义 LED 的 GPIO。
|
|
* FIXME: 根据你的板子的 GPIO 号码修改这些数字。
|
|
*/
|
|
static struct gpio leds[] = { { 1, GPIOF_OUT_INIT_LOW, "LED 1" } };
|
|
|
|
/* 定义按钮的 GPIO
|
|
* FIXME: 根据你的板子的 GPIO 号码修改这些数字。
|
|
*/
|
|
static struct gpio buttons[] = {
|
|
{ 2, GPIOF_IN, "LED 1 开按钮" },
|
|
{ 3, GPIOF_IN, "LED 1 关按钮" },
|
|
};
|
|
|
|
/* 当 IRQ 触发时立即发生 */
|
|
static irqreturn_t button_top_half(int irq, void *ident)
|
|
{
|
|
return IRQ_WAKE_THREAD;
|
|
}
|
|
|
|
/* 可以在空闲时处理,释放 IRQ 给其他高优先级任务 */
|
|
static irqreturn_t button_bottom_half(int irq, void *ident)
|
|
{
|
|
pr_info("后续部分任务开始\n");
|
|
mdelay(500); /* 执行一些耗时的操作 */
|
|
pr_info("后续部分任务结束\n");
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static int __init bottomhalf_init(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
pr_info("%s\n", __func__);
|
|
|
|
/* 注册 LED GPIO */
|
|
ret = gpio_request_array(leds, ARRAY_SIZE(leds));
|
|
|
|
if (ret) {
|
|
pr_err("无法请求 LED 的 GPIOs: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* 注册按钮 GPIO */
|
|
ret = gpio_request_array(buttons, ARRAY_SIZE(buttons));
|
|
|
|
if (ret) {
|
|
pr_err("无法请求 BUTTON 的 GPIOs: %d\n", ret);
|
|
goto fail1;
|
|
}
|
|
|
|
pr_info("当前 button1 的值: %d\n", gpio_get_value(buttons[0].gpio));
|
|
|
|
ret = gpio_to_irq(buttons[0].gpio);
|
|
|
|
if (ret < 0) {
|
|
pr_err("无法请求 IRQ: %d\n", ret);
|
|
goto fail2;
|
|
}
|
|
|
|
button_irqs[0] = ret;
|
|
|
|
pr_info("成功请求 BUTTON1 IRQ # %d\n", button_irqs[0]);
|
|
|
|
ret = request_threaded_irq(button_irqs[0], button_top_half,
|
|
button_bottom_half,
|
|
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
|
"gpiomod#button1", &buttons[0]);
|
|
|
|
if (ret) {
|
|
pr_err("无法请求 IRQ: %d\n", ret);
|
|
goto fail2;
|
|
}
|
|
|
|
ret = gpio_to_irq(buttons[1].gpio);
|
|
|
|
if (ret < 0) {
|
|
pr_err("无法请求 IRQ: %d\n", ret);
|
|
goto fail2;
|
|
}
|
|
|
|
button_irqs[1] = ret;
|
|
|
|
pr_info("成功请求 BUTTON2 IRQ # %d\n", button_irqs[1]);
|
|
|
|
ret = request_threaded_irq(button_irqs[1], button_top_half,
|
|
button_bottom_half,
|
|
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
|
"gpiomod#button2", &buttons[1]);
|
|
|
|
if (ret) {
|
|
pr_err("无法请求 IRQ: %d\n", ret);
|
|
goto fail3;
|
|
}
|
|
|
|
return 0;
|
|
|
|
/* 清理已设置的部分 */
|
|
fail3:
|
|
free_irq(button_irqs[0], NULL);
|
|
|
|
fail2:
|
|
gpio_free_array(buttons, ARRAY_SIZE(leds));
|
|
|
|
fail1:
|
|
gpio_free_array(leds, ARRAY_SIZE(leds));
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void __exit bottomhalf_exit(void)
|
|
{
|
|
int i;
|
|
|
|
pr_info("%s\n", __func__);
|
|
|
|
/* 释放 IRQ */
|
|
free_irq(button_irqs[0], NULL);
|
|
free_irq(button_irqs[1], NULL);
|
|
|
|
/* 关闭所有 LED */
|
|
for (i = 0; i < ARRAY_SIZE(leds); i++)
|
|
gpio_set_value(leds[i].gpio, 0);
|
|
|
|
/* 注销 */
|
|
gpio_free_array(leds, ARRAY_SIZE(leds));
|
|
gpio_free_array(buttons, ARRAY_SIZE(buttons));
|
|
}
|
|
|
|
module_init(bottomhalf_init);
|
|
module_exit(bottomhalf_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("起始部分和后续部分中断处理");
|