filename | src/maple/maple.c |
changeset | 35:21a4be098304 |
prev | 31:495e480360d7 |
next | 121:795fec623ce9 |
author | nkeynes |
date | Tue Mar 14 12:45:53 2006 +0000 (18 years ago) |
permissions | -rw-r--r-- |
last change | Move driver selection out to main at long last. Add video NULL driver for headless operation Make dcload exit() actually exit |
view | annotate | diff | log | raw |
1 /**
2 * $Id: maple.c,v 1.6 2005-12-26 03:54:55 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 void maple_init( void )
32 {
34 }
36 /**
37 * Input data looks like this:
38 * 0: transfer control word
39 * 0: length of data in words (not including 3 word header)
40 * 1: low bit = lightgun mode
41 * 2: low 2 bits = port # (0..3)
42 * 3: 0x80 = last packet, 0x00 = normal packet
43 * 4: output buffer address
44 * 8: Command word
45 * 8: command code
46 * 9: destination address
47 * 10: source address
48 * 11: length of data in words (not including 3 word header)
49 * 12: command-specific data
50 */
52 /**
53 * array is [port][subperipheral], so [0][0] is main peripheral on port A,
54 * [1][2] is the second subperipheral on port B and so on.
55 */
56 maple_device_t maple_devices[4][6];
57 int maple_periph_mask[4];
58 #define GETBYTE(n) ((uint32_t)(buf[n]))
59 #define GETWORD(n) (*((uint32_t *)(buf+(n))))
60 #define PUTBYTE(n,x) (buf[n] = (char)x)
61 #define PUTWORD(n,x) (*((uint32_t *)(return_buf+(n))) = (x))
63 void maple_handle_buffer( uint32_t address ) {
64 unsigned char *buf = (unsigned char *)mem_get_region(address);
65 if( buf == NULL ) {
66 ERROR( "Invalid or unmapped buffer passed to maple (0x%08X)", address );
67 } else {
68 unsigned int last = 0;
69 int i = 0, count;
70 for( count=0; !last; count++ ) {
71 unsigned int port, length, gun, periph, periph_id, out_length;
72 unsigned int cmd, recv_addr, send_addr;
73 uint32_t return_addr;
74 unsigned char *return_buf;
76 last = GETBYTE(3) & 0x80; /* indicates last packet */
77 port = GETBYTE(2) & 0x03;
78 gun = GETBYTE(1) & 0x01;
79 length = GETBYTE(0) & 0xFF;
80 return_addr = GETWORD(4);
81 if( return_addr == 0 ) {
82 /* ERROR */
83 }
84 return_buf = mem_get_region(return_addr);
85 cmd = GETBYTE(8);
86 recv_addr = GETBYTE(9);
87 send_addr = GETBYTE(10);
88 /* Sanity checks */
89 if( GETBYTE(11) != length ||
90 send_addr != (port<<6) ||
91 recv_addr >> 6 != port ||
92 return_buf == NULL ) {
93 /* ERROR */
94 }
95 periph = 0;
96 periph_id = recv_addr & 0x3F;
97 if( periph_id != 0x20 ) {
98 for( i=0;i<5;i++ ) {
99 if( periph_id == (1<<i) ) {
100 periph = i+1;
101 break;
102 }
103 }
104 if( periph == 0 ) { /* Bad setting */
105 /* ERROR */
106 }
107 }
109 INFO( "Maple packet %d: Cmd %d on port %d device %d", count, cmd, port, periph );
110 maple_device_t dev = maple_devices[port][periph];
111 if( dev == NULL ) {
112 /* no device attached */
113 *((uint32_t *)return_buf) = -1;
114 } else {
115 int status, func, block;
116 out_length = 0;
117 switch( cmd ) {
118 case MAPLE_CMD_INFO:
119 status = MAPLE_RESP_INFO;
120 memcpy( return_buf+4, dev->ident, 112 );
121 out_length = 0x1C;
122 break;
123 case MAPLE_CMD_EXT_INFO:
124 status = MAPLE_RESP_EXT_INFO;
125 memcpy( return_buf+4, dev->ident, 192 );
126 out_length = 0x30;
127 break;
128 case MAPLE_CMD_RESET:
129 if( dev->reset == NULL )
130 status = MAPLE_RESP_ACK;
131 else status = dev->reset(dev);
132 break;
133 case MAPLE_CMD_SHUTDOWN:
134 if( dev->shutdown == NULL )
135 status = MAPLE_RESP_ACK;
136 else status = dev->shutdown(dev);
137 break;
138 case MAPLE_CMD_GET_COND:
139 func = GETWORD(12);
140 if( dev->get_condition == NULL )
141 status = MAPLE_ERR_CMD_UNKNOWN;
142 else status = dev->get_condition(dev, func,
143 return_buf+8,
144 &out_length );
145 if( status == 0 ) {
146 status = MAPLE_RESP_DATA;
147 PUTWORD(4,func);
148 }
149 break;
150 case MAPLE_CMD_SET_COND:
151 func = GETWORD(12);
152 if( dev->set_condition == NULL )
153 status = MAPLE_ERR_CMD_UNKNOWN;
154 else status = dev->set_condition(dev, func,
155 buf+16,
156 length);
157 if( status == 0 )
158 status = MAPLE_RESP_ACK;
159 break;
160 case MAPLE_CMD_READ_BLOCK:
161 func = GETWORD(12);
162 block = GETWORD(16);
163 if( dev->read_block == NULL )
164 status = MAPLE_ERR_CMD_UNKNOWN;
165 else status = dev->read_block(dev, func, block,
166 return_buf+12,
167 &out_length );
168 if( status == 0 ) {
169 status = MAPLE_RESP_DATA;
170 PUTWORD(4,func);
171 PUTWORD(8,block);
172 }
173 break;
174 case MAPLE_CMD_WRITE_BLOCK:
175 func = GETWORD(12);
176 block = GETWORD(16);
177 if( dev->write_block == NULL )
178 status = MAPLE_ERR_CMD_UNKNOWN;
179 else {
180 status = dev->write_block(dev, func, block,
181 buf+20, length);
182 if( status == 0 )
183 status = MAPLE_RESP_ACK;
184 }
185 break;
186 default:
187 status = MAPLE_ERR_CMD_UNKNOWN;
188 }
189 return_buf[0] = status;
190 return_buf[1] = send_addr;
191 return_buf[2] = recv_addr;
192 if( periph == 0 )
193 return_buf[2] |= maple_periph_mask[port];
194 return_buf[3] = out_length;
195 }
196 buf += 12 + (length<<2);
197 }
198 asic_event( EVENT_MAPLE_DMA );
199 }
200 }
202 void maple_attach_device( maple_device_t dev, unsigned int port,
203 unsigned int periph ) {
204 assert( port < 4 );
205 assert( periph < 6 );
207 if( maple_devices[port][periph] != NULL ) {
208 /* Detach existing peripheral first */
209 maple_detach_device( port, periph );
210 }
212 maple_devices[port][periph] = dev;
213 if( periph != 0 )
214 maple_periph_mask[port] |= (1<<(periph-1));
215 else maple_periph_mask[port] |= 0x20;
216 if( dev->attach != NULL ) {
217 dev->attach( dev );
218 }
219 }
221 void maple_detach_device( unsigned int port, unsigned int periph ) {
222 assert( port < 4 );
223 assert( periph < 6 );
225 maple_device_t dev = maple_devices[port][periph];
226 if( dev == NULL ) /* already detached */
227 return;
228 maple_devices[port][periph] = NULL;
229 if( dev->detach != NULL ) {
230 dev->detach(dev);
231 }
232 if( periph == 0 ) {
233 /* If we detach the main peripheral, we also have to detach all the
234 * subperipherals, or the system could get quite confused
235 */
236 int i;
237 maple_periph_mask[port] = 0;
238 for( i=1; i<6; i++ ) {
239 maple_detach_device(port,i);
240 }
241 } else {
242 maple_periph_mask[port] &= (~(1<<(periph-1)));
243 }
245 }
.