mirror of
https://github.com/switchbrew/libnx.git
synced 2025-07-05 10:52:15 +02:00
Refactor usb:ds, add support for 5.0.0+
This commit is contained in:
parent
96dce1a8b6
commit
d146430265
@ -8,16 +8,14 @@
|
||||
#pragma once
|
||||
#include "../../types.h"
|
||||
|
||||
/// Initializes usbComms with the default number of interfaces (1)
|
||||
Result usbCommsInitialize(void);
|
||||
/// Initializes usbComms with a specific number of interfaces.
|
||||
Result usbCommsInitializeEx(u32 num_interfaces);
|
||||
|
||||
/// Exits usbComms.
|
||||
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);
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
/**
|
||||
* @file usb.h
|
||||
* @brief USB (usb:*) service IPC wrapper.
|
||||
* @author yellows8
|
||||
* @author SciresM, yellows8
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../types.h"
|
||||
#include "../services/sm.h"
|
||||
#include "../kernel/event.h"
|
||||
|
||||
/// usb:ds Switch-as-device<>host USB comms, see also here: http://switchbrew.org/index.php?title=USB_services
|
||||
|
||||
@ -18,6 +19,8 @@
|
||||
/* Descriptor sizes per descriptor type */
|
||||
#define USB_DT_INTERFACE_SIZE 9
|
||||
#define USB_DT_ENDPOINT_SIZE 7
|
||||
#define USB_DT_DEVICE_SIZE 0x12
|
||||
#define USB_DT_SS_ENDPOINT_COMPANION_SIZE 6
|
||||
|
||||
/// Imported from libusb, with some adjustments.
|
||||
struct usb_endpoint_descriptor {
|
||||
@ -35,13 +38,47 @@ struct usb_interface_descriptor {
|
||||
uint8_t bDescriptorType; /// Must match USB_DT_INTERFACE.
|
||||
uint8_t bInterfaceNumber; /// See also USBDS_DEFAULT_InterfaceNumber.
|
||||
uint8_t bAlternateSetting; /// Must match 0.
|
||||
uint8_t bNumEndpoints; /// Ignored.
|
||||
uint8_t bNumEndpoints;
|
||||
uint8_t bInterfaceClass;
|
||||
uint8_t bInterfaceSubClass;
|
||||
uint8_t bInterfaceProtocol;
|
||||
uint8_t iInterface; /// Ignored.
|
||||
};
|
||||
|
||||
/// Imported from libusb, with some adjustments.
|
||||
struct usb_device_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType; /// Must match USB_DT_Device.
|
||||
uint16_t bcdUSB;
|
||||
uint8_t bDeviceClass;
|
||||
uint8_t bDeviceSubClass;
|
||||
uint8_t bDeviceProtocol;
|
||||
uint8_t bMaxPacketSize0;
|
||||
uint16_t idVendor;
|
||||
uint16_t idProduct;
|
||||
uint16_t bcdDevice;
|
||||
uint8_t iManufacturer;
|
||||
uint8_t iProduct;
|
||||
uint8_t iSerialNumber;
|
||||
uint8_t bNumConfigurations;
|
||||
};
|
||||
|
||||
/// Imported from libusb, with some adjustments.
|
||||
struct usb_ss_endpoint_companion_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType; /// Must match USB_DT_SS_ENDPOINT_COMPANION.
|
||||
uint8_t bMaxBurst;
|
||||
uint8_t bmAttributes;
|
||||
uint16_t wBytesPerInterval;
|
||||
};
|
||||
|
||||
/// Imported from libusb, with some adjustments.
|
||||
struct usb_string_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType; /// Must match USB_DT_STRING.
|
||||
uint16_t wData[0x40];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u16 idVendor; /// VID
|
||||
u16 idProduct; /// PID
|
||||
@ -68,21 +105,27 @@ typedef struct {
|
||||
u32 interface_index;
|
||||
Service h;
|
||||
|
||||
Handle SetupEvent;
|
||||
Handle CtrlInCompletionEvent;
|
||||
Handle CtrlOutCompletionEvent;
|
||||
Event SetupEvent;
|
||||
Event CtrlInCompletionEvent;
|
||||
Event CtrlOutCompletionEvent;
|
||||
} UsbDsInterface;
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
Service h;
|
||||
Handle CompletionEvent;
|
||||
Event CompletionEvent;
|
||||
} UsbDsEndpoint;
|
||||
|
||||
typedef enum {
|
||||
UsbComplexId_Default = 0x2
|
||||
} UsbComplexId;
|
||||
|
||||
typedef enum {
|
||||
UsbDeviceSpeed_Full = 0x2,
|
||||
UsbDeviceSpeed_High = 0x3,
|
||||
UsbDeviceSpeed_Super = 0x4,
|
||||
} UsbDeviceSpeed;
|
||||
|
||||
/// Imported from libusb, with changed names.
|
||||
enum usb_class_code {
|
||||
USB_CLASS_PER_INTERFACE = 0,
|
||||
@ -153,38 +196,63 @@ enum usb_iso_usage_type {
|
||||
USB_ISO_USAGE_TYPE_IMPLICIT = 2,
|
||||
};
|
||||
|
||||
Result usbDsInitialize(UsbComplexId complexId, const UsbDsDeviceInfo* deviceinfo);
|
||||
|
||||
/// Exit usbDs. Any interfaces/endpoints which are left open are automatically closed, since otherwise usb-sysmodule won't fully reset usbds to defaults.
|
||||
/// Opens a session with usb:ds.
|
||||
Result usbDsInitialize(void);
|
||||
/// Closes the usb:ds session. Any interfaces/endpoints which are left open are automatically closed, since otherwise usb-sysmodule won't fully reset usb:ds to defaults.
|
||||
void usbDsExit(void);
|
||||
|
||||
Service* usbDsGetServiceSession(void);
|
||||
Handle usbDsGetStateChangeEvent(void);
|
||||
|
||||
Result usbDsGetState(u32 *out);
|
||||
Result usbDsGetDsInterface(UsbDsInterface** interface, struct usb_interface_descriptor* descriptor, const char *interface_name);
|
||||
|
||||
/// Wait for initialization to finish where data-transfer is usable.
|
||||
Result usbDsWaitReady(void);
|
||||
|
||||
/// Parse usbDsReportData from the Get*ReportData commands, where urbId is from the post-buffer commands. Will return the converted urb_status result-value.
|
||||
/// Helpers
|
||||
Result usbDsWaitReady(u64 timeout);
|
||||
Result usbDsParseReportData(UsbDsReportData *reportdata, u32 urbId, u32 *requestedSize, u32 *transferredSize);
|
||||
|
||||
/// IDsService
|
||||
// Do not provide API access to these functions, as they're handled by usbDsInitialize().
|
||||
// Result usbDsBindDevice(UsbComplexId complexId);
|
||||
// Result usbDsBindClientProcess(Handle prochandle);
|
||||
Event* usbDsGetStateChangeEvent(void);
|
||||
Result usbDsGetState(u32* out);
|
||||
|
||||
/// Removed in 5.0.0
|
||||
Result usbDsGetDsInterface(UsbDsInterface** out, struct usb_interface_descriptor* descriptor, const char* interface_name);
|
||||
Result usbDsSetVidPidBcd(const UsbDsDeviceInfo* deviceinfo);
|
||||
|
||||
/// Added in 5.0.0
|
||||
Result usbDsRegisterInterface(UsbDsInterface** out, u32 intf_num);
|
||||
Result usbDsClearDeviceData(void);
|
||||
Result usbDsAddUsbStringDescriptor(u8* out_index, const char* string);
|
||||
Result usbDsAddUsbLanguageStringDescriptor(u8* out_index, const u16* lang_ids, u16 num_langs);
|
||||
Result usbDsDeleteUsbStringDescriptor(u8 index);
|
||||
Result usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed speed, struct usb_device_descriptor* descriptor);
|
||||
Result usbDsSetBinaryObjectStore(void* bos, size_t bos_size);
|
||||
Result usbDsEnable(void);
|
||||
Result usbDsDisable(void);
|
||||
|
||||
/// IDsInterface
|
||||
void usbDsInterface_Close(UsbDsInterface* interface);
|
||||
Result usbDsInterface_GetDsEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, struct usb_endpoint_descriptor* descriptor);
|
||||
|
||||
Result usbDsInterface_GetSetupPacket(UsbDsInterface* interface, void* buffer, size_t size);
|
||||
Result usbDsInterface_EnableInterface(UsbDsInterface* interface);
|
||||
Result usbDsInterface_DisableInterface(UsbDsInterface* interface);
|
||||
Result usbDsInterface_CtrlInPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32 *urbId);
|
||||
Result usbDsInterface_CtrlOutPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32 *urbId);
|
||||
Result usbDsInterface_GetCtrlInReportData(UsbDsInterface* interface, UsbDsReportData *out);
|
||||
Result usbDsInterface_GetCtrlOutReportData(UsbDsInterface* interface, UsbDsReportData *out);
|
||||
Result usbDsInterface_CtrlInPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32* urbId);
|
||||
Result usbDsInterface_CtrlOutPostBufferAsync(UsbDsInterface* interface, void* buffer, size_t size, u32* urbId);
|
||||
Result usbDsInterface_GetCtrlInReportData(UsbDsInterface* interface, UsbDsReportData* out);
|
||||
Result usbDsInterface_GetCtrlOutReportData(UsbDsInterface* interface, UsbDsReportData* out);
|
||||
Result usbDsInterface_StallCtrl(UsbDsInterface* interface);
|
||||
|
||||
/// Removed in 5.0.0
|
||||
Result usbDsInterface_GetDsEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, struct usb_endpoint_descriptor* descriptor);
|
||||
|
||||
/// Added in 5.0.0
|
||||
Result usbDsInterface_RegisterEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, u8 endpoint_address);
|
||||
Result usbDsInterface_AppendConfigurationData(UsbDsInterface* interface, UsbDeviceSpeed speed, void* buffer, size_t size);
|
||||
|
||||
|
||||
/// IDsEndpoint
|
||||
|
||||
void usbDsEndpoint_Close(UsbDsEndpoint* endpoint);
|
||||
Result usbDsEndpoint_PostBufferAsync(UsbDsEndpoint* endpoint, void* buffer, size_t size, u32 *urbId);
|
||||
Result usbDsEndpoint_GetReportData(UsbDsEndpoint* endpoint, UsbDsReportData *out);
|
||||
Result usbDsEndpoint_StallCtrl(UsbDsEndpoint* endpoint);
|
||||
|
||||
Result usbDsEndpoint_Cancel(UsbDsEndpoint* endpoint);
|
||||
Result usbDsEndpoint_PostBufferAsync(UsbDsEndpoint* endpoint, void* buffer, size_t size, u32* urbId);
|
||||
Result usbDsEndpoint_GetReportData(UsbDsEndpoint* endpoint, UsbDsReportData* out);
|
||||
Result usbDsEndpoint_StallCtrl(UsbDsEndpoint* endpoint);
|
||||
Result usbDsEndpoint_SetZlt(UsbDsEndpoint* endpoint, bool zlt);
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <malloc.h>
|
||||
#include "types.h"
|
||||
#include "result.h"
|
||||
#include "kernel/detect.h"
|
||||
#include "kernel/rwlock.h"
|
||||
#include "services/fatal.h"
|
||||
#include "services/usb.h"
|
||||
@ -25,69 +26,127 @@ static usbCommsInterface g_usbCommsInterfaces[TOTAL_INTERFACES];
|
||||
|
||||
static RwLock g_usbCommsLock;
|
||||
|
||||
static Result _usbCommsInterfaceInit(usbCommsInterface *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol);
|
||||
static Result _usbCommsInterfaceInit1x(u32 intf_ind);
|
||||
static Result _usbCommsInterfaceInit5x(u32 intf_ind);
|
||||
static Result _usbCommsInterfaceInit(u32 intf_ind);
|
||||
|
||||
static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, size_t size, size_t *transferredSize);
|
||||
|
||||
Result usbCommsInitializeEx(u32 *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol)
|
||||
Result usbCommsInitializeEx(u32 num_interfaces)
|
||||
{
|
||||
bool found=0;
|
||||
usbCommsInterface *inter = NULL;
|
||||
|
||||
Result rc = 0;
|
||||
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 (g_usbCommsInitialized) {
|
||||
rc = MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
|
||||
} else if (num_interfaces > TOTAL_INTERFACES) {
|
||||
rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
||||
} else {
|
||||
rc = usbDsInitialize();
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
|
||||
if (kernelAbove500()) {
|
||||
u8 iManufacturer, iProduct, iSerialNumber;
|
||||
static const u16 supported_langs[1] = {0x0409};
|
||||
// Send language descriptor
|
||||
rc = usbDsAddUsbLanguageStringDescriptor(NULL, supported_langs, sizeof(supported_langs)/sizeof(u16));
|
||||
// Send manufacturer
|
||||
if (R_SUCCEEDED(rc)) rc = usbDsAddUsbStringDescriptor(&iManufacturer, "Switchbrew");
|
||||
// Send product
|
||||
if (R_SUCCEEDED(rc)) rc = usbDsAddUsbStringDescriptor(&iProduct, "libnx USB comms");
|
||||
// Send serial number
|
||||
if (R_SUCCEEDED(rc)) rc = usbDsAddUsbStringDescriptor(&iSerialNumber, "SerialNumber");
|
||||
|
||||
// Send device descriptors
|
||||
struct usb_device_descriptor device_descriptor = {
|
||||
.bLength = USB_DT_DEVICE_SIZE,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
.bcdUSB = 0x0110,
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
.bMaxPacketSize0 = 0x40,
|
||||
.idVendor = 0x057e,
|
||||
.idProduct = 0x3000,
|
||||
.bcdDevice = 0x0100,
|
||||
.iManufacturer = iManufacturer,
|
||||
.iProduct = iProduct,
|
||||
.iSerialNumber = iSerialNumber,
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
if (R_SUCCEEDED(rc)) rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Full, &device_descriptor);
|
||||
|
||||
// High Speed is USB 2.0
|
||||
device_descriptor.bcdUSB = 0x0200;
|
||||
if (R_SUCCEEDED(rc)) rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_High, &device_descriptor);
|
||||
|
||||
// Super Speed is USB 3.0
|
||||
device_descriptor.bcdUSB = 0x0300;
|
||||
// Upgrade packet size to 512
|
||||
device_descriptor.bMaxPacketSize0 = 0x09;
|
||||
if (R_SUCCEEDED(rc)) rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Super, &device_descriptor);
|
||||
|
||||
// Define Binary Object Store
|
||||
u8 bos[0x16] = {
|
||||
0x05, // .bLength
|
||||
USB_DT_BOS, // .bDescriptorType
|
||||
0x16, 0x00, // .wTotalLength
|
||||
0x02, // .bNumDeviceCaps
|
||||
|
||||
// USB 2.0
|
||||
0x07, // .bLength
|
||||
USB_DT_DEVICE_CAPABILITY, // .bDescriptorType
|
||||
0x02, // .bDevCapabilityType
|
||||
0x02, 0x00, 0x00, 0x00, // dev_capability_data
|
||||
|
||||
// USB 3.0
|
||||
0x0A, // .bLength
|
||||
USB_DT_DEVICE_CAPABILITY, // .bDescriptorType
|
||||
0x03, // .bDevCapabilityType
|
||||
0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00
|
||||
};
|
||||
if (R_SUCCEEDED(rc)) rc = usbDsSetBinaryObjectStore(bos, sizeof(bos));
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
for (u32 i = 0; i < num_interfaces; i++) {
|
||||
usbCommsInterface *intf = &g_usbCommsInterfaces[i];
|
||||
rwlockWriteLock(&intf->lock);
|
||||
rwlockWriteLock(&intf->lock_in);
|
||||
rwlockWriteLock(&intf->lock_out);
|
||||
rc = _usbCommsInterfaceInit(i);
|
||||
rwlockWriteUnlock(&intf->lock_out);
|
||||
rwlockWriteUnlock(&intf->lock_in);
|
||||
rwlockWriteUnlock(&intf->lock);
|
||||
if (R_FAILED(rc)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc) && kernelAbove500()) {
|
||||
rc = usbDsEnable();
|
||||
}
|
||||
|
||||
if (R_FAILED(rc)) {
|
||||
usbCommsExit();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (R_SUCCEEDED(rc)) g_usbCommsInitialized = true;
|
||||
|
||||
rwlockWriteUnlock(&g_usbCommsLock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbCommsInitialize(void)
|
||||
{
|
||||
return usbCommsInitializeEx(NULL, USB_CLASS_VENDOR_SPEC, USB_CLASS_VENDOR_SPEC, USB_CLASS_VENDOR_SPEC);
|
||||
return usbCommsInitializeEx(1);
|
||||
}
|
||||
|
||||
static void _usbCommsInterfaceExit(usbCommsInterface *interface)
|
||||
static void _usbCommsInterfaceFree(usbCommsInterface *interface)
|
||||
{
|
||||
rwlockWriteLock(&interface->lock);
|
||||
if (!interface->initialized) {
|
||||
@ -100,11 +159,6 @@ static void _usbCommsInterfaceExit(usbCommsInterface *interface)
|
||||
|
||||
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;
|
||||
@ -120,26 +174,6 @@ static void _usbCommsInterfaceExit(usbCommsInterface *interface)
|
||||
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)
|
||||
{
|
||||
u32 i;
|
||||
@ -154,27 +188,145 @@ void usbCommsExit(void)
|
||||
|
||||
for (i=0; i<TOTAL_INTERFACES; i++)
|
||||
{
|
||||
_usbCommsInterfaceExit(&g_usbCommsInterfaces[i]);
|
||||
_usbCommsInterfaceFree(&g_usbCommsInterfaces[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static Result _usbCommsInterfaceInit(usbCommsInterface *interface, u8 bInterfaceClass, u8 bInterfaceSubClass, u8 bInterfaceProtocol)
|
||||
static Result _usbCommsInterfaceInit(u32 intf_ind)
|
||||
{
|
||||
Result rc=0;
|
||||
if (kernelAbove500()) {
|
||||
return _usbCommsInterfaceInit5x(intf_ind);
|
||||
} else {
|
||||
return _usbCommsInterfaceInit1x(intf_ind);
|
||||
}
|
||||
}
|
||||
|
||||
static Result _usbCommsInterfaceInit5x(u32 intf_ind)
|
||||
{
|
||||
Result rc = 0;
|
||||
u32 ep_num = intf_ind + 1;
|
||||
usbCommsInterface *interface = &g_usbCommsInterfaces[intf_ind];
|
||||
|
||||
struct usb_interface_descriptor interface_descriptor = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = USBDS_DEFAULT_InterfaceNumber,
|
||||
.bInterfaceClass = bInterfaceClass,
|
||||
.bInterfaceSubClass = bInterfaceSubClass,
|
||||
.bInterfaceProtocol = bInterfaceProtocol,
|
||||
.bInterfaceNumber = intf_ind,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = 0xFF,
|
||||
.bInterfaceSubClass = 0xFF,
|
||||
.bInterfaceProtocol = 0xFF,
|
||||
};
|
||||
|
||||
struct usb_endpoint_descriptor endpoint_descriptor_in = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_ENDPOINT_IN,
|
||||
.bEndpointAddress = USB_ENDPOINT_IN + ep_num,
|
||||
.bmAttributes = USB_TRANSFER_TYPE_BULK,
|
||||
.wMaxPacketSize = 0x40,
|
||||
};
|
||||
|
||||
struct usb_endpoint_descriptor endpoint_descriptor_out = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_ENDPOINT_OUT + ep_num,
|
||||
.bmAttributes = USB_TRANSFER_TYPE_BULK,
|
||||
.wMaxPacketSize = 0x40,
|
||||
};
|
||||
|
||||
struct usb_ss_endpoint_companion_descriptor endpoint_companion = {
|
||||
.bLength = sizeof(struct usb_ss_endpoint_companion_descriptor),
|
||||
.bDescriptorType = USB_DT_SS_ENDPOINT_COMPANION,
|
||||
.bMaxBurst = 0x0F,
|
||||
.bmAttributes = 0x00,
|
||||
.wBytesPerInterval = 0x00,
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
rc = usbDsRegisterInterface(&interface->interface, interface_descriptor.bInterfaceNumber);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
// Full Speed Config
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Full, &interface_descriptor, USB_DT_INTERFACE_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Full, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Full, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
// High Speed Config
|
||||
endpoint_descriptor_in.wMaxPacketSize = 0x200;
|
||||
endpoint_descriptor_out.wMaxPacketSize = 0x200;
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_High, &interface_descriptor, USB_DT_INTERFACE_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_High, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_High, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
// Super Speed Config
|
||||
endpoint_descriptor_in.wMaxPacketSize = 0x400;
|
||||
endpoint_descriptor_out.wMaxPacketSize = 0x400;
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &interface_descriptor, USB_DT_INTERFACE_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_companion, USB_DT_SS_ENDPOINT_COMPANION_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
rc = usbDsInterface_AppendConfigurationData(interface->interface, UsbDeviceSpeed_Super, &endpoint_companion, USB_DT_SS_ENDPOINT_COMPANION_SIZE);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
//Setup endpoints.
|
||||
rc = usbDsInterface_RegisterEndpoint(interface->interface, &interface->endpoint_in, endpoint_descriptor_in.bEndpointAddress);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
rc = usbDsInterface_RegisterEndpoint(interface->interface, &interface->endpoint_out, endpoint_descriptor_out.bEndpointAddress);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
rc = usbDsInterface_EnableInterface(interface->interface);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static Result _usbCommsInterfaceInit1x(u32 intf_ind)
|
||||
{
|
||||
Result rc = 0;
|
||||
u32 ep_num = intf_ind + 1;
|
||||
usbCommsInterface *interface = &g_usbCommsInterfaces[intf_ind];
|
||||
|
||||
struct usb_interface_descriptor interface_descriptor = {
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = intf_ind,
|
||||
.bInterfaceClass = 0xFF,
|
||||
.bInterfaceSubClass = 0xFF,
|
||||
.bInterfaceProtocol = 0xFF,
|
||||
};
|
||||
|
||||
struct usb_endpoint_descriptor endpoint_descriptor_in = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_ENDPOINT_IN + ep_num,
|
||||
.bmAttributes = USB_TRANSFER_TYPE_BULK,
|
||||
.wMaxPacketSize = 0x200,
|
||||
};
|
||||
@ -182,7 +334,7 @@ static Result _usbCommsInterfaceInit(usbCommsInterface *interface, u8 bInterface
|
||||
struct usb_endpoint_descriptor endpoint_descriptor_out = {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = USB_ENDPOINT_OUT,
|
||||
.bEndpointAddress = USB_ENDPOINT_OUT + ep_num,
|
||||
.bmAttributes = USB_TRANSFER_TYPE_BULK,
|
||||
.wMaxPacketSize = 0x200,
|
||||
};
|
||||
@ -235,7 +387,7 @@ static Result _usbCommsRead(usbCommsInterface *interface, void* buffer, size_t s
|
||||
UsbDsReportData reportdata;
|
||||
|
||||
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
|
||||
rc = usbDsWaitReady();
|
||||
rc = usbDsWaitReady(U64_MAX);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
while(size)
|
||||
@ -264,8 +416,8 @@ static Result _usbCommsRead(usbCommsInterface *interface, void* buffer, size_t s
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
//Wait for the transfer to finish.
|
||||
svcWaitSynchronizationSingle(interface->endpoint_out->CompletionEvent, U64_MAX);
|
||||
svcClearEvent(interface->endpoint_out->CompletionEvent);
|
||||
eventWait(&interface->endpoint_out->CompletionEvent, U64_MAX);
|
||||
eventClear(&interface->endpoint_out->CompletionEvent);
|
||||
|
||||
rc = usbDsEndpoint_GetReportData(interface->endpoint_out, &reportdata);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
@ -300,7 +452,7 @@ static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, s
|
||||
UsbDsReportData reportdata;
|
||||
|
||||
//Makes sure endpoints are ready for data-transfer / wait for init if needed.
|
||||
rc = usbDsWaitReady();
|
||||
rc = usbDsWaitReady(U64_MAX);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
while(size)
|
||||
@ -327,8 +479,8 @@ static Result _usbCommsWrite(usbCommsInterface *interface, const void* buffer, s
|
||||
if(R_FAILED(rc))return rc;
|
||||
|
||||
//Wait for the transfer to finish.
|
||||
svcWaitSynchronizationSingle(interface->endpoint_in->CompletionEvent, U64_MAX);
|
||||
svcClearEvent(interface->endpoint_in->CompletionEvent);
|
||||
eventWait(&interface->endpoint_in->CompletionEvent, U64_MAX);
|
||||
eventClear(&interface->endpoint_in->CompletionEvent);
|
||||
|
||||
rc = usbDsEndpoint_GetReportData(interface->endpoint_in, &reportdata);
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
@ -6,26 +6,26 @@
|
||||
#include "kernel/detect.h"
|
||||
#include "services/usb.h"
|
||||
#include "services/sm.h"
|
||||
#include "runtime/util/utf.h"
|
||||
|
||||
#define TOTAL_INTERFACES 4
|
||||
#define TOTAL_ENDPOINTS 15*2
|
||||
#define TOTAL_ENDPOINTS_IN 16
|
||||
#define TOTAL_ENDPOINTS_OUT 16
|
||||
#define TOTAL_ENDPOINTS (TOTAL_ENDPOINTS_IN+TOTAL_ENDPOINTS_OUT)
|
||||
|
||||
static Service g_usbDsSrv;
|
||||
static Handle g_usbDsStateChangeEvent = INVALID_HANDLE;
|
||||
static Event g_usbDsStateChangeEvent = {0};
|
||||
|
||||
static UsbDsInterface g_usbDsInterfaceTable[TOTAL_INTERFACES];
|
||||
static UsbDsEndpoint g_usbDsEndpointTable[TOTAL_INTERFACES*TOTAL_ENDPOINTS];
|
||||
static UsbDsEndpoint g_usbDsEndpointTable[TOTAL_INTERFACES][TOTAL_ENDPOINTS];
|
||||
|
||||
static void _usbDsFreeTables(void);
|
||||
|
||||
static Result _usbDsBindDevice(UsbComplexId complexId);
|
||||
static Result _usbDsBindClientProcess(Handle prochandle);
|
||||
static Result _usbDsGetEvent(Service* srv, Handle* handle_out, u64 cmd_id);
|
||||
static Result _usbDsSetVidPidBcd(const UsbDsDeviceInfo* deviceinfo);
|
||||
static Result _usbDsGetEvent(Service* srv, Event* event_out, u64 cmd_id);
|
||||
|
||||
static Result _usbDsGetSession(Service* srv, Service* srv_out, u64 cmd_id, const void* buf0, size_t buf0size, const void* buf1, size_t buf1size);
|
||||
|
||||
Result usbDsInitialize(UsbComplexId complexId, const UsbDsDeviceInfo* deviceinfo)
|
||||
Result usbDsInitialize(void)
|
||||
{
|
||||
if (serviceIsActive(&g_usbDsSrv))
|
||||
return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized);
|
||||
@ -35,24 +35,21 @@ Result usbDsInitialize(UsbComplexId complexId, const UsbDsDeviceInfo* deviceinfo
|
||||
rc = smGetService(&g_usbDsSrv, "usb:ds");
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _usbDsBindDevice(complexId);
|
||||
rc = _usbDsBindDevice(UsbComplexId_Default);
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _usbDsBindClientProcess(CUR_PROCESS_HANDLE);
|
||||
|
||||
// GetStateChangeEvent
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _usbDsGetEvent(&g_usbDsSrv, &g_usbDsStateChangeEvent, 3);
|
||||
|
||||
if (R_SUCCEEDED(rc) && deviceinfo && kernelAbove200()) {
|
||||
rc = _usbDsSetVidPidBcd(deviceinfo);
|
||||
}
|
||||
|
||||
// Result code doesn't matter here, users can call themselves later, too. This prevents foot shooting.
|
||||
if (R_SUCCEEDED(rc))
|
||||
usbDsClearDeviceData();
|
||||
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
if(g_usbDsStateChangeEvent) {
|
||||
svcCloseHandle(g_usbDsStateChangeEvent);
|
||||
g_usbDsStateChangeEvent = INVALID_HANDLE;
|
||||
}
|
||||
eventClose(&g_usbDsStateChangeEvent);
|
||||
|
||||
serviceClose(&g_usbDsSrv);
|
||||
}
|
||||
@ -64,24 +61,31 @@ void usbDsExit(void)
|
||||
{
|
||||
if (!serviceIsActive(&g_usbDsSrv))
|
||||
return;
|
||||
|
||||
if (kernelAbove500()) {
|
||||
usbDsDisable();
|
||||
}
|
||||
|
||||
_usbDsFreeTables();
|
||||
|
||||
if (g_usbDsStateChangeEvent) {
|
||||
svcCloseHandle(g_usbDsStateChangeEvent);
|
||||
g_usbDsStateChangeEvent = 0;
|
||||
}
|
||||
eventClose(&g_usbDsStateChangeEvent);
|
||||
|
||||
serviceClose(&g_usbDsSrv);
|
||||
}
|
||||
|
||||
Service* usbDsGetServiceSession(void) {
|
||||
return &g_usbDsSrv;
|
||||
Event* usbDsGetStateChangeEvent(void)
|
||||
{
|
||||
return &g_usbDsStateChangeEvent;
|
||||
}
|
||||
|
||||
Handle usbDsGetStateChangeEvent(void)
|
||||
{
|
||||
return g_usbDsStateChangeEvent;
|
||||
static UsbDsInterface* _usbDsTryAllocateInterface(u32 num) {
|
||||
if (num >= TOTAL_INTERFACES) return NULL;
|
||||
UsbDsInterface* ptr = &g_usbDsInterfaceTable[num];
|
||||
if (ptr->initialized) return NULL;
|
||||
memset(ptr, 0, sizeof(UsbDsInterface));
|
||||
ptr->initialized = true;
|
||||
ptr->interface_index = num;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static UsbDsInterface* _usbDsAllocateInterface(void)
|
||||
@ -111,7 +115,7 @@ static UsbDsEndpoint* _usbDsAllocateEndpoint(UsbDsInterface* interface)
|
||||
|
||||
for(pos=0; pos<TOTAL_ENDPOINTS; pos++)
|
||||
{
|
||||
ptr = &g_usbDsEndpointTable[(interface->interface_index*TOTAL_ENDPOINTS) + pos];
|
||||
ptr = &g_usbDsEndpointTable[interface->interface_index][pos];
|
||||
if(ptr->initialized)continue;
|
||||
memset(ptr, 0, sizeof(UsbDsEndpoint));
|
||||
ptr->initialized = true;
|
||||
@ -121,53 +125,47 @@ static UsbDsEndpoint* _usbDsAllocateEndpoint(UsbDsInterface* interface)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _usbDsFreeInterface(UsbDsInterface* interface)
|
||||
{
|
||||
if (!interface->initialized)
|
||||
return;
|
||||
|
||||
if (interface->CtrlOutCompletionEvent) {
|
||||
svcCloseHandle(interface->CtrlOutCompletionEvent);
|
||||
interface->CtrlOutCompletionEvent = 0;
|
||||
}
|
||||
|
||||
if (interface->CtrlInCompletionEvent) {
|
||||
svcCloseHandle(interface->CtrlInCompletionEvent);
|
||||
interface->CtrlInCompletionEvent = 0;
|
||||
}
|
||||
|
||||
if (interface->SetupEvent) {
|
||||
svcCloseHandle(interface->SetupEvent);
|
||||
interface->SetupEvent = 0;
|
||||
}
|
||||
|
||||
serviceClose(&interface->h);
|
||||
|
||||
interface->initialized = false;
|
||||
}
|
||||
|
||||
static void _usbDsFreeEndpoint(UsbDsEndpoint* endpoint)
|
||||
{
|
||||
if (!endpoint->initialized)
|
||||
return;
|
||||
|
||||
/* Cancel any ongoing transactions. */
|
||||
usbDsEndpoint_Cancel(endpoint);
|
||||
|
||||
if (endpoint->CompletionEvent) {
|
||||
svcCloseHandle(endpoint->CompletionEvent);
|
||||
endpoint->CompletionEvent = 0;
|
||||
}
|
||||
eventClose(&endpoint->CompletionEvent);
|
||||
|
||||
serviceClose(&endpoint->h);
|
||||
|
||||
endpoint->initialized = false;
|
||||
}
|
||||
|
||||
static void _usbDsFreeInterface(UsbDsInterface* interface)
|
||||
{
|
||||
if (!interface->initialized)
|
||||
return;
|
||||
|
||||
/* Disable interface. */
|
||||
usbDsInterface_DisableInterface(interface);
|
||||
|
||||
/* Close endpoints. */
|
||||
for (u32 ep = 0; ep < TOTAL_ENDPOINTS; ep++) {
|
||||
_usbDsFreeEndpoint(&g_usbDsEndpointTable[interface->interface_index][ep]);
|
||||
}
|
||||
|
||||
eventClose(&interface->CtrlOutCompletionEvent);
|
||||
eventClose(&interface->CtrlInCompletionEvent);
|
||||
eventClose(&interface->SetupEvent);
|
||||
|
||||
serviceClose(&interface->h);
|
||||
|
||||
interface->initialized = false;
|
||||
}
|
||||
|
||||
static void _usbDsFreeTables(void)
|
||||
{
|
||||
u32 pos, pos2;
|
||||
for(pos=0; pos<TOTAL_INTERFACES; pos++)
|
||||
{
|
||||
for(pos2=0; pos2<TOTAL_ENDPOINTS; pos2++)_usbDsFreeEndpoint(&g_usbDsEndpointTable[(pos*TOTAL_ENDPOINTS) + pos2]);
|
||||
_usbDsFreeInterface(&g_usbDsInterfaceTable[pos]);
|
||||
for (u32 intf = 0; intf < TOTAL_INTERFACES; intf++) {
|
||||
_usbDsFreeInterface(&g_usbDsInterfaceTable[intf]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,7 +235,7 @@ static Result _usbDsBindClientProcess(Handle prochandle) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _usbDsGetEvent(Service* srv, Handle* handle_out, u64 cmd_id) {
|
||||
static Result _usbDsGetEvent(Service* srv, Event* event_out, u64 cmd_id) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
@ -265,7 +263,7 @@ static Result _usbDsGetEvent(Service* srv, Handle* handle_out, u64 cmd_id) {
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
*handle_out = r.Handles[0];
|
||||
eventLoadRemote(event_out, r.Handles[0], false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +303,7 @@ Result usbDsGetState(u32 *out) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbDsWaitReady(void) {
|
||||
Result usbDsWaitReady(u64 timeout) {
|
||||
Result rc;
|
||||
u32 state = 0;
|
||||
|
||||
@ -314,8 +312,8 @@ Result usbDsWaitReady(void) {
|
||||
|
||||
while (R_SUCCEEDED(rc) && state != 5)
|
||||
{
|
||||
svcWaitSynchronizationSingle(g_usbDsStateChangeEvent, U64_MAX);
|
||||
svcClearEvent(g_usbDsStateChangeEvent);
|
||||
eventWait(&g_usbDsStateChangeEvent, timeout);
|
||||
eventClear(&g_usbDsStateChangeEvent);
|
||||
rc = usbDsGetState(&state);
|
||||
}
|
||||
|
||||
@ -362,7 +360,7 @@ Result usbDsParseReportData(UsbDsReportData *reportdata, u32 urbId, u32 *request
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _usbDsSetVidPidBcd(const UsbDsDeviceInfo* deviceinfo) {
|
||||
Result usbDsSetVidPidBcd(const UsbDsDeviceInfo* deviceinfo) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
@ -569,6 +567,248 @@ Result usbDsGetDsInterface(UsbDsInterface** interface, struct usb_interface_desc
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbDsRegisterInterface(UsbDsInterface** interface, u32 intf_num)
|
||||
{
|
||||
UsbDsInterface* ptr = _usbDsTryAllocateInterface(intf_num);
|
||||
if(ptr == NULL)
|
||||
return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 intf_num;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
raw->intf_num = intf_num;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_usbDsSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreate(&ptr->h, r.Handles[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// GetSetupEvent
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _usbDsGetEvent(&ptr->h, &ptr->SetupEvent, 1);
|
||||
// GetCtrlInCompletionEvent
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _usbDsGetEvent(&ptr->h, &ptr->CtrlInCompletionEvent, 7);
|
||||
// GetCtrlOutCompletionEvent
|
||||
if (R_SUCCEEDED(rc))
|
||||
rc = _usbDsGetEvent(&ptr->h, &ptr->CtrlOutCompletionEvent, 9);
|
||||
|
||||
if (R_FAILED(rc))
|
||||
_usbDsFreeInterface(ptr);
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
*interface = ptr;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbDsClearDeviceData(void) {
|
||||
return _usbDsCmdNoParams(&g_usbDsSrv, 5);
|
||||
}
|
||||
|
||||
static Result _usbDsAddUsbStringDescriptorRaw(u8 *out_index, struct usb_string_descriptor *descriptor) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendBuffer(&c, descriptor, sizeof(*descriptor), 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 6;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_usbDsSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
u8 index;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
if (R_SUCCEEDED(rc) && out_index) {
|
||||
*out_index = resp->index;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbDsAddUsbStringDescriptor(u8* out_index, const char* string) {
|
||||
struct usb_string_descriptor descriptor = {
|
||||
.bDescriptorType = USB_DT_STRING,
|
||||
.wData = {0},
|
||||
};
|
||||
|
||||
// Convert
|
||||
u32 len = (u32)utf8_to_utf16(descriptor.wData, (const uint8_t *)string, sizeof(descriptor.wData)/sizeof(u16) - 1);
|
||||
if (len > sizeof(descriptor.wData)/sizeof(u16)) len = sizeof(descriptor.wData)/sizeof(u16);
|
||||
|
||||
// Set length
|
||||
descriptor.bLength = 2 + 2 * len;
|
||||
|
||||
return _usbDsAddUsbStringDescriptorRaw(out_index, &descriptor);
|
||||
}
|
||||
|
||||
Result usbDsAddUsbLanguageStringDescriptor(u8* out_index, const u16* lang_ids, u16 num_langs) {
|
||||
if (num_langs > 0x40) num_langs = 0x40;
|
||||
|
||||
struct usb_string_descriptor descriptor = {
|
||||
.bLength = 2 + 2 * num_langs,
|
||||
.bDescriptorType = USB_DT_STRING,
|
||||
.wData = {0},
|
||||
};
|
||||
|
||||
for (u32 i = 0; i < num_langs; i++) {
|
||||
descriptor.wData[i] = lang_ids[i];
|
||||
}
|
||||
|
||||
return _usbDsAddUsbStringDescriptorRaw(out_index, &descriptor);
|
||||
}
|
||||
|
||||
Result usbDsDeleteUsbStringDescriptor(u8 index) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 index;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 7;
|
||||
raw->index = index;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_usbDsSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
Result usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed speed, struct usb_device_descriptor* descriptor) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendBuffer(&c, descriptor, USB_DT_DEVICE_SIZE, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 speed;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 8;
|
||||
raw->speed = speed;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_usbDsSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbDsSetBinaryObjectStore(void* bos, size_t bos_size) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendBuffer(&c, bos, bos_size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 9;
|
||||
|
||||
Result rc = serviceIpcDispatch(&g_usbDsSrv);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbDsEnable(void) {
|
||||
return _usbDsCmdNoParams(&g_usbDsSrv, 10);
|
||||
}
|
||||
|
||||
Result usbDsDisable(void) {
|
||||
return _usbDsCmdNoParams(&g_usbDsSrv, 11);
|
||||
}
|
||||
|
||||
|
||||
//IDsInterface
|
||||
|
||||
void usbDsInterface_Close(UsbDsInterface* interface)
|
||||
@ -576,6 +816,41 @@ void usbDsInterface_Close(UsbDsInterface* interface)
|
||||
_usbDsFreeInterface(interface);
|
||||
}
|
||||
|
||||
Result usbDsInterface_GetSetupPacket(UsbDsInterface* interface, void* buffer, size_t size) {
|
||||
if(!interface->initialized)return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddRecvBuffer(&c, buffer, size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 2;
|
||||
|
||||
Result rc = serviceIpcDispatch(&interface->h);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbDsInterface_GetDsEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, struct usb_endpoint_descriptor* descriptor)
|
||||
{
|
||||
if(!interface->initialized)return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
@ -583,7 +858,7 @@ Result usbDsInterface_GetDsEndpoint(UsbDsInterface* interface, UsbDsEndpoint** e
|
||||
UsbDsEndpoint* ptr = _usbDsAllocateEndpoint(interface);
|
||||
if(ptr==NULL)return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
||||
|
||||
Result rc = _usbDsGetSession(&interface->h, &ptr->h, 0, descriptor, sizeof(struct usb_endpoint_descriptor), NULL, 0);
|
||||
Result rc = _usbDsGetSession(&interface->h, &ptr->h, 0, descriptor, USB_DT_ENDPOINT_SIZE, NULL, 0);
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _usbDsGetEvent(&ptr->h, &ptr->CompletionEvent, 2);//GetCompletionEvent
|
||||
|
||||
@ -642,6 +917,93 @@ Result usbDsInterface_StallCtrl(UsbDsInterface* interface)
|
||||
return _usbDsCmdNoParams(&interface->h, 11);
|
||||
}
|
||||
|
||||
Result usbDsInterface_RegisterEndpoint(UsbDsInterface* interface, UsbDsEndpoint** endpoint, u8 endpoint_address)
|
||||
{
|
||||
if(!interface->initialized)return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
UsbDsEndpoint* ptr = _usbDsAllocateEndpoint(interface);
|
||||
if(ptr==NULL)return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 ep_addr;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->ep_addr = endpoint_address;
|
||||
|
||||
Result rc = serviceIpcDispatch(&interface->h);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
serviceCreate(&ptr->h, r.Handles[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc)) rc = _usbDsGetEvent(&ptr->h, &ptr->CompletionEvent, 2);//GetCompletionEvent
|
||||
|
||||
if (R_FAILED(rc)) _usbDsFreeEndpoint(ptr);
|
||||
|
||||
if (R_SUCCEEDED(rc)) *endpoint = ptr;
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result usbDsInterface_AppendConfigurationData(UsbDsInterface* interface, UsbDeviceSpeed speed, void* buffer, size_t size) {
|
||||
if(!interface->initialized)return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
ipcAddSendBuffer(&c, buffer, size, 0);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 intf_num;
|
||||
u32 speed;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 12;
|
||||
raw->intf_num = interface->interface_index;
|
||||
raw->speed = speed;
|
||||
|
||||
Result rc = serviceIpcDispatch(&interface->h);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
//IDsEndpoint
|
||||
|
||||
void usbDsEndpoint_Close(UsbDsEndpoint* endpoint)
|
||||
@ -656,6 +1018,13 @@ Result usbDsEndpoint_PostBufferAsync(UsbDsEndpoint* endpoint, void* buffer, size
|
||||
return _usbDsPostBuffer(&endpoint->h, 0, buffer, size, urbId);
|
||||
}
|
||||
|
||||
Result usbDsEndpoint_Cancel(UsbDsEndpoint* endpoint)
|
||||
{
|
||||
if(!endpoint->initialized)return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
return _usbDsCmdNoParams(&endpoint->h, 1);
|
||||
}
|
||||
|
||||
Result usbDsEndpoint_GetReportData(UsbDsEndpoint* endpoint, UsbDsReportData *out)
|
||||
{
|
||||
if(!endpoint->initialized)return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
@ -670,3 +1039,39 @@ Result usbDsEndpoint_StallCtrl(UsbDsEndpoint* endpoint)
|
||||
return _usbDsCmdNoParams(&endpoint->h, 4);
|
||||
}
|
||||
|
||||
Result usbDsEndpoint_SetZlt(UsbDsEndpoint* endpoint, bool zlt)
|
||||
{
|
||||
if(!endpoint->initialized)return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u32 zlt;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 12;
|
||||
raw->zlt = zlt ? 1 : 0;
|
||||
|
||||
Result rc = serviceIpcDispatch(&endpoint->h);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user