diff --git a/usb/wdf_osrfx2_lab/kmdf/inc/prototypes.h b/usb/wdf_osrfx2_lab/kmdf/inc/prototypes.h
index cc99cdfe2..c8347277d 100644
--- a/usb/wdf_osrfx2_lab/kmdf/inc/prototypes.h
+++ b/usb/wdf_osrfx2_lab/kmdf/inc/prototypes.h
@@ -4,6 +4,7 @@ EVT_WDF_DRIVER_DEVICE_ADD EvtDeviceAdd;
EVT_WDF_DEVICE_CONTEXT_CLEANUP EvtDriverContextCleanup;
EVT_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware;
+EVT_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware;
EVT_WDF_IO_QUEUE_IO_READ EvtIoRead;
EVT_WDF_IO_QUEUE_IO_WRITE EvtIoWrite;
diff --git a/usb/wdf_osrfx2_lab/kmdf/step5/osrusbfx2.vcxproj b/usb/wdf_osrfx2_lab/kmdf/step5/osrusbfx2.vcxproj
index eca22cbc7..16b799948 100644
--- a/usb/wdf_osrfx2_lab/kmdf/step5/osrusbfx2.vcxproj
+++ b/usb/wdf_osrfx2_lab/kmdf/step5/osrusbfx2.vcxproj
@@ -111,7 +111,7 @@
%(AdditionalIncludeDirectories);..\inc
- %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib
+ %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;$(DDK_LIB_PATH)\usbdex.lib
sha256
@@ -132,7 +132,7 @@
%(AdditionalIncludeDirectories);..\inc
- %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib
+ %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;$(DDK_LIB_PATH)\usbdex.lib
sha256
@@ -153,7 +153,7 @@
%(AdditionalIncludeDirectories);..\inc
- %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib
+ %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;$(DDK_LIB_PATH)\usbdex.lib
sha256
@@ -174,7 +174,7 @@
%(AdditionalIncludeDirectories);..\inc
- %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib
+ %(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\usbd.lib;$(DDK_LIB_PATH)\usbdex.lib
sha256
diff --git a/usb/wdf_osrfx2_lab/kmdf/step5/step5.c b/usb/wdf_osrfx2_lab/kmdf/step5/step5.c
index fa5807416..44a79dc52 100644
--- a/usb/wdf_osrfx2_lab/kmdf/step5/step5.c
+++ b/usb/wdf_osrfx2_lab/kmdf/step5/step5.c
@@ -1,7 +1,8 @@
/*++
-Step4: This steps shows:
+Step5: This step shows:
1) How to map KdPrint function to do WPP tracing
+ 2) Demonstrates additional USB DDI coverage for usbdlib.h and wdfusb.h
--*/
#include // To avoid build errors on Win2K due to WPP
@@ -15,28 +16,164 @@ Step4: This steps shows:
#include "step5.tmh"
+#define POOL_TAG 'RsoU' // 'UsoR' — OSRUSBFX2 pool tag
+
DEFINE_GUID(GUID_DEVINTERFACE_OSRUSBFX2, // Generated using guidgen.exe
0x573e8c73, 0xcb4, 0x4471, 0xa1, 0xbf, 0xfa, 0xb2, 0x6c, 0x31, 0xd3, 0x84);
// {573E8C73-0CB4-4471-A1BF-FAB26C31D384}
#define IOCTL_INDEX 0x800
#define FILE_DEVICE_OSRUSBFX2 65500U
-#define USBFX2LK_SET_BARGRAPH_DISPLAY 0xD8
+#define USBFX2LK_READ_7SEGMENT_DISPLAY 0xD4
+#define USBFX2LK_READ_SWITCHES 0xD6
+#define USBFX2LK_READ_BARGRAPH_DISPLAY 0xD7
+#define USBFX2LK_SET_BARGRAPH_DISPLAY 0xD8
+#define USBFX2LK_REENUMERATE 0xDA
+#define USBFX2LK_SET_7SEGMENT_DISPLAY 0xDB
#define BULK_OUT_ENDPOINT_INDEX 1
#define BULK_IN_ENDPOINT_INDEX 2
+
+#include
+typedef struct _BAR_GRAPH_STATE {
+ union {
+ struct {
+ UCHAR Bar1 : 1;
+ UCHAR Bar2 : 1;
+ UCHAR Bar3 : 1;
+ UCHAR Bar4 : 1;
+ UCHAR Bar5 : 1;
+ UCHAR Bar6 : 1;
+ UCHAR Bar7 : 1;
+ UCHAR Bar8 : 1;
+ };
+ UCHAR BarsAsUChar;
+ };
+} BAR_GRAPH_STATE, *PBAR_GRAPH_STATE;
+
+typedef struct _SWITCH_STATE {
+ union {
+ struct {
+ UCHAR Switch1 : 1;
+ UCHAR Switch2 : 1;
+ UCHAR Switch3 : 1;
+ UCHAR Switch4 : 1;
+ UCHAR Switch5 : 1;
+ UCHAR Switch6 : 1;
+ UCHAR Switch7 : 1;
+ UCHAR Switch8 : 1;
+ };
+ UCHAR SwitchesAsUChar;
+ };
+} SWITCH_STATE, *PSWITCH_STATE;
+#include
+
+#define IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX, \
+ METHOD_BUFFERED, \
+ FILE_READ_ACCESS)
+
+#define IOCTL_OSRUSBFX2_RESET_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 1, \
+ METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+
+#define IOCTL_OSRUSBFX2_REENUMERATE_DEVICE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 3, \
+ METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+
+#define IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 4, \
+ METHOD_BUFFERED, \
+ FILE_READ_ACCESS)
+
#define IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
IOCTL_INDEX + 5, \
METHOD_BUFFERED, \
FILE_WRITE_ACCESS)
+
+#define IOCTL_OSRUSBFX2_READ_SWITCHES CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 6, \
+ METHOD_BUFFERED, \
+ FILE_READ_ACCESS)
+
+#define IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 7, \
+ METHOD_BUFFERED, \
+ FILE_READ_ACCESS)
+
+#define IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 8, \
+ METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+
+#define IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 9, \
+ METHOD_OUT_DIRECT, \
+ FILE_READ_ACCESS)
+
+//
+// Additional IOCTLs to demonstrate uncovered USB DDI usage.
+//
+#define IOCTL_OSRUSBFX2_GET_USB_STATUS CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 20, \
+ METHOD_BUFFERED, \
+ FILE_READ_ACCESS)
+
+#define IOCTL_OSRUSBFX2_SET_FEATURE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 21, \
+ METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+
+#define IOCTL_OSRUSBFX2_CLEAR_FEATURE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 22, \
+ METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+
+#define IOCTL_OSRUSBFX2_GET_STRING CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 23, \
+ METHOD_BUFFERED, \
+ FILE_READ_ACCESS)
+
+#define IOCTL_OSRUSBFX2_CYCLE_PORT CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 24, \
+ METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+
+#define IOCTL_OSRUSBFX2_RESET_PIPE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 25, \
+ METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+
+#define IOCTL_OSRUSBFX2_ABORT_PIPE CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 26, \
+ METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+
+#define IOCTL_OSRUSBFX2_WRITE_SYNC CTL_CODE(FILE_DEVICE_OSRUSBFX2,\
+ IOCTL_INDEX + 27, \
+ METHOD_BUFFERED, \
+ FILE_WRITE_ACCESS)
+
typedef struct _DEVICE_CONTEXT {
WDFUSBDEVICE UsbDevice;
WDFUSBINTERFACE UsbInterface;
WDFUSBPIPE BulkReadPipe;
WDFUSBPIPE BulkWritePipe;
+ USBD_HANDLE UsbdHandle;
} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext)
+//
+// Forward declaration for helper routine defined later in this file.
+//
+VOID
+OsrFxDemonstrateUrbDdis(
+ IN WDFDEVICE Device,
+ IN PDEVICE_CONTEXT pDeviceContext
+ );
+
NTSTATUS
DriverEntry(
@@ -108,6 +245,7 @@ EvtDeviceAdd(
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
pnpPowerCallbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware;
+ pnpPowerCallbacks.EvtDeviceReleaseHardware = EvtDeviceReleaseHardware;
WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);
@@ -204,6 +342,17 @@ EvtDevicePrepareHardware(
pDeviceContext->UsbInterface =
configParams.Types.SingleInterface.ConfiguredUsbInterface;
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbInterfaceGetNumEndpoints ----
+ // Query the number of endpoints on the current alternate setting.
+ //
+ {
+ BYTE numEndpoints;
+ numEndpoints = WdfUsbInterfaceGetNumEndpoints(
+ pDeviceContext->UsbInterface,
+ 0); // setting index 0
+ KdPrint(("Number of endpoints: %d\n", numEndpoints));
+ }
pDeviceContext->BulkReadPipe = WdfUsbInterfaceGetConfiguredPipe(
pDeviceContext->UsbInterface,
@@ -219,6 +368,285 @@ EvtDevicePrepareHardware(
WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pDeviceContext->BulkWritePipe);
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbInterfaceGetEndpointInformation ----
+ // Retrieve endpoint information for each configured endpoint.
+ //
+ {
+ BYTE i;
+ BYTE numEp;
+ numEp = WdfUsbInterfaceGetNumEndpoints(
+ pDeviceContext->UsbInterface, 0);
+ for (i = 0; i < numEp; i++) {
+ WDF_USB_PIPE_INFORMATION pipeInfo;
+ WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo);
+ WdfUsbInterfaceGetEndpointInformation(
+ pDeviceContext->UsbInterface,
+ 0, // setting index
+ i, // endpoint index
+ &pipeInfo);
+ KdPrint(("Endpoint %d: MaxPacketSize=%d, type=%d\n",
+ i, pipeInfo.MaximumPacketSize, pipeInfo.PipeType));
+ }
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbTargetPipeGetType ----
+ // Demonstrate querying pipe type for the bulk read and write pipes.
+ //
+ {
+ WDF_USB_PIPE_TYPE readPipeType;
+ WDF_USB_PIPE_TYPE writePipeType;
+ readPipeType = WdfUsbTargetPipeGetType(pDeviceContext->BulkReadPipe);
+ writePipeType = WdfUsbTargetPipeGetType(pDeviceContext->BulkWritePipe);
+ KdPrint(("Read pipe type: %d, Write pipe type: %d\n",
+ readPipeType, writePipeType));
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WDF_USB_PIPE_DIRECTION_IN / _OUT ----
+ // Verify pipe directions using the direction helper macros.
+ //
+ {
+ WDF_USB_PIPE_INFORMATION readPipeInfo, writePipeInfo;
+ WDF_USB_PIPE_INFORMATION_INIT(&readPipeInfo);
+ WDF_USB_PIPE_INFORMATION_INIT(&writePipeInfo);
+ WdfUsbInterfaceGetEndpointInformation(
+ pDeviceContext->UsbInterface, 0, BULK_IN_ENDPOINT_INDEX, &readPipeInfo);
+ WdfUsbInterfaceGetEndpointInformation(
+ pDeviceContext->UsbInterface, 0, BULK_OUT_ENDPOINT_INDEX, &writePipeInfo);
+
+ if (WDF_USB_PIPE_DIRECTION_IN(readPipeInfo.EndpointAddress)) {
+ KdPrint(("Read pipe confirmed as IN direction\n"));
+ }
+ if (WDF_USB_PIPE_DIRECTION_OUT(writePipeInfo.EndpointAddress)) {
+ KdPrint(("Write pipe confirmed as OUT direction\n"));
+ }
+ }
+
+ //
+ // ---- usbdlib.h DDI coverage: USBD_IsInterfaceVersionSupported ----
+ // Check if the USB driver stack supports USBD interface version 602.
+ //
+ {
+ USBD_HANDLE usbdHandle;
+ usbdHandle = NULL;
+ status = USBD_CreateHandle(WdfDeviceWdmGetDeviceObject(Device),
+ WdfDeviceWdmGetAttachedDevice(Device),
+ USBD_CLIENT_CONTRACT_VERSION_602,
+ POOL_TAG,
+ &usbdHandle);
+ if (NT_SUCCESS(status)) {
+ BOOLEAN supported;
+ supported = USBD_IsInterfaceVersionSupported(usbdHandle,
+ USBD_INTERFACE_VERSION_602);
+ KdPrint(("USBD interface version 602 supported: %d\n", supported));
+ pDeviceContext->UsbdHandle = usbdHandle;
+ } else {
+ KdPrint(("USBD_CreateHandle failed %!STATUS!\n", status));
+ pDeviceContext->UsbdHandle = NULL;
+ //
+ // Non-fatal: continue even without a USBD handle.
+ //
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // ---- usbdlib.h DDI coverage: USBD_GetPdoRegistryParameter ----
+ // Read a sample registry parameter from the device's hardware key.
+ //
+ {
+ ULONG regValue = 0;
+ NTSTATUS regStatus;
+ DECLARE_CONST_UNICODE_STRING(regKeyName, L"SampleValue");
+ regStatus = USBD_GetPdoRegistryParameter(
+ WdfDeviceWdmGetPhysicalDevice(Device),
+ ®Value,
+ sizeof(regValue),
+ (PWSTR)regKeyName.Buffer,
+ regKeyName.Length);
+ if (NT_SUCCESS(regStatus)) {
+ KdPrint(("PDO registry value: %lu\n", regValue));
+ } else {
+ KdPrint(("USBD_GetPdoRegistryParameter returned %!STATUS! (expected)\n",
+ regStatus));
+ }
+ }
+
+ //
+ // ---- usbdlib.h DDI coverage: WdfUsbTargetDeviceWdmGetConfigurationHandle ----
+ // Retrieve the WDM USBD configuration handle.
+ //
+ {
+ USBD_CONFIGURATION_HANDLE configHandle;
+ configHandle = WdfUsbTargetDeviceWdmGetConfigurationHandle(
+ pDeviceContext->UsbDevice);
+ KdPrint(("WDM Configuration handle: %p\n", configHandle));
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbTargetDeviceAllocAndQueryString ----
+ // Query the product string descriptor from the device.
+ //
+ {
+ WDFMEMORY stringMem = NULL;
+ USHORT numChars = 0;
+ NTSTATUS strStatus;
+ strStatus = WdfUsbTargetDeviceAllocAndQueryString(
+ pDeviceContext->UsbDevice,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &stringMem,
+ &numChars,
+ 2, // String descriptor index (typically product string)
+ 0x0409); // LANGID: English (US)
+ if (NT_SUCCESS(strStatus) && stringMem != NULL) {
+ KdPrint(("Product string length: %d chars\n", numChars));
+ WdfObjectDelete(stringMem);
+ } else {
+ KdPrint(("WdfUsbTargetDeviceAllocAndQueryString returned %!STATUS!\n",
+ strStatus));
+ }
+ }
+
+ //
+ // ---- usbdlib.h DDI coverage: USBD_GetInterfaceLength ----
+ // Demonstrate parsing an interface descriptor to get its total length.
+ //
+ {
+ PUSB_CONFIGURATION_DESCRIPTOR configDesc;
+ USHORT configDescSize;
+ NTSTATUS descStatus;
+ WDF_USB_DEVICE_INFORMATION deviceInfo;
+
+ WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo);
+ descStatus = WdfUsbTargetDeviceRetrieveInformation(
+ pDeviceContext->UsbDevice, &deviceInfo);
+ if (NT_SUCCESS(descStatus)) {
+ descStatus = WdfUsbTargetDeviceRetrieveConfigDescriptor(
+ pDeviceContext->UsbDevice, NULL, &configDescSize);
+ if (descStatus == STATUS_BUFFER_TOO_SMALL && configDescSize > 0) {
+ configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)
+ ExAllocatePool2(POOL_FLAG_NON_PAGED, configDescSize, POOL_TAG);
+ if (configDesc != NULL) {
+ descStatus = WdfUsbTargetDeviceRetrieveConfigDescriptor(
+ pDeviceContext->UsbDevice,
+ configDesc,
+ &configDescSize);
+ if (NT_SUCCESS(descStatus)) {
+ //
+ // Find the first interface descriptor and get its length.
+ //
+ PUSB_INTERFACE_DESCRIPTOR ifaceDesc;
+ ifaceDesc = USBD_ParseConfigurationDescriptorEx(
+ configDesc,
+ configDesc,
+ -1, // InterfaceNumber (any)
+ -1, // AlternateSetting (any)
+ -1, -1, -1); // Class, SubClass, Protocol
+ if (ifaceDesc != NULL) {
+ ULONG ifaceLength;
+ ifaceLength = USBD_GetInterfaceLength(
+ ifaceDesc,
+ (PUCHAR)configDesc + configDescSize);
+ KdPrint(("Interface descriptor length: %lu\n",
+ ifaceLength));
+
+ //
+ // ---- usbdlib.h DDI coverage: USBD_CreateConfigurationRequestEx ----
+ // Build a configuration request URB from the parsed descriptor.
+ //
+ {
+ PUSBD_INTERFACE_LIST_ENTRY ifaceList;
+ PURB configUrb;
+ ifaceList = (PUSBD_INTERFACE_LIST_ENTRY)
+ ExAllocatePool2(POOL_FLAG_NON_PAGED,
+ sizeof(USBD_INTERFACE_LIST_ENTRY) * 2,
+ POOL_TAG);
+ if (ifaceList != NULL) {
+ ifaceList[0].InterfaceDescriptor = ifaceDesc;
+ ifaceList[0].Interface = NULL;
+ ifaceList[1].InterfaceDescriptor = NULL;
+ ifaceList[1].Interface = NULL;
+
+ configUrb = USBD_CreateConfigurationRequestEx(
+ configDesc, ifaceList);
+ if (configUrb != NULL) {
+ KdPrint(("USBD_CreateConfigurationRequestEx "
+ "URB created, length=%lu\n",
+ configUrb->UrbHeader.Length));
+ ExFreePoolWithTag(configUrb, 0);
+ }
+ ExFreePoolWithTag(ifaceList, POOL_TAG);
+ }
+ }
+ }
+ }
+ ExFreePoolWithTag(configDesc, POOL_TAG);
+ }
+ }
+ }
+ }
+
+ //
+ // ---- usbdlib.h DDI coverage: GET_ISO_URB_SIZE, UsbBuildGetStatusRequest,
+ // UsbBuildInterruptOrBulkTransferRequest ----
+ // Demonstrate the macro-based URB builders (build URBs but do not submit).
+ //
+ {
+ //
+ // GET_ISO_URB_SIZE: Calculate the size needed for an isochronous URB.
+ //
+ ULONG isoUrbSize;
+ isoUrbSize = GET_ISO_URB_SIZE(8); // 8 packets
+ KdPrint(("ISO URB size for 8 packets: %lu bytes\n", isoUrbSize));
+ }
+
+ {
+ //
+ // UsbBuildGetStatusRequest: Format a URB to get device status.
+ //
+ URB statusUrb;
+ USHORT usbStatus = 0;
+ RtlZeroMemory(&statusUrb, sizeof(URB));
+ UsbBuildGetStatusRequest(
+ &statusUrb,
+ URB_FUNCTION_GET_STATUS_FROM_DEVICE,
+ 0, // Index
+ &usbStatus,
+ NULL, // Link
+ NULL); // TransferFlags not used by this macro
+ KdPrint(("UsbBuildGetStatusRequest: URB function=0x%x, length=%d\n",
+ statusUrb.UrbHeader.Function,
+ statusUrb.UrbHeader.Length));
+ }
+
+ {
+ //
+ // UsbBuildInterruptOrBulkTransferRequest: Format a bulk transfer URB.
+ //
+ URB bulkUrb;
+ UCHAR dummyBuffer[64];
+ RtlZeroMemory(&bulkUrb, sizeof(URB));
+ RtlZeroMemory(dummyBuffer, sizeof(dummyBuffer));
+ UsbBuildInterruptOrBulkTransferRequest(
+ &bulkUrb,
+ sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+ NULL, // PipeHandle — NULL since we're just demonstrating the build
+ dummyBuffer,
+ NULL, // TransferBufferMDL
+ sizeof(dummyBuffer),
+ USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
+ NULL); // Link
+ KdPrint(("UsbBuildInterruptOrBulkTransferRequest: URB function=0x%x\n",
+ bulkUrb.UrbHeader.Function));
+ }
+
+ //
+ // Call helper to demonstrate URB-based DDIs from usbdlib.h and wdfusb.h.
+ //
+ OsrFxDemonstrateUrbDdis(Device, pDeviceContext);
+
return status;
}
@@ -294,6 +722,564 @@ EvtIoDeviceControl(
}
break;
+ //
+ // ---- wdfusb.h DDI coverage: WDF_USB_CONTROL_SETUP_PACKET_INIT_GET_STATUS ----
+ // Retrieve the USB device status (2 bytes per USB spec).
+ //
+ case IOCTL_OSRUSBFX2_GET_USB_STATUS:
+ {
+ WDF_USB_CONTROL_SETUP_PACKET statusPacket;
+ USHORT usbDeviceStatus = 0;
+ WDF_MEMORY_DESCRIPTOR statusMemDesc;
+
+ if (OutputBufferLength < sizeof(USHORT)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ WDF_USB_CONTROL_SETUP_PACKET_INIT_GET_STATUS(
+ &statusPacket,
+ BmRequestToDevice,
+ 0); // Index
+
+ WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&statusMemDesc,
+ &usbDeviceStatus,
+ sizeof(usbDeviceStatus));
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(500));
+
+ status = WdfUsbTargetDeviceSendControlTransferSynchronously(
+ pDevContext->UsbDevice, NULL, &sendOptions,
+ &statusPacket, &statusMemDesc,
+ (PULONG)&bytesTransferred);
+ if (NT_SUCCESS(status)) {
+ //
+ // Copy the status back to the output buffer.
+ //
+ PUSHORT outputBuf;
+ NTSTATUS bufStatus;
+ bufStatus = WdfRequestRetrieveOutputBuffer(
+ Request, sizeof(USHORT), (PVOID*)&outputBuf, NULL);
+ if (NT_SUCCESS(bufStatus)) {
+ *outputBuf = usbDeviceStatus;
+ bytesTransferred = sizeof(USHORT);
+ }
+ KdPrint(("USB device status: 0x%04X\n", usbDeviceStatus));
+ }
+ break;
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE ----
+ // Send a SET_FEATURE request to the device.
+ //
+ case IOCTL_OSRUSBFX2_SET_FEATURE:
+ {
+ WDF_USB_CONTROL_SETUP_PACKET featurePacket;
+ USHORT featureSelector = 0;
+ PUSHORT inputBuf;
+
+ if (InputBufferLength < sizeof(USHORT)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = WdfRequestRetrieveInputBuffer(
+ Request, sizeof(USHORT), (PVOID*)&inputBuf, NULL);
+ if (!NT_SUCCESS(status)) break;
+ featureSelector = *inputBuf;
+
+ WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE(
+ &featurePacket,
+ BmRequestToDevice,
+ featureSelector,
+ 0, // Index
+ TRUE); // SetFeature = TRUE
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(500));
+
+ status = WdfUsbTargetDeviceSendControlTransferSynchronously(
+ pDevContext->UsbDevice, NULL, &sendOptions,
+ &featurePacket, NULL, NULL);
+ KdPrint(("SET_FEATURE(%d) %!STATUS!\n", featureSelector, status));
+ break;
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE ----
+ // Send a CLEAR_FEATURE request (SetFeature = FALSE).
+ //
+ case IOCTL_OSRUSBFX2_CLEAR_FEATURE:
+ {
+ WDF_USB_CONTROL_SETUP_PACKET clearPacket;
+ USHORT featureSelector = 0;
+ PUSHORT inputBuf;
+
+ if (InputBufferLength < sizeof(USHORT)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = WdfRequestRetrieveInputBuffer(
+ Request, sizeof(USHORT), (PVOID*)&inputBuf, NULL);
+ if (!NT_SUCCESS(status)) break;
+ featureSelector = *inputBuf;
+
+ WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE(
+ &clearPacket,
+ BmRequestToDevice,
+ featureSelector,
+ 0, // Index
+ FALSE); // SetFeature = FALSE => CLEAR_FEATURE
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(500));
+
+ status = WdfUsbTargetDeviceSendControlTransferSynchronously(
+ pDevContext->UsbDevice, NULL, &sendOptions,
+ &clearPacket, NULL, NULL);
+ KdPrint(("CLEAR_FEATURE(%d) %!STATUS!\n", featureSelector, status));
+ break;
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbTargetDeviceFormatRequestForString ----
+ // Asynchronously retrieve a USB string descriptor.
+ //
+ case IOCTL_OSRUSBFX2_GET_STRING:
+ {
+ WDFMEMORY outputMem;
+ WDFREQUEST stringRequest;
+ WDF_OBJECT_ATTRIBUTES reqAttributes;
+
+ if (OutputBufferLength < sizeof(WCHAR)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = WdfRequestRetrieveOutputMemory(Request, &outputMem);
+ if (!NT_SUCCESS(status)) break;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&reqAttributes);
+ reqAttributes.ParentObject = device;
+ status = WdfRequestCreate(&reqAttributes,
+ WdfUsbTargetDeviceGetIoTarget(pDevContext->UsbDevice),
+ &stringRequest);
+ if (!NT_SUCCESS(status)) break;
+
+ status = WdfUsbTargetDeviceFormatRequestForString(
+ pDevContext->UsbDevice,
+ stringRequest,
+ outputMem,
+ NULL, // Offset
+ 2, // StringIndex (product string)
+ 0x0409); // LANGID: English (US)
+ if (NT_SUCCESS(status)) {
+ //
+ // Send synchronously for simplicity in this demo.
+ //
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_SYNCHRONOUS |
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(1000));
+ if (WdfRequestSend(stringRequest,
+ WdfUsbTargetDeviceGetIoTarget(pDevContext->UsbDevice),
+ &sendOptions)) {
+ status = WdfRequestGetStatus(stringRequest);
+ if (NT_SUCCESS(status)) {
+ bytesTransferred = WdfRequestGetInformation(stringRequest);
+ }
+ } else {
+ status = WdfRequestGetStatus(stringRequest);
+ }
+ KdPrint(("FormatRequestForString: %!STATUS!, %Iu bytes\n",
+ status, bytesTransferred));
+ }
+ WdfObjectDelete(stringRequest);
+ break;
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbTargetDeviceFormatRequestForCyclePort ----
+ // Cycle the USB port (simulates unplug/replug).
+ //
+ case IOCTL_OSRUSBFX2_CYCLE_PORT:
+ {
+ WDFREQUEST cycleRequest;
+ WDF_OBJECT_ATTRIBUTES reqAttributes;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&reqAttributes);
+ reqAttributes.ParentObject = device;
+ status = WdfRequestCreate(&reqAttributes,
+ WdfUsbTargetDeviceGetIoTarget(pDevContext->UsbDevice),
+ &cycleRequest);
+ if (!NT_SUCCESS(status)) break;
+
+ status = WdfUsbTargetDeviceFormatRequestForCyclePort(
+ pDevContext->UsbDevice, cycleRequest);
+ if (NT_SUCCESS(status)) {
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_SYNCHRONOUS |
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(5000));
+ if (WdfRequestSend(cycleRequest,
+ WdfUsbTargetDeviceGetIoTarget(pDevContext->UsbDevice),
+ &sendOptions)) {
+ status = WdfRequestGetStatus(cycleRequest);
+ } else {
+ status = WdfRequestGetStatus(cycleRequest);
+ }
+ }
+ KdPrint(("CyclePort: %!STATUS!\n", status));
+ WdfObjectDelete(cycleRequest);
+ break;
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbTargetPipeFormatRequestForReset ----
+ // Reset the bulk read pipe.
+ //
+ case IOCTL_OSRUSBFX2_RESET_PIPE:
+ {
+ WDFREQUEST resetRequest;
+ WDF_OBJECT_ATTRIBUTES reqAttributes;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&reqAttributes);
+ reqAttributes.ParentObject = device;
+ status = WdfRequestCreate(&reqAttributes,
+ WdfUsbTargetPipeGetIoTarget(pDevContext->BulkReadPipe),
+ &resetRequest);
+ if (!NT_SUCCESS(status)) break;
+
+ status = WdfUsbTargetPipeFormatRequestForReset(
+ pDevContext->BulkReadPipe, resetRequest);
+ if (NT_SUCCESS(status)) {
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_SYNCHRONOUS |
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(2000));
+ if (WdfRequestSend(resetRequest,
+ WdfUsbTargetPipeGetIoTarget(pDevContext->BulkReadPipe),
+ &sendOptions)) {
+ status = WdfRequestGetStatus(resetRequest);
+ } else {
+ status = WdfRequestGetStatus(resetRequest);
+ }
+ }
+ KdPrint(("ResetPipe: %!STATUS!\n", status));
+ WdfObjectDelete(resetRequest);
+ break;
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbTargetPipeFormatRequestForAbort ----
+ // Abort pending transfers on the bulk read pipe.
+ //
+ case IOCTL_OSRUSBFX2_ABORT_PIPE:
+ {
+ WDFREQUEST abortRequest;
+ WDF_OBJECT_ATTRIBUTES reqAttributes;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&reqAttributes);
+ reqAttributes.ParentObject = device;
+ status = WdfRequestCreate(&reqAttributes,
+ WdfUsbTargetPipeGetIoTarget(pDevContext->BulkReadPipe),
+ &abortRequest);
+ if (!NT_SUCCESS(status)) break;
+
+ status = WdfUsbTargetPipeFormatRequestForAbort(
+ pDevContext->BulkReadPipe, abortRequest);
+ if (NT_SUCCESS(status)) {
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_SYNCHRONOUS |
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(2000));
+ if (WdfRequestSend(abortRequest,
+ WdfUsbTargetPipeGetIoTarget(pDevContext->BulkReadPipe),
+ &sendOptions)) {
+ status = WdfRequestGetStatus(abortRequest);
+ } else {
+ status = WdfRequestGetStatus(abortRequest);
+ }
+ }
+ KdPrint(("AbortPipe: %!STATUS!\n", status));
+ WdfObjectDelete(abortRequest);
+ break;
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbTargetPipeWriteSynchronously ----
+ // Synchronous write to the bulk write pipe with a timeout.
+ //
+ case IOCTL_OSRUSBFX2_WRITE_SYNC:
+ {
+ WDF_MEMORY_DESCRIPTOR writeMemDesc;
+
+ if (InputBufferLength == 0) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = WdfRequestRetrieveInputMemory(Request, &memory);
+ if (!NT_SUCCESS(status)) break;
+
+ WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&writeMemDesc, memory, NULL);
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(1000));
+
+ status = WdfUsbTargetPipeWriteSynchronously(
+ pDevContext->BulkWritePipe,
+ NULL, // Optional WDFREQUEST
+ &sendOptions,
+ &writeMemDesc,
+ (PULONG)&bytesTransferred);
+ KdPrint(("WriteSynchronously: %!STATUS!, %Iu bytes\n",
+ status, bytesTransferred));
+ break;
+ }
+
+ //
+ // ---- Standard test app IOCTLs ----
+ //
+
+ case IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR:
+ {
+ PUSB_CONFIGURATION_DESCRIPTOR configDesc = NULL;
+ USHORT requiredSize = 0;
+
+ status = WdfUsbTargetDeviceRetrieveConfigDescriptor(
+ pDevContext->UsbDevice, NULL, &requiredSize);
+ if (status != STATUS_BUFFER_TOO_SMALL) {
+ KdPrint(("RetrieveConfigDescriptor failed %!STATUS!\n", status));
+ break;
+ }
+
+ status = WdfRequestRetrieveOutputBuffer(Request,
+ (size_t)requiredSize, (PVOID*)&configDesc, NULL);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("Output buffer too small for config descriptor\n"));
+ break;
+ }
+
+ status = WdfUsbTargetDeviceRetrieveConfigDescriptor(
+ pDevContext->UsbDevice, configDesc, &requiredSize);
+ if (NT_SUCCESS(status)) {
+ bytesTransferred = requiredSize;
+ }
+ break;
+ }
+
+ case IOCTL_OSRUSBFX2_RESET_DEVICE:
+ status = WdfUsbTargetDeviceResetPortSynchronously(pDevContext->UsbDevice);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("ResetDevice failed %!STATUS!\n", status));
+ }
+ break;
+
+ case IOCTL_OSRUSBFX2_REENUMERATE_DEVICE:
+ {
+ WDF_USB_CONTROL_SETUP_PACKET reenumPacket;
+
+ WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&reenumPacket,
+ BmRequestHostToDevice,
+ BmRequestToDevice,
+ USBFX2LK_REENUMERATE,
+ 0, 0);
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(5000));
+
+ status = WdfUsbTargetDeviceSendControlTransferSynchronously(
+ pDevContext->UsbDevice, NULL, &sendOptions,
+ &reenumPacket, NULL, NULL);
+ KdPrint(("Reenumerate: %!STATUS!\n", status));
+ break;
+ }
+
+ case IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY:
+ {
+ PBAR_GRAPH_STATE barGraphState;
+ WDF_MEMORY_DESCRIPTOR barMemDesc;
+ ULONG transferred;
+
+ if (OutputBufferLength < sizeof(BAR_GRAPH_STATE)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = WdfRequestRetrieveOutputBuffer(Request,
+ sizeof(BAR_GRAPH_STATE), (PVOID*)&barGraphState, NULL);
+ if (!NT_SUCCESS(status)) break;
+
+ barGraphState->BarsAsUChar = 0;
+
+ WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
+ BmRequestDeviceToHost,
+ BmRequestToDevice,
+ USBFX2LK_READ_BARGRAPH_DISPLAY,
+ 0, 0);
+
+ WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&barMemDesc,
+ barGraphState, sizeof(BAR_GRAPH_STATE));
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(500));
+
+ status = WdfUsbTargetDeviceSendControlTransferSynchronously(
+ pDevContext->UsbDevice, NULL, &sendOptions,
+ &controlSetupPacket, &barMemDesc, &transferred);
+ if (NT_SUCCESS(status)) {
+ bytesTransferred = sizeof(BAR_GRAPH_STATE);
+ KdPrint(("GetBarGraph: 0x%x\n", barGraphState->BarsAsUChar));
+ }
+ break;
+ }
+
+ case IOCTL_OSRUSBFX2_READ_SWITCHES:
+ {
+ PSWITCH_STATE switchState;
+ WDF_MEMORY_DESCRIPTOR switchMemDesc;
+ ULONG transferred;
+
+ if (OutputBufferLength < sizeof(SWITCH_STATE)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = WdfRequestRetrieveOutputBuffer(Request,
+ sizeof(SWITCH_STATE), (PVOID*)&switchState, NULL);
+ if (!NT_SUCCESS(status)) break;
+
+ switchState->SwitchesAsUChar = 0;
+
+ WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
+ BmRequestDeviceToHost,
+ BmRequestToDevice,
+ USBFX2LK_READ_SWITCHES,
+ 0, 0);
+
+ WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&switchMemDesc,
+ switchState, sizeof(SWITCH_STATE));
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(500));
+
+ status = WdfUsbTargetDeviceSendControlTransferSynchronously(
+ pDevContext->UsbDevice, NULL, &sendOptions,
+ &controlSetupPacket, &switchMemDesc, &transferred);
+ if (NT_SUCCESS(status)) {
+ bytesTransferred = sizeof(SWITCH_STATE);
+ KdPrint(("ReadSwitches: 0x%x\n", switchState->SwitchesAsUChar));
+ }
+ break;
+ }
+
+ case IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY:
+ {
+ PUCHAR sevenSegment;
+ WDF_MEMORY_DESCRIPTOR segMemDesc;
+ ULONG transferred;
+
+ if (OutputBufferLength < sizeof(UCHAR)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = WdfRequestRetrieveOutputBuffer(Request,
+ sizeof(UCHAR), (PVOID*)&sevenSegment, NULL);
+ if (!NT_SUCCESS(status)) break;
+
+ *sevenSegment = 0;
+
+ WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
+ BmRequestDeviceToHost,
+ BmRequestToDevice,
+ USBFX2LK_READ_7SEGMENT_DISPLAY,
+ 0, 0);
+
+ WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&segMemDesc,
+ sevenSegment, sizeof(UCHAR));
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(500));
+
+ status = WdfUsbTargetDeviceSendControlTransferSynchronously(
+ pDevContext->UsbDevice, NULL, &sendOptions,
+ &controlSetupPacket, &segMemDesc, &transferred);
+ if (NT_SUCCESS(status)) {
+ bytesTransferred = sizeof(UCHAR);
+ KdPrint(("Get7Segment: 0x%x\n", *sevenSegment));
+ }
+ break;
+ }
+
+ case IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY:
+ {
+ PUCHAR sevenSegment;
+ WDF_MEMORY_DESCRIPTOR segMemDesc;
+ ULONG transferred;
+
+ if (InputBufferLength < sizeof(UCHAR)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = WdfRequestRetrieveInputBuffer(Request,
+ sizeof(UCHAR), (PVOID*)&sevenSegment, NULL);
+ if (!NT_SUCCESS(status)) break;
+
+ WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
+ BmRequestHostToDevice,
+ BmRequestToDevice,
+ USBFX2LK_SET_7SEGMENT_DISPLAY,
+ 0, 0);
+
+ WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&segMemDesc,
+ sevenSegment, sizeof(UCHAR));
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(500));
+
+ status = WdfUsbTargetDeviceSendControlTransferSynchronously(
+ pDevContext->UsbDevice, NULL, &sendOptions,
+ &controlSetupPacket, &segMemDesc, &transferred);
+ KdPrint(("Set7Segment: %!STATUS!\n", status));
+ break;
+ }
+
+ case IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE:
+ //
+ // The interrupt message IOCTL requires an interrupt endpoint queue.
+ // For simplicity, complete with STATUS_NOT_SUPPORTED.
+ //
+ status = STATUS_NOT_SUPPORTED;
+ KdPrint(("GET_INTERRUPT_MESSAGE: not implemented in step5\n"));
+ break;
+
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
@@ -477,3 +1463,366 @@ EvtRequestWriteCompletionRoutine(
return;
}
+
+//
+// EvtDeviceReleaseHardware: Clean up USBD handle and demonstrate remaining DDIs.
+//
+NTSTATUS
+EvtDeviceReleaseHardware(
+ IN WDFDEVICE Device,
+ IN WDFCMRESLIST ResourceListTranslated
+ )
+{
+ PDEVICE_CONTEXT pDeviceContext;
+
+ UNREFERENCED_PARAMETER(ResourceListTranslated);
+
+ pDeviceContext = GetDeviceContext(Device);
+
+ //
+ // ---- usbdlib.h DDI coverage: USBD_CloseHandle ----
+ // Close the USBD handle obtained during PrepareHardware.
+ //
+ if (pDeviceContext->UsbdHandle != NULL) {
+ USBD_CloseHandle(pDeviceContext->UsbdHandle);
+ pDeviceContext->UsbdHandle = NULL;
+ KdPrint(("USBD_CloseHandle completed\n"));
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//
+// OsrFxDemonstrateUrbDdis: Shows usbdlib.h and wdfusb.h URB-based DDI usage.
+// Called from EvtDevicePrepareHardware context but factored out for readability.
+// These DDIs build and format URBs but do not submit them to hardware.
+//
+VOID
+OsrFxDemonstrateUrbDdis(
+ IN WDFDEVICE Device,
+ IN PDEVICE_CONTEXT pDeviceContext
+ )
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Device);
+
+ //
+ // ---- wdfusb.h DDI coverage: WDF_USB_CONTROL_SETUP_PACKET_INIT ----
+ // Initialize a raw USB control setup packet (generic form).
+ //
+ {
+ WDF_USB_CONTROL_SETUP_PACKET rawPacket;
+ WDF_USB_CONTROL_SETUP_PACKET_INIT(
+ &rawPacket,
+ BmRequestDeviceToHost, // Direction
+ BmRequestToDevice, // Recipient
+ USB_REQUEST_GET_STATUS, // Request
+ 0, // Value
+ 0); // Index
+ KdPrint(("WDF_USB_CONTROL_SETUP_PACKET_INIT: bmRequestType=0x%02x\n",
+ rawPacket.Packet.bm.Request.Type));
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_DECONFIG ----
+ // Demonstrate building a deconfiguration request params structure.
+ //
+ {
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS deconfigParams;
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_DECONFIG(&deconfigParams);
+ KdPrint(("INIT_DECONFIG: Type=%d\n", deconfigParams.Type));
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_URB ----
+ // Demonstrate building a select-config-by-URB params structure.
+ //
+ {
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS urbConfigParams;
+ URB dummyUrb;
+ RtlZeroMemory(&dummyUrb, sizeof(URB));
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_URB(
+ &urbConfigParams, &dummyUrb);
+ KdPrint(("INIT_URB: Type=%d\n", urbConfigParams.Type));
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_URB ----
+ // Demonstrate building a select-interface-setting-by-URB params structure.
+ //
+ {
+ WDF_USB_INTERFACE_SELECT_SETTING_PARAMS settingParams;
+ URB dummyUrb;
+ RtlZeroMemory(&dummyUrb, sizeof(URB));
+ WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_URB(
+ &settingParams, &dummyUrb);
+ KdPrint(("SELECT_SETTING_INIT_URB: Type=%d\n", settingParams.Type));
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbTargetDeviceSendUrbSynchronously ----
+ // Send a GET_STATUS URB synchronously to the USB device.
+ // Note: USBD_CLIENT_CONTRACT_VERSION_602 requires URBs allocated via USBD_UrbAllocate.
+ //
+ if (pDeviceContext->UsbdHandle != NULL) {
+ PURB statusUrb = NULL;
+ USHORT deviceStatus = 0;
+ WDF_REQUEST_SEND_OPTIONS sendOptions;
+
+ status = USBD_UrbAllocate(pDeviceContext->UsbdHandle, &statusUrb);
+ if (NT_SUCCESS(status) && statusUrb != NULL) {
+ UsbBuildGetStatusRequest(
+ statusUrb,
+ URB_FUNCTION_GET_STATUS_FROM_DEVICE,
+ 0,
+ &deviceStatus,
+ NULL,
+ NULL);
+
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(1000));
+
+ status = WdfUsbTargetDeviceSendUrbSynchronously(
+ pDeviceContext->UsbDevice,
+ NULL,
+ &sendOptions,
+ statusUrb);
+ KdPrint(("SendUrbSynchronously (GET_STATUS): %!STATUS!, status=0x%04X\n",
+ status, deviceStatus));
+ USBD_UrbFree(pDeviceContext->UsbdHandle, statusUrb);
+ }
+ }
+
+ //
+ // ---- wdfusb.h DDI coverage: WdfUsbTargetDeviceFormatRequestForUrb ----
+ // Format a request for a raw URB submission (async pattern demo).
+ // Note: USBD_CLIENT_CONTRACT_VERSION_602 requires URBs allocated via USBD_UrbAllocate.
+ //
+ if (pDeviceContext->UsbdHandle != NULL) {
+ PURB getStatusUrb = NULL;
+ USHORT devStatus = 0;
+ WDFREQUEST urbRequest;
+ WDFMEMORY urbMemory;
+ WDF_OBJECT_ATTRIBUTES reqAttributes;
+ WDF_REQUEST_SEND_OPTIONS sendOptions;
+
+ status = USBD_UrbAllocate(pDeviceContext->UsbdHandle, &getStatusUrb);
+ if (NT_SUCCESS(status) && getStatusUrb != NULL) {
+ UsbBuildGetStatusRequest(
+ getStatusUrb,
+ URB_FUNCTION_GET_STATUS_FROM_DEVICE,
+ 0,
+ &devStatus,
+ NULL,
+ NULL);
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&reqAttributes);
+ status = WdfRequestCreate(&reqAttributes,
+ WdfUsbTargetDeviceGetIoTarget(pDeviceContext->UsbDevice),
+ &urbRequest);
+ if (NT_SUCCESS(status)) {
+ WDF_OBJECT_ATTRIBUTES memAttributes;
+ WDF_OBJECT_ATTRIBUTES_INIT(&memAttributes);
+ status = WdfMemoryCreatePreallocated(
+ &memAttributes, getStatusUrb, sizeof(URB), &urbMemory);
+ if (NT_SUCCESS(status)) {
+ status = WdfUsbTargetDeviceFormatRequestForUrb(
+ pDeviceContext->UsbDevice,
+ urbRequest,
+ urbMemory,
+ NULL); // Offset
+ if (NT_SUCCESS(status)) {
+ WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions,
+ WDF_REQUEST_SEND_OPTION_SYNCHRONOUS |
+ WDF_REQUEST_SEND_OPTION_TIMEOUT);
+ WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions,
+ WDF_REL_TIMEOUT_IN_MS(1000));
+ if (WdfRequestSend(urbRequest,
+ WdfUsbTargetDeviceGetIoTarget(pDeviceContext->UsbDevice),
+ &sendOptions)) {
+ status = WdfRequestGetStatus(urbRequest);
+ } else {
+ status = WdfRequestGetStatus(urbRequest);
+ }
+ KdPrint(("FormatRequestForUrb: %!STATUS!\n", status));
+ }
+ WdfObjectDelete(urbMemory);
+ }
+ WdfObjectDelete(urbRequest);
+ }
+ USBD_UrbFree(pDeviceContext->UsbdHandle, getStatusUrb);
+ }
+ }
+
+ //
+ // ---- usbdlib.h DDI coverage: USBD_AssignUrbToIoStackLocation ----
+ // Demonstrate assigning a URB to an IRP's next stack location.
+ // We build an IRP, assign the URB, then cancel/free (no actual submission).
+ //
+ {
+ PIRP irp;
+ PIO_STACK_LOCATION nextStack;
+ URB dummyUrb;
+ PDEVICE_OBJECT targetDevObj;
+
+ targetDevObj = WdfDeviceWdmGetAttachedDevice(Device);
+ RtlZeroMemory(&dummyUrb, sizeof(URB));
+ dummyUrb.UrbHeader.Length = sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST);
+ dummyUrb.UrbHeader.Function = URB_FUNCTION_GET_STATUS_FROM_DEVICE;
+
+ irp = IoAllocateIrp(targetDevObj->StackSize, FALSE);
+ if (irp != NULL) {
+ nextStack = IoGetNextIrpStackLocation(irp);
+ nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ //
+ // USBD_AssignUrbToIoStackLocation sets the URB pointer in the
+ // stack location. This is the recommended way for USBD_CLIENT_CONTRACT_VERSION_602.
+ //
+ USBD_AssignUrbToIoStackLocation(
+ pDeviceContext->UsbdHandle, nextStack, &dummyUrb);
+ KdPrint(("USBD_AssignUrbToIoStackLocation: URB assigned to IRP stack\n"));
+ IoFreeIrp(irp);
+ }
+ }
+
+ //
+ // ---- usbdlib.h DDI coverage: USBD_SelectConfigUrbAllocateAndBuild,
+ // USBD_SelectInterfaceUrbAllocateAndBuild, USBD_UrbAllocate, USBD_UrbFree ----
+ // Build select-config and select-interface URBs using the modern allocation APIs.
+ //
+ if (pDeviceContext->UsbdHandle != NULL) {
+ USHORT configDescSize = 0;
+ NTSTATUS descStatus;
+
+ descStatus = WdfUsbTargetDeviceRetrieveConfigDescriptor(
+ pDeviceContext->UsbDevice, NULL, &configDescSize);
+ if (descStatus == STATUS_BUFFER_TOO_SMALL && configDescSize > 0) {
+ PUSB_CONFIGURATION_DESCRIPTOR configDesc;
+ configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)
+ ExAllocatePool2(POOL_FLAG_NON_PAGED, configDescSize, POOL_TAG);
+ if (configDesc != NULL) {
+ descStatus = WdfUsbTargetDeviceRetrieveConfigDescriptor(
+ pDeviceContext->UsbDevice, configDesc,
+ &configDescSize);
+ if (NT_SUCCESS(descStatus)) {
+ PUSB_INTERFACE_DESCRIPTOR ifaceDesc;
+ ifaceDesc = USBD_ParseConfigurationDescriptorEx(
+ configDesc, configDesc,
+ -1, -1, -1, -1, -1);
+ if (ifaceDesc != NULL) {
+ PUSBD_INTERFACE_LIST_ENTRY ifaceList;
+ PURB selectConfigUrb = NULL;
+
+ ifaceList = (PUSBD_INTERFACE_LIST_ENTRY)
+ ExAllocatePool2(POOL_FLAG_NON_PAGED,
+ sizeof(USBD_INTERFACE_LIST_ENTRY) * 2, POOL_TAG);
+ if (ifaceList != NULL) {
+ ifaceList[0].InterfaceDescriptor = ifaceDesc;
+ ifaceList[0].Interface = NULL;
+ ifaceList[1].InterfaceDescriptor = NULL;
+ ifaceList[1].Interface = NULL;
+
+ status = USBD_SelectConfigUrbAllocateAndBuild(
+ pDeviceContext->UsbdHandle,
+ configDesc,
+ ifaceList,
+ &selectConfigUrb);
+ if (NT_SUCCESS(status) && selectConfigUrb != NULL) {
+ KdPrint(("USBD_SelectConfigUrbAllocateAndBuild: "
+ "URB length=%lu\n",
+ selectConfigUrb->UrbHeader.Length));
+ //
+ // Also demonstrate USBD_SelectInterfaceUrbAllocateAndBuild.
+ //
+ if (ifaceList[0].Interface != NULL) {
+ PURB selectIfaceUrb = NULL;
+ NTSTATUS ifaceStatus;
+ ifaceStatus = USBD_SelectInterfaceUrbAllocateAndBuild(
+ pDeviceContext->UsbdHandle,
+ selectConfigUrb->UrbSelectConfiguration.ConfigurationHandle,
+ ifaceList,
+ &selectIfaceUrb);
+ if (NT_SUCCESS(ifaceStatus) && selectIfaceUrb != NULL) {
+ KdPrint(("USBD_SelectInterfaceUrbAllocateAndBuild: "
+ "URB length=%lu\n",
+ selectIfaceUrb->UrbHeader.Length));
+ USBD_UrbFree(pDeviceContext->UsbdHandle,
+ selectIfaceUrb);
+ }
+ }
+ USBD_UrbFree(pDeviceContext->UsbdHandle, selectConfigUrb);
+ }
+ ExFreePoolWithTag(ifaceList, POOL_TAG);
+ }
+ }
+ }
+ ExFreePoolWithTag(configDesc, POOL_TAG);
+ }
+ }
+
+ //
+ // ---- usbdlib.h DDI coverage: USBD_UrbAllocate / USBD_UrbFree ----
+ // Allocate a generic URB using the modern USBD APIs.
+ //
+ {
+ PURB genericUrb = NULL;
+ status = USBD_UrbAllocate(pDeviceContext->UsbdHandle, &genericUrb);
+ if (NT_SUCCESS(status) && genericUrb != NULL) {
+ KdPrint(("USBD_UrbAllocate: allocated URB at %p\n", genericUrb));
+ USBD_UrbFree(pDeviceContext->UsbdHandle, genericUrb);
+ }
+ }
+
+ //
+ // ---- usbdlib.h DDI coverage: USBD_IsochUrbAllocate ----
+ // Allocate an isochronous URB with 8 packets.
+ //
+ {
+ PURB isoUrb = NULL;
+ status = USBD_IsochUrbAllocate(pDeviceContext->UsbdHandle,
+ 8, // NumberOfIsochPackets
+ &isoUrb);
+ if (NT_SUCCESS(status) && isoUrb != NULL) {
+ KdPrint(("USBD_IsochUrbAllocate: allocated ISO URB at %p\n", isoUrb));
+ USBD_UrbFree(pDeviceContext->UsbdHandle, isoUrb);
+ }
+ }
+ }
+
+ //
+ // ---- usbdlib.h DDI coverage: USBD_ValidateConfigurationDescriptor ----
+ // Validate the configuration descriptor retrieved from the device.
+ //
+ {
+ USHORT configDescSize = 0;
+ NTSTATUS descStatus;
+
+ descStatus = WdfUsbTargetDeviceRetrieveConfigDescriptor(
+ pDeviceContext->UsbDevice, NULL, &configDescSize);
+ if (descStatus == STATUS_BUFFER_TOO_SMALL && configDescSize > 0) {
+ PUSB_CONFIGURATION_DESCRIPTOR configDesc;
+ configDesc = (PUSB_CONFIGURATION_DESCRIPTOR)
+ ExAllocatePool2(POOL_FLAG_NON_PAGED, configDescSize, POOL_TAG);
+ if (configDesc != NULL) {
+ descStatus = WdfUsbTargetDeviceRetrieveConfigDescriptor(
+ pDeviceContext->UsbDevice, configDesc,
+ &configDescSize);
+ if (NT_SUCCESS(descStatus)) {
+ PUCHAR validationOffset = NULL;
+ descStatus = USBD_ValidateConfigurationDescriptor(
+ configDesc,
+ configDescSize,
+ 1, // level
+ &validationOffset,
+ POOL_TAG);
+ KdPrint(("USBD_ValidateConfigurationDescriptor: %!STATUS!, offset=%p\n",
+ descStatus, validationOffset));
+ }
+ ExFreePoolWithTag(configDesc, POOL_TAG);
+ }
+ }
+ }
+}