src/gba/gba-sio.c (view raw)
1#include "gba-sio.h"
2
3#include "gba-io.h"
4
5#include <limits.h>
6
7static struct GBASIODriver* _lookupDriver(struct GBASIO* sio, enum GBASIOMode mode) {
8 switch (mode) {
9 case SIO_NORMAL_8:
10 case SIO_NORMAL_32:
11 return sio->drivers.normal;
12 case SIO_MULTI:
13 return sio->drivers.multiplayer;
14 case SIO_JOYBUS:
15 return sio->drivers.joybus;
16 default:
17 return 0;
18 }
19}
20
21static void _switchMode(struct GBASIO* sio) {
22 int mode = ((sio->rcnt >> 14) & 0xC) | ((sio->siocnt >> 12) & 0x3);
23 enum GBASIOMode oldMode = sio->mode;
24 if (mode < 8) {
25 sio->mode = (enum GBASIOMode) (mode & 0x3);
26 } else {
27 sio->mode = (enum GBASIOMode) (mode & 0xC);
28 }
29 if (oldMode != mode) {
30 if (sio->activeDriver && sio->activeDriver->unload) {
31 sio->activeDriver->unload(sio->activeDriver);
32 }
33 sio->activeDriver = _lookupDriver(sio, mode);
34 if (sio->activeDriver && sio->activeDriver->load) {
35 sio->activeDriver->load(sio->activeDriver);
36 }
37 }
38}
39
40void GBASIOInit(struct GBASIO* sio) {
41 sio->rcnt = RCNT_INITIAL;
42 sio->siocnt = 0;
43 _switchMode(sio);
44}
45
46void GBASIODeinit(struct GBASIO* sio) {
47 if (sio->drivers.multiplayer && sio->drivers.multiplayer->deinit) {
48 sio->drivers.multiplayer->deinit(sio->drivers.multiplayer);
49 }
50 if (sio->drivers.joybus && sio->drivers.joybus->deinit) {
51 sio->drivers.joybus->deinit(sio->drivers.joybus);
52 }
53}
54
55void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) {
56 if (drivers->normal) {
57 GBASIOSetDriver(sio, drivers->normal, SIO_NORMAL_8);
58 }
59 if (drivers->multiplayer) {
60 GBASIOSetDriver(sio, drivers->multiplayer, SIO_MULTI);
61 }
62 if (drivers->joybus) {
63 GBASIOSetDriver(sio, drivers->multiplayer, SIO_JOYBUS);
64 }
65}
66
67void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASIOMode mode) {
68 struct GBASIODriver** driverLoc;
69 switch (mode) {
70 case SIO_NORMAL_8:
71 case SIO_NORMAL_32:
72 driverLoc = &sio->drivers.normal;
73 break;
74 case SIO_MULTI:
75 driverLoc = &sio->drivers.multiplayer;
76 break;
77 case SIO_JOYBUS:
78 driverLoc = &sio->drivers.joybus;
79 break;
80 default:
81 GBALog(sio->p, GBA_LOG_ERROR, "Setting an unsupported SIO driver: %x", mode);
82 return;
83 }
84 if (*driverLoc) {
85 if ((*driverLoc)->unload) {
86 (*driverLoc)->unload(*driverLoc);
87 }
88 if ((*driverLoc)->deinit) {
89 (*driverLoc)->deinit(*driverLoc);
90 }
91 }
92 if (driver) {
93 driver->p = sio;
94
95 if (driver->init) {
96 if (!driver->init(driver)) {
97 driver->deinit(driver);
98 GBALog(sio->p, GBA_LOG_ERROR, "Could not initialize SIO driver");
99 return;
100 }
101 }
102 if (sio->mode == mode) {
103 sio->activeDriver = driver;
104 if (driver->load) {
105 driver->load(driver);
106 }
107 }
108 }
109 *driverLoc = driver;
110}
111
112void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value) {
113 sio->rcnt = value;
114 _switchMode(sio);
115 if (sio->activeDriver && sio->activeDriver->writeRegister) {
116 sio->activeDriver->writeRegister(sio->activeDriver, REG_RCNT, value);
117 }
118}
119
120void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
121 if (sio->activeDriver && sio->activeDriver->writeRegister) {
122 value = sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOCNT, value);
123 }
124 sio->siocnt = value;
125 _switchMode(sio);
126}
127
128void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value) {
129 if (sio->activeDriver && sio->activeDriver->writeRegister) {
130 sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOMLT_SEND, value);
131 }
132}
133
134int32_t GBASIOProcessEvents(struct GBASIO* sio, int32_t cycles) {
135 if (sio->activeDriver && sio->activeDriver->processEvents) {
136 return sio->activeDriver->processEvents(sio->activeDriver, cycles);
137 }
138 return INT_MAX;
139}