Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 493:c8183f888b14
prev430:467519b050f4
next561:533f6b478071
author nkeynes
date Wed Nov 07 11:45:53 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Add crash handler to get a backtrace via gdb
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.27 2007-11-06 08:35:33 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 "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 	ide_raise_interrupt();
   194     } else {
   195 	idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
   196     }
   197 }
   199 /**
   200  * Begin command packet write to the device. This is always 12 bytes of PIO data
   201  */
   202 static void ide_start_command_packet_write( )
   203 {
   204     idereg.state = IDE_STATE_CMD_WRITE;
   205     idereg.status = 0x58;
   206     idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
   207     idereg.count = IDE_COUNT_CD;
   208     idereg.data_offset = 0;
   209     idereg.data_length = 12;
   210 }
   212 /**
   213  * Begin PIO/DMA read from the device. The data is assumed to already be
   214  * in the buffer at this point.
   215  */
   216 static void ide_start_read( int length, gboolean dma ) 
   217 {
   218     idereg.count = IDE_COUNT_IO;
   219     idereg.data_length = length;
   220     idereg.data_offset = 0;
   221     if( dma ) {
   222 	idereg.state = IDE_STATE_DMA_READ;
   223 	idereg.status = 0xD0;
   224     } else {
   225 	idereg.state = IDE_STATE_PIO_READ;
   226 	idereg.status = 0x58;
   227 	idereg.lba1 = length & 0xFF;
   228 	idereg.lba2 = length >> 8; 
   229 	ide_raise_interrupt( );
   230     }
   231 }
   233 static void ide_start_write( int length, gboolean dma )
   234 {
   235     idereg.count = 0;
   236     idereg.data_length = length;
   237     idereg.data_offset = 0;
   238     if( dma ) {
   239 	idereg.state = IDE_STATE_DMA_WRITE;
   240 	idereg.status = 0xD0;
   241     }  else {
   242 	idereg.state = IDE_STATE_PIO_WRITE;
   243 	idereg.status = 0x58;
   244 	idereg.lba1 = length & 0xFF;
   245 	idereg.lba2 = length >> 8;
   246 	ide_raise_interrupt( );
   247     }
   248 }
   250 static void ide_start_packet_read( int length, int sector_count )
   251 {
   252     idereg.sectors_left = sector_count;
   253     ide_set_packet_result( PKT_ERR_OK );
   254     ide_start_read( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   255 }
   257 static void ide_start_packet_write( int length, int sector_count )
   258 {
   259     idereg.sectors_left = sector_count;
   260     ide_set_packet_result( PKT_ERR_OK );
   261     ide_start_write( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   262 }
   264 static void ide_raise_interrupt( void )
   265 {
   266     if( idereg.intrq_pending == 0 ) {
   267 	idereg.intrq_pending = 1;
   268 	if( IS_IDE_IRQ_ENABLED() )
   269 	    asic_event( EVENT_IDE );
   270     }
   271 }
   273 static void ide_clear_interrupt( void ) 
   274 {
   275     if( idereg.intrq_pending != 0 ) {
   276 	idereg.intrq_pending = 0;
   277 	if( IS_IDE_IRQ_ENABLED() )
   278 	    asic_clear_event( EVENT_IDE );
   279     }
   280 }
   282 static void ide_set_error( int error_code )
   283 {
   284     idereg.status = 0x51;
   285     idereg.error = error_code;
   286 }
   288 uint8_t ide_read_status( void ) 
   289 {
   290     if( (idereg.status & IDE_STATUS_BSY) == 0 )
   291 	ide_clear_interrupt();
   292     return idereg.status;
   293 }
   295 uint16_t ide_read_data_pio( void ) {
   296     if( idereg.state == IDE_STATE_PIO_READ ) {
   297 	uint16_t rv = READ_BUFFER();
   298 	idereg.data_offset += 2;
   299 	if( idereg.data_offset >= idereg.data_length ) {
   300 	    idereg.state = IDE_STATE_IDLE;
   301 	    idereg.status &= ~IDE_STATUS_DRQ;
   302 	    idereg.data_offset = -1;
   303 	    idereg.count = 3; /* complete */
   304 	    ide_raise_interrupt();
   305 	    if( idereg.sectors_left > 0 ) {
   306 		ide_read_next_sector();
   307 	    }
   308 	}
   309 	return rv;
   310     } else {
   311         return 0xFFFF;
   312     }
   313 }
   316 /**
   317  * DMA read request
   318  *
   319  * This method is called from the ASIC side when a DMA read request is
   320  * initiated. If there is a pending DMA transfer already, we copy the
   321  * data immediately, otherwise we record the DMA buffer for use when we
   322  * get to actually doing the transfer.
   323  * @return number of bytes transfered
   324  */
   325 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
   326 {
   327     uint32_t xfercount = 0;
   328     if( idereg.state == IDE_STATE_DMA_READ ) {
   329 	while( xfercount < length ) {
   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     }
   354     return xfercount;
   355 }
   357 void ide_write_data_pio( uint16_t val ) {
   358     if( idereg.state == IDE_STATE_CMD_WRITE ) {
   359 	WRITE_BUFFER(val);
   360 	idereg.data_offset+=2;
   361 	if( idereg.data_offset >= idereg.data_length ) {
   362 	    idereg.state = IDE_STATE_BUSY;
   363 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   364 	    idereg.data_offset = -1;
   365 	    ide_packet_command(data_buffer);
   366 	}
   367     } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
   368 	WRITE_BUFFER(val);
   369 	idereg.data_offset +=2;
   370 	if( idereg.data_offset >= idereg.data_length ) {
   371 	    idereg.state = IDE_STATE_IDLE;
   372 	    idereg.status &= ~IDE_STATUS_DRQ;
   373 	    idereg.data_offset = -1;
   374 	    idereg.count = 3; /* complete */
   375 	    ide_raise_interrupt();
   376 	    ide_write_buffer( data_buffer, idereg.data_length );
   377 	}
   378     }
   379 }
   381 void ide_write_control( uint8_t val ) {
   382     if( IS_IDE_IRQ_ENABLED() ) {
   383 	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   384 	    asic_clear_event( EVENT_IDE );
   385     } else {
   386 	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   387 	    asic_event( EVENT_IDE );
   388     }
   389     idereg.control = val;
   390 }
   392 void ide_write_command( uint8_t val ) {
   393     ide_clear_interrupt();
   394     idereg.command = val;
   395     switch( val ) {
   396     case IDE_CMD_NOP: /* Effectively an "abort" */
   397 	idereg.state = IDE_STATE_IDLE;
   398 	idereg.status = 0x51;
   399 	idereg.error = 0x04;
   400 	idereg.data_offset = -1;
   401 	ide_raise_interrupt();
   402 	return;
   403     case IDE_CMD_RESET_DEVICE:
   404 	ide_reset();
   405 	break;
   406     case IDE_CMD_PACKET:
   407 	ide_start_command_packet_write();
   408 	break;
   409     case IDE_CMD_SET_FEATURE:
   410 	switch( idereg.feature ) {
   411 	case IDE_FEAT_SET_TRANSFER_MODE:
   412 	    switch( idereg.count & 0xF8 ) {
   413 	    case IDE_XFER_PIO:
   414 		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   415 		break;
   416 	    case IDE_XFER_PIO_FLOW:
   417 		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   418 		break;
   419 	    case IDE_XFER_MULTI_DMA:
   420 		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   421 		break;
   422 	    case IDE_XFER_ULTRA_DMA:
   423 		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   424 		break;
   425 	    default:
   426 		INFO( "Setting unknown transfer mode: %02X", idereg.count );
   427 		break;
   428 	    }
   429 	    break;
   430 	default:
   431 	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   432 	}
   433 	idereg.status = 0x50;
   434 	idereg.error = 0x00;
   435 	idereg.lba1 = 0x00;
   436 	idereg.lba2 = 0x00;
   437 	ide_raise_interrupt();
   438 	break;
   439     default:
   440 	WARN( "IDE: Unimplemented command: %02X", val );
   441     }
   442 }
   444 uint8_t ide_get_drive_status( void )
   445 {
   446     if( gdrom_disc == NULL ) {
   447 	return IDE_DISC_NONE;
   448     } else {
   449 	return gdrom_disc->drive_status(gdrom_disc);
   450     }
   451 }
   453 #define REQUIRE_DISC() if( gdrom_disc == NULL ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
   455 /**
   456  * Read the next sector from the active read, if any
   457  */
   458 static void ide_read_next_sector( void )
   459 {
   460     uint32_t sector_size;
   461     REQUIRE_DISC();
   462     gdrom_error_t status = 
   463 	gdrom_disc->read_sector( gdrom_disc, idereg.current_lba, idereg.current_mode, 
   464 				 data_buffer, &sector_size );
   465     if( status != PKT_ERR_OK ) {
   466 	ide_set_packet_result( status );
   467 	idereg.gdrom_sense[5] = (idereg.current_lba >> 16) & 0xFF;
   468 	idereg.gdrom_sense[6] = (idereg.current_lba >> 8) & 0xFF;
   469 	idereg.gdrom_sense[7] = idereg.current_lba & 0xFF;
   470 	WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
   471     } else {
   472 	idereg.current_lba++;
   473 	idereg.sectors_left--;
   474 	ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   475     }
   476 }
   478 /**
   479  * Execute a packet command. This particular method is responsible for parsing
   480  * the command buffers (12 bytes), and generating the appropriate responses, 
   481  * although the actual implementation is mostly delegated to gdrom.c
   482  */
   483 void ide_packet_command( unsigned char *cmd )
   484 {
   485     uint32_t length;
   486     uint32_t lba, status;
   488     /* Okay we have the packet in the command buffer */
   489     INFO( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   490 	  cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   491 	  cmd[8], cmd[9], cmd[10], cmd[11] );
   493     if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
   494 	ide_set_packet_result( PKT_ERR_RESET );
   495 	idereg.was_reset = FALSE;
   496 	return;
   497     }
   499     switch( cmd[0] ) {
   500     case PKT_CMD_TEST_READY:
   501 	REQUIRE_DISC();
   502 	ide_set_packet_result( 0 );
   503 	ide_raise_interrupt();
   504 	idereg.status = 0x50;
   505 	break;
   506     case PKT_CMD_MODE_SENSE:
   507 	lba = cmd[2];
   508 	if( lba >= GDROM_MODE_LENGTH ) {
   509 	    ide_set_error(PKT_ERR_BADFIELD);
   510 	} else {
   511 	    length = cmd[4];
   512 	    if( lba+length > GDROM_MODE_LENGTH )
   513 		length = GDROM_MODE_LENGTH - lba;
   514 	    memcpy( data_buffer, idereg.gdrom_mode + lba, length );
   515 	    ide_start_packet_read( length, 0 );
   516 	}
   517 	break;
   518     case PKT_CMD_MODE_SELECT:
   519 	lba = cmd[2];
   520 	if( lba >= GDROM_MODE_LENGTH ) {
   521 	    ide_set_error(PKT_ERR_BADFIELD);
   522 	} else {
   523 	    length = cmd[4];
   524 	    if( lba+length > GDROM_MODE_LENGTH )
   525 		length = GDROM_MODE_LENGTH - lba;
   526 	    idereg.current_lba = lba;
   527 	    ide_start_packet_write( length, 0 );
   528 	}
   529 	break;
   530     case PKT_CMD_SENSE:
   531 	length = cmd[4];
   532 	if( length > 10 )
   533 	    length = 10;
   534 	memcpy( data_buffer, idereg.gdrom_sense, length );
   535 	ide_start_packet_read( length, 0 );
   536 	break;
   537     case PKT_CMD_READ_TOC:
   538 	REQUIRE_DISC();
   539 	length = (cmd[3]<<8) | cmd[4];
   540 	if( length > sizeof(struct gdrom_toc) )
   541 	    length = sizeof(struct gdrom_toc);
   543 	status = gdrom_disc->read_toc( gdrom_disc, data_buffer );
   544 	if( status != PKT_ERR_OK ) {
   545 	    ide_set_packet_result( status );
   546 	} else {
   547 	    ide_start_packet_read( length, 0 );
   548 	}
   549 	break;
   550     case PKT_CMD_SESSION_INFO:
   551 	REQUIRE_DISC();
   552 	length = cmd[4];
   553 	if( length > 6 )
   554 	    length = 6;
   555 	status = gdrom_disc->read_session( gdrom_disc, cmd[2], data_buffer );
   556 	if( status != PKT_ERR_OK ) {
   557 	    ide_set_packet_result( status );
   558 	} else {
   559 	    ide_start_packet_read( length, 0 );
   560 	}
   561 	break;
   562     case PKT_CMD_PLAY_AUDIO:
   563 	REQUIRE_DISC();
   564 	ide_set_packet_result( 0 );
   565 	ide_raise_interrupt();
   566 	idereg.status = 0x50;
   567 	break;
   568     case PKT_CMD_READ_SECTOR:
   569 	REQUIRE_DISC();
   570 	idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   571 	idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   572 	idereg.current_mode = cmd[1];
   573 	ide_read_next_sector();
   574 	break;
   575     case PKT_CMD_SPIN_UP:
   576 	REQUIRE_DISC();
   577 	/* do nothing? */
   578 	ide_set_packet_result( PKT_ERR_OK );
   579 	ide_raise_interrupt();
   580 	break;
   581     case PKT_CMD_STATUS:
   582 	REQUIRE_DISC();
   583 	length = cmd[4];
   584 	switch( cmd[1] ) {
   585 	case 0:
   586 	    if( length > sizeof(gdrom_status) ) {
   587 		length = sizeof(gdrom_status);
   588 	    }
   589 	    memcpy( data_buffer, gdrom_status, length );
   590 	    ide_start_packet_read( length, 0 );
   591 	    break;
   592 	case 1:
   593 	    if( length > 14 ) {
   594 		length = 14;
   595 	    }
   596 	    gdrom_disc->read_position( gdrom_disc, idereg.current_lba, data_buffer );
   597 	    data_buffer[0] = 0x00;
   598 	    data_buffer[1] = 0x15; /* audio status ? */
   599 	    data_buffer[2] = 0x00;
   600 	    data_buffer[3] = 0x0E;
   601 	    ide_start_packet_read( length, 0 );
   602 	    break;
   603 	}
   604 	break;
   605     case PKT_CMD_71:
   606 	/* This is a weird one. As far as I can tell it returns random garbage
   607 	 * (and not even the same length each time, never mind the same data).
   608 	 * For sake of something to do, it returns the results from a test dump
   609 	 */
   610 	REQUIRE_DISC();
   611 	memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   612 	ide_start_packet_read( sizeof(gdrom_71), 0 );
   613 	break;
   614     default:
   615 	ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   616 	return;
   617     }
   618     idereg.last_packet_command = cmd[0];
   619 }
   621 void ide_write_buffer( unsigned char *data, uint32_t length )
   622 {
   623     switch( idereg.last_packet_command ) {
   624     case PKT_CMD_MODE_SELECT:
   625 	if( idereg.current_lba < 10 ) {
   626 	    if( idereg.current_lba + length > 10 ) {
   627 		length = 10 - idereg.current_lba;
   628 	    }
   629 	    memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
   630 	}
   631 	break;
   632     default:
   633 	WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
   634     }
   635 }
.