Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 342:850502f0e8de
prev258:8864fae65928
next422:61a0598e07ff
author nkeynes
date Sun Feb 04 11:30:41 2007 +0000 (17 years ago)
permissions -rw-r--r--
last change Fix handling of (some?) v3.0 cdi files
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.23 2007-01-31 10:58:42 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 "asic.h"
    29 #include "gdrom/ide.h"
    30 #include "gdrom/gdrom.h"
    31 #include "gdrom/packet.h"
    33 #define MAX_WRITE_BUF 4096
    34 #define MAX_SECTOR_SIZE 2352 /* Audio sector */
    35 #define DEFAULT_DATA_SECTORS 8
    37 static void ide_init( void );
    38 static void ide_reset( void );
    39 static uint32_t ide_run_slice( uint32_t nanosecs );
    40 static void ide_save_state( FILE *f );
    41 static int ide_load_state( FILE *f );
    42 static void ide_raise_interrupt( void );
    43 static void ide_clear_interrupt( void );
    44 static void ide_packet_command( unsigned char *data );
    45 static void ide_read_next_sector(void);
    47 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, ide_run_slice,
    48 				       NULL, ide_save_state, ide_load_state };
    50 struct ide_registers idereg;
    51 gdrom_disc_t gdrom_disc = NULL;
    53 unsigned char data_buffer[MAX_SECTOR_SIZE];
    55 #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
    56 #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
    58 /* "\0\0\0\0\xb4\x19\0\0\x08SE      REV 6.42990316" */
    59 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
    60                        0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
    61                        0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
    62                        0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
    64 unsigned char gdrom_71[] = { 0x3E, 0x0F, 0x90, 0xBE,  0x1D, 0xD9, 0x89, 0x04,  0x28, 0x3A, 0x8E, 0x26,  0x5C, 0x95, 0x10, 0x5A,
    65 				 0x0A, 0x99, 0xEE, 0xFB,  0x69, 0xCE, 0xD9, 0x63,  0x00, 0xF5, 0x0A, 0xBC,  0x2C, 0x0D, 0xF8, 0xE2,
    66 				 0x05, 0x02, 0x00, 0x7C,  0x03, 0x00, 0x3D, 0x08,  0xD8, 0x8D, 0x08, 0x7A,  0x6D, 0x00, 0x35, 0x06,
    67 				 0xBA, 0x66, 0x10, 0x00,  0x91, 0x08, 0x10, 0x29,  0xD0, 0x45, 0xDA, 0x00,  0x2D, 0x05, 0x69, 0x09,
    68 				 0x00, 0x5E, 0x0F, 0x70,  0x86, 0x12, 0x6C, 0x77,  0x5A, 0xFB, 0xCD, 0x56,  0xFB, 0xF7, 0xB7, 0x00,
    69 				 0x5D, 0x07, 0x19, 0x99,  0xF2, 0xAF, 0x00, 0x63,  0x03, 0x00, 0xF0, 0x10,  0xBE, 0xD7, 0xA0, 0x63,
    70 				 0xFA, 0x84, 0xA7, 0x74,  0x94, 0xEF, 0xAD, 0xC2,  0xAC, 0x00, 0x78, 0x07,  0x9F, 0x57, 0x0B, 0x62,
    71 				 0x00, 0xFE, 0x08, 0x08,  0x5D, 0x5A, 0x6A, 0x54,  0x00, 0xE2, 0x09, 0x93,  0x7E, 0x62, 0x2A, 0x5E,
    72 				 0xDA, 0x00, 0x7E, 0x0F,  0xF0, 0x07, 0x01, 0x6D,  0x50, 0x86, 0xDD, 0x4A,  0x15, 0x54, 0xC7, 0xEC,
    73 				 0x00, 0xF2, 0x0B, 0x07,  0xF8, 0x1A, 0xB0, 0x99,  0x3B, 0xF1, 0x36, 0x00,  0x94, 0x07, 0x34, 0xE3,
    74 				 0xBC, 0x6E, 0x00, 0x34,  0x0D, 0x6F, 0xDA, 0xBD,  0xEE, 0xF7, 0xCC, 0xCE,  0x39, 0x7E, 0xE3, 0x00,
    75 				 0x14, 0x08, 0xDC, 0xD2,  0xB9, 0xF9, 0x31, 0x00,  0xB0, 0x0C, 0x10, 0xA3,  0x45, 0x12, 0xC7, 0xCD,
    76 				 0xBF, 0x05, 0x37, 0x00,  0xC4, 0x0D, 0x5F, 0xE0,  0x59, 0xBB, 0x01, 0x59,  0x03, 0xD6, 0x29, 0x9C,
    77 				 0x00, 0x01, 0x0A, 0x09,  0xAA, 0xA8, 0xA8, 0x24,  0x0B, 0x66, 0x00, 0x5C,  0x05, 0xA5, 0xCE, 0x00,
    78 				 0xC1, 0x0B, 0xB7, 0xA0,  0x6F, 0xE9, 0x2B, 0xCC,  0xB5, 0xFC, 0x00, 0x8D,  0x05, 0xF4, 0xAC, 0x00,
    79 				 0x57, 0x04, 0xB6, 0x00,  0xFC, 0x03, 0x00, 0xC3,  0x10, 0x43, 0x3B, 0xBE,  0xA2, 0x96, 0xC3, 0x65,
    80 				 0x9F, 0x9A, 0x88, 0xD5,  0x49, 0x68, 0x00, 0xDC,  0x11, 0x56, 0x23, 0x2D,  0xF9, 0xFC, 0xF5, 0x8B,
    81 				 0x1B, 0xB1, 0xB7, 0x10,  0x21, 0x1C, 0x12, 0x00,  0x0D, 0x0D, 0xEB, 0x86,  0xA2, 0x49, 0x8D, 0x8D,
    82 				 0xBE, 0xA1, 0x6D, 0x53,  0x00, 0xE1, 0x0A, 0x8E,  0x67, 0xAA, 0x16, 0x79,  0x39, 0x59, 0x00, 0x36,
    83 				 0x0B, 0x2A, 0x4E, 0xAE,  0x51, 0x4B, 0xD0, 0x66,  0x33, 0x00, 0x8A, 0x07,  0xCD, 0x6F, 0xBA, 0x92,
    84 				 0x00, 0x1A, 0x0E, 0xDF,  0x4A, 0xB3, 0x77, 0x1F,  0xA5, 0x90, 0x19, 0xFA,  0x59, 0xD7, 0x00, 0x04,
    85 				 0x0F, 0xAC, 0xCA, 0x9F,  0xA4, 0xFC, 0x6D, 0x90,  0x86, 0x9E, 0x1F, 0x44,  0x40, 0x00, 0x9F, 0x04,
    86 				 0x56, 0x00, 0x22, 0x03,  0x00, 0xB8, 0x10, 0x2C,  0x7A, 0x53, 0xA4, 0xBF,  0xA3, 0x90, 0x90, 0x14,
    87 				 0x9D, 0x46, 0x6C, 0x96,  0x00, 0xC6, 0x0B, 0x9B,  0xBB, 0xB0, 0xAE, 0x60,  0x92, 0x8E, 0x0C, 0x00,
    88 				 0x14, 0x06, 0x4B, 0xAE,  0x7F, 0x00, 0x5C, 0x0B,  0x23, 0xFA, 0xE7, 0x51,  0xDA, 0x61, 0x49, 0x5E,
    89 				 0x00, 0xD7, 0x0B, 0x01,  0xFC, 0x55, 0x31, 0x84,  0xC5, 0x0C, 0x98, 0x00,  0x97, 0x50, 0x6E, 0xF9,
    90 				 0xEE, 0x75, 0x92, 0x53,  0xD3, 0x66, 0xA4, 0xAF,  0x3B, 0xFE, 0x7B, 0x27,  0x30, 0xBB, 0xB6, 0xF2,
    91 				 0x76, 0x22, 0x45, 0x42,  0xCA, 0xF9, 0xF0, 0xDE,  0x9F, 0x45, 0x16, 0x68,  0x22, 0xB9, 0x84, 0x28,
    92 				 0x8F, 0x2B, 0xB5, 0x5C,  0xD2, 0xF5, 0x45, 0x36,  0x3E, 0x76, 0xC6, 0xBF,  0x32, 0x5C, 0x41, 0xA6,
    93 				 0x26, 0xC7, 0x82, 0x2F,  0x2E, 0xB5, 0x75, 0xC6,  0xE6, 0x67, 0x9E, 0x77,  0x94, 0xAF, 0x6A, 0x05,
    94 				 0xC0, 0x05, 0x61, 0x71,  0x89, 0x5A, 0xB1, 0xD0,  0xFC, 0x7E, 0xC0, 0x9B,  0xCB, 0x3B, 0x69, 0xD9,
    95 				 0x5F, 0xAF, 0xCA, 0xAB,  0x25, 0xD5, 0xBE, 0x8A,  0x6B, 0xB0, 0xFB, 0x61,  0x6C, 0xEB, 0x85, 0x6E,
    96 				 0x7A, 0x48, 0xFF, 0x97,  0x91, 0x06, 0x3D, 0x4D,  0x68, 0xD3, 0x65, 0x83,  0x90, 0xA0, 0x08, 0x5C,
    97 				 0xFC, 0xEE, 0x7C, 0x33,  0x43, 0x7F, 0x80, 0x52,  0x8B, 0x19, 0x72, 0xF2,  0xC9, 0xAB, 0x93, 0xAF,
    98 				 0x16, 0xED, 0x36, 0x48,  0xAB, 0xC9, 0xD1, 0x03,  0xB3, 0xDC, 0x2F, 0xF2,  0x92, 0x3F, 0x0A, 0x19,
    99 				 0x25, 0xE2, 0xEF, 0x7A,  0x22, 0xDA, 0xDB, 0xCB,  0x32, 0x12, 0x61, 0x49,  0x5B, 0x74, 0x7C, 0x65,
   100 				 0x20, 0x89, 0x54, 0x9E,  0x0E, 0xC9, 0x52, 0xE3,  0xC9, 0x9A, 0x44, 0xC9,  0x5D, 0xA6, 0x77, 0xC0,
   101 				 0xE7, 0x60, 0x91, 0x80,  0x50, 0x1F, 0x33, 0xB1,  0xCD, 0xAD, 0xF4, 0x0D,  0xBB, 0x08, 0xB1, 0xD0,
   102 				 0x13, 0x95, 0xAE, 0xC9,  0xE2, 0x64, 0xA2, 0x65,  0xFB, 0x8F, 0xE9, 0xA2,  0x8A, 0xBC, 0x98, 0x81,
   103 				 0x45, 0xB4, 0x55, 0x4E,  0xB9, 0x74, 0xB4, 0x50,  0x76, 0xBF, 0xF0, 0x45,  0xE7, 0xEE, 0x41, 0x64,
   104 				 0x9F, 0xB5, 0xE0, 0xBB,  0x1C, 0xBB, 0x28, 0x66,  0x1B, 0xDD, 0x2B, 0x02,  0x66, 0xBF, 0xFD, 0x7D,
   105 				 0x37, 0x35, 0x1D, 0x76,  0x21, 0xC3, 0x8F, 0xAF,  0xF6, 0xF9, 0xE9, 0x27,  0x48, 0xE7, 0x3D, 0x95,
   106 				 0x74, 0x0C, 0x77, 0x88,  0x56, 0xD9, 0x84, 0xC8,  0x7D, 0x20, 0x31, 0x43,  0x53, 0xF1, 0xC1, 0xC7,
   107 				 0xC9, 0xF7, 0x5C, 0xC0,  0xA6, 0x5A, 0x27, 0x0A,  0x41, 0xD4, 0x44, 0x94,  0x65, 0x4F, 0xE2, 0x53,
   108 				 0x60, 0x0B, 0xD1, 0x23,  0x6C, 0x0C, 0xBC, 0x70,  0x6C, 0x26, 0x1A, 0x61,  0x1D, 0x35, 0x88, 0xEC,
   109 				 0xB8, 0x15, 0xE3, 0xB4,  0x82, 0xEE, 0xB3, 0x21,  0xAC, 0x6C, 0xB7, 0x33,  0x6D, 0x78, 0x0C, 0x0D,
   110 				 0xB4, 0x0B, 0x29, 0xF2,  0xD4, 0x8C, 0x3F, 0xDD,  0x3F, 0x47, 0xDD, 0xF2,  0xD8, 0x39, 0x57, 0x20,
   111 				 0x28, 0xD8, 0xDD, 0x32,  0xE2, 0x6A, 0x47, 0x53,  0x57, 0xC6, 0xFA, 0x7A,  0x38, 0x30, 0x31, 0x8F,
   112 				 0xE7, 0xD3, 0x84, 0x2B,  0x5D, 0x4F, 0x95, 0x98,  0xED, 0x0B, 0xD7, 0x50,  0x0C, 0x49, 0xDA, 0x59,
   113 				 0x15, 0xF1, 0x39, 0xF3,  0x40, 0xDC, 0xDC, 0x25,  0x24, 0x56, 0x6E, 0xA9,  0x2F, 0xF0, 0x00, 0x00 };
   116 char gdrom_status[] = { 
   117     0x00, 0x15, 0x00, 0x64, 0x00, 0x40, 0x00, 0x00, 
   118     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
   119     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
   120     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
   121     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   122     0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   123     0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   124     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   125     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
   126     0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   127     0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
   128     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
   129     0x00, 0x40, 0x00, 0x00 };
   132 static void ide_init( void )
   133 {
   134     ide_reset();
   135 }
   137 static void ide_reset( void )
   138 {
   139     ide_clear_interrupt();
   140     idereg.error = 0x01;
   141     idereg.count = 0x01;
   142     idereg.lba0 = /* 0x21; */ 0x81;
   143     idereg.lba1 = 0x14;
   144     idereg.lba2 = 0xeb;
   145     idereg.feature = 0; /* Indeterminate really */
   146     idereg.status = 0x00;
   147     idereg.device = 0x00;
   148     idereg.state = IDE_STATE_IDLE;
   149     memset( idereg.gdrom_sense, '\0', 10 );
   150     idereg.data_offset = -1;
   151     idereg.data_length = -1;
   152     idereg.last_read_track = 1;
   153     idereg.read_lba = 150;
   154     idereg.read_mode = 0x28;
   155     idereg.sectors_left = 0;
   156     idereg.was_reset = TRUE;
   157 }
   159 static uint32_t ide_run_slice( uint32_t nanosecs )
   160 {
   161     if( gdrom_disc != NULL && gdrom_disc->run_time_slice != NULL ) {
   162 	gdrom_disc->run_time_slice(gdrom_disc, nanosecs);
   163     }
   164     return nanosecs;
   165 }
   167 static void ide_save_state( FILE *f )
   168 {
   169     fwrite( &idereg, sizeof(idereg), 1, f );
   170     fwrite( data_buffer, MAX_SECTOR_SIZE, 1, f );
   171 }
   173 static int ide_load_state( FILE *f )
   174 {
   175     uint32_t length;
   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, 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     int 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, datalen;
   458     uint32_t lba, status;
   459     int mode;
   461     /* Okay we have the packet in the command buffer */
   462     INFO( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   463 	  cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   464 	  cmd[8], cmd[9], cmd[10], cmd[11] );
   466     if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
   467 	ide_set_packet_result( PKT_ERR_RESET );
   468 	idereg.was_reset = FALSE;
   469 	return;
   470     }
   472     switch( cmd[0] ) {
   473     case PKT_CMD_TEST_READY:
   474 	REQUIRE_DISC();
   475 	ide_set_packet_result( 0 );
   476 	ide_raise_interrupt();
   477 	idereg.status = 0x50;
   478 	break;
   479     case PKT_CMD_IDENTIFY:
   480 	lba = cmd[2];
   481 	if( lba >= sizeof(gdrom_ident) ) {
   482 	    ide_set_error(PKT_ERR_BADFIELD);
   483 	} else {
   484 	    length = cmd[4];
   485 	    if( lba+length > sizeof(gdrom_ident) )
   486 		length = sizeof(gdrom_ident) - lba;
   487 	    memcpy( data_buffer, gdrom_ident + lba, length );
   488 	    ide_start_packet_read( length, 0 );
   489 	}
   490 	break;
   491     case PKT_CMD_SENSE:
   492 	length = cmd[4];
   493 	if( length > 10 )
   494 	    length = 10;
   495 	memcpy( data_buffer, idereg.gdrom_sense, length );
   496 	ide_start_packet_read( length, 0 );
   497 	break;
   498     case PKT_CMD_READ_TOC:
   499 	REQUIRE_DISC();
   500 	length = (cmd[3]<<8) | cmd[4];
   501 	if( length > sizeof(struct gdrom_toc) )
   502 	    length = sizeof(struct gdrom_toc);
   504 	status = gdrom_disc->read_toc( gdrom_disc, data_buffer );
   505 	if( status != PKT_ERR_OK ) {
   506 	    ide_set_packet_result( status );
   507 	} else {
   508 	    ide_start_packet_read( length, 0 );
   509 	}
   510 	break;
   511     case PKT_CMD_SESSION_INFO:
   512 	REQUIRE_DISC();
   513 	length = cmd[4];
   514 	if( length > 6 )
   515 	    length = 6;
   516 	status = gdrom_disc->read_session( gdrom_disc, cmd[2], data_buffer );
   517 	if( status != PKT_ERR_OK ) {
   518 	    ide_set_packet_result( status );
   519 	} else {
   520 	    ide_start_packet_read( length, 0 );
   521 	}
   522 	break;
   523     case PKT_CMD_PLAY_AUDIO:
   524 	REQUIRE_DISC();
   525 	ide_set_packet_result( 0 );
   526 	ide_raise_interrupt();
   527 	idereg.status = 0x50;
   528 	break;
   529     case PKT_CMD_READ_SECTOR:
   530 	REQUIRE_DISC();
   531 	idereg.read_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   532 	idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   533 	idereg.read_mode = cmd[1];
   534 	ide_read_next_sector();
   535 	break;
   536     case PKT_CMD_SPIN_UP:
   537 	REQUIRE_DISC();
   538 	/* do nothing? */
   539 	ide_set_packet_result( PKT_ERR_OK );
   540 	ide_raise_interrupt();
   541 	break;
   542     case PKT_CMD_STATUS:
   543 	REQUIRE_DISC();
   544 	length = cmd[4];
   545 	switch( cmd[1] ) {
   546 	case 0:
   547 	    if( length > sizeof(gdrom_status) ) {
   548 		length = sizeof(gdrom_status);
   549 	    }
   550 	    memcpy( data_buffer, gdrom_status, length );
   551 	    ide_start_packet_read( length, 0 );
   552 	    break;
   553 	case 1:
   554 	    if( length > 14 ) {
   555 		length = 14;
   556 	    }
   557 	    gdrom_disc->read_position( gdrom_disc, idereg.read_lba, data_buffer );
   558 	    data_buffer[0] = 0x00;
   559 	    data_buffer[1] = 0x15; /* audio status ? */
   560 	    data_buffer[2] = 0x00;
   561 	    data_buffer[3] = 0x0E;
   562 	    ide_start_packet_read( length, 0 );
   563 	    break;
   564 	}
   565 	break;
   566     case PKT_CMD_71:
   567 	/* This is a weird one. As far as I can tell it returns random garbage
   568 	 * (and not even the same length each time, never mind the same data).
   569 	 * For sake of something to do, it returns the results from a test dump
   570 	 */
   571 	REQUIRE_DISC();
   572 	memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   573 	ide_start_packet_read( sizeof(gdrom_71), 0 );
   574 	break;
   575     default:
   576 	ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   577 	return;
   578     }
   579 }
.