summaryrefslogtreecommitdiff
path: root/firmware/inc/isr.h
blob: 73a8f03312cfdf6db322300602b5d20089038206 (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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __ISR_H
#define __ISR_H

#include <stdbool.h>
#include <stdint.h>

#include <cpu.h>
#include <list.h>
#include <util.h>
#include <seos.h>

struct ChainedInterrupt {
    link_t isrs;

    void (*const enable)(struct ChainedInterrupt *);
    void (*const disable)(struct ChainedInterrupt *);
};

struct ChainedIsr {
    link_t node;

    uint32_t maxLatencyNs;

    bool (*func)(struct ChainedIsr *);
    uint16_t tid;
};

static inline void chainIsr(struct ChainedInterrupt *interrupt, struct ChainedIsr *isr)
{
    interrupt->disable(interrupt);
    list_add_tail(&interrupt->isrs, &isr->node);
    interrupt->enable(interrupt);
}

static inline void unchainIsr(struct ChainedInterrupt *interrupt, struct ChainedIsr *isr)
{
    interrupt->disable(interrupt);
    isr->tid = 0;
    list_delete(&isr->node);
    if (!list_is_empty(&interrupt->isrs))
        interrupt->enable(interrupt);
}

static inline bool dispatchIsr(struct ChainedInterrupt *interrupt)
{
    struct link_t *cur, *tmp;
    bool handled = false;
    uint16_t oldTid = osGetCurrentTid();

    list_iterate(&interrupt->isrs, cur, tmp) {
        struct ChainedIsr *curIsr = container_of(cur, struct ChainedIsr, node);
        osSetCurrentTid(curIsr->tid);
        handled = curIsr->func(curIsr);
        if (handled)
            break;
    }
    osSetCurrentTid(oldTid);

    return handled;
}

static inline int unchainIsrAll(struct ChainedInterrupt *interrupt, uint32_t tid)
{
    int count = 0;
    struct link_t *cur, *tmp;

    list_iterate(&interrupt->isrs, cur, tmp) {
        struct ChainedIsr *curIsr = container_of(cur, struct ChainedIsr, node);
        if (curIsr->tid == tid) {
            unchainIsr(interrupt, curIsr);
            count++;
        }
    }

    return count;
}

static inline uint32_t maxLatencyIsr(struct ChainedInterrupt *interrupt)
{
    struct link_t *cur, *tmp;
    uint32_t latency = 0;

    list_iterate(&interrupt->isrs, cur, tmp) {
        struct ChainedIsr *curIsr = container_of(cur, struct ChainedIsr, node);
        if (!latency || (curIsr->maxLatencyNs && curIsr->maxLatencyNs < latency))
            latency = curIsr->maxLatencyNs;
    }

    return latency;
}

#endif /* __ISR_H */