From e77c72b0db6833b7612e8eb2d091ed35771a5c03 Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Fri, 12 Feb 2021 16:35:23 -0400 Subject: [PATCH] Some changes. * gamecard: added more comments, modified gamecardGetBundledFirmwareUpdateVersion() to fill a VersionType1 pointer instead of a u32, fallback to manually reading the gamecard certificate if fsDeviceOperatorGetGameCardDeviceCertificate() fails, updated GameCardFwVersion enum. * title: tweaked conditions for some functions. * usb: explicitly defined values for previously omitted struct members while initializing USB comms, imported libusb structs to make it easier to work with the USB BOS, added a few more comments and changed around some code. * utils: tweaked the illegal filesystem character array to remove some chars that are actually allowed. --- source/cert.h | 5 +- source/gamecard.c | 20 +++- source/gamecard.h | 33 +++++-- source/nacp.h | 2 +- source/title.c | 16 ++-- source/usb.c | 228 ++++++++++++++++++++++++++++++---------------- source/usb.h | 2 +- source/utils.c | 4 +- 8 files changed, 207 insertions(+), 103 deletions(-) diff --git a/source/cert.h b/source/cert.h index 8ce3f6f..bdc20e1 100644 --- a/source/cert.h +++ b/source/cert.h @@ -167,11 +167,12 @@ bool certRetrieveCertificateByName(Certificate *dst, const char *name); /// Retrieves a certificate chain by a full signature issuer string (e.g. "Root-CA00000003-XS00000020"). bool certRetrieveCertificateChainBySignatureIssuer(CertificateChain *dst, const char *issuer); -/// Returns a pointer to a heap allocated buffer that contains the raw contents from the certificate chain matching the input signature issuer. It must be freed by the user. +/// Returns a pointer to a dynamically allocated buffer that contains the raw contents from the certificate chain matching the input signature issuer. It must be freed by the user. /// NULL is returned if an error occurs. u8 *certGenerateRawCertificateChainBySignatureIssuer(const char *issuer, u64 *out_size); -/// Returns a pointer to a heap allocated buffer that contains the raw contents from the certificate chain matching the input Rights ID (stored in the inserted gamecard). It must be freed by the user. +/// Returns a pointer to a dynamically allocated buffer that contains the raw contents from the certificate chain matching the input Rights ID (stored in the inserted gamecard). +/// It must be freed by the user. /// NULL is returned if an error occurs. u8 *certRetrieveRawCertificateChainFromGameCardByRightsId(const FsRightsId *id, u64 *out_size); diff --git a/source/gamecard.c b/source/gamecard.c index 098a614..c4a269c 100644 --- a/source/gamecard.c +++ b/source/gamecard.c @@ -310,12 +310,22 @@ bool gamecardGetCertificate(FsGameCardCertificate *out) bool ret = false; mutexLock(&g_gamecardMutex); + if (g_gameCardInserted && g_gameCardHandle.value && out) { + /* Read the gamecard certificate using the official IPC call. */ rc = fsDeviceOperatorGetGameCardDeviceCertificate(&g_deviceOperator, &g_gameCardHandle, out); - if (R_FAILED(rc)) LOGFILE("fsDeviceOperatorGetGameCardDeviceCertificate failed! (0x%08X)", rc); + if (R_FAILED(rc)) + { + LOGFILE("fsDeviceOperatorGetGameCardDeviceCertificate failed! (0x%08X)", rc); + + /* Attempt to manually read the gamecard certificate. */ + if (gamecardReadStorageArea(out, sizeof(FsGameCardCertificate), GAMECARD_CERTIFICATE_OFFSET, false)) rc = 0; + } + ret = R_SUCCEEDED(rc); } + mutexUnlock(&g_gamecardMutex); return ret; @@ -348,7 +358,7 @@ bool gamecardGetRomCapacity(u64 *out) return ret; } -bool gamecardGetBundledFirmwareUpdateVersion(u32 *out) +bool gamecardGetBundledFirmwareUpdateVersion(VersionType1 *out) { Result rc = 0; u64 update_id = 0; @@ -356,14 +366,16 @@ bool gamecardGetBundledFirmwareUpdateVersion(u32 *out) bool ret = false; mutexLock(&g_gamecardMutex); + if (g_gameCardInserted && g_gameCardHandle.value && out) { rc = fsDeviceOperatorUpdatePartitionInfo(&g_deviceOperator, &g_gameCardHandle, &update_version, &update_id); if (R_FAILED(rc)) LOGFILE("fsDeviceOperatorUpdatePartitionInfo failed! (0x%08X)", rc); ret = (R_SUCCEEDED(rc) && update_id == GAMECARD_UPDATE_TID); - if (ret) *out = update_version; + if (ret) out->value = update_version; } + mutexUnlock(&g_gamecardMutex); return ret; @@ -872,7 +884,7 @@ static bool gamecardGetHandleAndStorage(u32 partition) NX_INLINE void gamecardCloseHandle(void) { - /* I need to find a way to properly close a gamecard handle... */ + /* TO DO: find a way to properly close a gamecard handle. */ if (!g_gameCardHandle.value) return; svcCloseHandle(g_gameCardHandle.value); g_gameCardHandle.value = 0; diff --git a/source/gamecard.h b/source/gamecard.h index a4fa1a9..0c51956 100644 --- a/source/gamecard.h +++ b/source/gamecard.h @@ -103,9 +103,10 @@ typedef enum { } GameCardSelSec; typedef enum { - GameCardFwVersion_ForDev = 0, - GameCardFwVersion_Before400NUP = 1, ///< cup_version < 268435456 (4.0.0-0.0) in GameCardHeaderEncryptedArea. - GameCardFwVersion_Since400NUP = 2 ///< cup_version >= 268435456 (4.0.0-0.0) in GameCardHeaderEncryptedArea. + GameCardFwVersion_ForDev = 0, + GameCardFwVersion_ForProd = BIT(0), + GameCardFwVersion_ForProdSince400NUP = BIT(1), ///< cup_version >= 268435456 (4.0.0-0.0) in GameCardHeaderEncryptedArea. + GameCardFwVersion_ForProdSince1100NUP = BIT(2) ///< cup_version >= 738197504 (11.0.0-0.0) in GameCardHeaderEncryptedArea. } GameCardFwVersion; typedef enum { @@ -175,7 +176,7 @@ typedef enum { GameCardHashFileSystemPartitionType_Logo = 2, ///< Only available in GameCardFwVersion_Since400NUP gamecards. GameCardHashFileSystemPartitionType_Normal = 3, GameCardHashFileSystemPartitionType_Secure = 4, - GameCardHashFileSystemPartitionType_Boot = 5, ///< Only available in Terra (Tencent) gamecards. + GameCardHashFileSystemPartitionType_Boot = 5, GameCardHashFileSystemPartitionType_Count = 6 ///< Not a real value. } GameCardHashFileSystemPartitionType; @@ -194,20 +195,34 @@ UEvent *gamecardGetStatusChangeUserEvent(void); /// Returns the current GameCardStatus value. u8 gamecardGetStatus(void); -/// Used to read data from the inserted gamecard. +/// Used to read raw data from the inserted gamecard. /// All required handles, changes between normal <-> secure storage areas and proper offset calculations are managed internally. /// 'offset' + 'read_size' must not exceed the value returned by gamecardGetTotalSize(). bool gamecardReadStorage(void *out, u64 read_size, u64 offset); -/// Miscellaneous functions. - +/// Fills the provided GameCardKeyArea pointer. Only GameCardInitialData data is retrieved at this moment. +/// This area can't be read using gamecardReadStorage(). bool gamecardGetKeyArea(GameCardKeyArea *out); + +/// Fills the provided GameCardHeader pointer. +/// This area can also be read using gamecardReadStorage(), starting at offset 0. bool gamecardGetHeader(GameCardHeader *out); + +/// Fills the provided FsGameCardCertificate pointer. +/// This area can also be read using gamecardReadStorage(), starting at GAMECARD_CERTIFICATE_OFFSET. bool gamecardGetCertificate(FsGameCardCertificate *out); + +/// Fills the provided u64 pointer with the total gamecard size, which is the size taken by both Normal and Secure storage areas. bool gamecardGetTotalSize(u64 *out); + +/// Fills the provided u64 pointer with the trimmed gamecard size, which is the same as the size returned by gamecardGetTotalSize() but using the trimmed Secure storage area size. bool gamecardGetTrimmedSize(u64 *out); -bool gamecardGetRomCapacity(u64 *out); ///< Not the same as gamecardGetTotalSize(). -bool gamecardGetBundledFirmwareUpdateVersion(u32 *out); + +/// Fills the provided u64 pointer with the gamecard ROM capacity, based on the GameCardRomSize value from the header. Not the same as gamecardGetTotalSize(). +bool gamecardGetRomCapacity(u64 *out); + +/// Fills the provided VersionType1 pointer with the bundled firmware update version in the inserted gamecard. +bool gamecardGetBundledFirmwareUpdateVersion(VersionType1 *out); /// Returns a pointer to a string holding the name of the provided hash file system partition type. Returns NULL if the provided value is invalid. const char *gamecardGetHashFileSystemPartitionName(u8 hfs_partition_type); diff --git a/source/nacp.h b/source/nacp.h index fc8dd58..e9288d6 100644 --- a/source/nacp.h +++ b/source/nacp.h @@ -250,7 +250,7 @@ typedef struct { typedef struct { u16 index : 15; - u16 continue_set : 1; ///< Called "flag" by Nintendo, which isn't really great... + u16 continue_set : 1; ///< Called "flag" by Nintendo, which isn't really great. } NacpDescriptors; typedef struct { diff --git a/source/title.c b/source/title.c index ad98c65..c12bb01 100644 --- a/source/title.c +++ b/source/title.c @@ -587,7 +587,7 @@ TitleApplicationMetadata **titleGetApplicationMetadataEntries(bool is_system, u3 u32 app_count = 0; TitleApplicationMetadata **app_metadata = NULL, **tmp_app_metadata = NULL; - if (!g_appMetadata || (is_system && g_appMetadataCount < g_systemTitlesCount) || (!is_system && g_appMetadataCount == g_systemTitlesCount) || !out_count) + if (!g_titleInterfaceInit || !g_appMetadata || (is_system && g_appMetadataCount < g_systemTitlesCount) || (!is_system && g_appMetadataCount == g_systemTitlesCount) || !out_count) { LOGFILE("Invalid parameters!"); goto end; @@ -640,7 +640,7 @@ bool titleGetUserApplicationData(u64 app_id, TitleUserApplicationData *out) bool success = false; - if (!out) + if (!g_titleInterfaceInit || !out) { LOGFILE("Invalid parameters!"); goto end; @@ -683,7 +683,7 @@ end: bool titleAreOrphanTitlesAvailable(void) { mutexLock(&g_titleMutex); - bool ret = (g_titleInfoOrphanCount > 0); + bool ret = (g_titleInterfaceInit && g_titleInfoOrphanCount > 0); mutexUnlock(&g_titleMutex); return ret; } @@ -694,7 +694,7 @@ TitleInfo **titleGetInfoFromOrphanTitles(u32 *out_count) TitleInfo **orphan_info = NULL; - if (!g_titleInfo || !g_titleInfoCount || !g_titleInfoOrphanCount || !out_count) + if (!g_titleInterfaceInit || !g_titleInfo || !g_titleInfoCount || !g_titleInfoOrphanCount || !out_count) { LOGFILE("Invalid parameters!"); goto end; @@ -732,7 +732,7 @@ bool titleIsGameCardInfoUpdated(void) mutexLock(&g_titleMutex); /* Check if the gamecard thread detected a gamecard status change. */ - bool ret = g_titleGameCardInfoUpdated; + bool ret = (g_titleInterfaceInit && g_titleGameCardInfoThreadCreated && g_titleGameCardInfoUpdated); if (!ret) goto end; /* Signal the gamecard update info user event. */ @@ -800,7 +800,7 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_ char *filename = NULL, *tmp_filename = NULL; char app_name[0x400] = {0}; - if (!g_titleGameCardAvailable || !g_titleInfo || !g_titleInfoCount || !g_titleInfoGameCardCount || g_titleInfoGameCardCount > g_titleInfoCount || \ + if (!g_titleInterfaceInit || !g_titleGameCardAvailable || !g_titleInfo || !g_titleInfoCount || !g_titleInfoGameCardCount || g_titleInfoGameCardCount > g_titleInfoCount || \ g_titleInfoGameCardStartIndex != (g_titleInfoCount - g_titleInfoGameCardCount) || name_convention > TitleFileNameConvention_IdAndVersionOnly || \ (name_convention == TitleFileNameConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly)) { @@ -1830,8 +1830,8 @@ static TitleInfo *_titleGetInfoFromStorageByTitleId(u8 storage_id, u64 title_id, TitleInfo *info = NULL; - if (!g_titleInfo || !g_titleInfoCount || storage_id < NcmStorageId_GameCard || storage_id > NcmStorageId_Any || (storage_id == NcmStorageId_GameCard && (!g_titleInfoGameCardCount || \ - g_titleInfoGameCardCount > g_titleInfoCount || g_titleInfoGameCardStartIndex != (g_titleInfoCount - g_titleInfoGameCardCount))) || !title_id) + if (!g_titleInterfaceInit || !g_titleInfo || !g_titleInfoCount || storage_id < NcmStorageId_GameCard || storage_id > NcmStorageId_Any || (storage_id == NcmStorageId_GameCard && \ + (!g_titleInfoGameCardCount || g_titleInfoGameCardCount > g_titleInfoCount || g_titleInfoGameCardStartIndex != (g_titleInfoCount - g_titleInfoGameCardCount))) || !title_id) { LOGFILE("Invalid parameters!"); goto end; diff --git a/source/usb.c b/source/usb.c index e4bb5bc..a001ebc 100644 --- a/source/usb.c +++ b/source/usb.c @@ -26,10 +26,10 @@ #define USB_ABI_VERSION 1 -#define USB_CMD_HEADER_MAGIC 0x4E584454 /* "NXDT". */ +#define USB_CMD_HEADER_MAGIC 0x4E584454 /* "NXDT". */ -#define USB_TRANSFER_ALIGNMENT 0x1000 /* 4 KiB. */ -#define USB_TRANSFER_TIMEOUT 5 /* 5 seconds. */ +#define USB_TRANSFER_ALIGNMENT 0x1000 /* 4 KiB. */ +#define USB_TRANSFER_TIMEOUT 5 /* 5 seconds. */ #define USB_FS_BCD_REVISION 0x0110 #define USB_FS_EP_MAX_PACKET_SIZE 0x40 @@ -40,6 +40,10 @@ #define USB_SS_BCD_REVISION 0x0300 #define USB_SS_EP_MAX_PACKET_SIZE 0x400 +#define USB_BOS_SIZE 0x16 /* usb_bos_descriptor + usb_2_0_extension_descriptor + usb_ss_usb_device_capability_descriptor. */ + +#define LANGID_EN_US 0x0409 + /* Type definitions. */ typedef struct { @@ -47,7 +51,7 @@ typedef struct { bool initialized; UsbDsInterface *interface; UsbDsEndpoint *endpoint_in, *endpoint_out; -} usbDeviceInterface; +} UsbDeviceInterface; typedef enum { UsbCommandType_StartSession = 0, @@ -103,10 +107,64 @@ typedef struct { u8 reserved[0x6]; } UsbStatus; +/// Imported from libusb, with some adjustments. +enum usb_bos_type { + USB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1, + USB_BT_USB_2_0_EXTENSION = 2, + USB_BT_SS_USB_DEVICE_CAPABILITY = 3, + USB_BT_CONTAINER_ID = 4 +}; + +/// Imported from libusb, with some adjustments. +enum usb_2_0_extension_attributes { + USB_BM_LPM_SUPPORT = 2 +}; + +/// Imported from libusb, with some adjustments. +enum usb_ss_usb_device_capability_attributes { + USB_BM_LTM_SUPPORT = 2 +}; + +/// Imported from libusb, with some adjustments. +enum usb_supported_speed { + USB_LOW_SPEED_OPERATION = BIT(0), + USB_FULL_SPEED_OPERATION = BIT(1), + USB_HIGH_SPEED_OPERATION = BIT(2), + USB_SUPER_SPEED_OPERATION = BIT(3) +}; + +/// Imported from libusb, with some adjustments. +struct usb_bos_descriptor { + u8 bLength; + u8 bDescriptorType; ///< Must match USB_DT_BOS. + u16 wTotalLength; ///< Length of this descriptor and all of its sub descriptors. + u8 bNumDeviceCaps; ///< The number of separate device capability descriptors in the BOS. +} PACKED; + +/// Imported from libusb, with some adjustments. +struct usb_2_0_extension_descriptor { + u8 bLength; + u8 bDescriptorType; ///< Must match USB_DT_DEVICE_CAPABILITY. + u8 bDevCapabilityType; ///< Must match USB_BT_USB_2_0_EXTENSION. + u32 bmAttributes; ///< usb_2_0_extension_attributes. +} PACKED; + +/// Imported from libusb, with some adjustments. +struct usb_ss_usb_device_capability_descriptor { + u8 bLength; + u8 bDescriptorType; ///< Must match USB_DT_DEVICE_CAPABILITY. + u8 bDevCapabilityType; ///< Must match USB_BT_SS_USB_DEVICE_CAPABILITY. + u8 bmAttributes; ///< usb_ss_usb_device_capability_attributes. + u16 wSpeedsSupported; ///< usb_supported_speed. + u8 bFunctionalitySupport; ///< The lowest speed at which all the functionality that the device supports is available to the user. + u8 bU1DevExitLat; ///< U1 Device Exit Latency. + u16 bU2DevExitLat; ///< U2 Device Exit Latency. +} PACKED; + /* Global variables. */ static RwLock g_usbDeviceLock = {0}; -static usbDeviceInterface g_usbDeviceInterface = {0}; +static UsbDeviceInterface g_usbDeviceInterface = {0}; static bool g_usbDeviceInterfaceInit = false; static Event *g_usbStateChangeEvent = NULL; @@ -705,6 +763,62 @@ static bool usbInitializeComms(void) { Result rc = 0; + /* Used on HOS >= 5.0.0. */ + struct usb_device_descriptor device_descriptor = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = USB_FS_BCD_REVISION, /* USB 1.0. Updated before setting new device descriptors for USB 2.0 and 3.0. */ + .bDeviceClass = 0x00, /* Defined at interface level. */ + .bDeviceSubClass = 0x00, /* Defined at interface level. */ + .bDeviceProtocol = 0x00, /* Defined at interface level. */ + .bMaxPacketSize0 = 0x40, /* 64 bytes. Updated before setting the USB 3.0 device descriptor. */ + .idVendor = 0x057e, /* VID officially used by usb:ds. */ + .idProduct = 0x3000, /* PID officially used by usb:ds. */ + .bcdDevice = 0x0100, + .iManufacturer = 0, /* Filled at a later time. */ + .iProduct = 0, /* Filled at a later time. */ + .iSerialNumber = 0, /* Filled at a later time. */ + .bNumConfigurations = 1 + }; + + static const u16 supported_langs[] = { LANGID_EN_US }; + static const u16 num_supported_langs = (u16)MAX_ELEMENTS(supported_langs); + + u8 bos[USB_BOS_SIZE] = {0}; + + struct usb_bos_descriptor *bos_desc = (struct usb_bos_descriptor*)bos; + struct usb_2_0_extension_descriptor *usb2_ext_desc = (struct usb_2_0_extension_descriptor*)(bos + sizeof(struct usb_bos_descriptor)); + struct usb_ss_usb_device_capability_descriptor *usb3_devcap_desc = (struct usb_ss_usb_device_capability_descriptor*)((u8*)usb2_ext_desc + sizeof(struct usb_2_0_extension_descriptor)); + + bos_desc->bLength = sizeof(struct usb_bos_descriptor); + bos_desc->bDescriptorType = USB_DT_BOS; + bos_desc->wTotalLength = USB_BOS_SIZE; + bos_desc->bNumDeviceCaps = 2; /* USB 2.0 + USB 3.0. No extra capabilities for USB 1.x. */ + + usb2_ext_desc->bLength = sizeof(struct usb_2_0_extension_descriptor); + usb2_ext_desc->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + usb2_ext_desc->bDevCapabilityType = USB_BT_USB_2_0_EXTENSION; + usb2_ext_desc->bmAttributes = USB_BM_LPM_SUPPORT; + + usb3_devcap_desc->bLength = sizeof(struct usb_ss_usb_device_capability_descriptor); + usb3_devcap_desc->bDescriptorType = USB_DT_DEVICE_CAPABILITY; + usb3_devcap_desc->bDevCapabilityType = USB_BT_SS_USB_DEVICE_CAPABILITY; + usb3_devcap_desc->bmAttributes = 0; + usb3_devcap_desc->wSpeedsSupported = (USB_SUPER_SPEED_OPERATION | USB_HIGH_SPEED_OPERATION | USB_FULL_SPEED_OPERATION); + usb3_devcap_desc->bFunctionalitySupport = 1; /* We can fully work under USB 1.x. */ + usb3_devcap_desc->bU1DevExitLat = 0; + usb3_devcap_desc->bU2DevExitLat = 0; + + /* Used on HOS < 5.0.0. */ + static const UsbDsDeviceInfo device_info = { + .idVendor = 0x057e, /* VID officially used by usb:ds. */ + .idProduct = 0x3000, /* PID officially used by usb:ds. */ + .bcdDevice = 0x0100, + .Manufacturer = APP_AUTHOR, + .Product = APP_TITLE, + .SerialNumber = APP_VERSION + }; + bool ret = (g_usbDeviceInterfaceInit && g_usbDeviceInterface.initialized); if (ret) goto end; @@ -717,113 +831,65 @@ static bool usbInitializeComms(void) if (hosversionAtLeast(5, 0, 0)) { - u8 manufacturer = 0, product = 0, serial_number = 0; - static const u16 supported_langs[1] = { 0x0409 }; - - /* Set language. */ - rc = usbDsAddUsbLanguageStringDescriptor(NULL, supported_langs, sizeof(supported_langs) / sizeof(u16)); + /* Set language string descriptor. */ + rc = usbDsAddUsbLanguageStringDescriptor(NULL, supported_langs, num_supported_langs); if (R_FAILED(rc)) LOGFILE("usbDsAddUsbLanguageStringDescriptor failed! (0x%08X).", rc); - /* Set manufacturer. */ + /* Set manufacturer string descriptor. */ if (R_SUCCEEDED(rc)) { - rc = usbDsAddUsbStringDescriptor(&manufacturer, APP_AUTHOR); + rc = usbDsAddUsbStringDescriptor(&(device_descriptor.iManufacturer), APP_AUTHOR); if (R_FAILED(rc)) LOGFILE("usbDsAddUsbStringDescriptor failed! (0x%08X) (manufacturer).", rc); } - /* Set product. */ + /* Set product string descriptor. */ if (R_SUCCEEDED(rc)) { - rc = usbDsAddUsbStringDescriptor(&product, APP_TITLE); + rc = usbDsAddUsbStringDescriptor(&(device_descriptor.iProduct), APP_TITLE); if (R_FAILED(rc)) LOGFILE("usbDsAddUsbStringDescriptor failed! (0x%08X) (product).", rc); } - /* Set serial number. */ + /* Set serial number string descriptor. */ if (R_SUCCEEDED(rc)) { - rc = usbDsAddUsbStringDescriptor(&serial_number, APP_VERSION); + rc = usbDsAddUsbStringDescriptor(&(device_descriptor.iSerialNumber), APP_VERSION); if (R_FAILED(rc)) LOGFILE("usbDsAddUsbStringDescriptor failed! (0x%08X) (serial number).", rc); } /* Set device descriptors. */ - struct usb_device_descriptor device_descriptor = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = USB_FS_BCD_REVISION, - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = 0x40, - .idVendor = 0x057e, - .idProduct = 0x3000, - .bcdDevice = 0x0100, - .iManufacturer = manufacturer, - .iProduct = product, - .iSerialNumber = serial_number, - .bNumConfigurations = 0x01 - }; - /* Full Speed is USB 1.1. */ if (R_SUCCEEDED(rc)) { - rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Full, &device_descriptor); + rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Full, &device_descriptor); /* Full Speed is USB 1.1. */ if (R_FAILED(rc)) LOGFILE("usbDsSetUsbDeviceDescriptor failed! (0x%08X) (USB 1.1).", rc); } - /* High Speed is USB 2.0. */ - device_descriptor.bcdUSB = USB_HS_BCD_REVISION; if (R_SUCCEEDED(rc)) { - rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_High, &device_descriptor); + /* Update USB revision before proceeding. */ + device_descriptor.bcdUSB = USB_HS_BCD_REVISION; + + rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_High, &device_descriptor); /* High Speed is USB 2.0. */ if (R_FAILED(rc)) LOGFILE("usbDsSetUsbDeviceDescriptor failed! (0x%08X) (USB 2.0).", rc); } - /* Super Speed is USB 3.0. */ - /* Upgrade packet size to 512 (1 << 9). */ - device_descriptor.bcdUSB = USB_SS_BCD_REVISION; - device_descriptor.bMaxPacketSize0 = 0x09; if (R_SUCCEEDED(rc)) { - rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Super, &device_descriptor); + /* Update USB revision and upgrade packet size to 512 (1 << 9) before proceeding. */ + device_descriptor.bcdUSB = USB_SS_BCD_REVISION; + device_descriptor.bMaxPacketSize0 = 0x09; + + rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Super, &device_descriptor); /* Super Speed is USB 3.0. */ if (R_FAILED(rc)) LOGFILE("usbDsSetUsbDeviceDescriptor failed! (0x%08X) (USB 3.0).", rc); } - /* Define Binary Object Store. */ - u8 bos[0x16] = { - /* USB 1.1. */ - 0x05, /* bLength. */ - USB_DT_BOS, /* bDescriptorType. */ - 0x16, 0x00, /* wTotalLength. */ - 0x02, /* bNumDeviceCaps. */ - - /* USB 2.0. */ - 0x07, /* bLength. */ - USB_DT_DEVICE_CAPABILITY, /* bDescriptorType. */ - 0x02, /* bDevCapabilityType. */ - 0x02, 0x00, 0x00, 0x00, /* dev_capability_data. */ - - /* USB 3.0. */ - 0x0A, /* bLength. */ - USB_DT_DEVICE_CAPABILITY, /* bDescriptorType. */ - 0x03, /* bDevCapabilityType. */ - 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00 - }; - + /* Set Binary Object Store. */ if (R_SUCCEEDED(rc)) { - rc = usbDsSetBinaryObjectStore(bos, sizeof(bos)); + rc = usbDsSetBinaryObjectStore(bos, USB_BOS_SIZE); if (R_FAILED(rc)) LOGFILE("usbDsSetBinaryObjectStore failed! (0x%08X).", rc); } } else { - static const UsbDsDeviceInfo device_info = { - .idVendor = 0x057e, - .idProduct = 0x3000, - .bcdDevice = 0x0100, - .Manufacturer = APP_AUTHOR, - .Product = APP_TITLE, - .SerialNumber = APP_VERSION - }; - /* Set VID, PID and BCD. */ rc = usbDsSetVidPidBcd(&device_info); if (R_FAILED(rc)) LOGFILE("usbDsSetVidPidBcd failed! (0x%08X).", rc); @@ -909,11 +975,13 @@ static bool usbInitializeDeviceInterface5x(void) struct usb_interface_descriptor interface_descriptor = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 4, + .bInterfaceNumber = USBDS_DEFAULT_InterfaceNumber, + .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = USB_CLASS_VENDOR_SPEC, .bInterfaceProtocol = USB_CLASS_VENDOR_SPEC, + .iInterface = 0 }; struct usb_endpoint_descriptor endpoint_descriptor_in = { @@ -921,7 +989,8 @@ static bool usbInitializeDeviceInterface5x(void) .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_ENDPOINT_IN, .bmAttributes = USB_TRANSFER_TYPE_BULK, - .wMaxPacketSize = USB_FS_EP_MAX_PACKET_SIZE, + .wMaxPacketSize = USB_FS_EP_MAX_PACKET_SIZE, /* Updated before setting new device descriptors for USB 2.0 and 3.0. */ + .bInterval = 0 }; struct usb_endpoint_descriptor endpoint_descriptor_out = { @@ -929,7 +998,8 @@ static bool usbInitializeDeviceInterface5x(void) .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_ENDPOINT_OUT, .bmAttributes = USB_TRANSFER_TYPE_BULK, - .wMaxPacketSize = USB_FS_EP_MAX_PACKET_SIZE, + .wMaxPacketSize = USB_FS_EP_MAX_PACKET_SIZE, /* Updated before setting new device descriptors for USB 2.0 and 3.0. */ + .bInterval = 0 }; struct usb_ss_endpoint_companion_descriptor endpoint_companion = { @@ -937,7 +1007,7 @@ static bool usbInitializeDeviceInterface5x(void) .bDescriptorType = USB_DT_SS_ENDPOINT_COMPANION, .bMaxBurst = 0x0F, .bmAttributes = 0x00, - .wBytesPerInterval = 0x00, + .wBytesPerInterval = 0x00 }; /* Enable device interface. */ @@ -1074,9 +1144,11 @@ static bool usbInitializeDeviceInterface1x(void) .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, + .bAlternateSetting = 0, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = USB_CLASS_VENDOR_SPEC, .bInterfaceProtocol = USB_CLASS_VENDOR_SPEC, + .iInterface = 0 }; struct usb_endpoint_descriptor endpoint_descriptor_in = { @@ -1085,6 +1157,7 @@ static bool usbInitializeDeviceInterface1x(void) .bEndpointAddress = USB_ENDPOINT_IN, .bmAttributes = USB_TRANSFER_TYPE_BULK, .wMaxPacketSize = USB_HS_EP_MAX_PACKET_SIZE, + .bInterval = 0 }; struct usb_endpoint_descriptor endpoint_descriptor_out = { @@ -1093,6 +1166,7 @@ static bool usbInitializeDeviceInterface1x(void) .bEndpointAddress = USB_ENDPOINT_OUT, .bmAttributes = USB_TRANSFER_TYPE_BULK, .wMaxPacketSize = USB_HS_EP_MAX_PACKET_SIZE, + .bInterval = 0 }; /* Enable device interface. */ diff --git a/source/usb.h b/source/usb.h index fdd6c9f..d0d4a7e 100644 --- a/source/usb.h +++ b/source/usb.h @@ -34,7 +34,7 @@ bool usbInitialize(void); /// Closes the USB interface, input and output endpoints and frees the transfer buffer. void usbExit(void); -/// Returns a pointer to a heap-allocated, page-aligned memory buffer that's suitable for USB transfers. +/// Returns a pointer to a dynamically allocated, page aligned memory buffer that's suitable for USB transfers. void *usbAllocatePageAlignedBuffer(size_t size); /// Used to check if the console has been connected to an USB host device and if a valid USB session has been established. diff --git a/source/utils.c b/source/utils.c index 0ca5eb0..757ed52 100644 --- a/source/utils.c +++ b/source/utils.c @@ -62,6 +62,8 @@ static const char *g_logfileLineBreak = "\r\n"; static const char *g_sizeSuffixes[] = { "B", "KiB", "MiB", "GiB" }; static const u32 g_sizeSuffixesCount = MAX_ELEMENTS(g_sizeSuffixes); +static const char *g_illegalFileSystemChars = "\\/:*?\"<>|^"; + /* Function prototypes. */ static bool _utilsGetCustomFirmwareType(void); @@ -524,7 +526,7 @@ void utilsReplaceIllegalCharacters(char *str, bool ascii_only) for(size_t i = 0; i < strsize; i++) { - if (memchr("?[]/\\=+<>:;\",*|^", str[i], sizeof("?[]/\\=+<>:;\",*|^") - 1) || str[i] < 0x20 || (!ascii_only && str[i] == 0x7F) || (ascii_only && str[i] >= 0x7F)) str[i] = '_'; + if (memchr(g_illegalFileSystemChars, str[i], sizeof(g_illegalFileSystemChars) - 1) || str[i] < 0x20 || (!ascii_only && str[i] == 0x7F) || (ascii_only && str[i] >= 0x7F)) str[i] = '_'; } }