mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 04:22:50 +02:00
Added usbds. The post-buffer cmds require dcache-flush for the specified buffer, this isn't included yet.
This commit is contained in:
parent
8308791835
commit
6cea85f338
@ -22,6 +22,7 @@ extern "C" {
|
||||
#include <switch/services/fs.h>
|
||||
#include <switch/services/bsd.h>
|
||||
#include <switch/services/fatal.h>
|
||||
#include <switch/services/usb.h>
|
||||
#include <switch/services/vi.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
215
nx/include/switch/services/usb.h
Normal file
215
nx/include/switch/services/usb.h
Normal file
@ -0,0 +1,215 @@
|
||||
/// 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
|
||||
|
||||
/// 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; /// Ignored.
|
||||
|
||||
uint8_t bInterfaceClass;
|
||||
|
||||
uint8_t bInterfaceSubClass;
|
||||
|
||||
uint8_t bInterfaceProtocol;
|
||||
|
||||
uint8_t iInterface; /// Ignored.
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u16 idVendor; /// VID
|
||||
u16 idProduct; /// PID
|
||||
u16 bcdDevice;
|
||||
char Manufacturer[0x20];
|
||||
char Product[0x20];
|
||||
char SerialNumber[0x20];
|
||||
} usbDsDeviceInfo;
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
u32 interface_index;
|
||||
Handle h;
|
||||
|
||||
Handle SetupEvent;
|
||||
Handle CtrlInCompletionEvent;
|
||||
Handle CtrlOutCompletionEvent;
|
||||
} UsbDsInterface;
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
Handle h;
|
||||
|
||||
Handle CompletionEvent;
|
||||
} UsbDsEndpoint;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USBCOMPLEXID_Default = 0x2
|
||||
} usbComplexId;
|
||||
|
||||
/// 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,
|
||||
};
|
||||
|
||||
Result usbDsInitialize(usbComplexId complexId, const usbDsDeviceInfo* deviceinfo);
|
||||
|
||||
/// Exit usbDs. Any interfaces/endpoints which are left open are automatically closed, since otherwise usb-sysmodule won't fully reset usbds to defaults.
|
||||
void usbDsExit(void);
|
||||
|
||||
Handle usbDsGetServiceSession(void);
|
||||
Handle usbDsGetStateChangeEvent(void);
|
||||
|
||||
Result usbDsGetDsInterface(UsbDsInterface** interface, struct usb_interface_descriptor* descriptor, const char *interface_name);
|
||||
|
||||
/// IDsInterface
|
||||
void usbDsInterface_Close(UsbDsInterface* interface);
|
||||
Result usbDsInterface_GetDsEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, struct usb_endpoint_descriptor* descriptor);
|
||||
Result usbDsInterface_EnableInterface(UsbDsInterface* interface);
|
||||
Result usbDsInterface_DisableInterface(UsbDsInterface* interface);
|
||||
Result usbDsInterface_CtrlInPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32 *out);
|
||||
Result usbDsInterface_CtrlOutPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32 *out);
|
||||
Result usbDsInterface_GetCtrlInReportData(UsbDsInterface* interface, u8 out[0x84]);
|
||||
Result usbDsInterface_GetCtrlOutReportData(UsbDsInterface* interface, u8 out[0x84]);
|
||||
Result usbDsInterface_StallCtrl(UsbDsInterface* interface);
|
||||
|
||||
/// IDsEndpoint
|
||||
|
||||
void usbDsEndpoint_Close(UsbDsEndpoint* endpoint);
|
||||
Result usbDsEndpoint_PostBufferAsync(UsbDsEndpoint* endpoint, void* buffer, size_t size, u32 *out);
|
||||
Result usbDsEndpoint_GetCtrlOutReportData(UsbDsEndpoint* endpoint, u8 out[0x84]);
|
||||
Result usbDsEndpoint_StallCtrl(UsbDsEndpoint* endpoint);
|
||||
|
577
nx/source/services/usb.c
Normal file
577
nx/source/services/usb.c
Normal file
@ -0,0 +1,577 @@
|
||||
#include <string.h>
|
||||
#include <switch.h>
|
||||
|
||||
#define TOTAL_INTERFACES 4
|
||||
#define TOTAL_ENDPOINTS 15*2
|
||||
|
||||
static Handle g_usbDsServiceSession = 0;
|
||||
static Handle g_usbDsStateChangeEvent = 0;
|
||||
|
||||
static UsbDsInterface g_usbDsInterfaceTable[TOTAL_INTERFACES];
|
||||
static UsbDsEndpoint g_usbDsEndpointTable[TOTAL_INTERFACES*TOTAL_ENDPOINTS];
|
||||
|
||||
static void _usbDsFreeTables(void);
|
||||
|
||||
static Result _usbDsBindDevice(usbComplexId complexId);
|
||||
static Result _usbDsBindClientProcess(Handle prochandle);
|
||||
static Result _usbDsGetEvent(Handle sessionhandle, Handle* handle_out, u64 cmd_id);
|
||||
static Result _usbDsSetVidPidBcd(const usbDsDeviceInfo* deviceinfo);
|
||||
|
||||
static Result _usbDsGetSession(Handle sessionhandle, Handle* handle_out, u64 cmd_id, const void* buf0, size_t buf0size, const void* buf1, size_t buf1size);
|
||||
|
||||
Result usbDsInitialize(usbComplexId complexId, const usbDsDeviceInfo* deviceinfo) {
|
||||
if(g_usbDsServiceSession!=0)return MAKERESULT(MODULE_LIBNX, LIBNX_ALREADYINITIALIZED);
|
||||
|
||||
Result rc = 0;
|
||||
|
||||
rc = smGetService(&g_usbDsServiceSession, "usb:ds");
|
||||
|
||||
if (R_SUCCEEDED(rc))rc = _usbDsBindDevice(complexId);
|
||||
if (R_SUCCEEDED(rc))rc = _usbDsBindClientProcess(CUR_PROCESS_HANDLE);
|
||||
if (R_SUCCEEDED(rc))rc = _usbDsGetEvent(g_usbDsServiceSession, &g_usbDsStateChangeEvent, 3);//GetStateChangeEvent
|
||||
if (R_SUCCEEDED(rc))rc = _usbDsSetVidPidBcd(deviceinfo);
|
||||
|
||||
if (R_FAILED(rc)) {
|
||||
if(g_usbDsStateChangeEvent) {
|
||||
svcCloseHandle(g_usbDsStateChangeEvent);
|
||||
g_usbDsStateChangeEvent = 0;
|
||||
}
|
||||
|
||||
if(g_usbDsServiceSession) {
|
||||
svcCloseHandle(g_usbDsServiceSession);
|
||||
g_usbDsServiceSession = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void usbDsExit(void)
|
||||
{
|
||||
if(g_usbDsServiceSession==0)return;
|
||||
|
||||
_usbDsFreeTables();
|
||||
|
||||
if(g_usbDsStateChangeEvent) {
|
||||
svcCloseHandle(g_usbDsStateChangeEvent);
|
||||
g_usbDsStateChangeEvent = 0;
|
||||
}
|
||||
|
||||
if(g_usbDsServiceSession) {
|
||||
svcCloseHandle(g_usbDsServiceSession);
|
||||
g_usbDsServiceSession = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Handle usbDsGetServiceSession(void)
|
||||
{
|
||||
return g_usbDsServiceSession;
|
||||
}
|
||||
|
||||
Handle usbDsGetStateChangeEvent(void)
|
||||
{
|
||||
return g_usbDsStateChangeEvent;
|
||||
}
|
||||
|
||||
static UsbDsInterface* _usbDsAllocateInterface(void)
|
||||
{
|
||||
u32 pos;
|
||||
UsbDsInterface* ptr = NULL;
|
||||
|
||||
for(pos=0; pos<TOTAL_INTERFACES; pos++)
|
||||
{
|
||||
ptr = &g_usbDsInterfaceTable[pos];
|
||||
if(ptr->initialized)continue;
|
||||
memset(ptr, 0, sizeof(UsbDsInterface));
|
||||
ptr->initialized = true;
|
||||
ptr->interface_index = pos;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static UsbDsEndpoint* _usbDsAllocateEndpoint(UsbDsInterface* interface)
|
||||
{
|
||||
u32 pos;
|
||||
UsbDsEndpoint* ptr = NULL;
|
||||
|
||||
if(interface->interface_index>TOTAL_INTERFACES)return NULL;
|
||||
|
||||
for(pos=0; pos<TOTAL_ENDPOINTS; pos++)
|
||||
{
|
||||
ptr = &g_usbDsEndpointTable[(interface->interface_index*TOTAL_ENDPOINTS) + pos];
|
||||
if(ptr->initialized)continue;
|
||||
memset(ptr, 0, sizeof(UsbDsEndpoint));
|
||||
ptr->initialized = true;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _usbDsFreeInterface(UsbDsInterface* interface)
|
||||
{
|
||||
if(!interface->initialized)return;
|
||||
|
||||
if(interface->CtrlOutCompletionEvent) {
|
||||
svcCloseHandle(interface->CtrlOutCompletionEvent);
|
||||
interface->CtrlOutCompletionEvent = 0;
|
||||
}
|
||||
|
||||
if(interface->CtrlInCompletionEvent) {
|
||||
svcCloseHandle(interface->CtrlInCompletionEvent);
|
||||
interface->CtrlInCompletionEvent = 0;
|
||||
}
|
||||
|
||||
if(interface->SetupEvent) {
|
||||
svcCloseHandle(interface->SetupEvent);
|
||||
interface->SetupEvent = 0;
|
||||
}
|
||||
|
||||
if(interface->h) {
|
||||
svcCloseHandle(interface->h);
|
||||
interface->h = 0;
|
||||
}
|
||||
|
||||
interface->initialized = false;
|
||||
}
|
||||
|
||||
static void _usbDsFreeEndpoint(UsbDsEndpoint* endpoint)
|
||||
{
|
||||
if(!endpoint->initialized)return;
|
||||
|
||||
if(endpoint->CompletionEvent) {
|
||||
svcCloseHandle(endpoint->CompletionEvent);
|
||||
endpoint->CompletionEvent = 0;
|
||||
}
|
||||
|
||||
if(endpoint->h) {
|
||||
svcCloseHandle(endpoint->h);
|
||||
endpoint->h = 0;
|
||||
}
|
||||
|
||||
endpoint->initialized = false;
|
||||
}
|
||||
|
||||
static void _usbDsFreeTables(void)
|
||||
{
|
||||
u32 pos, pos2;
|
||||
for(pos=0; pos<TOTAL_INTERFACES; pos++)
|
||||
{
|
||||
for(pos2=0; pos2<TOTAL_ENDPOINTS; pos2++)_usbDsFreeEndpoint(&g_usbDsEndpointTable[(pos*TOTAL_ENDPOINTS) + pos2]);
|
||||
_usbDsFreeInterface(&g_usbDsInterfaceTable[pos]);
|
||||
}
|
||||
}
|
||||
|
||||
static Result _usbDsBindDevice(usbComplexId complexId) {
|
||||
if(g_usbDsServiceSession==0)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 complexId;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->complexId = complexId;
|
||||
|
||||
Result rc = ipcDispatch(g_usbDsServiceSession);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcCommandResponse r;
|
||||
ipcParseResponse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _usbDsBindClientProcess(Handle prochandle) {
|
||||
if(g_usbDsServiceSession==0)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
ipcSendHandleCopy(&c, prochandle);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 1;
|
||||
|
||||
Result rc = ipcDispatch(g_usbDsServiceSession);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcCommandResponse r;
|
||||
ipcParseResponse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _usbDsGetEvent(Handle sessionhandle, Handle* handle_out, u64 cmd_id) {
|
||||
if(sessionhandle==0)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = ipcDispatch(sessionhandle);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcCommandResponse r;
|
||||
ipcParseResponse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*handle_out = r.Handles[0];
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _usbDsSetVidPidBcd(const usbDsDeviceInfo* deviceinfo) {
|
||||
if(g_usbDsServiceSession==0)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
ipcAddSendBuffer(&c, deviceinfo, sizeof(usbDsDeviceInfo), 0);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 5;
|
||||
|
||||
Result rc = ipcDispatch(g_usbDsServiceSession);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcCommandResponse r;
|
||||
ipcParseResponse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _usbDsGetSession(Handle sessionhandle, Handle* handle_out, u64 cmd_id, const void* buf0, size_t buf0size, const void* buf1, size_t buf1size) {
|
||||
if(sessionhandle==0)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
if(buf0 && buf0size)ipcAddSendBuffer(&c, buf0, buf0size, 0);
|
||||
if(buf1 && buf1size)ipcAddSendBuffer(&c, buf1, buf1size, 0);
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = ipcDispatch(sessionhandle);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcCommandResponse r;
|
||||
ipcParseResponse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*handle_out = r.Handles[0];
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _usbDsCmdNoParams(Handle sessionhandle, u64 cmd_id) {
|
||||
if(sessionhandle==0)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = ipcDispatch(sessionhandle);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcCommandResponse r;
|
||||
ipcParseResponse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _usbDsPostBuffer(Handle sessionhandle, u64 cmd_id, void* buffer, size_t size, u32 *out) {
|
||||
if(sessionhandle==0)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
//TODO: Add dache-flush code here, breaks otherwise.
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 size;
|
||||
u32 padding;
|
||||
u64 buffer;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
raw->size = (u32)size;
|
||||
raw->padding = 0;
|
||||
raw->buffer = (u64)buffer;
|
||||
|
||||
Result rc = ipcDispatch(sessionhandle);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcCommandResponse r;
|
||||
ipcParseResponse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u32 out;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc) && out)*out = resp->out;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _usbDsGetReport(Handle sessionhandle, u64 cmd_id, u8 out[0x84]) {
|
||||
if(sessionhandle==0)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = cmd_id;
|
||||
|
||||
Result rc = ipcDispatch(sessionhandle);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcCommandResponse r;
|
||||
ipcParseResponse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 out[0x84];
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc) && out)memcpy(out, resp->out, sizeof(resp->out));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbDsGetDsInterface(UsbDsInterface** interface, struct usb_interface_descriptor* descriptor, const char *interface_name)
|
||||
{
|
||||
UsbDsInterface* ptr = _usbDsAllocateInterface();
|
||||
if(ptr==NULL)return MAKERESULT(MODULE_LIBNX, LIBNX_OUTOFMEM);
|
||||
|
||||
Result rc = _usbDsGetSession(g_usbDsServiceSession, &ptr->h, 2, descriptor, sizeof(struct usb_interface_descriptor), interface_name, strlen(interface_name)+1);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _usbDsGetEvent(ptr->h, &ptr->SetupEvent, 1);//GetSetupEvent
|
||||
if (R_SUCCEEDED(rc)) rc = _usbDsGetEvent(ptr->h, &ptr->CtrlInCompletionEvent, 7);//GetCtrlInCompletionEvent
|
||||
if (R_SUCCEEDED(rc)) rc = _usbDsGetEvent(ptr->h, &ptr->CtrlOutCompletionEvent, 9);//GetCtrlOutCompletionEvent
|
||||
|
||||
if (R_FAILED(rc)) _usbDsFreeInterface(ptr);
|
||||
|
||||
if (R_SUCCEEDED(rc)) *interface = ptr;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//IDsInterface
|
||||
|
||||
void usbDsInterface_Close(UsbDsInterface* interface)
|
||||
{
|
||||
_usbDsFreeInterface(interface);
|
||||
}
|
||||
|
||||
Result usbDsInterface_GetDsEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, struct usb_endpoint_descriptor* descriptor)
|
||||
{
|
||||
if(!interface->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
UsbDsEndpoint* ptr = _usbDsAllocateEndpoint(interface);
|
||||
if(ptr==NULL)return MAKERESULT(MODULE_LIBNX, LIBNX_OUTOFMEM);
|
||||
|
||||
Result rc = _usbDsGetSession(interface->h, &ptr->h, 0, descriptor, sizeof(struct usb_endpoint_descriptor), NULL, 0);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _usbDsGetEvent(ptr->h, &ptr->CompletionEvent, 2);//GetCompletionEvent
|
||||
|
||||
if (R_FAILED(rc)) _usbDsFreeEndpoint(ptr);
|
||||
|
||||
if (R_SUCCEEDED(rc)) *endpoint = ptr;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbDsInterface_EnableInterface(UsbDsInterface* interface)
|
||||
{
|
||||
if(!interface->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
return _usbDsCmdNoParams(interface->h, 3);
|
||||
}
|
||||
|
||||
Result usbDsInterface_DisableInterface(UsbDsInterface* interface)
|
||||
{
|
||||
if(!interface->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
return _usbDsCmdNoParams(interface->h, 4);
|
||||
}
|
||||
|
||||
Result usbDsInterface_CtrlInPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32 *out)
|
||||
{
|
||||
if(!interface->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
return _usbDsPostBuffer(interface->h, 5, buffer, size, out);
|
||||
}
|
||||
|
||||
Result usbDsInterface_CtrlOutPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32 *out)
|
||||
{
|
||||
if(!interface->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
return _usbDsPostBuffer(interface->h, 6, buffer, size, out);
|
||||
}
|
||||
|
||||
Result usbDsInterface_GetCtrlInReportData(UsbDsInterface* interface, u8 out[0x84])
|
||||
{
|
||||
if(!interface->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
return _usbDsGetReport(interface->h, 8, out);
|
||||
}
|
||||
|
||||
Result usbDsInterface_GetCtrlOutReportData(UsbDsInterface* interface, u8 out[0x84])
|
||||
{
|
||||
if(!interface->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
return _usbDsGetReport(interface->h, 10, out);
|
||||
}
|
||||
|
||||
Result usbDsInterface_StallCtrl(UsbDsInterface* interface)
|
||||
{
|
||||
if(!interface->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
return _usbDsCmdNoParams(interface->h, 11);
|
||||
}
|
||||
|
||||
//IDsEndpoint
|
||||
|
||||
void usbDsEndpoint_Close(UsbDsEndpoint* endpoint)
|
||||
{
|
||||
_usbDsFreeEndpoint(endpoint);
|
||||
}
|
||||
|
||||
Result usbDsEndpoint_PostBufferAsync(UsbDsEndpoint* endpoint, void* buffer, size_t size, u32 *out)
|
||||
{
|
||||
if(!endpoint->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
return _usbDsPostBuffer(endpoint->h, 0, buffer, size, out);
|
||||
}
|
||||
|
||||
Result usbDsEndpoint_GetCtrlOutReportData(UsbDsEndpoint* endpoint, u8 out[0x84])
|
||||
{
|
||||
if(!endpoint->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
return _usbDsGetReport(endpoint->h, 3, out);
|
||||
}
|
||||
|
||||
Result usbDsEndpoint_StallCtrl(UsbDsEndpoint* endpoint)
|
||||
{
|
||||
if(!endpoint->initialized)return MAKERESULT(MODULE_LIBNX, LIBNX_NOTINITIALIZED);
|
||||
|
||||
return _usbDsCmdNoParams(endpoint->h, 4);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user