filename | src/maple/maple.c |
changeset | 1261:644f66135e94 |
prev | 1237:377077d10d62 |
next | 1296:30ecee61f811 |
author | nkeynes |
date | Wed Mar 21 09:01:41 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Surface management is actually already being taken care of - don't try to duplicate in onPause/onResume |
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 "eventq.h"
23 #include "dream.h"
24 #include "mem.h"
25 #include "asic.h"
26 #include "maple.h"
28 void maple_init( void );
30 struct dreamcast_module maple_module = { "Maple", maple_init, NULL, NULL, NULL,
31 NULL, NULL, NULL };
33 struct maple_device_class *maple_device_classes[] = {
34 &controller_class, &keyboard_class, &lightgun_class, &mouse_class, &vmu_class, NULL };
36 /**
37 * Fire interrupt to notify the completion of DMA transfer
38 */
39 static void maple_event_handler( int eventid )
40 {
41 MMIO_WRITE( ASIC, MAPLE_STATE, 0 );
42 asic_event( EVENT_MAPLE_DMA );
43 }
45 void maple_init( void )
46 {
47 register_event_callback( EVENT_MAPLE_DMA, maple_event_handler );
48 }
50 maple_device_t maple_new_device( const gchar *name )
51 {
52 maple_device_class_t clz = maple_get_device_class(name);
53 if( clz != NULL ) {
54 return clz->new_device();
55 }
56 return NULL;
57 }
59 maple_device_class_t maple_get_device_class( const gchar *name )
60 {
61 int i;
62 for( i=0; maple_device_classes[i] != NULL; i++ ) {
63 if( g_strcasecmp(maple_device_classes[i]->name, name ) == 0 )
64 return maple_device_classes[i];
65 }
66 return NULL;
67 }
69 const struct maple_device_class **maple_get_device_classes()
70 {
71 return (const struct maple_device_class **)maple_device_classes;
72 }
74 lxdream_config_group_t maple_get_device_config( maple_device_t dev )
75 {
76 if( dev->get_config == NULL )
77 return NULL;
78 return dev->get_config(dev);
79 }
81 /**
82 * Input data looks like this:
83 * 0: transfer control word
84 * 0: length of data in words (not including 3 word header)
85 * 1: low bit = lightgun mode
86 * 2: low 2 bits = port # (0..3)
87 * 3: 0x80 = last packet, 0x00 = normal packet
88 * 4: output buffer address
89 * 8: Command word
90 * 8: command code
91 * 9: destination address
92 * 10: source address
93 * 11: length of data in words (not including 3 word header)
94 * 12: command-specific data
95 */
97 /**
98 * array is [port][subperipheral], so [0][0] is main peripheral on port A,
99 * [1][2] is the second subperipheral on port B and so on.
100 */
101 maple_device_t maple_devices[4][6];
102 int maple_periph_mask[4];
103 #define GETBYTE(n) ((uint32_t)(buf[n]))
104 #define GETWORD(n) (*((uint32_t *)(buf+(n))))
105 #define PUTBYTE(n,x) (buf[n] = (char)x)
106 #define PUTWORD(n,x) (*((uint32_t *)(return_buf+(n))) = (x))
108 maple_device_t maple_get_device( unsigned int port, unsigned int periph ) {
109 if( port >= 4 )
110 return NULL;
111 if( periph >= 6 )
112 return NULL;
113 return maple_devices[port][periph];
114 }
116 void maple_handle_buffer( uint32_t address ) {
117 unsigned char *buf = (unsigned char *)mem_get_region(address);
118 if( buf == NULL ) {
119 ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
120 } else {
121 unsigned int last = 0;
122 int i = 0, count;
123 for( count=0; !last; count++ ) {
124 unsigned int port, length, mode, periph, periph_id, out_length;
125 unsigned int cmd, recv_addr, send_addr;
126 uint32_t return_addr;
127 unsigned char *return_buf;
128 maple_device_t dev;
130 last = GETBYTE(3) & 0x80; /* indicates last packet */
131 port = GETBYTE(2) & 0x03;
132 mode = GETBYTE(1) & 0x07;
133 length = GETBYTE(0) & 0xFF;
134 return_addr = GETWORD(4);
136 switch( mode ) {
137 case 2: /* lightgun */
138 dev = maple_devices[port][0];
139 if( dev != NULL && dev->start_gun != NULL ) {
140 dev->start_gun(dev);
141 return; // Pending
142 } else {
143 /* FIXME: Determine how long maple IO really takes to process,
144 * which is probably a function of the number of requests.
145 * For now, just use 0.2ms as a reasonable value.
146 */
147 event_schedule( EVENT_MAPLE_DMA, 200000 );
148 return;
149 }
150 case 7: /* skip */
151 buf += 4;
152 address +=4;
153 continue;
154 }
155 if( (return_addr & 0x1C000000) != 0x0C000000 ) {
156 ERROR( "Bad return address in maple packet: %08X", return_addr );
157 break;
158 }
159 return_buf = mem_get_region(return_addr);
160 cmd = GETBYTE(8);
161 recv_addr = GETBYTE(9);
162 send_addr = GETBYTE(10);
163 /* Sanity checks */
164 if( GETBYTE(11) != length ||
165 /* send_addr >> 6 != port || */ /* TODO: check that this is ignored? */
166 recv_addr >> 6 != port ||
167 return_buf == NULL ) {
168 ERROR( "Received bad packet: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
169 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
170 buf[8], buf[9], buf[10], buf[11] );
171 break;
172 }
173 periph = 0;
174 periph_id = recv_addr & 0x3F;
175 if( periph_id != 0x20 ) {
176 for( i=0;i<5;i++ ) {
177 if( periph_id == (1<<i) ) {
178 periph = i+1;
179 break;
180 }
181 }
182 if( periph == 0 ) { /* Bad setting */
183 /* ERROR */
184 }
185 }
187 dev = maple_devices[port][periph];
188 if( dev == NULL ) {
189 /* no device attached */
190 *((uint32_t *)return_buf) = -1;
191 } else {
192 int status, func;
193 unsigned int pt, phase, block, blkid;
194 out_length = 0;
195 switch( cmd ) {
196 case MAPLE_CMD_INFO:
197 status = MAPLE_RESP_INFO;
198 memcpy( return_buf+4, dev->ident, 112 );
199 out_length = 0x1C;
200 if( periph == 0 ) {
201 /* Identify command on the primary device also sets the
202 * bits in the address in the response according to the
203 * sub-peripherals present.
204 */
205 recv_addr &= 0xE0;
206 for( i=0; i<5; i++ ) {
207 if( maple_devices[port][i+1] != NULL ) {
208 recv_addr |= (1<<i);
209 }
210 }
211 }
212 break;
213 case MAPLE_CMD_EXT_INFO:
214 status = MAPLE_RESP_EXT_INFO;
215 memcpy( return_buf+4, dev->ident, 192 );
216 out_length = 0x30;
217 break;
218 case MAPLE_CMD_RESET:
219 if( dev->reset == NULL )
220 status = MAPLE_RESP_ACK;
221 else status = dev->reset(dev);
222 break;
223 case MAPLE_CMD_SHUTDOWN:
224 if( dev->shutdown == NULL )
225 status = MAPLE_RESP_ACK;
226 else status = dev->shutdown(dev);
227 break;
228 case MAPLE_CMD_GET_COND:
229 func = GETWORD(12);
230 if( dev->get_condition == NULL )
231 status = MAPLE_ERR_CMD_UNKNOWN;
232 else status = dev->get_condition(dev, func,
233 return_buf+8,
234 &out_length );
235 if( status == 0 ) {
236 out_length++;
237 status = MAPLE_RESP_DATA;
238 PUTWORD(4,func);
239 }
240 break;
241 case MAPLE_CMD_SET_COND:
242 func = GETWORD(12);
243 if( dev->set_condition == NULL )
244 status = MAPLE_ERR_CMD_UNKNOWN;
245 else status = dev->set_condition(dev, func,
246 buf+16,
247 length-1);
248 if( status == 0 )
249 status = MAPLE_RESP_ACK;
250 break;
251 case MAPLE_CMD_MEM_INFO:
252 func = GETWORD(12);
253 pt = GETWORD(16);
254 if( dev->get_memory_info == NULL )
255 status = MAPLE_ERR_CMD_UNKNOWN;
256 else status = dev->get_memory_info(dev,func, pt, return_buf+8, &out_length);
257 if( status == 0 ) {
258 out_length++;
259 status = MAPLE_RESP_DATA;
260 PUTWORD(4,func);
261 }
262 break;
263 case MAPLE_CMD_READ_BLOCK:
264 func = GETWORD(12);
265 pt = GETBYTE(16);
266 phase = GETBYTE(17);
267 block = (GETBYTE(18)<<8) | GETBYTE(19);
268 blkid = GETWORD(16);
269 if( dev->read_block == NULL )
270 status = MAPLE_ERR_CMD_UNKNOWN;
271 else status = dev->read_block(dev, func, pt, block, phase,
272 return_buf+12,
273 &out_length );
274 if( status == 0 ) {
275 status = MAPLE_RESP_DATA;
276 out_length += 2;
277 PUTWORD(4,func);
278 PUTWORD(8,blkid);
279 }
280 break;
281 case MAPLE_CMD_WRITE_BLOCK:
282 func = GETWORD(12);
283 pt = GETBYTE(16);
284 phase = GETBYTE(17);
285 block = (GETBYTE(18)<<8) | GETBYTE(19);
286 if( dev->write_block == NULL )
287 status = MAPLE_ERR_CMD_UNKNOWN;
288 else {
289 status = dev->write_block(dev, func, pt, block, phase,
290 buf+20, length-2);
291 if( status == 0 )
292 status = MAPLE_RESP_ACK;
293 }
294 break;
295 case MAPLE_CMD_SYNC_BLOCK:
296 func = GETWORD(12);
297 pt = GETBYTE(16);
298 phase = GETBYTE(17);
299 block = (GETBYTE(18)<<8) | GETBYTE(19);
300 /* TODO: something? */
301 status = MAPLE_RESP_ACK;
302 break;
303 default:
304 status = MAPLE_ERR_CMD_UNKNOWN;
305 }
306 return_buf[0] = status;
307 return_buf[1] = send_addr;
308 return_buf[2] = recv_addr;
309 if( periph == 0 )
310 return_buf[2] |= maple_periph_mask[port];
311 return_buf[3] = out_length;
312 }
313 buf += 12 + (length<<2);
314 address += 12 + (length<<2);
315 }
316 event_schedule( EVENT_MAPLE_DMA, 200000 );
317 }
318 }
320 void maple_attach_device( maple_device_t dev, unsigned int port,
321 unsigned int periph ) {
322 assert( port < 4 );
323 assert( periph < 6 );
325 if( maple_devices[port][periph] != NULL ) {
326 /* Detach existing peripheral first */
327 maple_detach_device( port, periph );
328 }
330 maple_devices[port][periph] = dev;
331 if( periph != 0 )
332 maple_periph_mask[port] |= (1<<(periph-1));
333 else maple_periph_mask[port] |= 0x20;
334 if( dev->attach != NULL ) {
335 dev->attach( dev );
336 }
337 }
339 void maple_detach_device( unsigned int port, unsigned int periph ) {
340 assert( port < 4 );
341 assert( periph < 6 );
343 maple_device_t dev = maple_devices[port][periph];
344 if( dev == NULL ) /* already detached */
345 return;
346 maple_devices[port][periph] = NULL;
347 if( dev->detach != NULL ) {
348 dev->detach(dev);
349 }
350 if( dev->destroy != NULL ) {
351 dev->destroy(dev);
352 }
353 if( periph == 0 ) {
354 /* If we detach the main peripheral, we also have to detach all the
355 * subperipherals, or the system could get quite confused
356 */
357 int i;
358 maple_periph_mask[port] = 0;
359 for( i=1; i<6; i++ ) {
360 maple_detach_device(port,i);
361 }
362 } else {
363 maple_periph_mask[port] &= (~(1<<(periph-1)));
364 }
366 }
368 void maple_detach_all() {
369 int i, j;
370 for( i=0; i<4; i++ ) {
371 for( j=0; j<6; j++ ) {
372 if( maple_devices[i][j] != NULL ) {
373 maple_device_t dev = maple_devices[i][j];
374 if( dev->detach != NULL )
375 dev->detach(dev);
376 if( dev->destroy != NULL )
377 dev->destroy(dev);
378 }
379 }
380 maple_periph_mask[i] = 0;
381 }
382 }
384 void maple_reattach_all()
385 {
386 int i, j;
387 for( i=0; i<4; i++ ) {
388 for( j=0; j<6; j++ ) {
389 if( maple_devices[i][j] != NULL ) {
390 maple_device_t dev = maple_devices[i][j];
391 if( dev->detach != NULL )
392 dev->detach(dev);
393 if( dev->attach != NULL )
394 dev->attach(dev);
395 }
396 }
397 }
398 }
400 gboolean maple_should_grab()
401 {
402 int mode = MAPLE_GRAB_DONTCARE;
403 int i,j;
404 for( i=0; i<4; i++ ) {
405 for( j=0; j<6; j++ ) {
406 if( maple_devices[i][j] != NULL ) {
407 maple_device_t dev = maple_devices[i][j];
408 if( (dev->device_class->flags&MAPLE_GRAB_MASK) > mode ) {
409 mode = dev->device_class->flags & MAPLE_GRAB_MASK;
410 }
411 }
412 }
413 }
414 return mode == MAPLE_GRAB_YES;
415 }
417 void maple_default_destroy( maple_device_t mdev )
418 {
419 free(mdev);
420 }
.