Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 125:49bf45f8210a
prev47:da09bcb7ce69
next138:afabd7e6d26d
author nkeynes
date Thu Mar 30 11:26:45 2006 +0000 (18 years ago)
permissions -rw-r--r--
last change Treat the 0x11000000 region as write-only texture ram (appears to be correct)
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.8 2006-03-22 14:29:02 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 <stdlib.h>
    22 #include "dream.h"
    23 #include "asic.h"
    24 #include "gdrom/ide.h"
    25 #include "gdrom/gdrom.h"
    27 #define MAX_WRITE_BUF 4096;
    29 void ide_init( void );
    30 void ide_init( void );
    32 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
    33 				       NULL, NULL, NULL };
    35 struct ide_registers idereg;
    37 static unsigned char command_buffer[12];
    39 /* "\0\0\0\0\xb4\x19\0\0\x08SE      REV 6.42990316" */
    40 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
    41                        0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
    42                        0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
    43                        0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
    46 gdrom_disc_t gdrom_disc = NULL;
    48 static void ide_set_write_buffer( unsigned char *buf, int len )
    49 {
    50     idereg.status |= IDE_ST_DATA;
    51     idereg.data = buf;
    52     idereg.datalen = len;
    53     idereg.writeptr = (uint16_t *)buf;
    54     idereg.readptr = NULL;
    55 }
    57 static void ide_set_read_buffer( unsigned char *buf, int len, int blocksize )
    58 {
    59     idereg.status |= IDE_ST_DATA;
    60     idereg.data = buf;
    61     idereg.datalen = len;
    62     idereg.readptr = (uint16_t *)buf;
    63     idereg.writeptr = NULL;
    64     idereg.lba1 = len&0xFF;
    65     idereg.lba2 = len>>8;
    66     idereg.blocksize = idereg.blockleft = blocksize;
    67 }
    69 static void ide_raise_interrupt( void )
    70 {
    71     if( idereg.intrq_pending == 0 ) {
    72 	idereg.intrq_pending = 1;
    73 	if( IS_IDE_IRQ_ENABLED() )
    74 	    asic_event( EVENT_IDE );
    75     }
    76 }
    78 static void ide_clear_interrupt( void ) 
    79 {
    80     if( idereg.intrq_pending != 0 ) {
    81 	idereg.intrq_pending = 0;
    82 	if( IS_IDE_IRQ_ENABLED() )
    83 	    asic_clear_event( EVENT_IDE );
    84     }
    85 }
    87 static void ide_set_error( int error_code )
    88 {
    89     idereg.status = 0x51;
    90     idereg.error = error_code;
    91 }
    93 void ide_init( void )
    94 {
    96 }
    98 void ide_reset( void )
    99 {
   100     ide_clear_interrupt();
   101     idereg.error = 0x01;
   102     idereg.count = 0x01;
   103     idereg.lba0 = /* 0x21; */ 0x81;
   104     idereg.lba1 = 0x14;
   105     idereg.lba2 = 0xeb;
   106     idereg.feature = 0; /* Indeterminate really */
   107     idereg.status = 0x00;
   108     idereg.device = 0x00;
   109     idereg.disc = (gdrom_disc == NULL ? IDE_DISC_NONE : (IDE_DISC_CDROM|IDE_DISC_READY));
   110 }
   112 uint8_t ide_read_status( void ) 
   113 {
   114     if( (idereg.status & IDE_ST_BUSY) == 0 )
   115 	ide_clear_interrupt();
   116     return idereg.status;
   117 }
   119 uint16_t ide_read_data_pio( void ) {
   120     if( idereg.readptr == NULL )
   121         return 0xFFFF;
   122     uint16_t rv = *idereg.readptr++;
   123     idereg.datalen-=2;
   124     idereg.blockleft-=2;
   125     if( idereg.datalen <=0 ) {
   126         idereg.readptr = NULL;
   127         idereg.status &= ~IDE_ST_DATA;
   128     } else if( idereg.blockleft <= 0 ) {
   129 	ide_raise_interrupt();
   130 	idereg.blockleft = idereg.blocksize;
   131     }
   132     return rv;
   133 }
   135 void ide_write_data_pio( uint16_t val ) {
   136     if( idereg.writeptr == NULL )
   137         return;
   138     *idereg.writeptr++ = val;
   139     idereg.datalen-=2;
   140     if( idereg.datalen <= 0 ) {
   141 	int len = ((unsigned char *)idereg.writeptr) - idereg.data;
   142         idereg.writeptr = NULL;
   143         idereg.status &= ~IDE_ST_DATA;
   144         ide_write_buffer( idereg.data, len );
   145     }
   146 }
   148 void ide_write_control( uint8_t val ) {
   149     if( IS_IDE_IRQ_ENABLED() ) {
   150 	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   151 	    asic_clear_event( EVENT_IDE );
   152     } else {
   153 	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   154 	    asic_event( EVENT_IDE );
   155     }
   156     idereg.control = val;
   157 }
   159 void ide_write_command( uint8_t val ) {
   160     ide_clear_interrupt();
   161     idereg.command = val;
   162     switch( val ) {
   163     case IDE_CMD_RESET_DEVICE:
   164 	ide_reset();
   165 	break;
   166     case IDE_CMD_PACKET:
   167 	ide_set_write_buffer(command_buffer,12);
   168 	break;
   169     case IDE_CMD_SET_FEATURE:
   170 	switch( idereg.feature ) {
   171 	case IDE_FEAT_SET_TRANSFER_MODE:
   172 	    switch( idereg.count & 0xF8 ) {
   173 	    case IDE_XFER_PIO:
   174 		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   175 		break;
   176 	    case IDE_XFER_PIO_FLOW:
   177 		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   178 		break;
   179 	    case IDE_XFER_MULTI_DMA:
   180 		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   181 		break;
   182 	    case IDE_XFER_ULTRA_DMA:
   183 		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   184 		break;
   185 	    default:
   186 		INFO( "Setting unknown transfer mode: %02X", idereg.count );
   187 		break;
   188 	    }
   189 	    break;
   190 	default:
   191 	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   192 	}
   193 	ide_raise_interrupt( );
   194 	break;
   195     default:
   196 	WARN( "IDE: Unimplemented command: %02X", val );
   197     }
   198     idereg.status |= IDE_ST_READY | IDE_ST_SERV;
   199 }
   201 void ide_packet_command( unsigned char *cmd )
   202 {
   203     uint32_t length;
   204     uint32_t lba;
   205     int blocksize = idereg.lba1 + (idereg.lba2<<8);
   207     ide_raise_interrupt( );
   208     /* Okay we have the packet in the command buffer */
   209     WARN( "ATAPI: Received Packet command: %02X", cmd[0] );
   210     fwrite_dump( (unsigned char *)cmd, 12, stderr );
   211     switch( cmd[0] ) {
   212     case PKT_CMD_IDENTIFY:
   213 	/* NB: Bios sets cmd[4] = 0x08, no idea what this is for;
   214 	 * different values here appear to have no effect.
   215 	 */
   216 	length = *((uint16_t*)(cmd+2));
   217 	if( length > sizeof(gdrom_ident) )
   218 	    length = sizeof(gdrom_ident);
   219 	ide_set_read_buffer(gdrom_ident, length, blocksize);
   220 	break;
   221     case PKT_CMD_READ_TOC:
   223 	break;
   224     case PKT_CMD_READ_SECTOR:
   225 	lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   226 	length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   227 	if( gdrom_disc == NULL ) {
   228 	    ide_set_error( 0x50 );
   229 	    return;
   230 	}
   231 	/*
   232 	if( gdrom_disc->read_data_sectors( lba, length ) == FALSE ) {
   233 	    ide_set_error( 0x50 );
   234 	    return;
   235 	}
   237 	*/	
   238 	break;
   239     }
   240 }
   242 void ide_write_buffer( unsigned char *data, int datalen ) {
   243     switch( idereg.command ) {
   244         case IDE_CMD_PACKET:
   245 	    ide_packet_command( data );
   246             break;
   247     }
   248 }
   250 /**
   251  * DMA read request
   252  *
   253  * This method is called from the ASIC side when a DMA read request is
   254  * initiated. If there is a pending DMA transfer already, we copy the
   255  * data immediately, otherwise we record the DMA buffer for use when we
   256  * get to actually doing the transfer.
   257  */
   258 void ide_dma_read_req( uint32_t addr, uint32_t length )
   259 {
   262 }
.