gbasys

annotate 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
rev   line source
nuclear@2 1 /*
nuclear@2 2 gbasys - a gameboy advance hardware abstraction library
nuclear@2 3 Copyright (C) 2005-2012 John Tsiombikas <nuclear@member.fsf.org>
nuclear@2 4
nuclear@2 5 This program is free software: you can redistribute it and/or modify
nuclear@2 6 it under the terms of the GNU General Public License as published by
nuclear@2 7 the Free Software Foundation, either version 3 of the License, or
nuclear@2 8 (at your option) any later version.
nuclear@2 9
nuclear@2 10 This program is distributed in the hope that it will be useful,
nuclear@2 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
nuclear@2 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
nuclear@2 13 GNU General Public License for more details.
nuclear@2 14
nuclear@2 15 You should have received a copy of the GNU General Public License
nuclear@2 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
nuclear@2 17 */
nuclear@2 18
nuclear@2 19 #include "comm.h"
nuclear@2 20 #include "error.h"
nuclear@2 21 #include "signal.h"
nuclear@2 22 #include "intr.h"
nuclear@2 23
nuclear@2 24 #define REG_SIODATA32 *((volatile unsigned short*)0x4000120)
nuclear@2 25 #define REG_SIOCNT *((volatile unsigned short*)0x4000128)
nuclear@2 26 #define REG_SIODATA8 *((volatile unsigned short*)0x400012a)
nuclear@2 27 #define REG_RCNT *((volatile unsigned short*)0x4000134)
nuclear@2 28
nuclear@2 29 /* REG_SIOCNT bits */
nuclear@2 30 #define SIOCNT_CLK_INTERN (1 << 0)
nuclear@2 31 #define SIOCNT_CLK_2MHZ (1 << 1)
nuclear@2 32 #define SIOCNT_RECV_ENABLE (1 << 2)
nuclear@2 33 #define SIOCNT_SEND_ENABLE (1 << 3)
nuclear@2 34 #define SIOCNT_START (1 << 7)
nuclear@2 35 #define SIOCNT_XFER_LEN (1 << 12)
nuclear@2 36 #define SIOCNT_INT_ENABLE (1 << 14)
nuclear@2 37
nuclear@2 38 /* only in 16bit multi player mode */
nuclear@2 39 #define SIOCNT_BAUD_38400 1
nuclear@2 40 #define SIOCNT_BAUD_57600 2
nuclear@2 41 #define SIOCNT_BAUD_115200 3
nuclear@2 42 #define SIOCNT_SI_STATUS (1 << 2)
nuclear@2 43 #define SIOCNT_SD_STATUS (1 << 3)
nuclear@2 44 #define SIOCNT_SLAVE1 (1 << 4)
nuclear@2 45 #define SIOCNT_SLAVE2 (2 << 4)
nuclear@2 46 #define SIOCNT_SLAVE3 (3 << 4)
nuclear@2 47 #define SIOCNT_ERROR (1 << 6)
nuclear@2 48
nuclear@2 49 /* REG_RCNT bits */
nuclear@2 50 #define RCNT_GPIO_DATA_MASK 0x000f
nuclear@2 51 #define RCNT_GPIO_DIR_MASK 0x00f0
nuclear@2 52 #define RCNT_GPIO_INT_ENABLE (1 << 8)
nuclear@2 53 #define RCNT_MODE_GPIO 0x8000
nuclear@2 54 #define RCNT_MODE_JOYBUS 0xc000
nuclear@2 55
nuclear@2 56
nuclear@2 57 static void setup_sio(int bits, int ms);
nuclear@2 58 static void setup_gpio(void);
nuclear@2 59 static void comm_intr(void);
nuclear@2 60
nuclear@2 61 static int sio_bits, sio_master;
nuclear@2 62 static void *sio_buf;
nuclear@2 63
nuclear@2 64
nuclear@2 65 void comm_setup(int mode)
nuclear@2 66 {
nuclear@2 67 int master = 0;
nuclear@2 68
nuclear@2 69 mask(INTR_COMM);
nuclear@2 70 interrupt(INTR_COMM, comm_intr);
nuclear@2 71 unmask(INTR_COMM);
nuclear@2 72
nuclear@2 73 switch(mode) {
nuclear@2 74 case COMM_SIO8_MASTER:
nuclear@2 75 master = 1;
nuclear@2 76 case COMM_SIO8_SLAVE:
nuclear@2 77 setup_sio(8, master);
nuclear@2 78 break;
nuclear@2 79
nuclear@2 80 case COMM_SIO32_MASTER:
nuclear@2 81 master = 1;
nuclear@2 82 case COMM_SIO32_SLAVE:
nuclear@2 83 setup_sio(32, master);
nuclear@2 84 break;
nuclear@2 85
nuclear@2 86 case COMM_GPIO:
nuclear@2 87 setup_gpio();
nuclear@2 88 break;
nuclear@2 89
nuclear@2 90 default:
nuclear@2 91 panic("unimplemented comm mode\n");
nuclear@2 92 }
nuclear@2 93 }
nuclear@2 94
nuclear@2 95 static void setup_sio(int bits, int ms)
nuclear@2 96 {
nuclear@2 97 REG_RCNT = 0; /* serial mode */
nuclear@2 98
nuclear@2 99 sio_bits = bits;
nuclear@2 100 sio_master = ms;
nuclear@2 101 }
nuclear@2 102
nuclear@2 103 void sio_transfer(void *in, const void *out)
nuclear@2 104 {
nuclear@2 105 /* load outgoing data */
nuclear@2 106 if(sio_bits <= 8) {
nuclear@2 107 REG_SIODATA8 = *(unsigned char*)out;
nuclear@2 108 } else {
nuclear@2 109 REG_SIODATA32 = *(unsigned long*)out;
nuclear@2 110 }
nuclear@2 111 sio_buf = in;
nuclear@2 112
nuclear@2 113 /* IE=1, external clock, send enable */
nuclear@2 114 REG_SIOCNT = SIOCNT_INT_ENABLE | SIOCNT_SEND_ENABLE;
nuclear@2 115
nuclear@2 116 /* start transfer */
nuclear@2 117 REG_SIOCNT |= SIOCNT_START;
nuclear@2 118
nuclear@2 119 /* wait until the transfer is complete */
nuclear@2 120 while(REG_SIOCNT & SIOCNT_START);
nuclear@2 121 }
nuclear@2 122
nuclear@2 123 void sio_transfer_async(void *in, const void *out)
nuclear@2 124 {
nuclear@2 125 /* load outgoing data */
nuclear@2 126 if(sio_bits <= 8) {
nuclear@2 127 REG_SIODATA8 = *(unsigned char*)out;
nuclear@2 128 } else {
nuclear@2 129 REG_SIODATA32 = *(unsigned long*)out;
nuclear@2 130 }
nuclear@2 131 sio_buf = in;
nuclear@2 132
nuclear@2 133 /* IE=1, external clock, send enable */
nuclear@2 134 REG_SIOCNT = SIOCNT_INT_ENABLE | SIOCNT_SEND_ENABLE;
nuclear@2 135
nuclear@2 136 /* start transfer */
nuclear@2 137 REG_SIOCNT |= SIOCNT_START;
nuclear@2 138 }
nuclear@2 139
nuclear@2 140
nuclear@2 141 static void setup_gpio(void)
nuclear@2 142 {
nuclear@2 143 REG_RCNT = RCNT_MODE_GPIO | RCNT_GPIO_INT_ENABLE;
nuclear@2 144 }
nuclear@2 145
nuclear@2 146 void gpio_dir(int dir_so, int dir_si, int dir_sd, int dir_sc)
nuclear@2 147 {
nuclear@2 148 unsigned char mask;
nuclear@2 149
nuclear@2 150 mask = ((dir_so & 1) << 7) | ((dir_si & 1) << 6) | ((dir_sd & 1) << 5) |
nuclear@2 151 ((dir_sc & 1) << 4);
nuclear@2 152 gpio_dir_mask(mask);
nuclear@2 153 }
nuclear@2 154
nuclear@2 155 void gpio_dir_mask(unsigned char dir)
nuclear@2 156 {
nuclear@2 157 REG_RCNT = (REG_RCNT & 0xff0f) | ((dir & 0xf) << 4);
nuclear@2 158 }
nuclear@2 159
nuclear@2 160 void gpio_set(unsigned char val)
nuclear@2 161 {
nuclear@2 162 REG_RCNT = (REG_RCNT & 0xfff0) | (val & 0xf);
nuclear@2 163 }
nuclear@2 164
nuclear@2 165 unsigned char gpio_get(void)
nuclear@2 166 {
nuclear@2 167 return REG_RCNT & 0xf;
nuclear@2 168 }
nuclear@2 169
nuclear@2 170 static void comm_intr(void)
nuclear@2 171 {
nuclear@2 172 if(sio_buf) {
nuclear@2 173 if(REG_SIOCNT & SIOCNT_START) {
nuclear@2 174 panic("asio: interrupt with start bit == 1");
nuclear@2 175 }
nuclear@2 176 if(sio_bits <= 8) {
nuclear@2 177 *(unsigned char*)sio_buf = REG_SIODATA8;
nuclear@2 178 } else {
nuclear@2 179 *(unsigned long*)sio_buf = REG_SIODATA32;
nuclear@2 180 }
nuclear@2 181 sio_buf = 0;
nuclear@2 182 }
nuclear@2 183
nuclear@2 184 if(signal_func(SIGIO)) {
nuclear@2 185 raise(SIGIO);
nuclear@2 186 }
nuclear@2 187 }