Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 254:7c9e34c37670
prev250:84e056e12a19
next256:8bac2f96ca1b
author nkeynes
date Thu Dec 21 11:12:19 2006 +0000 (17 years ago)
permissions -rw-r--r--
last change Fix reset PC when invoked from the SH4 itself
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.20 2006-12-21 10:15:54 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 = length & 0xFF;
   227 	idereg.lba2 = (length >> 8) & 0xFF;
   228 	//	idereg.lba1 = blocksize & 0xFF;
   229 	//	idereg.lba2 = blocksize >> 8; 
   230 	idereg.block_length = blocksize;
   231 	idereg.block_left = blocksize;
   232 	ide_raise_interrupt( );
   233     }
   234 }
   236 static void ide_start_packet_read( int length, int blocksize )
   237 {
   238     ide_set_packet_result( PKT_ERR_OK );
   239     ide_start_read( length, blocksize, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   240 }
   242 static void ide_raise_interrupt( void )
   243 {
   244     if( idereg.intrq_pending == 0 ) {
   245 	idereg.intrq_pending = 1;
   246 	if( IS_IDE_IRQ_ENABLED() )
   247 	    asic_event( EVENT_IDE );
   248     }
   249 }
   251 static void ide_clear_interrupt( void ) 
   252 {
   253     if( idereg.intrq_pending != 0 ) {
   254 	idereg.intrq_pending = 0;
   255 	if( IS_IDE_IRQ_ENABLED() )
   256 	    asic_clear_event( EVENT_IDE );
   257     }
   258 }
   260 static void ide_set_error( int error_code )
   261 {
   262     idereg.status = 0x51;
   263     idereg.error = error_code;
   264 }
   266 uint8_t ide_read_status( void ) 
   267 {
   268     if( (idereg.status & IDE_STATUS_BSY) == 0 )
   269 	ide_clear_interrupt();
   270     return idereg.status;
   271 }
   273 uint16_t ide_read_data_pio( void ) {
   274     if( idereg.state == IDE_STATE_PIO_READ ) {
   275 	uint16_t rv = READ_BUFFER();
   276 	idereg.data_offset += 2;
   277 	idereg.block_left -= 2;
   278 	if( idereg.data_offset >= idereg.data_length ) {
   279 	    idereg.state = IDE_STATE_IDLE;
   280 	    idereg.status &= ~IDE_STATUS_DRQ;
   281 	    idereg.data_offset = -1;
   282 	    idereg.count = 3; /* complete */
   283 	    ide_raise_interrupt();
   284 	} else if( idereg.block_left <= 0 ) {
   285 	    idereg.block_left = idereg.block_length;
   286 	    ide_raise_interrupt();
   287 	}
   288 	return rv;
   289     } else {
   290         return 0xFFFF;
   291     }
   292 }
   295 /**
   296  * DMA read request
   297  *
   298  * This method is called from the ASIC side when a DMA read request is
   299  * initiated. If there is a pending DMA transfer already, we copy the
   300  * data immediately, otherwise we record the DMA buffer for use when we
   301  * get to actually doing the transfer.
   302  * @return number of bytes transfered
   303  */
   304 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
   305 {
   306     if( idereg.state == IDE_STATE_DMA_READ ) {
   307 	int xferlen = length;
   308 	int remaining = idereg.data_length - idereg.data_offset;
   309 	if( xferlen > remaining )
   310 	    xferlen = remaining;
   311 	mem_copy_to_sh4( addr, data_buffer + idereg.data_offset, xferlen );
   312 	idereg.data_offset += xferlen;
   313 	if( idereg.data_offset >= idereg.data_length ) {
   314 	    idereg.data_offset = -1;
   315 	    idereg.state = IDE_STATE_IDLE;
   316 	    idereg.status = 0x50;
   317 	    idereg.count = 0x03;
   318 	    ide_raise_interrupt();
   319 	    asic_event( EVENT_IDE_DMA );
   320 	}
   321 	return xferlen;
   322     }
   323     return 0;
   324 }
   326 void ide_write_data_pio( uint16_t val ) {
   327     if( idereg.state == IDE_STATE_CMD_WRITE ) {
   328 	WRITE_BUFFER(val);
   329 	idereg.data_offset+=2;
   330 	if( idereg.data_offset >= idereg.data_length ) {
   331 	    idereg.state = IDE_STATE_BUSY;
   332 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   333 	    idereg.data_offset = -1;
   334 	    ide_packet_command(data_buffer);
   335 	}
   336     } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
   337 	WRITE_BUFFER(val);
   338 	if( idereg.data_offset >= idereg.data_length ) {
   339 	    idereg.state = IDE_STATE_BUSY;
   340 	    idereg.data_offset = -1;
   341 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   342 	    /* ??? - no data writes yet anyway */
   343 	}
   344     }
   345 }
   347 void ide_write_control( uint8_t val ) {
   348     if( IS_IDE_IRQ_ENABLED() ) {
   349 	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   350 	    asic_clear_event( EVENT_IDE );
   351     } else {
   352 	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   353 	    asic_event( EVENT_IDE );
   354     }
   355     idereg.control = val;
   356 }
   358 void ide_write_command( uint8_t val ) {
   359     ide_clear_interrupt();
   360     idereg.command = val;
   361     switch( val ) {
   362     case IDE_CMD_NOP: /* Effectively an "abort" */
   363 	idereg.state = IDE_STATE_IDLE;
   364 	idereg.status = 0x51;
   365 	idereg.error = 0x04;
   366 	idereg.data_offset = -1;
   367 	ide_raise_interrupt();
   368 	return;
   369     case IDE_CMD_RESET_DEVICE:
   370 	ide_reset();
   371 	break;
   372     case IDE_CMD_PACKET:
   373 	ide_start_command_packet_write();
   374 	break;
   375     case IDE_CMD_SET_FEATURE:
   376 	switch( idereg.feature ) {
   377 	case IDE_FEAT_SET_TRANSFER_MODE:
   378 	    switch( idereg.count & 0xF8 ) {
   379 	    case IDE_XFER_PIO:
   380 		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   381 		break;
   382 	    case IDE_XFER_PIO_FLOW:
   383 		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   384 		break;
   385 	    case IDE_XFER_MULTI_DMA:
   386 		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   387 		break;
   388 	    case IDE_XFER_ULTRA_DMA:
   389 		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   390 		break;
   391 	    default:
   392 		INFO( "Setting unknown transfer mode: %02X", idereg.count );
   393 		break;
   394 	    }
   395 	    break;
   396 	default:
   397 	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   398 	}
   399 	idereg.status = 0x50;
   400 	idereg.error = 0x00;
   401 	idereg.lba1 = 0x00;
   402 	idereg.lba2 = 0x00;
   403 	break;
   404     default:
   405 	WARN( "IDE: Unimplemented command: %02X", val );
   406     }
   407 }
   409 /**
   410  * Execute a packet command. This particular method is responsible for parsing
   411  * the command buffers (12 bytes), and generating the appropriate responses, 
   412  * although the actual implementation is mostly delegated to gdrom.c
   413  */
   414 void ide_packet_command( unsigned char *cmd )
   415 {
   416     uint32_t length, datalen;
   417     uint32_t lba, status;
   418     int mode;
   419     int blocksize = idereg.lba1 + (idereg.lba2<<8);
   421     /* Okay we have the packet in the command buffer */
   422     INFO( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   423 	  cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   424 	  cmd[8], cmd[9], cmd[10], cmd[11] );
   426     if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
   427 	ide_set_packet_result( PKT_ERR_RESET );
   428 	idereg.was_reset = FALSE;
   429 	return;
   430     }
   432     switch( cmd[0] ) {
   433     case PKT_CMD_TEST_READY:
   434 	if( !gdrom_is_mounted() ) {
   435 	    ide_set_packet_result( PKT_ERR_NODISC );
   436 	} else {
   437 	    ide_set_packet_result( 0 );
   438 	    ide_raise_interrupt();
   439 	    idereg.status = 0x50;
   440 	}
   441 	break;
   442     case PKT_CMD_IDENTIFY:
   443 	lba = cmd[2];
   444 	if( lba >= sizeof(gdrom_ident) ) {
   445 	    ide_set_error(PKT_ERR_BADFIELD);
   446 	} else {
   447 	    length = cmd[4];
   448 	    if( lba+length > sizeof(gdrom_ident) )
   449 		length = sizeof(gdrom_ident) - lba;
   450 	    memcpy( data_buffer, gdrom_ident + lba, length );
   451 	    ide_start_packet_read( length, blocksize );
   452 	}
   453 	break;
   454     case PKT_CMD_SENSE:
   455 	length = cmd[4];
   456 	if( length > 10 )
   457 	    length = 10;
   458 	memcpy( data_buffer, idereg.gdrom_sense, length );
   459 	ide_start_packet_read( length, blocksize );
   460 	break;
   461     case PKT_CMD_READ_TOC:
   462 	length = (cmd[3]<<8) | cmd[4];
   463 	if( length > sizeof(struct gdrom_toc) )
   464 	    length = sizeof(struct gdrom_toc);
   466 	status = gdrom_get_toc( data_buffer );
   467 	if( status != PKT_ERR_OK ) {
   468 	    ide_set_packet_result( status );
   469 	} else {
   470 	    ide_start_packet_read( length, blocksize );
   471 	}
   472 	break;
   473     case PKT_CMD_SESSION_INFO:
   474 	length = cmd[4];
   475 	if( length > 6 )
   476 	    length = 6;
   477 	status = gdrom_get_info( data_buffer, cmd[2] );
   478 	if( status != PKT_ERR_OK ) {
   479 	    ide_set_packet_result( status );
   480 	} else {
   481 	    ide_start_packet_read( length, blocksize );
   482 	}
   483 	break;
   484     case PKT_CMD_PLAY_CD:	    
   485 	ide_set_packet_result( 0 );
   486 	ide_raise_interrupt();
   487 	idereg.status = 0x50;
   488 	break;
   489     case PKT_CMD_READ_SECTOR:
   490 	lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   491 	length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   492 	switch( cmd[1] ) {
   493 	case 0x20: mode = GDROM_MODE1; break;     /* TODO - might be unchecked? */
   494 	case 0x24: mode = GDROM_GD; break;
   495 	case 0x28: mode = GDROM_MODE2_XA1; break; /* ??? */
   496 	case 0x30: mode = GDROM_RAW; break;
   497 	default:
   498 	    ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
   499 	    ide_set_packet_result( PKT_ERR_BADFIELD );
   500 	    return;
   501 	}
   503 	if( length > data_buffer_len ) {
   504 	    do {
   505 		data_buffer_len = data_buffer_len << 1;
   506 	    } while( data_buffer_len < length );
   507 	    data_buffer = realloc( data_buffer, MAX_SECTOR_SIZE * data_buffer_len );
   508 	}
   510 	datalen = data_buffer_len;
   511 	status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );
   512 	if( status != 0 ) {
   513 	    ide_set_packet_result( status );
   514 	    idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;
   515 	    idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;
   516 	    idereg.gdrom_sense[7] = lba & 0xFF;
   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, blocksize );
   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, blocksize );
   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, blocksize );
   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), blocksize );
   573 	break;
   574     default:
   575 	ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   576 	return;
   577     }
   578 }
.