/*************************************************************************************** * Genesis Plus * I/O Chip * * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code) * Eke-Eke (2007,2008,2009), additional code & fixes for the GCN/Wii port * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ****************************************************************************************/ #include "shared.h" uint8 io_reg[0x10]; uint8 region_code = REGION_USA; static struct port_t { void (*data_w)(unsigned int data); unsigned int (*data_r)(void); } port[3]; static void dummy_write(unsigned int data) { } static unsigned int dummy_read(void) { return 0x7F; } /***************************************************************************** * I/O chip functions * * * *****************************************************************************/ void io_init(void) { /* Initialize IO Ports handlers */ switch (input.system[0]) { case SYSTEM_GAMEPAD: port[0].data_w = gamepad_1_write; port[0].data_r = gamepad_1_read; break; case SYSTEM_MOUSE: port[0].data_w = mouse_write; port[0].data_r = mouse_read; break; case SYSTEM_WAYPLAY: port[0].data_w = wayplay_1_write; port[0].data_r = wayplay_1_read; break; case SYSTEM_TEAMPLAYER: port[0].data_w = teamplayer_1_write; port[0].data_r = teamplayer_1_read; break; default: port[0].data_w = dummy_write; port[0].data_r = dummy_read; break; } switch (input.system[1]) { case SYSTEM_GAMEPAD: port[1].data_w = gamepad_2_write; port[1].data_r = gamepad_2_read; break; case SYSTEM_MOUSE: port[1].data_w = mouse_write; port[1].data_r = mouse_read; break; case SYSTEM_MENACER: port[1].data_w = dummy_write; port[1].data_r = menacer_read; break; case SYSTEM_JUSTIFIER: port[1].data_w = dummy_write; port[1].data_r = justifier_read; break; case SYSTEM_WAYPLAY: port[1].data_w = wayplay_2_write; port[1].data_r = wayplay_2_read; break; case SYSTEM_TEAMPLAYER: port[1].data_w = teamplayer_2_write; port[1].data_r = teamplayer_2_read; break; default: port[1].data_w = dummy_write; port[1].data_r = dummy_read; break; } /* External Port (unconnected) */ port[2].data_w = dummy_write; port[2].data_r = dummy_read; /* Initialize connected input devices */ input_init(); } void io_reset(void) { /* Reset I/O registers */ io_reg[0x00] = region_code | 0x20 | (config.tmss & 1); io_reg[0x01] = 0x00; io_reg[0x02] = 0x00; io_reg[0x03] = 0x00; io_reg[0x04] = 0x00; io_reg[0x05] = 0x00; io_reg[0x06] = 0x00; io_reg[0x07] = 0xFF; io_reg[0x08] = 0x00; io_reg[0x09] = 0x00; io_reg[0x0A] = 0xFF; io_reg[0x0B] = 0x00; io_reg[0x0C] = 0x00; io_reg[0x0D] = 0xFB; io_reg[0x0E] = 0x00; io_reg[0x0F] = 0x00; /* Reset connected input devices */ input_reset(); } void io_write(unsigned int offset, unsigned int data) { switch (offset) { case 0x01: /* Port A Data */ case 0x02: /* Port B Data */ case 0x03: /* Port C Data */ io_reg[offset] = data; port[offset-1].data_w(data); return; case 0x04: /* Port A Ctrl */ case 0x05: /* Port B Ctrl */ case 0x06: /* Port C Ctrl */ if (data != io_reg[offset]) { io_reg[offset] = data; port[offset-4].data_w(io_reg[offset-3]); } return; case 0x07: /* Port A TxData */ case 0x0A: /* Port B TxData */ case 0x0D: /* Port C TxData */ io_reg[offset] = data; return; case 0x09: /* Port A S-Ctrl */ case 0x0C: /* Port B S-Ctrl */ case 0x0F: /* Port C S-Ctrl */ io_reg[offset] = data & 0xF8; return; default: /* Read-only ports */ return; } } unsigned int io_read(unsigned int offset) { switch(offset) { case 0x01: /* Port A Data */ case 0x02: /* Port B Data */ case 0x03: /* Port C Data */ { unsigned int mask = 0x80 | io_reg[offset + 3]; unsigned int data = port[offset-1].data_r(); return (io_reg[offset] & mask) | (data & ~mask); } default: /* return register value */ return io_reg[offset]; } }