From 174b5066a5c9881614aff4d448141fd240231c49 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Wed, 1 Feb 2023 14:00:33 -0500 Subject: [PATCH] usbhs: Use an user-specified buffer for tmem, etc. --- nx/include/switch/services/usbhs.h | 17 +++++++++++++---- nx/source/services/usbhs.c | 20 +++++++++----------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/nx/include/switch/services/usbhs.h b/nx/include/switch/services/usbhs.h index 6cc01e85..a46321fe 100644 --- a/nx/include/switch/services/usbhs.h +++ b/nx/include/switch/services/usbhs.h @@ -103,10 +103,9 @@ typedef struct { typedef struct { Service s; Event eventXfer; ///< [2.0.0+] Signaled when PostBufferAsync finishes. - TransferMemory tmem; u32 maxUrbCount; u64 max_reports; - bool tmem_initialized; + void* ringbuf; struct usb_endpoint_descriptor desc; } UsbHsClientEpSession; @@ -237,10 +236,18 @@ Result usbHsIfResetDevice(UsbHsClientIfSession* s); void usbHsEpClose(UsbHsClientEpSession* s); /// Gets the Xfer Event which is signaled when PostBufferAsync finishes. This is only valid for [2.0.0+]. If using \ref eventWait with this, then \ref eventClear should be used if the event was signaled (since the autoclear is false). -static inline Event* usbHsEpGetXferEvent(UsbHsClientEpSession* s) { +NX_CONSTEXPR Event* usbHsEpGetXferEvent(UsbHsClientEpSession* s) { return &s->eventXfer; } +/// Gets the buffer size to use with \ref usbHsEpShareReportRing. +NX_CONSTEXPR u32 usbHsEpGetReportRingSize(UsbHsClientEpSession* s) { + u64 max_reports = s->maxUrbCount * 0x21; + u32 size = sizeof(UsbHsRingHeader) + max_reports*sizeof(UsbHsXferReport); + size = (size+0xFFF) & ~0xFFF; + return size; +} + /** * @brief Starts an async data transfer with the specified endpoint. The Event from \ref usbHsEpGetXferEvent can be used to determine when the transfer finished. If you don't need async, \ref usbHsEpPostBuffer can be used instead. * @note Only available on [2.0.0+]. @@ -299,6 +306,8 @@ Result usbHsEpCreateSmmuSpace(UsbHsClientEpSession* s, void* buffer, u32 size); /** * @brief This creates TransferMemory which is used to read \ref UsbHsXferReport when \ref usbHsEpGetXferReport is used, instead of using the service cmd. * @note Only available on [4.0.0+]. + * @param buffer Buffer, must be 0x1000-byte aligned. + * @param[in] size Buffer size, \ref usbHsEpGetReportRingSize can be used to calculate this. */ -Result usbHsEpShareReportRing(UsbHsClientEpSession* s); +Result usbHsEpShareReportRing(UsbHsClientEpSession* s, void* buffer, size_t size); diff --git a/nx/source/services/usbhs.c b/nx/source/services/usbhs.c index a869ab4f..7b72fe3d 100644 --- a/nx/source/services/usbhs.c +++ b/nx/source/services/usbhs.c @@ -377,7 +377,6 @@ void usbHsEpClose(UsbHsClientEpSession* s) { serviceAssumeDomain(&s->s); serviceClose(&s->s); eventClose(&s->eventXfer); - tmemClose(&s->tmem); memset(s, 0, sizeof(UsbHsClientEpSession)); } @@ -420,7 +419,7 @@ Result usbHsEpGetXferReport(UsbHsClientEpSession* s, UsbHsXferReport* reports, u if (hosversionBefore(2,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - if (!s->tmem_initialized) { + if (s->ringbuf == NULL) { serviceAssumeDomain(&s->s); return serviceDispatchInOut(&s->s, 5, max_reports, *count, .buffer_attrs = { (hosversionBefore(3,0,0) ? SfBufferAttr_HipcMapAlias : SfBufferAttr_HipcAutoSelect) | SfBufferAttr_Out }, @@ -430,7 +429,7 @@ Result usbHsEpGetXferReport(UsbHsClientEpSession* s, UsbHsXferReport* reports, u u32 total=0; - UsbHsRingHeader *hdr = (UsbHsRingHeader*)s->tmem.src_addr; + UsbHsRingHeader *hdr = (UsbHsRingHeader*)s->ringbuf; UsbHsXferReport *ring_reports = (UsbHsXferReport*)(hdr+1); memset(reports, 0, max_reports*sizeof(UsbHsXferReport)); @@ -515,26 +514,25 @@ Result usbHsEpCreateSmmuSpace(UsbHsClientEpSession* s, void* buffer, u32 size) { return serviceDispatchIn(&s->s, 7, in); } -Result usbHsEpShareReportRing(UsbHsClientEpSession* s) { +Result usbHsEpShareReportRing(UsbHsClientEpSession* s, void* buffer, size_t size) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - if (s->tmem_initialized) + if (s->ringbuf) return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized); s->max_reports = s->maxUrbCount * 0x21; - u32 size = sizeof(UsbHsRingHeader) + s->max_reports*sizeof(UsbHsXferReport); - size = (size+0xFFF) & ~0xFFF; - Result rc = tmemCreate(&s->tmem, size, Perm_Rw); + TransferMemory tmem={}; + Result rc = tmemCreateFromMemory(&tmem, buffer, size, Perm_Rw); if (R_FAILED(rc)) return rc; serviceAssumeDomain(&s->s); rc = serviceDispatchIn(&s->s, 8, size, .in_num_handles = 1, - .in_handles = { s->tmem.handle }, + .in_handles = { tmem.handle }, ); - if (R_FAILED(rc)) tmemClose(&s->tmem); - else s->tmem_initialized = true; + tmemClose(&tmem); + if (R_SUCCEEDED(rc)) s->ringbuf = buffer; return rc; }