filename | src/maple/maple.c |
changeset | 561:533f6b478071 |
prev | 494:67c133a17400 |
next | 608:4f588e52bce0 |
author | nkeynes |
date | Mon Jan 21 11:59:46 2008 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Fix MAC.L/MAC.W stack issues Fix various recovery-table issues |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Implements the core Maple bus, including DMA transfers to and from the bus.
5 *
6 * Copyright (c) 2005 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18 #define MODULE maple_module
20 #include <assert.h>
21 #include <glib/gstrfuncs.h>
22 #include "dream.h"
23 #include "mem.h"
24 #include "asic.h"
25 #include "maple.h"
27 void maple_init( void );
29 struct dreamcast_module maple_module = { "Maple", maple_init, NULL, NULL, NULL,
30 NULL, NULL, NULL };
32 struct maple_device_class *maple_device_classes[] = { &controller_class, NULL };
34 void maple_init( void )
35 {
37 }
39 maple_device_t maple_new_device( const gchar *name )
40 {
41 maple_device_class_t clz = maple_get_device_class(name);
42 if( clz != NULL ) {
43 return clz->new_device();
44 }
45 return NULL;
46 }
48 maple_device_class_t maple_get_device_class( const gchar *name )
49 {
50 int i;
51 for( i=0; maple_device_classes[i] != NULL; i++ ) {
52 if( g_strcasecmp(maple_device_classes[i]->name, name ) == 0 )
53 return maple_device_classes[i];
54 }
55 return NULL;
56 }
58 const struct maple_device_class **maple_get_device_classes()
59 {
60 return (const struct maple_device_class **)maple_device_classes;
61 }
63 lxdream_config_entry_t maple_get_device_config( maple_device_t dev )
64 {
65 if( dev->get_config == NULL )
66 return NULL;
67 return dev->get_config(dev);
68 }
70 /**
71 * Input data looks like this:
72 * 0: transfer control word
73 * 0: length of data in words (not including 3 word header)
74 * 1: low bit = lightgun mode
75 * 2: low 2 bits = port # (0..3)
76 * 3: 0x80 = last packet, 0x00 = normal packet
77 * 4: output buffer address
78 * 8: Command word
79 * 8: command code
80 * 9: destination address
81 * 10: source address
82 * 11: length of data in words (not including 3 word header)
83 * 12: command-specific data
84 */
86 /**
87 * array is [port][subperipheral], so [0][0] is main peripheral on port A,
88 * [1][2] is the second subperipheral on port B and so on.
89 */
90 maple_device_t maple_devices[4][6];
91 int maple_periph_mask[4];
92 #define GETBYTE(n) ((uint32_t)(buf[n]))
93 #define GETWORD(n) (*((uint32_t *)(buf+(n))))
94 #define PUTBYTE(n,x) (buf[n] = (char)x)
95 #define PUTWORD(n,x) (*((uint32_t *)(return_buf+(n))) = (x))
97 maple_device_t maple_get_device( unsigned int port, unsigned int periph ) {
98 if( port >= 4 )
99 return NULL;
100 if( periph >= 6 )
101 return NULL;
102 return maple_devices[port][periph];
103 }
105 void maple_handle_buffer( uint32_t address ) {
106 unsigned char *buf = (unsigned char *)mem_get_region(address);
107 if( buf == NULL ) {
108 ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
109 } else {
110 unsigned int last = 0;
111 int i = 0, count;
112 for( count=0; !last; count++ ) {
113 unsigned int port, length, mode, periph, periph_id, out_length;
114 unsigned int cmd, recv_addr, send_addr;
115 uint32_t return_addr;
116 unsigned char *return_buf;
118 last = GETBYTE(3) & 0x80; /* indicates last packet */
119 port = GETBYTE(2) & 0x03;
120 mode = GETBYTE(1) & 0x07;
121 length = GETBYTE(0) & 0xFF;
122 return_addr = GETWORD(4);
124 if( mode == 0x07 ) {
125 buf += 4;
126 address +=4; /* skip? */
127 continue;
128 }
129 if( (return_addr & 0x1C000000) != 0x0C000000 ) {
130 ERROR( "Bad return address in maple packet: %08X", return_addr );
131 break;
132 }
133 return_buf = mem_get_region(return_addr);
134 cmd = GETBYTE(8);
135 recv_addr = GETBYTE(9);
136 send_addr = GETBYTE(10);
137 /* Sanity checks */
138 if( GETBYTE(11) != length ||
139 send_addr >> 6 != port ||
140 recv_addr >> 6 != port ||
141 return_buf == NULL ) {
142 ERROR( "Received bad packet: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
143 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
144 buf[8], buf[9], buf[10], buf[11] );
145 break;
146 }
147 periph = 0;
148 periph_id = recv_addr & 0x3F;
149 if( periph_id != 0x20 ) {
150 for( i=0;i<5;i++ ) {
151 if( periph_id == (1<<i) ) {
152 periph = i+1;
153 break;
154 }
155 }
156 if( periph == 0 ) { /* Bad setting */
157 /* ERROR */
158 }
159 }
161 maple_device_t dev = maple_devices[port][periph];
162 if( dev == NULL ) {
163 /* no device attached */
164 *((uint32_t *)return_buf) = -1;
165 } else {
166 int status, func, block;
167 out_length = 0;
168 switch( cmd ) {
169 case MAPLE_CMD_INFO:
170 status = MAPLE_RESP_INFO;
171 memcpy( return_buf+4, dev->ident, 112 );
172 out_length = 0x1C;
173 break;
174 case MAPLE_CMD_EXT_INFO:
175 status = MAPLE_RESP_EXT_INFO;
176 memcpy( return_buf+4, dev->ident, 192 );
177 out_length = 0x30;
178 break;
179 case MAPLE_CMD_RESET:
180 if( dev->reset == NULL )
181 status = MAPLE_RESP_ACK;
182 else status = dev->reset(dev);
183 break;
184 case MAPLE_CMD_SHUTDOWN:
185 if( dev->shutdown == NULL )
186 status = MAPLE_RESP_ACK;
187 else status = dev->shutdown(dev);
188 break;
189 case MAPLE_CMD_GET_COND:
190 func = GETWORD(12);
191 if( dev->get_condition == NULL )
192 status = MAPLE_ERR_CMD_UNKNOWN;
193 else status = dev->get_condition(dev, func,
194 return_buf+8,
195 &out_length );
196 out_length++;
197 if( status == 0 ) {
198 status = MAPLE_RESP_DATA;
199 PUTWORD(4,func);
200 }
201 break;
202 case MAPLE_CMD_SET_COND:
203 func = GETWORD(12);
204 if( dev->set_condition == NULL )
205 status = MAPLE_ERR_CMD_UNKNOWN;
206 else status = dev->set_condition(dev, func,
207 buf+16,
208 length);
209 if( status == 0 )
210 status = MAPLE_RESP_ACK;
211 break;
212 case MAPLE_CMD_READ_BLOCK:
213 func = GETWORD(12);
214 block = GETWORD(16);
215 if( dev->read_block == NULL )
216 status = MAPLE_ERR_CMD_UNKNOWN;
217 else status = dev->read_block(dev, func, block,
218 return_buf+12,
219 &out_length );
220 if( status == 0 ) {
221 status = MAPLE_RESP_DATA;
222 PUTWORD(4,func);
223 PUTWORD(8,block);
224 }
225 break;
226 case MAPLE_CMD_WRITE_BLOCK:
227 func = GETWORD(12);
228 block = GETWORD(16);
229 if( dev->write_block == NULL )
230 status = MAPLE_ERR_CMD_UNKNOWN;
231 else {
232 status = dev->write_block(dev, func, block,
233 buf+20, length);
234 if( status == 0 )
235 status = MAPLE_RESP_ACK;
236 }
237 break;
238 default:
239 status = MAPLE_ERR_CMD_UNKNOWN;
240 }
241 return_buf[0] = status;
242 return_buf[1] = send_addr;
243 return_buf[2] = recv_addr;
244 if( periph == 0 )
245 return_buf[2] |= maple_periph_mask[port];
246 return_buf[3] = out_length;
247 }
248 buf += 12 + (length<<2);
249 address += 12 + (length<<2);
250 }
251 asic_event( EVENT_MAPLE_DMA );
252 }
253 }
255 void maple_attach_device( maple_device_t dev, unsigned int port,
256 unsigned int periph ) {
257 assert( port < 4 );
258 assert( periph < 6 );
260 if( maple_devices[port][periph] != NULL ) {
261 /* Detach existing peripheral first */
262 maple_detach_device( port, periph );
263 }
265 maple_devices[port][periph] = dev;
266 if( periph != 0 )
267 maple_periph_mask[port] |= (1<<(periph-1));
268 else maple_periph_mask[port] |= 0x20;
269 if( dev->attach != NULL ) {
270 dev->attach( dev );
271 }
272 }
274 void maple_detach_device( unsigned int port, unsigned int periph ) {
275 assert( port < 4 );
276 assert( periph < 6 );
278 maple_device_t dev = maple_devices[port][periph];
279 if( dev == NULL ) /* already detached */
280 return;
281 maple_devices[port][periph] = NULL;
282 if( dev->detach != NULL ) {
283 dev->detach(dev);
284 }
285 if( dev->destroy != NULL ) {
286 dev->destroy(dev);
287 }
288 if( periph == 0 ) {
289 /* If we detach the main peripheral, we also have to detach all the
290 * subperipherals, or the system could get quite confused
291 */
292 int i;
293 maple_periph_mask[port] = 0;
294 for( i=1; i<6; i++ ) {
295 maple_detach_device(port,i);
296 }
297 } else {
298 maple_periph_mask[port] &= (~(1<<(periph-1)));
299 }
301 }
303 void maple_detach_all() {
304 int i, j;
305 for( i=0; i<4; i++ ) {
306 for( j=0; j<6; j++ ) {
307 if( maple_devices[i][j] != NULL ) {
308 maple_device_t dev = maple_devices[i][j];
309 if( dev->detach != NULL )
310 dev->detach(dev);
311 if( dev->destroy != NULL )
312 dev->destroy(dev);
313 }
314 }
315 maple_periph_mask[i] = 0;
316 }
317 }
319 void maple_reattach_all() {
320 int i, j;
321 for( i=0; i<4; i++ ) {
322 for( j=0; j<6; j++ ) {
323 if( maple_devices[i][j] != NULL ) {
324 maple_device_t dev = maple_devices[i][j];
325 if( dev->attach != NULL )
326 dev->attach(dev);
327 }
328 }
329 }
330 }
.