src/gba/gba-sio.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "gba-sio.h"
7
8#include "gba-io.h"
9
10static struct GBASIODriver* _lookupDriver(struct GBASIO* sio, enum GBASIOMode mode) {
11 switch (mode) {
12 case SIO_NORMAL_8:
13 case SIO_NORMAL_32:
14 return sio->drivers.normal;
15 case SIO_MULTI:
16 return sio->drivers.multiplayer;
17 case SIO_JOYBUS:
18 return sio->drivers.joybus;
19 default:
20 return 0;
21 }
22}
23
24static void _switchMode(struct GBASIO* sio) {
25 unsigned mode = ((sio->rcnt >> 14) & 0xC) | ((sio->siocnt >> 12) & 0x3);
26 enum GBASIOMode oldMode = sio->mode;
27 if (mode < 8) {
28 sio->mode = (enum GBASIOMode) (mode & 0x3);
29 } else {
30 sio->mode = (enum GBASIOMode) (mode & 0xC);
31 }
32 if (oldMode != mode) {
33 if (sio->activeDriver && sio->activeDriver->unload) {
34 sio->activeDriver->unload(sio->activeDriver);
35 }
36 sio->activeDriver = _lookupDriver(sio, mode);
37 if (sio->activeDriver && sio->activeDriver->load) {
38 sio->activeDriver->load(sio->activeDriver);
39 }
40 }
41}
42
43void GBASIOInit(struct GBASIO* sio) {
44 sio->rcnt = RCNT_INITIAL;
45 sio->siocnt = 0;
46 sio->mode = -1;
47 sio->activeDriver = 0;
48 sio->drivers.normal = 0;
49 sio->drivers.multiplayer = 0;
50 sio->drivers.joybus = 0;
51 _switchMode(sio);
52}
53
54void GBASIODeinit(struct GBASIO* sio) {
55 if (sio->drivers.multiplayer && sio->drivers.multiplayer->deinit) {
56 sio->drivers.multiplayer->deinit(sio->drivers.multiplayer);
57 }
58 if (sio->drivers.joybus && sio->drivers.joybus->deinit) {
59 sio->drivers.joybus->deinit(sio->drivers.joybus);
60 }
61}
62
63void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) {
64 GBASIOSetDriver(sio, drivers->normal, SIO_NORMAL_8);
65 GBASIOSetDriver(sio, drivers->multiplayer, SIO_MULTI);
66 GBASIOSetDriver(sio, drivers->joybus, SIO_JOYBUS);
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}