From 9377851197843fffc914d9cda601c2b69d46b004 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Mon, 13 Nov 2017 17:18:07 -0500 Subject: [PATCH] Imported usbComms from elsewhere. Removed usb_dev.h since the .c for it was previously removed. In usbDsInitialize(), skip calling _usbDsSetVidPidBcd() when deviceinfo is NULL. --- nx/Makefile | 2 +- nx/include/switch.h | 2 + nx/include/switch/devices/usb_comms.h | 6 + nx/include/switch/devices/usb_dev.h | 13 -- nx/source/devices/usb_comms.c | 297 ++++++++++++++++++++++++++ nx/source/services/usb.c | 2 +- 6 files changed, 307 insertions(+), 15 deletions(-) create mode 100644 nx/include/switch/devices/usb_comms.h delete mode 100644 nx/include/switch/devices/usb_dev.h create mode 100644 nx/source/devices/usb_comms.c diff --git a/nx/Makefile b/nx/Makefile index 71ccaac2..b398a3b7 100644 --- a/nx/Makefile +++ b/nx/Makefile @@ -24,7 +24,7 @@ VERSION := $(LIBNX_MAJOR).$(LIBNX_MINOR).$(LIBNX_PATCH) #--------------------------------------------------------------------------------- TARGET := nx #BUILD := build -SOURCES := source/arm source/system source/kernel source/services source/gfx +SOURCES := source/arm source/system source/kernel source/services source/gfx source/devices DATA := data INCLUDES := include diff --git a/nx/include/switch.h b/nx/include/switch.h index 7c43ca47..9cfb5754 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -37,6 +37,8 @@ extern "C" { #include #include +#include + #ifdef __cplusplus } #endif diff --git a/nx/include/switch/devices/usb_comms.h b/nx/include/switch/devices/usb_comms.h new file mode 100644 index 00000000..4d23aa01 --- /dev/null +++ b/nx/include/switch/devices/usb_comms.h @@ -0,0 +1,6 @@ +Result usbCommsInitialize(void); +void usbCommsExit(void); + +size_t usbCommsRead(void* buffer, size_t size); +size_t usbCommsWrite(const void* buffer, size_t size); + diff --git a/nx/include/switch/devices/usb_dev.h b/nx/include/switch/devices/usb_dev.h deleted file mode 100644 index 1138be89..00000000 --- a/nx/include/switch/devices/usb_dev.h +++ /dev/null @@ -1,13 +0,0 @@ -/// Switch-as-device<>host USB comms for serial, uses usbDs. Do not directly use usbDs when using this. -/// WARNING: This doesn't always work properly. - -/// usbDevInitialize will not return until the newline data transfer to the host finishes, aka when the host reads that data. -Result usbDevInitialize(void); -void usbDevExit(void); - -/// These will throw fatal-error when any errors occur. These return the actual transfer size. -/// Note that if you use usbDevRead() where size is <0x200(wMaxPacketSize), any data after that in an USB packet will be discarded. That remaining data in a packet won't be readable by calling usbDevRead again. -/// These will not return until the data transfer finishes. -size_t usbDevRead(void* buffer, size_t size); -size_t usbDevWrite(const void* buffer, size_t size); - diff --git a/nx/source/devices/usb_comms.c b/nx/source/devices/usb_comms.c new file mode 100644 index 00000000..ae697229 --- /dev/null +++ b/nx/source/devices/usb_comms.c @@ -0,0 +1,297 @@ +#include +#include +#include + +static bool g_usbCommsInitialized = false; + +static UsbDsInterface* interface = NULL; +static UsbDsEndpoint *g_usbComms_endpoint_in = NULL, *g_usbComms_endpoint_out = NULL; + +static u8 *g_usbComms_endpoint_in_buffer = NULL, *g_usbComms_endpoint_out_buffer = NULL; + +static Result _usbCommsInit(void); + +static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferredSize); + +Result usbCommsInitialize(void) +{ + if (g_usbCommsInitialized) return 0; + + Result ret=0; + + ret = usbDsInitialize(USBCOMPLEXID_Default, NULL); + + if (R_SUCCEEDED(ret)) { + //The buffer for PostBufferAsync commands must be 0x1000-byte aligned. + g_usbComms_endpoint_in_buffer = memalign(0x1000, 0x1000); + if (g_usbComms_endpoint_in_buffer==NULL) ret = MAKERESULT(MODULE_LIBNX, LIBNX_OUTOFMEM); + + if (R_SUCCEEDED(ret)) { + g_usbComms_endpoint_out_buffer = memalign(0x1000, 0x1000); + if (g_usbComms_endpoint_out_buffer==NULL) ret = MAKERESULT(MODULE_LIBNX, LIBNX_OUTOFMEM); + } + + if (R_SUCCEEDED(ret)) { + memset(g_usbComms_endpoint_in_buffer, 0, 0x1000); + memset(g_usbComms_endpoint_out_buffer, 0, 0x1000); + ret = _usbCommsInit(); + + if (ret != 0) { + ret += 2000<<9; + } + } + + if (R_FAILED(ret)) { + usbDsExit(); + + if (g_usbComms_endpoint_in_buffer) { + free(g_usbComms_endpoint_in_buffer); + g_usbComms_endpoint_in_buffer = NULL; + } + + if (g_usbComms_endpoint_out) { + free(g_usbComms_endpoint_out_buffer); + g_usbComms_endpoint_out_buffer = NULL; + } + } + } + else { + ret += 1000<<9; + } + + if (R_SUCCEEDED(ret)) g_usbCommsInitialized=true; + + return ret; +} + +void usbCommsExit(void) +{ + if (!g_usbCommsInitialized) return; + + usbDsExit(); + + g_usbCommsInitialized = false; + + g_usbComms_endpoint_in = NULL; + g_usbComms_endpoint_out = NULL; + + if (g_usbComms_endpoint_in_buffer) { + free(g_usbComms_endpoint_in_buffer); + g_usbComms_endpoint_in_buffer = NULL; + } + + if (g_usbComms_endpoint_out) { + free(g_usbComms_endpoint_out_buffer); + g_usbComms_endpoint_out_buffer = NULL; + } +} + +static Result _usbCommsInit(void) +{ + Result ret=0; + + struct usb_interface_descriptor interface_descriptor = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USBDS_DEFAULT_InterfaceNumber, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceProtocol = USB_CLASS_VENDOR_SPEC, + }; + + struct usb_endpoint_descriptor endpoint_descriptor_in = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_ENDPOINT_IN, + .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, + .bmAttributes = USB_TRANSFER_TYPE_BULK, + .wMaxPacketSize = 0x200, + }; + + //Setup interface. + ret = usbDsGetDsInterface(&interface, &interface_descriptor, "usb"); + if (R_FAILED(ret)) return ret; + + //Setup endpoints. + ret = usbDsInterface_GetDsEndpoint(interface, &g_usbComms_endpoint_in, &endpoint_descriptor_in);//device->host + if (R_FAILED(ret)) return ret; + + ret = usbDsInterface_GetDsEndpoint(interface, &g_usbComms_endpoint_out, &endpoint_descriptor_out);//host->device + if (R_FAILED(ret)) return ret; + + ret = usbDsInterface_EnableInterface(interface); + if (R_FAILED(ret)) return ret; + + return ret; +} + +static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize) +{ + Result ret=0; + u32 urbId=0; + u8 *bufptr = (u8*)buffer; + u8 *transfer_buffer = NULL; + u8 transfer_type=0; + s32 tmpindex=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. + ret = usbDsWaitReady(); + if (R_FAILED(ret)) return ret; + + 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 = g_usbComms_endpoint_out_buffer; + memset(g_usbComms_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 (sizedevice transfer. + ret = usbDsEndpoint_PostBufferAsync(g_usbComms_endpoint_out, transfer_buffer, chunksize, &urbId); + if (R_FAILED(ret)) return ret; + + //Wait for the transfer to finish. + svcWaitSynchronization(&tmpindex, &g_usbComms_endpoint_out->CompletionEvent, 1, U64_MAX); + svcClearEvent(g_usbComms_endpoint_out->CompletionEvent); + + ret = usbDsEndpoint_GetReportData(g_usbComms_endpoint_out, &reportdata); + if (R_FAILED(ret)) return ret; + + ret = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize); + if (R_FAILED(ret)) return ret; + + 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 ret; +} + +static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferredSize) +{ + Result ret=0; + u32 urbId=0; + u32 chunksize=0; + u8 *bufptr = (u8*)buffer; + u8 *transfer_buffer = NULL; + s32 tmpindex=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. + ret = usbDsWaitReady(); + if (R_FAILED(ret)) return ret; + + 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 = g_usbComms_endpoint_in_buffer; + memset(g_usbComms_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 (sizehost transfer. + ret = usbDsEndpoint_PostBufferAsync(g_usbComms_endpoint_in, transfer_buffer, chunksize, &urbId); + if(R_FAILED(ret))return ret; + + //Wait for the transfer to finish. + svcWaitSynchronization(&tmpindex, &g_usbComms_endpoint_in->CompletionEvent, 1, U64_MAX); + svcClearEvent(g_usbComms_endpoint_in->CompletionEvent); + + ret = usbDsEndpoint_GetReportData(g_usbComms_endpoint_in, &reportdata); + if (R_FAILED(ret)) return ret; + + ret = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize); + if (R_FAILED(ret)) return ret; + + 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 ret; +} + +size_t usbCommsRead(void* buffer, size_t size) +{ + size_t transferredSize=0; + u32 state=0; + Result ret, ret2; + ret = _usbCommsRead(buffer, size, &transferredSize); + if (R_FAILED(ret)) { + ret2 = usbDsGetState(&state); + if (R_SUCCEEDED(ret2)) { + if (state!=5) ret = _usbCommsRead(buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this. + } + if (R_FAILED(ret))fatalSimple(ret); + } + return transferredSize; +} + +size_t usbCommsWrite(const void* buffer, size_t size) +{ + size_t transferredSize=0; + u32 state=0; + Result ret, ret2; + ret = _usbCommsWrite(buffer, size, &transferredSize); + if (R_FAILED(ret)) { + ret2 = usbDsGetState(&state); + if (R_SUCCEEDED(ret2)) { + if (state!=5) ret = _usbCommsWrite(buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this. + } + if (R_FAILED(ret))fatalSimple(ret); + } + return transferredSize; +} + diff --git a/nx/source/services/usb.c b/nx/source/services/usb.c index 6554b2ac..be4c4a8d 100644 --- a/nx/source/services/usb.c +++ b/nx/source/services/usb.c @@ -30,7 +30,7 @@ Result usbDsInitialize(usbComplexId complexId, const usbDsDeviceInfo* deviceinfo 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) && kernelAbove200()) { + if (R_SUCCEEDED(rc) && deviceinfo && kernelAbove200()) { rc = _usbDsSetVidPidBcd(deviceinfo); }