Search
lxdream.org :: lxdream/src/gdrom/ide.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/gdrom/ide.c
changeset 158:a0a82246b44e
prev152:d42a4c5cc709
next166:8aa70cf503a2
author nkeynes
date Thu Jun 15 10:32:42 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change Fix IDE DMA to actually work for real.
Implement the mystery packet 0x71 by cribbing a block of data from the dc.
view annotate diff log raw
     1 /**
     2  * $Id: ide.c,v 1.15 2006-06-15 10:32: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 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 static void ide_init( void )
   114 {
   115     ide_reset();
   116     data_buffer_len = DEFAULT_DATA_SECTORS; 
   117     data_buffer = malloc( MAX_SECTOR_SIZE * data_buffer_len ); 
   118     assert( data_buffer != NULL );
   119 }
   121 static void ide_reset( void )
   122 {
   123     ide_clear_interrupt();
   124     idereg.error = 0x01;
   125     idereg.count = 0x01;
   126     idereg.lba0 = /* 0x21; */ 0x81;
   127     idereg.lba1 = 0x14;
   128     idereg.lba2 = 0xeb;
   129     idereg.feature = 0; /* Indeterminate really */
   130     idereg.status = 0x50;
   131     idereg.device = 0x00;
   132     idereg.disc = gdrom_is_mounted() ? (IDE_DISC_CDROM|IDE_DISC_READY) : IDE_DISC_NONE;
   133     idereg.state = IDE_STATE_IDLE;
   134     memset( idereg.gdrom_sense, '\0', 10 );
   135     idereg.data_offset = -1;
   136     idereg.data_length = -1;
   137 }
   139 static void ide_save_state( FILE *f )
   140 {
   141     fwrite( &idereg, sizeof(idereg), 1, f );
   142     fwrite( &data_buffer_len, sizeof(data_buffer_len), 1, f );
   143     fwrite( data_buffer, MAX_SECTOR_SIZE, data_buffer_len, f );
   144 }
   146 static int ide_load_state( FILE *f )
   147 {
   148     uint32_t length;
   149     fread( &idereg, sizeof(idereg), 1, f );
   150     fread( &length, sizeof(uint32_t), 1, f );
   151     if( length > data_buffer_len ) {
   152 	if( data_buffer != NULL )
   153 	    free( data_buffer );
   154 	data_buffer = malloc( MAX_SECTOR_SIZE * length  );
   155 	assert( data_buffer != NULL );
   156 	data_buffer_len = length;
   157     }
   158     fread( data_buffer, MAX_SECTOR_SIZE, length, f );
   159     return 0;
   160 }
   162 /************************ State transitions *************************/
   164 void ide_set_packet_result( uint16_t result )
   165 {
   166     idereg.gdrom_sense[0] = 0xf0;
   167     idereg.gdrom_sense[2] = result & 0xFF;
   168     idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
   169     idereg.error = (result & 0x0F) << 4;
   170     if( result != 0 ) {
   171 	idereg.status = 0x51;
   172 	ide_raise_interrupt();
   173     } else {
   174 	idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
   175     }
   176 }
   178 /**
   179  * Begin command packet write to the device. This is always 12 bytes of PIO data
   180  */
   181 static void ide_start_command_packet_write( )
   182 {
   183     idereg.state = IDE_STATE_CMD_WRITE;
   184     idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;
   185     idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
   186     idereg.count = IDE_COUNT_CD;
   187     idereg.data_offset = 0;
   188     idereg.data_length = 12;
   189 }
   191 /**
   192  * Begin PIO read from the device. The data is assumed to already be
   193  * in the buffer at this point.
   194  */
   195 static void ide_start_read( int length, int blocksize, gboolean dma ) 
   196 {
   197     idereg.count = IDE_COUNT_IO;
   198     idereg.data_length = length;
   199     idereg.data_offset = 0;
   200     if( dma ) {
   201 	idereg.state = IDE_STATE_DMA_READ;
   202 	idereg.status = 0xD0;
   203     } else {
   204 	idereg.state = IDE_STATE_PIO_READ;
   205 	idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;
   206 	idereg.lba1 = length & 0xFF;
   207 	idereg.lba2 = (length >> 8) & 0xFF;
   208 	//	idereg.lba1 = blocksize & 0xFF;
   209 	//	idereg.lba2 = blocksize >> 8; 
   210 	idereg.block_length = blocksize;
   211 	idereg.block_left = blocksize;
   212 	ide_raise_interrupt( );
   213     }
   214 }
   216 static void ide_start_packet_read( int length, int blocksize )
   217 {
   218     ide_set_packet_result( PKT_ERR_OK );
   219     ide_start_read( length, blocksize, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
   220 }
   222 static void ide_raise_interrupt( void )
   223 {
   224     if( idereg.intrq_pending == 0 ) {
   225 	idereg.intrq_pending = 1;
   226 	if( IS_IDE_IRQ_ENABLED() )
   227 	    asic_event( EVENT_IDE );
   228     }
   229 }
   231 static void ide_clear_interrupt( void ) 
   232 {
   233     if( idereg.intrq_pending != 0 ) {
   234 	idereg.intrq_pending = 0;
   235 	if( IS_IDE_IRQ_ENABLED() )
   236 	    asic_clear_event( EVENT_IDE );
   237     }
   238 }
   240 static void ide_set_error( int error_code )
   241 {
   242     idereg.status = 0x51;
   243     idereg.error = error_code;
   244 }
   246 uint8_t ide_read_status( void ) 
   247 {
   248     if( (idereg.status & IDE_STATUS_BSY) == 0 )
   249 	ide_clear_interrupt();
   250     return idereg.status;
   251 }
   253 uint16_t ide_read_data_pio( void ) {
   254     if( idereg.state == IDE_STATE_PIO_READ ) {
   255 	uint16_t rv = READ_BUFFER();
   256 	idereg.data_offset += 2;
   257 	idereg.block_left -= 2;
   258 	if( idereg.data_offset >= idereg.data_length ) {
   259 	    idereg.state = IDE_STATE_IDLE;
   260 	    idereg.status &= ~IDE_STATUS_DRQ;
   261 	    idereg.data_offset = -1;
   262 	    ide_raise_interrupt();
   263 	} else if( idereg.block_left <= 0 ) {
   264 	    idereg.block_left = idereg.block_length;
   265 	    ide_raise_interrupt();
   266 	}
   267 	return rv;
   268     } else {
   269         return 0xFFFF;
   270     }
   271 }
   274 /**
   275  * DMA read request
   276  *
   277  * This method is called from the ASIC side when a DMA read request is
   278  * initiated. If there is a pending DMA transfer already, we copy the
   279  * data immediately, otherwise we record the DMA buffer for use when we
   280  * get to actually doing the transfer.
   281  * @return number of bytes transfered
   282  */
   283 uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
   284 {
   285     if( idereg.state == IDE_STATE_DMA_READ ) {
   286 	int xferlen = length;
   287 	int remaining = idereg.data_length - idereg.data_offset;
   288 	if( xferlen > remaining )
   289 	    xferlen = remaining;
   290 	mem_copy_to_sh4( addr, data_buffer + idereg.data_offset, xferlen );
   291 	idereg.data_offset += xferlen;
   292 	if( idereg.data_offset >= idereg.data_length ) {
   293 	    idereg.data_offset = -1;
   294 	    idereg.state = IDE_STATE_IDLE;
   295 	    idereg.status = 0x50;
   296 	    ide_raise_interrupt();
   297 	    asic_event( EVENT_IDE_DMA );
   298 	}
   299 	return xferlen;
   300     }
   301     return 0;
   302 }
   304 void ide_write_data_pio( uint16_t val ) {
   305     if( idereg.state == IDE_STATE_CMD_WRITE ) {
   306 	WRITE_BUFFER(val);
   307 	idereg.data_offset+=2;
   308 	if( idereg.data_offset >= idereg.data_length ) {
   309 	    idereg.state = IDE_STATE_BUSY;
   310 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   311 	    idereg.data_offset = -1;
   312 	    ide_packet_command(data_buffer);
   313 	}
   314     } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
   315 	WRITE_BUFFER(val);
   316 	if( idereg.data_offset >= idereg.data_length ) {
   317 	    idereg.state = IDE_STATE_BUSY;
   318 	    idereg.data_offset = -1;
   319 	    idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
   320 	    /* ??? - no data writes yet anyway */
   321 	}
   322     }
   323 }
   325 void ide_write_control( uint8_t val ) {
   326     if( IS_IDE_IRQ_ENABLED() ) {
   327 	if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
   328 	    asic_clear_event( EVENT_IDE );
   329     } else {
   330 	if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
   331 	    asic_event( EVENT_IDE );
   332     }
   333     idereg.control = val;
   334 }
   336 void ide_write_command( uint8_t val ) {
   337     ide_clear_interrupt();
   338     idereg.command = val;
   339     switch( val ) {
   340     case IDE_CMD_RESET_DEVICE:
   341 	ide_reset();
   342 	break;
   343     case IDE_CMD_PACKET:
   344 	ide_start_command_packet_write();
   345 	break;
   346     case IDE_CMD_SET_FEATURE:
   347 	switch( idereg.feature ) {
   348 	case IDE_FEAT_SET_TRANSFER_MODE:
   349 	    switch( idereg.count & 0xF8 ) {
   350 	    case IDE_XFER_PIO:
   351 		INFO( "Set PIO default mode: %d", idereg.count&0x07 );
   352 		break;
   353 	    case IDE_XFER_PIO_FLOW:
   354 		INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
   355 		break;
   356 	    case IDE_XFER_MULTI_DMA:
   357 		INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
   358 		break;
   359 	    case IDE_XFER_ULTRA_DMA:
   360 		INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
   361 		break;
   362 	    default:
   363 		INFO( "Setting unknown transfer mode: %02X", idereg.count );
   364 		break;
   365 	    }
   366 	    break;
   367 	default:
   368 	    WARN( "IDE: unimplemented feature: %02X", idereg.feature );
   369 	}
   370 	ide_raise_interrupt( );
   371 	break;
   372     default:
   373 	WARN( "IDE: Unimplemented command: %02X", val );
   374     }
   375     idereg.status = (idereg.status | IDE_STATUS_DRDY | IDE_STATUS_SERV) & (~IDE_STATUS_CHK);
   376 }
   378 /**
   379  * Execute a packet command. This particular method is responsible for parsing
   380  * the command buffers (12 bytes), and generating the appropriate responses, 
   381  * although the actual implementation is mostly delegated to gdrom.c
   382  */
   383 void ide_packet_command( unsigned char *cmd )
   384 {
   385     uint32_t length, datalen;
   386     uint32_t lba, status;
   387     int mode;
   388     int blocksize = idereg.lba1 + (idereg.lba2<<8);
   390     /* Okay we have the packet in the command buffer */
   391     WARN( "ATAPI: Received Packet command: %02X", cmd[0] );
   392     fwrite_dump( (unsigned char *)cmd, 12, stderr );
   393     //    fprint_stack_trace( stderr );
   394     switch( cmd[0] ) {
   395     case PKT_CMD_TEST_READY:
   396 	if( !gdrom_is_mounted() ) {
   397 	    ide_set_packet_result( PKT_ERR_NODISC );
   398 	} else {
   399 	    ide_set_packet_result( 0 );
   400 	    ide_raise_interrupt();
   401 	    idereg.status = 0x50;
   402 	}
   403 	break;
   404     case PKT_CMD_IDENTIFY:
   405 	lba = cmd[2];
   406 	if( lba >= sizeof(gdrom_ident) ) {
   407 	    ide_set_error(PKT_ERR_BADFIELD);
   408 	} else {
   409 	    length = cmd[4];
   410 	    if( lba+length > sizeof(gdrom_ident) )
   411 		length = sizeof(gdrom_ident) - lba;
   412 	    memcpy( data_buffer, gdrom_ident + lba, length );
   413 	    ide_start_packet_read( length, blocksize );
   414 	}
   415 	break;
   416     case PKT_CMD_SENSE:
   417 	length = cmd[4];
   418 	if( length > 10 )
   419 	    length = 10;
   420 	memcpy( data_buffer, idereg.gdrom_sense, length );
   421 	ide_start_packet_read( length, blocksize );
   422 	break;
   423     case PKT_CMD_READ_TOC:
   424 	length = (cmd[3]<<8) | cmd[4];
   425 	if( length > sizeof(struct gdrom_toc) )
   426 	    length = sizeof(struct gdrom_toc);
   428 	status = gdrom_get_toc( data_buffer );
   429 	if( status != PKT_ERR_OK ) {
   430 	    ide_set_packet_result( status );
   431 	} else {
   432 	    ide_start_packet_read( length, blocksize );
   433 	}
   434 	break;
   435     case PKT_CMD_SESSION_INFO:
   436 	length = cmd[4];
   437 	if( length > 6 )
   438 	    length = 6;
   439 	status = gdrom_get_info( data_buffer, cmd[2] );
   440 	if( status != PKT_ERR_OK ) {
   441 	    ide_set_packet_result( status );
   442 	} else {
   443 	    ide_start_packet_read( length, blocksize );
   444 	}
   445 	break;
   446     case PKT_CMD_READ_SECTOR:
   447 	lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
   448 	length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
   449 	switch( cmd[1] ) {
   450 	case 0x20: mode = GDROM_MODE1; break;
   451 	case 0x24: mode = GDROM_GD; break;
   452 	case 0x28: mode = GDROM_MODE1; break; /* ??? */
   453 	case 0x30: mode = GDROM_RAW; break;
   454 	default:
   455 	    ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
   456 	    ide_set_packet_result( PKT_ERR_BADFIELD );
   457 	    return;
   458 	}
   460 	if( length > data_buffer_len ) {
   461 	    do {
   462 		data_buffer_len = data_buffer_len << 1;
   463 	    } while( data_buffer_len < length );
   464 	    data_buffer = realloc( data_buffer, MAX_SECTOR_SIZE * data_buffer_len );
   465 	}
   467 	datalen = data_buffer_len;
   468 	status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );
   469 	if( status != 0 ) {
   470 	    ide_set_packet_result( status );
   471 	    idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;
   472 	    idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;
   473 	    idereg.gdrom_sense[7] = lba & 0xFF;
   474 	} else {
   475 	    ide_start_packet_read( datalen, blocksize );
   476 	}
   477 	break;
   478     case PKT_CMD_SPIN_UP:
   479 	/* do nothing? */
   480 	ide_set_packet_result( PKT_ERR_OK );
   481 	ide_raise_interrupt();
   482 	break;
   483     case PKT_CMD_71:
   484 	/* This is a weird one. As far as I can tell it returns random garbage
   485 	 * (and not even the same length each time, never mind the same data).
   486 	 * For sake of something to do, it returns the results from a test dump
   487 	 */
   488 	memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
   489 	ide_start_packet_read( sizeof(gdrom_71), blocksize );
   490 	break;
   491     default:
   492 	ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
   493 	return;
   494     }
   495 }
.