Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 140:d26f4899898d
prev138:afabd7e6d26d
next142:2f631c3a3946
author nkeynes
date Sun Apr 30 12:22:31 2006 +0000 (17 years ago)
permissions -rw-r--r--
last change Fix IDENTIFY to be non-completely-broken
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.10 2006-04-30 12:22:31 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"
    28 #define MAX_WRITE_BUF 4096
    29 #define MAX_SECTOR_SIZE 2352 /* Audio sector */
    30 #define DEFAULT_DATA_SECTORS 8
    32 static void ide_init( void );
    33 static void ide_reset( void );
    34 static void ide_save_state( FILE *f );
    35 static int ide_load_state( FILE *f );
    36 static void ide_raise_interrupt( void );
    37 static void ide_clear_interrupt( void );
    39 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
    40 				       NULL, ide_save_state, ide_load_state };
    42 struct ide_registers idereg;
    44 static unsigned char command_buffer[12];
    45 unsigned char *data_buffer = NULL;
    46 uint32_t data_buffer_len = 0;
    48 /* "\0\0\0\0\xb4\x19\0\0\x08SE      REV 6.42990316" */
    49 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
    50                        0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
    51                        0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
    52                        0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
    55 static void ide_init( void )
    56 {
    57     ide_reset();
    58     data_buffer_len = DEFAULT_DATA_SECTORS; 
    59     data_buffer = malloc( MAX_SECTOR_SIZE * data_buffer_len ); 
    60     assert( data_buffer != NULL );
    61 }
    63 static void ide_reset( void )
    64 {
    65     ide_clear_interrupt();
    66     idereg.error = 0x01;
    67     idereg.count = 0x01;
    68     idereg.lba0 = /* 0x21; */ 0x81;
    69     idereg.lba1 = 0x14;
    70     idereg.lba2 = 0xeb;
    71     idereg.feature = 0; /* Indeterminate really */
    72     idereg.status = 0x00;
    73     idereg.device = 0x00;
    74     idereg.disc = gdrom_is_mounted() ? IDE_DISC_NONE : (IDE_DISC_CDROM|IDE_DISC_READY);
    75 }
    77 static void ide_save_state( FILE *f )
    78 {
    81 }
    83 static int ide_load_state( FILE *f )
    84 {
    85     return 0;
    86 }
    88 static void ide_set_write_buffer( unsigned char *buf, int len )
    89 {
    90     idereg.status |= IDE_ST_DATA;
    91     idereg.data = buf;
    92     idereg.datalen = len;
    93     idereg.writeptr = (uint16_t *)buf;
    94     idereg.readptr = NULL;
    95 }
    97 static void ide_set_read_buffer( unsigned char *buf, int len, int blocksize )
    98 {
    99     idereg.status |= IDE_ST_DATA;
   100     idereg.data = buf;
   101     idereg.datalen = len;
   102     idereg.readptr = (uint16_t *)buf;
   103     idereg.writeptr = NULL;
   104     idereg.lba1 = len&0xFF;
   105     idereg.lba2 = len>>8;
   106     idereg.blocksize = idereg.blockleft = blocksize;
   107 }
   109 static void ide_raise_interrupt( void )
   110 {
   111     if( idereg.intrq_pending == 0 ) {
   112 	idereg.intrq_pending = 1;
   113 	if( IS_IDE_IRQ_ENABLED() )
   114 	    asic_event( EVENT_IDE );
   115     }
   116 }
   118 static void ide_clear_interrupt( void ) 
   119 {
   120     if( idereg.intrq_pending != 0 ) {
   121 	idereg.intrq_pending = 0;
   122 	if( IS_IDE_IRQ_ENABLED() )
   123 	    asic_clear_event( EVENT_IDE );
   124     }
   125 }
   127 static void ide_set_error( int error_code )
   128 {
   129     idereg.status = 0x51;
   130     idereg.error = error_code;
   131 }
   133 uint8_t ide_read_status( void ) 
   134 {
   135     if( (idereg.status & IDE_ST_BUSY) == 0 )
   136 	ide_clear_interrupt();
   137     return idereg.status;
   138 }
   140 uint16_t ide_read_data_pio( void ) {
   141     if( idereg.readptr == NULL )
   142         return 0xFFFF;
   143     uint16_t rv = *idereg.readptr++;
   144     idereg.datalen-=2;
   145     idereg.blockleft-=2;
   146     if( idereg.datalen <=0 ) {
   147         idereg.readptr = NULL;
   148         idereg.status &= ~IDE_ST_DATA;
   149     } else if( idereg.blockleft <= 0 ) {
   150 	ide_raise_interrupt();
   151 	idereg.blockleft = idereg.blocksize;
   152     }
   153     return rv;
   154 }
   156 void ide_write_data_pio( uint16_t val ) {
   157     if( idereg.writeptr == NULL )
   158         return;
   159     *idereg.writeptr++ = val;
   160     idereg.datalen-=2;
   161     if( idereg.datalen <= 0 ) {
   162 	int len = ((unsigned char *)idereg.writeptr) - idereg.data;
   163         idereg.writeptr = NULL;
   164         idereg.status &= ~IDE_ST_DATA;
   165         ide_write_buffer( idereg.data, len );
   166     }
   167 }
   169 void ide_write_control( uint8_t val ) {
   170     if( IS_IDE_IRQ_ENABLED() ) {
   171 	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   172 	    asic_clear_event( EVENT_IDE );
   173     } else {
   174 	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   175 	    asic_event( EVENT_IDE );
   176     }
   177     idereg.control = val;
   178 }
   180 void ide_write_command( uint8_t val ) {
   181     ide_clear_interrupt();
   182     idereg.command = val;
   183     switch( val ) {
   184     case IDE_CMD_RESET_DEVICE:
   185 	ide_reset();
   186 	break;
   187     case IDE_CMD_PACKET:
   188 	ide_set_write_buffer(command_buffer,12);
   189 	break;
   190     case IDE_CMD_SET_FEATURE:
   191 	switch( idereg.feature ) {
   192 	case IDE_FEAT_SET_TRANSFER_MODE:
   193 	    switch( idereg.count & 0xF8 ) {
   194 	    case IDE_XFER_PIO:
   195 		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   196 		break;
   197 	    case IDE_XFER_PIO_FLOW:
   198 		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   199 		break;
   200 	    case IDE_XFER_MULTI_DMA:
   201 		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   202 		break;
   203 	    case IDE_XFER_ULTRA_DMA:
   204 		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   205 		break;
   206 	    default:
   207 		INFO( "Setting unknown transfer mode: %02X", idereg.count );
   208 		break;
   209 	    }
   210 	    break;
   211 	default:
   212 	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   213 	}
   214 	ide_raise_interrupt( );
   215 	break;
   216     default:
   217 	WARN( "IDE: Unimplemented command: %02X", val );
   218     }
   219     idereg.status |= IDE_ST_READY | IDE_ST_SERV;
   220 }
   222 void ide_packet_command( unsigned char *cmd )
   223 {
   224     uint32_t length, datalen;
   225     uint32_t lba;
   226     int blocksize = idereg.lba1 + (idereg.lba2<<8);
   228     ide_raise_interrupt( );
   229     /* Okay we have the packet in the command buffer */
   230     WARN( "ATAPI: Received Packet command: %02X", cmd[0] );
   231     fwrite_dump( (unsigned char *)cmd, 12, stderr );
   232     switch( cmd[0] ) {
   233     case PKT_CMD_IDENTIFY:
   234 	/* NB: Bios sets cmd[4] = 0x08, no idea what this is for;
   235 	 * different values here appear to have no effect.
   236 	 */
   237 	lba = cmd[2];
   238 	if( lba >= sizeof(gdrom_ident) ) {
   239 	    ide_set_error(0x50);
   240 	    return;
   241 	}
   242 	length = cmd[4];
   243 	if( lba+length > sizeof(gdrom_ident) )
   244 	    length = sizeof(gdrom_ident) - lba;
   245 	ide_set_read_buffer(gdrom_ident + lba, length, blocksize);
   246 	break;
   247     case PKT_CMD_READ_TOC:
   248 	if( !gdrom_get_toc( data_buffer ) ) {
   249 	    ide_set_error( 0x50 );
   250 	    return;
   251 	} 
   252 	ide_set_read_buffer( data_buffer, sizeof( struct gdrom_toc ), blocksize );
   253 	break;
   254     case PKT_CMD_READ_SECTOR:
   255 	lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   256 	length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   257 	if( length > data_buffer_len ) {
   258 	    do {
   259 		data_buffer_len = data_buffer_len << 1;
   260 	    } while( data_buffer_len < length );
   261 	    data_buffer = realloc( data_buffer, data_buffer_len );
   262 	}
   264 	datalen = gdrom_read_sectors( lba, length, data_buffer );
   265 	if( datalen == 0 ) {
   266 	    ide_set_error( 0x50 );
   267 	    return;
   268 	}
   269 	ide_set_read_buffer( data_buffer, datalen, blocksize );
   270 	break;
   271     }
   272 }
   274 void ide_write_buffer( unsigned char *data, int datalen ) {
   275     switch( idereg.command ) {
   276         case IDE_CMD_PACKET:
   277 	    ide_packet_command( data );
   278             break;
   279     }
   280 }
   282 /**
   283  * DMA read request
   284  *
   285  * This method is called from the ASIC side when a DMA read request is
   286  * initiated. If there is a pending DMA transfer already, we copy the
   287  * data immediately, otherwise we record the DMA buffer for use when we
   288  * get to actually doing the transfer.
   289  */
   290 void ide_dma_read_req( uint32_t addr, uint32_t length )
   291 {
   294 }
.