rev |
line source |
nuclear@2
|
1 /*
|
nuclear@2
|
2 gbasys - a gameboy advance hardware abstraction library
|
nuclear@3
|
3 Copyright (C) 2004-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 }
|