Merge "plat_stm32f4: exti: add chained ISRs" into mnc-dev
diff --git a/firmware/inc/platform/stm32f4xx/exti.h b/firmware/inc/platform/stm32f4xx/exti.h
index 849f1fa..c9873e4 100644
--- a/firmware/inc/platform/stm32f4xx/exti.h
+++ b/firmware/inc/platform/stm32f4xx/exti.h
@@ -1,7 +1,9 @@
#ifndef _EXTI_H_
#define _EXTI_H_
+#include <isr.h>
#include <stdbool.h>
+#include <plat/inc/cmsis.h>
#include <plat/inc/gpio.h>
#ifdef __cplusplus
@@ -45,6 +47,9 @@
bool extiIsPendingLine(const enum ExtiLine line);
void extiClearPendingLine(const enum ExtiLine line);
+int extiChainIsr(IRQn_Type n, struct ChainedIsr *isr);
+int extiUnchainIsr(IRQn_Type n, struct ChainedIsr *isr);
+
static inline void extiEnableIntGpio(const struct Gpio *__restrict gpio, enum ExtiTrigger trigger)
{
extiEnableIntLine(gpio->gpio & GPIO_PIN_MASK, trigger);
diff --git a/firmware/src/platform/stm32f4xx/exti.c b/firmware/src/platform/stm32f4xx/exti.c
index b997cc0..d63724d 100644
--- a/firmware/src/platform/stm32f4xx/exti.c
+++ b/firmware/src/platform/stm32f4xx/exti.c
@@ -1,3 +1,7 @@
+#include <errno.h>
+#include <isr.h>
+
+#include <plat/inc/cmsis.h>
#include <plat/inc/exti.h>
#include <plat/inc/pwr.h>
@@ -47,3 +51,90 @@
{
return (EXTI->PR & (1UL << line)) ? true : false;
}
+
+struct ExtiInterrupt
+{
+ struct ChainedInterrupt base;
+ IRQn_Type irq;
+};
+
+static void extiInterruptEnable(struct ChainedInterrupt *irq)
+{
+ struct ExtiInterrupt *exti = container_of(irq, struct ExtiInterrupt, base);
+ NVIC_EnableIRQ(exti->irq);
+}
+
+static void extiInterruptDisable(struct ChainedInterrupt *irq)
+{
+ struct ExtiInterrupt *exti = container_of(irq, struct ExtiInterrupt, base);
+ NVIC_DisableIRQ(exti->irq);
+}
+
+#define DECLARE_SHARED_EXTI(i) { \
+ .base = { \
+ .enable = extiInterruptEnable, \
+ .disable = extiInterruptDisable, \
+ }, \
+ .irq = i, \
+}
+
+static struct ExtiInterrupt gInterrupts[] = {
+ DECLARE_SHARED_EXTI(EXTI0_IRQn),
+ DECLARE_SHARED_EXTI(EXTI1_IRQn),
+ DECLARE_SHARED_EXTI(EXTI2_IRQn),
+ DECLARE_SHARED_EXTI(EXTI3_IRQn),
+ DECLARE_SHARED_EXTI(EXTI4_IRQn),
+ DECLARE_SHARED_EXTI(EXTI9_5_IRQn),
+ DECLARE_SHARED_EXTI(EXTI15_10_IRQn),
+};
+
+static inline struct ExtiInterrupt *extiForIrq(IRQn_Type n)
+{
+ if (n >= EXTI0_IRQn && n <= EXTI4_IRQn)
+ return &gInterrupts[n - EXTI0_IRQn];
+ if (n == EXTI9_5_IRQn)
+ return &gInterrupts[ARRAY_SIZE(gInterrupts) - 2];
+ if (n == EXTI15_10_IRQn)
+ return &gInterrupts[ARRAY_SIZE(gInterrupts) - 1];
+ return NULL;
+}
+
+static void extiIrqHandler(IRQn_Type n)
+{
+ struct ExtiInterrupt *exti = extiForIrq(n);
+ dispatchIsr(&exti->base);
+}
+
+#define DEFINE_SHARED_EXTI_ISR(i) \
+ void EXTI##i##_IRQHandler(void); \
+ void EXTI##i##_IRQHandler(void) { \
+ extiIrqHandler(EXTI##i##_IRQn); \
+ } \
+
+DEFINE_SHARED_EXTI_ISR(0)
+DEFINE_SHARED_EXTI_ISR(1)
+DEFINE_SHARED_EXTI_ISR(2)
+DEFINE_SHARED_EXTI_ISR(3)
+DEFINE_SHARED_EXTI_ISR(4)
+DEFINE_SHARED_EXTI_ISR(9_5)
+DEFINE_SHARED_EXTI_ISR(15_10)
+
+int extiChainIsr(IRQn_Type n, struct ChainedIsr *isr)
+{
+ struct ExtiInterrupt *exti = extiForIrq(n);
+ if (!exti)
+ return -EINVAL;
+
+ chainIsr(&exti->base, isr);
+ return 0;
+}
+
+int extiUnchainIsr(IRQn_Type n, struct ChainedIsr *isr)
+{
+ struct ExtiInterrupt *exti = extiForIrq(n);
+ if (!exti)
+ return -EINVAL;
+
+ unchainIsr(&exti->base, isr);
+ return 0;
+}