filename | src/maple/maple.c |
changeset | 144:7f0714e89aaa |
prev | 121:795fec623ce9 |
next | 159:406161fea392 |
author | nkeynes |
date | Mon May 15 08:28:52 2006 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Rename video_driver to display_driver Add input source to display Implement configuration file support Hook controllers up to configuration |
view | annotate | diff | log | raw |
1 /**
2 * $Id: maple.c,v 1.8 2006-05-15 08:28:52 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 int i;
41 for( i=0; maple_device_classes[i] != NULL; i++ ) {
42 if( g_strcasecmp(maple_device_classes[i]->name, name ) == 0 )
43 return maple_device_classes[i]->new_device();
44 }
45 return NULL;
46 }
48 dreamcast_config_entry_t maple_get_device_config( maple_device_t dev )
49 {
50 if( dev->get_config == NULL )
51 return NULL;
52 return dev->get_config(dev);
53 }
55 /**
56 * Input data looks like this:
57 * 0: transfer control word
58 * 0: length of data in words (not including 3 word header)
59 * 1: low bit = lightgun mode
60 * 2: low 2 bits = port # (0..3)
61 * 3: 0x80 = last packet, 0x00 = normal packet
62 * 4: output buffer address
63 * 8: Command word
64 * 8: command code
65 * 9: destination address
66 * 10: source address
67 * 11: length of data in words (not including 3 word header)
68 * 12: command-specific data
69 */
71 /**
72 * array is [port][subperipheral], so [0][0] is main peripheral on port A,
73 * [1][2] is the second subperipheral on port B and so on.
74 */
75 maple_device_t maple_devices[4][6];
76 int maple_periph_mask[4];
77 #define GETBYTE(n) ((uint32_t)(buf[n]))
78 #define GETWORD(n) (*((uint32_t *)(buf+(n))))
79 #define PUTBYTE(n,x) (buf[n] = (char)x)
80 #define PUTWORD(n,x) (*((uint32_t *)(return_buf+(n))) = (x))
82 maple_device_t maple_get_device( unsigned int port, unsigned int periph ) {
83 if( port >= 4 )
84 return NULL;
85 if( periph >= 6 )
86 return NULL;
87 return maple_devices[port][periph];
88 }
90 void maple_handle_buffer( uint32_t address ) {
91 unsigned char *buf = (unsigned char *)mem_get_region(address);
92 if( buf == NULL ) {
93 ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
94 } else {
95 unsigned int last = 0;
96 int i = 0, count;
97 for( count=0; !last; count++ ) {
98 unsigned int port, length, gun, periph, periph_id, out_length;
99 unsigned int cmd, recv_addr, send_addr;
100 uint32_t return_addr;
101 unsigned char *return_buf;
103 last = GETBYTE(3) & 0x80; /* indicates last packet */
104 port = GETBYTE(2) & 0x03;
105 gun = GETBYTE(1) & 0x01;
106 length = GETBYTE(0) & 0xFF;
107 return_addr = GETWORD(4);
108 if( return_addr == 0 ) {
109 /* ERROR */
110 }
111 return_buf = mem_get_region(return_addr);
112 cmd = GETBYTE(8);
113 recv_addr = GETBYTE(9);
114 send_addr = GETBYTE(10);
115 /* Sanity checks */
116 if( GETBYTE(11) != length ||
117 send_addr != (port<<6) ||
118 recv_addr >> 6 != port ||
119 return_buf == NULL ) {
120 /* ERROR */
121 }
122 periph = 0;
123 periph_id = recv_addr & 0x3F;
124 if( periph_id != 0x20 ) {
125 for( i=0;i<5;i++ ) {
126 if( periph_id == (1<<i) ) {
127 periph = i+1;
128 break;
129 }
130 }
131 if( periph == 0 ) { /* Bad setting */
132 /* ERROR */
133 }
134 }
136 INFO( "Maple packet %d: Cmd %d on port %d device %d", count, cmd, port, periph );
137 maple_device_t dev = maple_devices[port][periph];
138 if( dev == NULL ) {
139 /* no device attached */
140 *((uint32_t *)return_buf) = -1;
141 } else {
142 int status, func, block;
143 out_length = 0;
144 switch( cmd ) {
145 case MAPLE_CMD_INFO:
146 status = MAPLE_RESP_INFO;
147 memcpy( return_buf+4, dev->ident, 112 );
148 out_length = 0x1C;
149 break;
150 case MAPLE_CMD_EXT_INFO:
151 status = MAPLE_RESP_EXT_INFO;
152 memcpy( return_buf+4, dev->ident, 192 );
153 out_length = 0x30;
154 break;
155 case MAPLE_CMD_RESET:
156 if( dev->reset == NULL )
157 status = MAPLE_RESP_ACK;
158 else status = dev->reset(dev);
159 break;
160 case MAPLE_CMD_SHUTDOWN:
161 if( dev->shutdown == NULL )
162 status = MAPLE_RESP_ACK;
163 else status = dev->shutdown(dev);
164 break;
165 case MAPLE_CMD_GET_COND:
166 func = GETWORD(12);
167 if( dev->get_condition == NULL )
168 status = MAPLE_ERR_CMD_UNKNOWN;
169 else status = dev->get_condition(dev, func,
170 return_buf+8,
171 &out_length );
172 out_length++;
173 if( status == 0 ) {
174 status = MAPLE_RESP_DATA;
175 PUTWORD(4,func);
176 }
177 break;
178 case MAPLE_CMD_SET_COND:
179 func = GETWORD(12);
180 if( dev->set_condition == NULL )
181 status = MAPLE_ERR_CMD_UNKNOWN;
182 else status = dev->set_condition(dev, func,
183 buf+16,
184 length);
185 if( status == 0 )
186 status = MAPLE_RESP_ACK;
187 break;
188 case MAPLE_CMD_READ_BLOCK:
189 func = GETWORD(12);
190 block = GETWORD(16);
191 if( dev->read_block == NULL )
192 status = MAPLE_ERR_CMD_UNKNOWN;
193 else status = dev->read_block(dev, func, block,
194 return_buf+12,
195 &out_length );
196 if( status == 0 ) {
197 status = MAPLE_RESP_DATA;
198 PUTWORD(4,func);
199 PUTWORD(8,block);
200 }
201 break;
202 case MAPLE_CMD_WRITE_BLOCK:
203 func = GETWORD(12);
204 block = GETWORD(16);
205 if( dev->write_block == NULL )
206 status = MAPLE_ERR_CMD_UNKNOWN;
207 else {
208 status = dev->write_block(dev, func, block,
209 buf+20, length);
210 if( status == 0 )
211 status = MAPLE_RESP_ACK;
212 }
213 break;
214 default:
215 status = MAPLE_ERR_CMD_UNKNOWN;
216 }
217 return_buf[0] = status;
218 return_buf[1] = send_addr;
219 return_buf[2] = recv_addr;
220 if( periph == 0 )
221 return_buf[2] |= maple_periph_mask[port];
222 return_buf[3] = out_length;
223 }
224 buf += 12 + (length<<2);
225 }
226 asic_event( EVENT_MAPLE_DMA );
227 }
228 }
230 void maple_attach_device( maple_device_t dev, unsigned int port,
231 unsigned int periph ) {
232 assert( port < 4 );
233 assert( periph < 6 );
235 if( maple_devices[port][periph] != NULL ) {
236 /* Detach existing peripheral first */
237 maple_detach_device( port, periph );
238 }
240 maple_devices[port][periph] = dev;
241 if( periph != 0 )
242 maple_periph_mask[port] |= (1<<(periph-1));
243 else maple_periph_mask[port] |= 0x20;
244 if( dev->attach != NULL ) {
245 dev->attach( dev );
246 }
247 }
249 void maple_detach_device( unsigned int port, unsigned int periph ) {
250 assert( port < 4 );
251 assert( periph < 6 );
253 maple_device_t dev = maple_devices[port][periph];
254 if( dev == NULL ) /* already detached */
255 return;
256 maple_devices[port][periph] = NULL;
257 if( dev->detach != NULL ) {
258 dev->detach(dev);
259 }
260 if( periph == 0 ) {
261 /* If we detach the main peripheral, we also have to detach all the
262 * subperipherals, or the system could get quite confused
263 */
264 int i;
265 maple_periph_mask[port] = 0;
266 for( i=1; i<6; i++ ) {
267 maple_detach_device(port,i);
268 }
269 } else {
270 maple_periph_mask[port] &= (~(1<<(periph-1)));
271 }
273 }
275 void maple_detach_all() {
276 int i, j;
277 for( i=0; i<4; i++ ) {
278 for( j=0; j<6; j++ ) {
279 if( maple_devices[i][j] != NULL ) {
280 maple_device_t dev = maple_devices[i][j];
281 if( dev->detach != NULL )
282 dev->detach(dev);
283 if( dev->destroy != NULL )
284 dev->destroy(dev);
285 }
286 }
287 maple_periph_mask[i] = 0;
288 }
289 }
291 void maple_reattach_all() {
292 int i, j;
293 for( i=0; i<4; i++ ) {
294 for( j=0; j<6; j++ ) {
295 if( maple_devices[i][j] != NULL ) {
296 maple_device_t dev = maple_devices[i][j];
297 if( dev->attach != NULL )
298 dev->attach(dev);
299 }
300 }
301 }
302 }
.