Implemented usbhs endpoints, other adjustments. Updated field name in UsbHsXferReport. Added defines in usb.h from libusb.

This commit is contained in:
yellows8 2018-11-30 01:57:36 -05:00
parent 31cea3a6b6
commit ee066a27ee
3 changed files with 260 additions and 3 deletions

View File

@ -18,6 +18,11 @@
#define USB_DT_DEVICE_SIZE 0x12 #define USB_DT_DEVICE_SIZE 0x12
#define USB_DT_SS_ENDPOINT_COMPANION_SIZE 6 #define USB_DT_SS_ENDPOINT_COMPANION_SIZE 6
#define USB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
#define USB_ENDPOINT_DIR_MASK 0x80
#define USB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */
/// Imported from libusb, with some adjustments. /// Imported from libusb, with some adjustments.
struct usb_endpoint_descriptor { struct usb_endpoint_descriptor {
uint8_t bLength; uint8_t bLength;

View File

@ -75,7 +75,7 @@ typedef struct {
} PACKED UsbHsInterface; } PACKED UsbHsInterface;
typedef struct { typedef struct {
u32 unk_x0; u32 xferId;
Result res; Result res;
u32 requestedSize; u32 requestedSize;
u32 transferredSize; u32 transferredSize;
@ -94,6 +94,7 @@ typedef struct {
typedef struct { typedef struct {
Service s; Service s;
Event eventXfer; ///< [2.0.0+] Signaled when PostBufferAsync finishes.
struct usb_endpoint_descriptor desc; struct usb_endpoint_descriptor desc;
} UsbHsClientEpSession; } UsbHsClientEpSession;
@ -188,6 +189,24 @@ 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. /// 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); Result usbHsIfCtrlXfer(UsbHsClientIfSession* s, u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, void* buffer, u32* transferredSize);
/**
* @brief Opens an endpoint. maxUrbCount*maxXferSize must be non-zero.
* @param[in] s The interface object.
* @param[out] ep The endpoint object.
* @param[in] maxUrbCount maxUrbCount, must be <0x11.
* @param[in] maxXferSize Max transfer size for a packet. This can be desc->wMaxPacketSize. Must be <=0xFF0000.
* @param[in] desc Endpoint descriptor.
*/
Result usbHsIfOpenUsbEp(UsbHsClientIfSession* s, UsbHsClientEpSession* ep, u16 maxUrbCount, u32 maxXferSize, struct usb_endpoint_descriptor *desc);
/// Resets the device: has the same affect as unplugging the device and plugging it back in. /// Resets the device: has the same affect as unplugging the device and plugging it back in.
Result usbHsIfResetDevice(UsbHsClientIfSession* s); Result usbHsIfResetDevice(UsbHsClientIfSession* s);
/// UsbHsClientEpSession
/// Closes the specified endpoint session.
void usbHsEpClose(UsbHsClientEpSession* s);
/// Uses a data transfer with the specified endpoint, this will block until the transfer finishes. The buffer address and size should be aligned to 0x1000-bytes, where the input size is the original size.
Result usbHsEpPostBuffer(UsbHsClientEpSession* s, void* buffer, u32 size, u32* transferredSize);

View File

@ -56,6 +56,38 @@ Event* usbHsGetInterfaceStateChangeEvent(void) {
return &g_usbHsInterfaceStateChangeEvent; return &g_usbHsInterfaceStateChangeEvent;
} }
static Result _usbHsCmdNoIO(Service* s, u64 cmd_id) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
} *raw;
raw = serviceIpcPrepareHeader(s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = cmd_id;
Result rc = serviceIpcDispatch(s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
static Result _usbHsBindClientProcess(Handle prochandle) { static Result _usbHsBindClientProcess(Handle prochandle) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
@ -628,19 +660,31 @@ Result usbHsIfCtrlXfer(UsbHsClientIfSession* s, u8 bmRequestType, u8 bRequest, u
return rc; return rc;
} }
Result usbHsIfResetDevice(UsbHsClientIfSession* s) { Result usbHsIfOpenUsbEp(UsbHsClientIfSession* s, UsbHsClientEpSession* ep, u16 maxUrbCount, u32 maxXferSize, struct usb_endpoint_descriptor *desc) {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
memset(ep, 0, sizeof(UsbHsClientEpSession));
struct { struct {
u64 magic; u64 magic;
u64 cmd_id; u64 cmd_id;
u16 maxUrbCount;
u32 epType;
u32 epNumber;
u32 epDirection;
u32 maxXferSize;
} *raw; } *raw;
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw)); raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 8; raw->cmd_id = kernelAbove200() ? 9 : 4;
raw->maxUrbCount = maxUrbCount;
raw->epType = (desc->bmAttributes & USB_TRANSFER_TYPE_MASK) + 1;
raw->epNumber = desc->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
raw->epDirection = (desc->bEndpointAddress & USB_ENDPOINT_IN) == 0 ? 0x1 : 0x2;
raw->maxXferSize = maxXferSize;
Result rc = serviceIpcDispatch(&s->s); Result rc = serviceIpcDispatch(&s->s);
@ -649,14 +693,203 @@ Result usbHsIfResetDevice(UsbHsClientIfSession* s) {
struct { struct {
u64 magic; u64 magic;
u64 result; u64 result;
struct usb_endpoint_descriptor desc;
} PACKED *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) memcpy(&ep->desc, &resp->desc, sizeof(struct usb_endpoint_descriptor));
if (R_SUCCEEDED(rc)) {
serviceCreateSubservice(&ep->s, &s->s, &r, 0);
}
}
if (R_SUCCEEDED(rc)) {
if (kernelAbove200()) {
rc = _usbHsCmdNoIO(&ep->s, 3);//Populate
if (R_SUCCEEDED(rc)) rc = _usbHsGetEvent(&ep->s, &ep->eventXfer, 2);
}
if (R_FAILED(rc)) {
serviceClose(&ep->s);
eventClose(&ep->eventXfer);
}
}
return rc;
}
Result usbHsIfResetDevice(UsbHsClientIfSession* s) {
return _usbHsCmdNoIO(&s->s, 8);
}
void usbHsEpClose(UsbHsClientEpSession* s) {
if (!serviceIsActive(&s->s)) return;
_usbHsCmdNoIO(&s->s, kernelAbove200() ? 1 : 3);//Close
serviceClose(&s->s);
eventClose(&s->eventXfer);
memset(s, 0, sizeof(UsbHsClientIfSession));
}
static Result _usbHsEpSubmitRequest(UsbHsClientEpSession* s, void* buffer, u32 size, u32 timeoutInMs, u32* transferredSize) {
bool dir = (s->desc.bEndpointAddress & USB_ENDPOINT_IN) != 0;
size_t bufsize = (size + 0xFFF) & ~0xFFF;
armDCacheFlush(buffer, size);
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 size;
u32 timeoutInMs;//?
} *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 ? 1 : 0;
raw->size = size;
raw->timeoutInMs = timeoutInMs;
Result rc = serviceIpcDispatch(&s->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u32 transferredSize;
} *resp; } *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp)); serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw; resp = r.Raw;
rc = resp->result; rc = resp->result;
if (R_SUCCEEDED(rc) && transferredSize) *transferredSize = resp->transferredSize;
}
if (dir) armDCacheFlush(buffer, size);
return rc;
}
static Result _usbHsEpPostBufferAsync(UsbHsClientEpSession* s, void* buffer, u32 size, u64 unk, u32* xferId) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 size;
u64 buffer;
u64 unk;
} *raw;
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 4;
raw->size = size;
raw->buffer = (u64)buffer;
raw->unk = unk;
Result rc = serviceIpcDispatch(&s->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u32 xferId;
} *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && xferId) *xferId = resp->xferId;
} }
return rc; return rc;
} }
static Result _usbHsEpGetXferReport(UsbHsClientEpSession* s, UsbHsXferReport* reports, u32 max_reports, u32* count) {
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 max_reports;
} *raw;
ipcAddRecvBuffer(&c, reports, sizeof(UsbHsXferReport) * max_reports, BufferType_Normal);
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 5;
raw->max_reports = max_reports;
Result rc = serviceIpcDispatch(&s->s);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u32 count;
} *resp;
serviceIpcParse(&s->s, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc) && count) *count = resp->count;
}
return rc;
}
Result usbHsEpPostBuffer(UsbHsClientEpSession* s, void* buffer, u32 size, u32* transferredSize) {
Result rc=0;
u32 xferId=0;
u32 count=0;
UsbHsXferReport report;
if (!kernelAbove200()) return _usbHsEpSubmitRequest(s, buffer, size, 0, transferredSize);
rc = _usbHsEpPostBufferAsync(s, buffer, size, 0, &xferId);
if (R_FAILED(rc)) return rc;
rc = eventWait(&s->eventXfer, U64_MAX);
if (R_FAILED(rc)) return rc;
eventClear(&s->eventXfer);
memset(&report, 0, sizeof(report));
rc = _usbHsEpGetXferReport(s, &report, 1, &count);
if (R_FAILED(rc)) return rc;
if (count<1) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
*transferredSize = report.transferredSize;
rc = report.res;
return rc;
}