Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 736:a02d1475ccfd
prev678:35eb00945316
next833:1ea87e0221f8
author nkeynes
date Wed Jul 30 22:50:44 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Bug #61: OpenBSD support
(Modified) patch from bsdmaniak, thanks!
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     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 }
.