157 lines
6.0 KiB
C
157 lines
6.0 KiB
C
// USB composite driver. This file owns multi-interface device attachment and function handoff.
|
|
|
|
#include "usb.h"
|
|
|
|
DRIVER_OBJECT gUsbCompositeDriver;
|
|
|
|
static const IO_DEVICE_ID gUsbCompositeIds[] = {
|
|
{ IoBusUsb, { "USB\\COMPOSITE", sizeof("USB\\COMPOSITE") - 1 } },
|
|
};
|
|
|
|
static const IO_DRIVER_ID_TABLE gUsbCompositeIdTable = {
|
|
gUsbCompositeIds,
|
|
sizeof(gUsbCompositeIds) / sizeof(gUsbCompositeIds[0]),
|
|
};
|
|
|
|
// Implements the composite Create Interfaces operation.
|
|
static KSTATUS UsbCompositeCreateInterfaces(USB_COMPOSITE_EXTENSION* ext) {
|
|
if (!ext || !ext->Device || ext->InterfacesCreated)
|
|
return NTLSTATUS_SUCCESS;
|
|
|
|
XHCI_DEVICE* xdev = (XHCI_DEVICE*)ext->Device->HcdDeviceContext;
|
|
if (!xdev)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
KSTATUS st = UsbCreateInterfacePdos(ext->Device->Hcd, xdev, ext->Self);
|
|
if (KSUCCESS(st))
|
|
ext->InterfacesCreated = true;
|
|
return st;
|
|
}
|
|
|
|
// Implements the composite Forward Pnp operation.
|
|
static KSTATUS UsbCompositeForwardPnp(DEVICE_OBJECT* device, IRP* irp, KSTATUS localStatus) {
|
|
if (!KSUCCESS(localStatus)) {
|
|
IoCompleteRequest(irp, localStatus, 0);
|
|
return NTLSTATUS_PENDING;
|
|
}
|
|
return IoForwardIrpToLower(device, irp);
|
|
}
|
|
|
|
// Implements the composite Dispatch Pnp operation.
|
|
KSTATUS UsbCompositeDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
|
|
if (!device || !irp)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
// The composite driver owns two different device-object roles:
|
|
// * an FDO attached above a USB device PDO, and
|
|
// * interface PDOs that it creates for class drivers.
|
|
// Forwarded PnP IRPs from HID/storage land on the interface PDO, so the
|
|
// PDO must use the generic USB PDO PnP handler. Treating its
|
|
// USB_PDO_EXTENSION as USB_COMPOSITE_EXTENSION corrupts the dispatch path.
|
|
if (device->Type == DeviceObjectPhysical)
|
|
return UsbDispatchPdoPnp(device, irp);
|
|
|
|
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
|
|
if (!ios || ios->MajorFunction != IRP_MJ_PNP)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
USB_COMPOSITE_EXTENSION* ext = (USB_COMPOSITE_EXTENSION*)device->DeviceExtension;
|
|
KSTATUS st = NTLSTATUS_SUCCESS;
|
|
|
|
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
|
|
case IRP_MN_START_DEVICE:
|
|
device->PnpState = DevicePnpStarted;
|
|
if (ext) {
|
|
if (ext->DevicePdo)
|
|
ext->DevicePdo->PnpState = DevicePnpStarted;
|
|
ext->Started = true;
|
|
st = UsbCompositeCreateInterfaces(ext);
|
|
}
|
|
return UsbCompositeForwardPnp(device, irp, st);
|
|
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
device->PnpState = DevicePnpRemovePending;
|
|
return IoForwardIrpToLower(device, irp);
|
|
|
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
|
device->PnpState = DevicePnpStarted;
|
|
return IoForwardIrpToLower(device, irp);
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL:
|
|
device->PnpState = DevicePnpSurpriseRemoved;
|
|
if (ext)
|
|
ext->Started = false;
|
|
(void)UsbRemoveDeviceObjectChildren(device, true);
|
|
return IoForwardIrpToLower(device, irp);
|
|
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
device->PnpState = DevicePnpDeleted;
|
|
if (ext) {
|
|
ext->Started = false;
|
|
(void)UsbRemoveDeviceObjectChildren(device, false);
|
|
if (ext->LowerDevice) {
|
|
KSTATUS lower = IoForwardIrpToLower(device, irp);
|
|
IoDetachDevice(device);
|
|
ext->LowerDevice = (DEVICE_OBJECT*)0;
|
|
IoDeleteDevice(device);
|
|
if (lower == NTLSTATUS_NOT_SUPPORTED) {
|
|
IoCompleteRequest(irp, NTLSTATUS_SUCCESS, 0);
|
|
return NTLSTATUS_PENDING;
|
|
}
|
|
if (lower != NTLSTATUS_PENDING && !KSUCCESS(lower)) {
|
|
IoCompleteRequest(irp, lower, 0);
|
|
return NTLSTATUS_PENDING;
|
|
}
|
|
return lower;
|
|
}
|
|
}
|
|
IoDeleteDevice(device);
|
|
IoCompleteRequest(irp, NTLSTATUS_SUCCESS, 0);
|
|
return NTLSTATUS_PENDING;
|
|
|
|
default:
|
|
return IoForwardIrpToLower(device, irp);
|
|
}
|
|
}
|
|
|
|
// Implements the composite Add Device operation.
|
|
KSTATUS UsbCompositeAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject) {
|
|
if (!driver || !physicalDeviceObject || physicalDeviceObject->Type != DeviceObjectPhysical)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
USB_PDO_EXTENSION* pdoExt = (USB_PDO_EXTENSION*)physicalDeviceObject->DeviceExtension;
|
|
if (!pdoExt || pdoExt->Kind != UsbPdoDevice || !pdoExt->Device)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
DEVICE_OBJECT* fdo = (DEVICE_OBJECT*)0;
|
|
KSTATUS st = IoCreateDevice(driver, sizeof(USB_COMPOSITE_EXTENSION), &fdo);
|
|
if (!KSUCCESS(st))
|
|
return st;
|
|
|
|
(void)IoSetDeviceName(fdo, SYS_SV_LITERAL("usb-composite"));
|
|
|
|
USB_COMPOSITE_EXTENSION* ext = (USB_COMPOSITE_EXTENSION*)fdo->DeviceExtension;
|
|
ext->Self = fdo;
|
|
ext->DevicePdo = physicalDeviceObject;
|
|
ext->Device = pdoExt->Device;
|
|
ext->LowerDevice = IoAttachDeviceToDeviceStack(fdo, physicalDeviceObject);
|
|
if (!ext->LowerDevice) {
|
|
IoDeleteDevice(fdo);
|
|
return NTLSTATUS_FAILURE;
|
|
}
|
|
|
|
DbgPrint("usb: composite attached slot=%u\n", ext->Device->SlotId);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Initializes composite Driver.
|
|
KSTATUS UsbInitializeCompositeDriver(void) {
|
|
memset(&gUsbCompositeDriver, 0, sizeof(gUsbCompositeDriver));
|
|
IoInitializeDriverObject(&gUsbCompositeDriver, SYS_SV_LITERAL("usb-composite"));
|
|
gUsbCompositeDriver.IdTable = &gUsbCompositeIdTable;
|
|
gUsbCompositeDriver.DriverAddDevice = UsbCompositeAddDevice;
|
|
gUsbCompositeDriver.MajorFunction[IRP_MJ_PNP] = UsbCompositeDispatchPnp;
|
|
gUsbCompositeDriver.MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = UsbDispatchInternalDeviceControl;
|
|
return IoRegisterDriverObject(&gUsbCompositeDriver);
|
|
}
|