gbasys
diff src/comm.c @ 2:e3dc7705ad9c
communications stuff
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 07 Mar 2012 06:11:51 +0200 |
parents | |
children | 06726f0b8cd3 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/comm.c Wed Mar 07 06:11:51 2012 +0200 1.3 @@ -0,0 +1,187 @@ 1.4 +/* 1.5 +gbasys - a gameboy advance hardware abstraction library 1.6 +Copyright (C) 2005-2012 John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.20 +*/ 1.21 + 1.22 +#include "comm.h" 1.23 +#include "error.h" 1.24 +#include "signal.h" 1.25 +#include "intr.h" 1.26 + 1.27 +#define REG_SIODATA32 *((volatile unsigned short*)0x4000120) 1.28 +#define REG_SIOCNT *((volatile unsigned short*)0x4000128) 1.29 +#define REG_SIODATA8 *((volatile unsigned short*)0x400012a) 1.30 +#define REG_RCNT *((volatile unsigned short*)0x4000134) 1.31 + 1.32 +/* REG_SIOCNT bits */ 1.33 +#define SIOCNT_CLK_INTERN (1 << 0) 1.34 +#define SIOCNT_CLK_2MHZ (1 << 1) 1.35 +#define SIOCNT_RECV_ENABLE (1 << 2) 1.36 +#define SIOCNT_SEND_ENABLE (1 << 3) 1.37 +#define SIOCNT_START (1 << 7) 1.38 +#define SIOCNT_XFER_LEN (1 << 12) 1.39 +#define SIOCNT_INT_ENABLE (1 << 14) 1.40 + 1.41 +/* only in 16bit multi player mode */ 1.42 +#define SIOCNT_BAUD_38400 1 1.43 +#define SIOCNT_BAUD_57600 2 1.44 +#define SIOCNT_BAUD_115200 3 1.45 +#define SIOCNT_SI_STATUS (1 << 2) 1.46 +#define SIOCNT_SD_STATUS (1 << 3) 1.47 +#define SIOCNT_SLAVE1 (1 << 4) 1.48 +#define SIOCNT_SLAVE2 (2 << 4) 1.49 +#define SIOCNT_SLAVE3 (3 << 4) 1.50 +#define SIOCNT_ERROR (1 << 6) 1.51 + 1.52 +/* REG_RCNT bits */ 1.53 +#define RCNT_GPIO_DATA_MASK 0x000f 1.54 +#define RCNT_GPIO_DIR_MASK 0x00f0 1.55 +#define RCNT_GPIO_INT_ENABLE (1 << 8) 1.56 +#define RCNT_MODE_GPIO 0x8000 1.57 +#define RCNT_MODE_JOYBUS 0xc000 1.58 + 1.59 + 1.60 +static void setup_sio(int bits, int ms); 1.61 +static void setup_gpio(void); 1.62 +static void comm_intr(void); 1.63 + 1.64 +static int sio_bits, sio_master; 1.65 +static void *sio_buf; 1.66 + 1.67 + 1.68 +void comm_setup(int mode) 1.69 +{ 1.70 + int master = 0; 1.71 + 1.72 + mask(INTR_COMM); 1.73 + interrupt(INTR_COMM, comm_intr); 1.74 + unmask(INTR_COMM); 1.75 + 1.76 + switch(mode) { 1.77 + case COMM_SIO8_MASTER: 1.78 + master = 1; 1.79 + case COMM_SIO8_SLAVE: 1.80 + setup_sio(8, master); 1.81 + break; 1.82 + 1.83 + case COMM_SIO32_MASTER: 1.84 + master = 1; 1.85 + case COMM_SIO32_SLAVE: 1.86 + setup_sio(32, master); 1.87 + break; 1.88 + 1.89 + case COMM_GPIO: 1.90 + setup_gpio(); 1.91 + break; 1.92 + 1.93 + default: 1.94 + panic("unimplemented comm mode\n"); 1.95 + } 1.96 +} 1.97 + 1.98 +static void setup_sio(int bits, int ms) 1.99 +{ 1.100 + REG_RCNT = 0; /* serial mode */ 1.101 + 1.102 + sio_bits = bits; 1.103 + sio_master = ms; 1.104 +} 1.105 + 1.106 +void sio_transfer(void *in, const void *out) 1.107 +{ 1.108 + /* load outgoing data */ 1.109 + if(sio_bits <= 8) { 1.110 + REG_SIODATA8 = *(unsigned char*)out; 1.111 + } else { 1.112 + REG_SIODATA32 = *(unsigned long*)out; 1.113 + } 1.114 + sio_buf = in; 1.115 + 1.116 + /* IE=1, external clock, send enable */ 1.117 + REG_SIOCNT = SIOCNT_INT_ENABLE | SIOCNT_SEND_ENABLE; 1.118 + 1.119 + /* start transfer */ 1.120 + REG_SIOCNT |= SIOCNT_START; 1.121 + 1.122 + /* wait until the transfer is complete */ 1.123 + while(REG_SIOCNT & SIOCNT_START); 1.124 +} 1.125 + 1.126 +void sio_transfer_async(void *in, const void *out) 1.127 +{ 1.128 + /* load outgoing data */ 1.129 + if(sio_bits <= 8) { 1.130 + REG_SIODATA8 = *(unsigned char*)out; 1.131 + } else { 1.132 + REG_SIODATA32 = *(unsigned long*)out; 1.133 + } 1.134 + sio_buf = in; 1.135 + 1.136 + /* IE=1, external clock, send enable */ 1.137 + REG_SIOCNT = SIOCNT_INT_ENABLE | SIOCNT_SEND_ENABLE; 1.138 + 1.139 + /* start transfer */ 1.140 + REG_SIOCNT |= SIOCNT_START; 1.141 +} 1.142 + 1.143 + 1.144 +static void setup_gpio(void) 1.145 +{ 1.146 + REG_RCNT = RCNT_MODE_GPIO | RCNT_GPIO_INT_ENABLE; 1.147 +} 1.148 + 1.149 +void gpio_dir(int dir_so, int dir_si, int dir_sd, int dir_sc) 1.150 +{ 1.151 + unsigned char mask; 1.152 + 1.153 + mask = ((dir_so & 1) << 7) | ((dir_si & 1) << 6) | ((dir_sd & 1) << 5) | 1.154 + ((dir_sc & 1) << 4); 1.155 + gpio_dir_mask(mask); 1.156 +} 1.157 + 1.158 +void gpio_dir_mask(unsigned char dir) 1.159 +{ 1.160 + REG_RCNT = (REG_RCNT & 0xff0f) | ((dir & 0xf) << 4); 1.161 +} 1.162 + 1.163 +void gpio_set(unsigned char val) 1.164 +{ 1.165 + REG_RCNT = (REG_RCNT & 0xfff0) | (val & 0xf); 1.166 +} 1.167 + 1.168 +unsigned char gpio_get(void) 1.169 +{ 1.170 + return REG_RCNT & 0xf; 1.171 +} 1.172 + 1.173 +static void comm_intr(void) 1.174 +{ 1.175 + if(sio_buf) { 1.176 + if(REG_SIOCNT & SIOCNT_START) { 1.177 + panic("asio: interrupt with start bit == 1"); 1.178 + } 1.179 + if(sio_bits <= 8) { 1.180 + *(unsigned char*)sio_buf = REG_SIODATA8; 1.181 + } else { 1.182 + *(unsigned long*)sio_buf = REG_SIODATA32; 1.183 + } 1.184 + sio_buf = 0; 1.185 + } 1.186 + 1.187 + if(signal_func(SIGIO)) { 1.188 + raise(SIGIO); 1.189 + } 1.190 +}