Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 258:8864fae65928
prev256:8bac2f96ca1b
next342:850502f0e8de
author nkeynes
date Thu Jan 25 10:18:42 2007 +0000 (17 years ago)
permissions -rw-r--r--
last change Increase SH4 speed to 100Mips
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.22 2006-12-29 00:23:13 nkeynes Exp $
     3  *
     4  * IDE interface implementation
     5  *
     6  *
     7  * Note: All references to read/write are from the host's point of view.
     8  *
     9  * See: INF-8020 
    10  * Copyright (c) 2005 Nathan Keynes.
    11  *
    12  * This program is free software; you can redistribute it and/or modify
    13  * it under the terms of the GNU General Public License as published by
    14  * the Free Software Foundation; either version 2 of the License, or
    15  * (at your option) any later version.
    16  *
    17  * This program is distributed in the hope that it will be useful,
    18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    20  * GNU General Public License for more details.
    21  */
    23 #define MODULE ide_module
    25 #include <assert.h>
    26 #include <stdlib.h>
    27 #include "dream.h"
    28 #include "asic.h"
    29 #include "gdrom/ide.h"
    30 #include "gdrom/gdrom.h"
    31 #include "gdrom/packet.h"
    33 #define MAX_WRITE_BUF 4096
    34 #define MAX_SECTOR_SIZE 2352 /* Audio sector */
    35 #define DEFAULT_DATA_SECTORS 8
    37 static void ide_init( void );
    38 static void ide_reset( void );
    39 static void ide_save_state( FILE *f );
    40 static int ide_load_state( FILE *f );
    41 static void ide_raise_interrupt( void );
    42 static void ide_clear_interrupt( void );
    43 static void ide_packet_command( unsigned char *data );
    45 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
    46 				       NULL, ide_save_state, ide_load_state };
    48 struct ide_registers idereg;
    49 unsigned char *data_buffer = NULL;
    50 uint32_t data_buffer_len = 0;
    52 #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
    53 #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
    55 /* "\0\0\0\0\xb4\x19\0\0\x08SE      REV 6.42990316" */
    56 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
    57                        0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
    58                        0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
    59                        0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
    61 unsigned char gdrom_71[] = { 0x3E, 0x0F, 0x90, 0xBE,  0x1D, 0xD9, 0x89, 0x04,  0x28, 0x3A, 0x8E, 0x26,  0x5C, 0x95, 0x10, 0x5A,
    62 				 0x0A, 0x99, 0xEE, 0xFB,  0x69, 0xCE, 0xD9, 0x63,  0x00, 0xF5, 0x0A, 0xBC,  0x2C, 0x0D, 0xF8, 0xE2,
    63 				 0x05, 0x02, 0x00, 0x7C,  0x03, 0x00, 0x3D, 0x08,  0xD8, 0x8D, 0x08, 0x7A,  0x6D, 0x00, 0x35, 0x06,
    64 				 0xBA, 0x66, 0x10, 0x00,  0x91, 0x08, 0x10, 0x29,  0xD0, 0x45, 0xDA, 0x00,  0x2D, 0x05, 0x69, 0x09,
    65 				 0x00, 0x5E, 0x0F, 0x70,  0x86, 0x12, 0x6C, 0x77,  0x5A, 0xFB, 0xCD, 0x56,  0xFB, 0xF7, 0xB7, 0x00,
    66 				 0x5D, 0x07, 0x19, 0x99,  0xF2, 0xAF, 0x00, 0x63,  0x03, 0x00, 0xF0, 0x10,  0xBE, 0xD7, 0xA0, 0x63,
    67 				 0xFA, 0x84, 0xA7, 0x74,  0x94, 0xEF, 0xAD, 0xC2,  0xAC, 0x00, 0x78, 0x07,  0x9F, 0x57, 0x0B, 0x62,
    68 				 0x00, 0xFE, 0x08, 0x08,  0x5D, 0x5A, 0x6A, 0x54,  0x00, 0xE2, 0x09, 0x93,  0x7E, 0x62, 0x2A, 0x5E,
    69 				 0xDA, 0x00, 0x7E, 0x0F,  0xF0, 0x07, 0x01, 0x6D,  0x50, 0x86, 0xDD, 0x4A,  0x15, 0x54, 0xC7, 0xEC,
    70 				 0x00, 0xF2, 0x0B, 0x07,  0xF8, 0x1A, 0xB0, 0x99,  0x3B, 0xF1, 0x36, 0x00,  0x94, 0x07, 0x34, 0xE3,
    71 				 0xBC, 0x6E, 0x00, 0x34,  0x0D, 0x6F, 0xDA, 0xBD,  0xEE, 0xF7, 0xCC, 0xCE,  0x39, 0x7E, 0xE3, 0x00,
    72 				 0x14, 0x08, 0xDC, 0xD2,  0xB9, 0xF9, 0x31, 0x00,  0xB0, 0x0C, 0x10, 0xA3,  0x45, 0x12, 0xC7, 0xCD,
    73 				 0xBF, 0x05, 0x37, 0x00,  0xC4, 0x0D, 0x5F, 0xE0,  0x59, 0xBB, 0x01, 0x59,  0x03, 0xD6, 0x29, 0x9C,
    74 				 0x00, 0x01, 0x0A, 0x09,  0xAA, 0xA8, 0xA8, 0x24,  0x0B, 0x66, 0x00, 0x5C,  0x05, 0xA5, 0xCE, 0x00,
    75 				 0xC1, 0x0B, 0xB7, 0xA0,  0x6F, 0xE9, 0x2B, 0xCC,  0xB5, 0xFC, 0x00, 0x8D,  0x05, 0xF4, 0xAC, 0x00,
    76 				 0x57, 0x04, 0xB6, 0x00,  0xFC, 0x03, 0x00, 0xC3,  0x10, 0x43, 0x3B, 0xBE,  0xA2, 0x96, 0xC3, 0x65,
    77 				 0x9F, 0x9A, 0x88, 0xD5,  0x49, 0x68, 0x00, 0xDC,  0x11, 0x56, 0x23, 0x2D,  0xF9, 0xFC, 0xF5, 0x8B,
    78 				 0x1B, 0xB1, 0xB7, 0x10,  0x21, 0x1C, 0x12, 0x00,  0x0D, 0x0D, 0xEB, 0x86,  0xA2, 0x49, 0x8D, 0x8D,
    79 				 0xBE, 0xA1, 0x6D, 0x53,  0x00, 0xE1, 0x0A, 0x8E,  0x67, 0xAA, 0x16, 0x79,  0x39, 0x59, 0x00, 0x36,
    80 				 0x0B, 0x2A, 0x4E, 0xAE,  0x51, 0x4B, 0xD0, 0x66,  0x33, 0x00, 0x8A, 0x07,  0xCD, 0x6F, 0xBA, 0x92,
    81 				 0x00, 0x1A, 0x0E, 0xDF,  0x4A, 0xB3, 0x77, 0x1F,  0xA5, 0x90, 0x19, 0xFA,  0x59, 0xD7, 0x00, 0x04,
    82 				 0x0F, 0xAC, 0xCA, 0x9F,  0xA4, 0xFC, 0x6D, 0x90,  0x86, 0x9E, 0x1F, 0x44,  0x40, 0x00, 0x9F, 0x04,
    83 				 0x56, 0x00, 0x22, 0x03,  0x00, 0xB8, 0x10, 0x2C,  0x7A, 0x53, 0xA4, 0xBF,  0xA3, 0x90, 0x90, 0x14,
    84 				 0x9D, 0x46, 0x6C, 0x96,  0x00, 0xC6, 0x0B, 0x9B,  0xBB, 0xB0, 0xAE, 0x60,  0x92, 0x8E, 0x0C, 0x00,
    85 				 0x14, 0x06, 0x4B, 0xAE,  0x7F, 0x00, 0x5C, 0x0B,  0x23, 0xFA, 0xE7, 0x51,  0xDA, 0x61, 0x49, 0x5E,
    86 				 0x00, 0xD7, 0x0B, 0x01,  0xFC, 0x55, 0x31, 0x84,  0xC5, 0x0C, 0x98, 0x00,  0x97, 0x50, 0x6E, 0xF9,
    87 				 0xEE, 0x75, 0x92, 0x53,  0xD3, 0x66, 0xA4, 0xAF,  0x3B, 0xFE, 0x7B, 0x27,  0x30, 0xBB, 0xB6, 0xF2,
    88 				 0x76, 0x22, 0x45, 0x42,  0xCA, 0xF9, 0xF0, 0xDE,  0x9F, 0x45, 0x16, 0x68,  0x22, 0xB9, 0x84, 0x28,
    89 				 0x8F, 0x2B, 0xB5, 0x5C,  0xD2, 0xF5, 0x45, 0x36,  0x3E, 0x76, 0xC6, 0xBF,  0x32, 0x5C, 0x41, 0xA6,
    90 				 0x26, 0xC7, 0x82, 0x2F,  0x2E, 0xB5, 0x75, 0xC6,  0xE6, 0x67, 0x9E, 0x77,  0x94, 0xAF, 0x6A, 0x05,
    91 				 0xC0, 0x05, 0x61, 0x71,  0x89, 0x5A, 0xB1, 0xD0,  0xFC, 0x7E, 0xC0, 0x9B,  0xCB, 0x3B, 0x69, 0xD9,
    92 				 0x5F, 0xAF, 0xCA, 0xAB,  0x25, 0xD5, 0xBE, 0x8A,  0x6B, 0xB0, 0xFB, 0x61,  0x6C, 0xEB, 0x85, 0x6E,
    93 				 0x7A, 0x48, 0xFF, 0x97,  0x91, 0x06, 0x3D, 0x4D,  0x68, 0xD3, 0x65, 0x83,  0x90, 0xA0, 0x08, 0x5C,
    94 				 0xFC, 0xEE, 0x7C, 0x33,  0x43, 0x7F, 0x80, 0x52,  0x8B, 0x19, 0x72, 0xF2,  0xC9, 0xAB, 0x93, 0xAF,
    95 				 0x16, 0xED, 0x36, 0x48,  0xAB, 0xC9, 0xD1, 0x03,  0xB3, 0xDC, 0x2F, 0xF2,  0x92, 0x3F, 0x0A, 0x19,
    96 				 0x25, 0xE2, 0xEF, 0x7A,  0x22, 0xDA, 0xDB, 0xCB,  0x32, 0x12, 0x61, 0x49,  0x5B, 0x74, 0x7C, 0x65,
    97 				 0x20, 0x89, 0x54, 0x9E,  0x0E, 0xC9, 0x52, 0xE3,  0xC9, 0x9A, 0x44, 0xC9,  0x5D, 0xA6, 0x77, 0xC0,
    98 				 0xE7, 0x60, 0x91, 0x80,  0x50, 0x1F, 0x33, 0xB1,  0xCD, 0xAD, 0xF4, 0x0D,  0xBB, 0x08, 0xB1, 0xD0,
    99 				 0x13, 0x95, 0xAE, 0xC9,  0xE2, 0x64, 0xA2, 0x65,  0xFB, 0x8F, 0xE9, 0xA2,  0x8A, 0xBC, 0x98, 0x81,
   100 				 0x45, 0xB4, 0x55, 0x4E,  0xB9, 0x74, 0xB4, 0x50,  0x76, 0xBF, 0xF0, 0x45,  0xE7, 0xEE, 0x41, 0x64,
   101 				 0x9F, 0xB5, 0xE0, 0xBB,  0x1C, 0xBB, 0x28, 0x66,  0x1B, 0xDD, 0x2B, 0x02,  0x66, 0xBF, 0xFD, 0x7D,
   102 				 0x37, 0x35, 0x1D, 0x76,  0x21, 0xC3, 0x8F, 0xAF,  0xF6, 0xF9, 0xE9, 0x27,  0x48, 0xE7, 0x3D, 0x95,
   103 				 0x74, 0x0C, 0x77, 0x88,  0x56, 0xD9, 0x84, 0xC8,  0x7D, 0x20, 0x31, 0x43,  0x53, 0xF1, 0xC1, 0xC7,
   104 				 0xC9, 0xF7, 0x5C, 0xC0,  0xA6, 0x5A, 0x27, 0x0A,  0x41, 0xD4, 0x44, 0x94,  0x65, 0x4F, 0xE2, 0x53,
   105 				 0x60, 0x0B, 0xD1, 0x23,  0x6C, 0x0C, 0xBC, 0x70,  0x6C, 0x26, 0x1A, 0x61,  0x1D, 0x35, 0x88, 0xEC,
   106 				 0xB8, 0x15, 0xE3, 0xB4,  0x82, 0xEE, 0xB3, 0x21,  0xAC, 0x6C, 0xB7, 0x33,  0x6D, 0x78, 0x0C, 0x0D,
   107 				 0xB4, 0x0B, 0x29, 0xF2,  0xD4, 0x8C, 0x3F, 0xDD,  0x3F, 0x47, 0xDD, 0xF2,  0xD8, 0x39, 0x57, 0x20,
   108 				 0x28, 0xD8, 0xDD, 0x32,  0xE2, 0x6A, 0x47, 0x53,  0x57, 0xC6, 0xFA, 0x7A,  0x38, 0x30, 0x31, 0x8F,
   109 				 0xE7, 0xD3, 0x84, 0x2B,  0x5D, 0x4F, 0x95, 0x98,  0xED, 0x0B, 0xD7, 0x50,  0x0C, 0x49, 0xDA, 0x59,
   110 				 0x15, 0xF1, 0x39, 0xF3,  0x40, 0xDC, 0xDC, 0x25,  0x24, 0x56, 0x6E, 0xA9,  0x2F, 0xF0, 0x00, 0x00 };
   113 char gdrom_status[] = { 
   114     0x00, 0x15, 0x00, 0x64, 0x00, 0x40, 0x00, 0x00, 
   115     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
   116     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
   117     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
   118     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   119     0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   120     0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   121     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   122     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
   123     0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   124     0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
   125     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
   126     0x00, 0x40, 0x00, 0x00 };
   129 static void ide_init( void )
   130 {
   131     ide_reset();
   132     data_buffer_len = DEFAULT_DATA_SECTORS; 
   133     data_buffer = malloc( MAX_SECTOR_SIZE * data_buffer_len ); 
   134     assert( data_buffer != NULL );
   135 }
   137 static void ide_reset( void )
   138 {
   139     ide_clear_interrupt();
   140     idereg.error = 0x01;
   141     idereg.count = 0x01;
   142     idereg.lba0 = /* 0x21; */ 0x81;
   143     idereg.lba1 = 0x14;
   144     idereg.lba2 = 0xeb;
   145     idereg.feature = 0; /* Indeterminate really */
   146     idereg.status = 0x00;
   147     idereg.device = 0x00;
   148     idereg.disc = gdrom_is_mounted() ? (IDE_DISC_CDROM|IDE_DISC_READY) : IDE_DISC_NONE;
   149     idereg.state = IDE_STATE_IDLE;
   150     memset( idereg.gdrom_sense, '\0', 10 );
   151     idereg.data_offset = -1;
   152     idereg.data_length = -1;
   153     idereg.last_read_track = 1;
   154     idereg.last_read_lba = 150;
   155     idereg.was_reset = TRUE;
   156 }
   158 static void ide_save_state( FILE *f )
   159 {
   160     fwrite( &idereg, sizeof(idereg), 1, f );
   161     fwrite( &data_buffer_len, sizeof(data_buffer_len), 1, f );
   162     fwrite( data_buffer, MAX_SECTOR_SIZE, data_buffer_len, f );
   163 }
   165 static int ide_load_state( FILE *f )
   166 {
   167     uint32_t length;
   168     fread( &idereg, sizeof(idereg), 1, f );
   169     fread( &length, sizeof(uint32_t), 1, f );
   170     if( length > data_buffer_len ) {
   171 	if( data_buffer != NULL )
   172 	    free( data_buffer );
   173 	data_buffer = malloc( MAX_SECTOR_SIZE * length  );
   174 	assert( data_buffer != NULL );
   175 	data_buffer_len = length;
   176     }
   177     fread( data_buffer, MAX_SECTOR_SIZE, length, f );
   178     return 0;
   179 }
   181 /************************ State transitions *************************/
   183 void ide_set_packet_result( uint16_t result )
   184 {
   185     idereg.gdrom_sense[0] = 0xf0;
   186     idereg.gdrom_sense[2] = result & 0xFF;
   187     idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
   188     idereg.error = (result & 0x0F) << 4;
   189     idereg.count = 3;
   190     if( result != 0 ) {
   191 	idereg.status = 0x51;
   192 	ide_raise_interrupt();
   193     } else {
   194 	idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
   195     }
   196 }
   198 /**
   199  * Begin command packet write to the device. This is always 12 bytes of PIO data
   200  */
   201 static void ide_start_command_packet_write( )
   202 {
   203     idereg.state = IDE_STATE_CMD_WRITE;
   204     idereg.status = 0x58;
   205     idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
   206     idereg.count = IDE_COUNT_CD;
   207     idereg.data_offset = 0;
   208     idereg.data_length = 12;
   209 }
   211 /**
   212  * Begin PIO read from the device. The data is assumed to already be
   213  * in the buffer at this point.
   214  */
   215 static void ide_start_read( int length, int blocksize, gboolean dma ) 
   216 {
   217     idereg.count = IDE_COUNT_IO;
   218     idereg.data_length = length;
   219     idereg.data_offset = 0;
   220     if( dma ) {
   221 	idereg.state = IDE_STATE_DMA_READ;
   222 	idereg.status = 0xD0;
   223     } else {
   224 	idereg.state = IDE_STATE_PIO_READ;
   225 	idereg.status = 0x58;
   226 	idereg.lba1 = blocksize & 0xFF;
   227 	idereg.lba2 = blocksize >> 8; 
   228 	idereg.block_length = blocksize;
   229 	idereg.block_left = blocksize;
   230 	ide_raise_interrupt( );
   231     }
   232 }
   234 static void ide_start_packet_read( int length, int blocksize )
   235 {
   236     ide_set_packet_result( PKT_ERR_OK );
   237     ide_start_read( length, blocksize, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   238 }
   240 static void ide_raise_interrupt( void )
   241 {
   242     if( idereg.intrq_pending == 0 ) {
   243 	idereg.intrq_pending = 1;
   244 	if( IS_IDE_IRQ_ENABLED() )
   245 	    asic_event( EVENT_IDE );
   246     }
   247 }
   249 static void ide_clear_interrupt( void ) 
   250 {
   251     if( idereg.intrq_pending != 0 ) {
   252 	idereg.intrq_pending = 0;
   253 	if( IS_IDE_IRQ_ENABLED() )
   254 	    asic_clear_event( EVENT_IDE );
   255     }
   256 }
   258 static void ide_set_error( int error_code )
   259 {
   260     idereg.status = 0x51;
   261     idereg.error = error_code;
   262 }
   264 uint8_t ide_read_status( void ) 
   265 {
   266     if( (idereg.status & IDE_STATUS_BSY) == 0 )
   267 	ide_clear_interrupt();
   268     return idereg.status;
   269 }
   271 uint16_t ide_read_data_pio( void ) {
   272     if( idereg.state == IDE_STATE_PIO_READ ) {
   273 	uint16_t rv = READ_BUFFER();
   274 	idereg.data_offset += 2;
   275 	idereg.block_left -= 2;
   276 	if( idereg.data_offset >= idereg.data_length ) {
   277 	    idereg.state = IDE_STATE_IDLE;
   278 	    idereg.status &= ~IDE_STATUS_DRQ;
   279 	    idereg.data_offset = -1;
   280 	    idereg.count = 3; /* complete */
   281 	    ide_raise_interrupt();
   282 	} else if( idereg.block_left <= 0 ) {
   283 	    idereg.block_left = idereg.block_length;
   284 	    ide_raise_interrupt();
   285 	}
   286 	return rv;
   287     } else {
   288         return 0xFFFF;
   289     }
   290 }
   293 /**
   294  * DMA read request
   295  *
   296  * This method is called from the ASIC side when a DMA read request is
   297  * initiated. If there is a pending DMA transfer already, we copy the
   298  * data immediately, otherwise we record the DMA buffer for use when we
   299  * get to actually doing the transfer.
   300  * @return number of bytes transfered
   301  */
   302 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
   303 {
   304     if( idereg.state == IDE_STATE_DMA_READ ) {
   305 	int xferlen = length;
   306 	int remaining = idereg.data_length - idereg.data_offset;
   307 	if( xferlen > remaining )
   308 	    xferlen = remaining;
   309 	mem_copy_to_sh4( addr, data_buffer + idereg.data_offset, xferlen );
   310 	idereg.data_offset += xferlen;
   311 	if( idereg.data_offset >= idereg.data_length ) {
   312 	    idereg.data_offset = -1;
   313 	    idereg.state = IDE_STATE_IDLE;
   314 	    idereg.status = 0x50;
   315 	    idereg.count = 0x03;
   316 	    ide_raise_interrupt();
   317 	    asic_event( EVENT_IDE_DMA );
   318 	}
   319 	return xferlen;
   320     }
   321     return 0;
   322 }
   324 void ide_write_data_pio( uint16_t val ) {
   325     if( idereg.state == IDE_STATE_CMD_WRITE ) {
   326 	WRITE_BUFFER(val);
   327 	idereg.data_offset+=2;
   328 	if( idereg.data_offset >= idereg.data_length ) {
   329 	    idereg.state = IDE_STATE_BUSY;
   330 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   331 	    idereg.data_offset = -1;
   332 	    ide_packet_command(data_buffer);
   333 	}
   334     } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
   335 	WRITE_BUFFER(val);
   336 	if( idereg.data_offset >= idereg.data_length ) {
   337 	    idereg.state = IDE_STATE_BUSY;
   338 	    idereg.data_offset = -1;
   339 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   340 	    /* ??? - no data writes yet anyway */
   341 	}
   342     }
   343 }
   345 void ide_write_control( uint8_t val ) {
   346     if( IS_IDE_IRQ_ENABLED() ) {
   347 	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   348 	    asic_clear_event( EVENT_IDE );
   349     } else {
   350 	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   351 	    asic_event( EVENT_IDE );
   352     }
   353     idereg.control = val;
   354 }
   356 void ide_write_command( uint8_t val ) {
   357     ide_clear_interrupt();
   358     idereg.command = val;
   359     switch( val ) {
   360     case IDE_CMD_NOP: /* Effectively an "abort" */
   361 	idereg.state = IDE_STATE_IDLE;
   362 	idereg.status = 0x51;
   363 	idereg.error = 0x04;
   364 	idereg.data_offset = -1;
   365 	ide_raise_interrupt();
   366 	return;
   367     case IDE_CMD_RESET_DEVICE:
   368 	ide_reset();
   369 	break;
   370     case IDE_CMD_PACKET:
   371 	ide_start_command_packet_write();
   372 	break;
   373     case IDE_CMD_SET_FEATURE:
   374 	switch( idereg.feature ) {
   375 	case IDE_FEAT_SET_TRANSFER_MODE:
   376 	    switch( idereg.count & 0xF8 ) {
   377 	    case IDE_XFER_PIO:
   378 		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   379 		break;
   380 	    case IDE_XFER_PIO_FLOW:
   381 		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   382 		break;
   383 	    case IDE_XFER_MULTI_DMA:
   384 		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   385 		break;
   386 	    case IDE_XFER_ULTRA_DMA:
   387 		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   388 		break;
   389 	    default:
   390 		INFO( "Setting unknown transfer mode: %02X", idereg.count );
   391 		break;
   392 	    }
   393 	    break;
   394 	default:
   395 	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   396 	}
   397 	idereg.status = 0x50;
   398 	idereg.error = 0x00;
   399 	idereg.lba1 = 0x00;
   400 	idereg.lba2 = 0x00;
   401 	ide_raise_interrupt();
   402 	break;
   403     default:
   404 	WARN( "IDE: Unimplemented command: %02X", val );
   405     }
   406 }
   408 /**
   409  * Execute a packet command. This particular method is responsible for parsing
   410  * the command buffers (12 bytes), and generating the appropriate responses, 
   411  * although the actual implementation is mostly delegated to gdrom.c
   412  */
   413 void ide_packet_command( unsigned char *cmd )
   414 {
   415     uint32_t length, datalen;
   416     uint32_t lba, status;
   417     int mode;
   418     int blocksize = idereg.lba1 + (idereg.lba2<<8);
   420     /* Okay we have the packet in the command buffer */
   421     INFO( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   422 	  cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   423 	  cmd[8], cmd[9], cmd[10], cmd[11] );
   425     if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
   426 	ide_set_packet_result( PKT_ERR_RESET );
   427 	idereg.was_reset = FALSE;
   428 	return;
   429     }
   431     switch( cmd[0] ) {
   432     case PKT_CMD_TEST_READY:
   433 	if( !gdrom_is_mounted() ) {
   434 	    ide_set_packet_result( PKT_ERR_NODISC );
   435 	} else {
   436 	    ide_set_packet_result( 0 );
   437 	    ide_raise_interrupt();
   438 	    idereg.status = 0x50;
   439 	}
   440 	break;
   441     case PKT_CMD_IDENTIFY:
   442 	lba = cmd[2];
   443 	if( lba >= sizeof(gdrom_ident) ) {
   444 	    ide_set_error(PKT_ERR_BADFIELD);
   445 	} else {
   446 	    length = cmd[4];
   447 	    if( lba+length > sizeof(gdrom_ident) )
   448 		length = sizeof(gdrom_ident) - lba;
   449 	    memcpy( data_buffer, gdrom_ident + lba, length );
   450 	    ide_start_packet_read( length, length );
   451 	}
   452 	break;
   453     case PKT_CMD_SENSE:
   454 	length = cmd[4];
   455 	if( length > 10 )
   456 	    length = 10;
   457 	memcpy( data_buffer, idereg.gdrom_sense, length );
   458 	ide_start_packet_read( length, length );
   459 	break;
   460     case PKT_CMD_READ_TOC:
   461 	length = (cmd[3]<<8) | cmd[4];
   462 	if( length > sizeof(struct gdrom_toc) )
   463 	    length = sizeof(struct gdrom_toc);
   465 	status = gdrom_get_toc( data_buffer );
   466 	if( status != PKT_ERR_OK ) {
   467 	    ide_set_packet_result( status );
   468 	} else {
   469 	    ide_start_packet_read( length, length );
   470 	}
   471 	break;
   472     case PKT_CMD_SESSION_INFO:
   473 	length = cmd[4];
   474 	if( length > 6 )
   475 	    length = 6;
   476 	status = gdrom_get_info( data_buffer, cmd[2] );
   477 	if( status != PKT_ERR_OK ) {
   478 	    ide_set_packet_result( status );
   479 	} else {
   480 	    ide_start_packet_read( length, length );
   481 	}
   482 	break;
   483     case PKT_CMD_PLAY_CD:	    
   484 	ide_set_packet_result( 0 );
   485 	ide_raise_interrupt();
   486 	idereg.status = 0x50;
   487 	break;
   488     case PKT_CMD_READ_SECTOR:
   489 	lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   490 	length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   491 	switch( cmd[1] ) {
   492 	case 0x20: mode = GDROM_MODE1; break;     /* TODO - might be unchecked? */
   493 	case 0x24: mode = GDROM_GD; break;
   494 	case 0x28: mode = GDROM_MODE2_XA1; break; /* ??? */
   495 	case 0x30: mode = GDROM_RAW; break;
   496 	default:
   497 	    ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
   498 	    ide_set_packet_result( PKT_ERR_BADFIELD );
   499 	    return;
   500 	}
   502 	if( length > data_buffer_len ) {
   503 	    do {
   504 		data_buffer_len = data_buffer_len << 1;
   505 	    } while( data_buffer_len < length );
   506 	    data_buffer = realloc( data_buffer, MAX_SECTOR_SIZE * data_buffer_len );
   507 	}
   509 	datalen = data_buffer_len;
   510 	status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );
   511 	if( status != 0 ) {
   512 	    ide_set_packet_result( status );
   513 	    idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;
   514 	    idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;
   515 	    idereg.gdrom_sense[7] = lba & 0xFF;
   516 	    WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
   517 	} else {
   518 	    idereg.last_read_lba = lba + length;
   519 	    idereg.last_read_track = gdrom_get_track_no_by_lba( idereg.last_read_lba );
   520 	    ide_start_packet_read( datalen, 0x0800 );
   521 	}
   522 	break;
   523     case PKT_CMD_SPIN_UP:
   524 	/* do nothing? */
   525 	ide_set_packet_result( PKT_ERR_OK );
   526 	ide_raise_interrupt();
   527 	break;
   528     case PKT_CMD_STATUS:
   529 	length = cmd[4];
   530 	if( !gdrom_is_mounted() ) {
   531 	    ide_set_packet_result( PKT_ERR_NODISC );
   532 	} else {
   533 	    switch( cmd[1] ) {
   534 	    case 0:
   535 		if( length > sizeof(gdrom_status) ) {
   536 		    length = sizeof(gdrom_status);
   537 		}
   538 		memcpy( data_buffer, gdrom_status, length );
   539 		ide_start_packet_read( length, length );
   540 		break;
   541 	    case 1:
   542 		if( length > 14 ) {
   543 		    length = 14;
   544 		}
   545 		gdrom_track_t track = gdrom_get_track(idereg.last_read_track);
   546 		int offset = idereg.last_read_lba - track->lba;
   547 		data_buffer[0] = 0x00;
   548 		data_buffer[1] = 0x15; /* ??? */
   549 		data_buffer[2] = 0x00;
   550 		data_buffer[3] = 0x0E;
   551 		data_buffer[4] = track->flags;
   552 		data_buffer[5] = idereg.last_read_track;
   553 		data_buffer[6] = 0x01; /* ?? */
   554 		data_buffer[7] = (offset >> 16) & 0xFF;
   555 		data_buffer[8] = (offset >> 8) & 0xFF;
   556 		data_buffer[9] = offset & 0xFF;
   557 		data_buffer[10] = (idereg.last_read_lba >> 24) & 0xFF;
   558 		data_buffer[11] = (idereg.last_read_lba >> 16) & 0xFF;
   559 		data_buffer[12] = (idereg.last_read_lba >> 8) & 0xFF;
   560 		data_buffer[13] = idereg.last_read_lba & 0xFF;
   561 		ide_start_packet_read( length, length );
   562 		break;
   563 	    }
   564 	}
   565 	break;
   566     case PKT_CMD_71:
   567 	/* This is a weird one. As far as I can tell it returns random garbage
   568 	 * (and not even the same length each time, never mind the same data).
   569 	 * For sake of something to do, it returns the results from a test dump
   570 	 */
   571 	memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   572 	ide_start_packet_read( sizeof(gdrom_71), sizeof(gdrom_71) );
   573 	break;
   574     default:
   575 	ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   576 	return;
   577     }
   578 }
.