mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-23 05:12:39 +02:00
Allow using multiple interfaces with usbComms. Added usbComms Ex funcs. Use RwLock with usbComms. Various other usbComms changes.
This commit is contained in:
parent
58835fae1a
commit
a3baa0eeb1
@ -11,5 +11,21 @@
|
|||||||
Result usbCommsInitialize(void);
|
Result usbCommsInitialize(void);
|
||||||
void usbCommsExit(void);
|
void usbCommsExit(void);
|
||||||
|
|
||||||
|
/// Same as usbCommsInitialize, except this can be used after usbCommsInitialize (or instead of usbCommsInitialize), for creating new interface(s).
|
||||||
|
/// bInterface* are the values for the same fields in usb.h \ref usb_interface_descriptor. \ref usbCommsInitialize uses USB_CLASS_VENDOR_SPEC for all of these internally.
|
||||||
|
Result usbCommsInitializeEx(u32 *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol);
|
||||||
|
|
||||||
|
/// Shutdown the specified interface. If no interfaces are remaining, this then uses \ref usbCommsExit internally.
|
||||||
|
void usbCommsExitEx(u32 interface);
|
||||||
|
|
||||||
|
/// Read data with the default interface.
|
||||||
size_t usbCommsRead(void* buffer, size_t size);
|
size_t usbCommsRead(void* buffer, size_t size);
|
||||||
|
|
||||||
|
/// Write data with the default interface.
|
||||||
size_t usbCommsWrite(const void* buffer, size_t size);
|
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);
|
||||||
|
@ -2,97 +2,173 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "result.h"
|
#include "result.h"
|
||||||
|
#include "kernel/rwlock.h"
|
||||||
#include "services/fatal.h"
|
#include "services/fatal.h"
|
||||||
#include "services/usb.h"
|
#include "services/usb.h"
|
||||||
#include "runtime/devices/usb_comms.h"
|
#include "runtime/devices/usb_comms.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 bool g_usbCommsInitialized = false;
|
||||||
|
|
||||||
static UsbDsInterface* interface = NULL;
|
static usbCommsInterface g_usbCommsInterfaces[TOTAL_INTERFACES];
|
||||||
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 RwLock g_usbCommsLock;
|
||||||
|
|
||||||
static Result _usbCommsInit(void);
|
static Result _usbCommsInterfaceInit(usbCommsInterface *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol);
|
||||||
|
|
||||||
static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferredSize);
|
static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, size_t size, size_t *transferredSize);
|
||||||
|
|
||||||
|
Result usbCommsInitializeEx(u32 *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol)
|
||||||
|
{
|
||||||
|
bool found=0;
|
||||||
|
usbCommsInterface *inter = NULL;
|
||||||
|
|
||||||
|
rwlockWriteLock(&g_usbCommsLock);
|
||||||
|
|
||||||
|
if (g_usbCommsInitialized && interface==NULL) {
|
||||||
|
rwlockWriteUnlock(&g_usbCommsLock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result rc=0;
|
||||||
|
u32 i = 0;
|
||||||
|
|
||||||
|
if (!g_usbCommsInitialized) rc = usbDsInitialize(UsbComplexId_Default, NULL);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
for(i=0; i<TOTAL_INTERFACES; i++) {
|
||||||
|
inter = &g_usbCommsInterfaces[i];
|
||||||
|
rwlockReadLock(&inter->lock);
|
||||||
|
if (!inter->initialized) found=1;
|
||||||
|
rwlockReadUnlock(&inter->lock);
|
||||||
|
|
||||||
|
if (found) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
rwlockWriteLock(&inter->lock);
|
||||||
|
rwlockWriteLock(&inter->lock_in);
|
||||||
|
rwlockWriteLock(&inter->lock_out);
|
||||||
|
rc = _usbCommsInterfaceInit(inter, bInterfaceClass, bInterfaceSubClass, bInterfaceProtocol);
|
||||||
|
rwlockWriteUnlock(&inter->lock_out);
|
||||||
|
rwlockWriteUnlock(&inter->lock_in);
|
||||||
|
rwlockWriteUnlock(&inter->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
usbCommsExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) g_usbCommsInitialized=true;
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && interface) *interface = i;
|
||||||
|
|
||||||
|
rwlockWriteUnlock(&g_usbCommsLock);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
Result usbCommsInitialize(void)
|
Result usbCommsInitialize(void)
|
||||||
{
|
{
|
||||||
if (g_usbCommsInitialized) return 0;
|
return usbCommsInitializeEx(NULL, USB_CLASS_VENDOR_SPEC, USB_CLASS_VENDOR_SPEC, USB_CLASS_VENDOR_SPEC);
|
||||||
|
}
|
||||||
|
|
||||||
Result ret=0;
|
static void _usbCommsInterfaceExit(usbCommsInterface *interface)
|
||||||
|
{
|
||||||
ret = usbDsInitialize(UsbComplexId_Default, NULL);
|
rwlockWriteLock(&interface->lock);
|
||||||
|
if (!interface->initialized) {
|
||||||
if (R_SUCCEEDED(ret)) {
|
rwlockWriteUnlock(&interface->lock);
|
||||||
//The buffer for PostBufferAsync commands must be 0x1000-byte aligned.
|
return;
|
||||||
g_usbComms_endpoint_in_buffer = memalign(0x1000, 0x1000);
|
|
||||||
if (g_usbComms_endpoint_in_buffer==NULL) ret = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(ret)) {
|
|
||||||
g_usbComms_endpoint_out_buffer = memalign(0x1000, 0x1000);
|
|
||||||
if (g_usbComms_endpoint_out_buffer==NULL) ret = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
free(g_usbComms_endpoint_in_buffer);
|
|
||||||
g_usbComms_endpoint_in_buffer = NULL;
|
|
||||||
|
|
||||||
free(g_usbComms_endpoint_out_buffer);
|
|
||||||
g_usbComms_endpoint_out_buffer = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ret += 1000<<9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_SUCCEEDED(ret)) g_usbCommsInitialized=true;
|
rwlockWriteLock(&interface->lock_in);
|
||||||
|
rwlockWriteLock(&interface->lock_out);
|
||||||
|
|
||||||
return ret;
|
interface->initialized = 0;
|
||||||
|
|
||||||
|
usbDsInterface_DisableInterface(interface->interface);
|
||||||
|
usbDsEndpoint_Close(interface->endpoint_in);
|
||||||
|
usbDsEndpoint_Close(interface->endpoint_out);
|
||||||
|
usbDsInterface_Close(interface->interface);
|
||||||
|
|
||||||
|
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 usbCommsExitEx(u32 interface)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
bool found=0;
|
||||||
|
if (interface>=TOTAL_INTERFACES) return;
|
||||||
|
|
||||||
|
_usbCommsInterfaceExit(&g_usbCommsInterfaces[interface]);
|
||||||
|
|
||||||
|
for (i=0; i<TOTAL_INTERFACES; i++)
|
||||||
|
{
|
||||||
|
rwlockReadLock(&g_usbCommsInterfaces[i].lock);
|
||||||
|
if (g_usbCommsInterfaces[i].initialized) found = 1;
|
||||||
|
rwlockReadUnlock(&g_usbCommsInterfaces[i].lock);
|
||||||
|
|
||||||
|
if (found) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) usbCommsExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void usbCommsExit(void)
|
void usbCommsExit(void)
|
||||||
{
|
{
|
||||||
if (!g_usbCommsInitialized) return;
|
u32 i;
|
||||||
|
|
||||||
|
rwlockWriteLock(&g_usbCommsLock);
|
||||||
|
|
||||||
usbDsExit();
|
usbDsExit();
|
||||||
|
|
||||||
g_usbCommsInitialized = false;
|
g_usbCommsInitialized = false;
|
||||||
|
|
||||||
g_usbComms_endpoint_in = NULL;
|
rwlockWriteUnlock(&g_usbCommsLock);
|
||||||
g_usbComms_endpoint_out = NULL;
|
|
||||||
|
|
||||||
free(g_usbComms_endpoint_in_buffer);
|
for (i=0; i<TOTAL_INTERFACES; i++)
|
||||||
g_usbComms_endpoint_in_buffer = NULL;
|
{
|
||||||
|
_usbCommsInterfaceExit(&g_usbCommsInterfaces[i]);
|
||||||
free(g_usbComms_endpoint_out_buffer);
|
}
|
||||||
g_usbComms_endpoint_out_buffer = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result _usbCommsInit(void)
|
static Result _usbCommsInterfaceInit(usbCommsInterface *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol)
|
||||||
{
|
{
|
||||||
Result ret=0;
|
Result rc=0;
|
||||||
|
|
||||||
struct usb_interface_descriptor interface_descriptor = {
|
struct usb_interface_descriptor interface_descriptor = {
|
||||||
.bLength = USB_DT_INTERFACE_SIZE,
|
.bLength = USB_DT_INTERFACE_SIZE,
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
.bInterfaceNumber = USBDS_DEFAULT_InterfaceNumber,
|
.bInterfaceNumber = USBDS_DEFAULT_InterfaceNumber,
|
||||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
.bInterfaceClass = bInterfaceClass,
|
||||||
.bInterfaceSubClass = USB_CLASS_VENDOR_SPEC,
|
.bInterfaceSubClass = bInterfaceSubClass,
|
||||||
.bInterfaceProtocol = USB_CLASS_VENDOR_SPEC,
|
.bInterfaceProtocol = bInterfaceProtocol,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct usb_endpoint_descriptor endpoint_descriptor_in = {
|
struct usb_endpoint_descriptor endpoint_descriptor_in = {
|
||||||
@ -111,26 +187,44 @@ static Result _usbCommsInit(void)
|
|||||||
.wMaxPacketSize = 0x200,
|
.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.
|
//Setup interface.
|
||||||
ret = usbDsGetDsInterface(&interface, &interface_descriptor, "usb");
|
rc = usbDsGetDsInterface(&interface->interface, &interface_descriptor, "usb");
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
//Setup endpoints.
|
//Setup endpoints.
|
||||||
ret = usbDsInterface_GetDsEndpoint(interface, &g_usbComms_endpoint_in, &endpoint_descriptor_in);//device->host
|
rc = usbDsInterface_GetDsEndpoint(interface->interface, &interface->endpoint_in, &endpoint_descriptor_in);//device->host
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
ret = usbDsInterface_GetDsEndpoint(interface, &g_usbComms_endpoint_out, &endpoint_descriptor_out);//host->device
|
rc = usbDsInterface_GetDsEndpoint(interface->interface, &interface->endpoint_out, &endpoint_descriptor_out);//host->device
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
ret = usbDsInterface_EnableInterface(interface);
|
rc = usbDsInterface_EnableInterface(interface->interface);
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
return ret;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize)
|
static Result _usbCommsRead(usbCommsInterface *interface, void* buffer, size_t size, size_t *transferredSize)
|
||||||
{
|
{
|
||||||
Result ret=0;
|
Result rc=0;
|
||||||
u32 urbId=0;
|
u32 urbId=0;
|
||||||
u8 *bufptr = (u8*)buffer;
|
u8 *bufptr = (u8*)buffer;
|
||||||
u8 *transfer_buffer = NULL;
|
u8 *transfer_buffer = NULL;
|
||||||
@ -141,15 +235,15 @@ static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize)
|
|||||||
usbDsReportData reportdata;
|
usbDsReportData reportdata;
|
||||||
|
|
||||||
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
|
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
|
||||||
ret = usbDsWaitReady();
|
rc = usbDsWaitReady();
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
while(size)
|
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.
|
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;
|
transfer_buffer = interface->endpoint_out_buffer;
|
||||||
memset(g_usbComms_endpoint_out_buffer, 0, 0x1000);
|
memset(interface->endpoint_out_buffer, 0, 0x1000);
|
||||||
|
|
||||||
chunksize = 0x1000;
|
chunksize = 0x1000;
|
||||||
chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer).
|
chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer).
|
||||||
@ -166,18 +260,18 @@ static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Start a host->device transfer.
|
//Start a host->device transfer.
|
||||||
ret = usbDsEndpoint_PostBufferAsync(g_usbComms_endpoint_out, transfer_buffer, chunksize, &urbId);
|
rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_out, transfer_buffer, chunksize, &urbId);
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
//Wait for the transfer to finish.
|
//Wait for the transfer to finish.
|
||||||
svcWaitSynchronizationSingle(g_usbComms_endpoint_out->CompletionEvent, U64_MAX);
|
svcWaitSynchronizationSingle(interface->endpoint_out->CompletionEvent, U64_MAX);
|
||||||
svcClearEvent(g_usbComms_endpoint_out->CompletionEvent);
|
svcClearEvent(interface->endpoint_out->CompletionEvent);
|
||||||
|
|
||||||
ret = usbDsEndpoint_GetReportData(g_usbComms_endpoint_out, &reportdata);
|
rc = usbDsEndpoint_GetReportData(interface->endpoint_out, &reportdata);
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
ret = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
|
rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
|
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
|
||||||
total_transferredSize+= (size_t)tmp_transferredSize;
|
total_transferredSize+= (size_t)tmp_transferredSize;
|
||||||
@ -191,12 +285,12 @@ static Result _usbCommsRead(void* buffer, size_t size, size_t *transferredSize)
|
|||||||
|
|
||||||
if (transferredSize) *transferredSize = total_transferredSize;
|
if (transferredSize) *transferredSize = total_transferredSize;
|
||||||
|
|
||||||
return ret;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferredSize)
|
static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, size_t size, size_t *transferredSize)
|
||||||
{
|
{
|
||||||
Result ret=0;
|
Result rc=0;
|
||||||
u32 urbId=0;
|
u32 urbId=0;
|
||||||
u32 chunksize=0;
|
u32 chunksize=0;
|
||||||
u8 *bufptr = (u8*)buffer;
|
u8 *bufptr = (u8*)buffer;
|
||||||
@ -206,21 +300,21 @@ static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferre
|
|||||||
usbDsReportData reportdata;
|
usbDsReportData reportdata;
|
||||||
|
|
||||||
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
|
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
|
||||||
ret = usbDsWaitReady();
|
rc = usbDsWaitReady();
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
while(size)
|
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.
|
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;
|
transfer_buffer = interface->endpoint_in_buffer;
|
||||||
memset(g_usbComms_endpoint_in_buffer, 0, 0x1000);
|
memset(interface->endpoint_in_buffer, 0, 0x1000);
|
||||||
|
|
||||||
chunksize = 0x1000;
|
chunksize = 0x1000;
|
||||||
chunksize-= ((u64)bufptr) & 0xfff;//After this transfer, bufptr will be page-aligned(if size is large enough for another transfer).
|
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;
|
if (size<chunksize) chunksize = size;
|
||||||
|
|
||||||
memcpy(g_usbComms_endpoint_in_buffer, bufptr, chunksize);
|
memcpy(interface->endpoint_in_buffer, bufptr, chunksize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -229,18 +323,18 @@ static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferre
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Start a device->host transfer.
|
//Start a device->host transfer.
|
||||||
ret = usbDsEndpoint_PostBufferAsync(g_usbComms_endpoint_in, transfer_buffer, chunksize, &urbId);
|
rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_in, transfer_buffer, chunksize, &urbId);
|
||||||
if(R_FAILED(ret))return ret;
|
if(R_FAILED(rc))return rc;
|
||||||
|
|
||||||
//Wait for the transfer to finish.
|
//Wait for the transfer to finish.
|
||||||
svcWaitSynchronizationSingle(g_usbComms_endpoint_in->CompletionEvent, U64_MAX);
|
svcWaitSynchronizationSingle(interface->endpoint_in->CompletionEvent, U64_MAX);
|
||||||
svcClearEvent(g_usbComms_endpoint_in->CompletionEvent);
|
svcClearEvent(interface->endpoint_in->CompletionEvent);
|
||||||
|
|
||||||
ret = usbDsEndpoint_GetReportData(g_usbComms_endpoint_in, &reportdata);
|
rc = usbDsEndpoint_GetReportData(interface->endpoint_in, &reportdata);
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
ret = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
|
rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
|
||||||
if (R_FAILED(ret)) return ret;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
|
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
|
||||||
|
|
||||||
@ -254,38 +348,80 @@ static Result _usbCommsWrite(const void* buffer, size_t size, size_t *transferre
|
|||||||
|
|
||||||
if (transferredSize) *transferredSize = total_transferredSize;
|
if (transferredSize) *transferredSize = total_transferredSize;
|
||||||
|
|
||||||
return ret;
|
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)
|
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;
|
size_t transferredSize=0;
|
||||||
u32 state=0;
|
u32 state=0;
|
||||||
Result ret, ret2;
|
Result rc, rc2;
|
||||||
ret = _usbCommsRead(buffer, size, &transferredSize);
|
usbCommsInterface *inter = &g_usbCommsInterfaces[interface];
|
||||||
if (R_FAILED(ret)) {
|
bool initialized;
|
||||||
ret2 = usbDsGetState(&state);
|
|
||||||
if (R_SUCCEEDED(ret2)) {
|
if (interface>=TOTAL_INTERFACES) return 0;
|
||||||
if (state!=5) ret = _usbCommsRead(buffer, size, &transferredSize); //If state changed during transfer, try again. usbDsWaitReady() will be called from this.
|
|
||||||
|
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(ret))fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsRead));
|
if (R_FAILED(rc)) fatalSimple(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsWrite));
|
||||||
}
|
}
|
||||||
return transferredSize;
|
return transferredSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t usbCommsWrite(const void* buffer, size_t size)
|
size_t usbCommsWrite(const void* buffer, size_t size)
|
||||||
{
|
{
|
||||||
size_t transferredSize=0;
|
return usbCommsWriteEx(buffer, size, 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(MAKERESULT(Module_Libnx, LibnxError_BadUsbCommsWrite));
|
|
||||||
}
|
|
||||||
return transferredSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user