blob: dfbf136380d3e3054311bd53631eca794dc91bad (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
/* libhw/rp2040_dma.c - Utilities for sharing the DMA IRQs
*
* Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <stdbool.h>
#include <hardware/irq.h> /* for irq_set_exclusive_handler() */
#include "rp2040_dma.h"
struct dmairq_handler_entry {
dmairq_handler_t fn;
void *arg;
};
struct dmairq_handler_entry dmairq_handlers[NUM_DMA_CHANNELS] = {0};
bool dmairq_initialized[NUM_DMA_IRQS] = {0};
static void dmairq_handler(void) {
enum dmairq irq = __get_current_exception() - VTABLE_FIRST_IRQ;
size_t irq_idx = irq - DMAIRQ_0;
assert(irq_idx < NUM_DMA_IRQS);
uint32_t regval = dma_hw->irq_ctrl[irq_idx].ints;
for (uint channel = 0; channel < NUM_DMA_CHANNELS; channel++) {
if (regval & 1u<<channel) {
struct dmairq_handler_entry *handler = &dmairq_handlers[channel];
if (handler->fn)
handler->fn(handler->arg, irq, channel);
}
}
/* acknowledge irq */
dma_hw->intr = regval;
}
void dmairq_set_and_enable_exclusive_handler(enum dmairq irq, uint channel, dmairq_handler_t fn, void *arg) {
assert(irq == DMAIRQ_0 || irq == DMAIRQ_1);
assert(channel < NUM_DMA_CHANNELS);
assert(fn);
assert(dmairq_handlers[channel].fn == NULL);
dmairq_handlers[channel].fn = fn;
dmairq_handlers[channel].arg = arg;
size_t irq_idx = irq - DMAIRQ_0;
hw_set_bits(&dma_hw->irq_ctrl[irq_idx].inte, 1u<<channel);
if (!dmairq_initialized[irq_idx]) {
irq_set_exclusive_handler(irq, dmairq_handler);
irq_set_enabled(irq, true);
dmairq_initialized[irq_idx] = true;
}
}
|