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:
parent
ed2061ae3e
commit
e77c72b0db
8 changed files with 207 additions and 103 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -104,8 +104,9 @@ typedef enum {
|
|||
|
||||
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_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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
222
source/usb.c
222
source/usb.c
|
@ -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. */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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] = '_';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue