Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 629:2811e8a2debf
prev561:533f6b478071
next678:35eb00945316
author nkeynes
date Fri Feb 08 11:30:04 2008 +0000 (12 years ago)
permissions -rw-r--r--
last change Bail out properly on read errors during a DMA cycle
view annotate diff log raw
     1 /**
     2  * $Id$
     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 "mem.h"
    29 #include "asic.h"
    30 #include "gdrom/ide.h"
    31 #include "gdrom/gdrom.h"
    32 #include "gdrom/packet.h"
    34 #define MAX_WRITE_BUF 4096
    35 #define MAX_SECTOR_SIZE 2352 /* Audio sector */
    36 #define DEFAULT_DATA_SECTORS 8
    38 static void ide_init( void );
    39 static void ide_reset( void );
    40 static uint32_t ide_run_slice( uint32_t nanosecs );
    41 static void ide_save_state( FILE *f );
    42 static int ide_load_state( FILE *f );
    43 static void ide_raise_interrupt( void );
    44 static void ide_clear_interrupt( void );
    45 static void ide_packet_command( unsigned char *data );
    46 static void ide_read_next_sector(void);
    48 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, ide_run_slice,
    49 				       NULL, ide_save_state, ide_load_state };
    51 struct ide_registers idereg;
    52 gdrom_disc_t gdrom_disc = NULL;
    54 unsigned char data_buffer[MAX_SECTOR_SIZE];
    56 #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
    57 #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
    59 /* 10 bytes followed by "SE      REV 6.42990316" */
    60 unsigned char default_gdrom_mode[GDROM_MODE_LENGTH] = 
    61     { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00, 0x00, 0x08,
    62       0x53, 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
    63       0x52, 0x65, 0x76, 0x20, 0x36, 0x2e, 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
    65 unsigned char gdrom_71[] = { 0x3E, 0x0F, 0x90, 0xBE,  0x1D, 0xD9, 0x89, 0x04,  0x28, 0x3A, 0x8E, 0x26,  0x5C, 0x95, 0x10, 0x5A,
    66 				 0x0A, 0x99, 0xEE, 0xFB,  0x69, 0xCE, 0xD9, 0x63,  0x00, 0xF5, 0x0A, 0xBC,  0x2C, 0x0D, 0xF8, 0xE2,
    67 				 0x05, 0x02, 0x00, 0x7C,  0x03, 0x00, 0x3D, 0x08,  0xD8, 0x8D, 0x08, 0x7A,  0x6D, 0x00, 0x35, 0x06,
    68 				 0xBA, 0x66, 0x10, 0x00,  0x91, 0x08, 0x10, 0x29,  0xD0, 0x45, 0xDA, 0x00,  0x2D, 0x05, 0x69, 0x09,
    69 				 0x00, 0x5E, 0x0F, 0x70,  0x86, 0x12, 0x6C, 0x77,  0x5A, 0xFB, 0xCD, 0x56,  0xFB, 0xF7, 0xB7, 0x00,
    70 				 0x5D, 0x07, 0x19, 0x99,  0xF2, 0xAF, 0x00, 0x63,  0x03, 0x00, 0xF0, 0x10,  0xBE, 0xD7, 0xA0, 0x63,
    71 				 0xFA, 0x84, 0xA7, 0x74,  0x94, 0xEF, 0xAD, 0xC2,  0xAC, 0x00, 0x78, 0x07,  0x9F, 0x57, 0x0B, 0x62,
    72 				 0x00, 0xFE, 0x08, 0x08,  0x5D, 0x5A, 0x6A, 0x54,  0x00, 0xE2, 0x09, 0x93,  0x7E, 0x62, 0x2A, 0x5E,
    73 				 0xDA, 0x00, 0x7E, 0x0F,  0xF0, 0x07, 0x01, 0x6D,  0x50, 0x86, 0xDD, 0x4A,  0x15, 0x54, 0xC7, 0xEC,
    74 				 0x00, 0xF2, 0x0B, 0x07,  0xF8, 0x1A, 0xB0, 0x99,  0x3B, 0xF1, 0x36, 0x00,  0x94, 0x07, 0x34, 0xE3,
    75 				 0xBC, 0x6E, 0x00, 0x34,  0x0D, 0x6F, 0xDA, 0xBD,  0xEE, 0xF7, 0xCC, 0xCE,  0x39, 0x7E, 0xE3, 0x00,
    76 				 0x14, 0x08, 0xDC, 0xD2,  0xB9, 0xF9, 0x31, 0x00,  0xB0, 0x0C, 0x10, 0xA3,  0x45, 0x12, 0xC7, 0xCD,
    77 				 0xBF, 0x05, 0x37, 0x00,  0xC4, 0x0D, 0x5F, 0xE0,  0x59, 0xBB, 0x01, 0x59,  0x03, 0xD6, 0x29, 0x9C,
    78 				 0x00, 0x01, 0x0A, 0x09,  0xAA, 0xA8, 0xA8, 0x24,  0x0B, 0x66, 0x00, 0x5C,  0x05, 0xA5, 0xCE, 0x00,
    79 				 0xC1, 0x0B, 0xB7, 0xA0,  0x6F, 0xE9, 0x2B, 0xCC,  0xB5, 0xFC, 0x00, 0x8D,  0x05, 0xF4, 0xAC, 0x00,
    80 				 0x57, 0x04, 0xB6, 0x00,  0xFC, 0x03, 0x00, 0xC3,  0x10, 0x43, 0x3B, 0xBE,  0xA2, 0x96, 0xC3, 0x65,
    81 				 0x9F, 0x9A, 0x88, 0xD5,  0x49, 0x68, 0x00, 0xDC,  0x11, 0x56, 0x23, 0x2D,  0xF9, 0xFC, 0xF5, 0x8B,
    82 				 0x1B, 0xB1, 0xB7, 0x10,  0x21, 0x1C, 0x12, 0x00,  0x0D, 0x0D, 0xEB, 0x86,  0xA2, 0x49, 0x8D, 0x8D,
    83 				 0xBE, 0xA1, 0x6D, 0x53,  0x00, 0xE1, 0x0A, 0x8E,  0x67, 0xAA, 0x16, 0x79,  0x39, 0x59, 0x00, 0x36,
    84 				 0x0B, 0x2A, 0x4E, 0xAE,  0x51, 0x4B, 0xD0, 0x66,  0x33, 0x00, 0x8A, 0x07,  0xCD, 0x6F, 0xBA, 0x92,
    85 				 0x00, 0x1A, 0x0E, 0xDF,  0x4A, 0xB3, 0x77, 0x1F,  0xA5, 0x90, 0x19, 0xFA,  0x59, 0xD7, 0x00, 0x04,
    86 				 0x0F, 0xAC, 0xCA, 0x9F,  0xA4, 0xFC, 0x6D, 0x90,  0x86, 0x9E, 0x1F, 0x44,  0x40, 0x00, 0x9F, 0x04,
    87 				 0x56, 0x00, 0x22, 0x03,  0x00, 0xB8, 0x10, 0x2C,  0x7A, 0x53, 0xA4, 0xBF,  0xA3, 0x90, 0x90, 0x14,
    88 				 0x9D, 0x46, 0x6C, 0x96,  0x00, 0xC6, 0x0B, 0x9B,  0xBB, 0xB0, 0xAE, 0x60,  0x92, 0x8E, 0x0C, 0x00,
    89 				 0x14, 0x06, 0x4B, 0xAE,  0x7F, 0x00, 0x5C, 0x0B,  0x23, 0xFA, 0xE7, 0x51,  0xDA, 0x61, 0x49, 0x5E,
    90 				 0x00, 0xD7, 0x0B, 0x01,  0xFC, 0x55, 0x31, 0x84,  0xC5, 0x0C, 0x98, 0x00,  0x97, 0x50, 0x6E, 0xF9,
    91 				 0xEE, 0x75, 0x92, 0x53,  0xD3, 0x66, 0xA4, 0xAF,  0x3B, 0xFE, 0x7B, 0x27,  0x30, 0xBB, 0xB6, 0xF2,
    92 				 0x76, 0x22, 0x45, 0x42,  0xCA, 0xF9, 0xF0, 0xDE,  0x9F, 0x45, 0x16, 0x68,  0x22, 0xB9, 0x84, 0x28,
    93 				 0x8F, 0x2B, 0xB5, 0x5C,  0xD2, 0xF5, 0x45, 0x36,  0x3E, 0x76, 0xC6, 0xBF,  0x32, 0x5C, 0x41, 0xA6,
    94 				 0x26, 0xC7, 0x82, 0x2F,  0x2E, 0xB5, 0x75, 0xC6,  0xE6, 0x67, 0x9E, 0x77,  0x94, 0xAF, 0x6A, 0x05,
    95 				 0xC0, 0x05, 0x61, 0x71,  0x89, 0x5A, 0xB1, 0xD0,  0xFC, 0x7E, 0xC0, 0x9B,  0xCB, 0x3B, 0x69, 0xD9,
    96 				 0x5F, 0xAF, 0xCA, 0xAB,  0x25, 0xD5, 0xBE, 0x8A,  0x6B, 0xB0, 0xFB, 0x61,  0x6C, 0xEB, 0x85, 0x6E,
    97 				 0x7A, 0x48, 0xFF, 0x97,  0x91, 0x06, 0x3D, 0x4D,  0x68, 0xD3, 0x65, 0x83,  0x90, 0xA0, 0x08, 0x5C,
    98 				 0xFC, 0xEE, 0x7C, 0x33,  0x43, 0x7F, 0x80, 0x52,  0x8B, 0x19, 0x72, 0xF2,  0xC9, 0xAB, 0x93, 0xAF,
    99 				 0x16, 0xED, 0x36, 0x48,  0xAB, 0xC9, 0xD1, 0x03,  0xB3, 0xDC, 0x2F, 0xF2,  0x92, 0x3F, 0x0A, 0x19,
   100 				 0x25, 0xE2, 0xEF, 0x7A,  0x22, 0xDA, 0xDB, 0xCB,  0x32, 0x12, 0x61, 0x49,  0x5B, 0x74, 0x7C, 0x65,
   101 				 0x20, 0x89, 0x54, 0x9E,  0x0E, 0xC9, 0x52, 0xE3,  0xC9, 0x9A, 0x44, 0xC9,  0x5D, 0xA6, 0x77, 0xC0,
   102 				 0xE7, 0x60, 0x91, 0x80,  0x50, 0x1F, 0x33, 0xB1,  0xCD, 0xAD, 0xF4, 0x0D,  0xBB, 0x08, 0xB1, 0xD0,
   103 				 0x13, 0x95, 0xAE, 0xC9,  0xE2, 0x64, 0xA2, 0x65,  0xFB, 0x8F, 0xE9, 0xA2,  0x8A, 0xBC, 0x98, 0x81,
   104 				 0x45, 0xB4, 0x55, 0x4E,  0xB9, 0x74, 0xB4, 0x50,  0x76, 0xBF, 0xF0, 0x45,  0xE7, 0xEE, 0x41, 0x64,
   105 				 0x9F, 0xB5, 0xE0, 0xBB,  0x1C, 0xBB, 0x28, 0x66,  0x1B, 0xDD, 0x2B, 0x02,  0x66, 0xBF, 0xFD, 0x7D,
   106 				 0x37, 0x35, 0x1D, 0x76,  0x21, 0xC3, 0x8F, 0xAF,  0xF6, 0xF9, 0xE9, 0x27,  0x48, 0xE7, 0x3D, 0x95,
   107 				 0x74, 0x0C, 0x77, 0x88,  0x56, 0xD9, 0x84, 0xC8,  0x7D, 0x20, 0x31, 0x43,  0x53, 0xF1, 0xC1, 0xC7,
   108 				 0xC9, 0xF7, 0x5C, 0xC0,  0xA6, 0x5A, 0x27, 0x0A,  0x41, 0xD4, 0x44, 0x94,  0x65, 0x4F, 0xE2, 0x53,
   109 				 0x60, 0x0B, 0xD1, 0x23,  0x6C, 0x0C, 0xBC, 0x70,  0x6C, 0x26, 0x1A, 0x61,  0x1D, 0x35, 0x88, 0xEC,
   110 				 0xB8, 0x15, 0xE3, 0xB4,  0x82, 0xEE, 0xB3, 0x21,  0xAC, 0x6C, 0xB7, 0x33,  0x6D, 0x78, 0x0C, 0x0D,
   111 				 0xB4, 0x0B, 0x29, 0xF2,  0xD4, 0x8C, 0x3F, 0xDD,  0x3F, 0x47, 0xDD, 0xF2,  0xD8, 0x39, 0x57, 0x20,
   112 				 0x28, 0xD8, 0xDD, 0x32,  0xE2, 0x6A, 0x47, 0x53,  0x57, 0xC6, 0xFA, 0x7A,  0x38, 0x30, 0x31, 0x8F,
   113 				 0xE7, 0xD3, 0x84, 0x2B,  0x5D, 0x4F, 0x95, 0x98,  0xED, 0x0B, 0xD7, 0x50,  0x0C, 0x49, 0xDA, 0x59,
   114 				 0x15, 0xF1, 0x39, 0xF3,  0x40, 0xDC, 0xDC, 0x25,  0x24, 0x56, 0x6E, 0xA9,  0x2F, 0xF0, 0x00, 0x00 };
   117 char gdrom_status[] = { 
   118     0x00, 0x15, 0x00, 0x64, 0x00, 0x40, 0x00, 0x00, 
   119     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
   120     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
   121     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
   122     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   123     0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   124     0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   125     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   126     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
   127     0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   128     0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
   129     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
   130     0x00, 0x40, 0x00, 0x00 };
   133 static void ide_init( void )
   134 {
   135     ide_reset();
   136 }
   138 static void ide_reset( void )
   139 {
   140     ide_clear_interrupt();
   141     idereg.error = 0x01;
   142     idereg.count = 0x01;
   143     idereg.lba0 = /* 0x21; */ 0x81;
   144     idereg.lba1 = 0x14;
   145     idereg.lba2 = 0xeb;
   146     idereg.feature = 0; /* Indeterminate really */
   147     idereg.status = 0x00;
   148     idereg.device = 0x00;
   149     idereg.state = IDE_STATE_IDLE;
   150     memset( idereg.gdrom_sense, '\0', 10 );
   151     memcpy( idereg.gdrom_mode, default_gdrom_mode, GDROM_MODE_LENGTH );
   152     idereg.data_offset = -1;
   153     idereg.data_length = -1;
   154     idereg.last_read_track = 1;
   155     idereg.current_lba = 150;
   156     idereg.current_mode = 0x28;
   157     idereg.sectors_left = 0;
   158     idereg.was_reset = TRUE;
   159 }
   161 static uint32_t ide_run_slice( uint32_t nanosecs )
   162 {
   163     if( gdrom_disc != NULL && gdrom_disc->run_time_slice != NULL ) {
   164 	gdrom_disc->run_time_slice(gdrom_disc, nanosecs);
   165     }
   166     return nanosecs;
   167 }
   169 static void ide_save_state( FILE *f )
   170 {
   171     fwrite( &idereg, sizeof(idereg), 1, f );
   172     fwrite( data_buffer, MAX_SECTOR_SIZE, 1, f );
   173 }
   175 static int ide_load_state( FILE *f )
   176 {
   177     fread( &idereg, sizeof(idereg), 1, f );
   178     fread( data_buffer, MAX_SECTOR_SIZE, 1, f );
   179     return 0;
   180 }
   182 /************************ State transitions *************************/
   184 void ide_set_packet_result( uint16_t result )
   185 {
   186     idereg.gdrom_sense[0] = 0xf0;
   187     idereg.gdrom_sense[2] = result & 0xFF;
   188     idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
   189     idereg.error = (result & 0x0F) << 4;
   190     idereg.count = 3;
   191     if( result != 0 ) {
   192 	idereg.status = 0x51;
   193 	idereg.state = IDE_STATE_IDLE;
   194 	ide_raise_interrupt();
   195     } else {
   196 	idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
   197     }
   198 }
   200 /**
   201  * Begin command packet write to the device. This is always 12 bytes of PIO data
   202  */
   203 static void ide_start_command_packet_write( )
   204 {
   205     idereg.state = IDE_STATE_CMD_WRITE;
   206     idereg.status = 0x58;
   207     idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
   208     idereg.count = IDE_COUNT_CD;
   209     idereg.data_offset = 0;
   210     idereg.data_length = 12;
   211 }
   213 /**
   214  * Begin PIO/DMA read from the device. The data is assumed to already be
   215  * in the buffer at this point.
   216  */
   217 static void ide_start_read( int length, gboolean dma ) 
   218 {
   219     idereg.count = IDE_COUNT_IO;
   220     idereg.data_length = length;
   221     idereg.data_offset = 0;
   222     if( dma ) {
   223 	idereg.state = IDE_STATE_DMA_READ;
   224 	idereg.status = 0xD0;
   225     } else {
   226 	idereg.state = IDE_STATE_PIO_READ;
   227 	idereg.status = 0x58;
   228 	idereg.lba1 = length & 0xFF;
   229 	idereg.lba2 = length >> 8; 
   230 	ide_raise_interrupt( );
   231     }
   232 }
   234 static void ide_start_write( int length, gboolean dma )
   235 {
   236     idereg.count = 0;
   237     idereg.data_length = length;
   238     idereg.data_offset = 0;
   239     if( dma ) {
   240 	idereg.state = IDE_STATE_DMA_WRITE;
   241 	idereg.status = 0xD0;
   242     }  else {
   243 	idereg.state = IDE_STATE_PIO_WRITE;
   244 	idereg.status = 0x58;
   245 	idereg.lba1 = length & 0xFF;
   246 	idereg.lba2 = length >> 8;
   247 	ide_raise_interrupt( );
   248     }
   249 }
   251 static void ide_start_packet_read( int length, int sector_count )
   252 {
   253     idereg.sectors_left = sector_count;
   254     ide_set_packet_result( PKT_ERR_OK );
   255     ide_start_read( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   256 }
   258 static void ide_start_packet_write( int length, int sector_count )
   259 {
   260     idereg.sectors_left = sector_count;
   261     ide_set_packet_result( PKT_ERR_OK );
   262     ide_start_write( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   263 }
   265 static void ide_raise_interrupt( void )
   266 {
   267     if( idereg.intrq_pending == 0 ) {
   268 	idereg.intrq_pending = 1;
   269 	if( IS_IDE_IRQ_ENABLED() )
   270 	    asic_event( EVENT_IDE );
   271     }
   272 }
   274 static void ide_clear_interrupt( void ) 
   275 {
   276     if( idereg.intrq_pending != 0 ) {
   277 	idereg.intrq_pending = 0;
   278 	if( IS_IDE_IRQ_ENABLED() )
   279 	    asic_clear_event( EVENT_IDE );
   280     }
   281 }
   283 static void ide_set_error( int error_code )
   284 {
   285     idereg.status = 0x51;
   286     idereg.error = error_code;
   287 }
   289 uint8_t ide_read_status( void ) 
   290 {
   291     if( (idereg.status & IDE_STATUS_BSY) == 0 )
   292 	ide_clear_interrupt();
   293     return idereg.status;
   294 }
   296 uint16_t ide_read_data_pio( void ) {
   297     if( idereg.state == IDE_STATE_PIO_READ ) {
   298 	uint16_t rv = READ_BUFFER();
   299 	idereg.data_offset += 2;
   300 	if( idereg.data_offset >= idereg.data_length ) {
   301 	    idereg.state = IDE_STATE_IDLE;
   302 	    idereg.status &= ~IDE_STATUS_DRQ;
   303 	    idereg.data_offset = -1;
   304 	    idereg.count = 3; /* complete */
   305 	    ide_raise_interrupt();
   306 	    if( idereg.sectors_left > 0 ) {
   307 		ide_read_next_sector();
   308 	    }
   309 	}
   310 	return rv;
   311     } else {
   312         return 0xFFFF;
   313     }
   314 }
   317 /**
   318  * DMA read request
   319  *
   320  * This method is called from the ASIC side when a DMA read request is
   321  * initiated. If there is a pending DMA transfer already, we copy the
   322  * data immediately, otherwise we record the DMA buffer for use when we
   323  * get to actually doing the transfer.
   324  * @return number of bytes transfered
   325  */
   326 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
   327 {
   328     uint32_t xfercount = 0;
   329     while( xfercount < length && idereg.state == IDE_STATE_DMA_READ ) {
   330 	int xferlen = length - xfercount;
   331 	int remaining = idereg.data_length - idereg.data_offset;
   332 	if( xferlen > remaining ) {
   333 	    xferlen = remaining;
   334 	}
   335 	mem_copy_to_sh4( addr, (data_buffer + idereg.data_offset), xferlen );
   336 	xfercount += xferlen;
   337 	addr += xferlen;
   338 	idereg.data_offset += xferlen;
   339 	if( idereg.data_offset >= idereg.data_length ) {
   340 	    if( idereg.sectors_left > 0 ) {
   341 		ide_read_next_sector();
   342 	    } else {
   343 		idereg.data_offset = -1;
   344 		idereg.state = IDE_STATE_IDLE;
   345 		idereg.status = 0x50;
   346 		idereg.count = 0x03;
   347 		ide_raise_interrupt();
   348 		asic_event( EVENT_IDE_DMA );
   349 		break;
   350 	    }
   351 	}
   352     }
   353     return xfercount;
   354 }
   356 void ide_write_data_pio( uint16_t val ) {
   357     if( idereg.state == IDE_STATE_CMD_WRITE ) {
   358 	WRITE_BUFFER(val);
   359 	idereg.data_offset+=2;
   360 	if( idereg.data_offset >= idereg.data_length ) {
   361 	    idereg.state = IDE_STATE_BUSY;
   362 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   363 	    idereg.data_offset = -1;
   364 	    ide_packet_command(data_buffer);
   365 	}
   366     } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
   367 	WRITE_BUFFER(val);
   368 	idereg.data_offset +=2;
   369 	if( idereg.data_offset >= idereg.data_length ) {
   370 	    idereg.state = IDE_STATE_IDLE;
   371 	    idereg.status &= ~IDE_STATUS_DRQ;
   372 	    idereg.data_offset = -1;
   373 	    idereg.count = 3; /* complete */
   374 	    ide_raise_interrupt();
   375 	    ide_write_buffer( data_buffer, idereg.data_length );
   376 	}
   377     }
   378 }
   380 void ide_write_control( uint8_t val ) {
   381     if( IS_IDE_IRQ_ENABLED() ) {
   382 	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   383 	    asic_clear_event( EVENT_IDE );
   384     } else {
   385 	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   386 	    asic_event( EVENT_IDE );
   387     }
   388     idereg.control = val;
   389 }
   391 void ide_write_command( uint8_t val ) {
   392     ide_clear_interrupt();
   393     idereg.command = val;
   394     switch( val ) {
   395     case IDE_CMD_NOP: /* Effectively an "abort" */
   396 	idereg.state = IDE_STATE_IDLE;
   397 	idereg.status = 0x51;
   398 	idereg.error = 0x04;
   399 	idereg.data_offset = -1;
   400 	ide_raise_interrupt();
   401 	return;
   402     case IDE_CMD_RESET_DEVICE:
   403 	ide_reset();
   404 	break;
   405     case IDE_CMD_PACKET:
   406 	ide_start_command_packet_write();
   407 	break;
   408     case IDE_CMD_SET_FEATURE:
   409 	switch( idereg.feature ) {
   410 	case IDE_FEAT_SET_TRANSFER_MODE:
   411 	    switch( idereg.count & 0xF8 ) {
   412 	    case IDE_XFER_PIO:
   413 		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   414 		break;
   415 	    case IDE_XFER_PIO_FLOW:
   416 		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   417 		break;
   418 	    case IDE_XFER_MULTI_DMA:
   419 		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   420 		break;
   421 	    case IDE_XFER_ULTRA_DMA:
   422 		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   423 		break;
   424 	    default:
   425 		INFO( "Setting unknown transfer mode: %02X", idereg.count );
   426 		break;
   427 	    }
   428 	    break;
   429 	default:
   430 	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   431 	}
   432 	idereg.status = 0x50;
   433 	idereg.error = 0x00;
   434 	idereg.lba1 = 0x00;
   435 	idereg.lba2 = 0x00;
   436 	ide_raise_interrupt();
   437 	break;
   438     default:
   439 	WARN( "IDE: Unimplemented command: %02X", val );
   440     }
   441 }
   443 uint8_t ide_get_drive_status( void )
   444 {
   445     if( gdrom_disc == NULL ) {
   446 	return IDE_DISC_NONE;
   447     } else {
   448 	return gdrom_disc->drive_status(gdrom_disc);
   449     }
   450 }
   452 #define REQUIRE_DISC() if( gdrom_disc == NULL ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
   454 /**
   455  * Read the next sector from the active read, if any
   456  */
   457 static void ide_read_next_sector( void )
   458 {
   459     uint32_t sector_size;
   460     REQUIRE_DISC();
   461     gdrom_error_t status = 
   462 	gdrom_disc->read_sector( gdrom_disc, idereg.current_lba, idereg.current_mode, 
   463 				 data_buffer, &sector_size );
   464     if( status != PKT_ERR_OK ) {
   465 	ide_set_packet_result( status );
   466 	idereg.gdrom_sense[5] = (idereg.current_lba >> 16) & 0xFF;
   467 	idereg.gdrom_sense[6] = (idereg.current_lba >> 8) & 0xFF;
   468 	idereg.gdrom_sense[7] = idereg.current_lba & 0xFF;
   469 	WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
   470     } else {
   471 	idereg.current_lba++;
   472 	idereg.sectors_left--;
   473 	ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   474     }
   475 }
   477 /**
   478  * Execute a packet command. This particular method is responsible for parsing
   479  * the command buffers (12 bytes), and generating the appropriate responses, 
   480  * although the actual implementation is mostly delegated to gdrom.c
   481  */
   482 void ide_packet_command( unsigned char *cmd )
   483 {
   484     uint32_t length;
   485     uint32_t lba, status;
   487     /* Okay we have the packet in the command buffer */
   488     INFO( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   489 	  cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   490 	  cmd[8], cmd[9], cmd[10], cmd[11] );
   492     if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
   493 	ide_set_packet_result( PKT_ERR_RESET );
   494 	idereg.was_reset = FALSE;
   495 	return;
   496     }
   498     switch( cmd[0] ) {
   499     case PKT_CMD_TEST_READY:
   500 	REQUIRE_DISC();
   501 	ide_set_packet_result( 0 );
   502 	ide_raise_interrupt();
   503 	idereg.status = 0x50;
   504 	break;
   505     case PKT_CMD_MODE_SENSE:
   506 	lba = cmd[2];
   507 	if( lba >= GDROM_MODE_LENGTH ) {
   508 	    ide_set_error(PKT_ERR_BADFIELD);
   509 	} else {
   510 	    length = cmd[4];
   511 	    if( lba+length > GDROM_MODE_LENGTH )
   512 		length = GDROM_MODE_LENGTH - lba;
   513 	    memcpy( data_buffer, idereg.gdrom_mode + lba, length );
   514 	    ide_start_packet_read( length, 0 );
   515 	}
   516 	break;
   517     case PKT_CMD_MODE_SELECT:
   518 	lba = cmd[2];
   519 	if( lba >= GDROM_MODE_LENGTH ) {
   520 	    ide_set_error(PKT_ERR_BADFIELD);
   521 	} else {
   522 	    length = cmd[4];
   523 	    if( lba+length > GDROM_MODE_LENGTH )
   524 		length = GDROM_MODE_LENGTH - lba;
   525 	    idereg.current_lba = lba;
   526 	    ide_start_packet_write( length, 0 );
   527 	}
   528 	break;
   529     case PKT_CMD_SENSE:
   530 	length = cmd[4];
   531 	if( length > 10 )
   532 	    length = 10;
   533 	memcpy( data_buffer, idereg.gdrom_sense, length );
   534 	ide_start_packet_read( length, 0 );
   535 	break;
   536     case PKT_CMD_READ_TOC:
   537 	REQUIRE_DISC();
   538 	length = (cmd[3]<<8) | cmd[4];
   539 	if( length > sizeof(struct gdrom_toc) )
   540 	    length = sizeof(struct gdrom_toc);
   542 	status = gdrom_disc->read_toc( gdrom_disc, data_buffer );
   543 	if( status != PKT_ERR_OK ) {
   544 	    ide_set_packet_result( status );
   545 	} else {
   546 	    ide_start_packet_read( length, 0 );
   547 	}
   548 	break;
   549     case PKT_CMD_SESSION_INFO:
   550 	REQUIRE_DISC();
   551 	length = cmd[4];
   552 	if( length > 6 )
   553 	    length = 6;
   554 	status = gdrom_disc->read_session( gdrom_disc, cmd[2], data_buffer );
   555 	if( status != PKT_ERR_OK ) {
   556 	    ide_set_packet_result( status );
   557 	} else {
   558 	    ide_start_packet_read( length, 0 );
   559 	}
   560 	break;
   561     case PKT_CMD_PLAY_AUDIO:
   562 	REQUIRE_DISC();
   563 	ide_set_packet_result( 0 );
   564 	ide_raise_interrupt();
   565 	idereg.status = 0x50;
   566 	break;
   567     case PKT_CMD_READ_SECTOR:
   568 	REQUIRE_DISC();
   569 	idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   570 	idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   571 	idereg.current_mode = cmd[1];
   572 	ide_read_next_sector();
   573 	break;
   574     case PKT_CMD_SPIN_UP:
   575 	REQUIRE_DISC();
   576 	/* do nothing? */
   577 	ide_set_packet_result( PKT_ERR_OK );
   578 	ide_raise_interrupt();
   579 	break;
   580     case PKT_CMD_STATUS:
   581 	REQUIRE_DISC();
   582 	length = cmd[4];
   583 	switch( cmd[1] ) {
   584 	case 0:
   585 	    if( length > sizeof(gdrom_status) ) {
   586 		length = sizeof(gdrom_status);
   587 	    }
   588 	    memcpy( data_buffer, gdrom_status, length );
   589 	    ide_start_packet_read( length, 0 );
   590 	    break;
   591 	case 1:
   592 	    if( length > 14 ) {
   593 		length = 14;
   594 	    }
   595 	    gdrom_disc->read_position( gdrom_disc, idereg.current_lba, data_buffer );
   596 	    data_buffer[0] = 0x00;
   597 	    data_buffer[1] = 0x15; /* audio status ? */
   598 	    data_buffer[2] = 0x00;
   599 	    data_buffer[3] = 0x0E;
   600 	    ide_start_packet_read( length, 0 );
   601 	    break;
   602 	}
   603 	break;
   604     case PKT_CMD_71:
   605 	/* This is a weird one. As far as I can tell it returns random garbage
   606 	 * (and not even the same length each time, never mind the same data).
   607 	 * For sake of something to do, it returns the results from a test dump
   608 	 */
   609 	REQUIRE_DISC();
   610 	memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   611 	ide_start_packet_read( sizeof(gdrom_71), 0 );
   612 	break;
   613     default:
   614 	ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   615 	return;
   616     }
   617     idereg.last_packet_command = cmd[0];
   618 }
   620 void ide_write_buffer( unsigned char *data, uint32_t length )
   621 {
   622     switch( idereg.last_packet_command ) {
   623     case PKT_CMD_MODE_SELECT:
   624 	if( idereg.current_lba < 10 ) {
   625 	    if( idereg.current_lba + length > 10 ) {
   626 		length = 10 - idereg.current_lba;
   627 	    }
   628 	    memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
   629 	}
   630 	break;
   631     default:
   632 	WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
   633     }
   634 }
.