all repos — mgba @ 6451aeaefc7c2d46861fa2794c7b6abc0e086c1f

mGBA Game Boy Advance Emulator

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}