1 // Copyright (c) 2012- PPSSPP Project.
2 
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6 
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 // GNU General Public License 2.0 for more details.
11 
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14 
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17 
18 #include "Common/Serialize/Serializer.h"
19 #include "Common/Serialize/SerializeFuncs.h"
20 #include "Core/CoreTiming.h"
21 #include "Core/HLE/HLE.h"
22 #include "Core/HLE/FunctionWrappers.h"
23 #include "Core/HLE/KernelWaitHelpers.h"
24 #include "Core/HLE/sceKernelThread.h"
25 #include "Core/HLE/sceUsb.h"
26 #include "Core/MIPS/MIPS.h"
27 #include "Core/Reporting.h"
28 
29 static constexpr uint32_t ERROR_USB_WAIT_TIMEOUT = 0x80243008;
30 
31 // TODO: Map by driver name
32 static bool usbStarted = false;
33 // TODO: Check actual status
34 static bool usbConnected = true;
35 // TODO: Activation by product id
36 static bool usbActivated = false;
37 
38 static int usbWaitTimer = -1;
39 static std::vector<SceUID> waitingThreads;
40 
41 enum UsbStatus {
42 	USB_STATUS_STOPPED      = 0x001,
43 	USB_STATUS_STARTED      = 0x002,
44 	USB_STATUS_DISCONNECTED = 0x010,
45 	USB_STATUS_CONNECTED    = 0x020,
46 	USB_STATUS_DEACTIVATED  = 0x100,
47 	USB_STATUS_ACTIVATED    = 0x200,
48 };
49 
UsbCurrentState()50 static int UsbCurrentState() {
51 	int state = 0;
52 	if (usbStarted) {
53 		state = USB_STATUS_STARTED
54 			| (usbConnected ? USB_STATUS_CONNECTED : USB_STATUS_DISCONNECTED)
55 			| (usbActivated ? USB_STATUS_ACTIVATED : USB_STATUS_DEACTIVATED);
56 	}
57 	return state;
58 }
59 
UsbMatchState(int state,u32 mode)60 static bool UsbMatchState(int state, u32 mode) {
61 	int match = state & UsbCurrentState();
62 	if (mode == 0) {
63 		return match == state;
64 	}
65 	return match != 0;
66 }
67 
UsbSetTimeout(PSPPointer<int> timeout)68 static void UsbSetTimeout(PSPPointer<int> timeout) {
69 	if (!timeout.IsValid() || usbWaitTimer == -1)
70 		return;
71 
72 	// This should call __UsbWaitTimeout() later, unless we cancel it.
73 	CoreTiming::ScheduleEvent(usToCycles(*timeout), usbWaitTimer, __KernelGetCurThread());
74 }
75 
UsbWaitExecTimeout(u64 userdata,int cycleslate)76 static void UsbWaitExecTimeout(u64 userdata, int cycleslate) {
77 	u32 error;
78 	SceUID threadID = (SceUID)userdata;
79 
80 	PSPPointer<int> timeout = PSPPointer<int>::Create(__KernelGetWaitTimeoutPtr(threadID, error));
81 	if (timeout.IsValid())
82 		*timeout = 0;
83 
84 	HLEKernel::RemoveWaitingThread(waitingThreads, threadID);
85 	__KernelResumeThreadFromWait(threadID, ERROR_USB_WAIT_TIMEOUT);
86 	__KernelReSchedule("wait timed out");
87 }
88 
UsbUpdateState()89 static void UsbUpdateState() {
90 	u32 error;
91 	bool wokeThreads = false;
92 	for (size_t i = 0; i < waitingThreads.size(); ++i) {
93 		SceUID threadID = waitingThreads[i];
94 		int state = __KernelGetWaitID(threadID, WAITTYPE_USB, error);
95 		if (error != 0)
96 			continue;
97 
98 		u32 mode = __KernelGetWaitValue(threadID, error);
99 		if (UsbMatchState(state, mode)) {
100 			waitingThreads.erase(waitingThreads.begin() + i);
101 			--i;
102 
103 			PSPPointer<int> timeout = PSPPointer<int>::Create(__KernelGetWaitTimeoutPtr(threadID, error));
104 			if (timeout.IsValid() && usbWaitTimer != -1) {
105 				// Remove any event for this thread.
106 				s64 cyclesLeft = CoreTiming::UnscheduleEvent(usbWaitTimer, threadID);
107 				*timeout = (int)cyclesToUs(cyclesLeft);
108 			}
109 
110 			__KernelResumeThreadFromWait(threadID, UsbCurrentState());
111 		}
112 	}
113 
114 	if (wokeThreads)
115 		hleReSchedule("usb state change");
116 }
117 
__UsbInit()118 void __UsbInit() {
119 	usbStarted = false;
120 	usbConnected = true;
121 	usbActivated = false;
122 	waitingThreads.clear();
123 
124 	usbWaitTimer = CoreTiming::RegisterEvent("UsbWaitTimeout", UsbWaitExecTimeout);
125 }
126 
__UsbDoState(PointerWrap & p)127 void __UsbDoState(PointerWrap &p) {
128 	auto s = p.Section("sceUsb", 1, 3);
129 	if (!s)
130 		return;
131 
132 	if (s >= 2) {
133 		Do(p, usbStarted);
134 		Do(p, usbConnected);
135 	} else {
136 		usbStarted = false;
137 		usbConnected = true;
138 	}
139 	Do(p, usbActivated);
140 	if (s >= 3) {
141 		Do(p, waitingThreads);
142 		Do(p, usbWaitTimer);
143 	} else {
144 		waitingThreads.clear();
145 		usbWaitTimer = -1;
146 	}
147 	CoreTiming::RestoreRegisterEvent(usbWaitTimer, "UsbWaitTimeout", UsbWaitExecTimeout);
148 }
149 
sceUsbStart(const char * driverName,u32 argsSize,u32 argsPtr)150 static int sceUsbStart(const char* driverName, u32 argsSize, u32 argsPtr) {
151 	INFO_LOG(HLE, "sceUsbStart(%s, %i, %08x)", driverName, argsSize, argsPtr);
152 	usbStarted = true;
153 	UsbUpdateState();
154 	return 0;
155 }
156 
sceUsbStop(const char * driverName,u32 argsSize,u32 argsPtr)157 static int sceUsbStop(const char* driverName, u32 argsSize, u32 argsPtr) {
158 	INFO_LOG(HLE, "sceUsbStop(%s, %i, %08x)", driverName, argsSize, argsPtr);
159 	usbStarted = false;
160 	UsbUpdateState();
161 	return 0;
162 }
163 
sceUsbGetState()164 static int sceUsbGetState() {
165 	int state = 0;
166 	if (!usbStarted) {
167 		state = 0x80243007;
168 	} else {
169 		state = UsbCurrentState();
170 	}
171 	DEBUG_LOG(HLE, "sceUsbGetState: 0x%x", state);
172 	return state;
173 }
174 
sceUsbActivate(u32 pid)175 static int sceUsbActivate(u32 pid) {
176 	INFO_LOG(HLE, "sceUsbActivate(%i)", pid);
177 	usbActivated = true;
178 	UsbUpdateState();
179 	return 0;
180 }
181 
sceUsbDeactivate(u32 pid)182 static int sceUsbDeactivate(u32 pid) {
183 	INFO_LOG(HLE, "sceUsbDeactivate(%i)", pid);
184 	usbActivated = false;
185 	UsbUpdateState();
186 	return 0;
187 }
188 
sceUsbWaitState(int state,u32 waitMode,u32 timeoutPtr)189 static int sceUsbWaitState(int state, u32 waitMode, u32 timeoutPtr) {
190 	hleEatCycles(10000);
191 
192 	if (waitMode >= 2)
193 		return hleLogError(HLE, SCE_KERNEL_ERROR_ILLEGAL_MODE, "invalid mode");
194 	if (state == 0)
195 		return hleLogError(HLE, SCE_KERNEL_ERROR_EVF_ILPAT, "bad state");
196 
197 	if (UsbMatchState(state, waitMode)) {
198 		return hleLogSuccessX(HLE, UsbCurrentState());
199 	}
200 
201 	// We'll have to wait as long as it takes.  Cleanup first, just in case.
202 	HLEKernel::RemoveWaitingThread(waitingThreads, __KernelGetCurThread());
203 	waitingThreads.push_back(__KernelGetCurThread());
204 
205 	UsbSetTimeout(PSPPointer<int>::Create(timeoutPtr));
206 	__KernelWaitCurThread(WAITTYPE_USB, state, waitMode, timeoutPtr, false, "usb state waited");
207 	return hleLogSuccessI(HLE, 0, "waiting");
208 }
209 
sceUsbWaitStateCB(int state,u32 waitMode,u32 timeoutPtr)210 static int sceUsbWaitStateCB(int state, u32 waitMode, u32 timeoutPtr) {
211 	ERROR_LOG_REPORT(HLE, "UNIMPL sceUsbWaitStateCB(%i, %i, %08x)", state, waitMode, timeoutPtr);
212 	return 0;
213 }
214 
sceUsbstorBootSetCapacity(u32 capacity)215 static int sceUsbstorBootSetCapacity(u32 capacity) {
216 	return hleReportError(HLE, 0, "unimplemented");
217 }
218 
219 const HLEFunction sceUsb[] =
220 {
221 	{0XAE5DE6AF, &WrapI_CUU<sceUsbStart>,            "sceUsbStart",                             'i', "sxx"},
222 	{0XC2464FA0, &WrapI_CUU<sceUsbStop>,             "sceUsbStop",                              'i', "sxx"},
223 	{0XC21645A4, &WrapI_V<sceUsbGetState>,           "sceUsbGetState",                          'i', ""   },
224 	{0X4E537366, nullptr,                            "sceUsbGetDrvList",                        '?', ""   },
225 	{0X112CC951, nullptr,                            "sceUsbGetDrvState",                       '?', ""   },
226 	{0X586DB82C, &WrapI_U<sceUsbActivate>,           "sceUsbActivate",                          'i', "x"  },
227 	{0XC572A9C8, &WrapI_U<sceUsbDeactivate>,         "sceUsbDeactivate",                        'i', "x"  },
228 	{0X5BE0E002, &WrapI_IUU<sceUsbWaitState>,        "sceUsbWaitState",                         'x', "xip"},
229 	{0X616F2B61, &WrapI_IUU<sceUsbWaitStateCB>,      "sceUsbWaitStateCB",                       'x', "xip"},
230 	{0X1C360735, nullptr,                            "sceUsbWaitCancel",                        '?', ""   },
231 };
232 
233 const HLEFunction sceUsbstor[] =
234 {
235 	{0X60066CFE, nullptr,                            "sceUsbstorGetStatus",                     '?', ""   },
236 };
237 
238 const HLEFunction sceUsbstorBoot[] =
239 {
240 	{0XE58818A8, &WrapI_U<sceUsbstorBootSetCapacity>,"sceUsbstorBootSetCapacity",               'i', "x"  },
241 	{0X594BBF95, nullptr,                            "sceUsbstorBootSetLoadAddr",               '?', ""   },
242 	{0X6D865ECD, nullptr,                            "sceUsbstorBootGetDataSize",               '?', ""   },
243 	{0XA1119F0D, nullptr,                            "sceUsbstorBootSetStatus",                 '?', ""   },
244 	{0X1F080078, nullptr,                            "sceUsbstorBootRegisterNotify",            '?', ""   },
245 	{0XA55C9E16, nullptr,                            "sceUsbstorBootUnregisterNotify",          '?', ""   },
246 };
247 
Register_sceUsb()248 void Register_sceUsb()
249 {
250 	RegisterModule("sceUsbstor", ARRAY_SIZE(sceUsbstor), sceUsbstor);
251 	RegisterModule("sceUsbstorBoot", ARRAY_SIZE(sceUsbstorBoot), sceUsbstorBoot);
252 	RegisterModule("sceUsb", ARRAY_SIZE(sceUsb), sceUsb);
253 }
254