all repos — mgba @ f6a7fedb2813d070a07cd6da65e8ddd666cd41d1

mGBA Game Boy Advance Emulator

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}