Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 858:368fc0dcd57c
prev833:1ea87e0221f8
next888:9892c970b95a
author nkeynes
date Fri Sep 12 11:59:49 2008 +0000 (12 years ago)
permissions -rw-r--r--
last change Implement packet command 10h drive status
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_DRIVE_STATUS:
   505         lba = cmd[2];
   506         if( lba >= GDROM_DRIVE_STATUS_LENGTH ) {
   507             ide_set_error(PKT_ERR_BADFIELD);
   508         } else {
   509             uint8_t status = ide_get_drive_status();
   510             /* FIXME: Refactor read_position to avoid this kind of crud */
   511             char tmp[16];
   512             gdrom_disc->read_position( gdrom_disc, idereg.current_lba, tmp );
   514             length = cmd[4];
   515             if( lba+length > GDROM_DRIVE_STATUS_LENGTH )
   516                 length = GDROM_DRIVE_STATUS_LENGTH - lba;
   517             char data[10];
   518             data[0] = status & 0x0F;
   519             data[1] = status & 0xF0;
   520             data[2] = tmp[4];
   521             data[3] = tmp[5];
   522             data[4] = tmp[6];
   523             data[5] = tmp[11];
   524             data[6] = tmp[12];
   525             data[7] = tmp[13];
   526             data[8] = 0;
   527             data[9] = 0;
   528             memcpy( data_buffer, data + lba, length );
   529             ide_start_packet_read( length, 0 );
   530         }
   531         break;
   532     case PKT_CMD_MODE_SENSE:
   533         lba = cmd[2];
   534         if( lba >= GDROM_MODE_LENGTH ) {
   535             ide_set_error(PKT_ERR_BADFIELD);
   536         } else {
   537             length = cmd[4];
   538             if( lba+length > GDROM_MODE_LENGTH )
   539                 length = GDROM_MODE_LENGTH - lba;
   540             memcpy( data_buffer, idereg.gdrom_mode + lba, length );
   541             ide_start_packet_read( length, 0 );
   542         }
   543         break;
   544     case PKT_CMD_MODE_SELECT:
   545         lba = cmd[2];
   546         if( lba >= GDROM_MODE_LENGTH ) {
   547             ide_set_error(PKT_ERR_BADFIELD);
   548         } else {
   549             length = cmd[4];
   550             if( lba+length > GDROM_MODE_LENGTH )
   551                 length = GDROM_MODE_LENGTH - lba;
   552             idereg.current_lba = lba;
   553             ide_start_packet_write( length, 0 );
   554         }
   555         break;
   556     case PKT_CMD_SENSE:
   557         length = cmd[4];
   558         if( length > 10 )
   559             length = 10;
   560         memcpy( data_buffer, idereg.gdrom_sense, length );
   561         ide_start_packet_read( length, 0 );
   562         break;
   563     case PKT_CMD_READ_TOC:
   564         REQUIRE_DISC();
   565         length = (cmd[3]<<8) | cmd[4];
   566         if( length > sizeof(struct gdrom_toc) )
   567             length = sizeof(struct gdrom_toc);
   569         status = gdrom_disc->read_toc( gdrom_disc, data_buffer );
   570         if( status != PKT_ERR_OK ) {
   571             ide_set_packet_result( status );
   572         } else {
   573             ide_start_packet_read( length, 0 );
   574         }
   575         break;
   576     case PKT_CMD_SESSION_INFO:
   577         REQUIRE_DISC();
   578         length = cmd[4];
   579         if( length > 6 )
   580             length = 6;
   581         status = gdrom_disc->read_session( gdrom_disc, cmd[2], data_buffer );
   582         if( status != PKT_ERR_OK ) {
   583             ide_set_packet_result( status );
   584         } else {
   585             ide_start_packet_read( length, 0 );
   586         }
   587         break;
   588     case PKT_CMD_PLAY_AUDIO:
   589         REQUIRE_DISC();
   590         ide_set_packet_result( 0 );
   591         ide_raise_interrupt();
   592         idereg.status = 0x50;
   593         break;
   594     case PKT_CMD_READ_SECTOR:
   595         REQUIRE_DISC();
   596         idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   597         idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   598         idereg.current_mode = cmd[1];
   599         ide_read_next_sector();
   600         break;
   601     case PKT_CMD_SPIN_UP:
   602         REQUIRE_DISC();
   603         /* do nothing? */
   604         ide_set_packet_result( PKT_ERR_OK );
   605         ide_raise_interrupt();
   606         break;
   607     case PKT_CMD_STATUS:
   608         REQUIRE_DISC();
   609         length = cmd[4];
   610         switch( cmd[1] ) {
   611         case 0:
   612             if( length > sizeof(gdrom_status) ) {
   613                 length = sizeof(gdrom_status);
   614             }
   615             memcpy( data_buffer, gdrom_status, length );
   616             ide_start_packet_read( length, 0 );
   617             break;
   618         case 1:
   619             if( length > 14 ) {
   620                 length = 14;
   621             }
   622             gdrom_disc->read_position( gdrom_disc, idereg.current_lba, data_buffer );
   623             data_buffer[0] = 0x00;
   624             data_buffer[1] = 0x15; /* audio status ? */
   625             data_buffer[2] = 0x00;
   626             data_buffer[3] = 0x0E;
   627             ide_start_packet_read( length, 0 );
   628             break;
   629         }
   630         break;
   631         case PKT_CMD_71:
   632             /* This is a weird one. As far as I can tell it returns random garbage
   633              * (and not even the same length each time, never mind the same data).
   634              * For sake of something to do, it returns the results from a test dump
   635              */
   636             REQUIRE_DISC();
   637             memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   638             ide_start_packet_read( sizeof(gdrom_71), 0 );
   639             break;
   640         default:
   641             ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   642             return;
   643     }
   644     idereg.last_packet_command = cmd[0];
   645 }
   647 void ide_write_buffer( unsigned char *data, uint32_t length )
   648 {
   649     switch( idereg.last_packet_command ) {
   650     case PKT_CMD_MODE_SELECT:
   651         if( idereg.current_lba < 10 ) {
   652             if( idereg.current_lba + length > 10 ) {
   653                 length = 10 - idereg.current_lba;
   654             }
   655             memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
   656         }
   657         break;
   658     default:
   659         WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
   660     }
   661 }
.