Search
lxdream.org :: lxdream/src/gdrom/ide.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 152:d42a4c5cc709
prev149:d88dd2e9a190
next158:a0a82246b44e
author nkeynes
date Tue May 23 13:11:45 2006 +0000 (14 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 +0000
1.2 +++ b/src/gdrom/ide.c Tue May 23 13:11:45 2006 +0000
1.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 implementation
1.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-8020
1.14 * Copyright (c) 2005 Nathan Keynes.
1.15 *
1.16 * This program is free software; you can redistribute it and/or modify
1.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.22
1.23 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
1.24 NULL, ide_save_state, ide_load_state };
1.25
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.31
1.32 +#define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
1.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.47
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.56
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.72
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 data
1.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.93
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 be
1.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.131
1.132 static void ide_raise_interrupt( void )
1.133 @@ -133,38 +178,80 @@
1.134
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.142
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.174
1.175 +
1.176 +/**
1.177 + * DMA read request
1.178 + *
1.179 + * This method is called from the ASIC side when a DMA read request is
1.180 + * initiated. If there is a pending DMA transfer already, we copy the
1.181 + * data immediately, otherwise we record the DMA buffer for use when we
1.182 + * get to actually doing the transfer.
1.183 + * @return number of bytes transfered
1.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.235
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.253
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.270
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 request
1.388 - *
1.389 - * This method is called from the ASIC side when a DMA read request is
1.390 - * initiated. If there is a pending DMA transfer already, we copy the
1.391 - * data immediately, otherwise we record the DMA buffer for use when we
1.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 -}
.