Files
nt-lite/code/drivers/bus/usb/usb_bus.c
T

648 lines
22 KiB
C

// USB bus manager. This file owns device addressing, descriptor reads, and child PDO creation.
// This is the structural USB bus layer used by the upcoming composite, hub,
// and hotplug stages. The legacy direct xHCI class path is still present for
// boot HID/storage during migration, but newly enumerated xHCI devices now also
// get first-class USB PDOs and can accept internal URB IRPs.
#include "usb.h"
DRIVER_OBJECT gUsbBusDriver;
static bool gUsbBusModelReady;
static uint8_t gUsbNextControllerIndex;
// Implements the device Destroy operation.
static void UsbDeviceDestroy(OBJECT* object) {
USB_DEVICE* dev = (USB_DEVICE*)object;
if (dev->RemoveLockReady) {
IoDestroyRemoveLock(&dev->RemoveLock);
dev->RemoveLockReady = false;
}
if (dev->Pdo) {
IoDereferenceDeviceObject(dev->Pdo);
dev->Pdo = (DEVICE_OBJECT*)0;
}
}
// Implements the pipe Destroy operation.
static void UsbPipeDestroy(OBJECT* object) {
USB_PIPE* pipe = (USB_PIPE*)object;
if (pipe->Device) {
UsbDereferenceDevice(pipe->Device);
pipe->Device = (USB_DEVICE*)0;
}
}
// Implements the reference Device operation.
void UsbReferenceDevice(USB_DEVICE* dev) {
if (dev) ObReferenceObject(&dev->Header);
}
// Implements the dereference Device operation.
void UsbDereferenceDevice(USB_DEVICE* dev) {
if (dev) ObDereferenceObject(&dev->Header);
}
// Implements the reference Pipe operation.
void UsbReferencePipe(USB_PIPE* pipe) {
if (pipe) ObReferenceObject(&pipe->Header);
}
// Implements the dereference Pipe operation.
void UsbDereferencePipe(USB_PIPE* pipe) {
if (pipe) ObDereferenceObject(&pipe->Header);
}
// Creates dma Buffer.
void* UsbAllocateDmaBuffer(USB_DEVICE* dev, size_t pages, PHYSICAL_ADDRESS* outPhys) {
if (!dev || !dev->Hcd || !dev->Hcd->Operations || !dev->Hcd->Operations->AllocateDma)
return (void*)0;
return dev->Hcd->Operations->AllocateDma(dev->Hcd, pages, outPhys);
}
// Creates device.
static USB_DEVICE* UsbAllocateDevice(void) {
USB_DEVICE* dev = (USB_DEVICE*)ObAllocateObject(ObjectTypeUsbDevice, sizeof(USB_DEVICE));
if (!dev) return (USB_DEVICE*)0;
dev->Header.Destroy = UsbDeviceDestroy;
KSTATUS st = IoInitializeRemoveLock(&dev->RemoveLock);
if (!KSUCCESS(st)) {
ObDereferenceObject(&dev->Header);
return (USB_DEVICE*)0;
}
dev->RemoveLockReady = true;
dev->State = UsbDeviceAttached;
return dev;
}
KSTATUS UsbCreatePipe(USB_DEVICE* dev,
USB_PIPE_TYPE type,
uint8_t endpointAddress,
uint16_t maxPacketSize,
uint8_t interval,
USB_PIPE** outPipe) {
if (!dev || !outPipe) return STATUS_INVALID_PARAMETER;
USB_PIPE* pipe = (USB_PIPE*)ObAllocateObject(ObjectTypeUsbPipe, sizeof(USB_PIPE));
if (!pipe) return STATUS_NO_MEMORY;
pipe->Header.Destroy = UsbPipeDestroy;
pipe->Device = dev;
UsbReferenceDevice(dev);
pipe->Type = type;
pipe->EndpointAddress = endpointAddress;
pipe->EndpointId = XhciEndpointIdFromAddress(endpointAddress);
pipe->MaxPacketSize = maxPacketSize;
pipe->Interval = interval;
pipe->Open = true;
*outPipe = pipe;
return STATUS_SUCCESS;
}
// Implements the id From Buffer operation.
static SYS_STRING_VIEW UsbIdFromBuffer(char* buf) {
return SysSvFromCstr(buf);
}
// Implements the id Put Char operation.
static void UsbIdPutChar(char* buf, size_t cap, size_t* pos, char ch) {
if (!buf || !pos || cap == 0)
return;
if (*pos + 1 < cap)
buf[*pos] = ch;
(*pos)++;
if (*pos < cap)
buf[*pos] = '\0';
else
buf[cap - 1] = '\0';
}
// Implements the id Append Literal operation.
static void UsbIdAppendLiteral(char* buf, size_t cap, size_t* pos, const char* text) {
if (!text)
return;
while (*text)
UsbIdPutChar(buf, cap, pos, *text++);
}
// Implements the id Append Hex operation.
static void UsbIdAppendHex(char* buf, size_t cap, size_t* pos, uint32_t value, uint8_t digits) {
static const char kHex[] = "0123456789ABCDEF";
while (digits) {
digits--;
UsbIdPutChar(buf, cap, pos, kHex[(value >> (digits * 4u)) & 0xFu]);
}
}
// Implements the format Vid Pid Rev operation.
static void UsbFormatVidPidRev(char* buf, size_t cap, uint16_t vid, uint16_t pid, uint16_t rev) {
size_t pos = 0;
if (cap) buf[0] = '\0';
UsbIdAppendLiteral(buf, cap, &pos, "USB\\VID_");
UsbIdAppendHex(buf, cap, &pos, vid, 4);
UsbIdAppendLiteral(buf, cap, &pos, "&PID_");
UsbIdAppendHex(buf, cap, &pos, pid, 4);
UsbIdAppendLiteral(buf, cap, &pos, "&REV_");
UsbIdAppendHex(buf, cap, &pos, rev, 4);
}
// Implements the format Vid Pid operation.
static void UsbFormatVidPid(char* buf, size_t cap, uint16_t vid, uint16_t pid) {
size_t pos = 0;
if (cap) buf[0] = '\0';
UsbIdAppendLiteral(buf, cap, &pos, "USB\\VID_");
UsbIdAppendHex(buf, cap, &pos, vid, 4);
UsbIdAppendLiteral(buf, cap, &pos, "&PID_");
UsbIdAppendHex(buf, cap, &pos, pid, 4);
}
// Implements the format Vid Pid Mi operation.
static void UsbFormatVidPidMi(char* buf, size_t cap, uint16_t vid, uint16_t pid, uint8_t mi) {
size_t pos = 0;
if (cap) buf[0] = '\0';
UsbIdAppendLiteral(buf, cap, &pos, "USB\\VID_");
UsbIdAppendHex(buf, cap, &pos, vid, 4);
UsbIdAppendLiteral(buf, cap, &pos, "&PID_");
UsbIdAppendHex(buf, cap, &pos, pid, 4);
UsbIdAppendLiteral(buf, cap, &pos, "&MI_");
UsbIdAppendHex(buf, cap, &pos, mi, 2);
}
// Implements the format Class Sub Prot operation.
static void UsbFormatClassSubProt(char* buf, size_t cap, uint8_t cls, uint8_t sub, uint8_t proto) {
size_t pos = 0;
if (cap) buf[0] = '\0';
UsbIdAppendLiteral(buf, cap, &pos, "USB\\CLASS_");
UsbIdAppendHex(buf, cap, &pos, cls, 2);
UsbIdAppendLiteral(buf, cap, &pos, "&SUBCLASS_");
UsbIdAppendHex(buf, cap, &pos, sub, 2);
UsbIdAppendLiteral(buf, cap, &pos, "&PROT_");
UsbIdAppendHex(buf, cap, &pos, proto, 2);
}
// Implements the format Class operation.
static void UsbFormatClass(char* buf, size_t cap, uint8_t cls) {
size_t pos = 0;
if (cap) buf[0] = '\0';
UsbIdAppendLiteral(buf, cap, &pos, "USB\\CLASS_");
UsbIdAppendHex(buf, cap, &pos, cls, 2);
}
// Implements the format Composite operation.
static void UsbFormatComposite(char* buf, size_t cap) {
size_t pos = 0;
if (cap) buf[0] = '\0';
UsbIdAppendLiteral(buf, cap, &pos, "USB\\COMPOSITE");
}
// Implements the format Root Hub operation.
static void UsbFormatRootHub(char* buf, size_t cap) {
size_t pos = 0;
if (cap) buf[0] = '\0';
UsbIdAppendLiteral(buf, cap, &pos, "USB\\ROOT_HUB");
}
// Creates device Ids.
static void UsbMakeDeviceIds(const XHCI_DEVICE* xdev, IO_DEVICE_ID* ids, char idbuf[][USB_MAX_DEVICE_ID_TEXT], size_t* outCount) {
size_t n = 0;
UsbFormatVidPidRev(idbuf[n], USB_MAX_DEVICE_ID_TEXT, xdev->VendorId, xdev->ProductId, xdev->BcdDevice);
ids[n] = (IO_DEVICE_ID){ IoBusUsb, UsbIdFromBuffer(idbuf[n]) };
n++;
UsbFormatVidPid(idbuf[n], USB_MAX_DEVICE_ID_TEXT, xdev->VendorId, xdev->ProductId);
ids[n] = (IO_DEVICE_ID){ IoBusUsb, UsbIdFromBuffer(idbuf[n]) };
n++;
UsbFormatClassSubProt(idbuf[n], USB_MAX_DEVICE_ID_TEXT, xdev->DeviceClass, xdev->DeviceSubclass, xdev->DeviceProtocol);
ids[n] = (IO_DEVICE_ID){ IoBusUsb, UsbIdFromBuffer(idbuf[n]) };
n++;
UsbFormatClass(idbuf[n], USB_MAX_DEVICE_ID_TEXT, xdev->DeviceClass);
ids[n] = (IO_DEVICE_ID){ IoBusUsb, UsbIdFromBuffer(idbuf[n]) };
n++;
if (xdev->DeviceClass == 0 || xdev->InterfaceCount > 1) {
UsbFormatComposite(idbuf[n], USB_MAX_DEVICE_ID_TEXT);
ids[n] = (IO_DEVICE_ID){ IoBusUsb, UsbIdFromBuffer(idbuf[n]) };
n++;
}
*outCount = n;
}
static void UsbMakeInterfaceIds(const XHCI_DEVICE* xdev,
const USB_TRACKED_INTERFACE* iface,
IO_DEVICE_ID* ids,
char idbuf[][USB_MAX_DEVICE_ID_TEXT],
size_t* outCount) {
size_t n = 0;
const USB_INTERFACE_DESCRIPTOR* d = &iface->Descriptor;
UsbFormatVidPidMi(idbuf[n], USB_MAX_DEVICE_ID_TEXT, xdev->VendorId, xdev->ProductId, d->bInterfaceNumber);
ids[n] = (IO_DEVICE_ID){ IoBusUsb, UsbIdFromBuffer(idbuf[n]) };
n++;
UsbFormatClassSubProt(idbuf[n], USB_MAX_DEVICE_ID_TEXT, d->bInterfaceClass, d->bInterfaceSubClass, d->bInterfaceProtocol);
ids[n] = (IO_DEVICE_ID){ IoBusUsb, UsbIdFromBuffer(idbuf[n]) };
n++;
UsbFormatClass(idbuf[n], USB_MAX_DEVICE_ID_TEXT, d->bInterfaceClass);
ids[n] = (IO_DEVICE_ID){ IoBusUsb, UsbIdFromBuffer(idbuf[n]) };
n++;
*outCount = n;
}
// Initializes bus Model.
KSTATUS UsbInitializeBusModel(void) {
if (gUsbBusModelReady)
return STATUS_SUCCESS;
memset(&gUsbBusDriver, 0, sizeof(gUsbBusDriver));
IoInitializeDriverObject(&gUsbBusDriver, SYS_SV_LITERAL("usb-bus"));
gUsbBusDriver.MajorFunction[IRP_MJ_PNP] = UsbDispatchPdoPnp;
gUsbBusDriver.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = UsbDispatchInternalDeviceControl;
KSTATUS st = IoRegisterDriverObject(&gUsbBusDriver);
if (!KSUCCESS(st)) return st;
gUsbBusModelReady = true;
return STATUS_SUCCESS;
}
void UsbInitializeHcd(USB_HCD* hcd,
const USB_HCD_OPERATIONS* ops,
void* controllerContext,
uint8_t controllerIndex,
uint8_t maxRootPorts) {
if (!hcd) return;
memset(hcd, 0, sizeof(*hcd));
hcd->Operations = ops;
hcd->ControllerContext = controllerContext;
hcd->DriverObject = &gUsbBusDriver;
hcd->ControllerIndex = controllerIndex ? controllerIndex : ++gUsbNextControllerIndex;
hcd->MaxRootPorts = maxRootPorts;
}
// Creates root Hub Pdo.
KSTATUS UsbCreateRootHubPdo(USB_HCD* hcd) {
if (!hcd) return STATUS_INVALID_PARAMETER;
if (hcd->RootHubPdo) return STATUS_ALREADY_EXISTS;
IO_DEVICE_ID ids[2];
char idbuf[2][USB_MAX_DEVICE_ID_TEXT];
UsbFormatRootHub(idbuf[0], USB_MAX_DEVICE_ID_TEXT);
UsbFormatClass(idbuf[1], USB_MAX_DEVICE_ID_TEXT, USB_CLASS_HUB);
ids[0] = (IO_DEVICE_ID){ IoBusUsb, UsbIdFromBuffer(idbuf[0]) };
ids[1] = (IO_DEVICE_ID){ IoBusUsb, UsbIdFromBuffer(idbuf[1]) };
DEVICE_OBJECT* pdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreatePhysicalDevice(&gUsbBusDriver,
hcd->ControllerDevice,
ids,
2,
sizeof(USB_PDO_EXTENSION),
&pdo);
if (!KSUCCESS(st)) return st;
(void)IoSetDeviceName(pdo, SYS_SV_LITERAL("usb-root-hub"));
USB_PDO_EXTENSION* ext = (USB_PDO_EXTENSION*)pdo->DeviceExtension;
ext->Kind = UsbPdoRootHub;
ext->Hcd = hcd;
ext->Device = (USB_DEVICE*)0;
hcd->RootHubPdo = pdo;
st = IoRegisterPhysicalDevice(pdo);
if (!KSUCCESS(st) && st != STATUS_ALREADY_EXISTS)
return st;
DbgPrint("usb: created root hub PDO ports=%u\n", hcd->MaxRootPorts);
return STATUS_SUCCESS;
}
// Creates device Pdo.
KSTATUS UsbCreateDevicePdo(USB_HCD* hcd, XHCI_DEVICE* xdev, DEVICE_OBJECT* parent) {
if (!hcd || !xdev) return STATUS_INVALID_PARAMETER;
if (xdev->UsbPdo) return STATUS_ALREADY_EXISTS;
USB_DEVICE* udev = UsbAllocateDevice();
if (!udev) return STATUS_NO_MEMORY;
udev->Hcd = hcd;
udev->HcdDeviceContext = xdev;
udev->State = xdev->Configured ? UsbDeviceConfigured : (xdev->Addressed ? UsbDeviceAddressed : UsbDeviceAttached);
udev->SlotId = xdev->SlotId;
udev->Speed = xdev->Speed;
udev->Address = xdev->SlotId;
udev->MaxPacketSize0 = xdev->MaxPacketSize0;
udev->VendorId = xdev->VendorId;
udev->ProductId = xdev->ProductId;
udev->BcdUsb = xdev->BcdUsb;
udev->BcdDevice = xdev->BcdDevice;
udev->DeviceClass = xdev->DeviceClass;
udev->DeviceSubclass = xdev->DeviceSubclass;
udev->DeviceProtocol = xdev->DeviceProtocol;
udev->ConfigurationValue = xdev->ConfigurationValue;
udev->Path = xdev->Path;
if (udev->Path.RootPort == 0) {
udev->Path.RootPort = xdev->Port;
udev->Path.Depth = 0;
udev->Path.RouteString = 0;
}
IO_DEVICE_ID ids[5];
char idbuf[5][USB_MAX_DEVICE_ID_TEXT];
size_t idCount = 0;
UsbMakeDeviceIds(xdev, ids, idbuf, &idCount);
DEVICE_OBJECT* pdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreatePhysicalDevice(&gUsbBusDriver,
parent ? parent : (hcd->RootHubPdo ? hcd->RootHubPdo : hcd->ControllerDevice),
ids,
idCount,
sizeof(USB_PDO_EXTENSION),
&pdo);
if (!KSUCCESS(st)) {
UsbDereferenceDevice(udev);
return st;
}
(void)IoSetDeviceName(pdo, SYS_SV_LITERAL("usb-device"));
udev->Pdo = pdo;
IoReferenceDeviceObject(pdo);
USB_PDO_EXTENSION* ext = (USB_PDO_EXTENSION*)pdo->DeviceExtension;
ext->Kind = UsbPdoDevice;
ext->Hcd = hcd;
ext->Device = udev;
xdev->UsbDevice = udev;
xdev->UsbPdo = pdo;
st = IoRegisterPhysicalDevice(pdo);
if (!KSUCCESS(st) && st != STATUS_ALREADY_EXISTS)
return st;
DbgPrint("usb: created device PDO slot=%u vid=%04x pid=%04x ids=%llu\n",
xdev->SlotId, xdev->VendorId, xdev->ProductId, (unsigned long long)idCount);
return STATUS_SUCCESS;
}
// Creates interface Pdos.
KSTATUS UsbCreateInterfacePdos(USB_HCD* hcd, XHCI_DEVICE* xdev, DEVICE_OBJECT* parent) {
if (!hcd || !xdev || !xdev->UsbDevice) return STATUS_INVALID_PARAMETER;
DEVICE_OBJECT* deviceParent = parent ? parent : xdev->UsbPdo;
if (!deviceParent) return STATUS_INVALID_PARAMETER;
for (uint8_t i = 0; i < xdev->InterfaceCount; i++) {
USB_TRACKED_INTERFACE* iface = &xdev->Interfaces[i];
if (!iface->Present)
continue;
IO_DEVICE_ID ids[3];
char idbuf[3][USB_MAX_DEVICE_ID_TEXT];
size_t idCount = 0;
UsbMakeInterfaceIds(xdev, iface, ids, idbuf, &idCount);
DEVICE_OBJECT* pdo = (DEVICE_OBJECT*)0;
KSTATUS st = IoCreatePhysicalDevice(&gUsbCompositeDriver,
deviceParent,
ids,
idCount,
sizeof(USB_PDO_EXTENSION),
&pdo);
if (!KSUCCESS(st)) {
DbgPrint("usb: create interface PDO slot=%u if=%u failed st=0x%x\n",
xdev->SlotId, iface->Descriptor.bInterfaceNumber, st);
return st;
}
(void)IoSetDeviceName(pdo, SYS_SV_LITERAL("usb-interface"));
USB_PDO_EXTENSION* ext = (USB_PDO_EXTENSION*)pdo->DeviceExtension;
ext->Kind = UsbPdoInterface;
ext->Hcd = hcd;
ext->Device = xdev->UsbDevice;
ext->InterfaceIndex = i;
memcpy(&ext->InterfaceDescriptor, &iface->Descriptor, sizeof(iface->Descriptor));
ext->EndpointCount = iface->EndpointCount;
for (uint8_t ep = 0; ep < iface->EndpointCount && ep < USB_MAX_TRACKED_ENDPOINTS; ep++)
memcpy(&ext->Endpoints[ep], &iface->Endpoints[ep], sizeof(USB_ENDPOINT_DESCRIPTOR));
st = IoRegisterPhysicalDevice(pdo);
if (!KSUCCESS(st) && st != STATUS_ALREADY_EXISTS)
return st;
DbgPrint("usb: created interface PDO slot=%u if=%u class=%02x subclass=%02x proto=%02x\n",
xdev->SlotId,
iface->Descriptor.bInterfaceNumber,
iface->Descriptor.bInterfaceClass,
iface->Descriptor.bInterfaceSubClass,
iface->Descriptor.bInterfaceProtocol);
}
return STATUS_SUCCESS;
}
// Implements the reference First Child operation.
static DEVICE_OBJECT* UsbReferenceFirstChild(DEVICE_OBJECT* parent) {
if (!parent) return (DEVICE_OBJECT*)0;
uintptr_t flags = KeAcquireSpinlock(&parent->Lock);
DEVICE_OBJECT* child = parent->FirstChild;
if (child)
IoReferenceDeviceObject(child);
KeReleaseSpinlock(&parent->Lock, flags);
return child;
}
// Implements the send Pnp If Alive operation.
static void UsbSendPnpIfAlive(DEVICE_OBJECT* pdo, IO_PNP_MINOR_FUNCTION minor) {
if (!pdo || pdo->DeletePending)
return;
(void)IoSendPnpIrpSync(pdo, minor);
}
// Releases device Object Children.
KSTATUS UsbRemoveDeviceObjectChildren(DEVICE_OBJECT* parent, bool surprise) {
if (!parent)
return STATUS_INVALID_PARAMETER;
for (;;) {
DEVICE_OBJECT* child = UsbReferenceFirstChild(parent);
if (!child)
break;
if (child->Type == DeviceObjectPhysical)
(void)UsbRemovePdoSubtree(child, surprise);
else
(void)UsbRemoveDeviceObjectChildren(child, surprise);
IoDereferenceDeviceObject(child);
}
return STATUS_SUCCESS;
}
// Releases pdo Subtree.
KSTATUS UsbRemovePdoSubtree(DEVICE_OBJECT* pdo, bool surprise) {
if (!pdo || pdo->Type != DeviceObjectPhysical)
return STATUS_INVALID_PARAMETER;
// Child PDOs may be owned either directly by the PDO or by an attached FDO
// such as usb-composite or usb-hub. The attached driver's PnP handler is
// therefore responsible for removing its own child PDOs before forwarding
// REMOVE_DEVICE to the lower PDO.
(void)UsbRemoveDeviceObjectChildren(pdo, surprise);
if (surprise)
UsbSendPnpIfAlive(pdo, IRP_MN_SURPRISE_REMOVAL);
UsbSendPnpIfAlive(pdo, IRP_MN_REMOVE_DEVICE);
return STATUS_SUCCESS;
}
// Submits urb To Hcd.
static KSTATUS UsbSubmitUrbToHcd(USB_PDO_EXTENSION* ext, USB_URB* urb) {
if (!ext || !urb) return STATUS_INVALID_PARAMETER;
USB_HCD* hcd = ext->Hcd;
if (!hcd || !hcd->Operations || !hcd->Operations->SubmitUrb)
return STATUS_NOT_SUPPORTED;
if (!urb->Device)
urb->Device = ext->Device;
if (!urb->Device)
return STATUS_INVALID_PARAMETER;
return hcd->Operations->SubmitUrb(hcd, urb);
}
// Cancels urb.
KSTATUS UsbCancelUrb(USB_URB* urb) {
if (!urb || !urb->Device || !urb->Device->Hcd)
return STATUS_INVALID_PARAMETER;
USB_HCD* hcd = urb->Device->Hcd;
if (!hcd->Operations || !hcd->Operations->CancelUrb)
return STATUS_NOT_SUPPORTED;
return hcd->Operations->CancelUrb(hcd, urb);
}
// Submits urb Sync.
KSTATUS UsbSubmitUrbSync(DEVICE_OBJECT* target, USB_URB* urb) {
if (!target || !urb) return STATUS_INVALID_PARAMETER;
IRP irp;
IoInitializeIrp(&irp, 1);
IoBuildDeviceIoControlIrp(&irp,
IRP_MJ_INTERNAL_DEVICE_CONTROL,
USB_IOCTL_SUBMIT_URB,
urb,
sizeof(*urb),
urb,
sizeof(*urb));
KSTATUS st = IoSubmitIrpSync(target, &irp);
return KSUCCESS(st) ? urb->Status : st;
}
// Implements the async Urb Irp Complete operation.
static void UsbAsyncUrbIrpComplete(IRP* irp, void* context) {
(void)context;
IoFreeIrp(irp);
}
// Submits urb Async.
KSTATUS UsbSubmitUrbAsync(DEVICE_OBJECT* target, USB_URB* urb) {
if (!target || !urb) return STATUS_INVALID_PARAMETER;
IRP* irp = (IRP*)0;
KSTATUS st = IoAllocateIrp(1, &irp);
if (!KSUCCESS(st)) return st;
IoBuildDeviceIoControlIrp(irp,
IRP_MJ_INTERNAL_DEVICE_CONTROL,
USB_IOCTL_SUBMIT_URB,
urb,
sizeof(*urb),
urb,
sizeof(*urb));
IoSetCompletionRoutine(irp, UsbAsyncUrbIrpComplete, (void*)0);
st = IoSubmitIrp(target, irp);
if (st != STATUS_PENDING && !(irp->Flags & IRP_FLAG_COMPLETED)) {
IoFreeIrp(irp);
return st;
}
return st;
}
// Dispatches internal Device Control.
KSTATUS UsbDispatchInternalDeviceControl(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp) return STATUS_INVALID_PARAMETER;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios) return STATUS_INVALID_PARAMETER;
if (ios->Parameters.DeviceIoControl.IoControlCode != USB_IOCTL_SUBMIT_URB) {
IoCompleteRequest(irp, STATUS_NOT_SUPPORTED, 0);
return STATUS_PENDING;
}
if (ios->Parameters.DeviceIoControl.InputLength < sizeof(USB_URB) ||
!ios->Parameters.DeviceIoControl.InputBuffer) {
IoCompleteRequest(irp, STATUS_INVALID_PARAMETER, 0);
return STATUS_PENDING;
}
USB_URB* urb = (USB_URB*)ios->Parameters.DeviceIoControl.InputBuffer;
USB_PDO_EXTENSION* ext = (USB_PDO_EXTENSION*)device->DeviceExtension;
urb->Irp = irp;
KSTATUS st = UsbSubmitUrbToHcd(ext, urb);
urb->Status = st;
if (st == STATUS_PENDING) {
urb->Pending = true;
return STATUS_PENDING;
}
urb->Pending = false;
IoCompleteRequest(irp, st, KSUCCESS(st) ? urb->ActualLength : 0);
return STATUS_PENDING;
}
// Dispatches pdo Pnp.
KSTATUS UsbDispatchPdoPnp(DEVICE_OBJECT* device, IRP* irp) {
if (!device || !irp) return STATUS_INVALID_PARAMETER;
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
if (!ios || ios->MajorFunction != IRP_MJ_PNP)
return STATUS_INVALID_PARAMETER;
USB_PDO_EXTENSION* ext = (USB_PDO_EXTENSION*)device->DeviceExtension;
KSTATUS st = STATUS_SUCCESS;
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
case IRP_MN_START_DEVICE:
device->PnpState = DevicePnpStarted;
if (ext && ext->Device && ext->Device->State < UsbDeviceConfigured)
ext->Device->State = UsbDeviceConfigured;
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
device->PnpState = DevicePnpRemovePending;
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
device->PnpState = DevicePnpStarted;
break;
case IRP_MN_SURPRISE_REMOVAL:
device->PnpState = DevicePnpSurpriseRemoved;
if (ext && ext->Device)
ext->Device->State = UsbDeviceSurpriseRemoved;
break;
case IRP_MN_REMOVE_DEVICE:
device->PnpState = DevicePnpDeleted;
if (ext && ext->Device)
ext->Device->State = UsbDeviceRemoved;
IoDeleteDevice(device);
break;
default:
st = STATUS_NOT_SUPPORTED;
break;
}
if (st == STATUS_NOT_SUPPORTED)
return st;
IoCompleteRequest(irp, st, 0);
return STATUS_PENDING;
}