all repos — mgba @ f62ccde49d484c65b212ae86299f4720c9dc836d

mGBA Game Boy Advance Emulator

src/gba/gba-sio.c (view raw)

  1#include "gba-sio.h"
  2
  3#include "gba-io.h"
  4
  5static struct GBASIODriver* _lookupDriver(struct GBASIO* sio, enum GBASIOMode mode) {
  6	switch (mode) {
  7	case SIO_NORMAL_8:
  8	case SIO_NORMAL_32:
  9		return sio->drivers.normal;
 10	case SIO_MULTI:
 11		return sio->drivers.multiplayer;
 12	case SIO_JOYBUS:
 13		return sio->drivers.joybus;
 14	default:
 15		return 0;
 16	}
 17}
 18
 19static void _switchMode(struct GBASIO* sio) {
 20	unsigned mode = ((sio->rcnt >> 14) & 0xC) | ((sio->siocnt >> 12) & 0x3);
 21	enum GBASIOMode oldMode = sio->mode;
 22	if (mode < 8) {
 23		sio->mode = (enum GBASIOMode) (mode & 0x3);
 24	} else {
 25		sio->mode = (enum GBASIOMode) (mode & 0xC);
 26	}
 27	if (oldMode != mode) {
 28		if (sio->activeDriver && sio->activeDriver->unload) {
 29			sio->activeDriver->unload(sio->activeDriver);
 30		}
 31		sio->activeDriver = _lookupDriver(sio, mode);
 32		if (sio->activeDriver && sio->activeDriver->load) {
 33			sio->activeDriver->load(sio->activeDriver);
 34		}
 35	}
 36}
 37
 38void GBASIOInit(struct GBASIO* sio) {
 39	sio->rcnt = RCNT_INITIAL;
 40	sio->siocnt = 0;
 41	sio->mode = -1;
 42	sio->activeDriver = 0;
 43	sio->drivers.normal = 0;
 44	sio->drivers.multiplayer = 0;
 45	sio->drivers.joybus = 0;
 46	_switchMode(sio);
 47}
 48
 49void GBASIODeinit(struct GBASIO* sio) {
 50	if (sio->drivers.multiplayer && sio->drivers.multiplayer->deinit) {
 51		sio->drivers.multiplayer->deinit(sio->drivers.multiplayer);
 52	}
 53	if (sio->drivers.joybus && sio->drivers.joybus->deinit) {
 54		sio->drivers.joybus->deinit(sio->drivers.joybus);
 55	}
 56}
 57
 58void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) {
 59	GBASIOSetDriver(sio, drivers->normal, SIO_NORMAL_8);
 60	GBASIOSetDriver(sio, drivers->multiplayer, SIO_MULTI);
 61	GBASIOSetDriver(sio, drivers->joybus, SIO_JOYBUS);
 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}