Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 833:1ea87e0221f8
prev736:a02d1475ccfd
next858:368fc0dcd57c
author nkeynes
date Tue Sep 09 00:50:15 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Fix set_grab thinko
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                 break;
   349             }
   350         }
   351     }
   352     return xfercount;
   353 }
   355 void ide_write_data_pio( uint16_t val ) {
   356     if( idereg.state == IDE_STATE_CMD_WRITE ) {
   357         WRITE_BUFFER(val);
   358         idereg.data_offset+=2;
   359         if( idereg.data_offset >= idereg.data_length ) {
   360             idereg.state = IDE_STATE_BUSY;
   361             idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   362             idereg.data_offset = -1;
   363             ide_packet_command(data_buffer);
   364         }
   365     } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
   366         WRITE_BUFFER(val);
   367         idereg.data_offset +=2;
   368         if( idereg.data_offset >= idereg.data_length ) {
   369             idereg.state = IDE_STATE_IDLE;
   370             idereg.status &= ~IDE_STATUS_DRQ;
   371             idereg.data_offset = -1;
   372             idereg.count = 3; /* complete */
   373             ide_raise_interrupt();
   374             ide_write_buffer( data_buffer, idereg.data_length );
   375         }
   376     }
   377 }
   379 void ide_write_control( uint8_t val ) {
   380     if( IS_IDE_IRQ_ENABLED() ) {
   381         if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   382             asic_clear_event( EVENT_IDE );
   383     } else {
   384         if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   385             asic_event( EVENT_IDE );
   386     }
   387     idereg.control = val;
   388 }
   390 void ide_write_command( uint8_t val ) {
   391     ide_clear_interrupt();
   392     idereg.command = val;
   393     switch( val ) {
   394     case IDE_CMD_NOP: /* Effectively an "abort" */
   395         idereg.state = IDE_STATE_IDLE;
   396         idereg.status = 0x51;
   397         idereg.error = 0x04;
   398         idereg.data_offset = -1;
   399         ide_raise_interrupt();
   400         return;
   401     case IDE_CMD_RESET_DEVICE:
   402         ide_reset();
   403         break;
   404     case IDE_CMD_PACKET:
   405         ide_start_command_packet_write();
   406         break;
   407     case IDE_CMD_SET_FEATURE:
   408         switch( idereg.feature ) {
   409         case IDE_FEAT_SET_TRANSFER_MODE:
   410             switch( idereg.count & 0xF8 ) {
   411             case IDE_XFER_PIO:
   412                 INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   413                 break;
   414             case IDE_XFER_PIO_FLOW:
   415                 INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   416                 break;
   417             case IDE_XFER_MULTI_DMA:
   418                 INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   419                 break;
   420             case IDE_XFER_ULTRA_DMA:
   421                 INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   422                 break;
   423             default:
   424                 INFO( "Setting unknown transfer mode: %02X", idereg.count );
   425                 break;
   426             }
   427             break;
   428             default:
   429                 WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   430         }
   431         idereg.status = 0x50;
   432         idereg.error = 0x00;
   433         idereg.lba1 = 0x00;
   434         idereg.lba2 = 0x00;
   435         ide_raise_interrupt();
   436         break;
   437         default:
   438             WARN( "IDE: Unimplemented command: %02X", val );
   439     }
   440 }
   442 uint8_t ide_get_drive_status( void )
   443 {
   444     if( gdrom_disc == NULL ) {
   445         return IDE_DISC_NONE;
   446     } else {
   447         return gdrom_disc->drive_status(gdrom_disc);
   448     }
   449 }
   451 #define REQUIRE_DISC() if( gdrom_disc == NULL ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
   453 /**
   454  * Read the next sector from the active read, if any
   455  */
   456 static void ide_read_next_sector( void )
   457 {
   458     uint32_t sector_size;
   459     REQUIRE_DISC();
   460     gdrom_error_t status = 
   461         gdrom_disc->read_sector( gdrom_disc, idereg.current_lba, idereg.current_mode, 
   462                 data_buffer, &sector_size );
   463     if( status != PKT_ERR_OK ) {
   464         ide_set_packet_result( status );
   465         idereg.gdrom_sense[5] = (idereg.current_lba >> 16) & 0xFF;
   466         idereg.gdrom_sense[6] = (idereg.current_lba >> 8) & 0xFF;
   467         idereg.gdrom_sense[7] = idereg.current_lba & 0xFF;
   468         WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
   469     } else {
   470         idereg.current_lba++;
   471         idereg.sectors_left--;
   472         ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   473     }
   474 }
   476 /**
   477  * Execute a packet command. This particular method is responsible for parsing
   478  * the command buffers (12 bytes), and generating the appropriate responses, 
   479  * although the actual implementation is mostly delegated to gdrom.c
   480  */
   481 void ide_packet_command( unsigned char *cmd )
   482 {
   483     uint32_t length;
   484     uint32_t lba, status;
   486     /* Okay we have the packet in the command buffer */
   487     INFO( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   488           cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   489           cmd[8], cmd[9], cmd[10], cmd[11] );
   491     if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
   492         ide_set_packet_result( PKT_ERR_RESET );
   493         idereg.was_reset = FALSE;
   494         return;
   495     }
   497     switch( cmd[0] ) {
   498     case PKT_CMD_TEST_READY:
   499         REQUIRE_DISC();
   500         ide_set_packet_result( 0 );
   501         ide_raise_interrupt();
   502         idereg.status = 0x50;
   503         break;
   504     case PKT_CMD_MODE_SENSE:
   505         lba = cmd[2];
   506         if( lba >= GDROM_MODE_LENGTH ) {
   507             ide_set_error(PKT_ERR_BADFIELD);
   508         } else {
   509             length = cmd[4];
   510             if( lba+length > GDROM_MODE_LENGTH )
   511                 length = GDROM_MODE_LENGTH - lba;
   512             memcpy( data_buffer, idereg.gdrom_mode + lba, length );
   513             ide_start_packet_read( length, 0 );
   514         }
   515         break;
   516     case PKT_CMD_MODE_SELECT:
   517         lba = cmd[2];
   518         if( lba >= GDROM_MODE_LENGTH ) {
   519             ide_set_error(PKT_ERR_BADFIELD);
   520         } else {
   521             length = cmd[4];
   522             if( lba+length > GDROM_MODE_LENGTH )
   523                 length = GDROM_MODE_LENGTH - lba;
   524             idereg.current_lba = lba;
   525             ide_start_packet_write( length, 0 );
   526         }
   527         break;
   528     case PKT_CMD_SENSE:
   529         length = cmd[4];
   530         if( length > 10 )
   531             length = 10;
   532         memcpy( data_buffer, idereg.gdrom_sense, length );
   533         ide_start_packet_read( length, 0 );
   534         break;
   535     case PKT_CMD_READ_TOC:
   536         REQUIRE_DISC();
   537         length = (cmd[3]<<8) | cmd[4];
   538         if( length > sizeof(struct gdrom_toc) )
   539             length = sizeof(struct gdrom_toc);
   541         status = gdrom_disc->read_toc( gdrom_disc, data_buffer );
   542         if( status != PKT_ERR_OK ) {
   543             ide_set_packet_result( status );
   544         } else {
   545             ide_start_packet_read( length, 0 );
   546         }
   547         break;
   548     case PKT_CMD_SESSION_INFO:
   549         REQUIRE_DISC();
   550         length = cmd[4];
   551         if( length > 6 )
   552             length = 6;
   553         status = gdrom_disc->read_session( gdrom_disc, cmd[2], data_buffer );
   554         if( status != PKT_ERR_OK ) {
   555             ide_set_packet_result( status );
   556         } else {
   557             ide_start_packet_read( length, 0 );
   558         }
   559         break;
   560     case PKT_CMD_PLAY_AUDIO:
   561         REQUIRE_DISC();
   562         ide_set_packet_result( 0 );
   563         ide_raise_interrupt();
   564         idereg.status = 0x50;
   565         break;
   566     case PKT_CMD_READ_SECTOR:
   567         REQUIRE_DISC();
   568         idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   569         idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   570         idereg.current_mode = cmd[1];
   571         ide_read_next_sector();
   572         break;
   573     case PKT_CMD_SPIN_UP:
   574         REQUIRE_DISC();
   575         /* do nothing? */
   576         ide_set_packet_result( PKT_ERR_OK );
   577         ide_raise_interrupt();
   578         break;
   579     case PKT_CMD_STATUS:
   580         REQUIRE_DISC();
   581         length = cmd[4];
   582         switch( cmd[1] ) {
   583         case 0:
   584             if( length > sizeof(gdrom_status) ) {
   585                 length = sizeof(gdrom_status);
   586             }
   587             memcpy( data_buffer, gdrom_status, length );
   588             ide_start_packet_read( length, 0 );
   589             break;
   590         case 1:
   591             if( length > 14 ) {
   592                 length = 14;
   593             }
   594             gdrom_disc->read_position( gdrom_disc, idereg.current_lba, data_buffer );
   595             data_buffer[0] = 0x00;
   596             data_buffer[1] = 0x15; /* audio status ? */
   597             data_buffer[2] = 0x00;
   598             data_buffer[3] = 0x0E;
   599             ide_start_packet_read( length, 0 );
   600             break;
   601         }
   602         break;
   603         case PKT_CMD_71:
   604             /* This is a weird one. As far as I can tell it returns random garbage
   605              * (and not even the same length each time, never mind the same data).
   606              * For sake of something to do, it returns the results from a test dump
   607              */
   608             REQUIRE_DISC();
   609             memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   610             ide_start_packet_read( sizeof(gdrom_71), 0 );
   611             break;
   612         default:
   613             ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   614             return;
   615     }
   616     idereg.last_packet_command = cmd[0];
   617 }
   619 void ide_write_buffer( unsigned char *data, uint32_t length )
   620 {
   621     switch( idereg.last_packet_command ) {
   622     case PKT_CMD_MODE_SELECT:
   623         if( idereg.current_lba < 10 ) {
   624             if( idereg.current_lba + length > 10 ) {
   625                 length = 10 - idereg.current_lba;
   626             }
   627             memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
   628         }
   629         break;
   630     default:
   631         WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
   632     }
   633 }
.