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 Wed Mar 22 14:29:02 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change Rename IDE DMA registers appropriately
Remove forced irq hack
Add correct irq handling for IDE
Miscellaneous WIP for the GD-rom drive
file annotate diff log raw
nkeynes@31
     1
/**
nkeynes@125
     2
 * $Id: ide.c,v 1.8 2006-03-22 14:29:02 nkeynes Exp $
nkeynes@2
     3
 *
nkeynes@31
     4
 * IDE interface implementation
nkeynes@31
     5
 *
nkeynes@31
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@31
     7
 *
nkeynes@31
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@31
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@31
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@31
    11
 * (at your option) any later version.
nkeynes@31
    12
 *
nkeynes@31
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@31
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@31
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@31
    16
 * GNU General Public License for more details.
nkeynes@2
    17
 */
nkeynes@35
    18
nkeynes@35
    19
#define MODULE ide_module
nkeynes@35
    20
nkeynes@2
    21
#include <stdlib.h>
nkeynes@35
    22
#include "dream.h"
nkeynes@125
    23
#include "asic.h"
nkeynes@39
    24
#include "gdrom/ide.h"
nkeynes@125
    25
#include "gdrom/gdrom.h"
nkeynes@2
    26
nkeynes@2
    27
#define MAX_WRITE_BUF 4096;
nkeynes@2
    28
nkeynes@15
    29
void ide_init( void );
nkeynes@15
    30
void ide_init( void );
nkeynes@15
    31
nkeynes@15
    32
struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
nkeynes@23
    33
				       NULL, NULL, NULL };
nkeynes@15
    34
nkeynes@2
    35
struct ide_registers idereg;
nkeynes@2
    36
nkeynes@125
    37
static unsigned char command_buffer[12];
nkeynes@2
    38
nkeynes@2
    39
/* "\0\0\0\0\xb4\x19\0\0\x08SE      REV 6.42990316" */
nkeynes@125
    40
unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
nkeynes@2
    41
                       0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
nkeynes@2
    42
                       0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
nkeynes@2
    43
                       0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
nkeynes@2
    44
nkeynes@2
    45
nkeynes@125
    46
gdrom_disc_t gdrom_disc = NULL;
nkeynes@125
    47
nkeynes@125
    48
static void ide_set_write_buffer( unsigned char *buf, int len )
nkeynes@2
    49
{
nkeynes@2
    50
    idereg.status |= IDE_ST_DATA;
nkeynes@2
    51
    idereg.data = buf;
nkeynes@2
    52
    idereg.datalen = len;
nkeynes@2
    53
    idereg.writeptr = (uint16_t *)buf;
nkeynes@2
    54
    idereg.readptr = NULL;
nkeynes@2
    55
}
nkeynes@2
    56
nkeynes@125
    57
static void ide_set_read_buffer( unsigned char *buf, int len, int blocksize )
nkeynes@2
    58
{
nkeynes@2
    59
    idereg.status |= IDE_ST_DATA;
nkeynes@2
    60
    idereg.data = buf;
nkeynes@2
    61
    idereg.datalen = len;
nkeynes@2
    62
    idereg.readptr = (uint16_t *)buf;
nkeynes@2
    63
    idereg.writeptr = NULL;
nkeynes@2
    64
    idereg.lba1 = len&0xFF;
nkeynes@2
    65
    idereg.lba2 = len>>8;
nkeynes@125
    66
    idereg.blocksize = idereg.blockleft = blocksize;
nkeynes@2
    67
}
nkeynes@2
    68
nkeynes@125
    69
static void ide_raise_interrupt( void )
nkeynes@2
    70
{
nkeynes@125
    71
    if( idereg.intrq_pending == 0 ) {
nkeynes@125
    72
	idereg.intrq_pending = 1;
nkeynes@125
    73
	if( IS_IDE_IRQ_ENABLED() )
nkeynes@125
    74
	    asic_event( EVENT_IDE );
nkeynes@125
    75
    }
nkeynes@125
    76
}
nkeynes@125
    77
nkeynes@125
    78
static void ide_clear_interrupt( void ) 
nkeynes@125
    79
{
nkeynes@125
    80
    if( idereg.intrq_pending != 0 ) {
nkeynes@125
    81
	idereg.intrq_pending = 0;
nkeynes@125
    82
	if( IS_IDE_IRQ_ENABLED() )
nkeynes@125
    83
	    asic_clear_event( EVENT_IDE );
nkeynes@125
    84
    }
nkeynes@125
    85
}
nkeynes@125
    86
nkeynes@125
    87
static void ide_set_error( int error_code )
nkeynes@125
    88
{
nkeynes@125
    89
    idereg.status = 0x51;
nkeynes@125
    90
    idereg.error = error_code;
nkeynes@2
    91
}
nkeynes@2
    92
nkeynes@15
    93
void ide_init( void )
nkeynes@15
    94
{
nkeynes@15
    95
nkeynes@15
    96
}
nkeynes@15
    97
nkeynes@2
    98
void ide_reset( void )
nkeynes@2
    99
{
nkeynes@2
   100
    ide_clear_interrupt();
nkeynes@2
   101
    idereg.error = 0x01;
nkeynes@2
   102
    idereg.count = 0x01;
nkeynes@125
   103
    idereg.lba0 = /* 0x21; */ 0x81;
nkeynes@2
   104
    idereg.lba1 = 0x14;
nkeynes@2
   105
    idereg.lba2 = 0xeb;
nkeynes@2
   106
    idereg.feature = 0; /* Indeterminate really */
nkeynes@2
   107
    idereg.status = 0x00;
nkeynes@2
   108
    idereg.device = 0x00;
nkeynes@125
   109
    idereg.disc = (gdrom_disc == NULL ? IDE_DISC_NONE : (IDE_DISC_CDROM|IDE_DISC_READY));
nkeynes@125
   110
}
nkeynes@125
   111
nkeynes@125
   112
uint8_t ide_read_status( void ) 
nkeynes@125
   113
{
nkeynes@125
   114
    if( (idereg.status & IDE_ST_BUSY) == 0 )
nkeynes@125
   115
	ide_clear_interrupt();
nkeynes@125
   116
    return idereg.status;
nkeynes@2
   117
}
nkeynes@2
   118
nkeynes@2
   119
uint16_t ide_read_data_pio( void ) {
nkeynes@2
   120
    if( idereg.readptr == NULL )
nkeynes@2
   121
        return 0xFFFF;
nkeynes@2
   122
    uint16_t rv = *idereg.readptr++;
nkeynes@2
   123
    idereg.datalen-=2;
nkeynes@125
   124
    idereg.blockleft-=2;
nkeynes@2
   125
    if( idereg.datalen <=0 ) {
nkeynes@2
   126
        idereg.readptr = NULL;
nkeynes@2
   127
        idereg.status &= ~IDE_ST_DATA;
nkeynes@125
   128
    } else if( idereg.blockleft <= 0 ) {
nkeynes@125
   129
	ide_raise_interrupt();
nkeynes@125
   130
	idereg.blockleft = idereg.blocksize;
nkeynes@2
   131
    }
nkeynes@2
   132
    return rv;
nkeynes@2
   133
}
nkeynes@2
   134
nkeynes@2
   135
void ide_write_data_pio( uint16_t val ) {
nkeynes@2
   136
    if( idereg.writeptr == NULL )
nkeynes@2
   137
        return;
nkeynes@2
   138
    *idereg.writeptr++ = val;
nkeynes@2
   139
    idereg.datalen-=2;
nkeynes@2
   140
    if( idereg.datalen <= 0 ) {
nkeynes@125
   141
	int len = ((unsigned char *)idereg.writeptr) - idereg.data;
nkeynes@2
   142
        idereg.writeptr = NULL;
nkeynes@2
   143
        idereg.status &= ~IDE_ST_DATA;
nkeynes@125
   144
        ide_write_buffer( idereg.data, len );
nkeynes@2
   145
    }
nkeynes@2
   146
}
nkeynes@2
   147
nkeynes@2
   148
void ide_write_control( uint8_t val ) {
nkeynes@125
   149
    if( IS_IDE_IRQ_ENABLED() ) {
nkeynes@125
   150
	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
nkeynes@125
   151
	    asic_clear_event( EVENT_IDE );
nkeynes@125
   152
    } else {
nkeynes@125
   153
	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
nkeynes@125
   154
	    asic_event( EVENT_IDE );
nkeynes@125
   155
    }
nkeynes@125
   156
    idereg.control = val;
nkeynes@2
   157
}
nkeynes@2
   158
nkeynes@2
   159
void ide_write_command( uint8_t val ) {
nkeynes@125
   160
    ide_clear_interrupt();
nkeynes@2
   161
    idereg.command = val;
nkeynes@2
   162
    switch( val ) {
nkeynes@39
   163
    case IDE_CMD_RESET_DEVICE:
nkeynes@39
   164
	ide_reset();
nkeynes@39
   165
	break;
nkeynes@39
   166
    case IDE_CMD_PACKET:
nkeynes@125
   167
	ide_set_write_buffer(command_buffer,12);
nkeynes@39
   168
	break;
nkeynes@39
   169
    case IDE_CMD_SET_FEATURE:
nkeynes@39
   170
	switch( idereg.feature ) {
nkeynes@47
   171
	case IDE_FEAT_SET_TRANSFER_MODE:
nkeynes@47
   172
	    switch( idereg.count & 0xF8 ) {
nkeynes@47
   173
	    case IDE_XFER_PIO:
nkeynes@47
   174
		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
nkeynes@47
   175
		break;
nkeynes@47
   176
	    case IDE_XFER_PIO_FLOW:
nkeynes@47
   177
		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
nkeynes@47
   178
		break;
nkeynes@47
   179
	    case IDE_XFER_MULTI_DMA:
nkeynes@47
   180
		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
nkeynes@47
   181
		break;
nkeynes@47
   182
	    case IDE_XFER_ULTRA_DMA:
nkeynes@47
   183
		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
nkeynes@47
   184
		break;
nkeynes@47
   185
	    default:
nkeynes@47
   186
		INFO( "Setting unknown transfer mode: %02X", idereg.count );
nkeynes@47
   187
		break;
nkeynes@47
   188
	    }
nkeynes@47
   189
	    break;
nkeynes@39
   190
	default:
nkeynes@39
   191
	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
nkeynes@39
   192
	}
nkeynes@125
   193
	ide_raise_interrupt( );
nkeynes@39
   194
	break;
nkeynes@39
   195
    default:
nkeynes@39
   196
	WARN( "IDE: Unimplemented command: %02X", val );
nkeynes@2
   197
    }
nkeynes@2
   198
    idereg.status |= IDE_ST_READY | IDE_ST_SERV;
nkeynes@2
   199
}
nkeynes@2
   200
nkeynes@125
   201
void ide_packet_command( unsigned char *cmd )
nkeynes@125
   202
{
nkeynes@125
   203
    uint32_t length;
nkeynes@125
   204
    uint32_t lba;
nkeynes@125
   205
    int blocksize = idereg.lba1 + (idereg.lba2<<8);
nkeynes@125
   206
nkeynes@125
   207
    ide_raise_interrupt( );
nkeynes@125
   208
    /* Okay we have the packet in the command buffer */
nkeynes@125
   209
    WARN( "ATAPI: Received Packet command: %02X", cmd[0] );
nkeynes@125
   210
    fwrite_dump( (unsigned char *)cmd, 12, stderr );
nkeynes@125
   211
    switch( cmd[0] ) {
nkeynes@125
   212
    case PKT_CMD_IDENTIFY:
nkeynes@125
   213
	/* NB: Bios sets cmd[4] = 0x08, no idea what this is for;
nkeynes@125
   214
	 * different values here appear to have no effect.
nkeynes@125
   215
	 */
nkeynes@125
   216
	length = *((uint16_t*)(cmd+2));
nkeynes@125
   217
	if( length > sizeof(gdrom_ident) )
nkeynes@125
   218
	    length = sizeof(gdrom_ident);
nkeynes@125
   219
	ide_set_read_buffer(gdrom_ident, length, blocksize);
nkeynes@125
   220
	break;
nkeynes@125
   221
    case PKT_CMD_READ_TOC:
nkeynes@125
   222
	
nkeynes@125
   223
	break;
nkeynes@125
   224
    case PKT_CMD_READ_SECTOR:
nkeynes@125
   225
	lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
nkeynes@125
   226
	length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
nkeynes@125
   227
	if( gdrom_disc == NULL ) {
nkeynes@125
   228
	    ide_set_error( 0x50 );
nkeynes@125
   229
	    return;
nkeynes@125
   230
	}
nkeynes@125
   231
	/*
nkeynes@125
   232
	if( gdrom_disc->read_data_sectors( lba, length ) == FALSE ) {
nkeynes@125
   233
	    ide_set_error( 0x50 );
nkeynes@125
   234
	    return;
nkeynes@125
   235
	}
nkeynes@125
   236
	
nkeynes@125
   237
	*/	
nkeynes@125
   238
	break;
nkeynes@125
   239
    }
nkeynes@125
   240
}
nkeynes@125
   241
nkeynes@125
   242
void ide_write_buffer( unsigned char *data, int datalen ) {
nkeynes@2
   243
    switch( idereg.command ) {
nkeynes@2
   244
        case IDE_CMD_PACKET:
nkeynes@125
   245
	    ide_packet_command( data );
nkeynes@2
   246
            break;
nkeynes@2
   247
    }
nkeynes@2
   248
}
nkeynes@125
   249
nkeynes@125
   250
/**
nkeynes@125
   251
 * DMA read request
nkeynes@125
   252
 *
nkeynes@125
   253
 * This method is called from the ASIC side when a DMA read request is
nkeynes@125
   254
 * initiated. If there is a pending DMA transfer already, we copy the
nkeynes@125
   255
 * data immediately, otherwise we record the DMA buffer for use when we
nkeynes@125
   256
 * get to actually doing the transfer.
nkeynes@125
   257
 */
nkeynes@125
   258
void ide_dma_read_req( uint32_t addr, uint32_t length )
nkeynes@125
   259
{
nkeynes@125
   260
    
nkeynes@125
   261
nkeynes@125
   262
}
.