Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 1075:1a21750d300c
prev1023:264e2fd90be8
next1097:d4807997e450
author nkeynes
date Fri Jul 31 13:45:32 2009 +1000 (11 years ago)
permissions -rw-r--r--
last change Remove or change the level of a bunch of INFO messages that shouldn't really
be INFO level
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/gddriver.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     if( fread( &idereg, sizeof(idereg), 1, f ) != 1 ||
   178         fread( data_buffer, MAX_SECTOR_SIZE, 1, f ) != 1 ) {
   179         return -1;
   180     }
   181     return 0;
   182 }
   184 /************************ State transitions *************************/
   186 void ide_set_packet_result( uint16_t result )
   187 {
   188     idereg.gdrom_sense[0] = 0xf0;
   189     idereg.gdrom_sense[2] = result & 0xFF;
   190     idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
   191     idereg.error = (result & 0x0F) << 4;
   192     idereg.count = 3;
   193     if( result != 0 ) {
   194         idereg.status = 0x51;
   195         idereg.state = IDE_STATE_IDLE;
   196         ide_raise_interrupt();
   197     } else {
   198         idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
   199     }
   200 }
   202 /**
   203  * Begin command packet write to the device. This is always 12 bytes of PIO data
   204  */
   205 static void ide_start_command_packet_write( )
   206 {
   207     idereg.state = IDE_STATE_CMD_WRITE;
   208     idereg.status = 0x58;
   209     idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
   210     idereg.count = IDE_COUNT_CD;
   211     idereg.data_offset = 0;
   212     idereg.data_length = 12;
   213 }
   215 /**
   216  * Begin PIO/DMA read from the device. The data is assumed to already be
   217  * in the buffer at this point.
   218  */
   219 static void ide_start_read( int length, gboolean dma ) 
   220 {
   221     idereg.count = IDE_COUNT_IO;
   222     idereg.data_length = length;
   223     idereg.data_offset = 0;
   224     if( dma ) {
   225         idereg.state = IDE_STATE_DMA_READ;
   226         idereg.status = 0xD0;
   227     } else {
   228         idereg.state = IDE_STATE_PIO_READ;
   229         idereg.status = 0x58;
   230         idereg.lba1 = length & 0xFF;
   231         idereg.lba2 = length >> 8; 
   232         ide_raise_interrupt( );
   233     }
   234 }
   236 static void ide_start_write( int length, gboolean dma )
   237 {
   238     idereg.count = 0;
   239     idereg.data_length = length;
   240     idereg.data_offset = 0;
   241     if( dma ) {
   242         idereg.state = IDE_STATE_DMA_WRITE;
   243         idereg.status = 0xD0;
   244     }  else {
   245         idereg.state = IDE_STATE_PIO_WRITE;
   246         idereg.status = 0x58;
   247         idereg.lba1 = length & 0xFF;
   248         idereg.lba2 = length >> 8;
   249         ide_raise_interrupt( );
   250     }
   251 }
   253 static void ide_start_packet_read( int length, int sector_count )
   254 {
   255     idereg.sectors_left = sector_count;
   256     ide_set_packet_result( PKT_ERR_OK );
   257     ide_start_read( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   258 }
   260 static void ide_start_packet_write( int length, int sector_count )
   261 {
   262     idereg.sectors_left = sector_count;
   263     ide_set_packet_result( PKT_ERR_OK );
   264     ide_start_write( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   265 }
   267 static void ide_raise_interrupt( void )
   268 {
   269     if( idereg.intrq_pending == 0 ) {
   270         idereg.intrq_pending = 1;
   271         if( IS_IDE_IRQ_ENABLED() )
   272             asic_event( EVENT_IDE );
   273     }
   274 }
   276 static void ide_clear_interrupt( void ) 
   277 {
   278     if( idereg.intrq_pending != 0 ) {
   279         idereg.intrq_pending = 0;
   280         if( IS_IDE_IRQ_ENABLED() )
   281             asic_clear_event( EVENT_IDE );
   282     }
   283 }
   285 static void ide_set_error( int error_code )
   286 {
   287     idereg.status = 0x51;
   288     idereg.error = error_code;
   289 }
   291 uint8_t ide_read_status( void ) 
   292 {
   293     if( (idereg.status & IDE_STATUS_BSY) == 0 )
   294         ide_clear_interrupt();
   295     return idereg.status;
   296 }
   298 uint16_t ide_read_data_pio( void ) {
   299     if( idereg.state == IDE_STATE_PIO_READ ) {
   300         uint16_t rv = READ_BUFFER();
   301         idereg.data_offset += 2;
   302         if( idereg.data_offset >= idereg.data_length ) {
   303             idereg.state = IDE_STATE_IDLE;
   304             idereg.status &= ~IDE_STATUS_DRQ;
   305             idereg.data_offset = -1;
   306             idereg.count = 3; /* complete */
   307             ide_raise_interrupt();
   308             if( idereg.sectors_left > 0 ) {
   309                 ide_read_next_sector();
   310             }
   311         }
   312         return rv;
   313     } else {
   314         return 0xFFFF;
   315     }
   316 }
   319 /**
   320  * DMA read request
   321  *
   322  * This method is called from the ASIC side when a DMA read request is
   323  * initiated. If there is a pending DMA transfer already, we copy the
   324  * data immediately, otherwise we record the DMA buffer for use when we
   325  * get to actually doing the transfer.
   326  * @return number of bytes transfered
   327  */
   328 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
   329 {
   330     uint32_t xfercount = 0;
   331     while( xfercount < length && idereg.state == IDE_STATE_DMA_READ ) {
   332         int xferlen = length - xfercount;
   333         int remaining = idereg.data_length - idereg.data_offset;
   334         if( xferlen > remaining ) {
   335             xferlen = remaining;
   336         }
   337         mem_copy_to_sh4( addr, (data_buffer + idereg.data_offset), xferlen );
   338         xfercount += xferlen;
   339         addr += xferlen;
   340         idereg.data_offset += xferlen;
   341         if( idereg.data_offset >= idereg.data_length ) {
   342             if( idereg.sectors_left > 0 ) {
   343                 ide_read_next_sector();
   344             } else {
   345                 idereg.data_offset = -1;
   346                 idereg.state = IDE_STATE_IDLE;
   347                 idereg.status = 0x50;
   348                 idereg.count = 0x03;
   349                 ide_raise_interrupt();
   350                 break;
   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                 DEBUG( "Set PIO default mode: %d", idereg.count&0x07 );
   415                 break;
   416             case IDE_XFER_PIO_FLOW:
   417                 DEBUG( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   418                 break;
   419             case IDE_XFER_MULTI_DMA:
   420                 DEBUG( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   421                 break;
   422             case IDE_XFER_ULTRA_DMA:
   423                 DEBUG( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   424                 break;
   425             default:
   426                 DEBUG( "Setting unknown transfer mode: %02X", idereg.count );
   427                 break;
   428             }
   429             break;
   430             default:
   431                 DEBUG( "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             DEBUG( "IDE: Unimplemented command: %02X", val );
   441     }
   442 }
   444 uint8_t ide_get_drive_status( void )
   445 {
   446     return gdrom_disc_get_drive_status(gdrom_disc);
   447 }
   449 #define REQUIRE_DISC() if( gdrom_disc == NULL || gdrom_disc->disc_type == IDE_DISC_NONE  ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
   451 /**
   452  * Read the next sector from the active read, if any
   453  */
   454 static void ide_read_next_sector( void )
   455 {
   456     uint32_t sector_size;
   457     REQUIRE_DISC();
   458     gdrom_error_t status = 
   459         gdrom_disc->read_sector( gdrom_disc, idereg.current_lba, idereg.current_mode, 
   460                 data_buffer, &sector_size );
   461     if( status != PKT_ERR_OK ) {
   462         ide_set_packet_result( status );
   463         idereg.gdrom_sense[5] = (idereg.current_lba >> 16) & 0xFF;
   464         idereg.gdrom_sense[6] = (idereg.current_lba >> 8) & 0xFF;
   465         idereg.gdrom_sense[7] = idereg.current_lba & 0xFF;
   466         WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
   467     } else {
   468         idereg.current_lba++;
   469         idereg.sectors_left--;
   470         ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   471     }
   472 }
   474 /**
   475  * Execute a packet command. This particular method is responsible for parsing
   476  * the command buffers (12 bytes), and generating the appropriate responses, 
   477  * although the actual implementation is mostly delegated to gdrom.c
   478  */
   479 void ide_packet_command( unsigned char *cmd )
   480 {
   481     uint32_t length;
   482     uint32_t lba, status;
   484     /* Okay we have the packet in the command buffer */
   485     DEBUG( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   486           cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   487           cmd[8], cmd[9], cmd[10], cmd[11] );
   489     if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
   490         ide_set_packet_result( PKT_ERR_RESET );
   491         idereg.was_reset = FALSE;
   492         return;
   493     }
   495     switch( cmd[0] ) {
   496     case PKT_CMD_TEST_READY:
   497         REQUIRE_DISC();
   498         ide_set_packet_result( 0 );
   499         ide_raise_interrupt();
   500         idereg.status = 0x50;
   501         break;
   502     case PKT_CMD_DRIVE_STATUS:
   503         lba = cmd[2];
   504         if( lba >= GDROM_DRIVE_STATUS_LENGTH ) {
   505             ide_set_error(PKT_ERR_BADFIELD);
   506         } else {
   507             uint8_t status = ide_get_drive_status();
   508             /* FIXME: Refactor read_position to avoid this kind of crud */
   509             unsigned char tmp[16];
   510             gdrom_disc_get_short_status( gdrom_disc, idereg.current_lba, tmp );
   512             length = cmd[4];
   513             if( lba+length > GDROM_DRIVE_STATUS_LENGTH )
   514                 length = GDROM_DRIVE_STATUS_LENGTH - lba;
   515             char data[10];
   516             data[0] = status & 0x0F;
   517             data[1] = status & 0xF0;
   518             data[2] = tmp[4];
   519             data[3] = tmp[5];
   520             data[4] = tmp[6];
   521             data[5] = tmp[11];
   522             data[6] = tmp[12];
   523             data[7] = tmp[13];
   524             data[8] = 0;
   525             data[9] = 0;
   526             memcpy( data_buffer, data + lba, length );
   527             ide_start_packet_read( length, 0 );
   528         }
   529         break;
   530     case PKT_CMD_MODE_SENSE:
   531         lba = cmd[2];
   532         if( lba >= GDROM_MODE_LENGTH ) {
   533             ide_set_error(PKT_ERR_BADFIELD);
   534         } else {
   535             length = cmd[4];
   536             if( lba+length > GDROM_MODE_LENGTH )
   537                 length = GDROM_MODE_LENGTH - lba;
   538             memcpy( data_buffer, idereg.gdrom_mode + lba, length );
   539             ide_start_packet_read( length, 0 );
   540         }
   541         break;
   542     case PKT_CMD_MODE_SELECT:
   543         lba = cmd[2];
   544         if( lba >= GDROM_MODE_LENGTH ) {
   545             ide_set_error(PKT_ERR_BADFIELD);
   546         } else {
   547             length = cmd[4];
   548             if( lba+length > GDROM_MODE_LENGTH )
   549                 length = GDROM_MODE_LENGTH - lba;
   550             idereg.current_lba = lba;
   551             ide_start_packet_write( length, 0 );
   552         }
   553         break;
   554     case PKT_CMD_SENSE:
   555         length = cmd[4];
   556         if( length > 10 )
   557             length = 10;
   558         memcpy( data_buffer, idereg.gdrom_sense, length );
   559         ide_start_packet_read( length, 0 );
   560         break;
   561     case PKT_CMD_READ_TOC:
   562         REQUIRE_DISC();
   563         length = (cmd[3]<<8) | cmd[4];
   564         if( length > GDROM_TOC_SIZE )
   565             length = GDROM_TOC_SIZE;
   567         status = gdrom_disc_get_toc( gdrom_disc, data_buffer );
   568         if( status != PKT_ERR_OK ) {
   569             ide_set_packet_result( status );
   570         } else {
   571             ide_start_packet_read( length, 0 );
   572         }
   573         break;
   574     case PKT_CMD_SESSION_INFO:
   575         REQUIRE_DISC();
   576         length = cmd[4];
   577         if( length > 6 )
   578             length = 6;
   579         status = gdrom_disc_get_session_info( gdrom_disc, cmd[2], data_buffer );
   580         if( status != PKT_ERR_OK ) {
   581             ide_set_packet_result( status );
   582         } else {
   583             ide_start_packet_read( length, 0 );
   584         }
   585         break;
   586     case PKT_CMD_PLAY_AUDIO:
   587         REQUIRE_DISC();
   588         ide_set_packet_result( 0 );
   589         ide_raise_interrupt();
   590         idereg.status = 0x50;
   591         break;
   592     case PKT_CMD_READ_SECTOR:
   593         REQUIRE_DISC();
   594         idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   595         idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   596         idereg.current_mode = cmd[1];
   597         ide_read_next_sector();
   598         break;
   599     case PKT_CMD_SPIN_UP:
   600         REQUIRE_DISC();
   601         /* do nothing? */
   602         ide_set_packet_result( PKT_ERR_OK );
   603         ide_raise_interrupt();
   604         break;
   605     case PKT_CMD_STATUS:
   606         REQUIRE_DISC();
   607         length = cmd[4];
   608         switch( cmd[1] ) {
   609         case 0:
   610             if( length > sizeof(gdrom_status) ) {
   611                 length = sizeof(gdrom_status);
   612             }
   613             memcpy( data_buffer, gdrom_status, length );
   614             ide_start_packet_read( length, 0 );
   615             break;
   616         case 1:
   617             if( length > 14 ) {
   618                 length = 14;
   619             }
   620             gdrom_disc_get_short_status( gdrom_disc, idereg.current_lba, data_buffer );
   621             ide_start_packet_read( length, 0 );
   622             break;
   623         }
   624         break;
   625         case PKT_CMD_71:
   626             /* This is a weird one. As far as I can tell it returns random garbage
   627              * (and not even the same length each time, never mind the same data).
   628              * For sake of something to do, it returns the results from a test dump
   629              */
   630             REQUIRE_DISC();
   631             memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   632             ide_start_packet_read( sizeof(gdrom_71), 0 );
   633             break;
   634         default:
   635             ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   636             return;
   637     }
   638     idereg.last_packet_command = cmd[0];
   639 }
   641 void ide_write_buffer( unsigned char *data, uint32_t length )
   642 {
   643     switch( idereg.last_packet_command ) {
   644     case PKT_CMD_MODE_SELECT:
   645         if( idereg.current_lba < 10 ) {
   646             if( idereg.current_lba + length > 10 ) {
   647                 length = 10 - idereg.current_lba;
   648             }
   649             memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
   650         }
   651         break;
   652     default:
   653         WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
   654     }
   655 }
.