Search
lxdream.org :: lxdream/src/gdrom/ide.c
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
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.14 2006-05-23 13:11:45 nkeynes Exp $
     3  *
     4  * IDE interface implementation
     5  *
     6  *
     7  * Note: All references to read/write are from the host's point of view.
     8  *
     9  * See: INF-8020 
    10  * Copyright (c) 2005 Nathan Keynes.
    11  *
    12  * This program is free software; you can redistribute it and/or modify
    13  * it under the terms of the GNU General Public License as published by
    14  * the Free Software Foundation; either version 2 of the License, or
    15  * (at your option) any later version.
    16  *
    17  * This program is distributed in the hope that it will be useful,
    18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    20  * GNU General Public License for more details.
    21  */
    23 #define MODULE ide_module
    25 #include <assert.h>
    26 #include <stdlib.h>
    27 #include "dream.h"
    28 #include "asic.h"
    29 #include "gdrom/ide.h"
    30 #include "gdrom/gdrom.h"
    31 #include "gdrom/packet.h"
    33 #define MAX_WRITE_BUF 4096
    34 #define MAX_SECTOR_SIZE 2352 /* Audio sector */
    35 #define DEFAULT_DATA_SECTORS 8
    37 static void ide_init( void );
    38 static void ide_reset( void );
    39 static void ide_save_state( FILE *f );
    40 static int ide_load_state( FILE *f );
    41 static void ide_raise_interrupt( void );
    42 static void ide_clear_interrupt( void );
    43 static void ide_packet_command( unsigned char *data );
    45 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
    46 				       NULL, ide_save_state, ide_load_state };
    48 struct ide_registers idereg;
    49 unsigned char *data_buffer = NULL;
    50 uint32_t data_buffer_len = 0;
    52 #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
    53 #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
    55 /* "\0\0\0\0\xb4\x19\0\0\x08SE      REV 6.42990316" */
    56 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
    57                        0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
    58                        0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
    59                        0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
    62 static void ide_init( void )
    63 {
    64     ide_reset();
    65     data_buffer_len = DEFAULT_DATA_SECTORS; 
    66     data_buffer = malloc( MAX_SECTOR_SIZE * data_buffer_len ); 
    67     assert( data_buffer != NULL );
    68 }
    70 static void ide_reset( void )
    71 {
    72     ide_clear_interrupt();
    73     idereg.error = 0x01;
    74     idereg.count = 0x01;
    75     idereg.lba0 = /* 0x21; */ 0x81;
    76     idereg.lba1 = 0x14;
    77     idereg.lba2 = 0xeb;
    78     idereg.feature = 0; /* Indeterminate really */
    79     idereg.status = 0x00;
    80     idereg.device = 0x00;
    81     idereg.disc = gdrom_is_mounted() ? (IDE_DISC_CDROM|IDE_DISC_READY) : IDE_DISC_NONE;
    82     idereg.state = IDE_STATE_IDLE;
    83     memset( idereg.gdrom_sense, '\0', 10 );
    84     idereg.data_offset = -1;
    85     idereg.data_length = -1;
    86 }
    88 static void ide_save_state( FILE *f )
    89 {
    90     fwrite( &idereg, sizeof(idereg), 1, f );
    91     fwrite( &data_buffer_len, sizeof(data_buffer_len), 1, f );
    92     fwrite( data_buffer, data_buffer_len, 1, f );
    93 }
    95 static int ide_load_state( FILE *f )
    96 {
    97     uint32_t length;
    98     fread( &idereg, sizeof(idereg), 1, f );
    99     fread( &length, sizeof(uint32_t), 1, f );
   100     if( length > data_buffer_len ) {
   101 	if( data_buffer != NULL )
   102 	    free( data_buffer );
   103 	data_buffer = malloc( length );
   104 	assert( data_buffer != NULL );
   105 	data_buffer_len = length;
   106     }
   107     fread( data_buffer, length, 1, f );
   108     return 0;
   109 }
   111 /************************ State transitions *************************/
   113 /**
   114  * Begin command packet write to the device. This is always 12 bytes of PIO data
   115  */
   116 static void ide_start_command_packet_write( )
   117 {
   118     idereg.state = IDE_STATE_CMD_WRITE;
   119     idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;
   120     idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
   121     idereg.count = IDE_COUNT_CD;
   122     idereg.data_offset = 0;
   123     idereg.data_length = 12;
   124 }
   126 /**
   127  * Begin PIO read from the device. The data is assumed to already be
   128  * in the buffer at this point.
   129  */
   130 static void ide_start_read( int length, int blocksize, gboolean dma ) 
   131 {
   132     idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;
   133     idereg.count = IDE_COUNT_IO;
   134     idereg.data_length = length;
   135     idereg.data_offset = 0;
   136     if( dma ) {
   137 	idereg.state = IDE_STATE_DMA_READ;
   138 	idereg.status |= IDE_STATUS_DMRD;
   139     } else {
   140 	idereg.state = IDE_STATE_PIO_READ;
   141 	idereg.lba1 = length & 0xFF;
   142 	idereg.lba2 = (length >> 8) & 0xFF;
   143 	//	idereg.lba1 = blocksize & 0xFF;
   144 	//	idereg.lba2 = blocksize >> 8; 
   145 	idereg.block_length = blocksize;
   146 	idereg.block_left = blocksize;
   147     }
   148 }
   150 static void ide_start_packet_read( int length, int blocksize )
   151 {
   152     ide_start_read( length, blocksize, idereg.feature & IDE_FEAT_DMA ? TRUE : FALSE );
   153 }
   155 static void ide_raise_interrupt( void )
   156 {
   157     if( idereg.intrq_pending == 0 ) {
   158 	idereg.intrq_pending = 1;
   159 	if( IS_IDE_IRQ_ENABLED() )
   160 	    asic_event( EVENT_IDE );
   161     }
   162 }
   164 static void ide_clear_interrupt( void ) 
   165 {
   166     if( idereg.intrq_pending != 0 ) {
   167 	idereg.intrq_pending = 0;
   168 	if( IS_IDE_IRQ_ENABLED() )
   169 	    asic_clear_event( EVENT_IDE );
   170     }
   171 }
   173 static void ide_set_error( int error_code )
   174 {
   175     idereg.status = 0x51;
   176     idereg.error = error_code;
   177 }
   179 uint8_t ide_read_status( void ) 
   180 {
   181     if( (idereg.status & IDE_STATUS_BSY) == 0 )
   182 	ide_clear_interrupt();
   183     return idereg.status;
   184 }
   186 uint16_t ide_read_data_pio( void ) {
   187     if( idereg.state == IDE_STATE_PIO_READ ) {
   188 	uint16_t rv = READ_BUFFER();
   189 	idereg.data_offset += 2;
   190 	idereg.block_left -= 2;
   191 	if( idereg.data_offset >= idereg.data_length ) {
   192 	    idereg.state = IDE_STATE_IDLE;
   193 	    idereg.status &= ~IDE_STATUS_DRQ;
   194 	    idereg.data_offset = -1;
   195 	    ide_raise_interrupt();
   196 	} else if( idereg.block_left <= 0 ) {
   197 	    idereg.block_left = idereg.block_length;
   198 	    ide_raise_interrupt();
   199 	}
   200 	return rv;
   201     } else {
   202         return 0xFFFF;
   203     }
   204 }
   207 /**
   208  * DMA read request
   209  *
   210  * This method is called from the ASIC side when a DMA read request is
   211  * initiated. If there is a pending DMA transfer already, we copy the
   212  * data immediately, otherwise we record the DMA buffer for use when we
   213  * get to actually doing the transfer.
   214  * @return number of bytes transfered
   215  */
   216 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
   217 {
   218     if( idereg.state == IDE_STATE_DMA_READ ) {
   219 	int xferlen = length;
   220 	int remaining = idereg.data_length - idereg.data_offset;
   221 	if( xferlen > remaining )
   222 	    xferlen = remaining;
   223 	mem_copy_to_sh4( addr, data_buffer + idereg.data_offset, xferlen );
   224 	idereg.data_offset += xferlen;
   225 	if( idereg.data_offset >= idereg.data_length ) {
   226 	    idereg.data_offset = -1;
   227 	    idereg.state = IDE_STATE_IDLE;
   228 	    idereg.status &= ~IDE_STATUS_DRQ;
   229 	    ide_raise_interrupt();
   230 	}
   231 	return xferlen;
   232     }
   233     return 0;
   234 }
   237 void ide_write_data_pio( uint16_t val ) {
   238     if( idereg.state == IDE_STATE_CMD_WRITE ) {
   239 	WRITE_BUFFER(val);
   240 	idereg.data_offset+=2;
   241 	if( idereg.data_offset >= idereg.data_length ) {
   242 	    idereg.state = IDE_STATE_BUSY;
   243 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   244 	    idereg.data_offset = -1;
   245 	    ide_packet_command(data_buffer);
   246 	}
   247     } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
   248 	WRITE_BUFFER(val);
   249 	if( idereg.data_offset >= idereg.data_length ) {
   250 	    idereg.state = IDE_STATE_BUSY;
   251 	    idereg.data_offset = -1;
   252 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   253 	    /* ??? - no data writes yet anyway */
   254 	}
   255     }
   256 }
   258 void ide_write_control( uint8_t val ) {
   259     if( IS_IDE_IRQ_ENABLED() ) {
   260 	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   261 	    asic_clear_event( EVENT_IDE );
   262     } else {
   263 	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   264 	    asic_event( EVENT_IDE );
   265     }
   266     idereg.control = val;
   267 }
   269 void ide_write_command( uint8_t val ) {
   270     ide_clear_interrupt();
   271     idereg.command = val;
   272     switch( val ) {
   273     case IDE_CMD_RESET_DEVICE:
   274 	ide_reset();
   275 	break;
   276     case IDE_CMD_PACKET:
   277 	ide_start_command_packet_write();
   278 	break;
   279     case IDE_CMD_SET_FEATURE:
   280 	switch( idereg.feature ) {
   281 	case IDE_FEAT_SET_TRANSFER_MODE:
   282 	    switch( idereg.count & 0xF8 ) {
   283 	    case IDE_XFER_PIO:
   284 		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   285 		break;
   286 	    case IDE_XFER_PIO_FLOW:
   287 		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   288 		break;
   289 	    case IDE_XFER_MULTI_DMA:
   290 		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   291 		break;
   292 	    case IDE_XFER_ULTRA_DMA:
   293 		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   294 		break;
   295 	    default:
   296 		INFO( "Setting unknown transfer mode: %02X", idereg.count );
   297 		break;
   298 	    }
   299 	    break;
   300 	default:
   301 	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   302 	}
   303 	ide_raise_interrupt( );
   304 	break;
   305     default:
   306 	WARN( "IDE: Unimplemented command: %02X", val );
   307     }
   308     idereg.status = (idereg.status | IDE_STATUS_DRDY | IDE_STATUS_SERV) & (~IDE_STATUS_CHK);
   309 }
   311 void ide_set_packet_result( uint16_t result )
   312 {
   313     idereg.gdrom_sense[0] = 0xf0;
   314     idereg.gdrom_sense[2] = result & 0xFF;
   315     idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
   316     idereg.error = (result & 0x0F) << 4;
   317     if( result != 0 ) {
   318 	idereg.status = 0x51;
   319     } else {
   320 	idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
   321     }
   322 }
   324 /**
   325  * Execute a packet command. This particular method is responsible for parsing
   326  * the command buffers (12 bytes), and generating the appropriate responses, 
   327  * although the actual implementation is mostly delegated to gdrom.c
   328  */
   329 void ide_packet_command( unsigned char *cmd )
   330 {
   331     uint32_t length, datalen;
   332     uint32_t lba, status;
   333     int mode;
   334     int blocksize = idereg.lba1 + (idereg.lba2<<8);
   336     ide_raise_interrupt( );
   337     /* Okay we have the packet in the command buffer */
   338     WARN( "ATAPI: Received Packet command: %02X", cmd[0] );
   339     fwrite_dump( (unsigned char *)cmd, 12, stderr );
   340     switch( cmd[0] ) {
   341     case PKT_CMD_TEST_READY:
   342 	if( !gdrom_is_mounted() ) {
   343 	    ide_set_packet_result( PKT_ERR_NODISC );
   344 	    return;
   345 	}
   346 	ide_set_packet_result( 0 );
   347 	idereg.status = 0x50;
   348 	return;
   349 	break;
   350     case PKT_CMD_IDENTIFY:
   351 	lba = cmd[2];
   352 	if( lba >= sizeof(gdrom_ident) ) {
   353 	    ide_set_error(PKT_ERR_BADFIELD);
   354 	    return;
   355 	}
   356 	length = cmd[4];
   357 	if( lba+length > sizeof(gdrom_ident) )
   358 	    length = sizeof(gdrom_ident) - lba;
   359 	memcpy( data_buffer, gdrom_ident + lba, length );
   360 	ide_start_packet_read( length, blocksize );
   361 	break;
   362     case PKT_CMD_SENSE:
   363 	length = cmd[4];
   364 	if( length > 10 )
   365 	    length = 10;
   366 	memcpy( data_buffer, idereg.gdrom_sense, length );
   367 	ide_start_packet_read( length, blocksize );
   368 	break;
   369     case PKT_CMD_READ_TOC:
   370 	length = (cmd[3]<<8) | cmd[4];
   371 	if( length > sizeof(struct gdrom_toc) )
   372 	    length = sizeof(struct gdrom_toc);
   374 	status = gdrom_get_toc( data_buffer );
   375 	if( status != PKT_ERR_OK ) {
   376 	    ide_set_packet_result( status );
   377 	    return;
   378 	}
   379 	ide_start_packet_read( length, blocksize );
   380 	break;
   381     case PKT_CMD_DISC_INFO:
   382 	length = cmd[4];
   383 	if( length > 6 )
   384 	    length = 6;
   385 	status = gdrom_get_info( data_buffer, cmd[2] );
   386 	if( status != PKT_ERR_OK ) {
   387 	    ide_set_packet_result( status );
   388 	    return;
   389 	}
   390 	ide_start_packet_read( length, blocksize );
   391 	break;
   392     case PKT_CMD_READ_SECTOR:
   393 	lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   394 	length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   395 	if( length > data_buffer_len ) {
   396 	    do {
   397 		data_buffer_len = data_buffer_len << 1;
   398 	    } while( data_buffer_len < length );
   399 	    data_buffer = realloc( data_buffer, data_buffer_len );
   400 	}
   402 	switch( cmd[1] ) {
   403 	case 0x20: mode = GDROM_MODE1; break;
   404 	case 0x24: mode = GDROM_GD; break;
   405 	case 0x28: mode = GDROM_MODE1; break; /* ??? */
   406 	case 0x30: mode = GDROM_RAW; break;
   407 	default:
   408 	    ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
   409 	    ide_set_packet_result( PKT_ERR_BADFIELD );
   410 	    return;
   411 	}
   412 	datalen = data_buffer_len;
   413 	status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );
   414 	if( status != 0 ) {
   415 	    ide_set_packet_result( status );
   416 	    idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;
   417 	    idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;
   418 	    idereg.gdrom_sense[7] = lba & 0xFF;
   419 	    return;
   420 	}
   421 	ide_start_packet_read( datalen, blocksize );
   422 	break;
   423     case PKT_CMD_SPIN_UP:
   424 	/* do nothing? */
   425 	break;
   426     default:
   427 	ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   428 	return;
   429     }
   430     ide_set_packet_result( PKT_ERR_OK );
   431 }
.