Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 423:f92f80fe64da
prev422:61a0598e07ff
next430:467519b050f4
author nkeynes
date Sat Oct 06 09:04:53 2007 +0000 (12 years ago)
permissions -rw-r--r--
last change Fix remaining compilation warning
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.25 2007-10-06 09:04:53 nkeynes Exp $
     3  *
     4  * IDE interface implementation
     5  *
     6  *
     7  * Note: All references to read/write are from the host's point of view.
     8  *
     9  * See: INF-8020 
    10  * Copyright (c) 2005 Nathan Keynes.
    11  *
    12  * This program is free software; you can redistribute it and/or modify
    13  * it under the terms of the GNU General Public License as published by
    14  * the Free Software Foundation; either version 2 of the License, or
    15  * (at your option) any later version.
    16  *
    17  * This program is distributed in the hope that it will be useful,
    18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    20  * GNU General Public License for more details.
    21  */
    23 #define MODULE ide_module
    25 #include <assert.h>
    26 #include <stdlib.h>
    27 #include "dream.h"
    28 #include "mem.h"
    29 #include "asic.h"
    30 #include "gdrom/ide.h"
    31 #include "gdrom/gdrom.h"
    32 #include "gdrom/packet.h"
    34 #define MAX_WRITE_BUF 4096
    35 #define MAX_SECTOR_SIZE 2352 /* Audio sector */
    36 #define DEFAULT_DATA_SECTORS 8
    38 static void ide_init( void );
    39 static void ide_reset( void );
    40 static uint32_t ide_run_slice( uint32_t nanosecs );
    41 static void ide_save_state( FILE *f );
    42 static int ide_load_state( FILE *f );
    43 static void ide_raise_interrupt( void );
    44 static void ide_clear_interrupt( void );
    45 static void ide_packet_command( unsigned char *data );
    46 static void ide_read_next_sector(void);
    48 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, ide_run_slice,
    49 				       NULL, ide_save_state, ide_load_state };
    51 struct ide_registers idereg;
    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 /* "\0\0\0\0\xb4\x19\0\0\x08SE      REV 6.42990316" */
    60 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
    61                        0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
    62                        0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
    63                        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     idereg.data_offset = -1;
   152     idereg.data_length = -1;
   153     idereg.last_read_track = 1;
   154     idereg.read_lba = 150;
   155     idereg.read_mode = 0x28;
   156     idereg.sectors_left = 0;
   157     idereg.was_reset = TRUE;
   158 }
   160 static uint32_t ide_run_slice( uint32_t nanosecs )
   161 {
   162     if( gdrom_disc != NULL && gdrom_disc->run_time_slice != NULL ) {
   163 	gdrom_disc->run_time_slice(gdrom_disc, nanosecs);
   164     }
   165     return nanosecs;
   166 }
   168 static void ide_save_state( FILE *f )
   169 {
   170     fwrite( &idereg, sizeof(idereg), 1, f );
   171     fwrite( data_buffer, MAX_SECTOR_SIZE, 1, f );
   172 }
   174 static int ide_load_state( FILE *f )
   175 {
   176     fread( &idereg, sizeof(idereg), 1, f );
   177     fread( data_buffer, MAX_SECTOR_SIZE, 1, f );
   178     return 0;
   179 }
   181 /************************ State transitions *************************/
   183 void ide_set_packet_result( uint16_t result )
   184 {
   185     idereg.gdrom_sense[0] = 0xf0;
   186     idereg.gdrom_sense[2] = result & 0xFF;
   187     idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
   188     idereg.error = (result & 0x0F) << 4;
   189     idereg.count = 3;
   190     if( result != 0 ) {
   191 	idereg.status = 0x51;
   192 	ide_raise_interrupt();
   193     } else {
   194 	idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
   195     }
   196 }
   198 /**
   199  * Begin command packet write to the device. This is always 12 bytes of PIO data
   200  */
   201 static void ide_start_command_packet_write( )
   202 {
   203     idereg.state = IDE_STATE_CMD_WRITE;
   204     idereg.status = 0x58;
   205     idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
   206     idereg.count = IDE_COUNT_CD;
   207     idereg.data_offset = 0;
   208     idereg.data_length = 12;
   209 }
   211 /**
   212  * Begin PIO read from the device. The data is assumed to already be
   213  * in the buffer at this point.
   214  */
   215 static void ide_start_read( int length, gboolean dma ) 
   216 {
   217     idereg.count = IDE_COUNT_IO;
   218     idereg.data_length = length;
   219     idereg.data_offset = 0;
   220     if( dma ) {
   221 	idereg.state = IDE_STATE_DMA_READ;
   222 	idereg.status = 0xD0;
   223     } else {
   224 	idereg.state = IDE_STATE_PIO_READ;
   225 	idereg.status = 0x58;
   226 	idereg.lba1 = length & 0xFF;
   227 	idereg.lba2 = length >> 8; 
   228 	ide_raise_interrupt( );
   229     }
   230 }
   232 static void ide_start_packet_read( int length, int sector_count )
   233 {
   234     idereg.sectors_left = sector_count;
   235     ide_set_packet_result( PKT_ERR_OK );
   236     ide_start_read( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   237 }
   239 static void ide_raise_interrupt( void )
   240 {
   241     if( idereg.intrq_pending == 0 ) {
   242 	idereg.intrq_pending = 1;
   243 	if( IS_IDE_IRQ_ENABLED() )
   244 	    asic_event( EVENT_IDE );
   245     }
   246 }
   248 static void ide_clear_interrupt( void ) 
   249 {
   250     if( idereg.intrq_pending != 0 ) {
   251 	idereg.intrq_pending = 0;
   252 	if( IS_IDE_IRQ_ENABLED() )
   253 	    asic_clear_event( EVENT_IDE );
   254     }
   255 }
   257 static void ide_set_error( int error_code )
   258 {
   259     idereg.status = 0x51;
   260     idereg.error = error_code;
   261 }
   263 uint8_t ide_read_status( void ) 
   264 {
   265     if( (idereg.status & IDE_STATUS_BSY) == 0 )
   266 	ide_clear_interrupt();
   267     return idereg.status;
   268 }
   270 uint16_t ide_read_data_pio( void ) {
   271     if( idereg.state == IDE_STATE_PIO_READ ) {
   272 	uint16_t rv = READ_BUFFER();
   273 	idereg.data_offset += 2;
   274 	if( idereg.data_offset >= idereg.data_length ) {
   275 	    idereg.state = IDE_STATE_IDLE;
   276 	    idereg.status &= ~IDE_STATUS_DRQ;
   277 	    idereg.data_offset = -1;
   278 	    idereg.count = 3; /* complete */
   279 	    ide_raise_interrupt();
   280 	    if( idereg.sectors_left > 0 ) {
   281 		ide_read_next_sector();
   282 	    }
   283 	}
   284 	return rv;
   285     } else {
   286         return 0xFFFF;
   287     }
   288 }
   291 /**
   292  * DMA read request
   293  *
   294  * This method is called from the ASIC side when a DMA read request is
   295  * initiated. If there is a pending DMA transfer already, we copy the
   296  * data immediately, otherwise we record the DMA buffer for use when we
   297  * get to actually doing the transfer.
   298  * @return number of bytes transfered
   299  */
   300 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
   301 {
   302     uint32_t xfercount = 0;
   303     if( idereg.state == IDE_STATE_DMA_READ ) {
   304 	while( xfercount < length ) {
   305 	    int xferlen = length - xfercount;
   306 	    int remaining = idereg.data_length - idereg.data_offset;
   307 	    if( xferlen > remaining ) {
   308 		xferlen = remaining;
   309 	    }
   310 	    mem_copy_to_sh4( addr, (char *)(data_buffer + idereg.data_offset), xferlen );
   311 	    xfercount += xferlen;
   312 	    addr += xferlen;
   313 	    idereg.data_offset += xferlen;
   314 	    if( idereg.data_offset >= idereg.data_length ) {
   315 		if( idereg.sectors_left > 0 ) {
   316 		    ide_read_next_sector();
   317 		} else {
   318 		    idereg.data_offset = -1;
   319 		    idereg.state = IDE_STATE_IDLE;
   320 		    idereg.status = 0x50;
   321 		    idereg.count = 0x03;
   322 		    ide_raise_interrupt();
   323 		    asic_event( EVENT_IDE_DMA );
   324 		    break;
   325 		}
   326 	    }
   327 	}
   328     }
   329     return xfercount;
   330 }
   332 void ide_write_data_pio( uint16_t val ) {
   333     if( idereg.state == IDE_STATE_CMD_WRITE ) {
   334 	WRITE_BUFFER(val);
   335 	idereg.data_offset+=2;
   336 	if( idereg.data_offset >= idereg.data_length ) {
   337 	    idereg.state = IDE_STATE_BUSY;
   338 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   339 	    idereg.data_offset = -1;
   340 	    ide_packet_command(data_buffer);
   341 	}
   342     } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
   343 	WRITE_BUFFER(val);
   344 	if( idereg.data_offset >= idereg.data_length ) {
   345 	    idereg.state = IDE_STATE_BUSY;
   346 	    idereg.data_offset = -1;
   347 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   348 	    /* ??? - no data writes yet anyway */
   349 	}
   350     }
   351 }
   353 void ide_write_control( uint8_t val ) {
   354     if( IS_IDE_IRQ_ENABLED() ) {
   355 	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   356 	    asic_clear_event( EVENT_IDE );
   357     } else {
   358 	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   359 	    asic_event( EVENT_IDE );
   360     }
   361     idereg.control = val;
   362 }
   364 void ide_write_command( uint8_t val ) {
   365     ide_clear_interrupt();
   366     idereg.command = val;
   367     switch( val ) {
   368     case IDE_CMD_NOP: /* Effectively an "abort" */
   369 	idereg.state = IDE_STATE_IDLE;
   370 	idereg.status = 0x51;
   371 	idereg.error = 0x04;
   372 	idereg.data_offset = -1;
   373 	ide_raise_interrupt();
   374 	return;
   375     case IDE_CMD_RESET_DEVICE:
   376 	ide_reset();
   377 	break;
   378     case IDE_CMD_PACKET:
   379 	ide_start_command_packet_write();
   380 	break;
   381     case IDE_CMD_SET_FEATURE:
   382 	switch( idereg.feature ) {
   383 	case IDE_FEAT_SET_TRANSFER_MODE:
   384 	    switch( idereg.count & 0xF8 ) {
   385 	    case IDE_XFER_PIO:
   386 		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   387 		break;
   388 	    case IDE_XFER_PIO_FLOW:
   389 		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   390 		break;
   391 	    case IDE_XFER_MULTI_DMA:
   392 		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   393 		break;
   394 	    case IDE_XFER_ULTRA_DMA:
   395 		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   396 		break;
   397 	    default:
   398 		INFO( "Setting unknown transfer mode: %02X", idereg.count );
   399 		break;
   400 	    }
   401 	    break;
   402 	default:
   403 	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   404 	}
   405 	idereg.status = 0x50;
   406 	idereg.error = 0x00;
   407 	idereg.lba1 = 0x00;
   408 	idereg.lba2 = 0x00;
   409 	ide_raise_interrupt();
   410 	break;
   411     default:
   412 	WARN( "IDE: Unimplemented command: %02X", val );
   413     }
   414 }
   416 uint8_t ide_get_drive_status( void )
   417 {
   418     if( gdrom_disc == NULL ) {
   419 	return IDE_DISC_NONE;
   420     } else {
   421 	return gdrom_disc->drive_status(gdrom_disc);
   422     }
   423 }
   425 #define REQUIRE_DISC() if( gdrom_disc == NULL ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
   427 /**
   428  * Read the next sector from the active read, if any
   429  */
   430 static void ide_read_next_sector( void )
   431 {
   432     uint32_t sector_size;
   433     REQUIRE_DISC();
   434     gdrom_error_t status = 
   435 	gdrom_disc->read_sector( gdrom_disc, idereg.read_lba, idereg.read_mode, 
   436 				 data_buffer, &sector_size );
   437     if( status != PKT_ERR_OK ) {
   438 	ide_set_packet_result( status );
   439 	idereg.gdrom_sense[5] = (idereg.read_lba >> 16) & 0xFF;
   440 	idereg.gdrom_sense[6] = (idereg.read_lba >> 8) & 0xFF;
   441 	idereg.gdrom_sense[7] = idereg.read_lba & 0xFF;
   442 	WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
   443     } else {
   444 	idereg.read_lba++;
   445 	idereg.sectors_left--;
   446 	ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   447     }
   448 }
   450 /**
   451  * Execute a packet command. This particular method is responsible for parsing
   452  * the command buffers (12 bytes), and generating the appropriate responses, 
   453  * although the actual implementation is mostly delegated to gdrom.c
   454  */
   455 void ide_packet_command( unsigned char *cmd )
   456 {
   457     uint32_t length;
   458     uint32_t lba, status;
   460     /* Okay we have the packet in the command buffer */
   461     INFO( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   462 	  cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   463 	  cmd[8], cmd[9], cmd[10], cmd[11] );
   465     if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
   466 	ide_set_packet_result( PKT_ERR_RESET );
   467 	idereg.was_reset = FALSE;
   468 	return;
   469     }
   471     switch( cmd[0] ) {
   472     case PKT_CMD_TEST_READY:
   473 	REQUIRE_DISC();
   474 	ide_set_packet_result( 0 );
   475 	ide_raise_interrupt();
   476 	idereg.status = 0x50;
   477 	break;
   478     case PKT_CMD_IDENTIFY:
   479 	lba = cmd[2];
   480 	if( lba >= sizeof(gdrom_ident) ) {
   481 	    ide_set_error(PKT_ERR_BADFIELD);
   482 	} else {
   483 	    length = cmd[4];
   484 	    if( lba+length > sizeof(gdrom_ident) )
   485 		length = sizeof(gdrom_ident) - lba;
   486 	    memcpy( data_buffer, gdrom_ident + lba, length );
   487 	    ide_start_packet_read( length, 0 );
   488 	}
   489 	break;
   490     case PKT_CMD_SENSE:
   491 	length = cmd[4];
   492 	if( length > 10 )
   493 	    length = 10;
   494 	memcpy( data_buffer, idereg.gdrom_sense, length );
   495 	ide_start_packet_read( length, 0 );
   496 	break;
   497     case PKT_CMD_READ_TOC:
   498 	REQUIRE_DISC();
   499 	length = (cmd[3]<<8) | cmd[4];
   500 	if( length > sizeof(struct gdrom_toc) )
   501 	    length = sizeof(struct gdrom_toc);
   503 	status = gdrom_disc->read_toc( gdrom_disc, data_buffer );
   504 	if( status != PKT_ERR_OK ) {
   505 	    ide_set_packet_result( status );
   506 	} else {
   507 	    ide_start_packet_read( length, 0 );
   508 	}
   509 	break;
   510     case PKT_CMD_SESSION_INFO:
   511 	REQUIRE_DISC();
   512 	length = cmd[4];
   513 	if( length > 6 )
   514 	    length = 6;
   515 	status = gdrom_disc->read_session( gdrom_disc, cmd[2], data_buffer );
   516 	if( status != PKT_ERR_OK ) {
   517 	    ide_set_packet_result( status );
   518 	} else {
   519 	    ide_start_packet_read( length, 0 );
   520 	}
   521 	break;
   522     case PKT_CMD_PLAY_AUDIO:
   523 	REQUIRE_DISC();
   524 	ide_set_packet_result( 0 );
   525 	ide_raise_interrupt();
   526 	idereg.status = 0x50;
   527 	break;
   528     case PKT_CMD_READ_SECTOR:
   529 	REQUIRE_DISC();
   530 	idereg.read_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   531 	idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   532 	idereg.read_mode = cmd[1];
   533 	ide_read_next_sector();
   534 	break;
   535     case PKT_CMD_SPIN_UP:
   536 	REQUIRE_DISC();
   537 	/* do nothing? */
   538 	ide_set_packet_result( PKT_ERR_OK );
   539 	ide_raise_interrupt();
   540 	break;
   541     case PKT_CMD_STATUS:
   542 	REQUIRE_DISC();
   543 	length = cmd[4];
   544 	switch( cmd[1] ) {
   545 	case 0:
   546 	    if( length > sizeof(gdrom_status) ) {
   547 		length = sizeof(gdrom_status);
   548 	    }
   549 	    memcpy( data_buffer, gdrom_status, length );
   550 	    ide_start_packet_read( length, 0 );
   551 	    break;
   552 	case 1:
   553 	    if( length > 14 ) {
   554 		length = 14;
   555 	    }
   556 	    gdrom_disc->read_position( gdrom_disc, idereg.read_lba, data_buffer );
   557 	    data_buffer[0] = 0x00;
   558 	    data_buffer[1] = 0x15; /* audio status ? */
   559 	    data_buffer[2] = 0x00;
   560 	    data_buffer[3] = 0x0E;
   561 	    ide_start_packet_read( length, 0 );
   562 	    break;
   563 	}
   564 	break;
   565     case PKT_CMD_71:
   566 	/* This is a weird one. As far as I can tell it returns random garbage
   567 	 * (and not even the same length each time, never mind the same data).
   568 	 * For sake of something to do, it returns the results from a test dump
   569 	 */
   570 	REQUIRE_DISC();
   571 	memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   572 	ide_start_packet_read( sizeof(gdrom_71), 0 );
   573 	break;
   574     default:
   575 	ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   576 	return;
   577     }
   578 }
.