diff --git a/source/ums.c b/source/ums.c new file mode 100644 index 0000000..7b78b6a --- /dev/null +++ b/source/ums.c @@ -0,0 +1,249 @@ +/* + * ums.c + * + * Copyright (c) 2020, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * nxdumptool is distributed in the hope 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 + * along with this program. If not, see . + */ + +#include "utils.h" + +/* Global variables. */ + +static Mutex g_umsMutex = 0; +static bool g_umsInterfaceInit = false; + +static Thread g_umsDetectionThread = {0}; +static UEvent *g_umsStatusChangeEvent = NULL, g_umsDetectionThreadExitEvent = {0}; +static bool g_umsDetectionThreadCreated = false, g_umsDeviceInfoUpdated = false; + +static u32 g_umsDeviceCount = 0; +static UsbHsFsDevice *g_umsDevices = NULL; + +/* Function prototypes. */ + +static bool umsCreateDetectionThread(void); +static void umsDestroyDetectionThread(void); +static void umsDetectionThreadFunc(void *arg); + +static void umsFreeDeviceData(void); + +bool umsInitialize(void) +{ + mutexLock(&g_umsMutex); + + Result rc = 0; + + bool ret = g_umsInterfaceInit; + if (ret) goto end; + + /* Initialize USB Mass Storage Host interface. */ + rc = usbHsFsInitialize(0); + if (R_FAILED(rc)) + { + LOGFILE("usbHsFsInitialize failed! (0x%08X).", rc); + goto end; + } + + /* Get USB Mass Storage status change event. */ + g_umsStatusChangeEvent = usbHsFsGetStatusChangeUserEvent(); + + /* Create user-mode exit event. */ + ueventCreate(&g_umsDetectionThreadExitEvent, true); + + /* Create USB Mass Storage detection thread. */ + if (!(g_umsDetectionThreadCreated = umsCreateDetectionThread())) goto end; + + ret = g_umsInterfaceInit = true; + +end: + mutexUnlock(&g_umsMutex); + + return ret; +} + +void umsExit(void) +{ + mutexLock(&g_umsMutex); + + if (!g_umsInterfaceInit) goto end; + + /* Destroy USB Mass Storage detection thread. */ + if (g_umsDetectionThreadCreated) + { + umsDestroyDetectionThread(); + g_umsDetectionThreadCreated = false; + } + + /* Close USB Mass Storage Host interface. */ + usbHsFsExit(); + + g_umsInterfaceInit = false; + +end: + mutexUnlock(&g_umsMutex); +} + +bool umsIsDeviceInfoUpdated(void) +{ + mutexLock(&g_umsMutex); + + bool ret = false; + + if (g_umsInterfaceInit && g_umsDeviceInfoUpdated) + { + ret = true; + g_umsDeviceInfoUpdated = false; + } + + mutexUnlock(&g_umsMutex); + + return ret; +} + +u32 umsGetDeviceCount(void) +{ + mutexLock(&g_umsMutex); + u32 count = (g_umsInterfaceInit ? g_umsDeviceCount : 0); + mutexUnlock(&g_umsMutex); + return count; +} + +bool umsGetDeviceByIndex(u32 idx, UsbHsFsDevice *out_device) +{ + mutexLock(&g_umsMutex); + + bool ret = false; + + if (!g_umsInterfaceInit || !g_umsDeviceCount || !g_umsDevices || idx >= g_umsDeviceCount || !out_device) + { + LOGFILE("Invalid parameters!"); + goto end; + } + + /* Copy device data. */ + memcpy(out_device, &(g_umsDevices[idx]), sizeof(UsbHsFsDevice)); + + ret = true; + +end: + mutexUnlock(&g_umsMutex); + + return ret; +} + +static bool umsCreateDetectionThread(void) +{ + if (!utilsCreateThread(&g_umsDetectionThread, umsDetectionThreadFunc, NULL, 1)) + { + LOGFILE("Failed to create USB Mass Storage detection thread!"); + return false; + } + + return true; +} + +static void umsDestroyDetectionThread(void) +{ + /* Signal the exit event to terminate the USB Mass Storage detection thread. */ + ueventSignal(&g_umsDetectionThreadExitEvent); + + /* Wait for the USB Mass Storage detection thread to exit. */ + utilsJoinThread(&g_umsDetectionThread); +} + +static void umsDetectionThreadFunc(void *arg) +{ + (void)arg; + + Result rc = 0; + int idx = 0; + u32 listed_device_count = 0; + + Waiter status_change_event_waiter = waiterForUEvent(g_umsStatusChangeEvent); + Waiter exit_event_waiter = waiterForUEvent(&g_umsDetectionThreadExitEvent); + + while(true) + { + /* Wait until an event is triggered. */ + rc = waitMulti(&idx, -1, status_change_event_waiter, exit_event_waiter); + if (R_FAILED(rc)) continue; + + /* Exit event triggered. */ + if (idx == 1) break; + + mutexLock(&g_umsMutex); + + /* Free USB Mass Storage device data. */ + umsFreeDeviceData(); + + /* Get mounted device count. */ + g_umsDeviceCount = usbHsFsGetMountedDeviceCount(); + LOGFILE("USB Mass Storage status change event triggered! Mounted USB Mass Storage device count: %u.", g_umsDeviceCount); + + if (g_umsDeviceCount) + { + bool fail = false; + + /* Allocate mounted devices buffer. */ + g_umsDevices = calloc(g_umsDeviceCount, sizeof(UsbHsFsDevice)); + if (g_umsDevices) + { + /* List mounted devices. */ + if ((listed_device_count = usbHsFsListMountedDevices(g_umsDevices, g_umsDeviceCount))) + { + /* Check if we got as many devices as we expected. */ + if (listed_device_count == g_umsDeviceCount) + { + /* Update USB Mass Storage device info updated flag. */ + g_umsDeviceInfoUpdated = true; + } else { + LOGFILE("USB Mass Storage device count mismatch! (%u != %u).", listed_device_count, g_umsDeviceCount); + fail = true; + } + } else { + LOGFILE("Failed to list mounted USB Mass Storage devices!"); + fail = true; + } + } else { + LOGFILE("Failed to allocate memory for mounted USB Mass Storage devices buffer!"); + fail = true; + } + + /* Free USB Mass Storage device data if something went wrong. */ + if (fail) umsFreeDeviceData(); + } + + mutexUnlock(&g_umsMutex); + } + + /* Free USB Mass Storage device data. */ + umsFreeDeviceData(); + + threadExit(); +} + +static void umsFreeDeviceData(void) +{ + /* Free devices buffer. */ + if (g_umsDevices) + { + free(g_umsDevices); + g_umsDevices = NULL; + } + + /* Reset device count. */ + g_umsDeviceCount = 0; +} diff --git a/source/ums.h b/source/ums.h new file mode 100644 index 0000000..a1a4bea --- /dev/null +++ b/source/ums.h @@ -0,0 +1,41 @@ +/* + * ums.h + * + * Copyright (c) 2020, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * nxdumptool is distributed in the hope 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 + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __UMS_H__ +#define __UMS_H__ + +/// Initializes the USB Mass Storage interface. +bool umsInitialize(void); + +/// Closes the USB Mass Storage interface. +void umsExit(void); + +/// Returns true if USB Mass Storage device info has been updated. +bool umsIsDeviceInfoUpdated(void); + +/// Returns the available USB Mass Storage device count. +u32 umsGetDeviceCount(void); + +/// Saves USB Mass Storage device info to 'out_device' using the provided index. +bool umsGetDeviceByIndex(u32 idx, UsbHsFsDevice *out_device); + +#endif /* __UMS_H__ */ diff --git a/source/usb.c b/source/usb.c index 796eddf..987b966 100644 --- a/source/usb.c +++ b/source/usb.c @@ -107,7 +107,7 @@ typedef struct { static RwLock g_usbDeviceLock = {0}; static usbDeviceInterface g_usbDeviceInterface = {0}; -static bool g_usbDeviceInterfaceInitialized = false; +static bool g_usbDeviceInterfaceInit = false; static Event *g_usbStateChangeEvent = NULL; static Thread g_usbDetectionThread = {0}; @@ -250,7 +250,7 @@ bool usbSendFileProperties(u64 file_size, const char *filename, u32 nsp_header_s u32 status = UsbStatusType_Success; size_t filename_length = 0; - if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted || !filename || \ + if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInit || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted || !filename || \ !(filename_length = strlen(filename)) || filename_length >= FS_MAX_PATH || (!g_nspTransferMode && ((file_size && nsp_header_size >= file_size) || g_usbTransferRemainingSize)) || \ (g_nspTransferMode && nsp_header_size)) { @@ -299,7 +299,7 @@ bool usbSendFileData(void *data, u64 data_size) UsbStatus *cmd_status = NULL; bool ret = false, zlt_required = false; - if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted || !g_usbTransferRemainingSize || !data || \ + if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInit || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted || !g_usbTransferRemainingSize || !data || \ !data_size || data_size > USB_TRANSFER_BUFFER_SIZE || data_size > g_usbTransferRemainingSize) { LOGFILE("Invalid parameters!"); @@ -398,7 +398,7 @@ bool usbSendNspHeader(void *nsp_header, u32 nsp_header_size) u32 status = UsbStatusType_Success; bool ret = false, zlt_required = false; - if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted || g_usbTransferRemainingSize || \ + if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInit || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted || g_usbTransferRemainingSize || \ !g_nspTransferMode || !nsp_header || !nsp_header_size || nsp_header_size > (USB_TRANSFER_BUFFER_SIZE - sizeof(UsbCommandHeader))) { LOGFILE("Invalid parameters!"); @@ -441,7 +441,7 @@ void usbCancelFileTransfer(void) rwlockWriteLock(&(g_usbDeviceInterface.lock)); rwlockWriteLock(&(g_usbDeviceInterface.lock_in)); - if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted || (!g_usbTransferRemainingSize && \ + if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInit || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted || (!g_usbTransferRemainingSize && \ !g_nspTransferMode)) goto end; /* Reset variables. */ @@ -555,7 +555,7 @@ static bool usbStartSession(void) size_t cmd_size = 0; u32 status = UsbStatusType_Success; - if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized) + if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInit || !g_usbDeviceInterface.initialized) { LOGFILE("Invalid parameters!"); return false; @@ -598,7 +598,7 @@ static bool usbStartSession(void) static void usbEndSession(void) { - if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInitialized || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted) + if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInit || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted) { LOGFILE("Invalid parameters!"); return; @@ -705,7 +705,7 @@ static bool usbInitializeComms(void) { Result rc = 0; - bool ret = (g_usbDeviceInterfaceInitialized && g_usbDeviceInterface.initialized); + bool ret = (g_usbDeviceInterfaceInit && g_usbDeviceInterface.initialized); if (ret) goto end; rc = usbDsInitialize(); @@ -858,7 +858,7 @@ static bool usbInitializeComms(void) } } - ret = g_usbDeviceInterfaceInitialized = true; + ret = g_usbDeviceInterfaceInit = true; end: if (!ret) usbCloseComms(); @@ -869,7 +869,7 @@ end: static void usbCloseComms(void) { usbDsExit(); - g_usbDeviceInterfaceInitialized = false; + g_usbDeviceInterfaceInit = false; usbFreeDeviceInterface(); } diff --git a/source/utils.c b/source/utils.c index e924859..0728307 100644 --- a/source/utils.c +++ b/source/utils.c @@ -20,7 +20,6 @@ */ #include -#include #include "utils.h" //#include "freetype_helper.h" @@ -30,6 +29,7 @@ #include "services.h" #include "nca.h" #include "usb.h" +#include "ums.h" #include "title.h" #include "bfttf.h" #include "fatfs/ff.h" @@ -38,7 +38,7 @@ /* Global variables. */ -static bool g_resourcesInitialized = false, g_isDevUnit = false; +static bool g_resourcesInit = false, g_isDevUnit = false; static Mutex g_resourcesMutex = 0; static PadState g_padState = {0}; @@ -78,8 +78,7 @@ bool utilsInitializeResources(void) { mutexLock(&g_resourcesMutex); - Result rc = 0; - bool ret = g_resourcesInitialized; + bool ret = g_resourcesInit; if (ret) goto end; /* Configure input. */ @@ -118,13 +117,8 @@ bool utilsInitializeResources(void) goto end; } - /* Initialize USB Mass Storage Host interface. */ - rc = usbHsFsInitialize(0); - if (R_FAILED(rc)) - { - LOGFILE("Failed to initialize USB host FS interface! (0x%08X).", rc); - goto end; - } + /* Initialize USB Mass Storage interface. */ + if (!umsInitialize()) goto end; /* Load NCA keyset. */ if (!keysLoadNcaKeyset()) @@ -190,7 +184,7 @@ bool utilsInitializeResources(void) /* Initialize LVGL. */ //if (!lvglHelperInitialize()) return false; - ret = g_resourcesInitialized = true; + ret = g_resourcesInit = true; end: mutexUnlock(&g_resourcesMutex); @@ -235,8 +229,8 @@ void utilsCloseResources(void) /* Free NCA crypto buffer. */ ncaFreeCryptoBuffer(); - /* Close USB Mass Storage Host interface. */ - usbHsFsExit(); + /* Close USB Mass Storage interface. */ + umsExit(); /* Close USB interface. */ usbExit(); @@ -244,7 +238,7 @@ void utilsCloseResources(void) /* Close initialized services. */ servicesClose(); - g_resourcesInitialized = false; + g_resourcesInit = false; mutexUnlock(&g_resourcesMutex); } @@ -330,7 +324,7 @@ void utilsJoinThread(Thread *thread) bool utilsIsDevelopmentUnit(void) { mutexLock(&g_resourcesMutex); - bool ret = (g_resourcesInitialized && g_isDevUnit); + bool ret = (g_resourcesInit && g_isDevUnit); mutexUnlock(&g_resourcesMutex); return ret; } diff --git a/source/utils.h b/source/utils.h index b62a6bd..02c66a5 100644 --- a/source/utils.h +++ b/source/utils.h @@ -37,6 +37,7 @@ #include #include #include +#include #include "common.h"