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 sio->mode = -1;
44 sio->activeDriver = 0;
45 _switchMode(sio);
46}
47
48void GBASIODeinit(struct GBASIO* sio) {
49 if (sio->drivers.multiplayer && sio->drivers.multiplayer->deinit) {
50 sio->drivers.multiplayer->deinit(sio->drivers.multiplayer);
51 }
52 if (sio->drivers.joybus && sio->drivers.joybus->deinit) {
53 sio->drivers.joybus->deinit(sio->drivers.joybus);
54 }
55}
56
57void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) {
58 if (drivers->normal) {
59 GBASIOSetDriver(sio, drivers->normal, SIO_NORMAL_8);
60 }
61 if (drivers->multiplayer) {
62 GBASIOSetDriver(sio, drivers->multiplayer, SIO_MULTI);
63 }
64 if (drivers->joybus) {
65 GBASIOSetDriver(sio, drivers->multiplayer, SIO_JOYBUS);
66 }
67}
68
69void GBASIOSetDriver(struct GBASIO* sio, struct GBASIODriver* driver, enum GBASIOMode mode) {
70 struct GBASIODriver** driverLoc;
71 switch (mode) {
72 case SIO_NORMAL_8:
73 case SIO_NORMAL_32:
74 driverLoc = &sio->drivers.normal;
75 break;
76 case SIO_MULTI:
77 driverLoc = &sio->drivers.multiplayer;
78 break;
79 case SIO_JOYBUS:
80 driverLoc = &sio->drivers.joybus;
81 break;
82 default:
83 GBALog(sio->p, GBA_LOG_ERROR, "Setting an unsupported SIO driver: %x", mode);
84 return;
85 }
86 if (*driverLoc) {
87 if ((*driverLoc)->unload) {
88 (*driverLoc)->unload(*driverLoc);
89 }
90 if ((*driverLoc)->deinit) {
91 (*driverLoc)->deinit(*driverLoc);
92 }
93 }
94 if (driver) {
95 driver->p = sio;
96
97 if (driver->init) {
98 if (!driver->init(driver)) {
99 driver->deinit(driver);
100 GBALog(sio->p, GBA_LOG_ERROR, "Could not initialize SIO driver");
101 return;
102 }
103 }
104 if (sio->mode == mode) {
105 sio->activeDriver = driver;
106 if (driver->load) {
107 driver->load(driver);
108 }
109 }
110 }
111 *driverLoc = driver;
112}
113
114void GBASIOWriteRCNT(struct GBASIO* sio, uint16_t value) {
115 sio->rcnt = value;
116 _switchMode(sio);
117 if (sio->activeDriver && sio->activeDriver->writeRegister) {
118 sio->activeDriver->writeRegister(sio->activeDriver, REG_RCNT, value);
119 }
120}
121
122void GBASIOWriteSIOCNT(struct GBASIO* sio, uint16_t value) {
123 if (sio->activeDriver && sio->activeDriver->writeRegister) {
124 value = sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOCNT, value);
125 }
126 sio->siocnt = value;
127 _switchMode(sio);
128}
129
130void GBASIOWriteSIOMLT_SEND(struct GBASIO* sio, uint16_t value) {
131 if (sio->activeDriver && sio->activeDriver->writeRegister) {
132 sio->activeDriver->writeRegister(sio->activeDriver, REG_SIOMLT_SEND, value);
133 }
134}
135
136int32_t GBASIOProcessEvents(struct GBASIO* sio, int32_t cycles) {
137 if (sio->activeDriver && sio->activeDriver->processEvents) {
138 return sio->activeDriver->processEvents(sio->activeDriver, cycles);
139 }
140 return INT_MAX;
141}