Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 256:8bac2f96ca1b
prev254:7c9e34c37670
next258:8864fae65928
author nkeynes
date Thu Dec 21 11:13:10 2006 +0000 (13 years ago)
permissions -rw-r--r--
last change Put ide_raise_interrupt() back in after set feature - it's needed even tho
the test case seemed to indicate that it didn't happen...
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.21 2006-12-21 11:13:10 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 	ide_raise_interrupt();
   404 	break;
   405     default:
   406 	WARN( "IDE: Unimplemented command: %02X", val );
   407     }
   408 }
   410 /**
   411  * Execute a packet command. This particular method is responsible for parsing
   412  * the command buffers (12 bytes), and generating the appropriate responses, 
   413  * although the actual implementation is mostly delegated to gdrom.c
   414  */
   415 void ide_packet_command( unsigned char *cmd )
   416 {
   417     uint32_t length, datalen;
   418     uint32_t lba, status;
   419     int mode;
   420     int blocksize = idereg.lba1 + (idereg.lba2<<8);
   422     /* Okay we have the packet in the command buffer */
   423     INFO( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   424 	  cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   425 	  cmd[8], cmd[9], cmd[10], cmd[11] );
   427     if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
   428 	ide_set_packet_result( PKT_ERR_RESET );
   429 	idereg.was_reset = FALSE;
   430 	return;
   431     }
   433     switch( cmd[0] ) {
   434     case PKT_CMD_TEST_READY:
   435 	if( !gdrom_is_mounted() ) {
   436 	    ide_set_packet_result( PKT_ERR_NODISC );
   437 	} else {
   438 	    ide_set_packet_result( 0 );
   439 	    ide_raise_interrupt();
   440 	    idereg.status = 0x50;
   441 	}
   442 	break;
   443     case PKT_CMD_IDENTIFY:
   444 	lba = cmd[2];
   445 	if( lba >= sizeof(gdrom_ident) ) {
   446 	    ide_set_error(PKT_ERR_BADFIELD);
   447 	} else {
   448 	    length = cmd[4];
   449 	    if( lba+length > sizeof(gdrom_ident) )
   450 		length = sizeof(gdrom_ident) - lba;
   451 	    memcpy( data_buffer, gdrom_ident + lba, length );
   452 	    ide_start_packet_read( length, blocksize );
   453 	}
   454 	break;
   455     case PKT_CMD_SENSE:
   456 	length = cmd[4];
   457 	if( length > 10 )
   458 	    length = 10;
   459 	memcpy( data_buffer, idereg.gdrom_sense, length );
   460 	ide_start_packet_read( length, blocksize );
   461 	break;
   462     case PKT_CMD_READ_TOC:
   463 	length = (cmd[3]<<8) | cmd[4];
   464 	if( length > sizeof(struct gdrom_toc) )
   465 	    length = sizeof(struct gdrom_toc);
   467 	status = gdrom_get_toc( data_buffer );
   468 	if( status != PKT_ERR_OK ) {
   469 	    ide_set_packet_result( status );
   470 	} else {
   471 	    ide_start_packet_read( length, blocksize );
   472 	}
   473 	break;
   474     case PKT_CMD_SESSION_INFO:
   475 	length = cmd[4];
   476 	if( length > 6 )
   477 	    length = 6;
   478 	status = gdrom_get_info( data_buffer, cmd[2] );
   479 	if( status != PKT_ERR_OK ) {
   480 	    ide_set_packet_result( status );
   481 	} else {
   482 	    ide_start_packet_read( length, blocksize );
   483 	}
   484 	break;
   485     case PKT_CMD_PLAY_CD:	    
   486 	ide_set_packet_result( 0 );
   487 	ide_raise_interrupt();
   488 	idereg.status = 0x50;
   489 	break;
   490     case PKT_CMD_READ_SECTOR:
   491 	lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   492 	length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   493 	switch( cmd[1] ) {
   494 	case 0x20: mode = GDROM_MODE1; break;     /* TODO - might be unchecked? */
   495 	case 0x24: mode = GDROM_GD; break;
   496 	case 0x28: mode = GDROM_MODE2_XA1; break; /* ??? */
   497 	case 0x30: mode = GDROM_RAW; break;
   498 	default:
   499 	    ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
   500 	    ide_set_packet_result( PKT_ERR_BADFIELD );
   501 	    return;
   502 	}
   504 	if( length > data_buffer_len ) {
   505 	    do {
   506 		data_buffer_len = data_buffer_len << 1;
   507 	    } while( data_buffer_len < length );
   508 	    data_buffer = realloc( data_buffer, MAX_SECTOR_SIZE * data_buffer_len );
   509 	}
   511 	datalen = data_buffer_len;
   512 	status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );
   513 	if( status != 0 ) {
   514 	    ide_set_packet_result( status );
   515 	    idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;
   516 	    idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;
   517 	    idereg.gdrom_sense[7] = lba & 0xFF;
   518 	} else {
   519 	    idereg.last_read_lba = lba + length;
   520 	    idereg.last_read_track = gdrom_get_track_no_by_lba( idereg.last_read_lba );
   521 	    ide_start_packet_read( datalen, blocksize );
   522 	}
   523 	break;
   524     case PKT_CMD_SPIN_UP:
   525 	/* do nothing? */
   526 	ide_set_packet_result( PKT_ERR_OK );
   527 	ide_raise_interrupt();
   528 	break;
   529     case PKT_CMD_STATUS:
   530 	length = cmd[4];
   531 	if( !gdrom_is_mounted() ) {
   532 	    ide_set_packet_result( PKT_ERR_NODISC );
   533 	} else {
   534 	    switch( cmd[1] ) {
   535 	    case 0:
   536 		if( length > sizeof(gdrom_status) ) {
   537 		    length = sizeof(gdrom_status);
   538 		}
   539 		memcpy( data_buffer, gdrom_status, length );
   540 		ide_start_packet_read( length, blocksize );
   541 		break;
   542 	    case 1:
   543 		if( length > 14 ) {
   544 		    length = 14;
   545 		}
   546 		gdrom_track_t track = gdrom_get_track(idereg.last_read_track);
   547 		int offset = idereg.last_read_lba - track->lba;
   548 		data_buffer[0] = 0x00;
   549 		data_buffer[1] = 0x15; /* ??? */
   550 		data_buffer[2] = 0x00;
   551 		data_buffer[3] = 0x0E;
   552 		data_buffer[4] = track->flags;
   553 		data_buffer[5] = idereg.last_read_track;
   554 		data_buffer[6] = 0x01; /* ?? */
   555 		data_buffer[7] = (offset >> 16) & 0xFF;
   556 		data_buffer[8] = (offset >> 8) & 0xFF;
   557 		data_buffer[9] = offset & 0xFF;
   558 		data_buffer[10] = (idereg.last_read_lba >> 24) & 0xFF;
   559 		data_buffer[11] = (idereg.last_read_lba >> 16) & 0xFF;
   560 		data_buffer[12] = (idereg.last_read_lba >> 8) & 0xFF;
   561 		data_buffer[13] = idereg.last_read_lba & 0xFF;
   562 		ide_start_packet_read( length, blocksize );
   563 		break;
   564 	    }
   565 	}
   566 	break;
   567     case PKT_CMD_71:
   568 	/* This is a weird one. As far as I can tell it returns random garbage
   569 	 * (and not even the same length each time, never mind the same data).
   570 	 * For sake of something to do, it returns the results from a test dump
   571 	 */
   572 	memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   573 	ide_start_packet_read( sizeof(gdrom_71), blocksize );
   574 	break;
   575     default:
   576 	ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   577 	return;
   578     }
   579 }
.