filename | src/maple/maple.c |
changeset | 450:207461e79f21 |
prev | 447:3e095bfcb476 |
next | 480:d28c2992f5ee |
author | nkeynes |
date | Wed Oct 17 11:26:45 2007 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Split config management out to config.[ch] Manage config filename Check home dir + sysconfdir for conf file Initial work on a path settings dialog |
view | annotate | diff | log | raw |
1 /**
2 * $Id: maple.c,v 1.11 2007-10-17 11:26:45 nkeynes Exp $
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 "dream.h"
22 #include "mem.h"
23 #include "asic.h"
24 #include "maple.h"
26 void maple_init( void );
28 struct dreamcast_module maple_module = { "Maple", maple_init, NULL, NULL, NULL,
29 NULL, NULL, NULL };
31 struct maple_device_class *maple_device_classes[] = { &controller_class, NULL };
33 void maple_init( void )
34 {
36 }
38 maple_device_t maple_new_device( const gchar *name )
39 {
40 maple_device_class_t clz = maple_get_device_class(name);
41 if( clz != NULL ) {
42 return clz->new_device();
43 }
44 return NULL;
45 }
47 const maple_device_class_t maple_get_device_class( const gchar *name )
48 {
49 int i;
50 for( i=0; maple_device_classes[i] != NULL; i++ ) {
51 if( g_strcasecmp(maple_device_classes[i]->name, name ) == 0 )
52 return maple_device_classes[i];
53 }
54 return NULL;
55 }
57 const struct maple_device_class **maple_get_device_classes()
58 {
59 return maple_device_classes;
60 }
62 lxdream_config_entry_t maple_get_device_config( maple_device_t dev )
63 {
64 if( dev->get_config == NULL )
65 return NULL;
66 return dev->get_config(dev);
67 }
69 /**
70 * Input data looks like this:
71 * 0: transfer control word
72 * 0: length of data in words (not including 3 word header)
73 * 1: low bit = lightgun mode
74 * 2: low 2 bits = port # (0..3)
75 * 3: 0x80 = last packet, 0x00 = normal packet
76 * 4: output buffer address
77 * 8: Command word
78 * 8: command code
79 * 9: destination address
80 * 10: source address
81 * 11: length of data in words (not including 3 word header)
82 * 12: command-specific data
83 */
85 /**
86 * array is [port][subperipheral], so [0][0] is main peripheral on port A,
87 * [1][2] is the second subperipheral on port B and so on.
88 */
89 maple_device_t maple_devices[4][6];
90 int maple_periph_mask[4];
91 #define GETBYTE(n) ((uint32_t)(buf[n]))
92 #define GETWORD(n) (*((uint32_t *)(buf+(n))))
93 #define PUTBYTE(n,x) (buf[n] = (char)x)
94 #define PUTWORD(n,x) (*((uint32_t *)(return_buf+(n))) = (x))
96 maple_device_t maple_get_device( unsigned int port, unsigned int periph ) {
97 if( port >= 4 )
98 return NULL;
99 if( periph >= 6 )
100 return NULL;
101 return maple_devices[port][periph];
102 }
104 void maple_handle_buffer( uint32_t address ) {
105 unsigned char *buf = (unsigned char *)mem_get_region(address);
106 if( buf == NULL ) {
107 ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
108 } else {
109 unsigned int last = 0;
110 int i = 0, count;
111 for( count=0; !last; count++ ) {
112 unsigned int port, length, gun, periph, periph_id, out_length;
113 unsigned int cmd, recv_addr, send_addr;
114 uint32_t return_addr;
115 unsigned char *return_buf;
117 last = GETBYTE(3) & 0x80; /* indicates last packet */
118 port = GETBYTE(2) & 0x03;
119 gun = GETBYTE(1) & 0x01;
120 length = GETBYTE(0) & 0xFF;
121 return_addr = GETWORD(4);
123 if( (return_addr & 0x1C000000) != 0x0C000000 ) {
124 ERROR( "Bad return address in maple packet: %08X", return_addr );
125 break;
126 }
127 return_buf = mem_get_region(return_addr);
128 cmd = GETBYTE(8);
129 recv_addr = GETBYTE(9);
130 send_addr = GETBYTE(10);
131 /* Sanity checks */
132 if( GETBYTE(11) != length ||
133 send_addr >> 6 != port ||
134 recv_addr >> 6 != port ||
135 return_buf == NULL ) {
136 ERROR( "Received bad packet: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
137 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
138 buf[8], buf[9], buf[10], buf[11] );
139 break;
140 }
141 periph = 0;
142 periph_id = recv_addr & 0x3F;
143 if( periph_id != 0x20 ) {
144 for( i=0;i<5;i++ ) {
145 if( periph_id == (1<<i) ) {
146 periph = i+1;
147 break;
148 }
149 }
150 if( periph == 0 ) { /* Bad setting */
151 /* ERROR */
152 }
153 }
155 maple_device_t dev = maple_devices[port][periph];
156 if( dev == NULL ) {
157 /* no device attached */
158 *((uint32_t *)return_buf) = -1;
159 } else {
160 int status, func, block;
161 out_length = 0;
162 switch( cmd ) {
163 case MAPLE_CMD_INFO:
164 status = MAPLE_RESP_INFO;
165 memcpy( return_buf+4, dev->ident, 112 );
166 out_length = 0x1C;
167 break;
168 case MAPLE_CMD_EXT_INFO:
169 status = MAPLE_RESP_EXT_INFO;
170 memcpy( return_buf+4, dev->ident, 192 );
171 out_length = 0x30;
172 break;
173 case MAPLE_CMD_RESET:
174 if( dev->reset == NULL )
175 status = MAPLE_RESP_ACK;
176 else status = dev->reset(dev);
177 break;
178 case MAPLE_CMD_SHUTDOWN:
179 if( dev->shutdown == NULL )
180 status = MAPLE_RESP_ACK;
181 else status = dev->shutdown(dev);
182 break;
183 case MAPLE_CMD_GET_COND:
184 func = GETWORD(12);
185 if( dev->get_condition == NULL )
186 status = MAPLE_ERR_CMD_UNKNOWN;
187 else status = dev->get_condition(dev, func,
188 return_buf+8,
189 &out_length );
190 out_length++;
191 if( status == 0 ) {
192 status = MAPLE_RESP_DATA;
193 PUTWORD(4,func);
194 }
195 break;
196 case MAPLE_CMD_SET_COND:
197 func = GETWORD(12);
198 if( dev->set_condition == NULL )
199 status = MAPLE_ERR_CMD_UNKNOWN;
200 else status = dev->set_condition(dev, func,
201 buf+16,
202 length);
203 if( status == 0 )
204 status = MAPLE_RESP_ACK;
205 break;
206 case MAPLE_CMD_READ_BLOCK:
207 func = GETWORD(12);
208 block = GETWORD(16);
209 if( dev->read_block == NULL )
210 status = MAPLE_ERR_CMD_UNKNOWN;
211 else status = dev->read_block(dev, func, block,
212 return_buf+12,
213 &out_length );
214 if( status == 0 ) {
215 status = MAPLE_RESP_DATA;
216 PUTWORD(4,func);
217 PUTWORD(8,block);
218 }
219 break;
220 case MAPLE_CMD_WRITE_BLOCK:
221 func = GETWORD(12);
222 block = GETWORD(16);
223 if( dev->write_block == NULL )
224 status = MAPLE_ERR_CMD_UNKNOWN;
225 else {
226 status = dev->write_block(dev, func, block,
227 buf+20, length);
228 if( status == 0 )
229 status = MAPLE_RESP_ACK;
230 }
231 break;
232 default:
233 status = MAPLE_ERR_CMD_UNKNOWN;
234 }
235 return_buf[0] = status;
236 return_buf[1] = send_addr;
237 return_buf[2] = recv_addr;
238 if( periph == 0 )
239 return_buf[2] |= maple_periph_mask[port];
240 return_buf[3] = out_length;
241 }
242 buf += 12 + (length<<2);
243 address += 12 + (length<<2);
244 }
245 asic_event( EVENT_MAPLE_DMA );
246 }
247 }
249 void maple_attach_device( maple_device_t dev, unsigned int port,
250 unsigned int periph ) {
251 assert( port < 4 );
252 assert( periph < 6 );
254 if( maple_devices[port][periph] != NULL ) {
255 /* Detach existing peripheral first */
256 maple_detach_device( port, periph );
257 }
259 maple_devices[port][periph] = dev;
260 if( periph != 0 )
261 maple_periph_mask[port] |= (1<<(periph-1));
262 else maple_periph_mask[port] |= 0x20;
263 if( dev->attach != NULL ) {
264 dev->attach( dev );
265 }
266 }
268 void maple_detach_device( unsigned int port, unsigned int periph ) {
269 assert( port < 4 );
270 assert( periph < 6 );
272 maple_device_t dev = maple_devices[port][periph];
273 if( dev == NULL ) /* already detached */
274 return;
275 maple_devices[port][periph] = NULL;
276 if( dev->detach != NULL ) {
277 dev->detach(dev);
278 }
279 if( dev->destroy != NULL ) {
280 dev->destroy(dev);
281 }
282 if( periph == 0 ) {
283 /* If we detach the main peripheral, we also have to detach all the
284 * subperipherals, or the system could get quite confused
285 */
286 int i;
287 maple_periph_mask[port] = 0;
288 for( i=1; i<6; i++ ) {
289 maple_detach_device(port,i);
290 }
291 } else {
292 maple_periph_mask[port] &= (~(1<<(periph-1)));
293 }
295 }
297 void maple_detach_all() {
298 int i, j;
299 for( i=0; i<4; i++ ) {
300 for( j=0; j<6; j++ ) {
301 if( maple_devices[i][j] != NULL ) {
302 maple_device_t dev = maple_devices[i][j];
303 if( dev->detach != NULL )
304 dev->detach(dev);
305 if( dev->destroy != NULL )
306 dev->destroy(dev);
307 }
308 }
309 maple_periph_mask[i] = 0;
310 }
311 }
313 void maple_reattach_all() {
314 int i, j;
315 for( i=0; i<4; i++ ) {
316 for( j=0; j<6; j++ ) {
317 if( maple_devices[i][j] != NULL ) {
318 maple_device_t dev = maple_devices[i][j];
319 if( dev->attach != NULL )
320 dev->attach(dev);
321 }
322 }
323 }
324 }
.