summaryrefslogtreecommitdiff
path: root/libs/dolphin/src/si/SISteeringXfer.c
blob: 7f37b706640a959e08b097282cf949f6ff425331 (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
109
110
111
112
113
114
115
116
117
118
#include <dolphin/dolphin.h>
#include <dolphin/si.h>

#include "__os.h"

static void __SISteeringHandler(s32 chan, u32 error, OSContext* context) {
    SISteeringControl* sc;
    void (*proc)(s32);
    SISteeringCallback callback;
    OSContext exceptionContext;

    sc = &__SISteering[chan];
    if (!__SIResetSteering) {
        if (error & 8) {
            sc->ret = -1;
        } else if (error & 7) {
            sc->ret = -3;
        } else {
            sc->ret = 0;
        }

        if (sc->proc != 0) {
            proc = sc->proc;
            sc->proc = NULL;
            proc(chan);
        }

        if (sc->callback != 0) {
            OSClearContext(&exceptionContext);
            OSSetCurrentContext(&exceptionContext);
            callback = sc->callback;
            sc->callback = NULL;
            callback(chan, sc->ret);
            OSClearContext(&exceptionContext);
            OSSetCurrentContext(context);
        }
    }
}

void __SISteeringSyncCallback(s32 chan) {
    SISteeringControl* sc;

    sc = &__SISteering[chan];
    OSWakeupThread(&sc->threadQueue);
}

s32 __SISteeringSync(s32 chan) {
    SISteeringControl* sc;
    s32 ret;
    BOOL enabled;

    sc = &__SISteering[chan];
    enabled = OSDisableInterrupts();

    while (sc->callback != 0) {
        OSSleepThread(&sc->threadQueue);
    }

    ret = sc->ret;
    OSRestoreInterrupts(enabled);
    return ret;
}

static void TypeAndStatusCallback(s32 chan, u32 type) {
    SISteeringControl* sc;
    void (*proc)(s32);
    SISteeringCallback callback;
    OSContext exceptionContext;
    OSContext* context;

    sc = &__SISteering[chan];
    if (!__SIResetSteering) {
        ASSERTLINE(127, !(type & SI_ERROR_BUSY));

        if ((u32)((type & 0xFFFF0000) + 0xF8000000) == 0) {
            if (SITransfer(chan, sc, sc->outputBytes, sc->input, sc->inputBytes, __SISteeringHandler, 0)) {
                return;
            }
            sc->ret = -2;
        } else {
            sc->ret = -1;
        }

        if (sc->proc != 0) {
            proc = sc->proc;
            sc->proc = NULL;
            proc(chan);
        }

        if (sc->callback != 0) {
            context = OSGetCurrentContext();
            OSClearContext(&exceptionContext);
            OSSetCurrentContext(&exceptionContext);
            callback = sc->callback;
            sc->callback = NULL;
            callback(chan, sc->ret);
            OSClearContext(&exceptionContext);
            OSSetCurrentContext(context);
            __OSReschedule();
        }
    }
}

s32 __SISteeringTransfer(s32 chan, u32 outputBytes, u32 inputBytes, void (*proc)(s32)) {
    BOOL enabled;
    SISteeringControl* sc;

    sc = &__SISteering[chan];
    enabled = OSDisableInterrupts();

    sc->proc = proc;
    sc->outputBytes = outputBytes;
    sc->inputBytes = inputBytes;
    SIGetTypeAsync(chan, &TypeAndStatusCallback);

    OSRestoreInterrupts(enabled);
    return 0;
}