filename | src/gdrom/ide.c |
changeset | 149:d88dd2e9a190 |
prev | 143:9446fb6df0c5 |
next | 152:d42a4c5cc709 |
author | nkeynes |
date | Tue May 23 13:10:28 2006 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Add texcache invalidates on direct writes to 64-bit vram. Technically we should do it on direct writes to 32-bit vram as well, but noone (sane) is going to try to write a texture there... |
view | annotate | diff | log | raw |
1 /**
2 * $Id: ide.c,v 1.13 2006-05-20 06:24:49 nkeynes Exp $
3 *
4 * IDE interface implementation
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 */
19 #define MODULE ide_module
21 #include <assert.h>
22 #include <stdlib.h>
23 #include "dream.h"
24 #include "asic.h"
25 #include "gdrom/ide.h"
26 #include "gdrom/gdrom.h"
27 #include "gdrom/packet.h"
29 #define MAX_WRITE_BUF 4096
30 #define MAX_SECTOR_SIZE 2352 /* Audio sector */
31 #define DEFAULT_DATA_SECTORS 8
33 static void ide_init( void );
34 static void ide_reset( void );
35 static void ide_save_state( FILE *f );
36 static int ide_load_state( FILE *f );
37 static void ide_raise_interrupt( void );
38 static void ide_clear_interrupt( void );
40 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
41 NULL, ide_save_state, ide_load_state };
43 struct ide_registers idereg;
45 static unsigned char command_buffer[12];
46 unsigned char *data_buffer = NULL;
47 uint32_t data_buffer_len = 0;
49 /* "\0\0\0\0\xb4\x19\0\0\x08SE REV 6.42990316" */
50 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
51 0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
52 0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
53 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
56 static void ide_init( void )
57 {
58 ide_reset();
59 data_buffer_len = DEFAULT_DATA_SECTORS;
60 data_buffer = malloc( MAX_SECTOR_SIZE * data_buffer_len );
61 assert( data_buffer != NULL );
62 }
64 static void ide_reset( void )
65 {
66 ide_clear_interrupt();
67 idereg.error = 0x01;
68 idereg.count = 0x01;
69 idereg.lba0 = /* 0x21; */ 0x81;
70 idereg.lba1 = 0x14;
71 idereg.lba2 = 0xeb;
72 idereg.feature = 0; /* Indeterminate really */
73 idereg.status = 0x00;
74 idereg.device = 0x00;
75 idereg.disc = gdrom_is_mounted() ? (IDE_DISC_CDROM|IDE_DISC_READY) : IDE_DISC_NONE;
76 }
78 static void ide_save_state( FILE *f )
79 {
82 }
84 static int ide_load_state( FILE *f )
85 {
86 return 0;
87 }
89 static void ide_set_write_buffer( unsigned char *buf, int len )
90 {
91 idereg.status |= IDE_ST_DATA;
92 idereg.data = buf;
93 idereg.datalen = len;
94 idereg.writeptr = (uint16_t *)buf;
95 idereg.readptr = NULL;
96 }
98 static void ide_set_read_buffer( unsigned char *buf, int len, int blocksize )
99 {
100 idereg.status |= IDE_ST_DATA;
101 idereg.data = buf;
102 idereg.datalen = len;
103 idereg.readptr = (uint16_t *)buf;
104 idereg.writeptr = NULL;
105 idereg.lba1 = len&0xFF;
106 idereg.lba2 = len>>8;
107 idereg.blocksize = idereg.blockleft = blocksize;
108 }
110 static void ide_raise_interrupt( void )
111 {
112 if( idereg.intrq_pending == 0 ) {
113 idereg.intrq_pending = 1;
114 if( IS_IDE_IRQ_ENABLED() )
115 asic_event( EVENT_IDE );
116 }
117 }
119 static void ide_clear_interrupt( void )
120 {
121 if( idereg.intrq_pending != 0 ) {
122 idereg.intrq_pending = 0;
123 if( IS_IDE_IRQ_ENABLED() )
124 asic_clear_event( EVENT_IDE );
125 }
126 }
128 static void ide_set_error( int error_code )
129 {
130 idereg.status = 0x51;
131 idereg.error = error_code;
132 }
134 uint8_t ide_read_status( void )
135 {
136 if( (idereg.status & IDE_ST_BUSY) == 0 )
137 ide_clear_interrupt();
138 return idereg.status;
139 }
141 uint16_t ide_read_data_pio( void ) {
142 if( idereg.readptr == NULL )
143 return 0xFFFF;
144 uint16_t rv = *idereg.readptr++;
145 idereg.datalen-=2;
146 idereg.blockleft-=2;
147 if( idereg.datalen <=0 ) {
148 idereg.readptr = NULL;
149 idereg.status &= ~IDE_ST_DATA;
150 ide_raise_interrupt();
151 } else if( idereg.blockleft <= 0 ) {
152 ide_raise_interrupt();
153 idereg.blockleft = idereg.blocksize;
154 }
155 return rv;
156 }
158 void ide_write_data_pio( uint16_t val ) {
159 if( idereg.writeptr == NULL )
160 return;
161 *idereg.writeptr++ = val;
162 idereg.datalen-=2;
163 if( idereg.datalen <= 0 ) {
164 int len = ((unsigned char *)idereg.writeptr) - idereg.data;
165 idereg.writeptr = NULL;
166 idereg.status &= ~IDE_ST_DATA;
167 ide_write_buffer( idereg.data, len );
168 }
169 }
171 void ide_write_control( uint8_t val ) {
172 if( IS_IDE_IRQ_ENABLED() ) {
173 if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
174 asic_clear_event( EVENT_IDE );
175 } else {
176 if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
177 asic_event( EVENT_IDE );
178 }
179 idereg.control = val;
180 }
182 void ide_write_command( uint8_t val ) {
183 ide_clear_interrupt();
184 idereg.command = val;
185 switch( val ) {
186 case IDE_CMD_RESET_DEVICE:
187 ide_reset();
188 break;
189 case IDE_CMD_PACKET:
190 idereg.count = 0x01;
191 ide_set_write_buffer(command_buffer,12);
192 break;
193 case IDE_CMD_SET_FEATURE:
194 switch( idereg.feature ) {
195 case IDE_FEAT_SET_TRANSFER_MODE:
196 switch( idereg.count & 0xF8 ) {
197 case IDE_XFER_PIO:
198 INFO( "Set PIO default mode: %d", idereg.count&0x07 );
199 break;
200 case IDE_XFER_PIO_FLOW:
201 INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
202 break;
203 case IDE_XFER_MULTI_DMA:
204 INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
205 break;
206 case IDE_XFER_ULTRA_DMA:
207 INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
208 break;
209 default:
210 INFO( "Setting unknown transfer mode: %02X", idereg.count );
211 break;
212 }
213 break;
214 default:
215 WARN( "IDE: unimplemented feature: %02X", idereg.feature );
216 }
217 ide_raise_interrupt( );
218 break;
219 default:
220 WARN( "IDE: Unimplemented command: %02X", val );
221 }
222 idereg.status = (idereg.status | IDE_ST_READY | IDE_ST_SERV) & (~IDE_ST_ERROR);
223 }
225 void ide_set_packet_error( uint16_t error )
226 {
227 idereg.gdrom_error = error;
228 idereg.error = (error & 0x0F) << 4;
229 if( error != 0 ) {
230 idereg.status = 0x51;
231 }
232 }
234 /**
235 * Execute a packet command. This particular method is responsible for parsing
236 * the command buffers (12 bytes), and generating the appropriate responses,
237 * although the actual implementation is mostly delegated to gdrom.c
238 */
239 void ide_packet_command( unsigned char *cmd )
240 {
241 uint32_t length, datalen;
242 uint32_t lba, status;
243 int mode;
244 int blocksize = idereg.lba1 + (idereg.lba2<<8);
246 ide_raise_interrupt( );
247 /* Okay we have the packet in the command buffer */
248 WARN( "ATAPI: Received Packet command: %02X", cmd[0] );
249 fwrite_dump( (unsigned char *)cmd, 12, stderr );
250 switch( cmd[0] ) {
251 case PKT_CMD_TEST_READY:
252 if( !gdrom_is_mounted() ) {
253 ide_set_packet_error( PKT_ERR_NODISC );
254 return;
255 }
256 ide_set_packet_error( 0 );
257 idereg.status = 0x50;
258 return;
259 break;
260 case PKT_CMD_IDENTIFY:
261 lba = cmd[2];
262 if( lba >= sizeof(gdrom_ident) ) {
263 ide_set_error(PKT_ERR_BADFIELD);
264 return;
265 }
266 length = cmd[4];
267 if( lba+length > sizeof(gdrom_ident) )
268 length = sizeof(gdrom_ident) - lba;
269 ide_set_read_buffer(gdrom_ident + lba, length, blocksize);
270 break;
271 case PKT_CMD_SENSE:
272 memset( data_buffer, 0, 10 );
273 length = cmd[4];
274 if( length > 10 )
275 length = 10;
276 data_buffer[0] = 0xf0;
277 data_buffer[2] = idereg.gdrom_error & 0xFF;
278 data_buffer[8] = (idereg.gdrom_error >> 8) & 0xFF;
279 ide_set_read_buffer( data_buffer, length , blocksize );
280 break;
281 case PKT_CMD_READ_TOC:
282 status = gdrom_get_toc( data_buffer );
283 if( status != PKT_ERR_OK ) {
284 ide_set_packet_error( status );
285 return;
286 }
287 length = (cmd[3]<<8) | cmd[4];
288 if( length > sizeof(struct gdrom_toc) )
289 length = sizeof(struct gdrom_toc);
290 ide_set_read_buffer( data_buffer, length, blocksize );
291 break;
292 case PKT_CMD_DISC_INFO:
293 status = gdrom_get_info( data_buffer );
294 if( status != PKT_ERR_OK ) {
295 ide_set_packet_error( status );
296 return;
297 }
298 length = cmd[4];
299 if( length > 6 )
300 length = 6;
301 ide_set_read_buffer( data_buffer, length, blocksize );
302 break;
303 case PKT_CMD_READ_SECTOR:
304 lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
305 length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
306 if( length > data_buffer_len ) {
307 do {
308 data_buffer_len = data_buffer_len << 1;
309 } while( data_buffer_len < length );
310 data_buffer = realloc( data_buffer, data_buffer_len );
311 }
313 switch( cmd[1] ) {
314 case 0x20: mode = GDROM_MODE1; break;
315 case 0x24: mode = GDROM_GD; break;
316 case 0x28: mode = GDROM_MODE1; break; /* ??? */
317 case 0x30: mode = GDROM_RAW; break;
318 default:
319 ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
320 ide_set_packet_error( PKT_ERR_BADFIELD );
321 return;
322 }
324 status = gdrom_read_sectors( lba, length, mode, data_buffer, &data_buffer_len );
325 if( status != 0 ) {
326 ide_set_packet_error( status );
327 data_buffer[6] = (lba >> 8) & 0xFF;
328 data_buffer[7] = lba & 0xFF;
329 return;
330 }
331 ide_set_read_buffer( data_buffer, datalen, blocksize );
332 break;
333 case PKT_CMD_SPIN_UP:
334 /* do nothing? */
335 break;
336 default:
337 ide_set_packet_error( PKT_ERR_BADCMD ); /* Invalid command */
338 return;
339 }
340 ide_set_packet_error( PKT_ERR_OK );
341 }
343 void ide_write_buffer( unsigned char *data, int datalen ) {
344 switch( idereg.command ) {
345 case IDE_CMD_PACKET:
346 ide_packet_command( data );
347 break;
348 }
349 }
351 /**
352 * DMA read request
353 *
354 * This method is called from the ASIC side when a DMA read request is
355 * initiated. If there is a pending DMA transfer already, we copy the
356 * data immediately, otherwise we record the DMA buffer for use when we
357 * get to actually doing the transfer.
358 */
359 void ide_dma_read_req( uint32_t addr, uint32_t length )
360 {
363 }
.