nkeynes@31 | 1 | /**
|
nkeynes@561 | 2 | * $Id$
|
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@422 | 28 | #include "mem.h"
|
nkeynes@125 | 29 | #include "asic.h"
|
nkeynes@39 | 30 | #include "gdrom/ide.h"
|
nkeynes@125 | 31 | #include "gdrom/gdrom.h"
|
nkeynes@142 | 32 | #include "gdrom/packet.h"
|
nkeynes@2 | 33 |
|
nkeynes@138 | 34 | #define MAX_WRITE_BUF 4096
|
nkeynes@138 | 35 | #define MAX_SECTOR_SIZE 2352 /* Audio sector */
|
nkeynes@138 | 36 | #define DEFAULT_DATA_SECTORS 8
|
nkeynes@2 | 37 |
|
nkeynes@138 | 38 | static void ide_init( void );
|
nkeynes@138 | 39 | static void ide_reset( void );
|
nkeynes@342 | 40 | static uint32_t ide_run_slice( uint32_t nanosecs );
|
nkeynes@138 | 41 | static void ide_save_state( FILE *f );
|
nkeynes@138 | 42 | static int ide_load_state( FILE *f );
|
nkeynes@138 | 43 | static void ide_raise_interrupt( void );
|
nkeynes@138 | 44 | static void ide_clear_interrupt( void );
|
nkeynes@152 | 45 | static void ide_packet_command( unsigned char *data );
|
nkeynes@342 | 46 | static void ide_read_next_sector(void);
|
nkeynes@15 | 47 |
|
nkeynes@342 | 48 | struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, ide_run_slice,
|
nkeynes@138 | 49 | NULL, ide_save_state, ide_load_state };
|
nkeynes@15 | 50 |
|
nkeynes@2 | 51 | struct ide_registers idereg;
|
nkeynes@342 | 52 | gdrom_disc_t gdrom_disc = NULL;
|
nkeynes@342 | 53 |
|
nkeynes@342 | 54 | unsigned char data_buffer[MAX_SECTOR_SIZE];
|
nkeynes@2 | 55 |
|
nkeynes@152 | 56 | #define WRITE_BUFFER(x16) *((uint16_t *)(data_buffer + idereg.data_offset)) = x16
|
nkeynes@152 | 57 | #define READ_BUFFER() *((uint16_t *)(data_buffer + idereg.data_offset))
|
nkeynes@152 | 58 |
|
nkeynes@493 | 59 | /* 10 bytes followed by "SE REV 6.42990316" */
|
nkeynes@493 | 60 | unsigned char default_gdrom_mode[GDROM_MODE_LENGTH] =
|
nkeynes@493 | 61 | { 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x19, 0x00, 0x00, 0x08,
|
nkeynes@493 | 62 | 0x53, 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
nkeynes@493 | 63 | 0x52, 0x65, 0x76, 0x20, 0x36, 0x2e, 0x34, 0x32, 0x39, 0x39, 0x30, 0x33, 0x31, 0x36 };
|
nkeynes@493 | 64 |
|
nkeynes@158 | 65 | unsigned char gdrom_71[] = { 0x3E, 0x0F, 0x90, 0xBE, 0x1D, 0xD9, 0x89, 0x04, 0x28, 0x3A, 0x8E, 0x26, 0x5C, 0x95, 0x10, 0x5A,
|
nkeynes@158 | 66 | 0x0A, 0x99, 0xEE, 0xFB, 0x69, 0xCE, 0xD9, 0x63, 0x00, 0xF5, 0x0A, 0xBC, 0x2C, 0x0D, 0xF8, 0xE2,
|
nkeynes@158 | 67 | 0x05, 0x02, 0x00, 0x7C, 0x03, 0x00, 0x3D, 0x08, 0xD8, 0x8D, 0x08, 0x7A, 0x6D, 0x00, 0x35, 0x06,
|
nkeynes@158 | 68 | 0xBA, 0x66, 0x10, 0x00, 0x91, 0x08, 0x10, 0x29, 0xD0, 0x45, 0xDA, 0x00, 0x2D, 0x05, 0x69, 0x09,
|
nkeynes@158 | 69 | 0x00, 0x5E, 0x0F, 0x70, 0x86, 0x12, 0x6C, 0x77, 0x5A, 0xFB, 0xCD, 0x56, 0xFB, 0xF7, 0xB7, 0x00,
|
nkeynes@158 | 70 | 0x5D, 0x07, 0x19, 0x99, 0xF2, 0xAF, 0x00, 0x63, 0x03, 0x00, 0xF0, 0x10, 0xBE, 0xD7, 0xA0, 0x63,
|
nkeynes@158 | 71 | 0xFA, 0x84, 0xA7, 0x74, 0x94, 0xEF, 0xAD, 0xC2, 0xAC, 0x00, 0x78, 0x07, 0x9F, 0x57, 0x0B, 0x62,
|
nkeynes@158 | 72 | 0x00, 0xFE, 0x08, 0x08, 0x5D, 0x5A, 0x6A, 0x54, 0x00, 0xE2, 0x09, 0x93, 0x7E, 0x62, 0x2A, 0x5E,
|
nkeynes@158 | 73 | 0xDA, 0x00, 0x7E, 0x0F, 0xF0, 0x07, 0x01, 0x6D, 0x50, 0x86, 0xDD, 0x4A, 0x15, 0x54, 0xC7, 0xEC,
|
nkeynes@158 | 74 | 0x00, 0xF2, 0x0B, 0x07, 0xF8, 0x1A, 0xB0, 0x99, 0x3B, 0xF1, 0x36, 0x00, 0x94, 0x07, 0x34, 0xE3,
|
nkeynes@158 | 75 | 0xBC, 0x6E, 0x00, 0x34, 0x0D, 0x6F, 0xDA, 0xBD, 0xEE, 0xF7, 0xCC, 0xCE, 0x39, 0x7E, 0xE3, 0x00,
|
nkeynes@158 | 76 | 0x14, 0x08, 0xDC, 0xD2, 0xB9, 0xF9, 0x31, 0x00, 0xB0, 0x0C, 0x10, 0xA3, 0x45, 0x12, 0xC7, 0xCD,
|
nkeynes@158 | 77 | 0xBF, 0x05, 0x37, 0x00, 0xC4, 0x0D, 0x5F, 0xE0, 0x59, 0xBB, 0x01, 0x59, 0x03, 0xD6, 0x29, 0x9C,
|
nkeynes@158 | 78 | 0x00, 0x01, 0x0A, 0x09, 0xAA, 0xA8, 0xA8, 0x24, 0x0B, 0x66, 0x00, 0x5C, 0x05, 0xA5, 0xCE, 0x00,
|
nkeynes@158 | 79 | 0xC1, 0x0B, 0xB7, 0xA0, 0x6F, 0xE9, 0x2B, 0xCC, 0xB5, 0xFC, 0x00, 0x8D, 0x05, 0xF4, 0xAC, 0x00,
|
nkeynes@158 | 80 | 0x57, 0x04, 0xB6, 0x00, 0xFC, 0x03, 0x00, 0xC3, 0x10, 0x43, 0x3B, 0xBE, 0xA2, 0x96, 0xC3, 0x65,
|
nkeynes@158 | 81 | 0x9F, 0x9A, 0x88, 0xD5, 0x49, 0x68, 0x00, 0xDC, 0x11, 0x56, 0x23, 0x2D, 0xF9, 0xFC, 0xF5, 0x8B,
|
nkeynes@158 | 82 | 0x1B, 0xB1, 0xB7, 0x10, 0x21, 0x1C, 0x12, 0x00, 0x0D, 0x0D, 0xEB, 0x86, 0xA2, 0x49, 0x8D, 0x8D,
|
nkeynes@158 | 83 | 0xBE, 0xA1, 0x6D, 0x53, 0x00, 0xE1, 0x0A, 0x8E, 0x67, 0xAA, 0x16, 0x79, 0x39, 0x59, 0x00, 0x36,
|
nkeynes@158 | 84 | 0x0B, 0x2A, 0x4E, 0xAE, 0x51, 0x4B, 0xD0, 0x66, 0x33, 0x00, 0x8A, 0x07, 0xCD, 0x6F, 0xBA, 0x92,
|
nkeynes@158 | 85 | 0x00, 0x1A, 0x0E, 0xDF, 0x4A, 0xB3, 0x77, 0x1F, 0xA5, 0x90, 0x19, 0xFA, 0x59, 0xD7, 0x00, 0x04,
|
nkeynes@158 | 86 | 0x0F, 0xAC, 0xCA, 0x9F, 0xA4, 0xFC, 0x6D, 0x90, 0x86, 0x9E, 0x1F, 0x44, 0x40, 0x00, 0x9F, 0x04,
|
nkeynes@158 | 87 | 0x56, 0x00, 0x22, 0x03, 0x00, 0xB8, 0x10, 0x2C, 0x7A, 0x53, 0xA4, 0xBF, 0xA3, 0x90, 0x90, 0x14,
|
nkeynes@158 | 88 | 0x9D, 0x46, 0x6C, 0x96, 0x00, 0xC6, 0x0B, 0x9B, 0xBB, 0xB0, 0xAE, 0x60, 0x92, 0x8E, 0x0C, 0x00,
|
nkeynes@158 | 89 | 0x14, 0x06, 0x4B, 0xAE, 0x7F, 0x00, 0x5C, 0x0B, 0x23, 0xFA, 0xE7, 0x51, 0xDA, 0x61, 0x49, 0x5E,
|
nkeynes@158 | 90 | 0x00, 0xD7, 0x0B, 0x01, 0xFC, 0x55, 0x31, 0x84, 0xC5, 0x0C, 0x98, 0x00, 0x97, 0x50, 0x6E, 0xF9,
|
nkeynes@158 | 91 | 0xEE, 0x75, 0x92, 0x53, 0xD3, 0x66, 0xA4, 0xAF, 0x3B, 0xFE, 0x7B, 0x27, 0x30, 0xBB, 0xB6, 0xF2,
|
nkeynes@158 | 92 | 0x76, 0x22, 0x45, 0x42, 0xCA, 0xF9, 0xF0, 0xDE, 0x9F, 0x45, 0x16, 0x68, 0x22, 0xB9, 0x84, 0x28,
|
nkeynes@158 | 93 | 0x8F, 0x2B, 0xB5, 0x5C, 0xD2, 0xF5, 0x45, 0x36, 0x3E, 0x76, 0xC6, 0xBF, 0x32, 0x5C, 0x41, 0xA6,
|
nkeynes@158 | 94 | 0x26, 0xC7, 0x82, 0x2F, 0x2E, 0xB5, 0x75, 0xC6, 0xE6, 0x67, 0x9E, 0x77, 0x94, 0xAF, 0x6A, 0x05,
|
nkeynes@158 | 95 | 0xC0, 0x05, 0x61, 0x71, 0x89, 0x5A, 0xB1, 0xD0, 0xFC, 0x7E, 0xC0, 0x9B, 0xCB, 0x3B, 0x69, 0xD9,
|
nkeynes@158 | 96 | 0x5F, 0xAF, 0xCA, 0xAB, 0x25, 0xD5, 0xBE, 0x8A, 0x6B, 0xB0, 0xFB, 0x61, 0x6C, 0xEB, 0x85, 0x6E,
|
nkeynes@158 | 97 | 0x7A, 0x48, 0xFF, 0x97, 0x91, 0x06, 0x3D, 0x4D, 0x68, 0xD3, 0x65, 0x83, 0x90, 0xA0, 0x08, 0x5C,
|
nkeynes@158 | 98 | 0xFC, 0xEE, 0x7C, 0x33, 0x43, 0x7F, 0x80, 0x52, 0x8B, 0x19, 0x72, 0xF2, 0xC9, 0xAB, 0x93, 0xAF,
|
nkeynes@158 | 99 | 0x16, 0xED, 0x36, 0x48, 0xAB, 0xC9, 0xD1, 0x03, 0xB3, 0xDC, 0x2F, 0xF2, 0x92, 0x3F, 0x0A, 0x19,
|
nkeynes@158 | 100 | 0x25, 0xE2, 0xEF, 0x7A, 0x22, 0xDA, 0xDB, 0xCB, 0x32, 0x12, 0x61, 0x49, 0x5B, 0x74, 0x7C, 0x65,
|
nkeynes@158 | 101 | 0x20, 0x89, 0x54, 0x9E, 0x0E, 0xC9, 0x52, 0xE3, 0xC9, 0x9A, 0x44, 0xC9, 0x5D, 0xA6, 0x77, 0xC0,
|
nkeynes@158 | 102 | 0xE7, 0x60, 0x91, 0x80, 0x50, 0x1F, 0x33, 0xB1, 0xCD, 0xAD, 0xF4, 0x0D, 0xBB, 0x08, 0xB1, 0xD0,
|
nkeynes@158 | 103 | 0x13, 0x95, 0xAE, 0xC9, 0xE2, 0x64, 0xA2, 0x65, 0xFB, 0x8F, 0xE9, 0xA2, 0x8A, 0xBC, 0x98, 0x81,
|
nkeynes@158 | 104 | 0x45, 0xB4, 0x55, 0x4E, 0xB9, 0x74, 0xB4, 0x50, 0x76, 0xBF, 0xF0, 0x45, 0xE7, 0xEE, 0x41, 0x64,
|
nkeynes@158 | 105 | 0x9F, 0xB5, 0xE0, 0xBB, 0x1C, 0xBB, 0x28, 0x66, 0x1B, 0xDD, 0x2B, 0x02, 0x66, 0xBF, 0xFD, 0x7D,
|
nkeynes@158 | 106 | 0x37, 0x35, 0x1D, 0x76, 0x21, 0xC3, 0x8F, 0xAF, 0xF6, 0xF9, 0xE9, 0x27, 0x48, 0xE7, 0x3D, 0x95,
|
nkeynes@158 | 107 | 0x74, 0x0C, 0x77, 0x88, 0x56, 0xD9, 0x84, 0xC8, 0x7D, 0x20, 0x31, 0x43, 0x53, 0xF1, 0xC1, 0xC7,
|
nkeynes@158 | 108 | 0xC9, 0xF7, 0x5C, 0xC0, 0xA6, 0x5A, 0x27, 0x0A, 0x41, 0xD4, 0x44, 0x94, 0x65, 0x4F, 0xE2, 0x53,
|
nkeynes@158 | 109 | 0x60, 0x0B, 0xD1, 0x23, 0x6C, 0x0C, 0xBC, 0x70, 0x6C, 0x26, 0x1A, 0x61, 0x1D, 0x35, 0x88, 0xEC,
|
nkeynes@158 | 110 | 0xB8, 0x15, 0xE3, 0xB4, 0x82, 0xEE, 0xB3, 0x21, 0xAC, 0x6C, 0xB7, 0x33, 0x6D, 0x78, 0x0C, 0x0D,
|
nkeynes@158 | 111 | 0xB4, 0x0B, 0x29, 0xF2, 0xD4, 0x8C, 0x3F, 0xDD, 0x3F, 0x47, 0xDD, 0xF2, 0xD8, 0x39, 0x57, 0x20,
|
nkeynes@158 | 112 | 0x28, 0xD8, 0xDD, 0x32, 0xE2, 0x6A, 0x47, 0x53, 0x57, 0xC6, 0xFA, 0x7A, 0x38, 0x30, 0x31, 0x8F,
|
nkeynes@158 | 113 | 0xE7, 0xD3, 0x84, 0x2B, 0x5D, 0x4F, 0x95, 0x98, 0xED, 0x0B, 0xD7, 0x50, 0x0C, 0x49, 0xDA, 0x59,
|
nkeynes@158 | 114 | 0x15, 0xF1, 0x39, 0xF3, 0x40, 0xDC, 0xDC, 0x25, 0x24, 0x56, 0x6E, 0xA9, 0x2F, 0xF0, 0x00, 0x00 };
|
nkeynes@158 | 115 |
|
nkeynes@2 | 116 |
|
nkeynes@250 | 117 | char gdrom_status[] = {
|
nkeynes@250 | 118 | 0x00, 0x15, 0x00, 0x64, 0x00, 0x40, 0x00, 0x00,
|
nkeynes@250 | 119 | 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
|
nkeynes@250 | 120 | 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
|
nkeynes@250 | 121 | 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
|
nkeynes@250 | 122 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
nkeynes@250 | 123 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
|
nkeynes@250 | 124 | 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
nkeynes@250 | 125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
nkeynes@250 | 126 | 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
|
nkeynes@250 | 127 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
|
nkeynes@250 | 128 | 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40,
|
nkeynes@250 | 129 | 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
|
nkeynes@250 | 130 | 0x00, 0x40, 0x00, 0x00 };
|
nkeynes@250 | 131 |
|
nkeynes@250 | 132 |
|
nkeynes@138 | 133 | static void ide_init( void )
|
nkeynes@138 | 134 | {
|
nkeynes@138 | 135 | ide_reset();
|
nkeynes@138 | 136 | }
|
nkeynes@138 | 137 |
|
nkeynes@138 | 138 | static void ide_reset( void )
|
nkeynes@138 | 139 | {
|
nkeynes@138 | 140 | ide_clear_interrupt();
|
nkeynes@138 | 141 | idereg.error = 0x01;
|
nkeynes@138 | 142 | idereg.count = 0x01;
|
nkeynes@138 | 143 | idereg.lba0 = /* 0x21; */ 0x81;
|
nkeynes@138 | 144 | idereg.lba1 = 0x14;
|
nkeynes@138 | 145 | idereg.lba2 = 0xeb;
|
nkeynes@138 | 146 | idereg.feature = 0; /* Indeterminate really */
|
nkeynes@254 | 147 | idereg.status = 0x00;
|
nkeynes@138 | 148 | idereg.device = 0x00;
|
nkeynes@152 | 149 | idereg.state = IDE_STATE_IDLE;
|
nkeynes@152 | 150 | memset( idereg.gdrom_sense, '\0', 10 );
|
nkeynes@493 | 151 | memcpy( idereg.gdrom_mode, default_gdrom_mode, GDROM_MODE_LENGTH );
|
nkeynes@152 | 152 | idereg.data_offset = -1;
|
nkeynes@152 | 153 | idereg.data_length = -1;
|
nkeynes@245 | 154 | idereg.last_read_track = 1;
|
nkeynes@493 | 155 | idereg.current_lba = 150;
|
nkeynes@493 | 156 | idereg.current_mode = 0x28;
|
nkeynes@342 | 157 | idereg.sectors_left = 0;
|
nkeynes@254 | 158 | idereg.was_reset = TRUE;
|
nkeynes@138 | 159 | }
|
nkeynes@138 | 160 |
|
nkeynes@342 | 161 | static uint32_t ide_run_slice( uint32_t nanosecs )
|
nkeynes@342 | 162 | {
|
nkeynes@342 | 163 | if( gdrom_disc != NULL && gdrom_disc->run_time_slice != NULL ) {
|
nkeynes@342 | 164 | gdrom_disc->run_time_slice(gdrom_disc, nanosecs);
|
nkeynes@342 | 165 | }
|
nkeynes@342 | 166 | return nanosecs;
|
nkeynes@342 | 167 | }
|
nkeynes@342 | 168 |
|
nkeynes@138 | 169 | static void ide_save_state( FILE *f )
|
nkeynes@138 | 170 | {
|
nkeynes@152 | 171 | fwrite( &idereg, sizeof(idereg), 1, f );
|
nkeynes@342 | 172 | fwrite( data_buffer, MAX_SECTOR_SIZE, 1, f );
|
nkeynes@138 | 173 | }
|
nkeynes@138 | 174 |
|
nkeynes@138 | 175 | static int ide_load_state( FILE *f )
|
nkeynes@138 | 176 | {
|
nkeynes@152 | 177 | fread( &idereg, sizeof(idereg), 1, f );
|
nkeynes@342 | 178 | fread( data_buffer, MAX_SECTOR_SIZE, 1, f );
|
nkeynes@138 | 179 | return 0;
|
nkeynes@138 | 180 | }
|
nkeynes@125 | 181 |
|
nkeynes@152 | 182 | /************************ State transitions *************************/
|
nkeynes@152 | 183 |
|
nkeynes@158 | 184 | void ide_set_packet_result( uint16_t result )
|
nkeynes@158 | 185 | {
|
nkeynes@158 | 186 | idereg.gdrom_sense[0] = 0xf0;
|
nkeynes@158 | 187 | idereg.gdrom_sense[2] = result & 0xFF;
|
nkeynes@158 | 188 | idereg.gdrom_sense[8] = (result >> 8) & 0xFF;
|
nkeynes@158 | 189 | idereg.error = (result & 0x0F) << 4;
|
nkeynes@254 | 190 | idereg.count = 3;
|
nkeynes@158 | 191 | if( result != 0 ) {
|
nkeynes@158 | 192 | idereg.status = 0x51;
|
nkeynes@158 | 193 | ide_raise_interrupt();
|
nkeynes@158 | 194 | } else {
|
nkeynes@158 | 195 | idereg.status = idereg.status & ~(IDE_STATUS_BSY|IDE_STATUS_CHK);
|
nkeynes@158 | 196 | }
|
nkeynes@158 | 197 | }
|
nkeynes@158 | 198 |
|
nkeynes@152 | 199 | /**
|
nkeynes@152 | 200 | * Begin command packet write to the device. This is always 12 bytes of PIO data
|
nkeynes@152 | 201 | */
|
nkeynes@152 | 202 | static void ide_start_command_packet_write( )
|
nkeynes@2 | 203 | {
|
nkeynes@152 | 204 | idereg.state = IDE_STATE_CMD_WRITE;
|
nkeynes@254 | 205 | idereg.status = 0x58;
|
nkeynes@152 | 206 | idereg.error = idereg.feature & 0x03; /* Copy values of OVL/DMA */
|
nkeynes@152 | 207 | idereg.count = IDE_COUNT_CD;
|
nkeynes@152 | 208 | idereg.data_offset = 0;
|
nkeynes@152 | 209 | idereg.data_length = 12;
|
nkeynes@2 | 210 | }
|
nkeynes@2 | 211 |
|
nkeynes@152 | 212 | /**
|
nkeynes@493 | 213 | * Begin PIO/DMA read from the device. The data is assumed to already be
|
nkeynes@152 | 214 | * in the buffer at this point.
|
nkeynes@152 | 215 | */
|
nkeynes@342 | 216 | static void ide_start_read( int length, gboolean dma )
|
nkeynes@2 | 217 | {
|
nkeynes@152 | 218 | idereg.count = IDE_COUNT_IO;
|
nkeynes@152 | 219 | idereg.data_length = length;
|
nkeynes@152 | 220 | idereg.data_offset = 0;
|
nkeynes@152 | 221 | if( dma ) {
|
nkeynes@152 | 222 | idereg.state = IDE_STATE_DMA_READ;
|
nkeynes@158 | 223 | idereg.status = 0xD0;
|
nkeynes@152 | 224 | } else {
|
nkeynes@152 | 225 | idereg.state = IDE_STATE_PIO_READ;
|
nkeynes@254 | 226 | idereg.status = 0x58;
|
nkeynes@342 | 227 | idereg.lba1 = length & 0xFF;
|
nkeynes@342 | 228 | idereg.lba2 = length >> 8;
|
nkeynes@158 | 229 | ide_raise_interrupt( );
|
nkeynes@152 | 230 | }
|
nkeynes@152 | 231 | }
|
nkeynes@152 | 232 |
|
nkeynes@493 | 233 | static void ide_start_write( int length, gboolean dma )
|
nkeynes@493 | 234 | {
|
nkeynes@493 | 235 | idereg.count = 0;
|
nkeynes@493 | 236 | idereg.data_length = length;
|
nkeynes@493 | 237 | idereg.data_offset = 0;
|
nkeynes@493 | 238 | if( dma ) {
|
nkeynes@493 | 239 | idereg.state = IDE_STATE_DMA_WRITE;
|
nkeynes@493 | 240 | idereg.status = 0xD0;
|
nkeynes@493 | 241 | } else {
|
nkeynes@493 | 242 | idereg.state = IDE_STATE_PIO_WRITE;
|
nkeynes@493 | 243 | idereg.status = 0x58;
|
nkeynes@493 | 244 | idereg.lba1 = length & 0xFF;
|
nkeynes@493 | 245 | idereg.lba2 = length >> 8;
|
nkeynes@493 | 246 | ide_raise_interrupt( );
|
nkeynes@493 | 247 | }
|
nkeynes@493 | 248 | }
|
nkeynes@493 | 249 |
|
nkeynes@342 | 250 | static void ide_start_packet_read( int length, int sector_count )
|
nkeynes@152 | 251 | {
|
nkeynes@342 | 252 | idereg.sectors_left = sector_count;
|
nkeynes@158 | 253 | ide_set_packet_result( PKT_ERR_OK );
|
nkeynes@342 | 254 | ide_start_read( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
|
nkeynes@2 | 255 | }
|
nkeynes@2 | 256 |
|
nkeynes@493 | 257 | static void ide_start_packet_write( int length, int sector_count )
|
nkeynes@493 | 258 | {
|
nkeynes@493 | 259 | idereg.sectors_left = sector_count;
|
nkeynes@493 | 260 | ide_set_packet_result( PKT_ERR_OK );
|
nkeynes@493 | 261 | ide_start_write( length, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
|
nkeynes@493 | 262 | }
|
nkeynes@493 | 263 |
|
nkeynes@125 | 264 | static void ide_raise_interrupt( void )
|
nkeynes@2 | 265 | {
|
nkeynes@125 | 266 | if( idereg.intrq_pending == 0 ) {
|
nkeynes@125 | 267 | idereg.intrq_pending = 1;
|
nkeynes@125 | 268 | if( IS_IDE_IRQ_ENABLED() )
|
nkeynes@125 | 269 | asic_event( EVENT_IDE );
|
nkeynes@125 | 270 | }
|
nkeynes@125 | 271 | }
|
nkeynes@125 | 272 |
|
nkeynes@125 | 273 | static void ide_clear_interrupt( void )
|
nkeynes@125 | 274 | {
|
nkeynes@125 | 275 | if( idereg.intrq_pending != 0 ) {
|
nkeynes@125 | 276 | idereg.intrq_pending = 0;
|
nkeynes@125 | 277 | if( IS_IDE_IRQ_ENABLED() )
|
nkeynes@125 | 278 | asic_clear_event( EVENT_IDE );
|
nkeynes@125 | 279 | }
|
nkeynes@125 | 280 | }
|
nkeynes@125 | 281 |
|
nkeynes@125 | 282 | static void ide_set_error( int error_code )
|
nkeynes@125 | 283 | {
|
nkeynes@125 | 284 | idereg.status = 0x51;
|
nkeynes@125 | 285 | idereg.error = error_code;
|
nkeynes@2 | 286 | }
|
nkeynes@2 | 287 |
|
nkeynes@125 | 288 | uint8_t ide_read_status( void )
|
nkeynes@125 | 289 | {
|
nkeynes@152 | 290 | if( (idereg.status & IDE_STATUS_BSY) == 0 )
|
nkeynes@125 | 291 | ide_clear_interrupt();
|
nkeynes@125 | 292 | return idereg.status;
|
nkeynes@2 | 293 | }
|
nkeynes@2 | 294 |
|
nkeynes@2 | 295 | uint16_t ide_read_data_pio( void ) {
|
nkeynes@152 | 296 | if( idereg.state == IDE_STATE_PIO_READ ) {
|
nkeynes@152 | 297 | uint16_t rv = READ_BUFFER();
|
nkeynes@152 | 298 | idereg.data_offset += 2;
|
nkeynes@152 | 299 | if( idereg.data_offset >= idereg.data_length ) {
|
nkeynes@152 | 300 | idereg.state = IDE_STATE_IDLE;
|
nkeynes@152 | 301 | idereg.status &= ~IDE_STATUS_DRQ;
|
nkeynes@152 | 302 | idereg.data_offset = -1;
|
nkeynes@254 | 303 | idereg.count = 3; /* complete */
|
nkeynes@152 | 304 | ide_raise_interrupt();
|
nkeynes@342 | 305 | if( idereg.sectors_left > 0 ) {
|
nkeynes@342 | 306 | ide_read_next_sector();
|
nkeynes@342 | 307 | }
|
nkeynes@152 | 308 | }
|
nkeynes@152 | 309 | return rv;
|
nkeynes@152 | 310 | } else {
|
nkeynes@2 | 311 | return 0xFFFF;
|
nkeynes@2 | 312 | }
|
nkeynes@2 | 313 | }
|
nkeynes@2 | 314 |
|
nkeynes@152 | 315 |
|
nkeynes@152 | 316 | /**
|
nkeynes@152 | 317 | * DMA read request
|
nkeynes@152 | 318 | *
|
nkeynes@152 | 319 | * This method is called from the ASIC side when a DMA read request is
|
nkeynes@152 | 320 | * initiated. If there is a pending DMA transfer already, we copy the
|
nkeynes@152 | 321 | * data immediately, otherwise we record the DMA buffer for use when we
|
nkeynes@152 | 322 | * get to actually doing the transfer.
|
nkeynes@152 | 323 | * @return number of bytes transfered
|
nkeynes@152 | 324 | */
|
nkeynes@152 | 325 | uint32_t ide_read_data_dma( uint32_t addr, uint32_t length )
|
nkeynes@152 | 326 | {
|
nkeynes@342 | 327 | uint32_t xfercount = 0;
|
nkeynes@152 | 328 | if( idereg.state == IDE_STATE_DMA_READ ) {
|
nkeynes@342 | 329 | while( xfercount < length ) {
|
nkeynes@342 | 330 | int xferlen = length - xfercount;
|
nkeynes@342 | 331 | int remaining = idereg.data_length - idereg.data_offset;
|
nkeynes@342 | 332 | if( xferlen > remaining ) {
|
nkeynes@342 | 333 | xferlen = remaining;
|
nkeynes@342 | 334 | }
|
nkeynes@430 | 335 | mem_copy_to_sh4( addr, (data_buffer + idereg.data_offset), xferlen );
|
nkeynes@342 | 336 | xfercount += xferlen;
|
nkeynes@342 | 337 | addr += xferlen;
|
nkeynes@342 | 338 | idereg.data_offset += xferlen;
|
nkeynes@342 | 339 | if( idereg.data_offset >= idereg.data_length ) {
|
nkeynes@342 | 340 | if( idereg.sectors_left > 0 ) {
|
nkeynes@342 | 341 | ide_read_next_sector();
|
nkeynes@342 | 342 | } else {
|
nkeynes@342 | 343 | idereg.data_offset = -1;
|
nkeynes@342 | 344 | idereg.state = IDE_STATE_IDLE;
|
nkeynes@342 | 345 | idereg.status = 0x50;
|
nkeynes@342 | 346 | idereg.count = 0x03;
|
nkeynes@342 | 347 | ide_raise_interrupt();
|
nkeynes@342 | 348 | asic_event( EVENT_IDE_DMA );
|
nkeynes@342 | 349 | break;
|
nkeynes@342 | 350 | }
|
nkeynes@342 | 351 | }
|
nkeynes@152 | 352 | }
|
nkeynes@152 | 353 | }
|
nkeynes@342 | 354 | return xfercount;
|
nkeynes@152 | 355 | }
|
nkeynes@152 | 356 |
|
nkeynes@2 | 357 | void ide_write_data_pio( uint16_t val ) {
|
nkeynes@152 | 358 | if( idereg.state == IDE_STATE_CMD_WRITE ) {
|
nkeynes@152 | 359 | WRITE_BUFFER(val);
|
nkeynes@152 | 360 | idereg.data_offset+=2;
|
nkeynes@152 | 361 | if( idereg.data_offset >= idereg.data_length ) {
|
nkeynes@152 | 362 | idereg.state = IDE_STATE_BUSY;
|
nkeynes@152 | 363 | idereg.status = (idereg.status & ~IDE_STATUS_DRQ) | IDE_STATUS_BSY;
|
nkeynes@152 | 364 | idereg.data_offset = -1;
|
nkeynes@152 | 365 | ide_packet_command(data_buffer);
|
nkeynes@152 | 366 | }
|
nkeynes@152 | 367 | } else if( idereg.state == IDE_STATE_PIO_WRITE ) {
|
nkeynes@152 | 368 | WRITE_BUFFER(val);
|
nkeynes@493 | 369 | idereg.data_offset +=2;
|
nkeynes@152 | 370 | if( idereg.data_offset >= idereg.data_length ) {
|
nkeynes@493 | 371 | idereg.state = IDE_STATE_IDLE;
|
nkeynes@493 | 372 | idereg.status &= ~IDE_STATUS_DRQ;
|
nkeynes@152 | 373 | idereg.data_offset = -1;
|
nkeynes@493 | 374 | idereg.count = 3; /* complete */
|
nkeynes@493 | 375 | ide_raise_interrupt();
|
nkeynes@493 | 376 | ide_write_buffer( data_buffer, idereg.data_length );
|
nkeynes@152 | 377 | }
|
nkeynes@2 | 378 | }
|
nkeynes@2 | 379 | }
|
nkeynes@2 | 380 |
|
nkeynes@2 | 381 | void ide_write_control( uint8_t val ) {
|
nkeynes@125 | 382 | if( IS_IDE_IRQ_ENABLED() ) {
|
nkeynes@125 | 383 | if( (val & 0x02) != 0 && idereg.intrq_pending != 0 )
|
nkeynes@125 | 384 | asic_clear_event( EVENT_IDE );
|
nkeynes@125 | 385 | } else {
|
nkeynes@125 | 386 | if( (val & 0x02) == 0 && idereg.intrq_pending != 0 )
|
nkeynes@125 | 387 | asic_event( EVENT_IDE );
|
nkeynes@125 | 388 | }
|
nkeynes@125 | 389 | idereg.control = val;
|
nkeynes@2 | 390 | }
|
nkeynes@2 | 391 |
|
nkeynes@2 | 392 | void ide_write_command( uint8_t val ) {
|
nkeynes@125 | 393 | ide_clear_interrupt();
|
nkeynes@2 | 394 | idereg.command = val;
|
nkeynes@2 | 395 | switch( val ) {
|
nkeynes@240 | 396 | case IDE_CMD_NOP: /* Effectively an "abort" */
|
nkeynes@240 | 397 | idereg.state = IDE_STATE_IDLE;
|
nkeynes@240 | 398 | idereg.status = 0x51;
|
nkeynes@240 | 399 | idereg.error = 0x04;
|
nkeynes@240 | 400 | idereg.data_offset = -1;
|
nkeynes@240 | 401 | ide_raise_interrupt();
|
nkeynes@240 | 402 | return;
|
nkeynes@39 | 403 | case IDE_CMD_RESET_DEVICE:
|
nkeynes@39 | 404 | ide_reset();
|
nkeynes@39 | 405 | break;
|
nkeynes@39 | 406 | case IDE_CMD_PACKET:
|
nkeynes@152 | 407 | ide_start_command_packet_write();
|
nkeynes@39 | 408 | break;
|
nkeynes@39 | 409 | case IDE_CMD_SET_FEATURE:
|
nkeynes@39 | 410 | switch( idereg.feature ) {
|
nkeynes@47 | 411 | case IDE_FEAT_SET_TRANSFER_MODE:
|
nkeynes@47 | 412 | switch( idereg.count & 0xF8 ) {
|
nkeynes@47 | 413 | case IDE_XFER_PIO:
|
nkeynes@47 | 414 | INFO( "Set PIO default mode: %d", idereg.count&0x07 );
|
nkeynes@47 | 415 | break;
|
nkeynes@47 | 416 | case IDE_XFER_PIO_FLOW:
|
nkeynes@47 | 417 | INFO( "Set PIO Flow-control mode: %d", idereg.count&0x07 );
|
nkeynes@47 | 418 | break;
|
nkeynes@47 | 419 | case IDE_XFER_MULTI_DMA:
|
nkeynes@47 | 420 | INFO( "Set Multiword DMA mode: %d", idereg.count&0x07 );
|
nkeynes@47 | 421 | break;
|
nkeynes@47 | 422 | case IDE_XFER_ULTRA_DMA:
|
nkeynes@47 | 423 | INFO( "Set Ultra DMA mode: %d", idereg.count&0x07 );
|
nkeynes@47 | 424 | break;
|
nkeynes@47 | 425 | default:
|
nkeynes@47 | 426 | INFO( "Setting unknown transfer mode: %02X", idereg.count );
|
nkeynes@47 | 427 | break;
|
nkeynes@47 | 428 | }
|
nkeynes@47 | 429 | break;
|
nkeynes@39 | 430 | default:
|
nkeynes@39 | 431 | WARN( "IDE: unimplemented feature: %02X", idereg.feature );
|
nkeynes@39 | 432 | }
|
nkeynes@254 | 433 | idereg.status = 0x50;
|
nkeynes@254 | 434 | idereg.error = 0x00;
|
nkeynes@254 | 435 | idereg.lba1 = 0x00;
|
nkeynes@254 | 436 | idereg.lba2 = 0x00;
|
nkeynes@256 | 437 | ide_raise_interrupt();
|
nkeynes@39 | 438 | break;
|
nkeynes@39 | 439 | default:
|
nkeynes@39 | 440 | WARN( "IDE: Unimplemented command: %02X", val );
|
nkeynes@2 | 441 | }
|
nkeynes@2 | 442 | }
|
nkeynes@2 | 443 |
|
nkeynes@342 | 444 | uint8_t ide_get_drive_status( void )
|
nkeynes@342 | 445 | {
|
nkeynes@342 | 446 | if( gdrom_disc == NULL ) {
|
nkeynes@342 | 447 | return IDE_DISC_NONE;
|
nkeynes@342 | 448 | } else {
|
nkeynes@342 | 449 | return gdrom_disc->drive_status(gdrom_disc);
|
nkeynes@342 | 450 | }
|
nkeynes@342 | 451 | }
|
nkeynes@342 | 452 |
|
nkeynes@342 | 453 | #define REQUIRE_DISC() if( gdrom_disc == NULL ) { ide_set_packet_result( PKT_ERR_NODISC ); return; }
|
nkeynes@342 | 454 |
|
nkeynes@342 | 455 | /**
|
nkeynes@342 | 456 | * Read the next sector from the active read, if any
|
nkeynes@342 | 457 | */
|
nkeynes@342 | 458 | static void ide_read_next_sector( void )
|
nkeynes@342 | 459 | {
|
nkeynes@422 | 460 | uint32_t sector_size;
|
nkeynes@342 | 461 | REQUIRE_DISC();
|
nkeynes@342 | 462 | gdrom_error_t status =
|
nkeynes@493 | 463 | gdrom_disc->read_sector( gdrom_disc, idereg.current_lba, idereg.current_mode,
|
nkeynes@342 | 464 | data_buffer, §or_size );
|
nkeynes@342 | 465 | if( status != PKT_ERR_OK ) {
|
nkeynes@342 | 466 | ide_set_packet_result( status );
|
nkeynes@493 | 467 | idereg.gdrom_sense[5] = (idereg.current_lba >> 16) & 0xFF;
|
nkeynes@493 | 468 | idereg.gdrom_sense[6] = (idereg.current_lba >> 8) & 0xFF;
|
nkeynes@493 | 469 | idereg.gdrom_sense[7] = idereg.current_lba & 0xFF;
|
nkeynes@342 | 470 | WARN( " => Read CD returned sense key %02X, %02X", status & 0xFF, status >> 8 );
|
nkeynes@342 | 471 | } else {
|
nkeynes@493 | 472 | idereg.current_lba++;
|
nkeynes@342 | 473 | idereg.sectors_left--;
|
nkeynes@342 | 474 | ide_start_read( sector_size, (idereg.feature & IDE_FEAT_DMA) ? TRUE : FALSE );
|
nkeynes@342 | 475 | }
|
nkeynes@342 | 476 | }
|
nkeynes@342 | 477 |
|
nkeynes@142 | 478 | /**
|
nkeynes@142 | 479 | * Execute a packet command. This particular method is responsible for parsing
|
nkeynes@142 | 480 | * the command buffers (12 bytes), and generating the appropriate responses,
|
nkeynes@142 | 481 | * although the actual implementation is mostly delegated to gdrom.c
|
nkeynes@142 | 482 | */
|
nkeynes@125 | 483 | void ide_packet_command( unsigned char *cmd )
|
nkeynes@125 | 484 | {
|
nkeynes@422 | 485 | uint32_t length;
|
nkeynes@143 | 486 | uint32_t lba, status;
|
nkeynes@125 | 487 |
|
nkeynes@125 | 488 | /* Okay we have the packet in the command buffer */
|
nkeynes@166 | 489 | INFO( "ATAPI packet: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
|
nkeynes@166 | 490 | cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6], cmd[7],
|
nkeynes@166 | 491 | cmd[8], cmd[9], cmd[10], cmd[11] );
|
nkeynes@254 | 492 |
|
nkeynes@254 | 493 | if( cmd[0] != PKT_CMD_SENSE && idereg.was_reset ) {
|
nkeynes@254 | 494 | ide_set_packet_result( PKT_ERR_RESET );
|
nkeynes@254 | 495 | idereg.was_reset = FALSE;
|
nkeynes@254 | 496 | return;
|
nkeynes@254 | 497 | }
|
nkeynes@254 | 498 |
|
nkeynes@125 | 499 | switch( cmd[0] ) {
|
nkeynes@142 | 500 | case PKT_CMD_TEST_READY:
|
nkeynes@342 | 501 | REQUIRE_DISC();
|
nkeynes@342 | 502 | ide_set_packet_result( 0 );
|
nkeynes@342 | 503 | ide_raise_interrupt();
|
nkeynes@342 | 504 | idereg.status = 0x50;
|
nkeynes@142 | 505 | break;
|
nkeynes@493 | 506 | case PKT_CMD_MODE_SENSE:
|
nkeynes@140 | 507 | lba = cmd[2];
|
nkeynes@493 | 508 | if( lba >= GDROM_MODE_LENGTH ) {
|
nkeynes@142 | 509 | ide_set_error(PKT_ERR_BADFIELD);
|
nkeynes@158 | 510 | } else {
|
nkeynes@158 | 511 | length = cmd[4];
|
nkeynes@493 | 512 | if( lba+length > GDROM_MODE_LENGTH )
|
nkeynes@493 | 513 | length = GDROM_MODE_LENGTH - lba;
|
nkeynes@493 | 514 | memcpy( data_buffer, idereg.gdrom_mode + lba, length );
|
nkeynes@342 | 515 | ide_start_packet_read( length, 0 );
|
nkeynes@140 | 516 | }
|
nkeynes@125 | 517 | break;
|
nkeynes@493 | 518 | case PKT_CMD_MODE_SELECT:
|
nkeynes@493 | 519 | lba = cmd[2];
|
nkeynes@493 | 520 | if( lba >= GDROM_MODE_LENGTH ) {
|
nkeynes@493 | 521 | ide_set_error(PKT_ERR_BADFIELD);
|
nkeynes@493 | 522 | } else {
|
nkeynes@493 | 523 | length = cmd[4];
|
nkeynes@493 | 524 | if( lba+length > GDROM_MODE_LENGTH )
|
nkeynes@493 | 525 | length = GDROM_MODE_LENGTH - lba;
|
nkeynes@493 | 526 | idereg.current_lba = lba;
|
nkeynes@493 | 527 | ide_start_packet_write( length, 0 );
|
nkeynes@493 | 528 | }
|
nkeynes@493 | 529 | break;
|
nkeynes@142 | 530 | case PKT_CMD_SENSE:
|
nkeynes@142 | 531 | length = cmd[4];
|
nkeynes@142 | 532 | if( length > 10 )
|
nkeynes@142 | 533 | length = 10;
|
nkeynes@152 | 534 | memcpy( data_buffer, idereg.gdrom_sense, length );
|
nkeynes@342 | 535 | ide_start_packet_read( length, 0 );
|
nkeynes@142 | 536 | break;
|
nkeynes@125 | 537 | case PKT_CMD_READ_TOC:
|
nkeynes@342 | 538 | REQUIRE_DISC();
|
nkeynes@142 | 539 | length = (cmd[3]<<8) | cmd[4];
|
nkeynes@142 | 540 | if( length > sizeof(struct gdrom_toc) )
|
nkeynes@142 | 541 | length = sizeof(struct gdrom_toc);
|
nkeynes@152 | 542 |
|
nkeynes@342 | 543 | status = gdrom_disc->read_toc( gdrom_disc, data_buffer );
|
nkeynes@152 | 544 | if( status != PKT_ERR_OK ) {
|
nkeynes@152 | 545 | ide_set_packet_result( status );
|
nkeynes@158 | 546 | } else {
|
nkeynes@342 | 547 | ide_start_packet_read( length, 0 );
|
nkeynes@152 | 548 | }
|
nkeynes@125 | 549 | break;
|
nkeynes@158 | 550 | case PKT_CMD_SESSION_INFO:
|
nkeynes@342 | 551 | REQUIRE_DISC();
|
nkeynes@149 | 552 | length = cmd[4];
|
nkeynes@149 | 553 | if( length > 6 )
|
nkeynes@149 | 554 | length = 6;
|
nkeynes@342 | 555 | status = gdrom_disc->read_session( gdrom_disc, cmd[2], data_buffer );
|
nkeynes@152 | 556 | if( status != PKT_ERR_OK ) {
|
nkeynes@152 | 557 | ide_set_packet_result( status );
|
nkeynes@158 | 558 | } else {
|
nkeynes@342 | 559 | ide_start_packet_read( length, 0 );
|
nkeynes@152 | 560 | }
|
nkeynes@149 | 561 | break;
|
nkeynes@342 | 562 | case PKT_CMD_PLAY_AUDIO:
|
nkeynes@342 | 563 | REQUIRE_DISC();
|
nkeynes@250 | 564 | ide_set_packet_result( 0 );
|
nkeynes@250 | 565 | ide_raise_interrupt();
|
nkeynes@250 | 566 | idereg.status = 0x50;
|
nkeynes@250 | 567 | break;
|
nkeynes@125 | 568 | case PKT_CMD_READ_SECTOR:
|
nkeynes@342 | 569 | REQUIRE_DISC();
|
nkeynes@493 | 570 | idereg.current_lba = cmd[2] << 16 | cmd[3] << 8 | cmd[4];
|
nkeynes@342 | 571 | idereg.sectors_left = cmd[8] << 16 | cmd[9] << 8 | cmd[10]; /* blocks */
|
nkeynes@493 | 572 | idereg.current_mode = cmd[1];
|
nkeynes@342 | 573 | ide_read_next_sector();
|
nkeynes@125 | 574 | break;
|
nkeynes@149 | 575 | case PKT_CMD_SPIN_UP:
|
nkeynes@342 | 576 | REQUIRE_DISC();
|
nkeynes@149 | 577 | /* do nothing? */
|
nkeynes@158 | 578 | ide_set_packet_result( PKT_ERR_OK );
|
nkeynes@158 | 579 | ide_raise_interrupt();
|
nkeynes@158 | 580 | break;
|
nkeynes@245 | 581 | case PKT_CMD_STATUS:
|
nkeynes@342 | 582 | REQUIRE_DISC();
|
nkeynes@245 | 583 | length = cmd[4];
|
nkeynes@342 | 584 | switch( cmd[1] ) {
|
nkeynes@342 | 585 | case 0:
|
nkeynes@342 | 586 | if( length > sizeof(gdrom_status) ) {
|
nkeynes@342 | 587 | length = sizeof(gdrom_status);
|
nkeynes@245 | 588 | }
|
nkeynes@342 | 589 | memcpy( data_buffer, gdrom_status, length );
|
nkeynes@342 | 590 | ide_start_packet_read( length, 0 );
|
nkeynes@342 | 591 | break;
|
nkeynes@342 | 592 | case 1:
|
nkeynes@342 | 593 | if( length > 14 ) {
|
nkeynes@342 | 594 | length = 14;
|
nkeynes@342 | 595 | }
|
nkeynes@493 | 596 | gdrom_disc->read_position( gdrom_disc, idereg.current_lba, data_buffer );
|
nkeynes@342 | 597 | data_buffer[0] = 0x00;
|
nkeynes@342 | 598 | data_buffer[1] = 0x15; /* audio status ? */
|
nkeynes@342 | 599 | data_buffer[2] = 0x00;
|
nkeynes@342 | 600 | data_buffer[3] = 0x0E;
|
nkeynes@342 | 601 | ide_start_packet_read( length, 0 );
|
nkeynes@342 | 602 | break;
|
nkeynes@245 | 603 | }
|
nkeynes@245 | 604 | break;
|
nkeynes@158 | 605 | case PKT_CMD_71:
|
nkeynes@158 | 606 | /* This is a weird one. As far as I can tell it returns random garbage
|
nkeynes@158 | 607 | * (and not even the same length each time, never mind the same data).
|
nkeynes@158 | 608 | * For sake of something to do, it returns the results from a test dump
|
nkeynes@158 | 609 | */
|
nkeynes@342 | 610 | REQUIRE_DISC();
|
nkeynes@158 | 611 | memcpy( data_buffer, gdrom_71, sizeof(gdrom_71) );
|
nkeynes@342 | 612 | ide_start_packet_read( sizeof(gdrom_71), 0 );
|
nkeynes@149 | 613 | break;
|
nkeynes@142 | 614 | default:
|
nkeynes@152 | 615 | ide_set_packet_result( PKT_ERR_BADCMD ); /* Invalid command */
|
nkeynes@142 | 616 | return;
|
nkeynes@125 | 617 | }
|
nkeynes@493 | 618 | idereg.last_packet_command = cmd[0];
|
nkeynes@125 | 619 | }
|
nkeynes@493 | 620 |
|
nkeynes@493 | 621 | void ide_write_buffer( unsigned char *data, uint32_t length )
|
nkeynes@493 | 622 | {
|
nkeynes@493 | 623 | switch( idereg.last_packet_command ) {
|
nkeynes@493 | 624 | case PKT_CMD_MODE_SELECT:
|
nkeynes@493 | 625 | if( idereg.current_lba < 10 ) {
|
nkeynes@493 | 626 | if( idereg.current_lba + length > 10 ) {
|
nkeynes@493 | 627 | length = 10 - idereg.current_lba;
|
nkeynes@493 | 628 | }
|
nkeynes@493 | 629 | memcpy( idereg.gdrom_mode + idereg.current_lba, data, length );
|
nkeynes@493 | 630 | }
|
nkeynes@493 | 631 | break;
|
nkeynes@493 | 632 | default:
|
nkeynes@493 | 633 | WARN( "Don't know what to do with received data buffer for command %02X", idereg.last_packet_command );
|
nkeynes@493 | 634 | }
|
nkeynes@493 | 635 | }
|