-
-
Notifications
You must be signed in to change notification settings - Fork 93
/
blockdevice.c
137 lines (117 loc) · 2.86 KB
/
blockdevice.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
* Copyright (c) 2019-2022, Extrems <extrems@extremscorner.org>
*
* This file is part of Swiss.
*
* Swiss is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Swiss is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* with Swiss. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdbool.h>
#include "common.h"
#include "dolphin/exi.h"
#include "dolphin/os.h"
#include "emulator.h"
#include "frag.h"
#include "ipl.h"
static struct {
void *buffer;
uint32_t length;
uint32_t offset;
bool read;
} dvd;
bool do_read_disc(void *buffer, uint32_t length, uint32_t offset, const frag_t *frag, frag_callback callback)
{
return do_read_write_async(buffer, length, offset, frag->sector, false, callback);
}
void schedule_read(OSTick ticks)
{
#ifdef ASYNC_READ
void read_callback(void *address, uint32_t length)
{
dvd.buffer += length;
dvd.length -= length;
dvd.offset += length;
dvd.read = !!dvd.length;
schedule_read(0);
}
#else
OSCancelAlarm(&read_alarm);
#endif
if (!dvd.read) {
di_complete_transfer();
return;
}
#ifdef ASYNC_READ
frag_read_async(*VAR_CURRENT_DISC, dvd.buffer, dvd.length, dvd.offset, read_callback);
#else
OSSetAlarm(&read_alarm, ticks, trickle_read);
#endif
}
void perform_read(uint32_t address, uint32_t length, uint32_t offset)
{
if ((*VAR_IGR_TYPE & 0x80) && offset == 0x2440) {
*VAR_CURRENT_DISC = FRAGS_APPLOADER;
*VAR_SECOND_DISC = 0;
}
dvd.buffer = OSPhysicalToUncached(address);
dvd.length = length;
dvd.offset = offset;
dvd.read = true;
#ifdef DVD_MATH
void alarm_handler(OSAlarm *alarm, OSContext *context)
{
schedule_read(0);
}
if (*VAR_EMU_READ_SPEED) {
dvd_schedule_read(offset, length, alarm_handler);
return;
}
#endif
schedule_read(0);
}
#ifndef ASYNC_READ
void trickle_read()
{
#ifdef DTK
if (dtk_fill_buffer())
return;
#endif
if (dvd.read) {
OSTick start = OSGetTick();
int size = frag_read(*VAR_CURRENT_DISC, dvd.buffer, dvd.length, dvd.offset);
OSTick end = OSGetTick();
dvd.buffer += size;
dvd.length -= size;
dvd.offset += size;
dvd.read = !!dvd.length;
schedule_read(OSDiffTick(end, start));
}
}
#endif
bool change_disc(void)
{
if (*VAR_SECOND_DISC) {
*VAR_CURRENT_DISC ^= 1;
return true;
}
return false;
}
void reset_devices(void)
{
while (EXI[EXI_CHANNEL_0][3] & 0b000001);
while (EXI[EXI_CHANNEL_1][3] & 0b000001);
while (EXI[EXI_CHANNEL_2][3] & 0b000001);
reset_device();
ipl_set_config(0);
}