mirror of
https://github.com/Wack0/entii-for-workcubes.git
synced 2025-12-23 21:05:07 -05:00
1346 lines
44 KiB
C
1346 lines
44 KiB
C
// USB_VEN low level.
|
|
#define DEVL 1
|
|
#include <ntddk.h>
|
|
#include "usblow.h"
|
|
#include "iosusblow.h"
|
|
#include "iosapi.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#define ALIGN_TO_ULONG(val) (((ULONG)((val)) + 3) & ~3)
|
|
|
|
static IOS_HANDLE s_hUsbVen = IOS_HANDLE_INVALID;
|
|
static IOS_HANDLE s_hUsbHid = IOS_HANDLE_INVALID;
|
|
|
|
static const char sc_UsbVen[] ARC_ALIGNED(32) = STRING_BYTESWAP("/dev/usb/ven");
|
|
static const char sc_UsbHid[] ARC_ALIGNED(32) = STRING_BYTESWAP("/dev/usb/hid");
|
|
|
|
static PIOS_USB_DEVICE_CHANGE s_AttachedDevicesVen = NULL;
|
|
static PIOS_USB_DEVICE_CHANGE s_AttachedDevicesHid = NULL;
|
|
static volatile BOOLEAN s_KnownDevicesVen = FALSE;
|
|
static volatile BOOLEAN s_KnownDevicesHid = FALSE;
|
|
//static HANDLE s_DeviceChangeThread = NULL;
|
|
|
|
typedef struct _USB_OPENED_DEVICE {
|
|
IOS_USB_HANDLE DeviceHandle;
|
|
ULONG RefCount;
|
|
} USB_OPENED_DEVICE, *PUSB_OPENED_DEVICE;
|
|
static USB_OPENED_DEVICE s_OpenedDevices[USB_COUNT_DEVICES] = {0};
|
|
|
|
static void UlpAsyncInit(PIOS_USB_ASYNC_RESULT Async, PVOID Buffer) {
|
|
KeInitializeEvent(&Async->Event, NotificationEvent, FALSE);
|
|
Async->Status = STATUS_PENDING;
|
|
Async->Buffer = Buffer;
|
|
}
|
|
|
|
typedef enum {
|
|
VARIANT_VEN = 1,
|
|
VARIANT_HID = 2
|
|
} USB_INTERNAL_ASYNC_VARIANT;
|
|
|
|
#if 0
|
|
typedef enum {
|
|
THREAD_STATE_DEVICE_CHANGE,
|
|
THREAD_STATE_ATTACH_FINISH
|
|
} DEVICE_CHANGE_THREAD_STATE;
|
|
|
|
static NTSTATUS UlpDeviceChangeIoctl(
|
|
IOS_HANDLE Handle,
|
|
DEVICE_CHANGE_THREAD_STATE State,
|
|
PIOS_USB_DEVICE_CHANGE Attached,
|
|
PIOS_USB_ASYNC_RESULT Async
|
|
) {
|
|
if (State == THREAD_STATE_DEVICE_CHANGE)
|
|
return HalIopIoctlAsync(
|
|
Handle,
|
|
USB_IOCTL_DEVICE_CHANGE,
|
|
NULL, 0,
|
|
Attached, sizeof(*Attached),
|
|
&Async->Status, &Async->Event
|
|
);
|
|
else if (State == THREAD_STATE_ATTACH_FINISH)
|
|
return HalIopIoctlAsync(
|
|
Handle,
|
|
USB_IOCTL_ATTACH_FINISH,
|
|
NULL, 0, NULL, 0,
|
|
&Async->Status, &Async->Event
|
|
);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
static DEVICE_CHANGE_THREAD_STATE UlpDeviceChangeState(DEVICE_CHANGE_THREAD_STATE State) {
|
|
if (State == THREAD_STATE_DEVICE_CHANGE) return THREAD_STATE_ATTACH_FINISH;
|
|
return THREAD_STATE_DEVICE_CHANGE;
|
|
}
|
|
#endif
|
|
|
|
static void UlpDeviceChangeCallback(NTSTATUS Status, ULONG Result, PVOID Context);
|
|
|
|
static void UlpAttachFinishCallback(NTSTATUS Status, ULONG Result, PVOID Context) {
|
|
USB_INTERNAL_ASYNC_VARIANT Variant = (USB_INTERNAL_ASYNC_VARIANT)Context;
|
|
|
|
if (!NT_SUCCESS(Status)) return;
|
|
|
|
PIOS_USB_DEVICE_CHANGE Devices = NULL;
|
|
IOS_HANDLE Handle;
|
|
if (Variant == VARIANT_VEN) {
|
|
Devices = s_AttachedDevicesVen;
|
|
Handle = s_hUsbVen;
|
|
} else if (Variant == VARIANT_HID) {
|
|
Devices = s_AttachedDevicesHid;
|
|
Handle = s_hUsbHid;
|
|
}
|
|
else return; // wtf?
|
|
|
|
// Call DeviceChange.
|
|
HalIopIoctlAsyncDpc(
|
|
Handle,
|
|
USB_IOCTL_DEVICE_CHANGE,
|
|
NULL, 0,
|
|
Devices, sizeof(*Devices),
|
|
IOCTL_SWAP_NONE, IOCTL_SWAP_NONE,
|
|
UlpAttachFinishCallback,
|
|
Context
|
|
);
|
|
}
|
|
|
|
static void UlpDeviceChangeCallback(NTSTATUS Status, ULONG Result, PVOID Context) {
|
|
USB_INTERNAL_ASYNC_VARIANT Variant = (USB_INTERNAL_ASYNC_VARIANT)Context;
|
|
|
|
if (!NT_SUCCESS(Status)) return;
|
|
|
|
PIOS_USB_DEVICE_CHANGE Devices = NULL;
|
|
IOS_HANDLE Handle;
|
|
//CHAR Buffer[512];
|
|
BOOLEAN KnownDevices;
|
|
if (Variant == VARIANT_VEN) {
|
|
Devices = s_AttachedDevicesVen;
|
|
Handle = s_hUsbVen;
|
|
KnownDevices = s_KnownDevicesVen;
|
|
#if 0 // do we actually need this?
|
|
if (!s_KnownDevicesVen) {
|
|
//_snprintf(Buffer, sizeof(Buffer), "USBVEN: Number of attached devices: %d\n", Result);
|
|
//HalDisplayString(Buffer);
|
|
KeStallExecutionProcessor(100);
|
|
}
|
|
#endif
|
|
} else if (Variant == VARIANT_HID) {
|
|
Devices = s_AttachedDevicesHid;
|
|
Handle = s_hUsbHid;
|
|
KnownDevices = s_KnownDevicesHid;
|
|
#if 0 // do we actually need this?
|
|
if (!s_KnownDevicesHid) {
|
|
//_snprintf(Buffer, sizeof(Buffer), "USBVEN: Number of attached devices: %d\n", Result);
|
|
//HalDisplayString(Buffer);
|
|
KeStallExecutionProcessor(100);
|
|
}
|
|
#endif
|
|
}
|
|
else return; // wtf?
|
|
|
|
// when ARC doesn't restart IOS, first DeviceChange call will always give a response of zero devices, even though old device handles are still valid
|
|
//if (Result != 0 || KnownDevices)
|
|
{
|
|
// Zero out unused entries.
|
|
// Do this using NativeWriteBase32 because endianness reasons.
|
|
ULONG Length = sizeof(Devices->Entries[0]) * (USB_COUNT_DEVICES - Result);
|
|
Length /= sizeof(ULONG);
|
|
for (ULONG i = 0; i < Length; i++) {
|
|
NativeWriteBase32(Devices, __builtin_offsetof(IOS_USB_DEVICE_CHANGE, Entries[Result]) + (i * sizeof(ULONG)), 0);
|
|
}
|
|
}
|
|
|
|
if (Variant == VARIANT_VEN) s_KnownDevicesVen = TRUE;
|
|
if (Variant == VARIANT_HID) s_KnownDevicesHid = TRUE;
|
|
|
|
// Call AttachFinish.
|
|
HalIopIoctlAsyncDpc(
|
|
Handle,
|
|
USB_IOCTL_ATTACH_FINISH,
|
|
NULL, 0, NULL, 0,
|
|
IOCTL_SWAP_NONE, IOCTL_SWAP_NONE,
|
|
UlpAttachFinishCallback,
|
|
Context
|
|
);
|
|
}
|
|
|
|
#if 0
|
|
static void UlpDeviceChangeThread(PVOID Context) {
|
|
(void)Context;
|
|
|
|
IOS_USB_ASYNC_RESULT AsyncVen, AsyncHid;
|
|
UlpAsyncInit(&AsyncVen, NULL);
|
|
UlpAsyncInit(&AsyncHid, NULL);
|
|
BOOLEAN Continue = FALSE;
|
|
NTSTATUS StatusVen = STATUS_SUCCESS;
|
|
NTSTATUS StatusHid = STATUS_SUCCESS;
|
|
|
|
PVOID Objects[] = { &AsyncVen.Event, &AsyncHid.Event };
|
|
BOOLEAN IoctlVen = TRUE, IoctlHid = TRUE;
|
|
DEVICE_CHANGE_THREAD_STATE
|
|
StateVen = THREAD_STATE_DEVICE_CHANGE,
|
|
StateHid = THREAD_STATE_DEVICE_CHANGE;
|
|
|
|
do {
|
|
Continue = FALSE;
|
|
if (
|
|
NT_SUCCESS(StatusVen) &&
|
|
s_AttachedDevicesVen == NULL &&
|
|
s_hUsbVen != IOS_HANDLE_INVALID &&
|
|
IoctlVen
|
|
) {
|
|
Continue = TRUE;
|
|
IoctlVen = FALSE;
|
|
StatusVen = UlpDeviceChangeIoctl(
|
|
s_hUsbVen,
|
|
StateVen,
|
|
s_AttachedDevicesVen,
|
|
&AsyncVen
|
|
);
|
|
}
|
|
if (
|
|
NT_SUCCESS(StatusHid) &&
|
|
s_AttachedDevicesHid &&
|
|
s_hUsbHid != IOS_HANDLE_INVALID &&
|
|
IoctlHid
|
|
) {
|
|
Continue = TRUE;
|
|
IoctlHid = FALSE;
|
|
StatusVen = UlpDeviceChangeIoctl(
|
|
s_hUsbHid,
|
|
StateHid,
|
|
s_AttachedDevicesHid,
|
|
&AsyncHid
|
|
);
|
|
}
|
|
|
|
// If no ioctls were sent, then exit the thread.
|
|
if (!Continue) break;
|
|
|
|
// If either IoctlAsync call failed, that event won't ever be set.
|
|
// Therefore it is safe to do this.
|
|
|
|
NTSTATUS Status = KeWaitForMultipleObjects(
|
|
2, Objects, WaitAny, Executive, KernelMode, FALSE,
|
|
NULL, NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) break;
|
|
if (Status == STATUS_WAIT_0) {
|
|
IoctlVen = TRUE;
|
|
StatusVen = AsyncVen.Status;
|
|
if (StateVen == THREAD_STATE_DEVICE_CHANGE && NT_SUCCESS(StatusVen)) {
|
|
KeSetEvent(&s_DevicesKnownVen, 0, FALSE);
|
|
}
|
|
StateVen = UlpDeviceChangeState(StateVen);
|
|
UlpAsyncInit(&AsyncVen, NULL);
|
|
continue;
|
|
}
|
|
if (Status == STATUS_WAIT_1) {
|
|
IoctlHid = TRUE;
|
|
StatusHid = AsyncHid.Status;
|
|
if (StateHid == THREAD_STATE_DEVICE_CHANGE && NT_SUCCESS(StatusHid)) {
|
|
KeSetEvent(&s_DevicesKnownHid, 0, FALSE);
|
|
}
|
|
StateHid = UlpDeviceChangeState(StateHid);
|
|
UlpAsyncInit(&AsyncHid, NULL);
|
|
continue;
|
|
}
|
|
// ???
|
|
break;
|
|
} while (TRUE);
|
|
|
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|
}
|
|
#endif
|
|
|
|
static PIOS_USB_DEVICE_ENTRY UlpFindDevice(
|
|
PIOS_USB_DEVICE_CHANGE Host,
|
|
IOS_USB_HANDLE DeviceHandle
|
|
) {
|
|
if (Host == NULL) return NULL;
|
|
|
|
for (ULONG i = 0; i < USB_COUNT_DEVICES; i++) {
|
|
IOS_USB_HANDLE Self = NativeReadBase32(MMIO_OFFSET(Host, Entries[i].DeviceHandle));
|
|
if (Self == 0) break;
|
|
if (Self == DeviceHandle) return &Host->Entries[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static PIOS_USB_DEVICE_ENTRY UlpFindDeviceVen(IOS_USB_HANDLE DeviceHandle) {
|
|
return UlpFindDevice(s_AttachedDevicesVen, DeviceHandle);
|
|
}
|
|
|
|
static PIOS_USB_DEVICE_ENTRY UlpFindDeviceHid(IOS_USB_HANDLE DeviceHandle) {
|
|
return UlpFindDevice(s_AttachedDevicesHid, DeviceHandle);
|
|
}
|
|
|
|
static IOS_HANDLE UlpGetIosForUsb(IOS_USB_HANDLE DeviceHandle) {
|
|
// BUGBUG: is this still accurate here?
|
|
if (DeviceHandle < 0) return s_hUsbVen;
|
|
return s_hUsbHid;
|
|
}
|
|
|
|
static NTSTATUS UlpIoctl(IOS_USB_HANDLE DeviceHandle, ULONG ControlCode, PVOID Input, ULONG LengthInput, PVOID Output, ULONG LengthOutput, PIOS_USB_ASYNC_RESULT Async, IOP_CALLBACK Callback, PVOID Context) {
|
|
if (Async != NULL && Callback != NULL) return STATUS_INVALID_PARAMETER;
|
|
IOS_HANDLE Handle = UlpGetIosForUsb(DeviceHandle);
|
|
if (Async != NULL) return HalIopIoctlAsync(Handle, ControlCode, Input, LengthInput, Output, LengthOutput, IOCTL_SWAP_NONE, IOCTL_SWAP_NONE, &Async->Status, &Async->Event);
|
|
else if (Callback != NULL) return HalIopIoctlAsyncDpc(Handle, ControlCode, Input, LengthInput, Output, LengthOutput, IOCTL_SWAP_NONE, IOCTL_SWAP_NONE, Callback, Context);
|
|
else return HalIopIoctl(Handle, ControlCode, Input, LengthInput, Output, LengthOutput, IOCTL_SWAP_NONE, IOCTL_SWAP_NONE);
|
|
}
|
|
|
|
static NTSTATUS UlpIoctlv(IOS_USB_HANDLE DeviceHandle, ULONG ControlCode, ULONG NumRead, ULONG NumWritten, PIOS_IOCTL_VECTOR Buffers, BOOLEAN EndpointIn, PIOS_USB_ASYNC_RESULT Async, IOP_CALLBACK Callback, PVOID Context) {
|
|
if (Async != NULL && Callback != NULL) return STATUS_INVALID_PARAMETER;
|
|
IOS_HANDLE Handle = UlpGetIosForUsb(DeviceHandle);
|
|
// for an endpoint out (write), swap in and out
|
|
// for an endpoint in (read), swap out
|
|
ULONG SwapIn = 0;
|
|
if (!EndpointIn) SwapIn = BIT(1);
|
|
ULONG SwapOut = BIT(1);
|
|
if (Buffers[2].Pointer != NULL) {
|
|
// iso message, buffer 1 is array of u16 packet sizes in wrong endianness, swapping will place everything in correct place and correct endianness for IOP
|
|
SwapIn |= BIT(1);
|
|
if (!EndpointIn) SwapIn |= BIT(2);
|
|
SwapOut |= BIT(2);
|
|
}
|
|
|
|
if (Async != NULL) return HalIopIoctlvAsync(Handle, ControlCode, NumRead, NumWritten, Buffers, SwapIn, SwapOut, &Async->Status, &Async->Event);
|
|
else if (Callback != NULL) return HalIopIoctlvAsyncDpc(Handle, ControlCode, NumRead, NumWritten, Buffers, SwapIn, SwapOut, Callback, Context);
|
|
else return HalIopIoctlv(Handle, ControlCode, NumRead, NumWritten, Buffers, SwapIn, SwapOut);
|
|
}
|
|
|
|
static NTSTATUS UlpSendIsoMessage(
|
|
IOS_USB_HANDLE DeviceHandle,
|
|
UCHAR bEndpoint,
|
|
UCHAR bPackets,
|
|
PU16BE rpPacketSizes,
|
|
PVOID rpData,
|
|
PIOS_USB_ASYNC_RESULT Async,
|
|
IOP_CALLBACK Callback,
|
|
PVOID Context
|
|
) {
|
|
if (rpPacketSizes == NULL) return STATUS_INVALID_PARAMETER;
|
|
if (rpData == NULL) return STATUS_INVALID_PARAMETER;
|
|
|
|
USHORT wLength = 0;
|
|
for (ULONG i = 0; i < bPackets; i++) wLength += rpPacketSizes[i].v;
|
|
if (wLength == 0) return STATUS_INVALID_PARAMETER;
|
|
|
|
PIOS_USB_ISOCHRONOUS_TRANSFER_REQ Req =
|
|
(PIOS_USB_ISOCHRONOUS_TRANSFER_REQ)
|
|
HalIopAlloc(sizeof(IOS_USB_ISOCHRONOUS_TRANSFER_REQ));
|
|
if (Req == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
// Work around the requirement of 32-bit writes to uncached DDR mappings.
|
|
// RtlCopyMemory is guaranteed to always use 32-bit writes;
|
|
// as sizeof(Req) is 32 bit aligned.
|
|
IOS_USB_ISOCHRONOUS_TRANSFER_REQ _Req;
|
|
PIOS_USB_ISOCHRONOUS_TRANSFER_REQ pReq = &_Req;
|
|
RtlZeroMemory(pReq, sizeof(Req));
|
|
|
|
NATIVE_WRITE(pReq, DeviceHandle, DeviceHandle);
|
|
NATIVE_WRITE(pReq, NumberOfPackets, bPackets);
|
|
NATIVE_WRITE(pReq, EndpointAddress, bEndpoint);
|
|
|
|
pReq->Vectors[0].Pointer = Req;
|
|
pReq->Vectors[0].Length = sizeof(*Req);
|
|
pReq->Vectors[1].Pointer = rpPacketSizes;
|
|
pReq->Vectors[1].Length = sizeof(USHORT) * bPackets;
|
|
pReq->Vectors[2].Pointer = rpData;
|
|
pReq->Vectors[2].Length = wLength;
|
|
|
|
pReq->Context = Context;
|
|
|
|
RtlCopyMemory(Req, pReq, sizeof(*Req));
|
|
|
|
BOOLEAN EndpointIn = (bEndpoint & USB_ENDPOINT_IN) != 0;
|
|
|
|
if (Async != NULL) UlpAsyncInit(Async, Req);
|
|
NTSTATUS Status = UlpIoctlv(DeviceHandle, USB_IOCTLV_ISOCHRONOUS_TRANSFER, 1, 2, Req->Vectors, EndpointIn, Async, Callback, Req);
|
|
if ((Async == NULL && Callback == NULL) || !NT_SUCCESS(Status)) HalIopFree(Req);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS UlpSendControlMessage(
|
|
IOS_USB_HANDLE DeviceHandle,
|
|
UCHAR bmRequestType,
|
|
UCHAR bRequest,
|
|
USHORT wValue,
|
|
USHORT wIndex,
|
|
USHORT wLength,
|
|
PVOID rpData,
|
|
PIOS_USB_ASYNC_RESULT Async,
|
|
IOP_CALLBACK Callback,
|
|
PVOID Context
|
|
) {
|
|
if (rpData == NULL && wLength != 0) return STATUS_INVALID_PARAMETER;
|
|
if (wLength == 0 && rpData != NULL) return STATUS_INVALID_PARAMETER;
|
|
|
|
PIOS_USB_CONTROL_TRANSFER_REQ Req = (PIOS_USB_CONTROL_TRANSFER_REQ)
|
|
HalIopAlloc(sizeof(IOS_USB_CONTROL_TRANSFER_REQ));
|
|
if (Req == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
// Work around the requirement of 32-bit writes to uncached DDR mappings.
|
|
// RtlCopyMemory is guaranteed to always use 32-bit writes;
|
|
// as sizeof(Req) is 32 bit aligned.
|
|
IOS_USB_CONTROL_TRANSFER_REQ _Req;
|
|
PIOS_USB_CONTROL_TRANSFER_REQ pReq = &_Req;
|
|
|
|
RtlZeroMemory(pReq, sizeof(*Req));
|
|
|
|
NATIVE_WRITE(pReq, DeviceHandle, DeviceHandle);
|
|
NATIVE_WRITE(pReq, bmRequestType, bmRequestType);
|
|
NATIVE_WRITE(pReq, bRequest, bRequest);
|
|
NATIVE_WRITE(pReq, wValue, wValue);
|
|
NATIVE_WRITE(pReq, wIndex, wIndex);
|
|
|
|
pReq->Vectors[0].Pointer = Req;
|
|
pReq->Vectors[0].Length = sizeof(*Req);
|
|
pReq->Vectors[1].Pointer = rpData;
|
|
pReq->Vectors[1].Length = wLength;
|
|
|
|
pReq->Context = Context;
|
|
|
|
RtlCopyMemory(Req, pReq, sizeof(*Req));
|
|
|
|
#if 0
|
|
{
|
|
CHAR DebugText[512];
|
|
PUCHAR Req8 = (PUCHAR)(ULONG)Req;
|
|
for (int i = 0; i < sizeof(*Req); i += 0x10) {
|
|
_snprintf(DebugText, sizeof(DebugText),
|
|
"%02x %02x %02x %02x %02x %02x %02x %02x "
|
|
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
Req8[i + 0x0], Req8[i + 0x1],
|
|
Req8[i + 0x2], Req8[i + 0x3],
|
|
Req8[i + 0x4], Req8[i + 0x5],
|
|
Req8[i + 0x6], Req8[i + 0x7],
|
|
Req8[i + 0x8], Req8[i + 0x9],
|
|
Req8[i + 0xa], Req8[i + 0xb],
|
|
Req8[i + 0xc], Req8[i + 0xd],
|
|
Req8[i + 0xe], Req8[i + 0xf]
|
|
);
|
|
HalDisplayString(DebugText);
|
|
}
|
|
HalDisplayString("\n");
|
|
}
|
|
#endif
|
|
|
|
BOOLEAN EndpointIn = (bmRequestType & USB_CTRLTYPE_DIR_DEVICE2HOST) == 0;
|
|
|
|
if (Async != NULL) UlpAsyncInit(Async, Req);
|
|
NTSTATUS Status = UlpIoctlv(DeviceHandle, USB_IOCTLV_CONTROL_TRANSFER, 1, 1, Req->Vectors, EndpointIn, Async, Callback, Req);
|
|
if ((Async == NULL && Callback == NULL) || !NT_SUCCESS(Status)) HalIopFree(Req);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS UlpSendBulkMessage(
|
|
IOS_USB_HANDLE DeviceHandle,
|
|
UCHAR bEndpoint,
|
|
USHORT wLength,
|
|
PVOID rpData,
|
|
PIOS_USB_ASYNC_RESULT Async,
|
|
IOP_CALLBACK Callback,
|
|
PVOID Context
|
|
) {
|
|
|
|
if (rpData == NULL && wLength != 0) return STATUS_INVALID_PARAMETER;
|
|
if (wLength == 0 && rpData != NULL) return STATUS_INVALID_PARAMETER;
|
|
|
|
PIOS_USB_BULK_TRANSFER_REQ Req = (PIOS_USB_BULK_TRANSFER_REQ)
|
|
HalIopAlloc(sizeof(IOS_USB_BULK_TRANSFER_REQ));
|
|
if (Req == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
// Work around the requirement of 32-bit writes to uncached DDR mappings.
|
|
// RtlCopyMemory is guaranteed to always use 32-bit writes;
|
|
// as sizeof(Req) is 32 bit aligned.
|
|
IOS_USB_BULK_TRANSFER_REQ _Req;
|
|
PIOS_USB_BULK_TRANSFER_REQ pReq = &_Req;
|
|
|
|
RtlZeroMemory(pReq, sizeof(*Req));
|
|
|
|
NATIVE_WRITE(pReq, DeviceHandle, DeviceHandle);
|
|
NATIVE_WRITE(pReq, EndpointAddress, bEndpoint);
|
|
|
|
pReq->Vectors[0].Pointer = Req;
|
|
pReq->Vectors[0].Length = sizeof(*Req);
|
|
pReq->Vectors[1].Pointer = rpData;
|
|
pReq->Vectors[1].Length = wLength;
|
|
|
|
pReq->Context = Context;
|
|
RtlCopyMemory(Req, pReq, sizeof(*Req));
|
|
|
|
BOOLEAN EndpointIn = (bEndpoint & USB_ENDPOINT_IN) != 0;
|
|
|
|
if (Async != NULL) UlpAsyncInit(Async, Req);
|
|
NTSTATUS Status = UlpIoctlv(DeviceHandle, USB_IOCTLV_BULK_TRANSFER, 1, 1, Req->Vectors, EndpointIn, Async, Callback, Req);
|
|
if ((Async == NULL && Callback == NULL) || !NT_SUCCESS(Status)) HalIopFree(Req);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS UlpSendInterruptMessage(
|
|
IOS_USB_HANDLE DeviceHandle,
|
|
UCHAR bEndpoint,
|
|
USHORT wLength,
|
|
PVOID rpData,
|
|
PIOS_USB_ASYNC_RESULT Async,
|
|
IOP_CALLBACK Callback,
|
|
PVOID Context
|
|
) {
|
|
|
|
if (rpData == NULL && wLength != 0) return STATUS_INVALID_PARAMETER;
|
|
if (wLength == 0 && rpData != NULL) return STATUS_INVALID_PARAMETER;
|
|
|
|
PIOS_USB_INTERRUPT_TRANSFER_REQ Req = (PIOS_USB_INTERRUPT_TRANSFER_REQ)
|
|
HalIopAlloc(sizeof(IOS_USB_INTERRUPT_TRANSFER_REQ));
|
|
if (Req == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
// Work around the requirement of 32-bit writes to uncached DDR mappings.
|
|
// RtlCopyMemory is guaranteed to always use 32-bit writes;
|
|
// as sizeof(Req) is 32 bit aligned.
|
|
IOS_USB_INTERRUPT_TRANSFER_REQ _Req;
|
|
PIOS_USB_INTERRUPT_TRANSFER_REQ pReq = &_Req;
|
|
|
|
RtlZeroMemory(pReq, sizeof(*Req));
|
|
|
|
|
|
NATIVE_WRITE(pReq, DeviceHandle, DeviceHandle);
|
|
NATIVE_WRITE(pReq, Write, ((bEndpoint & USB_ENDPOINT_IN) == 0));
|
|
NATIVE_WRITE(pReq, EndpointAddress, bEndpoint);
|
|
pReq->Vectors[0].Pointer = Req;
|
|
pReq->Vectors[0].Length = sizeof(*Req);
|
|
pReq->Vectors[1].Pointer = rpData;
|
|
pReq->Vectors[1].Length = wLength;
|
|
|
|
pReq->Context = Context;
|
|
RtlCopyMemory(Req, pReq, sizeof(*Req));
|
|
|
|
BOOLEAN EndpointIn = (bEndpoint & USB_ENDPOINT_IN) != 0;
|
|
|
|
if (Async != NULL) UlpAsyncInit(Async, Req);
|
|
//HalDisplayString("Ioctlv InterruptTransfer\n");
|
|
NTSTATUS Status = UlpIoctlv(DeviceHandle, USB_IOCTLV_INTERRUPT_TRANSFER, 1, 1, Req->Vectors, EndpointIn, Async, Callback, Req);
|
|
if ((Async == NULL && Callback == NULL) || !NT_SUCCESS(Status)) HalIopFree(Req);
|
|
|
|
return Status;
|
|
}
|
|
|
|
static inline NTSTATUS UlpGetDesc(
|
|
IOS_USB_HANDLE DeviceHandle,
|
|
PVOID Buffer,
|
|
UCHAR ValueHigh,
|
|
UCHAR ValueLow,
|
|
USHORT Index,
|
|
USHORT Size
|
|
) {
|
|
UCHAR RequestType = USB_CTRLTYPE_DIR_DEVICE2HOST;
|
|
if (ValueHigh == USB_DT_HID || ValueHigh == USB_DT_REPORT || ValueHigh == USB_DT_PHYSICAL)
|
|
RequestType |= USB_CTRLTYPE_REC_INTERFACE;
|
|
|
|
return UlpSendControlMessage(
|
|
DeviceHandle,
|
|
RequestType,
|
|
USB_REQ_GETDESCRIPTOR,
|
|
(ValueHigh << 8) | ValueLow,
|
|
Index,
|
|
Size,
|
|
Buffer,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
#if 0
|
|
static ULONG UlpFindNextEndpoint(PVOID Buffer, LONG Size, UCHAR Align) {
|
|
PUCHAR Ptr = (PUCHAR)Buffer;
|
|
|
|
while (Size > 2 && Ptr[0] != 0) {
|
|
if (Ptr[1] == USB_DT_ENDPOINT || Ptr[1] == USB_DT_INTERFACE) break;
|
|
|
|
UCHAR ChunkSize = Ptr[0];
|
|
UCHAR AlignedChunkSize = (ChunkSize + Align) & ~Align;
|
|
Size -= AlignedChunkSize;
|
|
Ptr += AlignedChunkSize;
|
|
}
|
|
|
|
return ((ULONG)Ptr - (ULONG)Buffer);
|
|
}
|
|
#endif
|
|
|
|
static NTSTATUS UlpCheckVersionImpl(IOS_HANDLE Handle, PIOS_USB_VERSION UsbVersion) {
|
|
NTSTATUS Status = HalIopIoctl(Handle, USB_IOCTL_GET_VERSION, NULL, 0, UsbVersion, sizeof(*UsbVersion), IOCTL_SWAP_NONE, IOCTL_SWAP_NONE);
|
|
if (!NT_SUCCESS(Status)) return STATUS_OBJECT_TYPE_MISMATCH;
|
|
if (NativeReadBase8(MMIO_OFFSET(UsbVersion, Major)) != 5) return STATUS_OBJECT_TYPE_MISMATCH;
|
|
if (NativeReadBase8(MMIO_OFFSET(UsbVersion, Minor)) != 0) return STATUS_OBJECT_TYPE_MISMATCH;
|
|
if (NativeReadBase8(MMIO_OFFSET(UsbVersion, Revision)) != 1) return STATUS_OBJECT_TYPE_MISMATCH;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static NTSTATUS UlpCheckVersion(IOS_HANDLE Handle) {
|
|
PIOS_USB_VERSION UsbVersion = HalIopAlloc(sizeof(IOS_USB_VERSION));
|
|
if (UsbVersion == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
NTSTATUS Status = UlpCheckVersionImpl(Handle, UsbVersion);
|
|
HalIopFree(UsbVersion);
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS UlpSuspendResume(IOS_USB_HANDLE DeviceHandle, BOOLEAN Resumed) {
|
|
PIOS_USB_SUSPEND_RESUME_REQ Buf = (PIOS_USB_SUSPEND_RESUME_REQ)
|
|
HalIopAlloc(sizeof(IOS_USB_SUSPEND_RESUME_REQ));
|
|
if (Buf == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
IOS_USB_SUSPEND_RESUME_REQ Req;
|
|
PIOS_USB_SUSPEND_RESUME_REQ pReq = &Req;
|
|
RtlZeroMemory(&Req, sizeof(Req));
|
|
NATIVE_WRITE(pReq, DeviceHandle, DeviceHandle);
|
|
NATIVE_WRITE(pReq, Resume, Resumed);
|
|
RtlCopyMemory(Buf, &Req, sizeof(Req));
|
|
NTSTATUS Status = STATUS_NO_SUCH_DEVICE;
|
|
if (UlpFindDeviceVen(DeviceHandle) != NULL) {
|
|
Status = HalIopIoctl(s_hUsbVen, USB_IOCTL_SUSPEND_RESUME, Buf, sizeof(*Buf), NULL, 0, IOCTL_SWAP_NONE, IOCTL_SWAP_NONE);
|
|
} else if (UlpFindDeviceHid(DeviceHandle) != NULL) {
|
|
Status = HalIopIoctl(s_hUsbHid, USB_IOCTL_SUSPEND_RESUME, Buf, sizeof(*Buf), NULL, 0, IOCTL_SWAP_NONE, IOCTL_SWAP_NONE);
|
|
}
|
|
HalIopFree(Buf);
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS UlpSuspendDevice(IOS_USB_HANDLE DeviceHandle) {
|
|
return UlpSuspendResume(DeviceHandle, FALSE);
|
|
}
|
|
|
|
static NTSTATUS UlpResumeDevice(IOS_USB_HANDLE DeviceHandle) {
|
|
return UlpSuspendResume(DeviceHandle, TRUE);
|
|
}
|
|
|
|
NTSTATUS UlInit(void) {
|
|
//BOOLEAN InEmulator = (BOOLEAN) (ULONG) RUNTIME_BLOCK[RUNTIME_IN_EMULATOR];
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
if (s_AttachedDevicesVen == NULL) {
|
|
if (s_hUsbVen == IOS_HANDLE_INVALID) {
|
|
// Open handle.
|
|
NTSTATUS VenStatus = HalIopOpen(sc_UsbVen, IOSOPEN_NONE, &s_hUsbVen);
|
|
if (!NT_SUCCESS(VenStatus)) {
|
|
return VenStatus;
|
|
}
|
|
// Check version.
|
|
VenStatus = UlpCheckVersion(s_hUsbVen);
|
|
if (!NT_SUCCESS(VenStatus)) {
|
|
// Incorrect version.
|
|
HalIopClose(s_hUsbVen);
|
|
s_hUsbVen = IOS_HANDLE_INVALID;
|
|
return VenStatus;
|
|
}
|
|
}
|
|
// Allocate memory for attached devices.
|
|
s_AttachedDevicesVen = HalIopAlloc(sizeof(*s_AttachedDevicesVen));
|
|
if (s_AttachedDevicesVen == NULL) {
|
|
HalIopClose(s_hUsbVen);
|
|
s_hUsbVen = IOS_HANDLE_INVALID;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlZeroMemory(s_AttachedDevicesVen, sizeof(*s_AttachedDevicesVen));
|
|
}
|
|
|
|
// Unlike libogc implementation, only get here if usbven is open and is v5.
|
|
if (s_AttachedDevicesHid == NULL) {
|
|
NTSTATUS HidStatus;
|
|
if (s_hUsbHid == IOS_HANDLE_INVALID) {
|
|
// Open handle.
|
|
HidStatus = HalIopOpen(sc_UsbHid, IOSOPEN_NONE, &s_hUsbHid);
|
|
if (NT_SUCCESS(HidStatus)) {
|
|
// Check version.
|
|
HidStatus = UlpCheckVersion(s_hUsbHid);
|
|
if (!NT_SUCCESS(HidStatus)) {
|
|
// Incorrect version.
|
|
HalIopClose(s_hUsbHid);
|
|
s_hUsbHid = IOS_HANDLE_INVALID;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s_hUsbHid != IOS_HANDLE_INVALID) {
|
|
// Allocate memory for attached devices.
|
|
s_AttachedDevicesHid = HalIopAlloc(sizeof(*s_AttachedDevicesHid));
|
|
if (s_AttachedDevicesHid == NULL) {
|
|
HalIopClose(s_hUsbHid);
|
|
HalIopClose(s_hUsbVen);
|
|
HalIopFree(s_AttachedDevicesVen);
|
|
s_AttachedDevicesVen = NULL;
|
|
s_hUsbHid = IOS_HANDLE_INVALID;
|
|
s_hUsbVen = IOS_HANDLE_INVALID;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlZeroMemory(s_AttachedDevicesHid, sizeof(*s_AttachedDevicesHid));
|
|
} else {
|
|
HalIopClose(s_hUsbVen);
|
|
HalIopFree(s_AttachedDevicesVen);
|
|
s_AttachedDevicesVen = NULL;
|
|
s_hUsbHid = IOS_HANDLE_INVALID;
|
|
s_hUsbVen = IOS_HANDLE_INVALID;
|
|
return HidStatus;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
Status = PsCreateSystemThread(&s_DeviceChangeThread,
|
|
(ACCESS_MASK)0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
UlpDeviceChangeThread,
|
|
NULL
|
|
);
|
|
#endif
|
|
// Start asynchronous DeviceChange ioctls.
|
|
if (NT_SUCCESS(Status)) {
|
|
RtlZeroMemory(s_OpenedDevices, sizeof(s_OpenedDevices));
|
|
//PIOS_USB_DEVICE_CHANGE DeviceChange = (PIOS_USB_DEVICE_CHANGE) RUNTIME_BLOCK[RUNTIME_USB_DEVICES];
|
|
|
|
//RtlCopyMemory(s_AttachedDevicesVen, &DeviceChange[0], sizeof(DeviceChange[0]));
|
|
//RtlCopyMemory(s_AttachedDevicesHid, &DeviceChange[1], sizeof(DeviceChange[0]));
|
|
//s_KnownDevicesVen = TRUE;
|
|
//s_KnownDevicesHid = TRUE;
|
|
Status = HalIopIoctlAsyncDpc(
|
|
s_hUsbVen,
|
|
USB_IOCTL_DEVICE_CHANGE,
|
|
NULL, 0,
|
|
s_AttachedDevicesVen, sizeof(*s_AttachedDevicesVen),
|
|
IOCTL_SWAP_NONE, IOCTL_SWAP_NONE,
|
|
UlpDeviceChangeCallback,
|
|
(PVOID)VARIANT_VEN
|
|
);
|
|
}
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = HalIopIoctlAsyncDpc(
|
|
s_hUsbHid,
|
|
USB_IOCTL_DEVICE_CHANGE,
|
|
NULL, 0,
|
|
s_AttachedDevicesHid, sizeof(*s_AttachedDevicesHid),
|
|
IOCTL_SWAP_NONE, IOCTL_SWAP_NONE,
|
|
UlpDeviceChangeCallback,
|
|
(PVOID)VARIANT_HID
|
|
);
|
|
}
|
|
if (!NT_SUCCESS(Status)) {
|
|
HalIopIoctl(s_hUsbHid, USB_IOCTL_SHUTDOWN, NULL, 0, NULL, 0, IOCTL_SWAP_NONE, IOCTL_SWAP_NONE);
|
|
HalIopClose(s_hUsbHid);
|
|
HalIopIoctl(s_hUsbVen, USB_IOCTL_SHUTDOWN, NULL, 0, NULL, 0, IOCTL_SWAP_NONE, IOCTL_SWAP_NONE);
|
|
HalIopClose(s_hUsbVen);
|
|
HalIopFree(s_AttachedDevicesHid);
|
|
s_AttachedDevicesHid = NULL;
|
|
HalIopFree(s_AttachedDevicesVen);
|
|
s_AttachedDevicesVen = NULL;
|
|
s_hUsbHid = IOS_HANDLE_INVALID;
|
|
s_hUsbVen = IOS_HANDLE_INVALID;
|
|
} else {
|
|
// Spin until first device change comes in.
|
|
while (!s_KnownDevicesHid || !s_KnownDevicesVen) { }
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS UlpGetDescriptorsHidForOpen(IOS_USB_HANDLE DeviceHandle) {
|
|
PIOS_USB_GET_DEVICE_INFO_REQ Req = (PIOS_USB_GET_DEVICE_INFO_REQ)
|
|
HalIopAlloc(sizeof(IOS_USB_GET_DEVICE_INFO_REQ));
|
|
if (Req == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
IOS_USB_GET_DEVICE_INFO_REQ _Req;
|
|
PIOS_USB_GET_DEVICE_INFO_REQ pReq = &_Req;
|
|
RtlZeroMemory(&_Req, sizeof(_Req));
|
|
NATIVE_WRITE(pReq, DeviceHandle, DeviceHandle);
|
|
NATIVE_WRITE(pReq, AlternateSetting, 0);
|
|
RtlCopyMemory(Req, &_Req, sizeof(_Req));
|
|
|
|
PIOS_USB_GET_DEVICE_INFO_HID_RES HidRes = (PIOS_USB_GET_DEVICE_INFO_HID_RES)
|
|
HalIopAlloc(sizeof(IOS_USB_GET_DEVICE_INFO_HID_RES));
|
|
if (HidRes == NULL) {
|
|
HalIopFree(Req);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory(HidRes, sizeof(IOS_USB_GET_DEVICE_INFO_HID_RES));
|
|
NTSTATUS Status = HalIopIoctl(s_hUsbHid, USB_IOCTL_GET_DEVICE_INFO, Req, sizeof(*Req), HidRes, sizeof(*HidRes), IOCTL_SWAP_NONE, IOCTL_SWAP_NONE);
|
|
HalIopFree(Req);
|
|
HalIopFree(HidRes);
|
|
return Status;
|
|
}
|
|
|
|
#if 0
|
|
static NTSTATUS UlpResetDevice(IOS_USB_HANDLE DeviceHandle) {
|
|
PIOS_USB_RESET_REQ Buf = (PIOS_USB_RESET_REQ)
|
|
HalIopAlloc(sizeof(IOS_USB_RESET_REQ));
|
|
if (Buf == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
Buf->DeviceHandle = DeviceHandle;
|
|
NTSTATUS Status = STATUS_NO_SUCH_DEVICE;
|
|
if (UlpFindDeviceVen(DeviceHandle) != NULL) {
|
|
Status = HalIopIoctl(s_hUsbVen, USB_IOCTL_RESET, Buf, sizeof(*Buf), NULL, 0);
|
|
}
|
|
// HID does not have USB_IOCTL_RESET
|
|
HalIopFree(Buf);
|
|
return Status;
|
|
}
|
|
#endif
|
|
|
|
static NTSTATUS UlpClearHaltMsg(IOS_USB_HANDLE DeviceHandle) {
|
|
// some devices can't handle this, so ignore result.
|
|
UlpSendControlMessage(
|
|
DeviceHandle,
|
|
(USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_ENDPOINT),
|
|
USB_REQ_CLEARFEATURE,
|
|
USB_FEATURE_ENDPOINT_HALT,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static NTSTATUS UlpOpenDevice(IOS_USB_HANDLE DeviceHandle) {
|
|
// for HID, descriptor needs to be read
|
|
if (UlpFindDeviceHid(DeviceHandle) == NULL) {
|
|
if (UlpFindDeviceVen(DeviceHandle) != NULL) {
|
|
#if 0
|
|
NTSTATUS Status = UlpResumeDevice(DeviceHandle);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
Status = UlpClearHaltMsg(DeviceHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
UlpSuspendDevice(DeviceHandle);
|
|
}
|
|
return Status;
|
|
#endif
|
|
return UlpResumeDevice(DeviceHandle);
|
|
}
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
NTSTATUS Status = UlpResumeDevice(DeviceHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (Status == STATUS_INVALID_PARAMETER) {
|
|
// Might be opened already (perhaps from ARC firmware). Try suspend then resume.
|
|
Status = UlpSuspendDevice(DeviceHandle);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
Status = UlpResumeDevice(DeviceHandle);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
}
|
|
return Status;
|
|
}
|
|
//USB_DEVICE_DESC Descriptors;
|
|
Status = UlpGetDescriptorsHidForOpen(DeviceHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
UlpSuspendDevice(DeviceHandle);
|
|
return Status;
|
|
}
|
|
#if 0
|
|
Status = UlpClearHaltMsg(DeviceHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
UlpSuspendDevice(DeviceHandle);
|
|
}
|
|
#endif
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS UlpOpenDeviceEnsureClearHalt(IOS_USB_HANDLE DeviceHandle) {
|
|
return UlpOpenDevice(DeviceHandle);
|
|
}
|
|
|
|
NTSTATUS UlOpenDevice(IOS_USB_HANDLE DeviceHandle) {
|
|
PUSB_OPENED_DEVICE EmptyDevice = NULL;
|
|
for (ULONG i = 0; i < USB_COUNT_DEVICES; i++) {
|
|
IOS_USB_HANDLE Current = s_OpenedDevices[i].DeviceHandle;
|
|
if (Current == DeviceHandle) {
|
|
s_OpenedDevices[i].RefCount++;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
if (s_OpenedDevices[i].RefCount == 0 && Current == 0 && EmptyDevice == NULL) {
|
|
EmptyDevice = &s_OpenedDevices[i];
|
|
}
|
|
}
|
|
if (EmptyDevice == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
NTSTATUS Status = UlpOpenDeviceEnsureClearHalt(DeviceHandle);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
EmptyDevice->DeviceHandle = DeviceHandle;
|
|
EmptyDevice->RefCount = 1;
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS UlCloseDevice(IOS_USB_HANDLE DeviceHandle) {
|
|
for (ULONG i = 0; i < USB_COUNT_DEVICES; i++) {
|
|
IOS_USB_HANDLE Current = s_OpenedDevices[i].DeviceHandle;
|
|
if (Current == DeviceHandle) {
|
|
s_OpenedDevices[i].RefCount--;
|
|
if (s_OpenedDevices[i].RefCount != 0)
|
|
return STATUS_SUCCESS;
|
|
s_OpenedDevices[i].DeviceHandle = 0;
|
|
return UlpSuspendResume(DeviceHandle, FALSE);
|
|
}
|
|
}
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
NTSTATUS UlGetDeviceDesc(IOS_USB_HANDLE DeviceHandle, PUSB_DEVICE Device) {
|
|
PUSB_DEVICE Buf = HalIopAlloc(USB_DT_DEVICE_SIZE);
|
|
if (Buf == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
NTSTATUS Status = UlpSendControlMessage(DeviceHandle, USB_CTRLTYPE_DIR_DEVICE2HOST, USB_REQ_GETDESCRIPTOR, (USB_DT_DEVICE << 8), 0, USB_DT_DEVICE_SIZE, Buf, NULL, NULL, NULL);
|
|
if (NT_SUCCESS(Status)) RtlCopyMemory(Device, Buf, USB_DT_DEVICE_SIZE);
|
|
HalIopFree(Buf);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS UlGetDescriptors(IOS_USB_HANDLE DeviceHandle, PUSB_DEVICE_DESC Device) {
|
|
PIOS_USB_DEVICE_ENTRY Ven = UlpFindDeviceVen(DeviceHandle);
|
|
PIOS_USB_DEVICE_ENTRY Hid = UlpFindDeviceHid(DeviceHandle);
|
|
if (Ven == NULL && Hid == NULL) return STATUS_INVALID_PARAMETER;
|
|
|
|
PIOS_USB_GET_DEVICE_INFO_RES_BODY Body = NULL;
|
|
|
|
PIOS_USB_GET_DEVICE_INFO_REQ Req = (PIOS_USB_GET_DEVICE_INFO_REQ)
|
|
HalIopAlloc(sizeof(IOS_USB_GET_DEVICE_INFO_REQ));
|
|
if (Req == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
{
|
|
IOS_USB_GET_DEVICE_INFO_REQ _Req;
|
|
PIOS_USB_GET_DEVICE_INFO_REQ pReq = &_Req;
|
|
RtlZeroMemory(&_Req, sizeof(_Req));
|
|
NATIVE_WRITE(pReq, DeviceHandle, DeviceHandle);
|
|
NATIVE_WRITE(pReq, AlternateSetting, 0);
|
|
RtlCopyMemory(Req, &_Req, sizeof(_Req));
|
|
}
|
|
PVOID Res = NULL;
|
|
ULONG ResLength = 0;
|
|
IOS_HANDLE Handle = IOS_HANDLE_INVALID;
|
|
BOOLEAN IsHid = FALSE;
|
|
|
|
if (UlpFindDeviceVen(DeviceHandle) != NULL) {
|
|
PIOS_USB_GET_DEVICE_INFO_VEN_RES VenRes = (PIOS_USB_GET_DEVICE_INFO_VEN_RES)
|
|
HalIopAlloc(sizeof(IOS_USB_GET_DEVICE_INFO_VEN_RES));
|
|
if (VenRes == NULL) {
|
|
HalIopFree(Req);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
Res = VenRes;
|
|
ResLength = sizeof(IOS_USB_GET_DEVICE_INFO_VEN_RES);
|
|
Body = (PIOS_USB_GET_DEVICE_INFO_RES_BODY)&VenRes->Device;
|
|
Handle = s_hUsbVen;
|
|
} else if (UlpFindDeviceHid(DeviceHandle) != NULL) {
|
|
PIOS_USB_GET_DEVICE_INFO_HID_RES HidRes = (PIOS_USB_GET_DEVICE_INFO_HID_RES)
|
|
HalIopAlloc(sizeof(IOS_USB_GET_DEVICE_INFO_HID_RES));
|
|
if (HidRes == NULL) {
|
|
HalIopFree(Req);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
Res = HidRes;
|
|
ResLength = sizeof(IOS_USB_GET_DEVICE_INFO_HID_RES);
|
|
Body = (PIOS_USB_GET_DEVICE_INFO_RES_BODY)&HidRes->Device;
|
|
Handle = s_hUsbHid;
|
|
IsHid = TRUE;
|
|
}
|
|
|
|
RtlZeroMemory(Res, ResLength);
|
|
NTSTATUS Status = HalIopIoctl(Handle, USB_IOCTL_GET_DEVICE_INFO, Req, sizeof(*Req), Res, ResLength, IOCTL_SWAP_NONE, IOCTL_SWAP_OUTPUT);
|
|
|
|
// Don't need the request buffer any more.
|
|
HalIopFree(Req);
|
|
Req = NULL;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
HalIopFree(Res);
|
|
return Status;
|
|
}
|
|
|
|
// Ensure everything unused is zeroed.
|
|
RtlZeroMemory(Device, sizeof(*Device));
|
|
RtlCopyMemory(&Device->Device, &Body->Device, sizeof(Device->Device));
|
|
if (Device->Device.bNumConfigurations == 0) return Status;
|
|
if (Device->Device.bNumConfigurations > 1) Device->Device.bNumConfigurations = 1;
|
|
RtlCopyMemory(&Device->Config, &Body->Config, sizeof(Device->Config));
|
|
// IOS claims each interface is its own device
|
|
if (Device->Config.bNumInterfaces != 0) {
|
|
Device->Config.bNumInterfaces = 1;
|
|
RtlCopyMemory(&Device->Interface, &Body->Interface, sizeof(Device->Interface));
|
|
if (IsHid) {
|
|
// HID provides only an interface input and an interface output.
|
|
// If either are not present they will be zeroed.
|
|
UCHAR bNumEndpoints = 0;
|
|
ULONG iEndpoint = 0;
|
|
|
|
UCHAR dt = Body->Endpoints[iEndpoint].bDescriptorType;
|
|
if (dt != 0) {
|
|
RtlCopyMemory(&Device->Endpoints[bNumEndpoints], &Body->Endpoints[iEndpoint], sizeof(Device->Endpoints[0]));
|
|
bNumEndpoints++;
|
|
}
|
|
iEndpoint++;
|
|
|
|
dt = Body->Endpoints[iEndpoint].bDescriptorType;
|
|
if (dt != 0) {
|
|
RtlCopyMemory(&Device->Endpoints[bNumEndpoints], &Body->Endpoints[iEndpoint], sizeof(Device->Endpoints[0]));
|
|
bNumEndpoints++;
|
|
}
|
|
Device->Interface.bNumEndpoints = bNumEndpoints;
|
|
} else {
|
|
// Skip vendor and class specific descriptors.
|
|
ULONG iEndpoint = 0;
|
|
for (iEndpoint = 0; iEndpoint < Device->Interface.bNumEndpoints; iEndpoint++) {
|
|
UCHAR dt = Body->Endpoints[iEndpoint].bDescriptorType;
|
|
if (dt == USB_DT_ENDPOINT || dt == USB_DT_INTERFACE) break;
|
|
}
|
|
Device->Interface.bNumEndpoints -= iEndpoint;
|
|
RtlCopyMemory(Device->Endpoints, &Body->Endpoints[iEndpoint], sizeof(Device->Endpoints[0]) * Device->Interface.bNumEndpoints);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
for (ULONG iConf = 0; iConf < Device->Desc.bNumConfigurations; iConf++) {
|
|
PUSB_CONFIGURATION_DESC Config = &Device->Configs[iConf];
|
|
RtlCopyMemory(&Config->Desc, &Body->Config, sizeof(Config->Desc));
|
|
// IOS claims each interface is its own device
|
|
if (Config->Desc.bNumInterfaces == 0) continue;
|
|
Config->Desc.bNumInterfaces = 1;
|
|
PUSB_INTERFACE_DESC Interface = &Config->Interface;
|
|
RtlCopyMemory(&Interface->Desc, &Body->Interface, sizeof(Interface->Desc));
|
|
// Skip vendor and class specific descriptors.
|
|
PUSB_ENDPOINT pEndpoints = &Body->Endpoints[0];
|
|
Interface->ExtraSize = UlpFindNextEndpoint(pEndpoints, (ULONG)Res + ResLength - (ULONG)pEndpoints, 3);
|
|
if (Interface->ExtraSize != 0) {
|
|
Interface->Extra = ExAllocatePool(PagedPool, Interface->ExtraSize);
|
|
if (Interface->Extra == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
RtlCopyMemory(Interface->Extra, pEndpoints, Interface->ExtraSize);
|
|
pEndpoints = (PUSB_ENDPOINT)( (ULONG)pEndpoints + Interface->ExtraSize );
|
|
Interface->Desc.bNumEndpoints -= (Interface->ExtraSize / sizeof(USB_ENDPOINT));
|
|
}
|
|
|
|
if (Interface->Desc.bNumEndpoints == 0) continue;
|
|
Interface->Endpoints = ExAllocatePool(PagedPool, Interface->Desc.bNumEndpoints * sizeof(*Interface->Endpoints));
|
|
if (Interface->Endpoints == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
|
|
for (ULONG iEndpoint = 0; iEndpoint < Interface->Desc.bNumEndpoints; iEndpoint++) {
|
|
PUSB_ENDPOINT Endpoint = &Interface->Endpoints[iEndpoint];
|
|
RtlCopyMemory(Endpoint, &Body->Endpoints[iEndpoint], sizeof(*Endpoint));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
HalIopFree(Res);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS UlGetGenericDescriptor(
|
|
IOS_USB_HANDLE DeviceHandle,
|
|
UCHAR Type,
|
|
UCHAR Index,
|
|
UCHAR Interface,
|
|
PVOID Data,
|
|
ULONG Size
|
|
) {
|
|
PVOID Buffer = HalIopAlloc(Size);
|
|
if (Buffer == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
NTSTATUS Status = UlpGetDesc(DeviceHandle, Buffer, Type, Index, Interface, Size);
|
|
if (NT_SUCCESS(Status)) {
|
|
RtlCopyMemory(Data, Buffer, Size);
|
|
}
|
|
|
|
HalIopFree(Buffer);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS UlGetHidDescriptor(
|
|
IOS_USB_HANDLE DeviceHandle,
|
|
UCHAR Interface,
|
|
PUSB_HID Hid,
|
|
ULONG Size
|
|
) {
|
|
if (Size < sizeof(USB_HID)) return STATUS_INVALID_PARAMETER;
|
|
|
|
return UlGetGenericDescriptor(DeviceHandle, USB_DT_HID, 0, Interface, Hid, Size);
|
|
}
|
|
|
|
NTSTATUS UlGetReportDescriptorSize(IOS_USB_HANDLE DeviceHandle, UCHAR Interface, PUSHORT Length) {
|
|
USB_HID Hid;
|
|
NTSTATUS Status = UlGetHidDescriptor(DeviceHandle, Interface, &Hid, sizeof(Hid));
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
if (Hid.bLength > sizeof(Hid)) return STATUS_NO_SUCH_DEVICE;
|
|
|
|
for (ULONG i = 0; i < Hid.bNumDescriptors; i++) {
|
|
if (Hid.Descriptors[i].bDescriptorType == USB_DT_REPORT) {
|
|
*Length = Hid.Descriptors[i].wDescriptorLength;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
NTSTATUS UlGetReportDescriptor(IOS_USB_HANDLE DeviceHandle, UCHAR Interface, PVOID Data, USHORT Length) {
|
|
if (Data == NULL || Length < USB_DT_MINREPORT_SIZE) return STATUS_INVALID_PARAMETER;
|
|
return UlGetGenericDescriptor(DeviceHandle, USB_DT_REPORT, 0, Interface, Data, Length);
|
|
}
|
|
|
|
#if 0
|
|
void UlFreeDescriptors(PUSB_DEVICE_DESC Device) {
|
|
if (Device->Configs == NULL) {
|
|
RtlZeroMemory(&Device, sizeof(*Device));
|
|
return;
|
|
}
|
|
|
|
for (ULONG iConf = 0; iConf < Device->Desc.bNumConfigurations; iConf++) {
|
|
PUSB_CONFIGURATION_DESC Config = &Device->Configs[iConf];
|
|
if (Config->Desc.bNumInterfaces == 0) continue;
|
|
PUSB_INTERFACE_DESC Interface = &Config->Interface;
|
|
if (Interface->Extra != NULL) ExFreePool(Interface->Extra);
|
|
if (Interface->Endpoints != NULL) ExFreePool(Interface->Endpoints);
|
|
}
|
|
ExFreePool(Device->Configs);
|
|
RtlZeroMemory(&Device, sizeof(*Device));
|
|
}
|
|
#endif
|
|
|
|
NTSTATUS UlGetAsciiString(IOS_USB_HANDLE DeviceHandle, UCHAR Index, USHORT LangID, USHORT Length, PVOID Data, PUSHORT WrittenLength) {
|
|
if (Length > USB_MAX_STRING_LENGTH) Length = USB_MAX_STRING_LENGTH;
|
|
|
|
PUCHAR Buf = (PUCHAR)HalIopAlloc(USB_MAX_STRING_LENGTH);
|
|
if (Buf == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
NTSTATUS Status = UlpGetDesc(DeviceHandle, Buf, USB_DT_STRING, Index, LangID, USB_MAX_STRING_LENGTH);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if (Index == 0) {
|
|
// List of supported languages.
|
|
RtlCopyMemory(Data, Buf, Length);
|
|
} else {
|
|
// Convert UTF-16LE to ASCII.
|
|
UCHAR UnicodeIndex = 2;
|
|
UCHAR AsciiIndex = 0;
|
|
PUCHAR Data8 = (PUCHAR)Data;
|
|
while (AsciiIndex < (Length - 1) && UnicodeIndex < Buf[0]) {
|
|
UCHAR Value = Buf[UnicodeIndex];
|
|
if (Buf[UnicodeIndex + 1] != 0) Value = '?';
|
|
Data8[AsciiIndex] = Value;
|
|
AsciiIndex++;
|
|
UnicodeIndex += 2;
|
|
}
|
|
// Null terminate.
|
|
Data8[AsciiIndex] = 0;
|
|
Length = AsciiIndex - 1;
|
|
}
|
|
if (WrittenLength != NULL) *WrittenLength = Length;
|
|
}
|
|
HalIopFree(Buf);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS UlTransferIsoMessage(IOS_USB_HANDLE DeviceHandle, UCHAR Endpoint, UCHAR Packets, PU16BE PacketSizes, PVOID Data) {
|
|
return UlpSendIsoMessage(DeviceHandle, Endpoint, Packets, PacketSizes, Data, NULL, NULL, NULL);
|
|
}
|
|
|
|
NTSTATUS UlTransferIsoMessageAsync(IOS_USB_HANDLE DeviceHandle, UCHAR Endpoint, UCHAR Packets, PU16BE PacketSizes, PVOID Data, PIOS_USB_ASYNC_RESULT Async, PVOID Context) {
|
|
return UlpSendIsoMessage(DeviceHandle, Endpoint, Packets, PacketSizes, Data, Async, NULL, Context);
|
|
}
|
|
|
|
NTSTATUS UlTransferIsoMessageAsyncDpc(IOS_USB_HANDLE DeviceHandle, UCHAR Endpoint, UCHAR Packets, PU16BE PacketSizes, PVOID Data, IOP_CALLBACK Callback, PVOID Context) {
|
|
return UlpSendIsoMessage(DeviceHandle, Endpoint, Packets, PacketSizes, Data, NULL, Callback, Context);
|
|
}
|
|
|
|
NTSTATUS UlTransferInterruptMessage(IOS_USB_HANDLE DeviceHandle, UCHAR Endpoint, USHORT Length, PVOID Data) {
|
|
return UlpSendInterruptMessage(DeviceHandle, Endpoint, Length, Data, NULL, NULL, NULL);
|
|
}
|
|
|
|
NTSTATUS UlTransferInterruptMessageAsync(IOS_USB_HANDLE DeviceHandle, UCHAR Endpoint, USHORT Length, PVOID Data, PIOS_USB_ASYNC_RESULT Async, PVOID Context) {
|
|
return UlpSendInterruptMessage(DeviceHandle, Endpoint, Length, Data, Async, NULL, Context);
|
|
}
|
|
|
|
NTSTATUS UlTransferInterruptMessageAsyncDpc(IOS_USB_HANDLE DeviceHandle, UCHAR Endpoint, USHORT Length, PVOID Data, IOP_CALLBACK Callback, PVOID Context) {
|
|
return UlpSendInterruptMessage(DeviceHandle, Endpoint, Length, Data, NULL, Callback, Context);
|
|
}
|
|
|
|
NTSTATUS UlTransferBulkMessage(IOS_USB_HANDLE DeviceHandle, UCHAR Endpoint, USHORT Length, PVOID Data) {
|
|
return UlpSendBulkMessage(DeviceHandle, Endpoint, Length, Data, NULL, NULL, NULL);
|
|
}
|
|
|
|
NTSTATUS UlTransferBulkMessageAsync(IOS_USB_HANDLE DeviceHandle, UCHAR Endpoint, USHORT Length, PVOID Data, PIOS_USB_ASYNC_RESULT Async, PVOID Context) {
|
|
return UlpSendBulkMessage(DeviceHandle, Endpoint, Length, Data, Async, NULL, Context);
|
|
}
|
|
|
|
NTSTATUS UlTransferBulkMessageAsyncDpc(IOS_USB_HANDLE DeviceHandle, UCHAR Endpoint, USHORT Length, PVOID Data, IOP_CALLBACK Callback, PVOID Context) {
|
|
return UlpSendBulkMessage(DeviceHandle, Endpoint, Length, Data, NULL, Callback, Context);
|
|
}
|
|
|
|
NTSTATUS UlTransferControlMessage(IOS_USB_HANDLE DeviceHandle, UCHAR RequestType, UCHAR Request, USHORT Value, USHORT Index, USHORT Length, PVOID Data) {
|
|
return UlpSendControlMessage(DeviceHandle, RequestType, Request, Value, Index, Length, Data, NULL, NULL, NULL);
|
|
}
|
|
|
|
NTSTATUS UlTransferControlMessageAsync(IOS_USB_HANDLE DeviceHandle, UCHAR RequestType, UCHAR Request, USHORT Value, USHORT Index, USHORT Length, PVOID Data, PIOS_USB_ASYNC_RESULT Async, PVOID Context) {
|
|
return UlpSendControlMessage(DeviceHandle, RequestType, Request, Value, Index, Length, Data, Async, NULL, Context);
|
|
}
|
|
|
|
NTSTATUS UlTransferControlMessageAsyncDpc(IOS_USB_HANDLE DeviceHandle, UCHAR RequestType, UCHAR Request, USHORT Value, USHORT Index, USHORT Length, PVOID Data, IOP_CALLBACK Callback, PVOID Context) {
|
|
return UlpSendControlMessage(DeviceHandle, RequestType, Request, Value, Index, Length, Data, NULL, Callback, Context);
|
|
}
|
|
|
|
void UlGetDeviceList(PIOS_USB_DEVICE_ENTRY Entry, UCHAR Count, UCHAR InterfaceClass, PUCHAR WrittenCount) {
|
|
UCHAR Wrote = 0;
|
|
IOS_USB_DEVICE_ENTRY LocalEntry;
|
|
if (InterfaceClass != USB_CLASS_HID) {
|
|
ULONG i = 0;
|
|
while (i < USB_COUNT_DEVICES && Wrote < Count && NativeReadBase32(MMIO_OFFSET(s_AttachedDevicesVen, Entries[i].DeviceHandle)) != 0) {
|
|
// Pointer could be in uncached DDR, write to stack then copy
|
|
LocalEntry.DeviceHandle = NativeReadBase32(MMIO_OFFSET(s_AttachedDevicesVen, Entries[i].DeviceHandle));
|
|
LocalEntry.VendorId = NativeReadBase16(MMIO_OFFSET(s_AttachedDevicesVen, Entries[i].VendorId));
|
|
LocalEntry.ProductId = NativeReadBase16(MMIO_OFFSET(s_AttachedDevicesVen, Entries[i].ProductId));
|
|
LocalEntry.Token = NativeReadBase32(MMIO_OFFSET(s_AttachedDevicesVen, Entries[i].Token));
|
|
RtlCopyMemory(&Entry[Wrote], &LocalEntry, sizeof(LocalEntry));
|
|
Wrote++;
|
|
i++;
|
|
}
|
|
}
|
|
if (InterfaceClass == 0 || InterfaceClass == USB_CLASS_HID) {
|
|
ULONG i = 0;
|
|
while (i < USB_COUNT_DEVICES && Wrote < Count && s_AttachedDevicesHid->Entries[i].DeviceHandle != 0) {
|
|
// Pointer could be in uncached DDR, write to stack then copy
|
|
LocalEntry.DeviceHandle = NativeReadBase32(MMIO_OFFSET(s_AttachedDevicesHid, Entries[i].DeviceHandle));
|
|
LocalEntry.VendorId = NativeReadBase16(MMIO_OFFSET(s_AttachedDevicesHid, Entries[i].VendorId));
|
|
LocalEntry.ProductId = NativeReadBase16(MMIO_OFFSET(s_AttachedDevicesHid, Entries[i].ProductId));
|
|
LocalEntry.Token = NativeReadBase32(MMIO_OFFSET(s_AttachedDevicesHid, Entries[i].Token));
|
|
RtlCopyMemory(&Entry[Wrote], &LocalEntry, sizeof(LocalEntry));
|
|
Wrote++;
|
|
i++;
|
|
}
|
|
}
|
|
if (WrittenCount != NULL) *WrittenCount = Wrote;
|
|
}
|
|
|
|
NTSTATUS UlSetConfiguration(IOS_USB_HANDLE DeviceHandle, UCHAR Configuration) {
|
|
return UlpSendControlMessage(
|
|
DeviceHandle,
|
|
(USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE),
|
|
USB_REQ_SETCONFIG,
|
|
Configuration,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
NTSTATUS UlGetConfiguration(IOS_USB_HANDLE DeviceHandle, PUCHAR Configuration) {
|
|
PUCHAR Buffer = (PUCHAR)HalIopAlloc(sizeof(UCHAR));
|
|
if (Buffer == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
NTSTATUS Status = UlpSendControlMessage(
|
|
DeviceHandle,
|
|
(USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE),
|
|
USB_REQ_GETCONFIG,
|
|
0,
|
|
0,
|
|
sizeof(UCHAR),
|
|
Buffer,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (NT_SUCCESS(Status)) *Configuration = *Buffer;
|
|
HalIopFree(Buffer);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS UlSetAlternativeInterface(IOS_USB_HANDLE DeviceHandle, UCHAR Interface, UCHAR AlternateSetting) {
|
|
return UlpSendControlMessage(
|
|
DeviceHandle,
|
|
(USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_INTERFACE),
|
|
USB_REQ_SETINTERFACE,
|
|
AlternateSetting,
|
|
Interface,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
static NTSTATUS UlpCancelEndpoint(IOS_HANDLE Handle, IOS_USB_HANDLE DeviceHandle, PIOS_USB_CANCEL_ENDPOINT_REQ Req, UCHAR Endpoint) {
|
|
STACK_ALIGN(IOS_USB_CANCEL_ENDPOINT_REQ, pReq, 1, 8);
|
|
RtlZeroMemory(pReq, sizeof(*pReq));
|
|
NATIVE_WRITE(pReq, DeviceHandle, DeviceHandle);
|
|
NATIVE_WRITE(pReq, Endpoint, Endpoint);
|
|
RtlCopyMemory(Req, pReq, sizeof(*pReq));
|
|
return HalIopIoctl(Handle, USB_IOCTL_CANCEL_ENDPOINT, Req, sizeof(*Req), NULL, 0, IOCTL_SWAP_NONE, IOCTL_SWAP_NONE);
|
|
}
|
|
|
|
NTSTATUS UlCancelEndpoint(IOS_USB_HANDLE DeviceHandle, UCHAR Endpoint) {
|
|
PIOS_USB_CANCEL_ENDPOINT_REQ Req = (PIOS_USB_CANCEL_ENDPOINT_REQ)
|
|
HalIopAlloc(sizeof(IOS_USB_CANCEL_ENDPOINT_REQ));
|
|
if (Req == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
IOS_HANDLE Handle = IOS_HANDLE_INVALID;
|
|
if (UlpFindDeviceVen(DeviceHandle) != NULL) {
|
|
Handle = s_hUsbVen;
|
|
} else if (UlpFindDeviceHid(DeviceHandle) != NULL) {
|
|
Handle = s_hUsbHid;
|
|
}
|
|
|
|
NTSTATUS Status = STATUS_NO_SUCH_DEVICE;
|
|
do {
|
|
if (Handle == IOS_HANDLE_INVALID) break;
|
|
Status = UlpCancelEndpoint(Handle, DeviceHandle, Req, Endpoint);
|
|
} while (0);
|
|
|
|
HalIopFree(Req);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS UlClearHalt(IOS_USB_HANDLE DeviceHandle) {
|
|
PIOS_USB_CANCEL_ENDPOINT_REQ Req = (PIOS_USB_CANCEL_ENDPOINT_REQ)
|
|
HalIopAlloc(sizeof(IOS_USB_CANCEL_ENDPOINT_REQ));
|
|
if (Req == NULL) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
IOS_HANDLE Handle = IOS_HANDLE_INVALID;
|
|
if (UlpFindDeviceVen(DeviceHandle) != NULL) {
|
|
Handle = s_hUsbVen;
|
|
} else if (UlpFindDeviceHid(DeviceHandle) != NULL) {
|
|
Handle = s_hUsbHid;
|
|
}
|
|
|
|
NTSTATUS Status = STATUS_NO_SUCH_DEVICE;
|
|
do {
|
|
if (Handle == IOS_HANDLE_INVALID) break;
|
|
// Cancel control messages
|
|
Status = UlpCancelEndpoint(Handle, DeviceHandle, Req, USB_CANCEL_CONTROL);
|
|
if (!NT_SUCCESS(Status)) break;
|
|
// Cancel incoming messages
|
|
Status = UlpCancelEndpoint(Handle, DeviceHandle, Req, USB_CANCEL_INCOMING);
|
|
if (!NT_SUCCESS(Status)) break;
|
|
// Cancel outgoing messages
|
|
Status = UlpCancelEndpoint(Handle, DeviceHandle, Req, USB_CANCEL_OUTGOING);
|
|
} while (0);
|
|
|
|
HalIopFree(Req);
|
|
return Status;
|
|
}
|
|
|
|
PVOID UlGetPassedAsyncContext(PVOID AsyncContext) {
|
|
if (AsyncContext == NULL) return NULL;
|
|
PIOS_USB_CONTROL_TRANSFER_REQ Req = (PIOS_USB_CONTROL_TRANSFER_REQ)
|
|
AsyncContext;
|
|
PVOID Ret = Req->Context;
|
|
|
|
HalIopFree(Req);
|
|
return Ret;
|
|
} |