Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 250:84e056e12a19
prev245:a1d0655a88d3
next254:7c9e34c37670
author nkeynes
date Tue Dec 19 11:58:12 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change Add stub for packet 0x40,0x00 (status of some kind)
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.19 2006-12-19 11:58:12 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 void ide_save_state( FILE *f );
    40 static int ide_load_state( FILE *f );
    41 static void ide_raise_interrupt( void );
    42 static void ide_clear_interrupt( void );
    43 static void ide_packet_command( unsigned char *data );
    45 struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
    46 				       NULL, ide_save_state, ide_load_state };
    48 struct ide_registers idereg;
    49 unsigned char *data_buffer = NULL;
    50 uint32_t data_buffer_len = 0;
    52 #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
    53 #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
    55 /* "\0\0\0\0\xb4\x19\0\0\x08SE      REV 6.42990316" */
    56 unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
    57                        0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
    58                        0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
    59                        0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
    61 unsigned char gdrom_71[] = { 0x3E, 0x0F, 0x90, 0xBE,  0x1D, 0xD9, 0x89, 0x04,  0x28, 0x3A, 0x8E, 0x26,  0x5C, 0x95, 0x10, 0x5A,
    62 				 0x0A, 0x99, 0xEE, 0xFB,  0x69, 0xCE, 0xD9, 0x63,  0x00, 0xF5, 0x0A, 0xBC,  0x2C, 0x0D, 0xF8, 0xE2,
    63 				 0x05, 0x02, 0x00, 0x7C,  0x03, 0x00, 0x3D, 0x08,  0xD8, 0x8D, 0x08, 0x7A,  0x6D, 0x00, 0x35, 0x06,
    64 				 0xBA, 0x66, 0x10, 0x00,  0x91, 0x08, 0x10, 0x29,  0xD0, 0x45, 0xDA, 0x00,  0x2D, 0x05, 0x69, 0x09,
    65 				 0x00, 0x5E, 0x0F, 0x70,  0x86, 0x12, 0x6C, 0x77,  0x5A, 0xFB, 0xCD, 0x56,  0xFB, 0xF7, 0xB7, 0x00,
    66 				 0x5D, 0x07, 0x19, 0x99,  0xF2, 0xAF, 0x00, 0x63,  0x03, 0x00, 0xF0, 0x10,  0xBE, 0xD7, 0xA0, 0x63,
    67 				 0xFA, 0x84, 0xA7, 0x74,  0x94, 0xEF, 0xAD, 0xC2,  0xAC, 0x00, 0x78, 0x07,  0x9F, 0x57, 0x0B, 0x62,
    68 				 0x00, 0xFE, 0x08, 0x08,  0x5D, 0x5A, 0x6A, 0x54,  0x00, 0xE2, 0x09, 0x93,  0x7E, 0x62, 0x2A, 0x5E,
    69 				 0xDA, 0x00, 0x7E, 0x0F,  0xF0, 0x07, 0x01, 0x6D,  0x50, 0x86, 0xDD, 0x4A,  0x15, 0x54, 0xC7, 0xEC,
    70 				 0x00, 0xF2, 0x0B, 0x07,  0xF8, 0x1A, 0xB0, 0x99,  0x3B, 0xF1, 0x36, 0x00,  0x94, 0x07, 0x34, 0xE3,
    71 				 0xBC, 0x6E, 0x00, 0x34,  0x0D, 0x6F, 0xDA, 0xBD,  0xEE, 0xF7, 0xCC, 0xCE,  0x39, 0x7E, 0xE3, 0x00,
    72 				 0x14, 0x08, 0xDC, 0xD2,  0xB9, 0xF9, 0x31, 0x00,  0xB0, 0x0C, 0x10, 0xA3,  0x45, 0x12, 0xC7, 0xCD,
    73 				 0xBF, 0x05, 0x37, 0x00,  0xC4, 0x0D, 0x5F, 0xE0,  0x59, 0xBB, 0x01, 0x59,  0x03, 0xD6, 0x29, 0x9C,
    74 				 0x00, 0x01, 0x0A, 0x09,  0xAA, 0xA8, 0xA8, 0x24,  0x0B, 0x66, 0x00, 0x5C,  0x05, 0xA5, 0xCE, 0x00,
    75 				 0xC1, 0x0B, 0xB7, 0xA0,  0x6F, 0xE9, 0x2B, 0xCC,  0xB5, 0xFC, 0x00, 0x8D,  0x05, 0xF4, 0xAC, 0x00,
    76 				 0x57, 0x04, 0xB6, 0x00,  0xFC, 0x03, 0x00, 0xC3,  0x10, 0x43, 0x3B, 0xBE,  0xA2, 0x96, 0xC3, 0x65,
    77 				 0x9F, 0x9A, 0x88, 0xD5,  0x49, 0x68, 0x00, 0xDC,  0x11, 0x56, 0x23, 0x2D,  0xF9, 0xFC, 0xF5, 0x8B,
    78 				 0x1B, 0xB1, 0xB7, 0x10,  0x21, 0x1C, 0x12, 0x00,  0x0D, 0x0D, 0xEB, 0x86,  0xA2, 0x49, 0x8D, 0x8D,
    79 				 0xBE, 0xA1, 0x6D, 0x53,  0x00, 0xE1, 0x0A, 0x8E,  0x67, 0xAA, 0x16, 0x79,  0x39, 0x59, 0x00, 0x36,
    80 				 0x0B, 0x2A, 0x4E, 0xAE,  0x51, 0x4B, 0xD0, 0x66,  0x33, 0x00, 0x8A, 0x07,  0xCD, 0x6F, 0xBA, 0x92,
    81 				 0x00, 0x1A, 0x0E, 0xDF,  0x4A, 0xB3, 0x77, 0x1F,  0xA5, 0x90, 0x19, 0xFA,  0x59, 0xD7, 0x00, 0x04,
    82 				 0x0F, 0xAC, 0xCA, 0x9F,  0xA4, 0xFC, 0x6D, 0x90,  0x86, 0x9E, 0x1F, 0x44,  0x40, 0x00, 0x9F, 0x04,
    83 				 0x56, 0x00, 0x22, 0x03,  0x00, 0xB8, 0x10, 0x2C,  0x7A, 0x53, 0xA4, 0xBF,  0xA3, 0x90, 0x90, 0x14,
    84 				 0x9D, 0x46, 0x6C, 0x96,  0x00, 0xC6, 0x0B, 0x9B,  0xBB, 0xB0, 0xAE, 0x60,  0x92, 0x8E, 0x0C, 0x00,
    85 				 0x14, 0x06, 0x4B, 0xAE,  0x7F, 0x00, 0x5C, 0x0B,  0x23, 0xFA, 0xE7, 0x51,  0xDA, 0x61, 0x49, 0x5E,
    86 				 0x00, 0xD7, 0x0B, 0x01,  0xFC, 0x55, 0x31, 0x84,  0xC5, 0x0C, 0x98, 0x00,  0x97, 0x50, 0x6E, 0xF9,
    87 				 0xEE, 0x75, 0x92, 0x53,  0xD3, 0x66, 0xA4, 0xAF,  0x3B, 0xFE, 0x7B, 0x27,  0x30, 0xBB, 0xB6, 0xF2,
    88 				 0x76, 0x22, 0x45, 0x42,  0xCA, 0xF9, 0xF0, 0xDE,  0x9F, 0x45, 0x16, 0x68,  0x22, 0xB9, 0x84, 0x28,
    89 				 0x8F, 0x2B, 0xB5, 0x5C,  0xD2, 0xF5, 0x45, 0x36,  0x3E, 0x76, 0xC6, 0xBF,  0x32, 0x5C, 0x41, 0xA6,
    90 				 0x26, 0xC7, 0x82, 0x2F,  0x2E, 0xB5, 0x75, 0xC6,  0xE6, 0x67, 0x9E, 0x77,  0x94, 0xAF, 0x6A, 0x05,
    91 				 0xC0, 0x05, 0x61, 0x71,  0x89, 0x5A, 0xB1, 0xD0,  0xFC, 0x7E, 0xC0, 0x9B,  0xCB, 0x3B, 0x69, 0xD9,
    92 				 0x5F, 0xAF, 0xCA, 0xAB,  0x25, 0xD5, 0xBE, 0x8A,  0x6B, 0xB0, 0xFB, 0x61,  0x6C, 0xEB, 0x85, 0x6E,
    93 				 0x7A, 0x48, 0xFF, 0x97,  0x91, 0x06, 0x3D, 0x4D,  0x68, 0xD3, 0x65, 0x83,  0x90, 0xA0, 0x08, 0x5C,
    94 				 0xFC, 0xEE, 0x7C, 0x33,  0x43, 0x7F, 0x80, 0x52,  0x8B, 0x19, 0x72, 0xF2,  0xC9, 0xAB, 0x93, 0xAF,
    95 				 0x16, 0xED, 0x36, 0x48,  0xAB, 0xC9, 0xD1, 0x03,  0xB3, 0xDC, 0x2F, 0xF2,  0x92, 0x3F, 0x0A, 0x19,
    96 				 0x25, 0xE2, 0xEF, 0x7A,  0x22, 0xDA, 0xDB, 0xCB,  0x32, 0x12, 0x61, 0x49,  0x5B, 0x74, 0x7C, 0x65,
    97 				 0x20, 0x89, 0x54, 0x9E,  0x0E, 0xC9, 0x52, 0xE3,  0xC9, 0x9A, 0x44, 0xC9,  0x5D, 0xA6, 0x77, 0xC0,
    98 				 0xE7, 0x60, 0x91, 0x80,  0x50, 0x1F, 0x33, 0xB1,  0xCD, 0xAD, 0xF4, 0x0D,  0xBB, 0x08, 0xB1, 0xD0,
    99 				 0x13, 0x95, 0xAE, 0xC9,  0xE2, 0x64, 0xA2, 0x65,  0xFB, 0x8F, 0xE9, 0xA2,  0x8A, 0xBC, 0x98, 0x81,
   100 				 0x45, 0xB4, 0x55, 0x4E,  0xB9, 0x74, 0xB4, 0x50,  0x76, 0xBF, 0xF0, 0x45,  0xE7, 0xEE, 0x41, 0x64,
   101 				 0x9F, 0xB5, 0xE0, 0xBB,  0x1C, 0xBB, 0x28, 0x66,  0x1B, 0xDD, 0x2B, 0x02,  0x66, 0xBF, 0xFD, 0x7D,
   102 				 0x37, 0x35, 0x1D, 0x76,  0x21, 0xC3, 0x8F, 0xAF,  0xF6, 0xF9, 0xE9, 0x27,  0x48, 0xE7, 0x3D, 0x95,
   103 				 0x74, 0x0C, 0x77, 0x88,  0x56, 0xD9, 0x84, 0xC8,  0x7D, 0x20, 0x31, 0x43,  0x53, 0xF1, 0xC1, 0xC7,
   104 				 0xC9, 0xF7, 0x5C, 0xC0,  0xA6, 0x5A, 0x27, 0x0A,  0x41, 0xD4, 0x44, 0x94,  0x65, 0x4F, 0xE2, 0x53,
   105 				 0x60, 0x0B, 0xD1, 0x23,  0x6C, 0x0C, 0xBC, 0x70,  0x6C, 0x26, 0x1A, 0x61,  0x1D, 0x35, 0x88, 0xEC,
   106 				 0xB8, 0x15, 0xE3, 0xB4,  0x82, 0xEE, 0xB3, 0x21,  0xAC, 0x6C, 0xB7, 0x33,  0x6D, 0x78, 0x0C, 0x0D,
   107 				 0xB4, 0x0B, 0x29, 0xF2,  0xD4, 0x8C, 0x3F, 0xDD,  0x3F, 0x47, 0xDD, 0xF2,  0xD8, 0x39, 0x57, 0x20,
   108 				 0x28, 0xD8, 0xDD, 0x32,  0xE2, 0x6A, 0x47, 0x53,  0x57, 0xC6, 0xFA, 0x7A,  0x38, 0x30, 0x31, 0x8F,
   109 				 0xE7, 0xD3, 0x84, 0x2B,  0x5D, 0x4F, 0x95, 0x98,  0xED, 0x0B, 0xD7, 0x50,  0x0C, 0x49, 0xDA, 0x59,
   110 				 0x15, 0xF1, 0x39, 0xF3,  0x40, 0xDC, 0xDC, 0x25,  0x24, 0x56, 0x6E, 0xA9,  0x2F, 0xF0, 0x00, 0x00 };
   113 char gdrom_status[] = { 
   114     0x00, 0x15, 0x00, 0x64, 0x00, 0x40, 0x00, 0x00, 
   115     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
   116     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
   117     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
   118     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   119     0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   120     0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   121     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   122     0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
   123     0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   124     0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
   125     0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
   126     0x00, 0x40, 0x00, 0x00 };
   129 static void ide_init( void )
   130 {
   131     ide_reset();
   132     data_buffer_len = DEFAULT_DATA_SECTORS; 
   133     data_buffer = malloc( MAX_SECTOR_SIZE * data_buffer_len ); 
   134     assert( data_buffer != NULL );
   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 = 0x50;
   147     idereg.device = 0x00;
   148     idereg.disc = gdrom_is_mounted() ? (IDE_DISC_CDROM|IDE_DISC_READY) : IDE_DISC_NONE;
   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.last_read_lba = 150;
   155     idereg.last_read_count = 0;
   156 }
   158 static void ide_save_state( FILE *f )
   159 {
   160     fwrite( &idereg, sizeof(idereg), 1, f );
   161     fwrite( &data_buffer_len, sizeof(data_buffer_len), 1, f );
   162     fwrite( data_buffer, MAX_SECTOR_SIZE, data_buffer_len, f );
   163 }
   165 static int ide_load_state( FILE *f )
   166 {
   167     uint32_t length;
   168     fread( &idereg, sizeof(idereg), 1, f );
   169     fread( &length, sizeof(uint32_t), 1, f );
   170     if( length > data_buffer_len ) {
   171 	if( data_buffer != NULL )
   172 	    free( data_buffer );
   173 	data_buffer = malloc( MAX_SECTOR_SIZE * length  );
   174 	assert( data_buffer != NULL );
   175 	data_buffer_len = length;
   176     }
   177     fread( data_buffer, MAX_SECTOR_SIZE, length, 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     if( result != 0 ) {
   190 	idereg.status = 0x51;
   191 	ide_raise_interrupt();
   192     } else {
   193 	idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
   194     }
   195 }
   197 /**
   198  * Begin command packet write to the device. This is always 12 bytes of PIO data
   199  */
   200 static void ide_start_command_packet_write( )
   201 {
   202     idereg.state = IDE_STATE_CMD_WRITE;
   203     idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;
   204     idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
   205     idereg.count = IDE_COUNT_CD;
   206     idereg.data_offset = 0;
   207     idereg.data_length = 12;
   208 }
   210 /**
   211  * Begin PIO read from the device. The data is assumed to already be
   212  * in the buffer at this point.
   213  */
   214 static void ide_start_read( int length, int blocksize, gboolean dma ) 
   215 {
   216     idereg.count = IDE_COUNT_IO;
   217     idereg.data_length = length;
   218     idereg.data_offset = 0;
   219     if( dma ) {
   220 	idereg.state = IDE_STATE_DMA_READ;
   221 	idereg.status = 0xD0;
   222     } else {
   223 	idereg.state = IDE_STATE_PIO_READ;
   224 	idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;
   225 	idereg.lba1 = length & 0xFF;
   226 	idereg.lba2 = (length >> 8) & 0xFF;
   227 	//	idereg.lba1 = blocksize & 0xFF;
   228 	//	idereg.lba2 = blocksize >> 8; 
   229 	idereg.block_length = blocksize;
   230 	idereg.block_left = blocksize;
   231 	ide_raise_interrupt( );
   232     }
   233 }
   235 static void ide_start_packet_read( int length, int blocksize )
   236 {
   237     ide_set_packet_result( PKT_ERR_OK );
   238     ide_start_read( length, blocksize, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   239 }
   241 static void ide_raise_interrupt( void )
   242 {
   243     if( idereg.intrq_pending == 0 ) {
   244 	idereg.intrq_pending = 1;
   245 	if( IS_IDE_IRQ_ENABLED() )
   246 	    asic_event( EVENT_IDE );
   247     }
   248 }
   250 static void ide_clear_interrupt( void ) 
   251 {
   252     if( idereg.intrq_pending != 0 ) {
   253 	idereg.intrq_pending = 0;
   254 	if( IS_IDE_IRQ_ENABLED() )
   255 	    asic_clear_event( EVENT_IDE );
   256     }
   257 }
   259 static void ide_set_error( int error_code )
   260 {
   261     idereg.status = 0x51;
   262     idereg.error = error_code;
   263 }
   265 uint8_t ide_read_status( void ) 
   266 {
   267     if( (idereg.status & IDE_STATUS_BSY) == 0 )
   268 	ide_clear_interrupt();
   269     return idereg.status;
   270 }
   272 uint16_t ide_read_data_pio( void ) {
   273     if( idereg.state == IDE_STATE_PIO_READ ) {
   274 	uint16_t rv = READ_BUFFER();
   275 	idereg.data_offset += 2;
   276 	idereg.block_left -= 2;
   277 	if( idereg.data_offset >= idereg.data_length ) {
   278 	    idereg.state = IDE_STATE_IDLE;
   279 	    idereg.status &= ~IDE_STATUS_DRQ;
   280 	    idereg.data_offset = -1;
   281 	    ide_raise_interrupt();
   282 	} else if( idereg.block_left <= 0 ) {
   283 	    idereg.block_left = idereg.block_length;
   284 	    ide_raise_interrupt();
   285 	}
   286 	return rv;
   287     } else {
   288         return 0xFFFF;
   289     }
   290 }
   293 /**
   294  * DMA read request
   295  *
   296  * This method is called from the ASIC side when a DMA read request is
   297  * initiated. If there is a pending DMA transfer already, we copy the
   298  * data immediately, otherwise we record the DMA buffer for use when we
   299  * get to actually doing the transfer.
   300  * @return number of bytes transfered
   301  */
   302 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
   303 {
   304     if( idereg.state == IDE_STATE_DMA_READ ) {
   305 	int xferlen = length;
   306 	int remaining = idereg.data_length - idereg.data_offset;
   307 	if( xferlen > remaining )
   308 	    xferlen = remaining;
   309 	mem_copy_to_sh4( addr, data_buffer + idereg.data_offset, xferlen );
   310 	idereg.data_offset += xferlen;
   311 	if( idereg.data_offset >= idereg.data_length ) {
   312 	    idereg.data_offset = -1;
   313 	    idereg.state = IDE_STATE_IDLE;
   314 	    idereg.status = 0x50;
   315 	    ide_raise_interrupt();
   316 	    asic_event( EVENT_IDE_DMA );
   317 	}
   318 	return xferlen;
   319     }
   320     return 0;
   321 }
   323 void ide_write_data_pio( uint16_t val ) {
   324     if( idereg.state == IDE_STATE_CMD_WRITE ) {
   325 	WRITE_BUFFER(val);
   326 	idereg.data_offset+=2;
   327 	if( idereg.data_offset >= idereg.data_length ) {
   328 	    idereg.state = IDE_STATE_BUSY;
   329 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   330 	    idereg.data_offset = -1;
   331 	    ide_packet_command(data_buffer);
   332 	}
   333     } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
   334 	WRITE_BUFFER(val);
   335 	if( idereg.data_offset >= idereg.data_length ) {
   336 	    idereg.state = IDE_STATE_BUSY;
   337 	    idereg.data_offset = -1;
   338 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   339 	    /* ??? - no data writes yet anyway */
   340 	}
   341     }
   342 }
   344 void ide_write_control( uint8_t val ) {
   345     if( IS_IDE_IRQ_ENABLED() ) {
   346 	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   347 	    asic_clear_event( EVENT_IDE );
   348     } else {
   349 	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   350 	    asic_event( EVENT_IDE );
   351     }
   352     idereg.control = val;
   353 }
   355 void ide_write_command( uint8_t val ) {
   356     ide_clear_interrupt();
   357     idereg.command = val;
   358     switch( val ) {
   359     case IDE_CMD_NOP: /* Effectively an "abort" */
   360 	idereg.state = IDE_STATE_IDLE;
   361 	idereg.status = 0x51;
   362 	idereg.error = 0x04;
   363 	idereg.data_offset = -1;
   364 	ide_raise_interrupt();
   365 	return;
   366     case IDE_CMD_RESET_DEVICE:
   367 	ide_reset();
   368 	break;
   369     case IDE_CMD_PACKET:
   370 	ide_start_command_packet_write();
   371 	break;
   372     case IDE_CMD_SET_FEATURE:
   373 	switch( idereg.feature ) {
   374 	case IDE_FEAT_SET_TRANSFER_MODE:
   375 	    switch( idereg.count & 0xF8 ) {
   376 	    case IDE_XFER_PIO:
   377 		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   378 		break;
   379 	    case IDE_XFER_PIO_FLOW:
   380 		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   381 		break;
   382 	    case IDE_XFER_MULTI_DMA:
   383 		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   384 		break;
   385 	    case IDE_XFER_ULTRA_DMA:
   386 		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   387 		break;
   388 	    default:
   389 		INFO( "Setting unknown transfer mode: %02X", idereg.count );
   390 		break;
   391 	    }
   392 	    break;
   393 	default:
   394 	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   395 	}
   396 	ide_raise_interrupt( );
   397 	break;
   398     default:
   399 	WARN( "IDE: Unimplemented command: %02X", val );
   400     }
   401     idereg.status = (idereg.status | IDE_STATUS_DRDY | IDE_STATUS_SERV) & (~IDE_STATUS_CHK);
   402 }
   404 /**
   405  * Execute a packet command. This particular method is responsible for parsing
   406  * the command buffers (12 bytes), and generating the appropriate responses, 
   407  * although the actual implementation is mostly delegated to gdrom.c
   408  */
   409 void ide_packet_command( unsigned char *cmd )
   410 {
   411     uint32_t length, datalen;
   412     uint32_t lba, status;
   413     int mode;
   414     int blocksize = idereg.lba1 + (idereg.lba2<<8);
   416     /* Okay we have the packet in the command buffer */
   417     INFO( "ATAPI packet: %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X", 
   418 	  cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
   419 	  cmd[8], cmd[9], cmd[10], cmd[11] );
   420     switch( cmd[0] ) {
   421     case PKT_CMD_TEST_READY:
   422 	if( !gdrom_is_mounted() ) {
   423 	    ide_set_packet_result( PKT_ERR_NODISC );
   424 	} else {
   425 	    ide_set_packet_result( 0 );
   426 	    ide_raise_interrupt();
   427 	    idereg.status = 0x50;
   428 	}
   429 	break;
   430     case PKT_CMD_IDENTIFY:
   431 	lba = cmd[2];
   432 	if( lba >= sizeof(gdrom_ident) ) {
   433 	    ide_set_error(PKT_ERR_BADFIELD);
   434 	} else {
   435 	    length = cmd[4];
   436 	    if( lba+length > sizeof(gdrom_ident) )
   437 		length = sizeof(gdrom_ident) - lba;
   438 	    memcpy( data_buffer, gdrom_ident + lba, length );
   439 	    ide_start_packet_read( length, blocksize );
   440 	}
   441 	break;
   442     case PKT_CMD_SENSE:
   443 	length = cmd[4];
   444 	if( length > 10 )
   445 	    length = 10;
   446 	memcpy( data_buffer, idereg.gdrom_sense, length );
   447 	ide_start_packet_read( length, blocksize );
   448 	break;
   449     case PKT_CMD_READ_TOC:
   450 	length = (cmd[3]<<8) | cmd[4];
   451 	if( length > sizeof(struct gdrom_toc) )
   452 	    length = sizeof(struct gdrom_toc);
   454 	status = gdrom_get_toc( data_buffer );
   455 	if( status != PKT_ERR_OK ) {
   456 	    ide_set_packet_result( status );
   457 	} else {
   458 	    ide_start_packet_read( length, blocksize );
   459 	}
   460 	break;
   461     case PKT_CMD_SESSION_INFO:
   462 	length = cmd[4];
   463 	if( length > 6 )
   464 	    length = 6;
   465 	status = gdrom_get_info( data_buffer, cmd[2] );
   466 	if( status != PKT_ERR_OK ) {
   467 	    ide_set_packet_result( status );
   468 	} else {
   469 	    ide_start_packet_read( length, blocksize );
   470 	}
   471 	break;
   472     case PKT_CMD_PLAY_CD:	    
   473 	ide_set_packet_result( 0 );
   474 	ide_raise_interrupt();
   475 	idereg.status = 0x50;
   476 	break;
   477     case PKT_CMD_READ_SECTOR:
   478 	lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   479 	length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   480 	switch( cmd[1] ) {
   481 	case 0x20: mode = GDROM_MODE1; break;     /* TODO - might be unchecked? */
   482 	case 0x24: mode = GDROM_GD; break;
   483 	case 0x28: mode = GDROM_MODE2_XA1; break; /* ??? */
   484 	case 0x30: mode = GDROM_RAW; break;
   485 	default:
   486 	    ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
   487 	    ide_set_packet_result( PKT_ERR_BADFIELD );
   488 	    return;
   489 	}
   491 	if( length > data_buffer_len ) {
   492 	    do {
   493 		data_buffer_len = data_buffer_len << 1;
   494 	    } while( data_buffer_len < length );
   495 	    data_buffer = realloc( data_buffer, MAX_SECTOR_SIZE * data_buffer_len );
   496 	}
   498 	datalen = data_buffer_len;
   499 	status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );
   500 	if( status != 0 ) {
   501 	    ide_set_packet_result( status );
   502 	    idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;
   503 	    idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;
   504 	    idereg.gdrom_sense[7] = lba & 0xFF;
   505 	} else {
   506 	    idereg.last_read_count += length;
   507 	    idereg.last_read_lba = lba + length;
   508 	    idereg.last_read_track = gdrom_get_track_no_by_lba( idereg.last_read_lba );
   509 	    ide_start_packet_read( datalen, blocksize );
   510 	}
   511 	break;
   512     case PKT_CMD_SPIN_UP:
   513 	/* do nothing? */
   514 	ide_set_packet_result( PKT_ERR_OK );
   515 	ide_raise_interrupt();
   516 	break;
   517     case PKT_CMD_STATUS:
   518 	length = cmd[4];
   519 	if( !gdrom_is_mounted() ) {
   520 	    ide_set_packet_result( PKT_ERR_NODISC );
   521 	} else {
   522 	    switch( cmd[1] ) {
   523 	    case 0:
   524 		if( length > sizeof(gdrom_status) ) {
   525 		    length = sizeof(gdrom_status);
   526 		}
   527 		memcpy( data_buffer, gdrom_status, length );
   528 		ide_start_packet_read( length, blocksize );
   529 		break;
   530 	    case 1:
   531 		if( length > 16 ) {
   532 		    length = 16;
   533 		}
   534 		data_buffer[0] = 0x00;
   535 		data_buffer[1] = 0x15; /* ??? */
   536 		data_buffer[2] = 0x00;
   537 		data_buffer[3] = 0x0E;
   538 		data_buffer[4] = gdrom_get_track(idereg.last_read_track)->flags;
   539 		data_buffer[5] = idereg.last_read_track;
   540 		data_buffer[6] = 0x01; /* ?? */
   541 		data_buffer[7] = (idereg.last_read_count >> 16) & 0xFF;
   542 		data_buffer[8] = (idereg.last_read_count >> 8) & 0xFF;
   543 		data_buffer[9] = idereg.last_read_count & 0xFF;
   544 		data_buffer[10] = (idereg.last_read_lba >> 24) & 0xFF;
   545 		data_buffer[11] = (idereg.last_read_lba >> 16) & 0xFF;
   546 		data_buffer[12] = (idereg.last_read_lba >> 8) & 0xFF;
   547 		data_buffer[13] = idereg.last_read_lba & 0xFF;
   548 		data_buffer[14] = 0x00;
   549 		data_buffer[15] = 0x00;
   550 		ide_start_packet_read( length, blocksize );
   551 		break;
   552 	    }
   553 	}
   554 	break;
   555     case PKT_CMD_71:
   556 	/* This is a weird one. As far as I can tell it returns random garbage
   557 	 * (and not even the same length each time, never mind the same data).
   558 	 * For sake of something to do, it returns the results from a test dump
   559 	 */
   560 	memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   561 	ide_start_packet_read( sizeof(gdrom_71), blocksize );
   562 	break;
   563     default:
   564 	ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   565 	return;
   566     }
   567 }
.