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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
|
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <boost/serialization/array.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include "audio_core/dsp_interface.h"
#include "core/hle/kernel/event.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Service::DSP {
/// There are three types of interrupts
enum class InterruptType : u32 { Zero = 0, One = 1, Pipe = 2, Count };
class DSP_DSP final : public ServiceFramework<DSP_DSP> {
public:
explicit DSP_DSP(Core::System& system);
~DSP_DSP();
/// Actual service implementation only has 6 'slots' for interrupts.
static constexpr std::size_t max_number_of_interrupt_events = 6;
/// Signal interrupt on pipe
void SignalInterrupt(InterruptType type, AudioCore::DspPipe pipe);
private:
/**
* DSP_DSP::RecvData service function
* This function reads a value out of a DSP register.
* Inputs:
* 0 : Header Code[0x00010040]
* 1 : Register Number
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u16, Value in the register
* Notes:
* This function has only been observed being called with a register number of 0.
*/
void RecvData(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::RecvDataIsReady service function
* This function checks whether a DSP register is ready to be read.
* Inputs:
* 0 : Header Code[0x00020040]
* 1 : Register Number
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Reply Register Update Flag (0 = not ready, 1 = ready)
* Note:
* This function has only been observed being called with a register number of 0.
*/
void RecvDataIsReady(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::SetSemaphore service function
* Inputs:
* 0 : Header Code[0x00070040]
* 1 : u16, Semaphore value
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void SetSemaphore(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::ConvertProcessAddressFromDspDram service function
* Inputs:
* 0 : Header Code[0x000C0040]
* 1 : Address
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Address. (inaddr << 1) + 0x1FF40000 (where 0x1FF00000 is the DSP RAM address)
*/
void ConvertProcessAddressFromDspDram(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::WriteProcessPipe service function
* Inputs:
* 0 : Header Code[0x000D0082]
* 1 : Channel (0 - 7 0:Debug from DSP 1:P-DMA 2:audio 3:binary 4-7: free ?)
* 2 : Size
* 3 : (size << 14) | 0x402
* 4 : Buffer
* Outputs:
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
void WriteProcessPipe(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::ReadPipe service function
* Inputs:
* 0 : Header Code[0x000E00C0]
* 1 : Channel (0 - 7 0:Debug from DSP 1:P-DMA 2:audio 3:binary 4-7: free ?)
* 2 : Peer (0 = from DSP, 1 = from ARM)
* 3 : u16, Size
* 0x41 : Virtual address of memory buffer to write pipe contents to
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void ReadPipe(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::GetPipeReadableSize service function
* Inputs:
* 0 : Header Code[0x000F0080]
* 1 : Channel (0 - 7 0:Debug from DSP 1:P-DMA 2:audio 3:binary 4-7: free ?)
* 2 : Peer (0 = from DSP, 1 = from ARM)
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u16, Readable size
*/
void GetPipeReadableSize(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::ReadPipeIfPossible service function
* A pipe is a means of communication between the ARM11 and DSP that occurs on
* hardware by writing to/reading from the DSP registers at 0x10203000.
* Pipes are used for initialisation. See also DspInterface::PipeRead.
* Inputs:
* 0 : Header Code[0x001000C0]
* 1 : Channel (0 - 7 0:Debug from DSP 1:P-DMA 2:audio 3:binary 4-7: free ?)
* 2 : Peer (0 = from DSP, 1 = from ARM)
* 3 : u16, Size
* 0x41 : Virtual address of memory buffer to write pipe contents to
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u16, Actual read size
*/
void ReadPipeIfPossible(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::LoadComponent service function
* Inputs:
* 0 : Header Code[0x001100C2]
* 1 : Size
* 2 : Program mask (observed only half word used)
* 3 : Data mask (observed only half word used)
* 4 : (size << 4) | 0xA
* 5 : Component Buffer
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u8, Component Loaded (0 = not loaded, 1 = loaded)
* 3 : (Size << 4) | 0xA
* 4 : Component Buffer
*/
void LoadComponent(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::UnloadComponent service function
* Inputs:
* 0 : Header Code[0x00120000]
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void UnloadComponent(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::FlushDataCache service function
*
* This Function is a no-op, We aren't emulating the CPU cache any time soon.
*
* Inputs:
* 0 : Header Code[0x00130082]
* 1 : Address
* 2 : Size
* 3 : Value 0, some descriptor for the KProcess Handle
* 4 : KProcess handle
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void FlushDataCache(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::InvalidateDataCache service function
*
* This Function is a no-op, We aren't emulating the CPU cache any time soon.
*
* Inputs:
* 0 : Header Code[0x00140082]
* 1 : Address
* 2 : Size
* 3 : Value 0, some descriptor for the KProcess Handle
* 4 : KProcess handle
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void InvalidateDataCache(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::RegisterInterruptEvents service function
* Inputs:
* 0 : Header Code[0x00150082]
* 1 : Interrupt
* 2 : Channel
* 3 : 0x0, some descriptor for the Event Handle
* 4 : Interrupt Event handle (0 = unregister the event that was previous registered)
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void RegisterInterruptEvents(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::GetSemaphoreEventHandle service function
* Inputs:
* 0 : Header Code[0x00160000]
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : 0x0, some descriptor for the Event Handle
* 3 : Semaphore Event Handle
*/
void GetSemaphoreEventHandle(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::SetSemaphoreMask service function
* Inputs:
* 0 : Header Code[0x00170040]
* 1 : u16, Mask
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void SetSemaphoreMask(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::GetHeadphoneStatus service function
* Inputs:
* 0 : Header Code[0x001F0000]
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u8, The headphone status response, 0 = Not inserted, 1 = inserted
*/
void GetHeadphoneStatus(Kernel::HLERequestContext& ctx);
/**
* DSP_DSP::ForceHeadphoneOut service function
* Inputs:
* 0 : Header Code[0x00020040]
* 1 : u8, 0 = don't force, 1 = force
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void ForceHeadphoneOut(Kernel::HLERequestContext& ctx);
/// Returns the Interrupt Event for a given pipe
std::shared_ptr<Kernel::Event>& GetInterruptEvent(InterruptType type, AudioCore::DspPipe pipe);
/// Checks if we are trying to register more than 6 events
bool HasTooManyEventsRegistered() const;
Core::System& system;
std::shared_ptr<Kernel::Event> semaphore_event;
u16 preset_semaphore = 0;
std::shared_ptr<Kernel::Event> interrupt_zero = nullptr; /// Currently unknown purpose
std::shared_ptr<Kernel::Event> interrupt_one = nullptr; /// Currently unknown purpose
/// Each DSP pipe has an associated interrupt
std::array<std::shared_ptr<Kernel::Event>, AudioCore::num_dsp_pipe> pipes = {{}};
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
ar& semaphore_event;
ar& preset_semaphore;
ar& interrupt_zero;
ar& interrupt_one;
ar& pipes;
}
friend class boost::serialization::access;
};
void InstallInterfaces(Core::System& system);
} // namespace Service::DSP
BOOST_CLASS_EXPORT_KEY(Service::DSP::DSP_DSP)
SERVICE_CONSTRUCT(Service::DSP::DSP_DSP)
|