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->multiplayer) {
57 GBASIOSetDriver(sio, drivers->multiplayer, SIO_MULTI);
58 }
59 if (drivers->joybus) {
60 GBASIOSetDriver(sio, drivers->multiplayer, SIO_JOYBUS);
61 }
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}