Implemented MU support to xapi functions

This commit is contained in:
ergo720 2021-06-18 01:37:31 +02:00
parent 4cf90a6170
commit 88a786b700
7 changed files with 225 additions and 71 deletions

View File

@ -117,18 +117,19 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd)
for (unsigned i = 0; i < 4; ++i) {
int type;
g_EmuShared->GetInputDevTypeSettings(&type, i);
std::string port = std::to_string(i);
if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) {
std::string port = std::to_string(i);
switch (type)
{
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE):
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): {
ConstructHleInputDevice(&g_devs[CTRL_OFFSET + i], nullptr, type, port);
BindHostDevice(type, port);
for (unsigned slot = 0; slot < XBOX_CTRL_NUM_SLOTS; ++slot) {
g_EmuShared->GetInputSlotTypeSettings(&type, i, slot);
if (type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) {
assert(type == to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT));
ConstructHleInputDevice(&g_devs[MU_OFFSET + slot], &g_devs[CTRL_OFFSET + i], type, port + std::to_string(slot));
ConstructHleInputDevice(&g_devs[MU_OFFSET + slot], &g_devs[CTRL_OFFSET + i], type, port + "." + std::to_string(slot));
}
}
}
@ -137,6 +138,7 @@ void InputDeviceManager::Initialize(bool is_gui, HWND hwnd)
case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK):
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER):
ConstructHleInputDevice(&g_devs[CTRL_OFFSET + i], nullptr, type, port);
BindHostDevice(type, port);
break;
default:
@ -224,8 +226,8 @@ void InputDeviceManager::UpdateDevices(std::string_view port, bool ack)
{
DeviceState *dev, *upstream;
int port1, type, slot;
dev = &g_devs[port1];
PortStr2Int(port, &port1, &slot);
dev = &g_devs[port1];
if (slot == PORT_INVALID) { // Port references a device attached to an xbox port
upstream = nullptr;

View File

@ -59,10 +59,38 @@ std::atomic<bool> g_bIsDevicesEmulating = false;
// Protects access to xpp types
std::atomic<bool> g_bXppGuard = false;
// allocate enough memory for the max number of devices we can support simultaneously
// Allocate enough memory for the max number of devices we can support simultaneously
// 4 duke / S / sbc / arcade joystick (mutually exclusive) + 8 memory units
DeviceState g_devs[4 + 8];
xbox::ulong_xt g_Mounted_MUs = 0; // fallback if XapiMountedMUs is not found
xbox::ulong_xt *g_XapiMountedMUs = &g_Mounted_MUs;
std::mutex g_MuLock;
static inline xbox::char_xt MuPort2Lett(xbox::dword_xt port, xbox::dword_xt slot)
{
return 'F' + (XBOX_CTRL_NUM_SLOTS * port) + slot;
}
static inline int MuPort2Idx(xbox::dword_xt port, xbox::dword_xt slot)
{
return (port << 1) + slot;
}
static inline bool MuIsMounted(xbox::char_xt lett)
{
return *g_XapiMountedMUs & (1 << (lett - 'F'));
}
static inline void MuSetMounted(xbox::char_xt lett)
{
*g_XapiMountedMUs |= (1 << (lett - 'F'));
}
static inline void MuClearMounted(xbox::char_xt lett)
{
*g_XapiMountedMUs &= ~(1 << (lett - 'F'));
}
bool operator==(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType)
{
@ -103,7 +131,7 @@ bool operator==(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType)
void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view port)
{
xbox::PXPP_DEVICE_TYPE xpp;
xbox::PXPP_DEVICE_TYPE xpp = nullptr;
switch (type)
{
case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE:
@ -121,44 +149,38 @@ void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view p
break;
default:
xpp = nullptr;
assert(0);
}
assert(xpp != nullptr);
if (xpp == nullptr) {
// This will happen with xbes that act like launchers, and don't link against the xinput libraries, which results in all the global
// xpp types being nullptr. Test case: Innocent Tears
return;
}
int port1, slot;
PortStr2Int(port, &port1, &slot);
xbox::ulong_xt port_mask = 1 << port1;
xbox::ulong_xt slot_mask = 0;
// Guard against the unfortunate case where XGetDevices or XGetDeviceChanges have already checked for g_bIsDevicesInitializing
// and g_bIsDevicesEmulating and a thread switch happens to this function
while (g_bXppGuard) {}
if (xpp == g_DeviceType_MU) {
if ((dev->upstream->type != XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) ||
(dev->upstream->type != XBOX_INPUT_DEVICE::MS_CONTROLLER_S) ||
dev->upstream->bPendingRemoval) {
xpp->CurrentConnected &= ~port_mask;
xpp->CurrentConnected &= ~(port_mask << 16);
}
else {
for (unsigned i = 0, j = 0; i < XBOX_CTRL_NUM_SLOTS; ++i, j += 16) {
if (xpp == dev->type && !dev->bPendingRemoval) {
xpp->CurrentConnected |= (port_mask << j);
}
else {
xpp->CurrentConnected &= ~(port_mask << j);
}
}
assert((dev->upstream->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) ||
(dev->upstream->type == XBOX_INPUT_DEVICE::MS_CONTROLLER_S));
assert(slot != PORT_INVALID);
if (slot == 1) {
slot_mask = 16;
}
}
if (xpp == dev->type && !dev->bPendingRemoval) {
xpp->CurrentConnected |= (port_mask << slot_mask);
}
else {
if (xpp == dev->type && !dev->bPendingRemoval) {
xpp->CurrentConnected |= port_mask;
}
else {
xpp->CurrentConnected &= ~port_mask;
}
xpp->CurrentConnected &= ~(port_mask << slot_mask);
}
xpp->ChangeConnected = xpp->PreviousConnected ^ xpp->CurrentConnected;
@ -425,6 +447,34 @@ void SetupXboxDeviceTypes()
else {
EmuLog(LOG_LEVEL::INFO, "XDEVICE_TYPE_MEMORY_UNIT was not found because MU_Init could not be found");
}
// Temporary code until XapiMountedMUs is derived by XbSymbolDatabase
Xbe::LibraryVersion *pLibraryVersion = reinterpret_cast<Xbe::LibraryVersion *>(CxbxKrnl_Xbe->m_Header.dwLibraryVersionsAddr);
if (pLibraryVersion != nullptr) {
if (uint8_t *start = reinterpret_cast<uint8_t *>(g_SymbolAddresses["XUnmountMU"])) {
uint32_t offset = 0;
for (unsigned v = 0; v < CxbxKrnl_Xbe->m_Header.dwLibraryVersions; ++v) {
if (std::strcmp(pLibraryVersion[v].szName, "XAPILIB") == 0) {
if (pLibraryVersion[v].wBuildVersion < 4242) {
offset = 0x1D;
}
else {
offset = 0x2A;
}
break;
}
}
// skip 2 because the address is hard-coded inside a test instruction
g_XapiMountedMUs = reinterpret_cast<xbox::ulong_xt *>(*reinterpret_cast<uint32_t *>((g_SymbolAddresses["XUnmountMU"] + offset + 2)));
EmuLog(LOG_LEVEL::INFO, "XapiMountedMUs found at 0x%08X", reinterpret_cast<uintptr_t>(g_XapiMountedMUs));
}
else {
EmuLog(LOG_LEVEL::WARNING, "XapiMountedMUs was not found because XUnmountMU could not be found");
}
}
else {
EmuLog(LOG_LEVEL::WARNING, "XapiMountedMUs was not found because this xbe does not have a library version address");
}
}
template<bool IsXInputPoll>
@ -1318,18 +1368,28 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XMountMUA)
PCHAR pchDrive
)
{
LOG_FUNC_BEGIN
LOG_FUNC_ARG(dwPort)
LOG_FUNC_ARG(dwSlot)
LOG_FUNC_ARG(pchDrive)
LOG_FUNC_END;
// TODO: Actually allow memory card emulation? This might make transferring
// game saves a bit easier if the memory card directory was configurable. =]
std::lock_guard lock(g_MuLock);
RETURN(E_FAIL);
char lett = MuPort2Lett(dwPort, dwSlot);
if (MuIsMounted(lett)) {
if (pchDrive != zeroptr) {
*pchDrive = lett;
}
RETURN(ERROR_ALREADY_ASSIGNED);
}
MuSetMounted(lett);
if (pchDrive != zeroptr) {
*pchDrive = lett;
}
RETURN(ERROR_SUCCESS);
}
// ******************************************************************
@ -1378,16 +1438,41 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XMountMURootA)
PCHAR pchDrive
)
{
LOG_FUNC_BEGIN
LOG_FUNC_ARG(dwPort)
LOG_FUNC_ARG(dwSlot)
LOG_FUNC_ARG(pchDrive)
LOG_FUNC_END;
// TODO: The params are probably wrong...
LOG_UNIMPLEMENTED();
std::lock_guard lock(g_MuLock);
char_xt lett = MuPort2Lett(dwPort, dwSlot);
if (MuIsMounted(lett)) {
if (pchDrive != zeroptr) {
*pchDrive = lett;
}
RETURN(ERROR_ALREADY_ASSIGNED);
}
std::string mu_path_str(DrivePrefix + lett + ":");
std::string mu_dev_str(DeviceMU + std::to_string(MuPort2Idx(dwPort, dwSlot)));
ANSI_STRING mu_dev, mu_path;
RtlInitAnsiString(&mu_path, mu_path_str.data());
RtlInitAnsiString(&mu_dev, mu_dev_str.data());
ntstatus_xt status = IoCreateSymbolicLink(&mu_path, &mu_dev);
if (!nt_success(status)) {
if (pchDrive != zeroptr) {
*pchDrive = 0;
}
RtlNtStatusToDosError(status);
RETURN(status);
}
MuSetMounted(lett);
if (pchDrive != zeroptr) {
*pchDrive = lett;
}
RETURN(ERROR_SUCCESS);
}
@ -1401,14 +1486,29 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XUnmountMU)
dword_xt dwSlot
)
{
LOG_FUNC_BEGIN
LOG_FUNC_ARG(dwPort)
LOG_FUNC_ARG(dwSlot)
LOG_FUNC_END;
LOG_UNIMPLEMENTED();
std::lock_guard lock(g_MuLock);
char_xt lett = MuPort2Lett(dwPort, dwSlot);
if (!MuIsMounted(lett)) {
RETURN(ERROR_INVALID_DRIVE);
}
std::string mu_path_str(DrivePrefix + lett + ":");
ANSI_STRING mu_path;
RtlInitAnsiString(&mu_path, mu_path_str.data());
ntstatus_xt status = IoDeleteSymbolicLink(&mu_path);
if (!nt_success(status)) {
RtlNtStatusToDosError(status);
RETURN(status);
}
MuClearMounted(lett);
RETURN(ERROR_SUCCESS);
}

View File

@ -1501,25 +1501,48 @@ XBSYSAPI EXPORTNUM(218) xbox::ntstatus_xt NTAPI xbox::NtQueryVolumeInformationFi
if ((DWORD)FileInformationClass == FileFsSizeInformation) {
PFILE_FS_SIZE_INFORMATION XboxSizeInfo = (PFILE_FS_SIZE_INFORMATION)FileInformation;
XboxPartitionTable partitionTable = CxbxGetPartitionTable();
int partitionNumber = CxbxGetPartitionNumberFromHandle(FileHandle);
FATX_SUPERBLOCK superBlock = CxbxGetFatXSuperBlock(partitionNumber);
// This might access the HDD or a MU, so we need to figure out the correct one first
const std::wstring path = CxbxGetFinalPathNameByHandle(FileHandle);
size_t pos = path.rfind(L"\\EmuDisk\\Partition");
if (pos != std::string::npos) {
// We are accessing a disk partition
XboxSizeInfo->BytesPerSector = 512;
XboxPartitionTable partitionTable = CxbxGetPartitionTable();
int partitionNumber = CxbxGetPartitionNumberFromPath(path);
FATX_SUPERBLOCK superBlock = CxbxGetFatXSuperBlock(partitionNumber);
// In some cases, the emulated partition hasn't been formatted yet, as these are forwarded to a real folder, this doesn't actually matter.
// We just pretend they are valid by defaulting the SectorsPerAllocationUnit value to the most common for system partitions
XboxSizeInfo->SectorsPerAllocationUnit = 32;
XboxSizeInfo->BytesPerSector = 512;
// If there is a valid cluster size, we calculate SectorsPerAllocationUnit from that instead
if (superBlock.ClusterSize > 0) {
XboxSizeInfo->SectorsPerAllocationUnit = superBlock.ClusterSize;
// In some cases, the emulated partition hasn't been formatted yet, as these are forwarded to a real folder, this doesn't actually matter.
// We just pretend they are valid by defaulting the SectorsPerAllocationUnit value to the most common for system partitions
XboxSizeInfo->SectorsPerAllocationUnit = 32;
// If there is a valid cluster size, we calculate SectorsPerAllocationUnit from that instead
if (superBlock.ClusterSize > 0) {
XboxSizeInfo->SectorsPerAllocationUnit = superBlock.ClusterSize;
}
XboxSizeInfo->TotalAllocationUnits.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize / XboxSizeInfo->SectorsPerAllocationUnit;
XboxSizeInfo->AvailableAllocationUnits.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize / XboxSizeInfo->SectorsPerAllocationUnit;
RETURN(xbox::status_success);
}
XboxSizeInfo->TotalAllocationUnits.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize / XboxSizeInfo->SectorsPerAllocationUnit;
XboxSizeInfo->AvailableAllocationUnits.QuadPart = partitionTable.TableEntries[partitionNumber - 1].LBASize / XboxSizeInfo->SectorsPerAllocationUnit;
pos = path.rfind(L"\\EmuMu");
if (pos != std::string::npos) {
// We are accessing a MU
RETURN(xbox::status_success);
XboxSizeInfo->BytesPerSector = 512;
XboxSizeInfo->SectorsPerAllocationUnit = 32;
XboxSizeInfo->TotalAllocationUnits.QuadPart = 512; // 8MB -> ((1024)^2 * 8) / (BytesPerSector * SectorsPerAllocationUnit)
XboxSizeInfo->AvailableAllocationUnits.QuadPart = 512; // constant, so there's always free space available to write stuff
RETURN(xbox::status_success);
}
EmuLog(LOG_LEVEL::WARNING, "%s: Unrecongnized handle 0x%X with class FileFsSizeInformation", __func__, FileHandle);
RETURN(xbox::status_invalid_handle);
}
// Get the required size for the host buffer

View File

@ -1509,16 +1509,15 @@ __declspec(noreturn) void CxbxKrnlInit
CxbxRegisterDeviceHostPath(DeviceHarddisk0Partition7, CxbxBasePath + "Partition7");
CxbxRegisterDeviceHostPath(DevicePrefix + "\\Chihiro", CxbxBasePath + "Chihiro");
// Create MU directories
for (unsigned i = 0; i < 8; ++i) {
std::error_code error;
static char mu_letter = 'F';
std::string mu_path = MuBasePath + mu_letter;
if (!(std::filesystem::exists(mu_path) || std::filesystem::create_directory(mu_path, error))) {
CxbxKrnlCleanup("Failed to create memory unit directories");
}
++mu_letter;
}
// Create the MU directories
CxbxRegisterDeviceHostPath(DeviceMU0, MuBasePath + "F");
CxbxRegisterDeviceHostPath(DeviceMU1, MuBasePath + "G");
CxbxRegisterDeviceHostPath(DeviceMU2, MuBasePath + "H");
CxbxRegisterDeviceHostPath(DeviceMU3, MuBasePath + "I");
CxbxRegisterDeviceHostPath(DeviceMU4, MuBasePath + "J");
CxbxRegisterDeviceHostPath(DeviceMU5, MuBasePath + "K");
CxbxRegisterDeviceHostPath(DeviceMU6, MuBasePath + "L");
CxbxRegisterDeviceHostPath(DeviceMU7, MuBasePath + "M");
// Create default symbolic links :
EmuLogInit(LOG_LEVEL::DEBUG, "Creating default symbolic links.");

View File

@ -139,7 +139,7 @@ FATX_SUPERBLOCK CxbxGetFatXSuperBlock(int partitionNumber)
return superblock;
}
static std::wstring CxbxGetFinalPathNameByHandle(HANDLE hFile)
std::wstring CxbxGetFinalPathNameByHandle(HANDLE hFile)
{
constexpr size_t INITIAL_BUF_SIZE = MAX_PATH;
std::wstring path(INITIAL_BUF_SIZE, '\0');
@ -173,20 +173,30 @@ static bool CxbxIsPathInsideEmuDisk(const std::filesystem::path& path)
return match.first == rootPath.end();
}
int CxbxGetPartitionNumberFromHandle(HANDLE hFile)
static int CxbxGetPartitionNumber(const std::wstring_view path)
{
// Get which partition number is being accessed, by parsing the filename and extracting the last portion
const std::wstring path = CxbxGetFinalPathNameByHandle(hFile);
const std::wstring_view partitionString = L"\\EmuDisk\\Partition";
const size_t pos = path.rfind(partitionString);
if (pos == std::string::npos) {
return 0;
}
const std::wstring partitionNumberString = path.substr(pos + partitionString.length(), 1);
const std::wstring_view partitionNumberString = path.substr(pos + partitionString.length(), 1);
// wcstol returns 0 on non-numeric characters, so we don't need to error check here
return wcstol(partitionNumberString.c_str(), nullptr, 0);
return wcstol(partitionNumberString.data(), nullptr, 0);
}
int CxbxGetPartitionNumberFromPath(const std::wstring_view path)
{
return CxbxGetPartitionNumber(path);
}
int CxbxGetPartitionNumberFromHandle(HANDLE hFile)
{
// Get which partition number is being accessed, by parsing the filename and extracting the last portion
const std::wstring path = CxbxGetFinalPathNameByHandle(hFile);
return CxbxGetPartitionNumber(path);
}
std::filesystem::path CxbxGetPartitionDataPathFromHandle(HANDLE hFile)
@ -267,6 +277,7 @@ const std::string DriveZ = DrivePrefix + "Z:"; // Z: is Title utility data regio
const std::string DevicePrefix = "\\Device";
const std::string DeviceCdrom0 = DevicePrefix + "\\CdRom0";
const std::string DeviceHarddisk0 = DevicePrefix + "\\Harddisk0";
const std::string DeviceMU = DevicePrefix + "\\MU_";
const std::string DeviceHarddisk0PartitionPrefix = DevicePrefix + "\\Harddisk0\\partition";
const std::string DeviceHarddisk0Partition0 = DeviceHarddisk0PartitionPrefix + "0"; // Contains raw config sectors (like XBOX_REFURB_INFO) + entire hard disk
const std::string DeviceHarddisk0Partition1 = DeviceHarddisk0PartitionPrefix + "1"; // Data partition. Contains TDATA and UDATA folders.
@ -289,6 +300,14 @@ const std::string DeviceHarddisk0Partition17 = DeviceHarddisk0PartitionPrefix +
const std::string DeviceHarddisk0Partition18 = DeviceHarddisk0PartitionPrefix + "18";
const std::string DeviceHarddisk0Partition19 = DeviceHarddisk0PartitionPrefix + "19";
const std::string DeviceHarddisk0Partition20 = DeviceHarddisk0PartitionPrefix + "20"; // 20 = Largest possible partition number
const std::string DeviceMU0 = DeviceMU + "0";
const std::string DeviceMU1 = DeviceMU + "1";
const std::string DeviceMU2 = DeviceMU + "2";
const std::string DeviceMU3 = DeviceMU + "3";
const std::string DeviceMU4 = DeviceMU + "4";
const std::string DeviceMU5 = DeviceMU + "5";
const std::string DeviceMU6 = DeviceMU + "6";
const std::string DeviceMU7 = DeviceMU + "7"; // 7 = Largest possible mu number
EmuNtSymbolicLinkObject* NtSymbolicLinkObjects['Z' - 'A' + 1];
std::vector<XboxDevice> Devices;

View File

@ -73,6 +73,7 @@ extern const std::string DriveZ;
extern const std::string DevicePrefix;
extern const std::string DeviceCdrom0;
extern const std::string DeviceHarddisk0;
extern const std::string DeviceMU;
extern const std::string DeviceHarddisk0PartitionPrefix;
extern const std::string DeviceHarddisk0Partition0;
extern const std::string DeviceHarddisk0Partition1;
@ -95,6 +96,14 @@ extern const std::string DeviceHarddisk0Partition17;
extern const std::string DeviceHarddisk0Partition18;
extern const std::string DeviceHarddisk0Partition19;
extern const std::string DeviceHarddisk0Partition20;
extern const std::string DeviceMU0;
extern const std::string DeviceMU1;
extern const std::string DeviceMU2;
extern const std::string DeviceMU3;
extern const std::string DeviceMU4;
extern const std::string DeviceMU5;
extern const std::string DeviceMU6;
extern const std::string DeviceMU7;
constexpr char CxbxAutoMountDriveLetter = 'D';
extern std::string CxbxBasePath;
@ -318,6 +327,8 @@ typedef struct _FATX_SUPERBLOCK
XboxPartitionTable CxbxGetPartitionTable();
FATX_SUPERBLOCK CxbxGetFatXSuperBlock(int partitionNumber);
int CxbxGetPartitionNumberFromHandle(HANDLE hFile);
int CxbxGetPartitionNumberFromPath(const std::wstring_view path);
std::wstring CxbxGetFinalPathNameByHandle(HANDLE hFile);
std::filesystem::path CxbxGetPartitionDataPathFromHandle(HANDLE hFile);
void CxbxFormatPartitionByHandle(HANDLE hFile);

View File

@ -161,7 +161,7 @@ INT_PTR CALLBACK DlgInputConfigProc(HWND hWndDlg, UINT uMsg, WPARAM wParam, LPAR
HWND hHandle = GetDlgItem(hWndDlg, IDC_DEVICE_PORT1 + port);
int DeviceType = SendMessage(hHandle, CB_GETITEMDATA, SendMessage(hHandle, CB_GETCURSEL, 0, 0), 0);
g_Settings->m_input_port[port].Type = DeviceType;
if (DeviceType != to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) ||
if (DeviceType != to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE) &&
DeviceType != to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S)) {
// Forcefully set the child devices to none. This will happen if the user sets MUs in the controller dialog but
// then they set the parent device to a device that cannot support them in the input dialog