nkeynes@31 | 1 | /**
|
nkeynes@152 | 2 | * $Id: ide.c,v 1.14 2006-05-23 13:11:45 nkeynes Exp $
|
nkeynes@2 | 3 | *
|
nkeynes@31 | 4 | * IDE interface implementation
|
nkeynes@31 | 5 | *
|
nkeynes@152 | 6 | *
|
nkeynes@152 | 7 | * Note: All references to read/write are from the host's point of view.
|
nkeynes@152 | 8 | *
|
nkeynes@152 | 9 | * See: INF-8020
|
nkeynes@31 | 10 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@31 | 11 | *
|
nkeynes@31 | 12 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@31 | 13 | * it under the terms of the GNU General Public License as published by
|
nkeynes@31 | 14 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@31 | 15 | * (at your option) any later version.
|
nkeynes@31 | 16 | *
|
nkeynes@31 | 17 | * This program is distributed in the hope that it will be useful,
|
nkeynes@31 | 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@31 | 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@31 | 20 | * GNU General Public License for more details.
|
nkeynes@2 | 21 | */
|
nkeynes@35 | 22 |
|
nkeynes@35 | 23 | #define MODULE ide_module
|
nkeynes@35 | 24 |
|
nkeynes@138 | 25 | #include <assert.h>
|
nkeynes@2 | 26 | #include <stdlib.h>
|
nkeynes@35 | 27 | #include "dream.h"
|
nkeynes@125 | 28 | #include "asic.h"
|
nkeynes@39 | 29 | #include "gdrom/ide.h"
|
nkeynes@125 | 30 | #include "gdrom/gdrom.h"
|
nkeynes@142 | 31 | #include "gdrom/packet.h"
|
nkeynes@2 | 32 |
|
nkeynes@138 | 33 | #define MAX_WRITE_BUF 4096
|
nkeynes@138 | 34 | #define MAX_SECTOR_SIZE 2352 /* Audio sector */
|
nkeynes@138 | 35 | #define DEFAULT_DATA_SECTORS 8
|
nkeynes@2 | 36 |
|
nkeynes@138 | 37 | static void ide_init( void );
|
nkeynes@138 | 38 | static void ide_reset( void );
|
nkeynes@138 | 39 | static void ide_save_state( FILE *f );
|
nkeynes@138 | 40 | static int ide_load_state( FILE *f );
|
nkeynes@138 | 41 | static void ide_raise_interrupt( void );
|
nkeynes@138 | 42 | static void ide_clear_interrupt( void );
|
nkeynes@152 | 43 | static void ide_packet_command( unsigned char *data );
|
nkeynes@15 | 44 |
|
nkeynes@15 | 45 | struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL,
|
nkeynes@138 | 46 | NULL, ide_save_state, ide_load_state };
|
nkeynes@15 | 47 |
|
nkeynes@2 | 48 | struct ide_registers idereg;
|
nkeynes@138 | 49 | unsigned char *data_buffer = NULL;
|
nkeynes@138 | 50 | uint32_t data_buffer_len = 0;
|
nkeynes@2 | 51 |
|
nkeynes@152 | 52 | #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
|
nkeynes@152 | 53 | #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
|
nkeynes@152 | 54 |
|
nkeynes@2 | 55 | /* "\0\0\0\0\xb4\x19\0\0\x08SE REV 6.42990316" */
|
nkeynes@125 | 56 | unsigned char gdrom_ident[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00,
|
nkeynes@2 | 57 | 0x00, 0x08, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20,
|
nkeynes@2 | 58 | 0x20, 0x20, 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e,
|
nkeynes@2 | 59 | 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
|
nkeynes@2 | 60 |
|
nkeynes@2 | 61 |
|
nkeynes@138 | 62 | static void ide_init( void )
|
nkeynes@138 | 63 | {
|
nkeynes@138 | 64 | ide_reset();
|
nkeynes@138 | 65 | data_buffer_len = DEFAULT_DATA_SECTORS;
|
nkeynes@138 | 66 | data_buffer = malloc( MAX_SECTOR_SIZE * data_buffer_len );
|
nkeynes@138 | 67 | assert( data_buffer != NULL );
|
nkeynes@138 | 68 | }
|
nkeynes@138 | 69 |
|
nkeynes@138 | 70 | static void ide_reset( void )
|
nkeynes@138 | 71 | {
|
nkeynes@138 | 72 | ide_clear_interrupt();
|
nkeynes@138 | 73 | idereg.error = 0x01;
|
nkeynes@138 | 74 | idereg.count = 0x01;
|
nkeynes@138 | 75 | idereg.lba0 = /* 0x21; */ 0x81;
|
nkeynes@138 | 76 | idereg.lba1 = 0x14;
|
nkeynes@138 | 77 | idereg.lba2 = 0xeb;
|
nkeynes@138 | 78 | idereg.feature = 0; /* Indeterminate really */
|
nkeynes@138 | 79 | idereg.status = 0x00;
|
nkeynes@138 | 80 | idereg.device = 0x00;
|
nkeynes@143 | 81 | idereg.disc = gdrom_is_mounted() ? (IDE_DISC_CDROM|IDE_DISC_READY) : IDE_DISC_NONE;
|
nkeynes@152 | 82 | idereg.state = IDE_STATE_IDLE;
|
nkeynes@152 | 83 | memset( idereg.gdrom_sense, '\0', 10 );
|
nkeynes@152 | 84 | idereg.data_offset = -1;
|
nkeynes@152 | 85 | idereg.data_length = -1;
|
nkeynes@138 | 86 | }
|
nkeynes@138 | 87 |
|
nkeynes@138 | 88 | static void ide_save_state( FILE *f )
|
nkeynes@138 | 89 | {
|
nkeynes@152 | 90 | fwrite( &idereg, sizeof(idereg), 1, f );
|
nkeynes@152 | 91 | fwrite( &data_buffer_len, sizeof(data_buffer_len), 1, f );
|
nkeynes@152 | 92 | fwrite( data_buffer, data_buffer_len, 1, f );
|
nkeynes@138 | 93 | }
|
nkeynes@138 | 94 |
|
nkeynes@138 | 95 | static int ide_load_state( FILE *f )
|
nkeynes@138 | 96 | {
|
nkeynes@152 | 97 | uint32_t length;
|
nkeynes@152 | 98 | fread( &idereg, sizeof(idereg), 1, f );
|
nkeynes@152 | 99 | fread( &length, sizeof(uint32_t), 1, f );
|
nkeynes@152 | 100 | if( length > data_buffer_len ) {
|
nkeynes@152 | 101 | if( data_buffer != NULL )
|
nkeynes@152 | 102 | free( data_buffer );
|
nkeynes@152 | 103 | data_buffer = malloc( length );
|
nkeynes@152 | 104 | assert( data_buffer != NULL );
|
nkeynes@152 | 105 | data_buffer_len = length;
|
nkeynes@152 | 106 | }
|
nkeynes@152 | 107 | fread( data_buffer, length, 1, f );
|
nkeynes@138 | 108 | return 0;
|
nkeynes@138 | 109 | }
|
nkeynes@125 | 110 |
|
nkeynes@152 | 111 | /************************ State transitions *************************/
|
nkeynes@152 | 112 |
|
nkeynes@152 | 113 | /**
|
nkeynes@152 | 114 | * Begin command packet write to the device. This is always 12 bytes of PIO data
|
nkeynes@152 | 115 | */
|
nkeynes@152 | 116 | static void ide_start_command_packet_write( )
|
nkeynes@2 | 117 | {
|
nkeynes@152 | 118 | idereg.state = IDE_STATE_CMD_WRITE;
|
nkeynes@152 | 119 | idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;
|
nkeynes@152 | 120 | idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
|
nkeynes@152 | 121 | idereg.count = IDE_COUNT_CD;
|
nkeynes@152 | 122 | idereg.data_offset = 0;
|
nkeynes@152 | 123 | idereg.data_length = 12;
|
nkeynes@2 | 124 | }
|
nkeynes@2 | 125 |
|
nkeynes@152 | 126 | /**
|
nkeynes@152 | 127 | * Begin PIO read from the device. The data is assumed to already be
|
nkeynes@152 | 128 | * in the buffer at this point.
|
nkeynes@152 | 129 | */
|
nkeynes@152 | 130 | static void ide_start_read( int length, int blocksize, gboolean dma )
|
nkeynes@2 | 131 | {
|
nkeynes@152 | 132 | idereg.status = IDE_STATUS_DRDY | IDE_STATUS_DRQ;
|
nkeynes@152 | 133 | idereg.count = IDE_COUNT_IO;
|
nkeynes@152 | 134 | idereg.data_length = length;
|
nkeynes@152 | 135 | idereg.data_offset = 0;
|
nkeynes@152 | 136 | if( dma ) {
|
nkeynes@152 | 137 | idereg.state = IDE_STATE_DMA_READ;
|
nkeynes@152 | 138 | idereg.status |= IDE_STATUS_DMRD;
|
nkeynes@152 | 139 | } else {
|
nkeynes@152 | 140 | idereg.state = IDE_STATE_PIO_READ;
|
nkeynes@152 | 141 | idereg.lba1 = length & 0xFF;
|
nkeynes@152 | 142 | idereg.lba2 = (length >> 8) & 0xFF;
|
nkeynes@152 | 143 | // idereg.lba1 = blocksize & 0xFF;
|
nkeynes@152 | 144 | // idereg.lba2 = blocksize >> 8;
|
nkeynes@152 | 145 | idereg.block_length = blocksize;
|
nkeynes@152 | 146 | idereg.block_left = blocksize;
|
nkeynes@152 | 147 | }
|
nkeynes@152 | 148 | }
|
nkeynes@152 | 149 |
|
nkeynes@152 | 150 | static void ide_start_packet_read( int length, int blocksize )
|
nkeynes@152 | 151 | {
|
nkeynes@152 | 152 | ide_start_read( length, blocksize, idereg.feature & IDE_FEAT_DMA ? TRUE : FALSE );
|
nkeynes@2 | 153 | }
|
nkeynes@2 | 154 |
|
nkeynes@125 | 155 | static void ide_raise_interrupt( void )
|
nkeynes@2 | 156 | {
|
nkeynes@125 | 157 | if( idereg.intrq_pending == 0 ) {
|
nkeynes@125 | 158 | idereg.intrq_pending = 1;
|
nkeynes@125 | 159 | if( IS_IDE_IRQ_ENABLED() )
|
nkeynes@125 | 160 | asic_event( EVENT_IDE );
|
nkeynes@125 | 161 | }
|
nkeynes@125 | 162 | }
|
nkeynes@125 | 163 |
|
nkeynes@125 | 164 | static void ide_clear_interrupt( void )
|
nkeynes@125 | 165 | {
|
nkeynes@125 | 166 | if( idereg.intrq_pending != 0 ) {
|
nkeynes@125 | 167 | idereg.intrq_pending = 0;
|
nkeynes@125 | 168 | if( IS_IDE_IRQ_ENABLED() )
|
nkeynes@125 | 169 | asic_clear_event( EVENT_IDE );
|
nkeynes@125 | 170 | }
|
nkeynes@125 | 171 | }
|
nkeynes@125 | 172 |
|
nkeynes@125 | 173 | static void ide_set_error( int error_code )
|
nkeynes@125 | 174 | {
|
nkeynes@125 | 175 | idereg.status = 0x51;
|
nkeynes@125 | 176 | idereg.error = error_code;
|
nkeynes@2 | 177 | }
|
nkeynes@2 | 178 |
|
nkeynes@125 | 179 | uint8_t ide_read_status( void )
|
nkeynes@125 | 180 | {
|
nkeynes@152 | 181 | if( (idereg.status & IDE_STATUS_BSY) == 0 )
|
nkeynes@125 | 182 | ide_clear_interrupt();
|
nkeynes@125 | 183 | return idereg.status;
|
nkeynes@2 | 184 | }
|
nkeynes@2 | 185 |
|
nkeynes@2 | 186 | uint16_t ide_read_data_pio( void ) {
|
nkeynes@152 | 187 | if( idereg.state == IDE_STATE_PIO_READ ) {
|
nkeynes@152 | 188 | uint16_t rv = READ_BUFFER();
|
nkeynes@152 | 189 | idereg.data_offset += 2;
|
nkeynes@152 | 190 | idereg.block_left -= 2;
|
nkeynes@152 | 191 | if( idereg.data_offset >= idereg.data_length ) {
|
nkeynes@152 | 192 | idereg.state = IDE_STATE_IDLE;
|
nkeynes@152 | 193 | idereg.status &= ~IDE_STATUS_DRQ;
|
nkeynes@152 | 194 | idereg.data_offset = -1;
|
nkeynes@152 | 195 | ide_raise_interrupt();
|
nkeynes@152 | 196 | } else if( idereg.block_left <= 0 ) {
|
nkeynes@152 | 197 | idereg.block_left = idereg.block_length;
|
nkeynes@152 | 198 | ide_raise_interrupt();
|
nkeynes@152 | 199 | }
|
nkeynes@152 | 200 | return rv;
|
nkeynes@152 | 201 | } else {
|
nkeynes@2 | 202 | return 0xFFFF;
|
nkeynes@2 | 203 | }
|
nkeynes@2 | 204 | }
|
nkeynes@2 | 205 |
|
nkeynes@152 | 206 |
|
nkeynes@152 | 207 | /**
|
nkeynes@152 | 208 | * DMA read request
|
nkeynes@152 | 209 | *
|
nkeynes@152 | 210 | * This method is called from the ASIC side when a DMA read request is
|
nkeynes@152 | 211 | * initiated. If there is a pending DMA transfer already, we copy the
|
nkeynes@152 | 212 | * data immediately, otherwise we record the DMA buffer for use when we
|
nkeynes@152 | 213 | * get to actually doing the transfer.
|
nkeynes@152 | 214 | * @return number of bytes transfered
|
nkeynes@152 | 215 | */
|
nkeynes@152 | 216 | uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
|
nkeynes@152 | 217 | {
|
nkeynes@152 | 218 | if( idereg.state == IDE_STATE_DMA_READ ) {
|
nkeynes@152 | 219 | int xferlen = length;
|
nkeynes@152 | 220 | int remaining = idereg.data_length - idereg.data_offset;
|
nkeynes@152 | 221 | if( xferlen > remaining )
|
nkeynes@152 | 222 | xferlen = remaining;
|
nkeynes@152 | 223 | mem_copy_to_sh4( addr, data_buffer + idereg.data_offset, xferlen );
|
nkeynes@152 | 224 | idereg.data_offset += xferlen;
|
nkeynes@152 | 225 | if( idereg.data_offset >= idereg.data_length ) {
|
nkeynes@152 | 226 | idereg.data_offset = -1;
|
nkeynes@152 | 227 | idereg.state = IDE_STATE_IDLE;
|
nkeynes@152 | 228 | idereg.status &= ~IDE_STATUS_DRQ;
|
nkeynes@152 | 229 | ide_raise_interrupt();
|
nkeynes@152 | 230 | }
|
nkeynes@152 | 231 | return xferlen;
|
nkeynes@152 | 232 | }
|
nkeynes@152 | 233 | return 0;
|
nkeynes@152 | 234 | }
|
nkeynes@152 | 235 |
|
nkeynes@152 | 236 |
|
nkeynes@2 | 237 | void ide_write_data_pio( uint16_t val ) {
|
nkeynes@152 | 238 | if( idereg.state == IDE_STATE_CMD_WRITE ) {
|
nkeynes@152 | 239 | WRITE_BUFFER(val);
|
nkeynes@152 | 240 | idereg.data_offset+=2;
|
nkeynes@152 | 241 | if( idereg.data_offset >= idereg.data_length ) {
|
nkeynes@152 | 242 | idereg.state = IDE_STATE_BUSY;
|
nkeynes@152 | 243 | idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
|
nkeynes@152 | 244 | idereg.data_offset = -1;
|
nkeynes@152 | 245 | ide_packet_command(data_buffer);
|
nkeynes@152 | 246 | }
|
nkeynes@152 | 247 | } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
|
nkeynes@152 | 248 | WRITE_BUFFER(val);
|
nkeynes@152 | 249 | if( idereg.data_offset >= idereg.data_length ) {
|
nkeynes@152 | 250 | idereg.state = IDE_STATE_BUSY;
|
nkeynes@152 | 251 | idereg.data_offset = -1;
|
nkeynes@152 | 252 | idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
|
nkeynes@152 | 253 | /* ??? - no data writes yet anyway */
|
nkeynes@152 | 254 | }
|
nkeynes@2 | 255 | }
|
nkeynes@2 | 256 | }
|
nkeynes@2 | 257 |
|
nkeynes@2 | 258 | void ide_write_control( uint8_t val ) {
|
nkeynes@125 | 259 | if( IS_IDE_IRQ_ENABLED() ) {
|
nkeynes@125 | 260 | if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
|
nkeynes@125 | 261 | asic_clear_event( EVENT_IDE );
|
nkeynes@125 | 262 | } else {
|
nkeynes@125 | 263 | if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
|
nkeynes@125 | 264 | asic_event( EVENT_IDE );
|
nkeynes@125 | 265 | }
|
nkeynes@125 | 266 | idereg.control = val;
|
nkeynes@2 | 267 | }
|
nkeynes@2 | 268 |
|
nkeynes@2 | 269 | void ide_write_command( uint8_t val ) {
|
nkeynes@125 | 270 | ide_clear_interrupt();
|
nkeynes@2 | 271 | idereg.command = val;
|
nkeynes@2 | 272 | switch( val ) {
|
nkeynes@39 | 273 | case IDE_CMD_RESET_DEVICE:
|
nkeynes@39 | 274 | ide_reset();
|
nkeynes@39 | 275 | break;
|
nkeynes@39 | 276 | case IDE_CMD_PACKET:
|
nkeynes@152 | 277 | ide_start_command_packet_write();
|
nkeynes@39 | 278 | break;
|
nkeynes@39 | 279 | case IDE_CMD_SET_FEATURE:
|
nkeynes@39 | 280 | switch( idereg.feature ) {
|
nkeynes@47 | 281 | case IDE_FEAT_SET_TRANSFER_MODE:
|
nkeynes@47 | 282 | switch( idereg.count & 0xF8 ) {
|
nkeynes@47 | 283 | case IDE_XFER_PIO:
|
nkeynes@47 | 284 | INFO( "Set PIO default mode: %d", idereg.count&0x07 );
|
nkeynes@47 | 285 | break;
|
nkeynes@47 | 286 | case IDE_XFER_PIO_FLOW:
|
nkeynes@47 | 287 | INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
|
nkeynes@47 | 288 | break;
|
nkeynes@47 | 289 | case IDE_XFER_MULTI_DMA:
|
nkeynes@47 | 290 | INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
|
nkeynes@47 | 291 | break;
|
nkeynes@47 | 292 | case IDE_XFER_ULTRA_DMA:
|
nkeynes@47 | 293 | INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
|
nkeynes@47 | 294 | break;
|
nkeynes@47 | 295 | default:
|
nkeynes@47 | 296 | INFO( "Setting unknown transfer mode: %02X", idereg.count );
|
nkeynes@47 | 297 | break;
|
nkeynes@47 | 298 | }
|
nkeynes@47 | 299 | break;
|
nkeynes@39 | 300 | default:
|
nkeynes@39 | 301 | WARN( "IDE: unimplemented feature: %02X", idereg.feature );
|
nkeynes@39 | 302 | }
|
nkeynes@125 | 303 | ide_raise_interrupt( );
|
nkeynes@39 | 304 | break;
|
nkeynes@39 | 305 | default:
|
nkeynes@39 | 306 | WARN( "IDE: Unimplemented command: %02X", val );
|
nkeynes@2 | 307 | }
|
nkeynes@152 | 308 | idereg.status = (idereg.status | IDE_STATUS_DRDY | IDE_STATUS_SERV) & (~IDE_STATUS_CHK);
|
nkeynes@2 | 309 | }
|
nkeynes@2 | 310 |
|
nkeynes@152 | 311 | void ide_set_packet_result( uint16_t result )
|
nkeynes@142 | 312 | {
|
nkeynes@152 | 313 | idereg.gdrom_sense[0] = 0xf0;
|
nkeynes@152 | 314 | idereg.gdrom_sense[2] = result & 0xFF;
|
nkeynes@152 | 315 | idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
|
nkeynes@152 | 316 | idereg.error = (result & 0x0F) << 4;
|
nkeynes@152 | 317 | if( result != 0 ) {
|
nkeynes@142 | 318 | idereg.status = 0x51;
|
nkeynes@152 | 319 | } else {
|
nkeynes@152 | 320 | idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
|
nkeynes@142 | 321 | }
|
nkeynes@142 | 322 | }
|
nkeynes@142 | 323 |
|
nkeynes@142 | 324 | /**
|
nkeynes@142 | 325 | * Execute a packet command. This particular method is responsible for parsing
|
nkeynes@142 | 326 | * the command buffers (12 bytes), and generating the appropriate responses,
|
nkeynes@142 | 327 | * although the actual implementation is mostly delegated to gdrom.c
|
nkeynes@142 | 328 | */
|
nkeynes@125 | 329 | void ide_packet_command( unsigned char *cmd )
|
nkeynes@125 | 330 | {
|
nkeynes@138 | 331 | uint32_t length, datalen;
|
nkeynes@143 | 332 | uint32_t lba, status;
|
nkeynes@143 | 333 | int mode;
|
nkeynes@125 | 334 | int blocksize = idereg.lba1 + (idereg.lba2<<8);
|
nkeynes@125 | 335 |
|
nkeynes@125 | 336 | ide_raise_interrupt( );
|
nkeynes@125 | 337 | /* Okay we have the packet in the command buffer */
|
nkeynes@125 | 338 | WARN( "ATAPI: Received Packet command: %02X", cmd[0] );
|
nkeynes@125 | 339 | fwrite_dump( (unsigned char *)cmd, 12, stderr );
|
nkeynes@125 | 340 | switch( cmd[0] ) {
|
nkeynes@142 | 341 | case PKT_CMD_TEST_READY:
|
nkeynes@142 | 342 | if( !gdrom_is_mounted() ) {
|
nkeynes@152 | 343 | ide_set_packet_result( PKT_ERR_NODISC );
|
nkeynes@142 | 344 | return;
|
nkeynes@142 | 345 | }
|
nkeynes@152 | 346 | ide_set_packet_result( 0 );
|
nkeynes@142 | 347 | idereg.status = 0x50;
|
nkeynes@142 | 348 | return;
|
nkeynes@142 | 349 | break;
|
nkeynes@125 | 350 | case PKT_CMD_IDENTIFY:
|
nkeynes@140 | 351 | lba = cmd[2];
|
nkeynes@140 | 352 | if( lba >= sizeof(gdrom_ident) ) {
|
nkeynes@142 | 353 | ide_set_error(PKT_ERR_BADFIELD);
|
nkeynes@140 | 354 | return;
|
nkeynes@140 | 355 | }
|
nkeynes@140 | 356 | length = cmd[4];
|
nkeynes@140 | 357 | if( lba+length > sizeof(gdrom_ident) )
|
nkeynes@140 | 358 | length = sizeof(gdrom_ident) - lba;
|
nkeynes@152 | 359 | memcpy( data_buffer, gdrom_ident + lba, length );
|
nkeynes@152 | 360 | ide_start_packet_read( length, blocksize );
|
nkeynes@125 | 361 | break;
|
nkeynes@142 | 362 | case PKT_CMD_SENSE:
|
nkeynes@142 | 363 | length = cmd[4];
|
nkeynes@142 | 364 | if( length > 10 )
|
nkeynes@142 | 365 | length = 10;
|
nkeynes@152 | 366 | memcpy( data_buffer, idereg.gdrom_sense, length );
|
nkeynes@152 | 367 | ide_start_packet_read( length, blocksize );
|
nkeynes@142 | 368 | break;
|
nkeynes@125 | 369 | case PKT_CMD_READ_TOC:
|
nkeynes@142 | 370 | length = (cmd[3]<<8) | cmd[4];
|
nkeynes@142 | 371 | if( length > sizeof(struct gdrom_toc) )
|
nkeynes@142 | 372 | length = sizeof(struct gdrom_toc);
|
nkeynes@152 | 373 |
|
nkeynes@152 | 374 | status = gdrom_get_toc( data_buffer );
|
nkeynes@152 | 375 | if( status != PKT_ERR_OK ) {
|
nkeynes@152 | 376 | ide_set_packet_result( status );
|
nkeynes@152 | 377 | return;
|
nkeynes@152 | 378 | }
|
nkeynes@152 | 379 | ide_start_packet_read( length, blocksize );
|
nkeynes@125 | 380 | break;
|
nkeynes@149 | 381 | case PKT_CMD_DISC_INFO:
|
nkeynes@149 | 382 | length = cmd[4];
|
nkeynes@149 | 383 | if( length > 6 )
|
nkeynes@149 | 384 | length = 6;
|
nkeynes@152 | 385 | status = gdrom_get_info( data_buffer, cmd[2] );
|
nkeynes@152 | 386 | if( status != PKT_ERR_OK ) {
|
nkeynes@152 | 387 | ide_set_packet_result( status );
|
nkeynes@152 | 388 | return;
|
nkeynes@152 | 389 | }
|
nkeynes@152 | 390 | ide_start_packet_read( length, blocksize );
|
nkeynes@149 | 391 | break;
|
nkeynes@125 | 392 | case PKT_CMD_READ_SECTOR:
|
nkeynes@125 | 393 | lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
|
nkeynes@125 | 394 | length = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
|
nkeynes@138 | 395 | if( length > data_buffer_len ) {
|
nkeynes@138 | 396 | do {
|
nkeynes@138 | 397 | data_buffer_len = data_buffer_len << 1;
|
nkeynes@138 | 398 | } while( data_buffer_len < length );
|
nkeynes@138 | 399 | data_buffer = realloc( data_buffer, data_buffer_len );
|
nkeynes@138 | 400 | }
|
nkeynes@142 | 401 |
|
nkeynes@143 | 402 | switch( cmd[1] ) {
|
nkeynes@143 | 403 | case 0x20: mode = GDROM_MODE1; break;
|
nkeynes@143 | 404 | case 0x24: mode = GDROM_GD; break;
|
nkeynes@143 | 405 | case 0x28: mode = GDROM_MODE1; break; /* ??? */
|
nkeynes@143 | 406 | case 0x30: mode = GDROM_RAW; break;
|
nkeynes@143 | 407 | default:
|
nkeynes@143 | 408 | ERROR( "Unrecognized read mode '%02X' in GD-Rom read request", cmd[1] );
|
nkeynes@152 | 409 | ide_set_packet_result( PKT_ERR_BADFIELD );
|
nkeynes@142 | 410 | return;
|
nkeynes@142 | 411 | }
|
nkeynes@152 | 412 | datalen = data_buffer_len;
|
nkeynes@152 | 413 | status = gdrom_read_sectors( lba, length, mode, data_buffer, &datalen );
|
nkeynes@143 | 414 | if( status != 0 ) {
|
nkeynes@152 | 415 | ide_set_packet_result( status );
|
nkeynes@152 | 416 | idereg.gdrom_sense[5] = (lba >> 16) & 0xFF;
|
nkeynes@152 | 417 | idereg.gdrom_sense[6] = (lba >> 8) & 0xFF;
|
nkeynes@152 | 418 | idereg.gdrom_sense[7] = lba & 0xFF;
|
nkeynes@125 | 419 | return;
|
nkeynes@125 | 420 | }
|
nkeynes@152 | 421 | ide_start_packet_read( datalen, blocksize );
|
nkeynes@125 | 422 | break;
|
nkeynes@149 | 423 | case PKT_CMD_SPIN_UP:
|
nkeynes@149 | 424 | /* do nothing? */
|
nkeynes@149 | 425 | break;
|
nkeynes@142 | 426 | default:
|
nkeynes@152 | 427 | ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
|
nkeynes@142 | 428 | return;
|
nkeynes@125 | 429 | }
|
nkeynes@152 | 430 | ide_set_packet_result( PKT_ERR_OK );
|
nkeynes@125 | 431 | }
|