1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-12-23 09:02:06 +00:00

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.
This commit is contained in:
Pablo Curiel 2021-02-12 16:35:23 -04:00
parent ed2061ae3e
commit e77c72b0db
8 changed files with 207 additions and 103 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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 {

View file

@ -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;

View file

@ -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. */

View file

@ -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.

View file

@ -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] = '_';
}
}