static Result _usbCommsWrite(usbCommsInterface* interface, const void* buffer, size_t size, size_t* transferredSize, u64 timeout) {
Result rc = 0;
u32 urbId = 0;
u32 chunksize = 0;
u8* bufptr = (u8*)buffer;
u8* transfer_buffer = NULL;
u32 tmp_transferredSize = 0;
size_t total_transferredSize = 0;
UsbDsReportData reportdata;
const u32 wMaxPacketSize = 0x200; // Adjust based on your USB endpoint settings
// Make sure endpoints are ready for data-transfer / wait for init if needed.
rc = usbDsWaitReady(timeout);
if (R_FAILED(rc)) return rc;
while (size) {
if (((u64)bufptr) & 0xfff) { // If bufptr isn't page-aligned, use a temp buffer
transfer_buffer = interface->endpoint_in_buffer;
memset(interface->endpoint_in_buffer, 0, 0x1000);
chunksize = 0x1000;
chunksize -= ((u64)bufptr) & 0xfff; // Align for next transfer
if (size < chunksize) chunksize = size;
memcpy(interface->endpoint_in_buffer, bufptr, chunksize);
}
else {
transfer_buffer = bufptr;
chunksize = size;
}
// Ensure buffer alignment
if (((u64)transfer_buffer) & 0xfff) {
printf("Error: Transfer buffer is not 0x1000 aligned!\n");
return -1;
}
// Disable caching for this memory range
/*
rc = svcSetMemoryAttribute(transfer_buffer, chunksize, 0, 8);
if (R_FAILED(rc)) {
printf("Failed to set memory attribute: 0x%08X\n", rc);
return rc;
}
*/
// Flush data cache before sending
svcFlushProcessDataCache(CUR_PROCESS_HANDLE, (u64)transfer_buffer, chunksize);
// Start a device->host transfer.
printf("Posting buffer: addr=%p, size=%u\n", transfer_buffer, chunksize);
rc = usbDsEndpoint_PostBufferAsync(interface->endpoint_in, transfer_buffer, chunksize, &urbId);
if (R_FAILED(rc)) return rc;
// Wait for transfer to complete
rc = eventWait(&interface->endpoint_in->CompletionEvent, timeout);
if (R_FAILED(rc)) {
printf("eventWait timeout: 0x%08X\n", rc);
usbDsEndpoint_Cancel(interface->endpoint_in);
eventWait(&interface->endpoint_in->CompletionEvent, UINT64_MAX);
eventClear(&interface->endpoint_in->CompletionEvent);
return rc;
}
eventClear(&interface->endpoint_in->CompletionEvent);
// Get transfer status
rc = usbDsEndpoint_GetReportData(interface->endpoint_in, &reportdata);
if (R_FAILED(rc)) return rc;
rc = usbDsParseReportData(&reportdata, urbId, NULL, &tmp_transferredSize);
if (R_FAILED(rc)) return rc;
if (tmp_transferredSize > chunksize) tmp_transferredSize = chunksize;
total_transferredSize += (size_t)tmp_transferredSize;
bufptr += tmp_transferredSize;
size -= tmp_transferredSize;
// If transfer completes early, exit loop
if (tmp_transferredSize < chunksize) break;
}
// Send Zero-Length Packet (ZLP) if needed
if ((total_transferredSize % wMaxPacketSize) == 0 && total_transferredSize > 0) {
printf("Sending Zero-Length Packet (ZLP)...\n");
usbDsEndpoint_PostBufferAsync(interface->endpoint_in, NULL, 0, &urbId);
// Wait for ZLP transfer to complete
rc = eventWait(&interface->endpoint_in->CompletionEvent, timeout);
if (R_FAILED(rc)) {
printf("ZLP eventWait failed: 0x%08X\n", rc);
usbDsEndpoint_Cancel(interface->endpoint_in);
return rc;
}
eventClear(&interface->endpoint_in->CompletionEvent);
}
if (transferredSize) *transferredSize = total_transferredSize;
return rc;
}