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