Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 1097:d4807997e450
prev1075:1a21750d300c
author nkeynes
date Sat Mar 03 15:52:59 2012 +1000 (12 years ago)
permissions -rw-r--r--
last change Swap between run + pause icons when pressed
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;
    53 unsigned char data_buffer[MAX_SECTOR_SIZE];
    55 #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
    56 #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
    58 /* 10 bytes followed by "SE      REV 6.42990316" */
    59 unsigned char default_gdrom_mode[GDROM_MODE_LENGTH] = 
    60 { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00, 0x00, 0x08,
    61         0x53, 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
    62         0x52, 0x65, 0x76, 0x20, 0x36, 0x2e, 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
    64 unsigned char gdrom_71[] = { 0x3E, 0x0F, 0x90, 0xBE,  0x1D, 0xD9, 0x89, 0x04,  0x28, 0x3A, 0x8E, 0x26,  0x5C, 0x95, 0x10, 0x5A,
    65         0x0A, 0x99, 0xEE, 0xFB,  0x69, 0xCE, 0xD9, 0x63,  0x00, 0xF5, 0x0A, 0xBC,  0x2C, 0x0D, 0xF8, 0xE2,
    66         0x05, 0x02, 0x00, 0x7C,  0x03, 0x00, 0x3D, 0x08,  0xD8, 0x8D, 0x08, 0x7A,  0x6D, 0x00, 0x35, 0x06,
    67         0xBA, 0x66, 0x10, 0x00,  0x91, 0x08, 0x10, 0x29,  0xD0, 0x45, 0xDA, 0x00,  0x2D, 0x05, 0x69, 0x09,
    68         0x00, 0x5E, 0x0F, 0x70,  0x86, 0x12, 0x6C, 0x77,  0x5A, 0xFB, 0xCD, 0x56,  0xFB, 0xF7, 0xB7, 0x00,
    69         0x5D, 0x07, 0x19, 0x99,  0xF2, 0xAF, 0x00, 0x63,  0x03, 0x00, 0xF0, 0x10,  0xBE, 0xD7, 0xA0, 0x63,
    70         0xFA, 0x84, 0xA7, 0x74,  0x94, 0xEF, 0xAD, 0xC2,  0xAC, 0x00, 0x78, 0x07,  0x9F, 0x57, 0x0B, 0x62,
    71         0x00, 0xFE, 0x08, 0x08,  0x5D, 0x5A, 0x6A, 0x54,  0x00, 0xE2, 0x09, 0x93,  0x7E, 0x62, 0x2A, 0x5E,
    72         0xDA, 0x00, 0x7E, 0x0F,  0xF0, 0x07, 0x01, 0x6D,  0x50, 0x86, 0xDD, 0x4A,  0x15, 0x54, 0xC7, 0xEC,
    73         0x00, 0xF2, 0x0B, 0x07,  0xF8, 0x1A, 0xB0, 0x99,  0x3B, 0xF1, 0x36, 0x00,  0x94, 0x07, 0x34, 0xE3,
    74         0xBC, 0x6E, 0x00, 0x34,  0x0D, 0x6F, 0xDA, 0xBD,  0xEE, 0xF7, 0xCC, 0xCE,  0x39, 0x7E, 0xE3, 0x00,
    75         0x14, 0x08, 0xDC, 0xD2,  0xB9, 0xF9, 0x31, 0x00,  0xB0, 0x0C, 0x10, 0xA3,  0x45, 0x12, 0xC7, 0xCD,
    76         0xBF, 0x05, 0x37, 0x00,  0xC4, 0x0D, 0x5F, 0xE0,  0x59, 0xBB, 0x01, 0x59,  0x03, 0xD6, 0x29, 0x9C,
    77         0x00, 0x01, 0x0A, 0x09,  0xAA, 0xA8, 0xA8, 0x24,  0x0B, 0x66, 0x00, 0x5C,  0x05, 0xA5, 0xCE, 0x00,
    78         0xC1, 0x0B, 0xB7, 0xA0,  0x6F, 0xE9, 0x2B, 0xCC,  0xB5, 0xFC, 0x00, 0x8D,  0x05, 0xF4, 0xAC, 0x00,
    79         0x57, 0x04, 0xB6, 0x00,  0xFC, 0x03, 0x00, 0xC3,  0x10, 0x43, 0x3B, 0xBE,  0xA2, 0x96, 0xC3, 0x65,
    80         0x9F, 0x9A, 0x88, 0xD5,  0x49, 0x68, 0x00, 0xDC,  0x11, 0x56, 0x23, 0x2D,  0xF9, 0xFC, 0xF5, 0x8B,
    81         0x1B, 0xB1, 0xB7, 0x10,  0x21, 0x1C, 0x12, 0x00,  0x0D, 0x0D, 0xEB, 0x86,  0xA2, 0x49, 0x8D, 0x8D,
    82         0xBE, 0xA1, 0x6D, 0x53,  0x00, 0xE1, 0x0A, 0x8E,  0x67, 0xAA, 0x16, 0x79,  0x39, 0x59, 0x00, 0x36,
    83         0x0B, 0x2A, 0x4E, 0xAE,  0x51, 0x4B, 0xD0, 0x66,  0x33, 0x00, 0x8A, 0x07,  0xCD, 0x6F, 0xBA, 0x92,
    84         0x00, 0x1A, 0x0E, 0xDF,  0x4A, 0xB3, 0x77, 0x1F,  0xA5, 0x90, 0x19, 0xFA,  0x59, 0xD7, 0x00, 0x04,
    85         0x0F, 0xAC, 0xCA, 0x9F,  0xA4, 0xFC, 0x6D, 0x90,  0x86, 0x9E, 0x1F, 0x44,  0x40, 0x00, 0x9F, 0x04,
    86         0x56, 0x00, 0x22, 0x03,  0x00, 0xB8, 0x10, 0x2C,  0x7A, 0x53, 0xA4, 0xBF,  0xA3, 0x90, 0x90, 0x14,
    87         0x9D, 0x46, 0x6C, 0x96,  0x00, 0xC6, 0x0B, 0x9B,  0xBB, 0xB0, 0xAE, 0x60,  0x92, 0x8E, 0x0C, 0x00,
    88         0x14, 0x06, 0x4B, 0xAE,  0x7F, 0x00, 0x5C, 0x0B,  0x23, 0xFA, 0xE7, 0x51,  0xDA, 0x61, 0x49, 0x5E,
    89         0x00, 0xD7, 0x0B, 0x01,  0xFC, 0x55, 0x31, 0x84,  0xC5, 0x0C, 0x98, 0x00,  0x97, 0x50, 0x6E, 0xF9,
    90         0xEE, 0x75, 0x92, 0x53,  0xD3, 0x66, 0xA4, 0xAF,  0x3B, 0xFE, 0x7B, 0x27,  0x30, 0xBB, 0xB6, 0xF2,
    91         0x76, 0x22, 0x45, 0x42,  0xCA, 0xF9, 0xF0, 0xDE,  0x9F, 0x45, 0x16, 0x68,  0x22, 0xB9, 0x84, 0x28,
    92         0x8F, 0x2B, 0xB5, 0x5C,  0xD2, 0xF5, 0x45, 0x36,  0x3E, 0x76, 0xC6, 0xBF,  0x32, 0x5C, 0x41, 0xA6,
    93         0x26, 0xC7, 0x82, 0x2F,  0x2E, 0xB5, 0x75, 0xC6,  0xE6, 0x67, 0x9E, 0x77,  0x94, 0xAF, 0x6A, 0x05,
    94         0xC0, 0x05, 0x61, 0x71,  0x89, 0x5A, 0xB1, 0xD0,  0xFC, 0x7E, 0xC0, 0x9B,  0xCB, 0x3B, 0x69, 0xD9,
    95         0x5F, 0xAF, 0xCA, 0xAB,  0x25, 0xD5, 0xBE, 0x8A,  0x6B, 0xB0, 0xFB, 0x61,  0x6C, 0xEB, 0x85, 0x6E,
    96         0x7A, 0x48, 0xFF, 0x97,  0x91, 0x06, 0x3D, 0x4D,  0x68, 0xD3, 0x65, 0x83,  0x90, 0xA0, 0x08, 0x5C,
    97         0xFC, 0xEE, 0x7C, 0x33,  0x43, 0x7F, 0x80, 0x52,  0x8B, 0x19, 0x72, 0xF2,  0xC9, 0xAB, 0x93, 0xAF,
    98         0x16, 0xED, 0x36, 0x48,  0xAB, 0xC9, 0xD1, 0x03,  0xB3, 0xDC, 0x2F, 0xF2,  0x92, 0x3F, 0x0A, 0x19,
    99         0x25, 0xE2, 0xEF, 0x7A,  0x22, 0xDA, 0xDB, 0xCB,  0x32, 0x12, 0x61, 0x49,  0x5B, 0x74, 0x7C, 0x65,
   100         0x20, 0x89, 0x54, 0x9E,  0x0E, 0xC9, 0x52, 0xE3,  0xC9, 0x9A, 0x44, 0xC9,  0x5D, 0xA6, 0x77, 0xC0,
   101         0xE7, 0x60, 0x91, 0x80,  0x50, 0x1F, 0x33, 0xB1,  0xCD, 0xAD, 0xF4, 0x0D,  0xBB, 0x08, 0xB1, 0xD0,
   102         0x13, 0x95, 0xAE, 0xC9,  0xE2, 0x64, 0xA2, 0x65,  0xFB, 0x8F, 0xE9, 0xA2,  0x8A, 0xBC, 0x98, 0x81,
   103         0x45, 0xB4, 0x55, 0x4E,  0xB9, 0x74, 0xB4, 0x50,  0x76, 0xBF, 0xF0, 0x45,  0xE7, 0xEE, 0x41, 0x64,
   104         0x9F, 0xB5, 0xE0, 0xBB,  0x1C, 0xBB, 0x28, 0x66,  0x1B, 0xDD, 0x2B, 0x02,  0x66, 0xBF, 0xFD, 0x7D,
   105         0x37, 0x35, 0x1D, 0x76,  0x21, 0xC3, 0x8F, 0xAF,  0xF6, 0xF9, 0xE9, 0x27,  0x48, 0xE7, 0x3D, 0x95,
   106         0x74, 0x0C, 0x77, 0x88,  0x56, 0xD9, 0x84, 0xC8,  0x7D, 0x20, 0x31, 0x43,  0x53, 0xF1, 0xC1, 0xC7,
   107         0xC9, 0xF7, 0x5C, 0xC0,  0xA6, 0x5A, 0x27, 0x0A,  0x41, 0xD4, 0x44, 0x94,  0x65, 0x4F, 0xE2, 0x53,
   108         0x60, 0x0B, 0xD1, 0x23,  0x6C, 0x0C, 0xBC, 0x70,  0x6C, 0x26, 0x1A, 0x61,  0x1D, 0x35, 0x88, 0xEC,
   109         0xB8, 0x15, 0xE3, 0xB4,  0x82, 0xEE, 0xB3, 0x21,  0xAC, 0x6C, 0xB7, 0x33,  0x6D, 0x78, 0x0C, 0x0D,
   110         0xB4, 0x0B, 0x29, 0xF2,  0xD4, 0x8C, 0x3F, 0xDD,  0x3F, 0x47, 0xDD, 0xF2,  0xD8, 0x39, 0x57, 0x20,
   111         0x28, 0xD8, 0xDD, 0x32,  0xE2, 0x6A, 0x47, 0x53,  0x57, 0xC6, 0xFA, 0x7A,  0x38, 0x30, 0x31, 0x8F,
   112         0xE7, 0xD3, 0x84, 0x2B,  0x5D, 0x4F, 0x95, 0x98,  0xED, 0x0B, 0xD7, 0x50,  0x0C, 0x49, 0xDA, 0x59,
   113         0x15, 0xF1, 0x39, 0xF3,  0x40, 0xDC, 0xDC, 0x25,  0x24, 0x56, 0x6E, 0xA9,  0x2F, 0xF0, 0x00, 0x00 };
   116 char gdrom_status[] = { 
   117         0x00, 0x15, 0x00, 0x64, 0x00, 0x40, 0x00, 0x00, 
   118         0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
   119         0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
   120         0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
   121         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   122         0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   123         0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   124         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   125         0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
   126         0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   127         0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
   128         0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
   129         0x00, 0x40, 0x00, 0x00 };
   132 static void ide_init( void )
   133 {
   134     ide_reset();
   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.state = IDE_STATE_IDLE;
   149     memset( idereg.gdrom_sense, '\0', 10 );
   150     memcpy( idereg.gdrom_mode, default_gdrom_mode, GDROM_MODE_LENGTH );
   151     idereg.data_offset = -1;
   152     idereg.data_length = -1;
   153     idereg.last_read_track = 1;
   154     idereg.current_lba = 150;
   155     idereg.current_mode = 0x28;
   156     idereg.sectors_left = 0;
   157     idereg.was_reset = TRUE;
   158 }
   160 static uint32_t ide_run_slice( uint32_t nanosecs )
   161 {
   162     gdrom_run_slice(nanosecs);
   163     return nanosecs;
   164 }
   166 static void ide_save_state( FILE *f )
   167 {
   168     fwrite( &idereg, sizeof(idereg), 1, f );
   169     fwrite( data_buffer, MAX_SECTOR_SIZE, 1, f );
   170 }
   172 static int ide_load_state( FILE *f )
   173 {
   174     if( fread( &idereg, sizeof(idereg), 1, f ) != 1 ||
   175         fread( data_buffer, MAX_SECTOR_SIZE, 1, f ) != 1 ) {
   176         return -1;
   177     }
   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         idereg.state = IDE_STATE_IDLE;
   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     while( xfercount < length && idereg.state == IDE_STATE_DMA_READ ) {
   329         int xferlen = length - xfercount;
   330         int remaining = idereg.data_length - idereg.data_offset;
   331         if( xferlen > remaining ) {
   332             xferlen = remaining;
   333         }
   334         mem_copy_to_sh4( addr, (data_buffer + idereg.data_offset), xferlen );
   335         xfercount += xferlen;
   336         addr += xferlen;
   337         idereg.data_offset += xferlen;
   338         if( idereg.data_offset >= idereg.data_length ) {
   339             if( idereg.sectors_left > 0 ) {
   340                 ide_read_next_sector();
   341             } else {
   342                 idereg.data_offset = -1;
   343                 idereg.state = IDE_STATE_IDLE;
   344                 idereg.status = 0x50;
   345                 idereg.count = 0x03;
   346                 ide_raise_interrupt();
   347                 break;
   348             }
   349         }
   350     }
   351     return xfercount;
   352 }
   354 void ide_write_data_pio( uint16_t val ) {
   355     if( idereg.state == IDE_STATE_CMD_WRITE ) {
   356         WRITE_BUFFER(val);
   357         idereg.data_offset+=2;
   358         if( idereg.data_offset >= idereg.data_length ) {
   359             idereg.state = IDE_STATE_BUSY;
   360             idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   361             idereg.data_offset = -1;
   362             ide_packet_command(data_buffer);
   363         }
   364     } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
   365         WRITE_BUFFER(val);
   366         idereg.data_offset +=2;
   367         if( idereg.data_offset >= idereg.data_length ) {
   368             idereg.state = IDE_STATE_IDLE;
   369             idereg.status &= ~IDE_STATUS_DRQ;
   370             idereg.data_offset = -1;
   371             idereg.count = 3; /* complete */
   372             ide_raise_interrupt();
   373             ide_write_buffer( data_buffer, idereg.data_length );
   374         }
   375     }
   376 }
   378 void ide_write_control( uint8_t val ) {
   379     if( IS_IDE_IRQ_ENABLED() ) {
   380         if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   381             asic_clear_event( EVENT_IDE );
   382     } else {
   383         if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   384             asic_event( EVENT_IDE );
   385     }
   386     idereg.control = val;
   387 }
   389 void ide_write_command( uint8_t val ) {
   390     ide_clear_interrupt();
   391     idereg.command = val;
   392     switch( val ) {
   393     case IDE_CMD_NOP: /* Effectively an "abort" */
   394         idereg.state = IDE_STATE_IDLE;
   395         idereg.status = 0x51;
   396         idereg.error = 0x04;
   397         idereg.data_offset = -1;
   398         ide_raise_interrupt();
   399         return;
   400     case IDE_CMD_RESET_DEVICE:
   401         ide_reset();
   402         break;
   403     case IDE_CMD_PACKET:
   404         ide_start_command_packet_write();
   405         break;
   406     case IDE_CMD_SET_FEATURE:
   407         switch( idereg.feature ) {
   408         case IDE_FEAT_SET_TRANSFER_MODE:
   409             switch( idereg.count & 0xF8 ) {
   410             case IDE_XFER_PIO:
   411                 DEBUG( "Set PIO default mode: %d", idereg.count&0x07 );
   412                 break;
   413             case IDE_XFER_PIO_FLOW:
   414                 DEBUG( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   415                 break;
   416             case IDE_XFER_MULTI_DMA:
   417                 DEBUG( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   418                 break;
   419             case IDE_XFER_ULTRA_DMA:
   420                 DEBUG( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   421                 break;
   422             default:
   423                 DEBUG( "Setting unknown transfer mode: %02X", idereg.count );
   424                 break;
   425             }
   426             break;
   427             default:
   428                 DEBUG( "IDE: unimplemented feature: %02X", idereg.feature );
   429         }
   430         idereg.status = 0x50;
   431         idereg.error = 0x00;
   432         idereg.lba1 = 0x00;
   433         idereg.lba2 = 0x00;
   434         ide_raise_interrupt();
   435         break;
   436         default:
   437             DEBUG( "IDE: Unimplemented command: %02X", val );
   438     }
   439 }
   441 uint8_t ide_get_drive_status( void )
   442 {
   443     return gdrom_get_drive_status();
   444 }
   446 #define REQUIRE_DISC() if( gdrom_get_drive_status() == IDE_DISC_NONE ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
   448 /**
   449  * Read the next sector from the active read, if any
   450  */
   451 static void ide_read_next_sector( void )
   452 {
   453     size_t sector_size;
   454     cdrom_error_t status = gdrom_read_cd( idereg.current_lba, 1, idereg.current_mode, data_buffer, &sector_size );
   455     if( status != PKT_ERR_OK ) {
   456         ide_set_packet_result( status );
   457         idereg.gdrom_sense[5] = (idereg.current_lba >> 16) & 0xFF;
   458         idereg.gdrom_sense[6] = (idereg.current_lba >> 8) & 0xFF;
   459         idereg.gdrom_sense[7] = idereg.current_lba & 0xFF;
   460         WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
   461     } else {
   462         idereg.current_lba++;
   463         idereg.sectors_left--;
   464         ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   465     }
   466 }
   468 /**
   469  * Execute a packet command. This particular method is responsible for parsing
   470  * the command buffers (12 bytes), and generating the appropriate responses, 
   471  * although the actual implementation is mostly delegated to gdrom.c
   472  */
   473 void ide_packet_command( unsigned char *cmd )
   474 {
   475     uint32_t length;
   476     uint32_t lba, status;
   478     /* Okay we have the packet in the command buffer */
   479     DEBUG( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   480           cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   481           cmd[8], cmd[9], cmd[10], cmd[11] );
   483     if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
   484         ide_set_packet_result( PKT_ERR_RESET );
   485         idereg.was_reset = FALSE;
   486         return;
   487     }
   489     switch( cmd[0] ) {
   490     case PKT_CMD_TEST_READY:
   491         REQUIRE_DISC();
   492         ide_set_packet_result( 0 );
   493         ide_raise_interrupt();
   494         idereg.status = 0x50;
   495         break;
   496     case PKT_CMD_DRIVE_STATUS:
   497         lba = cmd[2];
   498         if( lba >= GDROM_DRIVE_STATUS_LENGTH ) {
   499             ide_set_error(PKT_ERR_BADFIELD);
   500         } else {
   501             uint8_t status = ide_get_drive_status();
   502             /* FIXME: Refactor read_position to avoid this kind of crud */
   503             unsigned char tmp[16];
   504             gdrom_read_short_status( idereg.current_lba, tmp );
   506             length = cmd[4];
   507             if( lba+length > GDROM_DRIVE_STATUS_LENGTH )
   508                 length = GDROM_DRIVE_STATUS_LENGTH - lba;
   509             char data[10];
   510             data[0] = status & 0x0F;
   511             data[1] = status & 0xF0;
   512             data[2] = tmp[4];
   513             data[3] = tmp[5];
   514             data[4] = tmp[6];
   515             data[5] = tmp[11];
   516             data[6] = tmp[12];
   517             data[7] = tmp[13];
   518             data[8] = 0;
   519             data[9] = 0;
   520             memcpy( data_buffer, data + lba, length );
   521             ide_start_packet_read( length, 0 );
   522         }
   523         break;
   524     case PKT_CMD_MODE_SENSE:
   525         lba = cmd[2];
   526         if( lba >= GDROM_MODE_LENGTH ) {
   527             ide_set_error(PKT_ERR_BADFIELD);
   528         } else {
   529             length = cmd[4];
   530             if( lba+length > GDROM_MODE_LENGTH )
   531                 length = GDROM_MODE_LENGTH - lba;
   532             memcpy( data_buffer, idereg.gdrom_mode + lba, length );
   533             ide_start_packet_read( length, 0 );
   534         }
   535         break;
   536     case PKT_CMD_MODE_SELECT:
   537         lba = cmd[2];
   538         if( lba >= GDROM_MODE_LENGTH ) {
   539             ide_set_error(PKT_ERR_BADFIELD);
   540         } else {
   541             length = cmd[4];
   542             if( lba+length > GDROM_MODE_LENGTH )
   543                 length = GDROM_MODE_LENGTH - lba;
   544             idereg.current_lba = lba;
   545             ide_start_packet_write( length, 0 );
   546         }
   547         break;
   548     case PKT_CMD_SENSE:
   549         length = cmd[4];
   550         if( length > 10 )
   551             length = 10;
   552         memcpy( data_buffer, idereg.gdrom_sense, length );
   553         ide_start_packet_read( length, 0 );
   554         break;
   555     case PKT_CMD_READ_TOC:
   556         length = (cmd[3]<<8) | cmd[4];
   557         if( length > GDROM_TOC_SIZE )
   558             length = GDROM_TOC_SIZE;
   560         status = gdrom_read_toc( data_buffer );
   561         if( status != PKT_ERR_OK ) {
   562             ide_set_packet_result( status );
   563         } else {
   564             ide_start_packet_read( length, 0 );
   565         }
   566         break;
   567     case PKT_CMD_SESSION_INFO:
   568         length = cmd[4];
   569         if( length > 6 )
   570             length = 6;
   571         status = gdrom_read_session( cmd[2], data_buffer );
   572         if( status != PKT_ERR_OK ) {
   573             ide_set_packet_result( status );
   574         } else {
   575             ide_start_packet_read( length, 0 );
   576         }
   577         break;
   578     case PKT_CMD_PLAY_AUDIO:
   579         lba = (cmd[2] << 16) | (cmd[3]<<8) | cmd[4];
   580         length = ((cmd[8]<<16) | (cmd[9]<<8) | cmd[10]) - lba;
   581         status = gdrom_play_audio( lba, length );
   582         ide_set_packet_result( status );
   583         ide_raise_interrupt();
   584         idereg.status = 0x50;
   585         break;
   586     case PKT_CMD_READ_SECTOR:
   587         REQUIRE_DISC();
   588         idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   589         idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   590         idereg.current_mode = cmd[1];
   591         ide_read_next_sector();
   592         break;
   593     case PKT_CMD_SPIN_UP:
   594         REQUIRE_DISC();
   595         /* do nothing? */
   596         ide_set_packet_result( PKT_ERR_OK );
   597         ide_raise_interrupt();
   598         break;
   599     case PKT_CMD_STATUS:
   600         REQUIRE_DISC();
   601         length = cmd[4];
   602         switch( cmd[1] ) {
   603         case 0:
   604             if( length > sizeof(gdrom_status) ) {
   605                 length = sizeof(gdrom_status);
   606             }
   607             memcpy( data_buffer, gdrom_status, length );
   608             ide_start_packet_read( length, 0 );
   609             break;
   610         case 1:
   611             if( length > 14 ) {
   612                 length = 14;
   613             }
   614             gdrom_read_short_status( idereg.current_lba, data_buffer );
   615             ide_start_packet_read( length, 0 );
   616             break;
   617         }
   618         break;
   619         case PKT_CMD_71:
   620             /* This is a weird one. As far as I can tell it returns random garbage
   621              * (and not even the same length each time, never mind the same data).
   622              * For sake of something to do, it returns the results from a test dump
   623              */
   624             REQUIRE_DISC();
   625             memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   626             ide_start_packet_read( sizeof(gdrom_71), 0 );
   627             break;
   628         default:
   629             ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   630             return;
   631     }
   632     idereg.last_packet_command = cmd[0];
   633 }
   635 void ide_write_buffer( unsigned char *data, uint32_t length )
   636 {
   637     switch( idereg.last_packet_command ) {
   638     case PKT_CMD_MODE_SELECT:
   639         if( idereg.current_lba < 10 ) {
   640             if( idereg.current_lba + length > 10 ) {
   641                 length = 10 - idereg.current_lba;
   642             }
   643             memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
   644         }
   645         break;
   646     default:
   647         WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
   648     }
   649 }
.