4 * Implements the core Maple bus, including DMA transfers to and from the bus.
6 * Copyright (c) 2005 Nathan Keynes.
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.
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.
18 #define MODULE maple_module
21 #include <glib/gstrfuncs.h>
27 void maple_init( void );
29 struct dreamcast_module maple_module = { "Maple", maple_init, NULL, NULL, NULL,
32 struct maple_device_class *maple_device_classes[] = {
33 &controller_class, &keyboard_class, &lightgun_class, &mouse_class, NULL };
35 void maple_init( void )
40 maple_device_t maple_new_device( const gchar *name )
42 maple_device_class_t clz = maple_get_device_class(name);
44 return clz->new_device();
49 maple_device_class_t maple_get_device_class( const gchar *name )
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];
59 const struct maple_device_class **maple_get_device_classes()
61 return (const struct maple_device_class **)maple_device_classes;
64 lxdream_config_entry_t maple_get_device_config( maple_device_t dev )
66 if( dev->get_config == NULL )
68 return dev->get_config(dev);
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
81 * 9: destination address
83 * 11: length of data in words (not including 3 word header)
84 * 12: command-specific data
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.
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 ) {
103 return maple_devices[port][periph];
106 void maple_handle_buffer( uint32_t address ) {
107 unsigned char *buf = (unsigned char *)mem_get_region(address);
109 ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
111 unsigned int last = 0;
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;
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);
127 case 2: /* lightgun */
128 dev = maple_devices[port][0];
129 if( dev != NULL && dev->start_gun != NULL ) {
133 asic_event( EVENT_MAPLE_DMA );
141 if( (return_addr & 0x1C000000) != 0x0C000000 ) {
142 ERROR( "Bad return address in maple packet: %08X", return_addr );
145 return_buf = mem_get_region(return_addr);
147 recv_addr = GETBYTE(9);
148 send_addr = GETBYTE(10);
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] );
160 periph_id = recv_addr & 0x3F;
161 if( periph_id != 0x20 ) {
163 if( periph_id == (1<<i) ) {
168 if( periph == 0 ) { /* Bad setting */
173 dev = maple_devices[port][periph];
175 /* no device attached */
176 *((uint32_t *)return_buf) = -1;
178 int status, func, block;
182 status = MAPLE_RESP_INFO;
183 memcpy( return_buf+4, dev->ident, 112 );
186 case MAPLE_CMD_EXT_INFO:
187 status = MAPLE_RESP_EXT_INFO;
188 memcpy( return_buf+4, dev->ident, 192 );
191 case MAPLE_CMD_RESET:
192 if( dev->reset == NULL )
193 status = MAPLE_RESP_ACK;
194 else status = dev->reset(dev);
196 case MAPLE_CMD_SHUTDOWN:
197 if( dev->shutdown == NULL )
198 status = MAPLE_RESP_ACK;
199 else status = dev->shutdown(dev);
201 case MAPLE_CMD_GET_COND:
203 if( dev->get_condition == NULL )
204 status = MAPLE_ERR_CMD_UNKNOWN;
205 else status = dev->get_condition(dev, func,
210 status = MAPLE_RESP_DATA;
214 case MAPLE_CMD_SET_COND:
216 if( dev->set_condition == NULL )
217 status = MAPLE_ERR_CMD_UNKNOWN;
218 else status = dev->set_condition(dev, func,
222 status = MAPLE_RESP_ACK;
224 case MAPLE_CMD_READ_BLOCK:
227 if( dev->read_block == NULL )
228 status = MAPLE_ERR_CMD_UNKNOWN;
229 else status = dev->read_block(dev, func, block,
233 status = MAPLE_RESP_DATA;
238 case MAPLE_CMD_WRITE_BLOCK:
241 if( dev->write_block == NULL )
242 status = MAPLE_ERR_CMD_UNKNOWN;
244 status = dev->write_block(dev, func, block,
247 status = MAPLE_RESP_ACK;
251 status = MAPLE_ERR_CMD_UNKNOWN;
253 return_buf[0] = status;
254 return_buf[1] = send_addr;
255 return_buf[2] = recv_addr;
257 return_buf[2] |= maple_periph_mask[port];
258 return_buf[3] = out_length;
260 buf += 12 + (length<<2);
261 address += 12 + (length<<2);
263 asic_event( EVENT_MAPLE_DMA );
267 void maple_attach_device( maple_device_t dev, unsigned int port,
268 unsigned int periph ) {
270 assert( periph < 6 );
272 if( maple_devices[port][periph] != NULL ) {
273 /* Detach existing peripheral first */
274 maple_detach_device( port, periph );
277 maple_devices[port][periph] = dev;
279 maple_periph_mask[port] |= (1<<(periph-1));
280 else maple_periph_mask[port] |= 0x20;
281 if( dev->attach != NULL ) {
286 void maple_detach_device( unsigned int port, unsigned int periph ) {
288 assert( periph < 6 );
290 maple_device_t dev = maple_devices[port][periph];
291 if( dev == NULL ) /* already detached */
293 maple_devices[port][periph] = NULL;
294 if( dev->detach != NULL ) {
297 if( dev->destroy != NULL ) {
301 /* If we detach the main peripheral, we also have to detach all the
302 * subperipherals, or the system could get quite confused
305 maple_periph_mask[port] = 0;
306 for( i=1; i<6; i++ ) {
307 maple_detach_device(port,i);
310 maple_periph_mask[port] &= (~(1<<(periph-1)));
315 void maple_detach_all() {
317 for( i=0; i<4; i++ ) {
318 for( j=0; j<6; j++ ) {
319 if( maple_devices[i][j] != NULL ) {
320 maple_device_t dev = maple_devices[i][j];
321 if( dev->detach != NULL )
323 if( dev->destroy != NULL )
327 maple_periph_mask[i] = 0;
331 void maple_reattach_all()
334 for( i=0; i<4; i++ ) {
335 for( j=0; j<6; j++ ) {
336 if( maple_devices[i][j] != NULL ) {
337 maple_device_t dev = maple_devices[i][j];
338 if( dev->detach != NULL )
340 if( dev->attach != NULL )
347 gboolean maple_should_grab()
349 int mode = MAPLE_GRAB_DONTCARE;
351 for( i=0; i<4; i++ ) {
352 for( j=0; j<6; j++ ) {
353 if( maple_devices[i][j] != NULL ) {
354 maple_device_t dev = maple_devices[i][j];
355 if( dev->grab_mode > mode ) {
356 mode = dev->grab_mode;
361 return mode == MAPLE_GRAB_YES;
364 void maple_set_device_config_value( maple_device_t dev, unsigned int key, const gchar *value )
366 if( dev != NULL && dev->set_config_value != NULL ) {
367 dev->set_config_value( dev, key, value );
371 void maple_default_destroy( maple_device_t mdev )
.