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