diff --git a/nx/include/switch/services/usbhs.h b/nx/include/switch/services/usbhs.h index 6612f6bb..a0d81814 100644 --- a/nx/include/switch/services/usbhs.h +++ b/nx/include/switch/services/usbhs.h @@ -41,7 +41,7 @@ typedef struct { u8 bInterfaceProtocol; } UsbHsInterfaceFilter; -/// Interface struct. Note that devices have a seperate \ref UsbHsInterface for each interface. Descriptors which are not available are set to all-zero. +/// Descriptors which are not available are set to all-zero. typedef struct { s32 ID; u32 deviceID_2; @@ -57,6 +57,11 @@ typedef struct { u8 pad_x155[0x6]; struct usb_ss_endpoint_companion_descriptor input_ss_endpoint_companion_descs[15]; ///< ? u8 pad_x1b5[0x3]; +} PACKED UsbHsInterfaceInfo; + +/// Interface struct. Note that devices have a seperate \ref UsbHsInterface for each interface. +typedef struct { + UsbHsInterfaceInfo inf; char pathstr[0x40]; u32 busID; @@ -77,6 +82,21 @@ typedef struct { u64 unk_x10; } UsbHsXferReport; +/// The interface service object. These Events have autoclear=false. +typedef struct { + Service s; + Event event0; ///< Unknown. + Event eventCtrlXfer; ///< [2.0.0+] Signaled when CtrlXferAsync finishes. + + UsbHsInterface inf; ///< Initialized with the input interface from \ref usbHsAcquireUsbIf, then the first 0x1B8-bytes are overwritten with the cmd output (data before pathstr). +} UsbHsClientIfSession; + +typedef struct { + Service s; + + struct usb_endpoint_descriptor desc; +} UsbHsClientEpSession; + /// Initialize/exit usb:hs. Result usbHsInitialize(void); void usbHsExit(void); @@ -126,3 +146,15 @@ Result usbHsCreateInterfaceAvailableEvent(Event* event, bool autoclear, u8 index */ Result usbHsDestroyInterfaceAvailableEvent(Event* event, u8 index); +/** + * @brief Acquires/opens the specified interface. + * @param[in] s The service object. + * @param[in] interface Interface to use. + */ +Result usbHsAcquireUsbIf(UsbHsClientIfSession* s, UsbHsInterface *interface); + +/// UsbHsClientIfSession + +/// Closes the specified interface session. +void usbHsIfClose(UsbHsClientIfSession* s); + diff --git a/nx/source/services/usbhs.c b/nx/source/services/usbhs.c index 600a08f5..1d020642 100644 --- a/nx/source/services/usbhs.c +++ b/nx/source/services/usbhs.c @@ -291,3 +291,64 @@ Result usbHsDestroyInterfaceAvailableEvent(Event* event, u8 index) { return rc; } +Result usbHsAcquireUsbIf(UsbHsClientIfSession* s, UsbHsInterface *interface) { + IpcCommand c; + ipcInitialize(&c); + + memset(s, 0, sizeof(UsbHsClientIfSession)); + memcpy(&s->inf, interface, sizeof(UsbHsInterface)); + + struct { + u64 magic; + u64 cmd_id; + s32 ID; + } *raw; + + ipcAddRecvBuffer(&c, &s->inf.inf, sizeof(UsbHsInterfaceInfo), BufferType_Normal); + + raw = serviceIpcPrepareHeader(&g_usbHsSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = kernelAbove200() ? 7 : 6; + raw->ID = interface->inf.ID; + + Result rc = serviceIpcDispatch(&g_usbHsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_usbHsSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + serviceCreateSubservice(&s->s, &g_usbHsSrv, &r, 0); + } + } + + if (R_SUCCEEDED(rc)) { + rc = _usbHsGetEvent(&s->s, &s->event0, 0); + if (kernelAbove200()) rc = _usbHsGetEvent(&s->s, &s->event0, 6); + + if (R_FAILED(rc)) { + serviceClose(&s->s); + eventClose(&s->event0); + eventClose(&s->eventCtrlXfer); + } + } + + return rc; +} + +void usbHsIfClose(UsbHsClientIfSession* s) { + serviceClose(&s->s); + eventClose(&s->event0); + eventClose(&s->eventCtrlXfer); + memset(s, 0, sizeof(UsbHsClientIfSession)); +} +