mirror of
https://github.com/Huntereb/Awoo-Installer
synced 2024-11-10 06:04:20 +00:00
Latest libnx changes, install screen elements, error handling, better sigpatches stuff
This commit is contained in:
parent
049004bea4
commit
2fe766af47
43 changed files with 369 additions and 3009 deletions
|
@ -35,12 +35,12 @@ namespace tin::data
|
||||||
std::unique_ptr<BufferSegment[]> m_bufferSegments;
|
std::unique_ptr<BufferSegment[]> m_bufferSegments;
|
||||||
|
|
||||||
nx::ncm::ContentStorage* m_contentStorage;
|
nx::ncm::ContentStorage* m_contentStorage;
|
||||||
NcmNcaId m_ncaId;
|
NcmContentId m_ncaId;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const int NUM_BUFFER_SEGMENTS = 4;
|
static const int NUM_BUFFER_SEGMENTS = 4;
|
||||||
|
|
||||||
BufferedPlaceholderWriter(nx::ncm::ContentStorage* contentStorage, NcmNcaId ncaId, size_t totalDataSize);
|
BufferedPlaceholderWriter(nx::ncm::ContentStorage* contentStorage, NcmContentId ncaId, size_t totalDataSize);
|
||||||
|
|
||||||
void AppendData(void* source, size_t length);
|
void AppendData(void* source, size_t length);
|
||||||
bool CanAppendData(size_t length);
|
bool CanAppendData(size_t length);
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace tin::install::nsp
|
||||||
|
|
||||||
HTTPNSP(std::string url);
|
HTTPNSP(std::string url);
|
||||||
|
|
||||||
virtual void StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmNcaId placeholderId) override;
|
virtual void StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmContentId placeholderId) override;
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -33,7 +33,7 @@ namespace tin::install
|
||||||
virtual void InstallContentMetaRecords(tin::data::ByteBuffer& installContentMetaBuf);
|
virtual void InstallContentMetaRecords(tin::data::ByteBuffer& installContentMetaBuf);
|
||||||
virtual void InstallApplicationRecord();
|
virtual void InstallApplicationRecord();
|
||||||
virtual void InstallTicketCert() = 0;
|
virtual void InstallTicketCert() = 0;
|
||||||
virtual void InstallNCA(const NcmNcaId &ncaId) = 0;
|
virtual void InstallNCA(const NcmContentId &ncaId) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void Prepare();
|
virtual void Prepare();
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace tin::install::nsp
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::tuple<nx::ncm::ContentMeta, NcmContentInfo> ReadCNMT() override;
|
std::tuple<nx::ncm::ContentMeta, NcmContentInfo> ReadCNMT() override;
|
||||||
void InstallNCA(const NcmNcaId& ncaId) override;
|
void InstallNCA(const NcmContentId& ncaId) override;
|
||||||
void InstallTicketCert() override;
|
void InstallTicketCert() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace tin::install::nsp
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::tuple<nx::ncm::ContentMeta, NcmContentInfo> ReadCNMT() override;
|
std::tuple<nx::ncm::ContentMeta, NcmContentInfo> ReadCNMT() override;
|
||||||
void InstallNCA(const NcmNcaId& ncaId) override;
|
void InstallNCA(const NcmContentId& ncaId) override;
|
||||||
void InstallTicketCert() override;
|
void InstallTicketCert() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace tin::install::nsp
|
||||||
RemoteNSP();
|
RemoteNSP();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmNcaId placeholderId) = 0;
|
virtual void StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmContentId placeholderId) = 0;
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) = 0;
|
virtual void BufferData(void* buf, off_t offset, size_t size) = 0;
|
||||||
|
|
||||||
virtual void RetrieveHeader();
|
virtual void RetrieveHeader();
|
||||||
|
@ -27,7 +27,7 @@ namespace tin::install::nsp
|
||||||
|
|
||||||
virtual const PFS0FileEntry* GetFileEntry(unsigned int index);
|
virtual const PFS0FileEntry* GetFileEntry(unsigned int index);
|
||||||
virtual const PFS0FileEntry* GetFileEntryByName(std::string name);
|
virtual const PFS0FileEntry* GetFileEntryByName(std::string name);
|
||||||
virtual const PFS0FileEntry* GetFileEntryByNcaId(const NcmNcaId& ncaId);
|
virtual const PFS0FileEntry* GetFileEntryByNcaId(const NcmContentId& ncaId);
|
||||||
virtual const PFS0FileEntry* GetFileEntryByExtension(std::string extension);
|
virtual const PFS0FileEntry* GetFileEntryByExtension(std::string extension);
|
||||||
|
|
||||||
virtual const char* GetFileEntryName(const PFS0FileEntry* fileEntry);
|
virtual const char* GetFileEntryName(const PFS0FileEntry* fileEntry);
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "install/remote_nsp.hpp"
|
|
||||||
|
|
||||||
namespace tin::install::nsp
|
|
||||||
{
|
|
||||||
class USBNSP : public RemoteNSP
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::string m_nspName;
|
|
||||||
|
|
||||||
public:
|
|
||||||
USBNSP(std::string nspName);
|
|
||||||
|
|
||||||
virtual void StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmNcaId placeholderId) override;
|
|
||||||
virtual void BufferData(void* buf, off_t offset, size_t size) override;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
namespace inst::ui {
|
namespace inst::ui {
|
||||||
void setInstInfoText(std::string ourText);
|
void setInstInfoText(std::string ourText);
|
||||||
|
void setInstBarPerc(double ourPercent);
|
||||||
|
void hideInstBar(bool hidden);
|
||||||
void loadMainMenu();
|
void loadMainMenu();
|
||||||
void loadInstallScreen();
|
void loadInstallScreen();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ typedef struct {
|
||||||
|
|
||||||
Result esInitialize();
|
Result esInitialize();
|
||||||
void esExit();
|
void esExit();
|
||||||
|
Service* esGetServiceSession();
|
||||||
|
|
||||||
Result esImportTicket(void const *tikBuf, size_t tikSize, void const *certBuf, size_t certSize); //1
|
Result esImportTicket(void const *tikBuf, size_t tikSize, void const *certBuf, size_t certSize); //1
|
||||||
Result esDeleteTicket(const RightsId *rightsIdBuf, size_t bufSize); //3
|
Result esDeleteTicket(const RightsId *rightsIdBuf, size_t bufSize); //3
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/**
|
|
||||||
* @file usb_comms.h
|
|
||||||
* @brief USB comms.
|
|
||||||
* @author yellows8
|
|
||||||
* @author plutoo
|
|
||||||
* @copyright libnx Authors
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <switch/types.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Initializes usbComms with the default number of interfaces (1)
|
|
||||||
Result usbCommsInitialize(void);
|
|
||||||
/// Initializes usbComms with a specific number of interfaces.
|
|
||||||
Result usbCommsInitializeEx(u32 num_interfaces);
|
|
||||||
|
|
||||||
/// Exits usbComms.
|
|
||||||
void usbCommsExit(void);
|
|
||||||
|
|
||||||
/// Read data with the default interface.
|
|
||||||
size_t usbCommsRead(void* buffer, size_t size);
|
|
||||||
|
|
||||||
/// Write data with the default interface.
|
|
||||||
size_t usbCommsWrite(const void* buffer, size_t size);
|
|
||||||
|
|
||||||
/// Same as usbCommsRead except with the specified interface.
|
|
||||||
size_t usbCommsReadEx(void* buffer, size_t size, u32 interface);
|
|
||||||
|
|
||||||
/// Same as usbCommsWrite except with the specified interface.
|
|
||||||
size_t usbCommsWriteEx(const void* buffer, size_t size, u32 interface);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,265 +0,0 @@
|
||||||
/**
|
|
||||||
* @file usb.h
|
|
||||||
* @brief USB (usb:*) service IPC wrapper.
|
|
||||||
* @author SciresM, yellows8
|
|
||||||
* @copyright libnx Authors
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <switch/types.h>
|
|
||||||
#include <switch/services/sm.h>
|
|
||||||
#include <switch/kernel/event.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// usb:ds Switch-as-device<>host USB comms, see also here: http://switchbrew.org/index.php?title=USB_services
|
|
||||||
|
|
||||||
/// Names starting with "libusb" were changed to "usb" to avoid collision with actual libusb if it's ever used.
|
|
||||||
|
|
||||||
#define USBDS_DEFAULT_InterfaceNumber 0x4 ///Value for usb_interface_descriptor bInterfaceNumber for automatically allocating the actual bInterfaceNumber.
|
|
||||||
|
|
||||||
/// Imported from libusb with changed names.
|
|
||||||
/* Descriptor sizes per descriptor type */
|
|
||||||
#define USB_DT_INTERFACE_SIZE 9
|
|
||||||
#define USB_DT_ENDPOINT_SIZE 7
|
|
||||||
#define USB_DT_DEVICE_SIZE 0x12
|
|
||||||
#define USB_DT_SS_ENDPOINT_COMPANION_SIZE 6
|
|
||||||
|
|
||||||
/// Imported from libusb, with some adjustments.
|
|
||||||
struct usb_endpoint_descriptor {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType; /// Must match USB_DT_ENDPOINT.
|
|
||||||
uint8_t bEndpointAddress; /// Should be one of the usb_endpoint_direction values, the endpoint-number is automatically allocated.
|
|
||||||
uint8_t bmAttributes;
|
|
||||||
uint16_t wMaxPacketSize;
|
|
||||||
uint8_t bInterval;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Imported from libusb, with some adjustments.
|
|
||||||
struct usb_interface_descriptor {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType; /// Must match USB_DT_INTERFACE.
|
|
||||||
uint8_t bInterfaceNumber; /// See also USBDS_DEFAULT_InterfaceNumber.
|
|
||||||
uint8_t bAlternateSetting; /// Must match 0.
|
|
||||||
uint8_t bNumEndpoints;
|
|
||||||
uint8_t bInterfaceClass;
|
|
||||||
uint8_t bInterfaceSubClass;
|
|
||||||
uint8_t bInterfaceProtocol;
|
|
||||||
uint8_t iInterface; /// Ignored.
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Imported from libusb, with some adjustments.
|
|
||||||
struct usb_device_descriptor {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType; /// Must match USB_DT_Device.
|
|
||||||
uint16_t bcdUSB;
|
|
||||||
uint8_t bDeviceClass;
|
|
||||||
uint8_t bDeviceSubClass;
|
|
||||||
uint8_t bDeviceProtocol;
|
|
||||||
uint8_t bMaxPacketSize0;
|
|
||||||
uint16_t idVendor;
|
|
||||||
uint16_t idProduct;
|
|
||||||
uint16_t bcdDevice;
|
|
||||||
uint8_t iManufacturer;
|
|
||||||
uint8_t iProduct;
|
|
||||||
uint8_t iSerialNumber;
|
|
||||||
uint8_t bNumConfigurations;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Imported from libusb, with some adjustments.
|
|
||||||
struct usb_ss_endpoint_companion_descriptor {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType; /// Must match USB_DT_SS_ENDPOINT_COMPANION.
|
|
||||||
uint8_t bMaxBurst;
|
|
||||||
uint8_t bmAttributes;
|
|
||||||
uint16_t wBytesPerInterval;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Imported from libusb, with some adjustments.
|
|
||||||
struct usb_string_descriptor {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType; /// Must match USB_DT_STRING.
|
|
||||||
uint16_t wData[0x40];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u16 idVendor; /// VID
|
|
||||||
u16 idProduct; /// PID
|
|
||||||
u16 bcdDevice;
|
|
||||||
char Manufacturer[0x20];
|
|
||||||
char Product[0x20];
|
|
||||||
char SerialNumber[0x20];
|
|
||||||
} UsbDsDeviceInfo;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u32 id; /// urbId from post-buffer cmds
|
|
||||||
u32 requestedSize;
|
|
||||||
u32 transferredSize;
|
|
||||||
u32 urb_status;
|
|
||||||
} UsbDsReportEntry;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
UsbDsReportEntry report[8];
|
|
||||||
u32 report_count;
|
|
||||||
} UsbDsReportData;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool initialized;
|
|
||||||
u32 interface_index;
|
|
||||||
Service h;
|
|
||||||
|
|
||||||
Event SetupEvent;
|
|
||||||
Event CtrlInCompletionEvent;
|
|
||||||
Event CtrlOutCompletionEvent;
|
|
||||||
} UsbDsInterface;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool initialized;
|
|
||||||
Service h;
|
|
||||||
Event CompletionEvent;
|
|
||||||
} UsbDsEndpoint;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
UsbComplexId_Default = 0x2
|
|
||||||
} UsbComplexId;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
UsbDeviceSpeed_Full = 0x2,
|
|
||||||
UsbDeviceSpeed_High = 0x3,
|
|
||||||
UsbDeviceSpeed_Super = 0x4,
|
|
||||||
} UsbDeviceSpeed;
|
|
||||||
|
|
||||||
/// Imported from libusb, with changed names.
|
|
||||||
enum usb_class_code {
|
|
||||||
USB_CLASS_PER_INTERFACE = 0,
|
|
||||||
USB_CLASS_AUDIO = 1,
|
|
||||||
USB_CLASS_COMM = 2,
|
|
||||||
USB_CLASS_HID = 3,
|
|
||||||
USB_CLASS_PHYSICAL = 5,
|
|
||||||
USB_CLASS_PRINTER = 7,
|
|
||||||
USB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */
|
|
||||||
USB_CLASS_IMAGE = 6,
|
|
||||||
USB_CLASS_MASS_STORAGE = 8,
|
|
||||||
USB_CLASS_HUB = 9,
|
|
||||||
USB_CLASS_DATA = 10,
|
|
||||||
USB_CLASS_SMART_CARD = 0x0b,
|
|
||||||
USB_CLASS_CONTENT_SECURITY = 0x0d,
|
|
||||||
USB_CLASS_VIDEO = 0x0e,
|
|
||||||
USB_CLASS_PERSONAL_HEALTHCARE = 0x0f,
|
|
||||||
USB_CLASS_DIAGNOSTIC_DEVICE = 0xdc,
|
|
||||||
USB_CLASS_WIRELESS = 0xe0,
|
|
||||||
USB_CLASS_APPLICATION = 0xfe,
|
|
||||||
USB_CLASS_VENDOR_SPEC = 0xff
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Imported from libusb, with changed names.
|
|
||||||
enum usb_descriptor_type {
|
|
||||||
USB_DT_DEVICE = 0x01,
|
|
||||||
USB_DT_CONFIG = 0x02,
|
|
||||||
USB_DT_STRING = 0x03,
|
|
||||||
USB_DT_INTERFACE = 0x04,
|
|
||||||
USB_DT_ENDPOINT = 0x05,
|
|
||||||
USB_DT_BOS = 0x0f,
|
|
||||||
USB_DT_DEVICE_CAPABILITY = 0x10,
|
|
||||||
USB_DT_HID = 0x21,
|
|
||||||
USB_DT_REPORT = 0x22,
|
|
||||||
USB_DT_PHYSICAL = 0x23,
|
|
||||||
USB_DT_HUB = 0x29,
|
|
||||||
USB_DT_SUPERSPEED_HUB = 0x2a,
|
|
||||||
USB_DT_SS_ENDPOINT_COMPANION = 0x30
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Imported from libusb, with changed names.
|
|
||||||
enum usb_endpoint_direction {
|
|
||||||
USB_ENDPOINT_IN = 0x80,
|
|
||||||
USB_ENDPOINT_OUT = 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Imported from libusb, with changed names.
|
|
||||||
enum usb_transfer_type {
|
|
||||||
USB_TRANSFER_TYPE_CONTROL = 0,
|
|
||||||
USB_TRANSFER_TYPE_ISOCHRONOUS = 1,
|
|
||||||
USB_TRANSFER_TYPE_BULK = 2,
|
|
||||||
USB_TRANSFER_TYPE_INTERRUPT = 3,
|
|
||||||
USB_TRANSFER_TYPE_BULK_STREAM = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Imported from libusb, with changed names.
|
|
||||||
enum usb_iso_sync_type {
|
|
||||||
USB_ISO_SYNC_TYPE_NONE = 0,
|
|
||||||
USB_ISO_SYNC_TYPE_ASYNC = 1,
|
|
||||||
USB_ISO_SYNC_TYPE_ADAPTIVE = 2,
|
|
||||||
USB_ISO_SYNC_TYPE_SYNC = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Imported from libusb, with changed names.
|
|
||||||
enum usb_iso_usage_type {
|
|
||||||
USB_ISO_USAGE_TYPE_DATA = 0,
|
|
||||||
USB_ISO_USAGE_TYPE_FEEDBACK = 1,
|
|
||||||
USB_ISO_USAGE_TYPE_IMPLICIT = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Opens a session with usb:ds.
|
|
||||||
Result usbDsInitialize(void);
|
|
||||||
/// Closes the usb:ds session. Any interfaces/endpoints which are left open are automatically closed, since otherwise usb-sysmodule won't fully reset usb:ds to defaults.
|
|
||||||
void usbDsExit(void);
|
|
||||||
|
|
||||||
/// Helpers
|
|
||||||
Result usbDsWaitReady(u64 timeout);
|
|
||||||
Result usbDsParseReportData(UsbDsReportData *reportdata, u32 urbId, u32 *requestedSize, u32 *transferredSize);
|
|
||||||
|
|
||||||
/// IDsService
|
|
||||||
// Do not provide API access to these functions, as they're handled by usbDsInitialize().
|
|
||||||
// Result usbDsBindDevice(UsbComplexId complexId);
|
|
||||||
// Result usbDsBindClientProcess(Handle prochandle);
|
|
||||||
Event* usbDsGetStateChangeEvent(void);
|
|
||||||
Result usbDsGetState(u32* out);
|
|
||||||
|
|
||||||
/// Removed in 5.0.0
|
|
||||||
Result usbDsGetDsInterface(UsbDsInterface** out, struct usb_interface_descriptor* descriptor, const char* interface_name);
|
|
||||||
Result usbDsSetVidPidBcd(const UsbDsDeviceInfo* deviceinfo);
|
|
||||||
|
|
||||||
/// Added in 5.0.0
|
|
||||||
Result usbDsRegisterInterface(UsbDsInterface** out, u32 intf_num);
|
|
||||||
Result usbDsClearDeviceData(void);
|
|
||||||
Result usbDsAddUsbStringDescriptor(u8* out_index, const char* string);
|
|
||||||
Result usbDsAddUsbLanguageStringDescriptor(u8* out_index, const u16* lang_ids, u16 num_langs);
|
|
||||||
Result usbDsDeleteUsbStringDescriptor(u8 index);
|
|
||||||
Result usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed speed, struct usb_device_descriptor* descriptor);
|
|
||||||
Result usbDsSetBinaryObjectStore(void* bos, size_t bos_size);
|
|
||||||
Result usbDsEnable(void);
|
|
||||||
Result usbDsDisable(void);
|
|
||||||
|
|
||||||
/// IDsInterface
|
|
||||||
void usbDsInterface_Close(UsbDsInterface* interface);
|
|
||||||
|
|
||||||
Result usbDsInterface_GetSetupPacket(UsbDsInterface* interface, void* buffer, size_t size);
|
|
||||||
Result usbDsInterface_EnableInterface(UsbDsInterface* interface);
|
|
||||||
Result usbDsInterface_DisableInterface(UsbDsInterface* interface);
|
|
||||||
Result usbDsInterface_CtrlInPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32* urbId);
|
|
||||||
Result usbDsInterface_CtrlOutPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32* urbId);
|
|
||||||
Result usbDsInterface_GetCtrlInReportData(UsbDsInterface* interface, UsbDsReportData* out);
|
|
||||||
Result usbDsInterface_GetCtrlOutReportData(UsbDsInterface* interface, UsbDsReportData* out);
|
|
||||||
Result usbDsInterface_StallCtrl(UsbDsInterface* interface);
|
|
||||||
|
|
||||||
/// Removed in 5.0.0
|
|
||||||
Result usbDsInterface_GetDsEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, struct usb_endpoint_descriptor* descriptor);
|
|
||||||
|
|
||||||
/// Added in 5.0.0
|
|
||||||
Result usbDsInterface_RegisterEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, u8 endpoint_address);
|
|
||||||
Result usbDsInterface_AppendConfigurationData(UsbDsInterface* interface, UsbDeviceSpeed speed, void* buffer, size_t size);
|
|
||||||
|
|
||||||
|
|
||||||
/// IDsEndpoint
|
|
||||||
void usbDsEndpoint_Close(UsbDsEndpoint* endpoint);
|
|
||||||
|
|
||||||
Result usbDsEndpoint_Cancel(UsbDsEndpoint* endpoint);
|
|
||||||
Result usbDsEndpoint_PostBufferAsync(UsbDsEndpoint* endpoint, void* buffer, size_t size, u32* urbId);
|
|
||||||
Result usbDsEndpoint_GetReportData(UsbDsEndpoint* endpoint, UsbDsReportData* out);
|
|
||||||
Result usbDsEndpoint_StallCtrl(UsbDsEndpoint* endpoint);
|
|
||||||
Result usbDsEndpoint_SetZlt(UsbDsEndpoint* endpoint, bool zlt);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -25,12 +25,12 @@ namespace nx::ncm
|
||||||
ContentStorage(FsStorageId storageId);
|
ContentStorage(FsStorageId storageId);
|
||||||
~ContentStorage();
|
~ContentStorage();
|
||||||
|
|
||||||
void CreatePlaceholder(const NcmNcaId &placeholderId, const NcmNcaId ®isteredId, size_t size);
|
void CreatePlaceholder(const NcmContentId &placeholderId, const NcmContentId ®isteredId, size_t size);
|
||||||
void DeletePlaceholder(const NcmNcaId &placeholderId);
|
void DeletePlaceholder(const NcmContentId &placeholderId);
|
||||||
void WritePlaceholder(const NcmNcaId &placeholderId, u64 offset, void *buffer, size_t bufSize);
|
void WritePlaceholder(const NcmContentId &placeholderId, u64 offset, void *buffer, size_t bufSize);
|
||||||
void Register(const NcmNcaId &placeholderId, const NcmNcaId ®isteredId);
|
void Register(const NcmContentId &placeholderId, const NcmContentId ®isteredId);
|
||||||
void Delete(const NcmNcaId ®isteredId);
|
void Delete(const NcmContentId ®isteredId);
|
||||||
bool Has(const NcmNcaId ®isteredId);
|
bool Has(const NcmContentId ®isteredId);
|
||||||
std::string GetPath(const NcmNcaId ®isteredId);
|
std::string GetPath(const NcmContentId ®isteredId);
|
||||||
};
|
};
|
||||||
}
|
}
|
3
include/sigInstall.hpp
Executable file
3
include/sigInstall.hpp
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
namespace sig {
|
||||||
|
void installSigPatches ();
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ namespace inst::ui {
|
||||||
PU_SMART_CTOR(instPage)
|
PU_SMART_CTOR(instPage)
|
||||||
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
void onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos);
|
||||||
TextBlock::Ref pageInfoText;
|
TextBlock::Ref pageInfoText;
|
||||||
|
pu::ui::elm::ProgressBar::Ref installBar;
|
||||||
private:
|
private:
|
||||||
TextBlock::Ref topText;
|
TextBlock::Ref topText;
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,8 +10,8 @@ namespace tin::util
|
||||||
u64 GetRightsIdTid(RightsId rightsId);
|
u64 GetRightsIdTid(RightsId rightsId);
|
||||||
u64 GetRightsIdKeyGen(RightsId rightsId);
|
u64 GetRightsIdKeyGen(RightsId rightsId);
|
||||||
|
|
||||||
std::string GetNcaIdString(const NcmNcaId& ncaId);
|
std::string GetNcaIdString(const NcmContentId& ncaId);
|
||||||
NcmNcaId GetNcaIdFromString(std::string ncaIdStr);
|
NcmContentId GetNcaIdFromString(std::string ncaIdStr);
|
||||||
|
|
||||||
u64 GetBaseTitleId(u64 titleId, NcmContentMetaType contentMetaType);
|
u64 GetBaseTitleId(u64 titleId, NcmContentMetaType contentMetaType);
|
||||||
std::string GetBaseTitleName(u64 baseTitleId);
|
std::string GetBaseTitleName(u64 baseTitleId);
|
||||||
|
|
|
@ -9,4 +9,6 @@ namespace util {
|
||||||
void initApp ();
|
void initApp ();
|
||||||
void deinitApp ();
|
void deinitApp ();
|
||||||
std::vector<std::filesystem::path> getDirectoryFiles(const std::string & dir, const std::vector<std::string> & extensions);
|
std::vector<std::filesystem::path> getDirectoryFiles(const std::string & dir, const std::vector<std::string> & extensions);
|
||||||
|
bool removeDirectory(std::string dir);
|
||||||
|
bool copyFile(std::string inFile, std::string outFile);
|
||||||
}
|
}
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
namespace tin::data
|
namespace tin::data
|
||||||
{
|
{
|
||||||
BufferedPlaceholderWriter::BufferedPlaceholderWriter(nx::ncm::ContentStorage* contentStorage, NcmNcaId ncaId, size_t totalDataSize) :
|
BufferedPlaceholderWriter::BufferedPlaceholderWriter(nx::ncm::ContentStorage* contentStorage, NcmContentId ncaId, size_t totalDataSize) :
|
||||||
m_totalDataSize(totalDataSize), m_contentStorage(contentStorage), m_ncaId(ncaId)
|
m_totalDataSize(totalDataSize), m_contentStorage(contentStorage), m_ncaId(ncaId)
|
||||||
{
|
{
|
||||||
// Though currently the number of segments is fixed, we want them allocated on the heap, not the stack
|
// Though currently the number of segments is fixed, we want them allocated on the heap, not the stack
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "util/title_util.hpp"
|
#include "util/title_util.hpp"
|
||||||
#include "util/error.hpp"
|
#include "util/error.hpp"
|
||||||
#include "util/debug.h"
|
#include "util/debug.h"
|
||||||
|
#include "nspInstall.hpp"
|
||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
|
@ -56,7 +57,7 @@ namespace tin::install::nsp
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPNSP::StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmNcaId placeholderId)
|
void HTTPNSP::StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmContentId placeholderId)
|
||||||
{
|
{
|
||||||
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
|
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
|
||||||
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
||||||
|
@ -103,6 +104,8 @@ namespace tin::install::nsp
|
||||||
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
||||||
|
|
||||||
printf("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
|
printf("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
|
||||||
|
inst::ui::setInstInfoText("Downloading " + ncaFileName + "...");
|
||||||
|
inst::ui::setInstBarPerc((double)downloadProgress);
|
||||||
//consoleUpdate(NULL);
|
//consoleUpdate(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,9 +117,11 @@ namespace tin::install::nsp
|
||||||
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
||||||
|
|
||||||
printf("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
|
printf("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
|
||||||
|
inst::ui::setInstInfoText("Installing " + ncaFileName + "...");
|
||||||
|
inst::ui::setInstBarPerc((double)installProgress);
|
||||||
//consoleUpdate(NULL);
|
//consoleUpdate(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
thrd_join(curlThread, NULL);
|
thrd_join(curlThread, NULL);
|
||||||
thrd_join(writeThread, NULL);
|
thrd_join(writeThread, NULL);
|
||||||
//consoleUpdate(NULL);
|
//consoleUpdate(NULL);
|
||||||
|
|
|
@ -156,7 +156,7 @@ namespace tin::install
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Post Install Records: \n");
|
printf("Post Install Records: \n");
|
||||||
this->DebugPrintInstallData();
|
//this->DebugPrintInstallData();
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Install::GetTitleId()
|
u64 Install::GetTitleId()
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "util/title_util.hpp"
|
#include "util/title_util.hpp"
|
||||||
#include "util/debug.h"
|
#include "util/debug.h"
|
||||||
#include "util/error.hpp"
|
#include "util/error.hpp"
|
||||||
|
#include "nspInstall.hpp"
|
||||||
|
|
||||||
namespace tin::install::nsp
|
namespace tin::install::nsp
|
||||||
{
|
{
|
||||||
|
@ -55,7 +56,7 @@ namespace tin::install::nsp
|
||||||
//consoleUpdate(NULL);
|
//consoleUpdate(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NSPInstallTask::InstallNCA(const NcmNcaId &ncaId)
|
void NSPInstallTask::InstallNCA(const NcmContentId &ncaId)
|
||||||
{
|
{
|
||||||
std::string ncaName = tin::util::GetNcaIdString(ncaId);
|
std::string ncaName = tin::util::GetNcaIdString(ncaId);
|
||||||
|
|
||||||
|
@ -101,8 +102,11 @@ namespace tin::install::nsp
|
||||||
// Clear the buffer before we read anything, just to be sure
|
// Clear the buffer before we read anything, just to be sure
|
||||||
progress = (float)fileOff / (float)ncaSize;
|
progress = (float)fileOff / (float)ncaSize;
|
||||||
|
|
||||||
if (fileOff % (0x400000 * 3) == 0)
|
if (fileOff % (0x400000 * 3) == 0) {
|
||||||
printf("> Progress: %lu/%lu MB (%d%s)\r", (fileOff / 1000000), (ncaSize / 1000000), (int)(progress * 100.0), "%");
|
printf("> Progress: %lu/%lu MB (%d%s)\r", (fileOff / 1000000), (ncaSize / 1000000), (int)(progress * 100.0), "%");
|
||||||
|
inst::ui::setInstInfoText("Installing " + ncaName + "...");
|
||||||
|
inst::ui::setInstBarPerc((double)(progress * 100.0));
|
||||||
|
}
|
||||||
|
|
||||||
if (fileOff + readSize >= ncaSize) readSize = ncaSize - fileOff;
|
if (fileOff + readSize >= ncaSize) readSize = ncaSize - fileOff;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace tin::install::nsp
|
||||||
THROW_FORMAT("Failed to find cnmt file entry!\n");
|
THROW_FORMAT("Failed to find cnmt file entry!\n");
|
||||||
|
|
||||||
std::string cnmtNcaName(m_remoteNSP->GetFileEntryName(fileEntry));
|
std::string cnmtNcaName(m_remoteNSP->GetFileEntryName(fileEntry));
|
||||||
NcmNcaId cnmtContentId = tin::util::GetNcaIdFromString(cnmtNcaName);
|
NcmContentId cnmtContentId = tin::util::GetNcaIdFromString(cnmtNcaName);
|
||||||
size_t cnmtNcaSize = fileEntry->fileSize;
|
size_t cnmtNcaSize = fileEntry->fileSize;
|
||||||
|
|
||||||
nx::ncm::ContentStorage contentStorage(m_destStorageId);
|
nx::ncm::ContentStorage contentStorage(m_destStorageId);
|
||||||
|
@ -44,7 +44,7 @@ namespace tin::install::nsp
|
||||||
return { tin::util::GetContentMetaFromNCA(cnmtNCAFullPath), cnmtContentInfo };
|
return { tin::util::GetContentMetaFromNCA(cnmtNCAFullPath), cnmtContentInfo };
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteNSPInstall::InstallNCA(const NcmNcaId& ncaId)
|
void RemoteNSPInstall::InstallNCA(const NcmContentId& ncaId)
|
||||||
{
|
{
|
||||||
const PFS0FileEntry* fileEntry = m_remoteNSP->GetFileEntryByNcaId(ncaId);
|
const PFS0FileEntry* fileEntry = m_remoteNSP->GetFileEntryByNcaId(ncaId);
|
||||||
std::string ncaFileName = m_remoteNSP->GetFileEntryName(fileEntry);
|
std::string ncaFileName = m_remoteNSP->GetFileEntryName(fileEntry);
|
||||||
|
|
|
@ -76,7 +76,7 @@ namespace tin::install::nsp
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PFS0FileEntry* RemoteNSP::GetFileEntryByNcaId(const NcmNcaId& ncaId)
|
const PFS0FileEntry* RemoteNSP::GetFileEntryByNcaId(const NcmContentId& ncaId)
|
||||||
{
|
{
|
||||||
const PFS0FileEntry* fileEntry = nullptr;
|
const PFS0FileEntry* fileEntry = nullptr;
|
||||||
std::string ncaIdStr = tin::util::GetNcaIdString(ncaId);
|
std::string ncaIdStr = tin::util::GetNcaIdString(ncaId);
|
||||||
|
|
|
@ -1,149 +0,0 @@
|
||||||
#include "install/usb_nsp.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
#include <switch.h>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <threads.h>
|
|
||||||
#include "data/byte_buffer.hpp"
|
|
||||||
#include "data/buffered_placeholder_writer.hpp"
|
|
||||||
#include "util/usb_util.hpp"
|
|
||||||
#include "util/error.hpp"
|
|
||||||
#include "util/debug.h"
|
|
||||||
|
|
||||||
namespace tin::install::nsp
|
|
||||||
{
|
|
||||||
USBNSP::USBNSP(std::string nspName) :
|
|
||||||
m_nspName(nspName)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct USBFuncArgs
|
|
||||||
{
|
|
||||||
std::string nspName;
|
|
||||||
tin::data::BufferedPlaceholderWriter* bufferedPlaceholderWriter;
|
|
||||||
u64 pfs0Offset;
|
|
||||||
u64 ncaSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
int USBThreadFunc(void* in)
|
|
||||||
{
|
|
||||||
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
|
|
||||||
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(args->nspName, args->pfs0Offset, args->ncaSize);
|
|
||||||
|
|
||||||
u8* buf = (u8*)memalign(0x1000, 0x800000);
|
|
||||||
u64 sizeRemaining = header.dataSize;
|
|
||||||
size_t tmpSizeRead = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (sizeRemaining)
|
|
||||||
{
|
|
||||||
tmpSizeRead = usbCommsRead(buf, std::min(sizeRemaining, (u64)0x800000));
|
|
||||||
//printf("Read bytes\n")
|
|
||||||
//printBytes(nxlinkout, buf, tmpSizeRead, true);
|
|
||||||
sizeRemaining -= tmpSizeRead;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (args->bufferedPlaceholderWriter->CanAppendData(tmpSizeRead))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
args->bufferedPlaceholderWriter->AppendData(buf, tmpSizeRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::exception& e)
|
|
||||||
{
|
|
||||||
printf("An error occurred:\n%s\n", e.what());
|
|
||||||
printf("An error occurred:\n%s", e.what());
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int USBPlaceholderWriteFunc(void* in)
|
|
||||||
{
|
|
||||||
USBFuncArgs* args = reinterpret_cast<USBFuncArgs*>(in);
|
|
||||||
|
|
||||||
while (!args->bufferedPlaceholderWriter->IsPlaceholderComplete())
|
|
||||||
{
|
|
||||||
if (args->bufferedPlaceholderWriter->CanWriteSegmentToPlaceholder())
|
|
||||||
args->bufferedPlaceholderWriter->WriteSegmentToPlaceholder();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void USBNSP::StreamToPlaceholder(nx::ncm::ContentStorage& contentStorage, NcmNcaId placeholderId)
|
|
||||||
{
|
|
||||||
const PFS0FileEntry* fileEntry = this->GetFileEntryByNcaId(placeholderId);
|
|
||||||
std::string ncaFileName = this->GetFileEntryName(fileEntry);
|
|
||||||
|
|
||||||
printf("Retrieving %s\n", ncaFileName.c_str());
|
|
||||||
size_t ncaSize = fileEntry->fileSize;
|
|
||||||
|
|
||||||
tin::data::BufferedPlaceholderWriter bufferedPlaceholderWriter(&contentStorage, placeholderId, ncaSize);
|
|
||||||
USBFuncArgs args;
|
|
||||||
args.nspName = m_nspName;
|
|
||||||
args.bufferedPlaceholderWriter = &bufferedPlaceholderWriter;
|
|
||||||
args.pfs0Offset = this->GetDataOffset() + fileEntry->dataOffset;
|
|
||||||
args.ncaSize = ncaSize;
|
|
||||||
thrd_t usbThread;
|
|
||||||
thrd_t writeThread;
|
|
||||||
|
|
||||||
thrd_create(&usbThread, USBThreadFunc, &args);
|
|
||||||
thrd_create(&writeThread, USBPlaceholderWriteFunc, &args);
|
|
||||||
|
|
||||||
u64 freq = armGetSystemTickFreq();
|
|
||||||
u64 startTime = armGetSystemTick();
|
|
||||||
size_t startSizeBuffered = 0;
|
|
||||||
double speed = 0.0;
|
|
||||||
|
|
||||||
while (!bufferedPlaceholderWriter.IsBufferDataComplete())
|
|
||||||
{
|
|
||||||
u64 newTime = armGetSystemTick();
|
|
||||||
|
|
||||||
if (newTime - startTime >= freq)
|
|
||||||
{
|
|
||||||
size_t newSizeBuffered = bufferedPlaceholderWriter.GetSizeBuffered();
|
|
||||||
double mbBuffered = (newSizeBuffered / 1000000.0) - (startSizeBuffered / 1000000.0);
|
|
||||||
double duration = ((double)(newTime - startTime) / (double)freq);
|
|
||||||
speed = mbBuffered / duration;
|
|
||||||
|
|
||||||
startTime = newTime;
|
|
||||||
startSizeBuffered = newSizeBuffered;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
|
||||||
u64 downloadSizeMB = bufferedPlaceholderWriter.GetSizeBuffered() / 1000000;
|
|
||||||
int downloadProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeBuffered() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
|
||||||
|
|
||||||
printf("> Download Progress: %lu/%lu MB (%i%s) (%.2f MB/s)\r", downloadSizeMB, totalSizeMB, downloadProgress, "%", speed);
|
|
||||||
//consoleUpdate(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 totalSizeMB = bufferedPlaceholderWriter.GetTotalDataSize() / 1000000;
|
|
||||||
|
|
||||||
while (!bufferedPlaceholderWriter.IsPlaceholderComplete())
|
|
||||||
{
|
|
||||||
u64 installSizeMB = bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / 1000000;
|
|
||||||
int installProgress = (int)(((double)bufferedPlaceholderWriter.GetSizeWrittenToPlaceholder() / (double)bufferedPlaceholderWriter.GetTotalDataSize()) * 100.0);
|
|
||||||
|
|
||||||
printf("> Install Progress: %lu/%lu MB (%i%s)\r", installSizeMB, totalSizeMB, installProgress, "%");
|
|
||||||
//consoleUpdate(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
thrd_join(usbThread, NULL);
|
|
||||||
thrd_join(writeThread, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void USBNSP::BufferData(void* buf, off_t offset, size_t size)
|
|
||||||
{
|
|
||||||
tin::util::USBCmdHeader header = tin::util::USBCmdManager::SendFileRangeCmd(m_nspName, offset, size);
|
|
||||||
tin::util::USBRead(buf, header.dataSize);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -43,7 +43,6 @@ namespace netInstStuff{
|
||||||
|
|
||||||
if (m_serverSocket < -1)
|
if (m_serverSocket < -1)
|
||||||
{
|
{
|
||||||
inst::ui::mainApp->CreateShowDialog("Failed to create a server socket.", "", {"OK"}, true);
|
|
||||||
THROW_FORMAT("Failed to create a server socket. Error code: %u\n", errno);
|
THROW_FORMAT("Failed to create a server socket. Error code: %u\n", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +53,6 @@ namespace netInstStuff{
|
||||||
|
|
||||||
if (bind(m_serverSocket, (struct sockaddr*) &server, sizeof(server)) < 0)
|
if (bind(m_serverSocket, (struct sockaddr*) &server, sizeof(server)) < 0)
|
||||||
{
|
{
|
||||||
inst::ui::mainApp->CreateShowDialog("Failed to bind server socket.", "", {"OK"}, true);
|
|
||||||
THROW_FORMAT("Failed to bind server socket. Error code: %u\n", errno);
|
THROW_FORMAT("Failed to bind server socket. Error code: %u\n", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,13 +61,11 @@ namespace netInstStuff{
|
||||||
|
|
||||||
if (listen(m_serverSocket, 5) < 0)
|
if (listen(m_serverSocket, 5) < 0)
|
||||||
{
|
{
|
||||||
inst::ui::mainApp->CreateShowDialog("Failed to listen on server socket.", "", {"OK"}, true);
|
|
||||||
THROW_FORMAT("Failed to listen on server socket. Error code: %u\n", errno);
|
THROW_FORMAT("Failed to listen on server socket. Error code: %u\n", errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
inst::ui::mainApp->CreateShowDialog("Failed to initialize server socket!", "", {"OK"}, true);
|
|
||||||
printf("Failed to initialize server socket!\n");
|
printf("Failed to initialize server socket!\n");
|
||||||
fprintf(stdout, "%s", e.what());
|
fprintf(stdout, "%s", e.what());
|
||||||
|
|
||||||
|
@ -78,6 +74,7 @@ namespace netInstStuff{
|
||||||
close(m_serverSocket);
|
close(m_serverSocket);
|
||||||
m_serverSocket = 0;
|
m_serverSocket = 0;
|
||||||
}
|
}
|
||||||
|
inst::ui::mainApp->CreateShowDialog("Failed to initialize server socket!", (std::string)e.what(), {"OK"}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnUnwound()
|
void OnUnwound()
|
||||||
|
@ -100,7 +97,7 @@ namespace netInstStuff{
|
||||||
tin::install::nsp::HTTPNSP httpNSP(ourUrl);
|
tin::install::nsp::HTTPNSP httpNSP(ourUrl);
|
||||||
|
|
||||||
printf("%s %s\n", "NSP_INSTALL_FROM", ourUrl.c_str());
|
printf("%s %s\n", "NSP_INSTALL_FROM", ourUrl.c_str());
|
||||||
// second var is ignoring required version
|
// second var is ignoring required version --- add config for this
|
||||||
tin::install::nsp::RemoteNSPInstall install(m_destStorageId, true, &httpNSP);
|
tin::install::nsp::RemoteNSPInstall install(m_destStorageId, true, &httpNSP);
|
||||||
|
|
||||||
printf("%s\n", "NSP_INSTALL_PREPARING");
|
printf("%s\n", "NSP_INSTALL_PREPARING");
|
||||||
|
@ -127,7 +124,7 @@ namespace netInstStuff{
|
||||||
printf("Failed to install NSP");
|
printf("Failed to install NSP");
|
||||||
printf("%s", e.what());
|
printf("%s", e.what());
|
||||||
fprintf(stdout, "%s", e.what());
|
fprintf(stdout, "%s", e.what());
|
||||||
inst::ui::mainApp->CreateShowDialog("Failed to install NSP!", "", {"OK"}, true);
|
inst::ui::mainApp->CreateShowDialog("Failed to install NSP!", (std::string)e.what(), {"OK"}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Done");
|
printf("Done");
|
||||||
|
@ -149,7 +146,6 @@ namespace netInstStuff{
|
||||||
|
|
||||||
if (m_serverSocket <= 0)
|
if (m_serverSocket <= 0)
|
||||||
{
|
{
|
||||||
inst::ui::mainApp->CreateShowDialog("Server socket failed to initialize.", "", {"OK"}, true);
|
|
||||||
THROW_FORMAT("Server socket failed to initialize.\n");
|
THROW_FORMAT("Server socket failed to initialize.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +189,6 @@ namespace netInstStuff{
|
||||||
|
|
||||||
if (size > MAX_URL_SIZE * MAX_URLS)
|
if (size > MAX_URL_SIZE * MAX_URLS)
|
||||||
{
|
{
|
||||||
inst::ui::mainApp->CreateShowDialog("URL size is too large!", "", {"OK"}, true);
|
|
||||||
THROW_FORMAT("URL size %x is too large!\n", size);
|
THROW_FORMAT("URL size %x is too large!\n", size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +213,6 @@ namespace netInstStuff{
|
||||||
}
|
}
|
||||||
else if (errno != EAGAIN)
|
else if (errno != EAGAIN)
|
||||||
{
|
{
|
||||||
inst::ui::mainApp->CreateShowDialog("Failed to open client socket", "", {"OK"}, true);
|
|
||||||
THROW_FORMAT("Failed to open client socket with code %u\n", errno);
|
THROW_FORMAT("Failed to open client socket with code %u\n", errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,10 +222,10 @@ namespace netInstStuff{
|
||||||
}
|
}
|
||||||
catch (std::runtime_error& e)
|
catch (std::runtime_error& e)
|
||||||
{
|
{
|
||||||
inst::ui::mainApp->CreateShowDialog("Failed to perform remote install!", "", {"OK"}, true);
|
|
||||||
printf("Failed to perform remote install!\n");
|
printf("Failed to perform remote install!\n");
|
||||||
printf("%s", e.what());
|
printf("%s", e.what());
|
||||||
fprintf(stdout, "%s", e.what());
|
fprintf(stdout, "%s", e.what());
|
||||||
|
inst::ui::mainApp->CreateShowDialog("Failed to perform remote install!", (std::string)e.what(), {"OK"}, true);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,20 @@ namespace inst::ui {
|
||||||
mainApp->CallForRender();
|
mainApp->CallForRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setInstBarPerc(double ourPercent){
|
||||||
|
mainApp->instpage->installBar->SetVisible(true);
|
||||||
|
mainApp->instpage->installBar->SetProgress(ourPercent);
|
||||||
|
mainApp->CallForRender();
|
||||||
|
}
|
||||||
|
|
||||||
void loadMainMenu(){
|
void loadMainMenu(){
|
||||||
mainApp->LoadLayout(mainApp->mainPage);
|
mainApp->LoadLayout(mainApp->mainPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadInstallScreen(){
|
void loadInstallScreen(){
|
||||||
mainApp->instpage->pageInfoText->SetText("");
|
mainApp->instpage->pageInfoText->SetText("");
|
||||||
|
mainApp->instpage->installBar->SetProgress(0);
|
||||||
|
mainApp->instpage->installBar->SetVisible(false);
|
||||||
mainApp->LoadLayout(mainApp->instpage);
|
mainApp->LoadLayout(mainApp->instpage);
|
||||||
mainApp->CallForRender();
|
mainApp->CallForRender();
|
||||||
}
|
}
|
||||||
|
@ -75,7 +83,7 @@ namespace nspInstStuff {
|
||||||
printf("Failed to install NSP");
|
printf("Failed to install NSP");
|
||||||
printf("%s", e.what());
|
printf("%s", e.what());
|
||||||
fprintf(stdout, "%s", e.what());
|
fprintf(stdout, "%s", e.what());
|
||||||
inst::ui::mainApp->CreateShowDialog("Failed to install NSP!", "", {"OK"}, true);
|
inst::ui::mainApp->CreateShowDialog("Failed to install NSP!", (std::string)e.what(), {"OK"}, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace nx::fs
|
||||||
|
|
||||||
Result IFileSystem::OpenSdFileSystem()
|
Result IFileSystem::OpenSdFileSystem()
|
||||||
{
|
{
|
||||||
ASSERT_OK(fsMountSdcard(&m_fileSystem), "Failed to mount sd card");
|
ASSERT_OK(fsOpenSdCardFileSystem(&m_fileSystem), "Failed to mount sd card");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,301 +3,109 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <switch/arm/atomics.h>
|
#include "service_guard.h"
|
||||||
|
|
||||||
static Service g_esSrv;
|
static Service g_esSrv;
|
||||||
static u64 g_esRefCnt;
|
|
||||||
|
|
||||||
Result esInitialize() {
|
NX_GENERATE_SERVICE_GUARD(es);
|
||||||
atomicIncrement64(&g_esRefCnt);
|
|
||||||
Result rc = smGetService(&g_esSrv, "es");
|
Result _esInitialize() {
|
||||||
return rc;
|
return smGetService(&g_esSrv, "es");
|
||||||
}
|
}
|
||||||
|
|
||||||
void esExit() {
|
void _esCleanup() {
|
||||||
if (atomicDecrement64(&g_esRefCnt) == 0) {
|
serviceClose(&g_esSrv);
|
||||||
serviceClose(&g_esSrv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esImportTicket(void const *tikBuf, size_t tikSize, void const *certBuf, size_t certSize)
|
Service* esGetServiceSession() {
|
||||||
{
|
return &g_esSrv;
|
||||||
IpcCommand c;
|
}
|
||||||
ipcInitialize(&c);
|
|
||||||
ipcAddSendBuffer(&c, tikBuf, tikSize, BufferType_Normal);
|
|
||||||
ipcAddSendBuffer(&c, certBuf, certSize, BufferType_Normal);
|
|
||||||
|
|
||||||
struct {
|
Result esImportTicket(void const *tikBuf, size_t tikSize, void const *certBuf, size_t certSize) {
|
||||||
u64 magic;
|
return serviceDispatch(&g_esSrv, 1,
|
||||||
u64 cmd_id;
|
.buffer_attrs = {
|
||||||
} *raw;
|
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
||||||
|
SfBufferAttr_HipcMapAlias | SfBufferAttr_In,
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
},
|
||||||
raw->magic = SFCI_MAGIC;
|
.buffers = {
|
||||||
raw->cmd_id = 1;
|
{ tikBuf, tikSize },
|
||||||
|
{ certBuf, certSize },
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
},
|
||||||
|
);
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esDeleteTicket(const RightsId *rightsIdBuf, size_t bufSize) {
|
Result esDeleteTicket(const RightsId *rightsIdBuf, size_t bufSize) {
|
||||||
IpcCommand c;
|
return serviceDispatch(&g_esSrv, 3,
|
||||||
ipcInitialize(&c);
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
||||||
ipcAddSendBuffer(&c, rightsIdBuf, bufSize, BufferType_Normal);
|
.buffers = { { rightsIdBuf, bufSize }, },
|
||||||
|
);
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 3;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esGetTitleKey(const RightsId *rightsId, u8 *outBuf, size_t bufSize) {
|
Result esGetTitleKey(const RightsId *rightsId, u8 *outBuf, size_t bufSize) {
|
||||||
IpcCommand c;
|
return serviceDispatchIn(&g_esSrv, 8, *rightsId,
|
||||||
ipcInitialize(&c);
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||||
ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal);
|
.buffers = { { outBuf, bufSize } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result esCountCommonTicket(u32 *numTickets) {
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u32 num_tickets;
|
||||||
u64 cmd_id;
|
} out;
|
||||||
RightsId rights_id;
|
|
||||||
u32 key_generation;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 8;
|
|
||||||
raw->key_generation = 0;
|
|
||||||
memcpy(&raw->rights_id, rightsId, sizeof(RightsId));
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
Result rc = serviceDispatchOut(&g_esSrv, 9, out);
|
||||||
IpcParsedCommand r;
|
if (R_SUCCEEDED(rc) && numTickets) *numTickets = out.num_tickets;
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esCountCommonTicket(u32 *numTickets)
|
Result esCountPersonalizedTicket(u32 *numTickets) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u32 num_tickets;
|
||||||
u64 cmd_id;
|
} out;
|
||||||
} *raw;
|
|
||||||
|
Result rc = serviceDispatchOut(&g_esSrv, 10, out);
|
||||||
|
if (R_SUCCEEDED(rc) && numTickets) *numTickets = out.num_tickets;
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return rc;
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 9;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 num_tickets;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (numTickets) *numTickets = resp->num_tickets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result esCountPersonalizedTicket(u32 *numTickets)
|
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 10;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 num_tickets;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (numTickets) *numTickets = resp->num_tickets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esListCommonTicket(u32 *numRightsIdsWritten, RightsId *outBuf, size_t bufSize) {
|
Result esListCommonTicket(u32 *numRightsIdsWritten, RightsId *outBuf, size_t bufSize) {
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u32 num_rights_ids_written;
|
||||||
u64 cmd_id;
|
} out;
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
Result rc = serviceDispatchInOut(&g_esSrv, 11, *numRightsIdsWritten, out,
|
||||||
raw->magic = SFCI_MAGIC;
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||||
raw->cmd_id = 11;
|
.buffers = { { outBuf, bufSize } },
|
||||||
|
);
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
if (R_SUCCEEDED(rc) && numRightsIdsWritten) *numRightsIdsWritten = out.num_rights_ids_written;
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 num_rights_ids_written;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (numRightsIdsWritten) *numRightsIdsWritten = resp->num_rights_ids_written;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, RightsId *outBuf, size_t bufSize) {
|
Result esListPersonalizedTicket(u32 *numRightsIdsWritten, RightsId *outBuf, size_t bufSize) {
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
ipcAddRecvBuffer(&c, outBuf, bufSize, BufferType_Normal);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u32 num_rights_ids_written;
|
||||||
u64 cmd_id;
|
} out;
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
Result rc = serviceDispatchInOut(&g_esSrv, 12, *numRightsIdsWritten, out,
|
||||||
raw->magic = SFCI_MAGIC;
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||||
raw->cmd_id = 12;
|
.buffers = { { outBuf, bufSize } },
|
||||||
|
);
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
if (R_SUCCEEDED(rc) && numRightsIdsWritten) *numRightsIdsWritten = out.num_rights_ids_written;
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 num_rights_ids_written;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (numRightsIdsWritten) *numRightsIdsWritten = resp->num_rights_ids_written;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result esGetCommonTicketData(u64 *unkOut, void *outBuf1, size_t bufSize1, const RightsId* rightsId)
|
Result esGetCommonTicketData(u64 *unkOut, void *outBuf1, size_t bufSize1, const RightsId* rightsId) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
ipcAddRecvBuffer(&c, outBuf1, bufSize1, BufferType_Normal);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 unk;
|
||||||
u64 cmd_id;
|
} out;
|
||||||
RightsId rights_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 16;
|
|
||||||
memcpy(&raw->rights_id, rightsId, sizeof(RightsId));
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_esSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
Result rc = serviceDispatchInOut(&g_esSrv, 16, rightsId, out,
|
||||||
IpcParsedCommand r;
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||||
ipcParse(&r);
|
.buffers = { { outBuf1, bufSize1 } },
|
||||||
|
);
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u64 unk;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (unkOut) *unkOut = resp->unk;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
|
@ -3,677 +3,231 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <switch.h>
|
#include <switch.h>
|
||||||
#include <switch/arm/atomics.h>
|
#include "service_guard.h"
|
||||||
|
|
||||||
static Service g_nsAppManSrv, g_nsGetterSrv;
|
static Service g_nsAppManSrv, g_nsGetterSrv;
|
||||||
static u64 g_nsRefCnt;
|
|
||||||
|
|
||||||
static Result _nsGetInterface(Service* srv_out, u64 cmd_id);
|
static Result _nsextGetSession(Service* srv, Service* srv_out, u32 cmd_id);
|
||||||
|
|
||||||
Result nsextInitialize(void)
|
NX_GENERATE_SERVICE_GUARD(nsext);
|
||||||
{
|
|
||||||
|
Result _nsextInitialize(void) {
|
||||||
Result rc=0;
|
Result rc=0;
|
||||||
|
|
||||||
atomicIncrement64(&g_nsRefCnt);
|
if(hosversionBefore(3,0,0))
|
||||||
|
|
||||||
if (serviceIsActive(&g_nsGetterSrv) || serviceIsActive(&g_nsAppManSrv))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if(!kernelAbove300())
|
|
||||||
return smGetService(&g_nsAppManSrv, "ns:am");
|
return smGetService(&g_nsAppManSrv, "ns:am");
|
||||||
|
|
||||||
rc = smGetService(&g_nsGetterSrv, "ns:am2");//TODO: Support the other services?(Only useful when ns:am2 isn't accessible)
|
rc = smGetService(&g_nsGetterSrv, "ns:am2");//TODO: Support the other services?(Only useful when ns:am2 isn't accessible)
|
||||||
if (R_FAILED(rc)) return rc;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
rc = _nsGetInterface(&g_nsAppManSrv, 7996);
|
rc = _nsextGetSession(&g_nsGetterSrv, &g_nsAppManSrv, 7996);
|
||||||
|
|
||||||
if (R_FAILED(rc)) serviceClose(&g_nsGetterSrv);
|
if (R_FAILED(rc)) serviceClose(&g_nsGetterSrv);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsextExit(void)
|
void _nsextCleanup(void) {
|
||||||
{
|
serviceClose(&g_nsAppManSrv);
|
||||||
if (atomicDecrement64(&g_nsRefCnt) == 0) {
|
if(hosversionBefore(3,0,0)) return;
|
||||||
serviceClose(&g_nsAppManSrv);
|
|
||||||
if(!kernelAbove300()) return;
|
|
||||||
|
|
||||||
serviceClose(&g_nsGetterSrv);
|
serviceClose(&g_nsGetterSrv);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result _nsGetInterface(Service* srv_out, u64 cmd_id) {
|
static Result _nsextGetSession(Service* srv, Service* srv_out, u32 cmd_id) {
|
||||||
IpcCommand c;
|
return serviceDispatch(srv, cmd_id,
|
||||||
ipcInitialize(&c);
|
.out_num_objects = 1,
|
||||||
|
.out_objects = srv_out,
|
||||||
struct {
|
);
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = cmd_id;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsGetterSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
serviceCreate(srv_out, r.Handles[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsPushApplicationRecord(u64 title_id, u8 last_modified_event, ContentStorageRecord *content_records_buf, size_t buf_size)
|
Result nsPushApplicationRecord(u64 title_id, u8 last_modified_event, ContentStorageRecord *content_records_buf, size_t buf_size) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
ipcAddSendBuffer(&c, content_records_buf, buf_size, 0);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u8 last_modified_event;
|
u8 last_modified_event;
|
||||||
u8 padding[0x7];
|
u8 padding[0x7];
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
} *raw;
|
} in = { last_modified_event, {0}, title_id };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 16, in,
|
||||||
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
|
||||||
raw->magic = SFCI_MAGIC;
|
.buffers = { { content_records_buf, buf_size } });
|
||||||
raw->cmd_id = 16;
|
|
||||||
raw->last_modified_event = last_modified_event;
|
|
||||||
raw->title_id = title_id;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsCalculateApplicationOccupiedSize(u64 titleID, void *out_buf)
|
Result nsCalculateApplicationOccupiedSize(u64 titleID, void *out_buf) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 titleID;
|
u64 titleID;
|
||||||
} *raw;
|
} in = { titleID };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 11;
|
|
||||||
raw->titleID = titleID;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u8 out[0x80];
|
||||||
u64 result;
|
} out;
|
||||||
u8 out[0x80];
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
Result rc = serviceDispatchInOut(&g_nsAppManSrv, 11, in, out);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && out_buf) memcpy(out_buf, out.out, 0x80);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
memcpy(out_buf, resp->out, 0x80);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsListApplicationRecordContentMeta(u64 offset, u64 titleID, void *out_buf, size_t out_buf_size, u32 *entries_read_out)
|
Result nsListApplicationRecordContentMeta(u64 offset, u64 titleID, void *out_buf, size_t out_buf_size, u32 *entries_read_out) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
ipcAddRecvBuffer(&c, out_buf, out_buf_size, 0);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u64 titleID;
|
u64 titleID;
|
||||||
} *raw;
|
} in = { offset, titleID };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 17;
|
|
||||||
raw->titleID = titleID;
|
|
||||||
raw->offset = offset;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u32 entries_read;
|
||||||
u64 result;
|
} out;
|
||||||
u32 entries_read;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
Result rc = serviceDispatchInOut(&g_nsAppManSrv, 17, in, out,
|
||||||
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||||
|
.buffers = { { out_buf, out_buf_size } });
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (entries_read_out) *entries_read_out = resp->entries_read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && entries_read_out) *entries_read_out = out.entries_read;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsTouchApplication(u64 titleID)
|
Result nsTouchApplication(u64 titleID) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 titleID;
|
u64 titleID;
|
||||||
} *raw;
|
} in = { titleID };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 904, in);
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 904;
|
|
||||||
raw->titleID = titleID;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 entries_read;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsDeleteApplicationRecord(u64 titleID)
|
Result nsDeleteApplicationRecord(u64 titleID) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 titleID;
|
u64 titleID;
|
||||||
} *raw;
|
} in = { titleID };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 27, in);
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 27;
|
|
||||||
raw->titleID = titleID;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 entries_read;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsLaunchApplication(u64 titleID)
|
Result nsLaunchApplication(u64 titleID) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 titleID;
|
u64 titleID;
|
||||||
} *raw;
|
} in = { titleID };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 19, in);
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 19;
|
|
||||||
raw->titleID = titleID;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsPushLaunchVersion(u64 titleID, u32 version)
|
Result nsPushLaunchVersion(u64 titleID, u32 version) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 titleID;
|
||||||
u64 cmd_id;
|
|
||||||
u64 title_id;
|
|
||||||
u32 version;
|
u32 version;
|
||||||
u32 padding;
|
u32 padding;
|
||||||
} *raw;
|
} in = { titleID, version, 0 };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 36, in);
|
||||||
|
}
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 36;
|
|
||||||
raw->title_id = titleID;
|
|
||||||
raw->version = version;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
Result nsCheckApplicationLaunchVersion(u64 titleID) {
|
||||||
u64 magic;
|
struct {
|
||||||
u64 result;
|
u64 titleID;
|
||||||
} *resp = r.Raw;
|
} in = { titleID };
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return serviceDispatchIn(&g_nsAppManSrv, 38, in);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result nsCountApplicationContentMeta(u64 titleId, u32* countOut) {
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u64 titleId;
|
||||||
|
} in = { titleId };
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u32 count;
|
||||||
|
} out;
|
||||||
|
|
||||||
|
Result rc = serviceDispatchInOut(&g_nsAppManSrv, 600, in, out);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && countOut) *countOut = out.count;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsCheckApplicationLaunchVersion(u64 titleID)
|
Result nsGetContentMetaStorage(const NcmContentMetaKey *record, u8 *storageOut) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 title_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 38;
|
|
||||||
raw->title_id = titleID;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result nsCountApplicationContentMeta(u64 titleId, u32* countOut)
|
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 title_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 600;
|
|
||||||
raw->title_id = titleId;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
u32 count;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (countOut) *countOut = resp->count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result nsGetContentMetaStorage(const NcmContentMetaKey *record, u8 *out)
|
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
NcmContentMetaKey metaRecord;
|
NcmContentMetaKey metaRecord;
|
||||||
} *raw;
|
} in = { *record };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 606;
|
|
||||||
memcpy(&raw->metaRecord, record, sizeof(NcmContentMetaKey));
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u8 out;
|
||||||
u64 result;
|
} out;
|
||||||
u8 out;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
Result rc = serviceDispatchInOut(&g_nsAppManSrv, 606, in, out);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && storageOut) *storageOut = out.out;
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
if (out) *out = resp->out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsBeginInstallApplication(u64 tid, u32 unk, u8 storageId) {
|
Result nsBeginInstallApplication(u64 tid, u32 unk, u8 storageId) {
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u32 storageId;
|
u32 storageId;
|
||||||
u32 unk;
|
u32 unk;
|
||||||
u64 tid;
|
u64 tid;
|
||||||
} *raw;
|
} in = { storageId, unk, tid };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 26, in);
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 26;
|
|
||||||
raw->storageId = storageId;
|
|
||||||
raw->unk = unk;
|
|
||||||
raw->tid = tid;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsInvalidateAllApplicationControlCache(void) {
|
Result nsInvalidateAllApplicationControlCache(void) {
|
||||||
IpcCommand c;
|
return serviceDispatch(&g_nsAppManSrv, 401);
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 401;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsInvalidateApplicationControlCache(u64 tid) {
|
Result nsInvalidateApplicationControlCache(u64 tid) {
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 tid;
|
u64 tid;
|
||||||
} *raw;
|
} in = { tid };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 404, in);
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 404;
|
|
||||||
raw->tid = tid;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsCheckApplicationLaunchRights(u64 tid)
|
Result nsCheckApplicationLaunchRights(u64 tid) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 tid;
|
u64 tid;
|
||||||
} *raw;
|
} in = { tid };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 39, in);
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 39;
|
|
||||||
raw->tid = tid;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsGetApplicationContentPath(u64 tid, u8 type, char *out, size_t buf_size) {
|
Result nsGetApplicationContentPath(u64 tid, u8 type, char *out, size_t buf_size) {
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
ipcAddRecvBuffer(&c, out, buf_size, 0);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u8 padding[0x7];
|
u8 padding[0x7];
|
||||||
u8 type;
|
u8 type;
|
||||||
u64 tid;
|
u64 tid;
|
||||||
} *raw;
|
} in = { {0}, type, tid };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 21, in,
|
||||||
|
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
|
||||||
raw->magic = SFCI_MAGIC;
|
.buffers = { { out, buf_size } }
|
||||||
raw->cmd_id = 21;
|
);
|
||||||
raw->type = type;
|
|
||||||
raw->tid = tid;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsDisableApplicationAutoUpdate(u64 titleID)
|
Result nsDisableApplicationAutoUpdate(u64 titleID) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
} *raw;
|
} in = { titleID };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 903, in);
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 903;
|
|
||||||
raw->title_id = titleID;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result nsWithdrawApplicationUpdateRequest(u64 titleId)
|
Result nsWithdrawApplicationUpdateRequest(u64 titleId) {
|
||||||
{
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
} *raw;
|
} in = { titleId };
|
||||||
|
|
||||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
return serviceDispatchIn(&g_nsAppManSrv, 907, in);
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 907;
|
|
||||||
raw->title_id = titleId;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_nsAppManSrv);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
ipcParse(&r);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp = r.Raw;
|
|
||||||
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
52
source/nx/ipc/service_guard.h
Executable file
52
source/nx/ipc/service_guard.h
Executable file
|
@ -0,0 +1,52 @@
|
||||||
|
#pragma once
|
||||||
|
#include <switch.h>
|
||||||
|
|
||||||
|
typedef struct ServiceGuard {
|
||||||
|
Mutex mutex;
|
||||||
|
u32 refCount;
|
||||||
|
} ServiceGuard;
|
||||||
|
|
||||||
|
NX_INLINE bool serviceGuardBeginInit(ServiceGuard* g)
|
||||||
|
{
|
||||||
|
mutexLock(&g->mutex);
|
||||||
|
return (g->refCount++) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE Result serviceGuardEndInit(ServiceGuard* g, Result rc, void (*cleanupFunc)(void))
|
||||||
|
{
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
cleanupFunc();
|
||||||
|
--g->refCount;
|
||||||
|
}
|
||||||
|
mutexUnlock(&g->mutex);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE void serviceGuardExit(ServiceGuard* g, void (*cleanupFunc)(void))
|
||||||
|
{
|
||||||
|
mutexLock(&g->mutex);
|
||||||
|
if (g->refCount && (--g->refCount) == 0)
|
||||||
|
cleanupFunc();
|
||||||
|
mutexUnlock(&g->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \
|
||||||
|
\
|
||||||
|
static ServiceGuard g_##name##Guard; \
|
||||||
|
NX_INLINE Result _##name##Initialize _paramdecl; \
|
||||||
|
static void _##name##Cleanup(void); \
|
||||||
|
\
|
||||||
|
Result name##Initialize _paramdecl \
|
||||||
|
{ \
|
||||||
|
Result rc = 0; \
|
||||||
|
if (serviceGuardBeginInit(&g_##name##Guard)) \
|
||||||
|
rc = _##name##Initialize _parampass; \
|
||||||
|
return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void name##Exit(void) \
|
||||||
|
{ \
|
||||||
|
serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NX_GENERATE_SERVICE_GUARD(name) NX_GENERATE_SERVICE_GUARD_PARAMS(name, (void), ())
|
|
@ -1,579 +0,0 @@
|
||||||
#include "nx/ipc/usb_new.h"
|
|
||||||
#include "nx/ipc/usb_comms_new.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <switch/types.h>
|
|
||||||
#include <switch/result.h>
|
|
||||||
#include <switch/kernel/detect.h>
|
|
||||||
#include <switch/kernel/rwlock.h>
|
|
||||||
#include <switch/services/fatal.h>
|
|
||||||
|
|
||||||
#define TOTAL_INTERFACES 4
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
RwLock lock, lock_in, lock_out;
|
|
||||||
bool initialized;
|
|
||||||
|
|
||||||
UsbDsInterface* interface;
|
|
||||||
UsbDsEndpoint *endpoint_in, *endpoint_out;
|
|
||||||
|
|
||||||
u8 *endpoint_in_buffer, *endpoint_out_buffer;
|
|
||||||
} usbCommsInterface;
|
|
||||||
|
|
||||||
static bool g_usbCommsInitialized = false;
|
|
||||||
|
|
||||||
static usbCommsInterface g_usbCommsInterfaces[TOTAL_INTERFACES];
|
|
||||||
|
|
||||||
static RwLock g_usbCommsLock;
|
|
||||||
|
|
||||||
static Result _usbCommsInterfaceInit1x(u32 intf_ind);
|
|
||||||
static Result _usbCommsInterfaceInit5x(u32 intf_ind);
|
|
||||||
static Result _usbCommsInterfaceInit(u32 intf_ind);
|
|
||||||
|
|
||||||
static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, size_t size, size_t *transferredSize);
|
|
||||||
|
|
||||||
Result usbCommsInitializeEx(u32 num_interfaces)
|
|
||||||
{
|
|
||||||
Result rc = 0;
|
|
||||||
rwlockWriteLock(&g_usbCommsLock);
|
|
||||||
|
|
||||||
if (g_usbCommsInitialized) {
|
|
||||||
rc = MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
|
|
||||||
} else if (num_interfaces > TOTAL_INTERFACES) {
|
|
||||||
rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
|
||||||
} else {
|
|
||||||
rc = usbDsInitialize();
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
|
|
||||||
if (kernelAbove500()) {
|
|
||||||
u8 iManufacturer, iProduct, iSerialNumber;
|
|
||||||
static const u16 supported_langs[1] = {0x0409};
|
|
||||||
// Send language descriptor
|
|
||||||
rc = usbDsAddUsbLanguageStringDescriptor(NULL, supported_langs, sizeof(supported_langs)/sizeof(u16));
|
|
||||||
// Send manufacturer
|
|
||||||
if (R_SUCCEEDED(rc)) rc = usbDsAddUsbStringDescriptor(&iManufacturer, "Switchbrew");
|
|
||||||
// Send product
|
|
||||||
if (R_SUCCEEDED(rc)) rc = usbDsAddUsbStringDescriptor(&iProduct, "libnx USB comms");
|
|
||||||
// Send serial number
|
|
||||||
if (R_SUCCEEDED(rc)) rc = usbDsAddUsbStringDescriptor(&iSerialNumber, "SerialNumber");
|
|
||||||
|
|
||||||
// Send device descriptors
|
|
||||||
struct usb_device_descriptor device_descriptor = {
|
|
||||||
.bLength = USB_DT_DEVICE_SIZE,
|
|
||||||
.bDescriptorType = USB_DT_DEVICE,
|
|
||||||
.bcdUSB = 0x0110,
|
|
||||||
.bDeviceClass = 0x00,
|
|
||||||
.bDeviceSubClass = 0x00,
|
|
||||||
.bDeviceProtocol = 0x00,
|
|
||||||
.bMaxPacketSize0 = 0x40,
|
|
||||||
.idVendor = 0x057e,
|
|
||||||
.idProduct = 0x3000,
|
|
||||||
.bcdDevice = 0x0100,
|
|
||||||
.iManufacturer = iManufacturer,
|
|
||||||
.iProduct = iProduct,
|
|
||||||
.iSerialNumber = iSerialNumber,
|
|
||||||
.bNumConfigurations = 0x01
|
|
||||||
};
|
|
||||||
if (R_SUCCEEDED(rc)) rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Full, &device_descriptor);
|
|
||||||
|
|
||||||
// High Speed is USB 2.0
|
|
||||||
device_descriptor.bcdUSB = 0x0200;
|
|
||||||
if (R_SUCCEEDED(rc)) rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_High, &device_descriptor);
|
|
||||||
|
|
||||||
// Super Speed is USB 3.0
|
|
||||||
device_descriptor.bcdUSB = 0x0300;
|
|
||||||
// Upgrade packet size to 512
|
|
||||||
device_descriptor.bMaxPacketSize0 = 0x09;
|
|
||||||
if (R_SUCCEEDED(rc)) rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Super, &device_descriptor);
|
|
||||||
|
|
||||||
// Define Binary Object Store
|
|
||||||
u8 bos[0x16] = {
|
|
||||||
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
|
|
||||||
};
|
|
||||||
if (R_SUCCEEDED(rc)) rc = usbDsSetBinaryObjectStore(bos, sizeof(bos));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
for (u32 i = 0; i < num_interfaces; i++) {
|
|
||||||
usbCommsInterface *intf = &g_usbCommsInterfaces[i];
|
|
||||||
rwlockWriteLock(&intf->lock);
|
|
||||||
rwlockWriteLock(&intf->lock_in);
|
|
||||||
rwlockWriteLock(&intf->lock_out);
|
|
||||||
rc = _usbCommsInterfaceInit(i);
|
|
||||||
rwlockWriteUnlock(&intf->lock_out);
|
|
||||||
rwlockWriteUnlock(&intf->lock_in);
|
|
||||||
rwlockWriteUnlock(&intf->lock);
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc) && kernelAbove500()) {
|
|
||||||
rc = usbDsEnable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
usbCommsExit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) g_usbCommsInitialized = true;
|
|
||||||
|
|
||||||
rwlockWriteUnlock(&g_usbCommsLock);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result usbCommsInitialize(void)
|
|
||||||
{
|
|
||||||
return usbCommsInitializeEx(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _usbCommsInterfaceFree(usbCommsInterface *interface)
|
|
||||||
{
|
|
||||||
rwlockWriteLock(&interface->lock);
|
|
||||||
if (!interface->initialized) {
|
|
||||||
rwlockWriteUnlock(&interface->lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rwlockWriteLock(&interface->lock_in);
|
|
||||||
rwlockWriteLock(&interface->lock_out);
|
|
||||||
|
|
||||||
interface->initialized = 0;
|
|
||||||
|
|
||||||
interface->endpoint_in = NULL;
|
|
||||||
interface->endpoint_out = NULL;
|
|
||||||
interface->interface = NULL;
|
|
||||||
|
|
||||||
free(interface->endpoint_in_buffer);
|
|
||||||
free(interface->endpoint_out_buffer);
|
|
||||||
interface->endpoint_in_buffer = NULL;
|
|
||||||
interface->endpoint_out_buffer = NULL;
|
|
||||||
|
|
||||||
rwlockWriteUnlock(&interface->lock_out);
|
|
||||||
rwlockWriteUnlock(&interface->lock_in);
|
|
||||||
|
|
||||||
rwlockWriteUnlock(&interface->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void usbCommsExit(void)
|
|
||||||
{
|
|
||||||
u32 i;
|
|
||||||
|
|
||||||
rwlockWriteLock(&g_usbCommsLock);
|
|
||||||
|
|
||||||
usbDsExit();
|
|
||||||
|
|
||||||
g_usbCommsInitialized = false;
|
|
||||||
|
|
||||||
rwlockWriteUnlock(&g_usbCommsLock);
|
|
||||||
|
|
||||||
for (i=0; i<TOTAL_INTERFACES; i++)
|
|
||||||
{
|
|
||||||
_usbCommsInterfaceFree(&g_usbCommsInterfaces[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Result _usbCommsInterfaceInit(u32 intf_ind)
|
|
||||||
{
|
|
||||||
if (kernelAbove500()) {
|
|
||||||
return _usbCommsInterfaceInit5x(intf_ind);
|
|
||||||
} else {
|
|
||||||
return _usbCommsInterfaceInit1x(intf_ind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Result _usbCommsInterfaceInit5x(u32 intf_ind)
|
|
||||||
{
|
|
||||||
Result rc = 0;
|
|
||||||
u32 ep_num = intf_ind + 1;
|
|
||||||
usbCommsInterface *interface = &g_usbCommsInterfaces[intf_ind];
|
|
||||||
|
|
||||||
struct usb_interface_descriptor interface_descriptor = {
|
|
||||||
.bLength = USB_DT_INTERFACE_SIZE,
|
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
|
||||||
.bInterfaceNumber = intf_ind,
|
|
||||||
.bNumEndpoints = 2,
|
|
||||||
.bInterfaceClass = 0xFF,
|
|
||||||
.bInterfaceSubClass = 0xFF,
|
|
||||||
.bInterfaceProtocol = 0xFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct usb_endpoint_descriptor endpoint_descriptor_in = {
|
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
|
||||||
.bEndpointAddress = USB_ENDPOINT_IN + ep_num,
|
|
||||||
.bmAttributes = USB_TRANSFER_TYPE_BULK,
|
|
||||||
.wMaxPacketSize = 0x40,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct usb_endpoint_descriptor endpoint_descriptor_out = {
|
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
|
||||||
.bEndpointAddress = USB_ENDPOINT_OUT + ep_num,
|
|
||||||
.bmAttributes = USB_TRANSFER_TYPE_BULK,
|
|
||||||
.wMaxPacketSize = 0x40,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct usb_ss_endpoint_companion_descriptor endpoint_companion = {
|
|
||||||
.bLength = sizeof(struct usb_ss_endpoint_companion_descriptor),
|
|
||||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMPANION,
|
|
||||||
.bMaxBurst = 0x0F,
|
|
||||||
.bmAttributes = 0x00,
|
|
||||||
.wBytesPerInterval = 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
interface->initialized = 1;
|
|
||||||
|
|
||||||
//The buffer for PostBufferAsync commands must be 0x1000-byte aligned.
|
|
||||||
interface->endpoint_in_buffer = memalign(0x1000, 0x1000);
|
|
||||||
if (interface->endpoint_in_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
interface->endpoint_out_buffer = memalign(0x1000, 0x1000);
|
|
||||||
if (interface->endpoint_out_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
memset(interface->endpoint_in_buffer, 0, 0x1000);
|
|
||||||
memset(interface->endpoint_out_buffer, 0, 0x1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
rc = usbDsRegisterInterface(&interface->interface, interface_descriptor.bInterfaceNumber);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
// Full Speed Config
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Full, &interface_descriptor, USB_DT_INTERFACE_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Full, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Full, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
// High Speed Config
|
|
||||||
endpoint_descriptor_in.wMaxPacketSize = 0x200;
|
|
||||||
endpoint_descriptor_out.wMaxPacketSize = 0x200;
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_High, &interface_descriptor, USB_DT_INTERFACE_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_High, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_High, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
// Super Speed Config
|
|
||||||
endpoint_descriptor_in.wMaxPacketSize = 0x400;
|
|
||||||
endpoint_descriptor_out.wMaxPacketSize = 0x400;
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &interface_descriptor, USB_DT_INTERFACE_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_companion, USB_DT_SS_ENDPOINT_COMPANION_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_companion, USB_DT_SS_ENDPOINT_COMPANION_SIZE);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
//Setup endpoints.
|
|
||||||
rc = usbDsInterface_RegisterEndpoint(interface->interface, &interface->endpoint_in, endpoint_descriptor_in.bEndpointAddress);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
rc = usbDsInterface_RegisterEndpoint(interface->interface, &interface->endpoint_out, endpoint_descriptor_out.bEndpointAddress);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
rc = usbDsInterface_EnableInterface(interface->interface);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static Result _usbCommsInterfaceInit1x(u32 intf_ind)
|
|
||||||
{
|
|
||||||
Result rc = 0;
|
|
||||||
u32 ep_num = intf_ind + 1;
|
|
||||||
usbCommsInterface *interface = &g_usbCommsInterfaces[intf_ind];
|
|
||||||
|
|
||||||
struct usb_interface_descriptor interface_descriptor = {
|
|
||||||
.bLength = USB_DT_INTERFACE_SIZE,
|
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
|
||||||
.bInterfaceNumber = intf_ind,
|
|
||||||
.bInterfaceClass = 0xFF,
|
|
||||||
.bInterfaceSubClass = 0xFF,
|
|
||||||
.bInterfaceProtocol = 0xFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct usb_endpoint_descriptor endpoint_descriptor_in = {
|
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
|
||||||
.bEndpointAddress = USB_ENDPOINT_IN + ep_num,
|
|
||||||
.bmAttributes = USB_TRANSFER_TYPE_BULK,
|
|
||||||
.wMaxPacketSize = 0x200,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct usb_endpoint_descriptor endpoint_descriptor_out = {
|
|
||||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
|
||||||
.bDescriptorType = USB_DT_ENDPOINT,
|
|
||||||
.bEndpointAddress = USB_ENDPOINT_OUT + ep_num,
|
|
||||||
.bmAttributes = USB_TRANSFER_TYPE_BULK,
|
|
||||||
.wMaxPacketSize = 0x200,
|
|
||||||
};
|
|
||||||
|
|
||||||
interface->initialized = 1;
|
|
||||||
|
|
||||||
//The buffer for PostBufferAsync commands must be 0x1000-byte aligned.
|
|
||||||
interface->endpoint_in_buffer = memalign(0x1000, 0x1000);
|
|
||||||
if (interface->endpoint_in_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
interface->endpoint_out_buffer = memalign(0x1000, 0x1000);
|
|
||||||
if (interface->endpoint_out_buffer==NULL) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
memset(interface->endpoint_in_buffer, 0, 0x1000);
|
|
||||||
memset(interface->endpoint_out_buffer, 0, 0x1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
//Setup interface.
|
|
||||||
rc = usbDsGetDsInterface(&interface->interface, &interface_descriptor, "usb");
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
//Setup endpoints.
|
|
||||||
rc = usbDsInterface_GetDsEndpoint(interface->interface, &interface->endpoint_in, &endpoint_descriptor_in);//device->host
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
rc = usbDsInterface_GetDsEndpoint(interface->interface, &interface->endpoint_out, &endpoint_descriptor_out);//host->device
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
rc = usbDsInterface_EnableInterface(interface->interface);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Result _usbCommsRead(usbCommsInterface *interface, void* buffer, size_t size, size_t *transferredSize)
|
|
||||||
{
|
|
||||||
Result rc=0;
|
|
||||||
u32 urbId=0;
|
|
||||||
u8 *bufptr = (u8*)buffer;
|
|
||||||
u8 *transfer_buffer = NULL;
|
|
||||||
u8 transfer_type=0;
|
|
||||||
u32 chunksize=0;
|
|
||||||
u32 tmp_transferredSize = 0;
|
|
||||||
size_t total_transferredSize=0;
|
|
||||||
UsbDsReportData reportdata;
|
|
||||||
|
|
||||||
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
|
|
||||||
rc = usbDsWaitReady(U64_MAX);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
while(size)
|
|
||||||
{
|
|
||||||
if(((u64)bufptr) & 0xfff)//When bufptr isn't page-aligned copy the data into g_usbComms_endpoint_in_buffer and transfer that, otherwise use the bufptr directly.
|
|
||||||
{
|
|
||||||
transfer_buffer = interface->endpoint_out_buffer;
|
|
||||||
memset(interface->endpoint_out_buffer, 0, 0x1000);
|
|
||||||
|
|
||||||
chunksize = 0x1000;
|
|
||||||
chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer).
|
|
||||||
if (size<chunksize) chunksize = size;
|
|
||||||
|
|
||||||
transfer_type = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
transfer_buffer = bufptr;
|
|
||||||
chunksize = size;
|
|
||||||
|
|
||||||
transfer_type = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Start a host->device transfer.
|
|
||||||
rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_out, transfer_buffer, chunksize, &urbId);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
//Wait for the transfer to finish.
|
|
||||||
eventWait(&interface->endpoint_out->CompletionEvent, U64_MAX);
|
|
||||||
eventClear(&interface->endpoint_out->CompletionEvent);
|
|
||||||
|
|
||||||
rc = usbDsEndpoint_GetReportData(interface->endpoint_out, &reportdata);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
|
|
||||||
total_transferredSize+= (size_t)tmp_transferredSize;
|
|
||||||
|
|
||||||
if (transfer_type==0) memcpy(bufptr, transfer_buffer, tmp_transferredSize);
|
|
||||||
bufptr+= tmp_transferredSize;
|
|
||||||
size-= tmp_transferredSize;
|
|
||||||
|
|
||||||
if(tmp_transferredSize < chunksize)break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transferredSize) *transferredSize = total_transferredSize;
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, size_t size, size_t *transferredSize)
|
|
||||||
{
|
|
||||||
Result rc=0;
|
|
||||||
u32 urbId=0;
|
|
||||||
u32 chunksize=0;
|
|
||||||
u8 *bufptr = (u8*)buffer;
|
|
||||||
u8 *transfer_buffer = NULL;
|
|
||||||
u32 tmp_transferredSize = 0;
|
|
||||||
size_t total_transferredSize=0;
|
|
||||||
UsbDsReportData reportdata;
|
|
||||||
|
|
||||||
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
|
|
||||||
rc = usbDsWaitReady(U64_MAX);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
while(size)
|
|
||||||
{
|
|
||||||
if(((u64)bufptr) & 0xfff)//When bufptr isn't page-aligned copy the data into g_usbComms_endpoint_in_buffer and transfer that, otherwise use the bufptr directly.
|
|
||||||
{
|
|
||||||
transfer_buffer = interface->endpoint_in_buffer;
|
|
||||||
memset(interface->endpoint_in_buffer, 0, 0x1000);
|
|
||||||
|
|
||||||
chunksize = 0x1000;
|
|
||||||
chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer).
|
|
||||||
if (size<chunksize) chunksize = size;
|
|
||||||
|
|
||||||
memcpy(interface->endpoint_in_buffer, bufptr, chunksize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
transfer_buffer = bufptr;
|
|
||||||
chunksize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Start a device->host transfer.
|
|
||||||
rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_in, transfer_buffer, chunksize, &urbId);
|
|
||||||
if(R_FAILED(rc))return rc;
|
|
||||||
|
|
||||||
//Wait for the transfer to finish.
|
|
||||||
eventWait(&interface->endpoint_in->CompletionEvent, U64_MAX);
|
|
||||||
eventClear(&interface->endpoint_in->CompletionEvent);
|
|
||||||
|
|
||||||
rc = usbDsEndpoint_GetReportData(interface->endpoint_in, &reportdata);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
|
|
||||||
if (R_FAILED(rc)) return rc;
|
|
||||||
|
|
||||||
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
|
|
||||||
|
|
||||||
total_transferredSize+= (size_t)tmp_transferredSize;
|
|
||||||
|
|
||||||
bufptr+= tmp_transferredSize;
|
|
||||||
size-= tmp_transferredSize;
|
|
||||||
|
|
||||||
if (tmp_transferredSize < chunksize) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transferredSize) *transferredSize = total_transferredSize;
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t usbCommsReadEx(void* buffer, size_t size, u32 interface)
|
|
||||||
{
|
|
||||||
size_t transferredSize=0;
|
|
||||||
u32 state=0;
|
|
||||||
Result rc, rc2;
|
|
||||||
usbCommsInterface *inter = &g_usbCommsInterfaces[interface];
|
|
||||||
bool initialized;
|
|
||||||
|
|
||||||
if (interface>=TOTAL_INTERFACES) return 0;
|
|
||||||
|
|
||||||
rwlockReadLock(&inter->lock);
|
|
||||||
initialized = inter->initialized;
|
|
||||||
rwlockReadUnlock(&inter->lock);
|
|
||||||
if (!initialized) return 0;
|
|
||||||
|
|
||||||
rwlockWriteLock(&inter->lock_out);
|
|
||||||
rc = _usbCommsRead(inter, buffer, size, &transferredSize);
|
|
||||||
rwlockWriteUnlock(&inter->lock_out);
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
rc2 = usbDsGetState(&state);
|
|
||||||
if (R_SUCCEEDED(rc2)) {
|
|
||||||
if (state!=5) {
|
|
||||||
rwlockWriteLock(&inter->lock_out);
|
|
||||||
rc = _usbCommsRead(&g_usbCommsInterfaces[interface], buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this.
|
|
||||||
rwlockWriteUnlock(&inter->lock_out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsRead));
|
|
||||||
}
|
|
||||||
return transferredSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t usbCommsRead(void* buffer, size_t size)
|
|
||||||
{
|
|
||||||
return usbCommsReadEx(buffer, size, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t usbCommsWriteEx(const void* buffer, size_t size, u32 interface)
|
|
||||||
{
|
|
||||||
size_t transferredSize=0;
|
|
||||||
u32 state=0;
|
|
||||||
Result rc, rc2;
|
|
||||||
usbCommsInterface *inter = &g_usbCommsInterfaces[interface];
|
|
||||||
bool initialized;
|
|
||||||
|
|
||||||
if (interface>=TOTAL_INTERFACES) return 0;
|
|
||||||
|
|
||||||
rwlockReadLock(&inter->lock);
|
|
||||||
initialized = inter->initialized;
|
|
||||||
rwlockReadUnlock(&inter->lock);
|
|
||||||
if (!initialized) return 0;
|
|
||||||
|
|
||||||
rwlockWriteLock(&inter->lock_in);
|
|
||||||
rc = _usbCommsWrite(&g_usbCommsInterfaces[interface], buffer, size, &transferredSize);
|
|
||||||
rwlockWriteUnlock(&inter->lock_in);
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
rc2 = usbDsGetState(&state);
|
|
||||||
if (R_SUCCEEDED(rc2)) {
|
|
||||||
if (state!=5) {
|
|
||||||
rwlockWriteLock(&inter->lock_in);
|
|
||||||
rc = _usbCommsWrite(&g_usbCommsInterfaces[interface], buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this.
|
|
||||||
rwlockWriteUnlock(&inter->lock_in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsWrite));
|
|
||||||
}
|
|
||||||
return transferredSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t usbCommsWrite(const void* buffer, size_t size)
|
|
||||||
{
|
|
||||||
return usbCommsWriteEx(buffer, size, 0);
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,39 +13,39 @@ namespace nx::ncm
|
||||||
serviceClose(&m_contentStorage.s);
|
serviceClose(&m_contentStorage.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentStorage::CreatePlaceholder(const NcmNcaId &placeholderId, const NcmNcaId ®isteredId, size_t size)
|
void ContentStorage::CreatePlaceholder(const NcmContentId &placeholderId, const NcmContentId ®isteredId, size_t size)
|
||||||
{
|
{
|
||||||
ASSERT_OK(ncmContentStorageCreatePlaceHolder(&m_contentStorage, &placeholderId, ®isteredId, size), "Failed to create placeholder");
|
ASSERT_OK(ncmContentStorageCreatePlaceHolder(&m_contentStorage, &placeholderId, ®isteredId, size), "Failed to create placeholder");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentStorage::DeletePlaceholder(const NcmNcaId &placeholderId)
|
void ContentStorage::DeletePlaceholder(const NcmContentId &placeholderId)
|
||||||
{
|
{
|
||||||
ASSERT_OK(ncmContentStorageDeletePlaceHolder(&m_contentStorage, &placeholderId), "Failed to delete placeholder");
|
ASSERT_OK(ncmContentStorageDeletePlaceHolder(&m_contentStorage, &placeholderId), "Failed to delete placeholder");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentStorage::WritePlaceholder(const NcmNcaId &placeholderId, u64 offset, void *buffer, size_t bufSize)
|
void ContentStorage::WritePlaceholder(const NcmContentId &placeholderId, u64 offset, void *buffer, size_t bufSize)
|
||||||
{
|
{
|
||||||
ASSERT_OK(ncmContentStorageWritePlaceHolder(&m_contentStorage, &placeholderId, offset, buffer, bufSize), "Failed to write to placeholder");
|
ASSERT_OK(ncmContentStorageWritePlaceHolder(&m_contentStorage, &placeholderId, offset, buffer, bufSize), "Failed to write to placeholder");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentStorage::Register(const NcmNcaId &placeholderId, const NcmNcaId ®isteredId)
|
void ContentStorage::Register(const NcmContentId &placeholderId, const NcmContentId ®isteredId)
|
||||||
{
|
{
|
||||||
ASSERT_OK(ncmContentStorageRegister(&m_contentStorage, ®isteredId, &placeholderId), "Failed to register placeholder NCA");
|
ASSERT_OK(ncmContentStorageRegister(&m_contentStorage, ®isteredId, &placeholderId), "Failed to register placeholder NCA");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentStorage::Delete(const NcmNcaId ®isteredId)
|
void ContentStorage::Delete(const NcmContentId ®isteredId)
|
||||||
{
|
{
|
||||||
ASSERT_OK(ncmContentStorageDelete(&m_contentStorage, ®isteredId), "Failed to delete registered NCA");
|
ASSERT_OK(ncmContentStorageDelete(&m_contentStorage, ®isteredId), "Failed to delete registered NCA");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContentStorage::Has(const NcmNcaId ®isteredId)
|
bool ContentStorage::Has(const NcmContentId ®isteredId)
|
||||||
{
|
{
|
||||||
bool hasNCA = false;
|
bool hasNCA = false;
|
||||||
ASSERT_OK(ncmContentStorageHas(&m_contentStorage, &hasNCA, ®isteredId), "Failed to check if NCA is present");
|
ASSERT_OK(ncmContentStorageHas(&m_contentStorage, &hasNCA, ®isteredId), "Failed to check if NCA is present");
|
||||||
return hasNCA;
|
return hasNCA;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ContentStorage::GetPath(const NcmNcaId ®isteredId)
|
std::string ContentStorage::GetPath(const NcmContentId ®isteredId)
|
||||||
{
|
{
|
||||||
char pathBuf[FS_MAX_PATH] = {0};
|
char pathBuf[FS_MAX_PATH] = {0};
|
||||||
ASSERT_OK(ncmContentStorageGetPath(&m_contentStorage, pathBuf, FS_MAX_PATH, ®isteredId), "Failed to get installed NCA path");
|
ASSERT_OK(ncmContentStorageGetPath(&m_contentStorage, pathBuf, FS_MAX_PATH, ®isteredId), "Failed to get installed NCA path");
|
||||||
|
|
40
source/sigInstall.cpp
Executable file
40
source/sigInstall.cpp
Executable file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "ui/MainApplication.hpp"
|
||||||
|
#include "util/curl.hpp"
|
||||||
|
#include "util/util.hpp"
|
||||||
|
#include "util/unzip.hpp"
|
||||||
|
|
||||||
|
namespace inst::ui {
|
||||||
|
extern MainApplication *mainApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sig {
|
||||||
|
void installSigPatches () {
|
||||||
|
int ourResult = inst::ui::mainApp->CreateShowDialog("Install signature patches?", "Signature patches are required for installing and playing NSP contents!", {"Install", "Uninstall", "Cancel"}, true);
|
||||||
|
if (ourResult == 0) {
|
||||||
|
if (!util::copyFile("sdmc:/bootloader/patches.ini", "sdmc:/bootloader/patches.ini.old")) {
|
||||||
|
if (inst::ui::mainApp->CreateShowDialog("Could not back up old Hekate patches.ini! Install anyway?", "", {"Yes", "No"}, false)) return;
|
||||||
|
}
|
||||||
|
std::string ourPath = appVariables::appDir + "patches.zip";
|
||||||
|
bool didDownload = curlStuff::downloadFile("http://github.com/Joonie86/hekate/releases/download/5.0.0J/Kosmos_patches_10_09_2019.zip", ourPath.c_str());
|
||||||
|
bool didExtract = false;
|
||||||
|
if (didDownload) didExtract = zipStuff::extractFile(ourPath, "sdmc:/");
|
||||||
|
else {
|
||||||
|
inst::ui::mainApp->CreateShowDialog("Could not download signature patches!", "Check your internet connection and try again", {"OK"}, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::filesystem::remove(ourPath);
|
||||||
|
if (didExtract) inst::ui::mainApp->CreateShowDialog("Install complete!", "Restart your console to apply!", {"OK"}, true);
|
||||||
|
else {
|
||||||
|
inst::ui::mainApp->CreateShowDialog("Could not extract files!", "", {"OK"}, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (ourResult == 1) {
|
||||||
|
if (!util::copyFile( "sdmc:/bootloader/patches.ini.old", "sdmc:/bootloader/patches.ini")) {
|
||||||
|
if (inst::ui::mainApp->CreateShowDialog("Unable to restore original Hekate patches.ini! Continue uninstalling?", "", {"Yes", "No"}, false)) return;
|
||||||
|
} else std::filesystem::remove("sdmc:/bootloader/patches.ini.old");
|
||||||
|
if (util::removeDirectory("sdmc:/atmosphere/exefs_patches/es_patches")) inst::ui::mainApp->CreateShowDialog("Uninstall complete", "Restart your console to apply", {"OK"}, true);
|
||||||
|
else inst::ui::mainApp->CreateShowDialog("Unable to remove signature patches", "Files may have been renamed or deleted", {"OK"}, true);
|
||||||
|
} else return;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include "ui/MainApplication.hpp"
|
#include "ui/MainApplication.hpp"
|
||||||
#include "ui/mainPage.hpp"
|
|
||||||
#include "ui/instPage.hpp"
|
#include "ui/instPage.hpp"
|
||||||
#include "util.hpp"
|
|
||||||
|
|
||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
|
||||||
|
@ -13,10 +11,13 @@ namespace inst::ui {
|
||||||
this->SetBackgroundColor(COLOR("#670000FF"));
|
this->SetBackgroundColor(COLOR("#670000FF"));
|
||||||
this->topText = TextBlock::New(10, 2, "Awoo Installer", 35);
|
this->topText = TextBlock::New(10, 2, "Awoo Installer", 35);
|
||||||
this->topText->SetColor(COLOR("#FFFFFFFF"));
|
this->topText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->pageInfoText = TextBlock::New(10, 45, "", 35);
|
this->pageInfoText = TextBlock::New(10, 180, "", 35);
|
||||||
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
this->pageInfoText->SetColor(COLOR("#FFFFFFFF"));
|
||||||
|
this->installBar = pu::ui::elm::ProgressBar::New(340, 360, 600, 48, 100.0f);
|
||||||
|
this->installBar->SetColor(COLOR("#222222FF"));
|
||||||
this->Add(this->topText);
|
this->Add(this->topText);
|
||||||
this->Add(this->pageInfoText);
|
this->Add(this->pageInfoText);
|
||||||
|
this->Add(this->installBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void instPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
void instPage::onInput(u64 Down, u64 Up, u64 Held, pu::ui::Touch Pos) {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include "ui/MainApplication.hpp"
|
#include "ui/MainApplication.hpp"
|
||||||
#include "ui/mainPage.hpp"
|
#include "ui/mainPage.hpp"
|
||||||
#include "curl.hpp"
|
#include "util/util.hpp"
|
||||||
#include "util.hpp"
|
#include "sigInstall.hpp"
|
||||||
#include "unzip.hpp"
|
|
||||||
#include "netInstall.hpp"
|
#include "netInstall.hpp"
|
||||||
|
|
||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
@ -18,16 +17,12 @@ namespace inst::ui {
|
||||||
this->optionMenu = pu::ui::elm::Menu::New(0, 160, 1280, COLOR("#FFFFFF00"), 80, (560 / 80));
|
this->optionMenu = pu::ui::elm::Menu::New(0, 160, 1280, COLOR("#FFFFFF00"), 80, (560 / 80));
|
||||||
this->optionMenu->SetOnFocusColor(COLOR("#00000033"));
|
this->optionMenu->SetOnFocusColor(COLOR("#00000033"));
|
||||||
this->installMenuItem = pu::ui::elm::MenuItem::New("Install NSP");
|
this->installMenuItem = pu::ui::elm::MenuItem::New("Install NSP");
|
||||||
//this->installMenuItem->AddOnClick(std::bind(&MainPage::installMenuItem_Click, this));
|
|
||||||
this->installMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
this->installMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->netInstallMenuItem = pu::ui::elm::MenuItem::New("Install NSP Over LAN");
|
this->netInstallMenuItem = pu::ui::elm::MenuItem::New("Install NSP Over LAN");
|
||||||
//this->netInstallMenuItem->AddOnClick(std::bind(&MainPage::netInstallMenuItem_Click, this));
|
|
||||||
this->netInstallMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
this->netInstallMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->sigPatchesMenuItem = pu::ui::elm::MenuItem::New("Install Signature Patches");
|
this->sigPatchesMenuItem = pu::ui::elm::MenuItem::New("Manage Signature Patches");
|
||||||
//this->sigPatchesMenuItem->AddOnClick(std::bind(&MainPage::sigPatchesMenuItem_Click, this));
|
|
||||||
this->sigPatchesMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
this->sigPatchesMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->exitMenuItem = pu::ui::elm::MenuItem::New("Exit");
|
this->exitMenuItem = pu::ui::elm::MenuItem::New("Exit");
|
||||||
//this->exitMenuItem->AddOnClick(std::bind(&MainPage::exitMenuItem_Click, this));
|
|
||||||
this->exitMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
this->exitMenuItem->SetColor(COLOR("#FFFFFFFF"));
|
||||||
this->Add(this->topText);
|
this->Add(this->topText);
|
||||||
this->optionMenu->AddItem(this->installMenuItem);
|
this->optionMenu->AddItem(this->installMenuItem);
|
||||||
|
@ -50,21 +45,7 @@ namespace inst::ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainPage::sigPatchesMenuItem_Click() {
|
void MainPage::sigPatchesMenuItem_Click() {
|
||||||
std::string ourPath = appVariables::appDir + "patches.zip";
|
sig::installSigPatches();
|
||||||
bool didDownload = curlStuff::downloadFile("http://github.com/Joonie86/hekate/releases/download/5.0.0J/Kosmos_patches_10_09_2019.zip", ourPath.c_str());
|
|
||||||
bool didExtract = false;
|
|
||||||
if (didDownload) didExtract = zipStuff::extractFile(ourPath, "sdmc:/");
|
|
||||||
else {
|
|
||||||
mainApp->CreateShowDialog("Could not download signature patches!", "", {"OK"}, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::filesystem::remove(ourPath);
|
|
||||||
if (didExtract) mainApp->CreateShowDialog("Install complete! Restart your console to apply!", "", {"OK"}, true);
|
|
||||||
else {
|
|
||||||
mainApp->CreateShowDialog("Could not extract files!", "", {"OK"}, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainPage::exitMenuItem_Click() {
|
void MainPage::exitMenuItem_Click() {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include "ui/MainApplication.hpp"
|
#include "ui/MainApplication.hpp"
|
||||||
#include "ui/mainPage.hpp"
|
#include "ui/mainPage.hpp"
|
||||||
#include "ui/netInstPage.hpp"
|
#include "ui/netInstPage.hpp"
|
||||||
#include "util.hpp"
|
#include "util/util.hpp"
|
||||||
#include "netInstall.hpp"
|
#include "netInstall.hpp"
|
||||||
|
|
||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "ui/mainPage.hpp"
|
#include "ui/mainPage.hpp"
|
||||||
#include "ui/nspInstPage.hpp"
|
#include "ui/nspInstPage.hpp"
|
||||||
#include "nspInstall.hpp"
|
#include "nspInstall.hpp"
|
||||||
#include "util.hpp"
|
#include "util/util.hpp"
|
||||||
|
|
||||||
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
#define COLOR(hex) pu::ui::Color::FromHex(hex)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "curl.hpp"
|
#include "util/curl.hpp"
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace tin::util
|
||||||
return __bswap64(*(u64 *)(rightsId.c + 8));
|
return __bswap64(*(u64 *)(rightsId.c + 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetNcaIdString(const NcmNcaId& ncaId)
|
std::string GetNcaIdString(const NcmContentId& ncaId)
|
||||||
{
|
{
|
||||||
char ncaIdStr[FS_MAX_PATH] = {0};
|
char ncaIdStr[FS_MAX_PATH] = {0};
|
||||||
u64 ncaIdLower = __bswap64(*(u64 *)ncaId.c);
|
u64 ncaIdLower = __bswap64(*(u64 *)ncaId.c);
|
||||||
|
@ -24,9 +24,9 @@ namespace tin::util
|
||||||
return std::string(ncaIdStr);
|
return std::string(ncaIdStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
NcmNcaId GetNcaIdFromString(std::string ncaIdStr)
|
NcmContentId GetNcaIdFromString(std::string ncaIdStr)
|
||||||
{
|
{
|
||||||
NcmNcaId ncaId = {0};
|
NcmContentId ncaId = {0};
|
||||||
char lowerU64[17] = {0};
|
char lowerU64[17] = {0};
|
||||||
char upperU64[17] = {0};
|
char upperU64[17] = {0};
|
||||||
memcpy(lowerU64, ncaIdStr.c_str(), 16);
|
memcpy(lowerU64, ncaIdStr.c_str(), 16);
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <fstream>
|
||||||
|
#include <unistd.h>
|
||||||
#include "switch.h"
|
#include "switch.h"
|
||||||
#include "util.hpp"
|
#include "util/util.hpp"
|
||||||
#include "nx/ipc/tin_ipc.h"
|
#include "nx/ipc/tin_ipc.h"
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
|
@ -48,4 +50,32 @@ namespace util {
|
||||||
std::reverse(files.begin(), files.end());
|
std::reverse(files.begin(), files.end());
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool removeDirectory(std::string dir) {
|
||||||
|
try {
|
||||||
|
for(auto & p: std::filesystem::recursive_directory_iterator(dir))
|
||||||
|
{
|
||||||
|
if (std::filesystem::is_regular_file(p))
|
||||||
|
{
|
||||||
|
std::filesystem::remove(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rmdir(dir.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (std::filesystem::filesystem_error & e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool copyFile(std::string inFile, std::string outFile) {
|
||||||
|
char ch;
|
||||||
|
std::ifstream f1(inFile);
|
||||||
|
std::ofstream f2(outFile);
|
||||||
|
|
||||||
|
if(!f1 || !f2) return false;
|
||||||
|
|
||||||
|
while(f1 && f1.get(ch)) f2.put(ch);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue