Implemented usbhs control transfers. Fixed eventCtrlXfer init. Updated a field name in UsbHsXferReport.

This commit is contained in:
yellows8 2018-11-29 23:28:19 -05:00
parent 2049ff081d
commit 31cea3a6b6
2 changed files with 163 additions and 2 deletions

View File

@ -77,7 +77,7 @@ typedef struct {
typedef struct {
u32 unk_x0;
Result res;
u32 unk_x8;
u32 requestedSize;
u32 transferredSize;
u64 unk_x10;
} UsbHsXferReport;
@ -185,6 +185,9 @@ Result usbHsIfGetAlternateInterface(UsbHsClientIfSession* s, UsbHsInterfaceInfo*
/// On 1.0.0 this is stubbed, just returns 0 with out=0.
Result usbHsIfGetCurrentFrame(UsbHsClientIfSession* s, u32* out);
/// Uses a control transfer, this will block until the transfer finishes. The buffer address and size should be aligned to 0x1000-bytes, where wLength is the original size.
Result usbHsIfCtrlXfer(UsbHsClientIfSession* s, u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, void* buffer, u32* transferredSize);
/// Resets the device: has the same affect as unplugging the device and plugging it back in.
Result usbHsIfResetDevice(UsbHsClientIfSession* s);

View File

@ -334,7 +334,7 @@ Result usbHsAcquireUsbIf(UsbHsClientIfSession* s, UsbHsInterface *interface) {
if (R_SUCCEEDED(rc)) {
rc = _usbHsGetEvent(&s->s, &s->event0, 0);
if (kernelAbove200()) rc = _usbHsGetEvent(&s->s, &s->event0, 6);
if (kernelAbove200()) rc = _usbHsGetEvent(&s->s, &s->eventCtrlXfer, 6);
if (R_FAILED(rc)) {
serviceClose(&s->s);
@ -470,6 +470,164 @@ Result usbHsIfGetCurrentFrame(UsbHsClientIfSession* s, u32* out) {
return rc;
}
static Result _usbHsIfSubmitControlRequest(UsbHsClientIfSession* s, u8 bRequest, u8 bmRequestType, u16 wValue, u16 wIndex, u16 wLength, void* buffer, u32 timeoutInMs, u32* transferredSize) {
bool dir = (bmRequestType & USB_ENDPOINT_IN) != 0;
size_t bufsize = (wLength + 0xFFF) & ~0xFFF;
armDCacheFlush(buffer, wLength);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u8 bRequest;
u8 bmRequestType;
u16 wValue;
u16 wIndex;
u16 wLength;
u32 timeoutInMs;
} PACKED *raw;
if (dir) ipcAddRecvBuffer(&c, buffer, bufsize, BufferType_Normal);
if (!dir) ipcAddSendBuffer(&c, buffer, bufsize, BufferType_Normal);
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = dir ? 6 : 7;
raw->bRequest = bRequest;
raw->bmRequestType = bmRequestType;
raw->wValue = wValue;
raw->wIndex = wIndex;
raw->wLength = wLength;
raw->timeoutInMs = timeoutInMs;
Result rc = serviceIpcDispatch(&s->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u32 transferredSize;
} *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && transferredSize) *transferredSize = resp->transferredSize;
}
if (dir) armDCacheFlush(buffer, wLength);
return rc;
}
static Result _usbHsIfCtrlXferAsync(UsbHsClientIfSession* s, u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, void* buffer) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u8 bmRequestType;
u8 bRequest;
u16 wValue;
u16 wIndex;
u16 wLength;
u64 buffer;
} PACKED *raw;
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 5;
raw->bmRequestType = bmRequestType;
raw->bRequest = bRequest;
raw->wValue = wValue;
raw->wIndex = wIndex;
raw->wLength = wLength;
raw->buffer = (u64)buffer;
Result rc = serviceIpcDispatch(&s->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
static Result _usbHsIfGetCtrlXferReport(UsbHsClientIfSession* s, UsbHsXferReport* report) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
ipcAddRecvBuffer(&c, report, sizeof(UsbHsXferReport), BufferType_Normal);
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 7;
Result rc = serviceIpcDispatch(&s->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result usbHsIfCtrlXfer(UsbHsClientIfSession* s, u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, void* buffer, u32* transferredSize) {
Result rc=0;
UsbHsXferReport report;
if (!kernelAbove200()) return _usbHsIfSubmitControlRequest(s, bRequest, bmRequestType, wValue, wIndex, wLength, buffer, 0, transferredSize);
rc = _usbHsIfCtrlXferAsync(s, bmRequestType, bRequest, wValue, wIndex, wLength, buffer);
if (R_FAILED(rc)) return rc;
rc = eventWait(&s->eventCtrlXfer, U64_MAX);
if (R_FAILED(rc)) return rc;
eventClear(&s->eventCtrlXfer);
memset(&report, 0, sizeof(report));
rc = _usbHsIfGetCtrlXferReport(s, &report);
if (R_FAILED(rc)) return rc;
*transferredSize = report.transferredSize;
rc = report.res;
return rc;
}
Result usbHsIfResetDevice(UsbHsClientIfSession* s) {
IpcCommand c;
ipcInitialize(&c);