filename | src/gdrom/ide.c |
changeset | 152:d42a4c5cc709 |
prev | 149:d88dd2e9a190 |
next | 158:a0a82246b44e |
author | nkeynes |
date | Tue May 23 13:11:45 2006 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Clean up the buffer and i/o handling Implement save/load state |
file | annotate | diff | log | raw |
1.1 --- a/src/gdrom/ide.c Sat May 20 06:24:49 2006 +00001.2 +++ b/src/gdrom/ide.c Tue May 23 13:11:45 2006 +00001.3 @@ -1,8 +1,12 @@1.4 /**1.5 - * $Id: ide.c,v 1.13 2006-05-20 06:24:49 nkeynes Exp $1.6 + * $Id: ide.c,v 1.14 2006-05-23 13:11:45 nkeynes Exp $1.7 *1.8 * IDE interface implementation1.9 *1.10 + *1.11 + * Note: All references to read/write are from the host's point of view.1.12 + *1.13 + * See: INF-80201.14 * Copyright (c) 2005 Nathan Keynes.1.15 *1.16 * This program is free software; you can redistribute it and/or modify1.17 @@ -36,16 +40,18 @@1.18 static int ide_load_state( FILE *f );1.19 static void ide_raise_interrupt( void );1.20 static void ide_clear_interrupt( void );1.21 +static void ide_packet_command( unsigned char *data );1.23 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,1.24 NULL, ide_save_state, ide_load_state };1.26 struct ide_registers idereg;1.27 -1.28 -static unsigned char command_buffer[12];1.29 unsigned char *data_buffer = NULL;1.30 uint32_t data_buffer_len = 0;1.32 +#define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x161.33 +#define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))1.34 +1.35 /* "\0\0\0\0\xb4\x19\0\0\x08SE REV 6.42990316" */1.36 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,1.37 0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,1.38 @@ -73,38 +79,77 @@1.39 idereg.status = 0x00;1.40 idereg.device = 0x00;1.41 idereg.disc = gdrom_is_mounted() ? (IDE_DISC_CDROM|IDE_DISC_READY) : IDE_DISC_NONE;1.42 + idereg.state = IDE_STATE_IDLE;1.43 + memset( idereg.gdrom_sense, '\0', 10 );1.44 + idereg.data_offset = -1;1.45 + idereg.data_length = -1;1.46 }1.48 static void ide_save_state( FILE *f )1.49 {1.50 -1.51 -1.52 + fwrite( &idereg, sizeof(idereg), 1, f );1.53 + fwrite( &data_buffer_len, sizeof(data_buffer_len), 1, f );1.54 + fwrite( data_buffer, data_buffer_len, 1, f );1.55 }1.57 static int ide_load_state( FILE *f )1.58 {1.59 + uint32_t length;1.60 + fread( &idereg, sizeof(idereg), 1, f );1.61 + fread( &length, sizeof(uint32_t), 1, f );1.62 + if( length > data_buffer_len ) {1.63 + if( data_buffer != NULL )1.64 + free( data_buffer );1.65 + data_buffer = malloc( length );1.66 + assert( data_buffer != NULL );1.67 + data_buffer_len = length;1.68 + }1.69 + fread( data_buffer, length, 1, f );1.70 return 0;1.71 }1.73 -static void ide_set_write_buffer( unsigned char *buf, int len )1.74 +/************************ State transitions *************************/1.75 +1.76 +/**1.77 + * Begin command packet write to the device. This is always 12 bytes of PIO data1.78 + */1.79 +static void ide_start_command_packet_write( )1.80 {1.81 - idereg.status |= IDE_ST_DATA;1.82 - idereg.data = buf;1.83 - idereg.datalen = len;1.84 - idereg.writeptr = (uint16_t *)buf;1.85 - idereg.readptr = NULL;1.86 + idereg.state = IDE_STATE_CMD_WRITE;1.87 + idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;1.88 + idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */1.89 + idereg.count = IDE_COUNT_CD;1.90 + idereg.data_offset = 0;1.91 + idereg.data_length = 12;1.92 }1.94 -static void ide_set_read_buffer( unsigned char *buf, int len, int blocksize )1.95 +/**1.96 + * Begin PIO read from the device. The data is assumed to already be1.97 + * in the buffer at this point.1.98 + */1.99 +static void ide_start_read( int length, int blocksize, gboolean dma )1.100 {1.101 - idereg.status |= IDE_ST_DATA;1.102 - idereg.data = buf;1.103 - idereg.datalen = len;1.104 - idereg.readptr = (uint16_t *)buf;1.105 - idereg.writeptr = NULL;1.106 - idereg.lba1 = len&0xFF;1.107 - idereg.lba2 = len>>8;1.108 - idereg.blocksize = idereg.blockleft = blocksize;1.109 + idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;1.110 + idereg.count = IDE_COUNT_IO;1.111 + idereg.data_length = length;1.112 + idereg.data_offset = 0;1.113 + if( dma ) {1.114 + idereg.state = IDE_STATE_DMA_READ;1.115 + idereg.status |= IDE_STATUS_DMRD;1.116 + } else {1.117 + idereg.state = IDE_STATE_PIO_READ;1.118 + idereg.lba1 = length & 0xFF;1.119 + idereg.lba2 = (length >> 8) & 0xFF;1.120 + // idereg.lba1 = blocksize & 0xFF;1.121 + // idereg.lba2 = blocksize >> 8;1.122 + idereg.block_length = blocksize;1.123 + idereg.block_left = blocksize;1.124 + }1.125 +}1.126 +1.127 +static void ide_start_packet_read( int length, int blocksize )1.128 +{1.129 + ide_start_read( length, blocksize, idereg.feature & IDE_FEAT_DMA ? TRUE : FALSE );1.130 }1.132 static void ide_raise_interrupt( void )1.133 @@ -133,38 +178,80 @@1.135 uint8_t ide_read_status( void )1.136 {1.137 - if( (idereg.status & IDE_ST_BUSY) == 0 )1.138 + if( (idereg.status & IDE_STATUS_BSY) == 0 )1.139 ide_clear_interrupt();1.140 return idereg.status;1.141 }1.143 uint16_t ide_read_data_pio( void ) {1.144 - if( idereg.readptr == NULL )1.145 + if( idereg.state == IDE_STATE_PIO_READ ) {1.146 + uint16_t rv = READ_BUFFER();1.147 + idereg.data_offset += 2;1.148 + idereg.block_left -= 2;1.149 + if( idereg.data_offset >= idereg.data_length ) {1.150 + idereg.state = IDE_STATE_IDLE;1.151 + idereg.status &= ~IDE_STATUS_DRQ;1.152 + idereg.data_offset = -1;1.153 + ide_raise_interrupt();1.154 + } else if( idereg.block_left <= 0 ) {1.155 + idereg.block_left = idereg.block_length;1.156 + ide_raise_interrupt();1.157 + }1.158 + return rv;1.159 + } else {1.160 return 0xFFFF;1.161 - uint16_t rv = *idereg.readptr++;1.162 - idereg.datalen-=2;1.163 - idereg.blockleft-=2;1.164 - if( idereg.datalen <=0 ) {1.165 - idereg.readptr = NULL;1.166 - idereg.status &= ~IDE_ST_DATA;1.167 - ide_raise_interrupt();1.168 - } else if( idereg.blockleft <= 0 ) {1.169 - ide_raise_interrupt();1.170 - idereg.blockleft = idereg.blocksize;1.171 }1.172 - return rv;1.173 }1.175 +1.176 +/**1.177 + * DMA read request1.178 + *1.179 + * This method is called from the ASIC side when a DMA read request is1.180 + * initiated. If there is a pending DMA transfer already, we copy the1.181 + * data immediately, otherwise we record the DMA buffer for use when we1.182 + * get to actually doing the transfer.1.183 + * @return number of bytes transfered1.184 + */1.185 +uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )1.186 +{1.187 + if( idereg.state == IDE_STATE_DMA_READ ) {1.188 + int xferlen = length;1.189 + int remaining = idereg.data_length - idereg.data_offset;1.190 + if( xferlen > remaining )1.191 + xferlen = remaining;1.192 + mem_copy_to_sh4( addr, data_buffer + idereg.data_offset, xferlen );1.193 + idereg.data_offset += xferlen;1.194 + if( idereg.data_offset >= idereg.data_length ) {1.195 + idereg.data_offset = -1;1.196 + idereg.state = IDE_STATE_IDLE;1.197 + idereg.status &= ~IDE_STATUS_DRQ;1.198 + ide_raise_interrupt();1.199 + }1.200 + return xferlen;1.201 + }1.202 + return 0;1.203 +}1.204 +1.205 +1.206 void ide_write_data_pio( uint16_t val ) {1.207 - if( idereg.writeptr == NULL )1.208 - return;1.209 - *idereg.writeptr++ = val;1.210 - idereg.datalen-=2;1.211 - if( idereg.datalen <= 0 ) {1.212 - int len = ((unsigned char *)idereg.writeptr) - idereg.data;1.213 - idereg.writeptr = NULL;1.214 - idereg.status &= ~IDE_ST_DATA;1.215 - ide_write_buffer( idereg.data, len );1.216 + if( idereg.state == IDE_STATE_CMD_WRITE ) {1.217 + WRITE_BUFFER(val);1.218 + idereg.data_offset+=2;1.219 + if( idereg.data_offset >= idereg.data_length ) {1.220 + idereg.state = IDE_STATE_BUSY;1.221 + idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;1.222 + idereg.data_offset = -1;1.223 + ide_packet_command(data_buffer);1.224 + }1.225 + } else if( idereg.state == IDE_STATE_PIO_WRITE ) {1.226 + WRITE_BUFFER(val);1.227 + if( idereg.data_offset >= idereg.data_length ) {1.228 + idereg.state = IDE_STATE_BUSY;1.229 + idereg.data_offset = -1;1.230 + idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;1.231 + /* ??? - no data writes yet anyway */1.232 + }1.233 }1.234 }1.236 @@ -187,8 +274,7 @@1.237 ide_reset();1.238 break;1.239 case IDE_CMD_PACKET:1.240 - idereg.count = 0x01;1.241 - ide_set_write_buffer(command_buffer,12);1.242 + ide_start_command_packet_write();1.243 break;1.244 case IDE_CMD_SET_FEATURE:1.245 switch( idereg.feature ) {1.246 @@ -219,15 +305,19 @@1.247 default:1.248 WARN( "IDE: Unimplemented command: %02X", val );1.249 }1.250 - idereg.status = (idereg.status | IDE_ST_READY | IDE_ST_SERV) & (~IDE_ST_ERROR);1.251 + idereg.status = (idereg.status | IDE_STATUS_DRDY | IDE_STATUS_SERV) & (~IDE_STATUS_CHK);1.252 }1.254 -void ide_set_packet_error( uint16_t error )1.255 +void ide_set_packet_result( uint16_t result )1.256 {1.257 - idereg.gdrom_error = error;1.258 - idereg.error = (error & 0x0F) << 4;1.259 - if( error != 0 ) {1.260 + idereg.gdrom_sense[0] = 0xf0;1.261 + idereg.gdrom_sense[2] = result & 0xFF;1.262 + idereg.gdrom_sense[8] = (result >> 8) & 0xFF;1.263 + idereg.error = (result & 0x0F) << 4;1.264 + if( result != 0 ) {1.265 idereg.status = 0x51;1.266 + } else {1.267 + idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);1.268 }1.269 }1.271 @@ -250,10 +340,10 @@1.272 switch( cmd[0] ) {1.273 case PKT_CMD_TEST_READY:1.274 if( !gdrom_is_mounted() ) {1.275 - ide_set_packet_error( PKT_ERR_NODISC );1.276 + ide_set_packet_result( PKT_ERR_NODISC );1.277 return;1.278 }1.279 - ide_set_packet_error( 0 );1.280 + ide_set_packet_result( 0 );1.281 idereg.status = 0x50;1.282 return;1.283 break;1.284 @@ -266,39 +356,38 @@1.285 length = cmd[4];1.286 if( lba+length > sizeof(gdrom_ident) )1.287 length = sizeof(gdrom_ident) - lba;1.288 - ide_set_read_buffer(gdrom_ident + lba, length, blocksize);1.289 + memcpy( data_buffer, gdrom_ident + lba, length );1.290 + ide_start_packet_read( length, blocksize );1.291 break;1.292 case PKT_CMD_SENSE:1.293 - memset( data_buffer, 0, 10 );1.294 length = cmd[4];1.295 if( length > 10 )1.296 length = 10;1.297 - data_buffer[0] = 0xf0;1.298 - data_buffer[2] = idereg.gdrom_error & 0xFF;1.299 - data_buffer[8] = (idereg.gdrom_error >> 8) & 0xFF;1.300 - ide_set_read_buffer( data_buffer, length , blocksize );1.301 + memcpy( data_buffer, idereg.gdrom_sense, length );1.302 + ide_start_packet_read( length, blocksize );1.303 break;1.304 case PKT_CMD_READ_TOC:1.305 - status = gdrom_get_toc( data_buffer );1.306 - if( status != PKT_ERR_OK ) {1.307 - ide_set_packet_error( status );1.308 - return;1.309 - }1.310 length = (cmd[3]<<8) | cmd[4];1.311 if( length > sizeof(struct gdrom_toc) )1.312 length = sizeof(struct gdrom_toc);1.313 - ide_set_read_buffer( data_buffer, length, blocksize );1.314 +1.315 + status = gdrom_get_toc( data_buffer );1.316 + if( status != PKT_ERR_OK ) {1.317 + ide_set_packet_result( status );1.318 + return;1.319 + }1.320 + ide_start_packet_read( length, blocksize );1.321 break;1.322 case PKT_CMD_DISC_INFO:1.323 - status = gdrom_get_info( data_buffer );1.324 - if( status != PKT_ERR_OK ) {1.325 - ide_set_packet_error( status );1.326 - return;1.327 - }1.328 length = cmd[4];1.329 if( length > 6 )1.330 length = 6;1.331 - ide_set_read_buffer( data_buffer, length, blocksize );1.332 + status = gdrom_get_info( data_buffer, cmd[2] );1.333 + if( status != PKT_ERR_OK ) {1.334 + ide_set_packet_result( status );1.335 + return;1.336 + }1.337 + ide_start_packet_read( length, blocksize );1.338 break;1.339 case PKT_CMD_READ_SECTOR:1.340 lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];1.341 @@ -317,47 +406,26 @@1.342 case 0x30: mode = GDROM_RAW; break;1.343 default:1.344 ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );1.345 - ide_set_packet_error( PKT_ERR_BADFIELD );1.346 + ide_set_packet_result( PKT_ERR_BADFIELD );1.347 return;1.348 }1.349 -1.350 - status = gdrom_read_sectors( lba, length, mode, data_buffer, &data_buffer_len );1.351 + datalen = data_buffer_len;1.352 + status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );1.353 if( status != 0 ) {1.354 - ide_set_packet_error( status );1.355 - data_buffer[6] = (lba >> 8) & 0xFF;1.356 - data_buffer[7] = lba & 0xFF;1.357 + ide_set_packet_result( status );1.358 + idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;1.359 + idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;1.360 + idereg.gdrom_sense[7] = lba & 0xFF;1.361 return;1.362 }1.363 - ide_set_read_buffer( data_buffer, datalen, blocksize );1.364 + ide_start_packet_read( datalen, blocksize );1.365 break;1.366 case PKT_CMD_SPIN_UP:1.367 /* do nothing? */1.368 break;1.369 default:1.370 - ide_set_packet_error( PKT_ERR_BADCMD ); /* Invalid command */1.371 + ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */1.372 return;1.373 }1.374 - ide_set_packet_error( PKT_ERR_OK );1.375 + ide_set_packet_result( PKT_ERR_OK );1.376 }1.377 -1.378 -void ide_write_buffer( unsigned char *data, int datalen ) {1.379 - switch( idereg.command ) {1.380 - case IDE_CMD_PACKET:1.381 - ide_packet_command( data );1.382 - break;1.383 - }1.384 -}1.385 -1.386 -/**1.387 - * DMA read request1.388 - *1.389 - * This method is called from the ASIC side when a DMA read request is1.390 - * initiated. If there is a pending DMA transfer already, we copy the1.391 - * data immediately, otherwise we record the DMA buffer for use when we1.392 - * get to actually doing the transfer.1.393 - */1.394 -void ide_dma_read_req( uint32_t addr, uint32_t length )1.395 -{1.396 -1.397 -1.398 -}
.