all repos — mgba @ 9c8e5fc2228f32e5b986bf9f121de8ab58a35ca1

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