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