Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 149:d88dd2e9a190
prev143:9446fb6df0c5
next152: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 }
.