nkeynes@87 | 1 | /**
|
nkeynes@586 | 2 | * $Id$
|
nkeynes@87 | 3 | *
|
nkeynes@87 | 4 | * "Fake" BIOS functions, for operation without the actual BIOS.
|
nkeynes@87 | 5 | *
|
nkeynes@87 | 6 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@87 | 7 | *
|
nkeynes@87 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@87 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@87 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@87 | 11 | * (at your option) any later version.
|
nkeynes@87 | 12 | *
|
nkeynes@87 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@87 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@87 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@87 | 16 | * GNU General Public License for more details.
|
nkeynes@87 | 17 | */
|
nkeynes@87 | 18 |
|
nkeynes@87 | 19 | #include "dream.h"
|
nkeynes@87 | 20 | #include "mem.h"
|
nkeynes@102 | 21 | #include "syscall.h"
|
nkeynes@422 | 22 | #include "dreamcast.h"
|
nkeynes@586 | 23 | #include "sh4/sh4.h"
|
nkeynes@87 | 24 |
|
nkeynes@87 | 25 | #define COMMAND_QUEUE_LENGTH 16
|
nkeynes@87 | 26 |
|
nkeynes@87 | 27 | /* TODO: Check if these are the real ATAPI command codes or not */
|
nkeynes@87 | 28 | #define GD_CMD_PIOREAD 16
|
nkeynes@87 | 29 | #define GD_CMD_DMAREAD 17
|
nkeynes@87 | 30 | #define GD_CMD_GETTOC 18
|
nkeynes@87 | 31 | #define GD_CMD_GETTOC2 19
|
nkeynes@87 | 32 | #define GD_CMD_PLAY 20
|
nkeynes@87 | 33 | #define GD_CMD_PLAY2 21
|
nkeynes@87 | 34 | #define GD_CMD_PAUSE 22
|
nkeynes@87 | 35 | #define GD_CMD_RELEASE 23
|
nkeynes@87 | 36 | #define GD_CMD_INIT 24
|
nkeynes@87 | 37 | #define GD_CMD_SEEK 27
|
nkeynes@87 | 38 | #define GD_CMD_READ 28
|
nkeynes@87 | 39 | #define GD_CMD_STOP 33
|
nkeynes@87 | 40 | #define GD_CMD_GETSCD 34
|
nkeynes@87 | 41 | #define GD_CMD_GETSES 35
|
nkeynes@87 | 42 |
|
nkeynes@87 | 43 | #define GD_CMD_STATUS_NONE 0
|
nkeynes@87 | 44 | #define GD_CMD_STATUS_ACTIVE 1
|
nkeynes@87 | 45 | #define GD_CMD_STATUS_DONE 2
|
nkeynes@87 | 46 | #define GD_CMD_STATUS_ABORT 3
|
nkeynes@87 | 47 | #define GD_CMD_STATUS_ERROR 4
|
nkeynes@87 | 48 |
|
nkeynes@87 | 49 | #define GD_ERROR_OK 0
|
nkeynes@87 | 50 | #define GD_ERROR_NO_DISC 2
|
nkeynes@87 | 51 | #define GD_ERROR_DISC_CHANGE 6
|
nkeynes@87 | 52 | #define GD_ERROR_SYSTEM 1
|
nkeynes@87 | 53 |
|
nkeynes@87 | 54 |
|
nkeynes@87 | 55 | typedef struct gdrom_command {
|
nkeynes@87 | 56 | int status;
|
nkeynes@87 | 57 | uint32_t cmd_code;
|
nkeynes@502 | 58 | sh4ptr_t data;
|
nkeynes@87 | 59 | uint32_t result[4];
|
nkeynes@87 | 60 | } *gdrom_command_t;
|
nkeynes@87 | 61 |
|
nkeynes@87 | 62 | static struct gdrom_command gdrom_cmd_queue[COMMAND_QUEUE_LENGTH];
|
nkeynes@87 | 63 |
|
nkeynes@87 | 64 | static struct bios_gdrom_status {
|
nkeynes@87 | 65 | uint32_t status;
|
nkeynes@87 | 66 | uint32_t disk_type;
|
nkeynes@87 | 67 | } bios_gdrom_status;
|
nkeynes@87 | 68 |
|
nkeynes@87 | 69 | void bios_gdrom_run_command( gdrom_command_t cmd )
|
nkeynes@87 | 70 | {
|
nkeynes@87 | 71 | DEBUG( "BIOS GD command %d", cmd->cmd_code );
|
nkeynes@87 | 72 | switch( cmd->cmd_code ) {
|
nkeynes@87 | 73 | case GD_CMD_INIT:
|
nkeynes@87 | 74 | /* *shrug* */
|
nkeynes@87 | 75 | cmd->status = GD_CMD_STATUS_DONE;
|
nkeynes@87 | 76 | break;
|
nkeynes@87 | 77 | default:
|
nkeynes@87 | 78 | cmd->status = GD_CMD_STATUS_ERROR;
|
nkeynes@87 | 79 | cmd->result[0] = GD_ERROR_SYSTEM;
|
nkeynes@87 | 80 | break;
|
nkeynes@87 | 81 | }
|
nkeynes@87 | 82 | }
|
nkeynes@87 | 83 |
|
nkeynes@87 | 84 | void bios_gdrom_init( void )
|
nkeynes@87 | 85 | {
|
nkeynes@87 | 86 | memset( &gdrom_cmd_queue, 0, sizeof(gdrom_cmd_queue) );
|
nkeynes@87 | 87 | }
|
nkeynes@87 | 88 |
|
nkeynes@502 | 89 | uint32_t bios_gdrom_enqueue( uint32_t cmd, sh4ptr_t ptr )
|
nkeynes@87 | 90 | {
|
nkeynes@87 | 91 | int i;
|
nkeynes@87 | 92 | for( i=0; i<COMMAND_QUEUE_LENGTH; i++ ) {
|
nkeynes@87 | 93 | if( gdrom_cmd_queue[i].status != GD_CMD_STATUS_ACTIVE ) {
|
nkeynes@87 | 94 | gdrom_cmd_queue[i].status = GD_CMD_STATUS_ACTIVE;
|
nkeynes@87 | 95 | gdrom_cmd_queue[i].cmd_code = cmd;
|
nkeynes@87 | 96 | gdrom_cmd_queue[i].data = ptr;
|
nkeynes@87 | 97 | return i;
|
nkeynes@87 | 98 | }
|
nkeynes@87 | 99 | }
|
nkeynes@87 | 100 | return -1;
|
nkeynes@87 | 101 | }
|
nkeynes@87 | 102 |
|
nkeynes@87 | 103 | void bios_gdrom_run_queue( void )
|
nkeynes@87 | 104 | {
|
nkeynes@87 | 105 | int i;
|
nkeynes@87 | 106 | for( i=0; i<COMMAND_QUEUE_LENGTH; i++ ) {
|
nkeynes@87 | 107 | if( gdrom_cmd_queue[i].status == GD_CMD_STATUS_ACTIVE ) {
|
nkeynes@87 | 108 | bios_gdrom_run_command( &gdrom_cmd_queue[i] );
|
nkeynes@87 | 109 | }
|
nkeynes@87 | 110 | }
|
nkeynes@87 | 111 | }
|
nkeynes@87 | 112 |
|
nkeynes@87 | 113 | gdrom_command_t bios_gdrom_get_command( uint32_t id )
|
nkeynes@87 | 114 | {
|
nkeynes@87 | 115 | if( id >= COMMAND_QUEUE_LENGTH ||
|
nkeynes@87 | 116 | gdrom_cmd_queue[id].status == GD_CMD_STATUS_NONE )
|
nkeynes@87 | 117 | return NULL;
|
nkeynes@87 | 118 | return &gdrom_cmd_queue[id];
|
nkeynes@87 | 119 | }
|
nkeynes@87 | 120 |
|
nkeynes@87 | 121 | /**
|
nkeynes@87 | 122 | * Syscall list courtesy of Marcus Comstedt
|
nkeynes@87 | 123 | */
|
nkeynes@87 | 124 |
|
nkeynes@87 | 125 | void bios_syscall( uint32_t syscallid )
|
nkeynes@87 | 126 | {
|
nkeynes@87 | 127 | gdrom_command_t cmd;
|
nkeynes@87 | 128 |
|
nkeynes@87 | 129 | switch( syscallid ) {
|
nkeynes@87 | 130 | case 0xB0: /* sysinfo */
|
nkeynes@87 | 131 | break;
|
nkeynes@87 | 132 | case 0xB4: /* Font */
|
nkeynes@87 | 133 | break;
|
nkeynes@87 | 134 | case 0xB8: /* Flash */
|
nkeynes@87 | 135 | break;
|
nkeynes@87 | 136 | case 0xBC: /* Misc/GD-Rom */
|
nkeynes@87 | 137 | switch( sh4r.r[6] ) {
|
nkeynes@87 | 138 | case 0: /* GD-Rom */
|
nkeynes@87 | 139 | switch( sh4r.r[7] ) {
|
nkeynes@87 | 140 | case 0: /* Send command */
|
nkeynes@87 | 141 | if( sh4r.r[5] == 0 )
|
nkeynes@87 | 142 | sh4r.r[0] = bios_gdrom_enqueue( sh4r.r[4], NULL );
|
nkeynes@87 | 143 | else
|
nkeynes@87 | 144 | sh4r.r[0] = bios_gdrom_enqueue( sh4r.r[4], mem_get_region(sh4r.r[5]) );
|
nkeynes@87 | 145 | break;
|
nkeynes@87 | 146 | case 1: /* Check command */
|
nkeynes@87 | 147 | cmd = bios_gdrom_get_command( sh4r.r[4] );
|
nkeynes@87 | 148 | if( cmd == NULL ) {
|
nkeynes@87 | 149 | sh4r.r[0] = GD_CMD_STATUS_NONE;
|
nkeynes@87 | 150 | } else {
|
nkeynes@87 | 151 | sh4r.r[0] = cmd->status;
|
nkeynes@87 | 152 | if( cmd->status == GD_CMD_STATUS_ERROR &&
|
nkeynes@87 | 153 | sh4r.r[5] != 0 ) {
|
nkeynes@502 | 154 | mem_copy_to_sh4( sh4r.r[5], (sh4ptr_t)&cmd->result, sizeof(cmd->result) );
|
nkeynes@87 | 155 | }
|
nkeynes@87 | 156 | }
|
nkeynes@87 | 157 | break;
|
nkeynes@87 | 158 | case 2: /* Mainloop */
|
nkeynes@87 | 159 | bios_gdrom_run_queue();
|
nkeynes@87 | 160 | break;
|
nkeynes@87 | 161 | case 3: /* Init */
|
nkeynes@87 | 162 | bios_gdrom_init();
|
nkeynes@87 | 163 | break;
|
nkeynes@87 | 164 | case 4: /* Drive status */
|
nkeynes@87 | 165 | if( sh4r.r[4] != 0 ) {
|
nkeynes@502 | 166 | mem_copy_to_sh4( sh4r.r[4], (sh4ptr_t)&bios_gdrom_status,
|
nkeynes@87 | 167 | sizeof(bios_gdrom_status) );
|
nkeynes@87 | 168 | }
|
nkeynes@87 | 169 | sh4r.r[0] = 0;
|
nkeynes@87 | 170 | break;
|
nkeynes@87 | 171 | case 8: /* Abort command */
|
nkeynes@87 | 172 | cmd = bios_gdrom_get_command( sh4r.r[4] );
|
nkeynes@87 | 173 | if( cmd == NULL || cmd->status != GD_CMD_STATUS_ACTIVE ) {
|
nkeynes@87 | 174 | sh4r.r[0] = -1;
|
nkeynes@87 | 175 | } else {
|
nkeynes@87 | 176 | cmd->status = GD_CMD_STATUS_ABORT;
|
nkeynes@87 | 177 | sh4r.r[0] = 0;
|
nkeynes@87 | 178 | }
|
nkeynes@87 | 179 | break;
|
nkeynes@87 | 180 | case 9: /* Reset */
|
nkeynes@87 | 181 | break;
|
nkeynes@87 | 182 | case 10: /* Set mode */
|
nkeynes@87 | 183 | sh4r.r[0] = 0;
|
nkeynes@87 | 184 | break;
|
nkeynes@87 | 185 | }
|
nkeynes@87 | 186 | break;
|
nkeynes@87 | 187 | case -1: /* Misc */
|
nkeynes@87 | 188 | break;
|
nkeynes@87 | 189 | default: /* ??? */
|
nkeynes@87 | 190 | break;
|
nkeynes@87 | 191 | }
|
nkeynes@87 | 192 | break;
|
nkeynes@87 | 193 | case 0xE0: /* Menu */
|
nkeynes@87 | 194 | switch( sh4r.r[7] ) {
|
nkeynes@87 | 195 | case 0:
|
nkeynes@87 | 196 | WARN( "Entering main program" );
|
nkeynes@87 | 197 | break;
|
nkeynes@87 | 198 | case 1:
|
nkeynes@87 | 199 | WARN( "Program aborted to DC menu");
|
nkeynes@87 | 200 | dreamcast_stop();
|
nkeynes@87 | 201 | break;
|
nkeynes@87 | 202 | }
|
nkeynes@87 | 203 | }
|
nkeynes@87 | 204 | }
|
nkeynes@102 | 205 |
|
nkeynes@102 | 206 | void bios_install( void )
|
nkeynes@102 | 207 | {
|
nkeynes@102 | 208 | bios_gdrom_init();
|
nkeynes@102 | 209 | syscall_add_hook_vector( 0xB0, 0x8C0000B0, bios_syscall );
|
nkeynes@102 | 210 | syscall_add_hook_vector( 0xB4, 0x8C0000B4, bios_syscall );
|
nkeynes@102 | 211 | syscall_add_hook_vector( 0xB8, 0x8C0000B8, bios_syscall );
|
nkeynes@102 | 212 | syscall_add_hook_vector( 0xBC, 0x8C0000BC, bios_syscall );
|
nkeynes@102 | 213 | syscall_add_hook_vector( 0xE0, 0x8C0000E0, bios_syscall );
|
nkeynes@102 | 214 | }
|