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