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 Sat May 20 06:24:49 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change Add disc info + spin up (probably seek) commands
file annotate diff log raw
nkeynes@31
     1
/**
nkeynes@149
     2
 * $Id: ide.c,v 1.13 2006-05-20 06:24:49 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@138
    21
#include <assert.h>
nkeynes@2
    22
#include <stdlib.h>
nkeynes@35
    23
#include "dream.h"
nkeynes@125
    24
#include "asic.h"
nkeynes@39
    25
#include "gdrom/ide.h"
nkeynes@125
    26
#include "gdrom/gdrom.h"
nkeynes@142
    27
#include "gdrom/packet.h"
nkeynes@2
    28
nkeynes@138
    29
#define MAX_WRITE_BUF 4096
nkeynes@138
    30
#define MAX_SECTOR_SIZE 2352 /* Audio sector */
nkeynes@138
    31
#define DEFAULT_DATA_SECTORS 8
nkeynes@2
    32
nkeynes@138
    33
static void ide_init( void );
nkeynes@138
    34
static void ide_reset( void );
nkeynes@138
    35
static void ide_save_state( FILE *f );
nkeynes@138
    36
static int ide_load_state( FILE *f );
nkeynes@138
    37
static void ide_raise_interrupt( void );
nkeynes@138
    38
static void ide_clear_interrupt( void );
nkeynes@15
    39
nkeynes@15
    40
struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
nkeynes@138
    41
				       NULL, ide_save_state, ide_load_state };
nkeynes@15
    42
nkeynes@2
    43
struct ide_registers idereg;
nkeynes@2
    44
nkeynes@125
    45
static unsigned char command_buffer[12];
nkeynes@138
    46
unsigned char *data_buffer = NULL;
nkeynes@138
    47
uint32_t data_buffer_len = 0;
nkeynes@2
    48
nkeynes@2
    49
/* "\0\0\0\0\xb4\x19\0\0\x08SE      REV 6.42990316" */
nkeynes@125
    50
unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
nkeynes@2
    51
                       0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
nkeynes@2
    52
                       0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
nkeynes@2
    53
                       0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
nkeynes@2
    54
nkeynes@2
    55
nkeynes@138
    56
static void ide_init( void )
nkeynes@138
    57
{
nkeynes@138
    58
    ide_reset();
nkeynes@138
    59
    data_buffer_len = DEFAULT_DATA_SECTORS; 
nkeynes@138
    60
    data_buffer = malloc( MAX_SECTOR_SIZE * data_buffer_len ); 
nkeynes@138
    61
    assert( data_buffer != NULL );
nkeynes@138
    62
}
nkeynes@138
    63
nkeynes@138
    64
static void ide_reset( void )
nkeynes@138
    65
{
nkeynes@138
    66
    ide_clear_interrupt();
nkeynes@138
    67
    idereg.error = 0x01;
nkeynes@138
    68
    idereg.count = 0x01;
nkeynes@138
    69
    idereg.lba0 = /* 0x21; */ 0x81;
nkeynes@138
    70
    idereg.lba1 = 0x14;
nkeynes@138
    71
    idereg.lba2 = 0xeb;
nkeynes@138
    72
    idereg.feature = 0; /* Indeterminate really */
nkeynes@138
    73
    idereg.status = 0x00;
nkeynes@138
    74
    idereg.device = 0x00;
nkeynes@143
    75
    idereg.disc = gdrom_is_mounted() ? (IDE_DISC_CDROM|IDE_DISC_READY) : IDE_DISC_NONE;
nkeynes@138
    76
}
nkeynes@138
    77
nkeynes@138
    78
static void ide_save_state( FILE *f )
nkeynes@138
    79
{
nkeynes@138
    80
    
nkeynes@138
    81
nkeynes@138
    82
}
nkeynes@138
    83
nkeynes@138
    84
static int ide_load_state( FILE *f )
nkeynes@138
    85
{
nkeynes@138
    86
    return 0;
nkeynes@138
    87
}
nkeynes@125
    88
nkeynes@125
    89
static void ide_set_write_buffer( unsigned char *buf, int len )
nkeynes@2
    90
{
nkeynes@2
    91
    idereg.status |= IDE_ST_DATA;
nkeynes@2
    92
    idereg.data = buf;
nkeynes@2
    93
    idereg.datalen = len;
nkeynes@2
    94
    idereg.writeptr = (uint16_t *)buf;
nkeynes@2
    95
    idereg.readptr = NULL;
nkeynes@2
    96
}
nkeynes@2
    97
nkeynes@125
    98
static void ide_set_read_buffer( unsigned char *buf, int len, int blocksize )
nkeynes@2
    99
{
nkeynes@2
   100
    idereg.status |= IDE_ST_DATA;
nkeynes@2
   101
    idereg.data = buf;
nkeynes@2
   102
    idereg.datalen = len;
nkeynes@2
   103
    idereg.readptr = (uint16_t *)buf;
nkeynes@2
   104
    idereg.writeptr = NULL;
nkeynes@2
   105
    idereg.lba1 = len&0xFF;
nkeynes@2
   106
    idereg.lba2 = len>>8;
nkeynes@125
   107
    idereg.blocksize = idereg.blockleft = blocksize;
nkeynes@2
   108
}
nkeynes@2
   109
nkeynes@125
   110
static void ide_raise_interrupt( void )
nkeynes@2
   111
{
nkeynes@125
   112
    if( idereg.intrq_pending == 0 ) {
nkeynes@125
   113
	idereg.intrq_pending = 1;
nkeynes@125
   114
	if( IS_IDE_IRQ_ENABLED() )
nkeynes@125
   115
	    asic_event( EVENT_IDE );
nkeynes@125
   116
    }
nkeynes@125
   117
}
nkeynes@125
   118
nkeynes@125
   119
static void ide_clear_interrupt( void ) 
nkeynes@125
   120
{
nkeynes@125
   121
    if( idereg.intrq_pending != 0 ) {
nkeynes@125
   122
	idereg.intrq_pending = 0;
nkeynes@125
   123
	if( IS_IDE_IRQ_ENABLED() )
nkeynes@125
   124
	    asic_clear_event( EVENT_IDE );
nkeynes@125
   125
    }
nkeynes@125
   126
}
nkeynes@125
   127
nkeynes@125
   128
static void ide_set_error( int error_code )
nkeynes@125
   129
{
nkeynes@125
   130
    idereg.status = 0x51;
nkeynes@125
   131
    idereg.error = error_code;
nkeynes@2
   132
}
nkeynes@2
   133
nkeynes@125
   134
uint8_t ide_read_status( void ) 
nkeynes@125
   135
{
nkeynes@125
   136
    if( (idereg.status & IDE_ST_BUSY) == 0 )
nkeynes@125
   137
	ide_clear_interrupt();
nkeynes@125
   138
    return idereg.status;
nkeynes@2
   139
}
nkeynes@2
   140
nkeynes@2
   141
uint16_t ide_read_data_pio( void ) {
nkeynes@2
   142
    if( idereg.readptr == NULL )
nkeynes@2
   143
        return 0xFFFF;
nkeynes@2
   144
    uint16_t rv = *idereg.readptr++;
nkeynes@2
   145
    idereg.datalen-=2;
nkeynes@125
   146
    idereg.blockleft-=2;
nkeynes@2
   147
    if( idereg.datalen <=0 ) {
nkeynes@2
   148
        idereg.readptr = NULL;
nkeynes@2
   149
        idereg.status &= ~IDE_ST_DATA;
nkeynes@143
   150
	ide_raise_interrupt();
nkeynes@125
   151
    } else if( idereg.blockleft <= 0 ) {
nkeynes@125
   152
	ide_raise_interrupt();
nkeynes@125
   153
	idereg.blockleft = idereg.blocksize;
nkeynes@2
   154
    }
nkeynes@2
   155
    return rv;
nkeynes@2
   156
}
nkeynes@2
   157
nkeynes@2
   158
void ide_write_data_pio( uint16_t val ) {
nkeynes@2
   159
    if( idereg.writeptr == NULL )
nkeynes@2
   160
        return;
nkeynes@2
   161
    *idereg.writeptr++ = val;
nkeynes@2
   162
    idereg.datalen-=2;
nkeynes@2
   163
    if( idereg.datalen <= 0 ) {
nkeynes@125
   164
	int len = ((unsigned char *)idereg.writeptr) - idereg.data;
nkeynes@2
   165
        idereg.writeptr = NULL;
nkeynes@2
   166
        idereg.status &= ~IDE_ST_DATA;
nkeynes@125
   167
        ide_write_buffer( idereg.data, len );
nkeynes@2
   168
    }
nkeynes@2
   169
}
nkeynes@2
   170
nkeynes@2
   171
void ide_write_control( uint8_t val ) {
nkeynes@125
   172
    if( IS_IDE_IRQ_ENABLED() ) {
nkeynes@125
   173
	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
nkeynes@125
   174
	    asic_clear_event( EVENT_IDE );
nkeynes@125
   175
    } else {
nkeynes@125
   176
	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
nkeynes@125
   177
	    asic_event( EVENT_IDE );
nkeynes@125
   178
    }
nkeynes@125
   179
    idereg.control = val;
nkeynes@2
   180
}
nkeynes@2
   181
nkeynes@2
   182
void ide_write_command( uint8_t val ) {
nkeynes@125
   183
    ide_clear_interrupt();
nkeynes@2
   184
    idereg.command = val;
nkeynes@2
   185
    switch( val ) {
nkeynes@39
   186
    case IDE_CMD_RESET_DEVICE:
nkeynes@39
   187
	ide_reset();
nkeynes@39
   188
	break;
nkeynes@39
   189
    case IDE_CMD_PACKET:
nkeynes@149
   190
	idereg.count = 0x01;
nkeynes@125
   191
	ide_set_write_buffer(command_buffer,12);
nkeynes@39
   192
	break;
nkeynes@39
   193
    case IDE_CMD_SET_FEATURE:
nkeynes@39
   194
	switch( idereg.feature ) {
nkeynes@47
   195
	case IDE_FEAT_SET_TRANSFER_MODE:
nkeynes@47
   196
	    switch( idereg.count & 0xF8 ) {
nkeynes@47
   197
	    case IDE_XFER_PIO:
nkeynes@47
   198
		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
nkeynes@47
   199
		break;
nkeynes@47
   200
	    case IDE_XFER_PIO_FLOW:
nkeynes@47
   201
		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
nkeynes@47
   202
		break;
nkeynes@47
   203
	    case IDE_XFER_MULTI_DMA:
nkeynes@47
   204
		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
nkeynes@47
   205
		break;
nkeynes@47
   206
	    case IDE_XFER_ULTRA_DMA:
nkeynes@47
   207
		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
nkeynes@47
   208
		break;
nkeynes@47
   209
	    default:
nkeynes@47
   210
		INFO( "Setting unknown transfer mode: %02X", idereg.count );
nkeynes@47
   211
		break;
nkeynes@47
   212
	    }
nkeynes@47
   213
	    break;
nkeynes@39
   214
	default:
nkeynes@39
   215
	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
nkeynes@39
   216
	}
nkeynes@125
   217
	ide_raise_interrupt( );
nkeynes@39
   218
	break;
nkeynes@39
   219
    default:
nkeynes@39
   220
	WARN( "IDE: Unimplemented command: %02X", val );
nkeynes@2
   221
    }
nkeynes@142
   222
    idereg.status = (idereg.status | IDE_ST_READY | IDE_ST_SERV) & (~IDE_ST_ERROR);
nkeynes@2
   223
}
nkeynes@2
   224
nkeynes@142
   225
void ide_set_packet_error( uint16_t error )
nkeynes@142
   226
{
nkeynes@142
   227
    idereg.gdrom_error = error;
nkeynes@143
   228
    idereg.error = (error & 0x0F) << 4;
nkeynes@142
   229
    if( error != 0 ) {
nkeynes@142
   230
	idereg.status = 0x51;
nkeynes@142
   231
    }
nkeynes@142
   232
}
nkeynes@142
   233
nkeynes@142
   234
/**
nkeynes@142
   235
 * Execute a packet command. This particular method is responsible for parsing
nkeynes@142
   236
 * the command buffers (12 bytes), and generating the appropriate responses, 
nkeynes@142
   237
 * although the actual implementation is mostly delegated to gdrom.c
nkeynes@142
   238
 */
nkeynes@125
   239
void ide_packet_command( unsigned char *cmd )
nkeynes@125
   240
{
nkeynes@138
   241
    uint32_t length, datalen;
nkeynes@143
   242
    uint32_t lba, status;
nkeynes@143
   243
    int mode;
nkeynes@125
   244
    int blocksize = idereg.lba1 + (idereg.lba2<<8);
nkeynes@125
   245
nkeynes@125
   246
    ide_raise_interrupt( );
nkeynes@125
   247
    /* Okay we have the packet in the command buffer */
nkeynes@125
   248
    WARN( "ATAPI: Received Packet command: %02X", cmd[0] );
nkeynes@125
   249
    fwrite_dump( (unsigned char *)cmd, 12, stderr );
nkeynes@125
   250
    switch( cmd[0] ) {
nkeynes@142
   251
    case PKT_CMD_TEST_READY:
nkeynes@142
   252
	if( !gdrom_is_mounted() ) {
nkeynes@142
   253
	    ide_set_packet_error( PKT_ERR_NODISC );
nkeynes@142
   254
	    return;
nkeynes@142
   255
	}
nkeynes@142
   256
	ide_set_packet_error( 0 );
nkeynes@142
   257
	idereg.status = 0x50;
nkeynes@142
   258
	return;
nkeynes@142
   259
	break;
nkeynes@125
   260
    case PKT_CMD_IDENTIFY:
nkeynes@140
   261
	lba = cmd[2];
nkeynes@140
   262
	if( lba >= sizeof(gdrom_ident) ) {
nkeynes@142
   263
	    ide_set_error(PKT_ERR_BADFIELD);
nkeynes@140
   264
	    return;
nkeynes@140
   265
	}
nkeynes@140
   266
	length = cmd[4];
nkeynes@140
   267
	if( lba+length > sizeof(gdrom_ident) )
nkeynes@140
   268
	    length = sizeof(gdrom_ident) - lba;
nkeynes@140
   269
	ide_set_read_buffer(gdrom_ident + lba, length, blocksize);
nkeynes@125
   270
	break;
nkeynes@142
   271
    case PKT_CMD_SENSE:
nkeynes@142
   272
	memset( data_buffer, 0, 10 );
nkeynes@142
   273
	length = cmd[4];
nkeynes@142
   274
	if( length > 10 )
nkeynes@142
   275
	    length = 10;
nkeynes@142
   276
	data_buffer[0] = 0xf0;
nkeynes@142
   277
	data_buffer[2] = idereg.gdrom_error & 0xFF;
nkeynes@142
   278
	data_buffer[8] = (idereg.gdrom_error >> 8) & 0xFF;
nkeynes@142
   279
	ide_set_read_buffer( data_buffer, length , blocksize );
nkeynes@142
   280
	break;
nkeynes@125
   281
    case PKT_CMD_READ_TOC:
nkeynes@149
   282
	status = gdrom_get_toc( data_buffer );
nkeynes@149
   283
	if( status != PKT_ERR_OK ) {
nkeynes@149
   284
	    ide_set_packet_error( status );
nkeynes@138
   285
	    return;
nkeynes@149
   286
	}
nkeynes@142
   287
	length = (cmd[3]<<8) | cmd[4];
nkeynes@142
   288
	if( length > sizeof(struct gdrom_toc) )
nkeynes@142
   289
	    length = sizeof(struct gdrom_toc);
nkeynes@142
   290
	ide_set_read_buffer( data_buffer, length, blocksize );
nkeynes@125
   291
	break;
nkeynes@149
   292
    case PKT_CMD_DISC_INFO:
nkeynes@149
   293
	status = gdrom_get_info( data_buffer );
nkeynes@149
   294
	if( status != PKT_ERR_OK ) {
nkeynes@149
   295
	    ide_set_packet_error( status );
nkeynes@149
   296
	    return;
nkeynes@149
   297
	}
nkeynes@149
   298
	length = cmd[4];
nkeynes@149
   299
	if( length > 6 )
nkeynes@149
   300
	    length = 6;
nkeynes@149
   301
	ide_set_read_buffer( data_buffer, length, blocksize );
nkeynes@149
   302
	break;
nkeynes@125
   303
    case PKT_CMD_READ_SECTOR:
nkeynes@125
   304
	lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
nkeynes@125
   305
	length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
nkeynes@138
   306
	if( length > data_buffer_len ) {
nkeynes@138
   307
	    do {
nkeynes@138
   308
		data_buffer_len = data_buffer_len << 1;
nkeynes@138
   309
	    } while( data_buffer_len < length );
nkeynes@138
   310
	    data_buffer = realloc( data_buffer, data_buffer_len );
nkeynes@138
   311
	}
nkeynes@142
   312
nkeynes@143
   313
	switch( cmd[1] ) {
nkeynes@143
   314
	case 0x20: mode = GDROM_MODE1; break;
nkeynes@143
   315
	case 0x24: mode = GDROM_GD; break;
nkeynes@143
   316
	case 0x28: mode = GDROM_MODE1; break; /* ??? */
nkeynes@143
   317
	case 0x30: mode = GDROM_RAW; break;
nkeynes@143
   318
	default:
nkeynes@143
   319
	    ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
nkeynes@143
   320
	    ide_set_packet_error( PKT_ERR_BADFIELD );
nkeynes@142
   321
	    return;
nkeynes@142
   322
	}
nkeynes@142
   323
nkeynes@143
   324
	status = gdrom_read_sectors( lba, length, mode, data_buffer, &data_buffer_len );
nkeynes@143
   325
	if( status != 0 ) {
nkeynes@143
   326
	    ide_set_packet_error( status );
nkeynes@143
   327
	    data_buffer[6] = (lba >> 8) & 0xFF;
nkeynes@143
   328
	    data_buffer[7] = lba & 0xFF;
nkeynes@125
   329
	    return;
nkeynes@125
   330
	}
nkeynes@138
   331
	ide_set_read_buffer( data_buffer, datalen, blocksize );
nkeynes@125
   332
	break;
nkeynes@149
   333
    case PKT_CMD_SPIN_UP:
nkeynes@149
   334
	/* do nothing? */
nkeynes@149
   335
	break;
nkeynes@142
   336
    default:
nkeynes@142
   337
	ide_set_packet_error( PKT_ERR_BADCMD ); /* Invalid command */
nkeynes@142
   338
	return;
nkeynes@125
   339
    }
nkeynes@142
   340
    ide_set_packet_error( PKT_ERR_OK );
nkeynes@125
   341
}
nkeynes@125
   342
nkeynes@125
   343
void ide_write_buffer( unsigned char *data, int datalen ) {
nkeynes@2
   344
    switch( idereg.command ) {
nkeynes@2
   345
        case IDE_CMD_PACKET:
nkeynes@125
   346
	    ide_packet_command( data );
nkeynes@2
   347
            break;
nkeynes@2
   348
    }
nkeynes@2
   349
}
nkeynes@125
   350
nkeynes@125
   351
/**
nkeynes@125
   352
 * DMA read request
nkeynes@125
   353
 *
nkeynes@125
   354
 * This method is called from the ASIC side when a DMA read request is
nkeynes@125
   355
 * initiated. If there is a pending DMA transfer already, we copy the
nkeynes@125
   356
 * data immediately, otherwise we record the DMA buffer for use when we
nkeynes@125
   357
 * get to actually doing the transfer.
nkeynes@125
   358
 */
nkeynes@125
   359
void ide_dma_read_req( uint32_t addr, uint32_t length )
nkeynes@125
   360
{
nkeynes@125
   361
    
nkeynes@125
   362
nkeynes@125
   363
}
.