NTSTATUS SetPowerPolicy(__in WDFDEVICE Device) { WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; NTSTATUS status = STATUS_SUCCESS; PAGED_CODE(); // Init the idle policy structure. WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IDLE_CAPS_TYPE); idleSettings.IdleTimeout = 10000; // 10-sec status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(3, ("WdfDeviceAssignS0IdleSettings failed! (Status = %x)\n", status)); return status; } // Init wait-wake policy structure. WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(3, ("WdfDeviceAssignSxWakeSettings failed! (Status = %x)\n", status)); return status; } return status; }
/*++ Routine Description sends an abort pipe request on all open pipes. Arguments: Device - Handle to a framework device Return Value: NT status value --*/ NTSTATUS AbortPipes(IN WDFDEVICE Device) { UCHAR i; ULONG count; NTSTATUS status; PDEVICE_CONTEXT pDevContext; PAGED_CODE(); // initialize variables pDevContext = GetDeviceContext(Device); PSDrv_DbgPrint(3, ("AbortPipes - begins\n")); count = pDevContext->NumberConfiguredPipes; for (i = 0; i < count; i++) { WDFUSBPIPE pipe; pipe = WdfUsbInterfaceGetConfiguredPipe(pDevContext->UsbInterface, i, NULL); PSDrv_DbgPrint(3, ("Aborting open pipe: %d\n", i)); status = WdfUsbTargetPipeAbortSynchronously(pipe, WDF_NO_HANDLE, NULL); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfUsbTargetPipeAbortSynchronously failed! (Status = %x)\n", status)); break; } } PSDrv_DbgPrint(3, ("AbortPipes - ends\n")); return STATUS_SUCCESS; }
/*++ Routine Description: DriverEntry initializes the driver and is the first routine called by the system after the driver is loaded. Parameters Description: DriverObject - represents the instance of the function driver that is loaded into memory. DriverEntry must initialize members of DriverObject before it returns to the caller. DriverObject is allocated by the system before the driver is loaded, and it is released by the system after the system unloads the function driver from memory. RegistryPath - represents the driver specific path in the Registry. The function driver can use the path to store driver related data between reboots. The path does not store hardware instance specific data. Return Value: STATUS_SUCCESS if successful, STATUS_UNSUCCESSFUL otherwise. --*/ NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { WDF_DRIVER_CONFIG config; NTSTATUS status; PSDrv_DbgPrint(3, ("Prime Sensor Driver v%s - DebEgg Edition.\n", PSDRV_BRIEF_VERSION_STRING)); PSDrv_DbgPrint(3, ("Built %s %s\n", __DATE__, __TIME__)); // Initialize driver config to control the attributes that // are global to the driver. Note that framework by default // provides a driver unload routine. If you create any resources // in the DriverEntry and want to be cleaned in driver unload, // you can override that by manually setting the EvtDriverUnload in the // config structure. In general xxx_CONFIG_INIT macros are provided to // initialize most commonly used members. WDF_DRIVER_CONFIG_INIT(&config, PSDrv_EvtDeviceAdd); // Create a framework driver object to represent our driver. status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfDriverCreate failed! (Status = %x)\n", status)); } return status; }
/*++ Routine Description: This helper routine reads the configuration descriptor for the device in couple of steps. Arguments: Device - Handle to a framework device Return Value: NTSTATUS - NT status value --*/ NTSTATUS ConfigureDevice(IN WDFDEVICE Device) { USHORT size = 0; NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor; WDF_OBJECT_ATTRIBUTES attributes; WDFMEMORY memory; PAGED_CODE(); // // initialize the variables // configurationDescriptor = NULL; pDeviceContext = GetDeviceContext(Device); // Read the first configuration descriptor // This requires two steps: // 1. Ask the WDFUSBDEVICE how big it is // 2. Allocate it and get it from the WDFUSBDEVICE status = WdfUsbTargetDeviceRetrieveConfigDescriptor(pDeviceContext->WdfUsbTargetDevice, NULL, &size); if (status != STATUS_BUFFER_TOO_SMALL || size == 0) { PSDrv_DbgPrint(3, ("WdfUsbTargetDeviceRetrieveConfigDescriptor failed! (Status = %x)\n", status)); return status; } // Create a memory object and specify usbdevice as the parent so that it will be freed automatically. WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = pDeviceContext->WdfUsbTargetDevice; status = WdfMemoryCreate(&attributes, NonPagedPool, POOL_TAG, size, &memory, &configurationDescriptor); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(3, ("WdfMemoryCreate for configurationDescriptor failed! (Status = %x)\n", status)); return status; } status = WdfUsbTargetDeviceRetrieveConfigDescriptor(pDeviceContext->WdfUsbTargetDevice, configurationDescriptor, &size); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(3, ("WdfUsbTargetDeviceRetrieveConfigDescriptor failed! (Status = %x)\n", status)); return status; } pDeviceContext->UsbConfigurationDescriptor = configurationDescriptor; status = SelectInterfaces(Device); return status; }
/*++ Routine Description: The framework calls a driver's EvtDeviceFileCreate callback when the framework receives an IRP_MJ_CREATE request. The system sends this request when a user application opens the device to perform an I/O operation, such as reading or writing a file. This callback is called synchronously, in the context of the thread that created the IRP_MJ_CREATE request. Arguments: Device - Handle to a framework device object. FileObject - Pointer to fileobject that represents the open handle. CreateParams - copy of the create IO_STACK_LOCATION Return Value: NT status code --*/ VOID PSDrv_EvtDeviceFileCreate(IN WDFDEVICE Device, IN WDFREQUEST Request, IN WDFFILEOBJECT FileObject) { NTSTATUS status = STATUS_UNSUCCESSFUL; PUNICODE_STRING fileName; PFILE_CONTEXT pFileContext; PDEVICE_CONTEXT pDevContext; WDFUSBPIPE pipe; PSDrv_DbgPrint(3, ("PSDrv_EvtDeviceFileCreate - begins\n")); PAGED_CODE(); // initialize variables pDevContext = GetDeviceContext(Device); pFileContext = GetFileContext(FileObject); fileName = WdfFileObjectGetFileName(FileObject); if (0 == fileName->Length) { // opening a device as opposed to pipe. status = STATUS_SUCCESS; } else { pipe = GetPipeFromName(pDevContext, fileName); // Does the pipe exists? if (pipe != NULL) { pFileContext->Pipe = pipe; WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); // Set the default timeout pFileContext->nTimeOut = PSUSBDRV_DEFAULT_TIMEOUT; status = STATUS_SUCCESS; } else { status = STATUS_INVALID_DEVICE_REQUEST; } } WdfRequestComplete(Request, status); PSDrv_DbgPrint(3, ("PSDrv_EvtDeviceFileCreate - ends\n")); return; }
/*++ Routine Description: Called by the framework when it receives Write requests. Arguments: Queue - Default queue handle Request - Handle to the read/write request Length - Length of the data buffer associated with the request. The default property of the queue is to not dispatch zero length read & write requests to the driver and complete is with status success. So we will never get a zero length request. --*/ VOID PSDrv_EvtIoWrite(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; PAGED_CODE(); // Get the pipe associate with this request. fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; if (pipe == NULL) { PSDrv_DbgPrint(1, ("PSDrv_EvtIoWrite: Invalid pipe!\n")); WdfRequestCompleteWithInformation(Request, STATUS_INVALID_PARAMETER, 0); return; } WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if((WdfUsbPipeTypeBulk == pipeInfo.PipeType) || (WdfUsbPipeTypeInterrupt == pipeInfo.PipeType)) { ReadWriteBulkEndPoints(Queue, Request, (ULONG)Length, WdfRequestTypeWrite); return; } else if(WdfUsbPipeTypeIsochronous == pipeInfo.PipeType) { ReadWriteIsochEndPoints(Queue, Request, (ULONG)Length, WdfRequestTypeWrite); return; } return; }
/*++ Routine Description: In this callback, the driver does whatever is necessary to make the hardware ready to use. In the case of a USB device, this involves reading and selecting descriptors. --*/ NTSTATUS PSDrv_EvtDevicePrepareHardware(IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated) { NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; WDF_USB_DEVICE_INFORMATION info; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); PSDrv_DbgPrint(3, ("PSDrv_EvtDevicePrepareHardware - begins\n")); PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); // Read the device descriptor, configuration descriptor and select the interface descriptors status = ReadAndSelectDescriptors(Device); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("ReadAndSelectDescriptors failed! (Status = %x)\n", status)); return status; } WDF_USB_DEVICE_INFORMATION_INIT(&info); // Retrieve USBD version information, port driver capabilities and device capabilities such as speed, power, etc. status = WdfUsbTargetDeviceRetrieveInformation(pDeviceContext->WdfUsbTargetDevice, &info); if (NT_SUCCESS(status)) { pDeviceContext->IsDeviceHighSpeed = (info.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) ? TRUE : FALSE; PSDrv_DbgPrint(3, ("DeviceIsHighSpeed: %s\n", pDeviceContext->IsDeviceHighSpeed ? "TRUE" : "FALSE")); } else { pDeviceContext->IsDeviceHighSpeed = FALSE; } PSDrv_DbgPrint(3, ("IsDeviceSelfPowered: %s\n", (info.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED) ? "TRUE" : "FALSE")); pDeviceContext->WaitWakeEnable = info.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; PSDrv_DbgPrint(3, ("IsDeviceRemoteWakeable: %s\n", (info.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE) ? "TRUE" : "FALSE")); // Enable wait-wake and idle timeout if the device supports it if(pDeviceContext->WaitWakeEnable) { status = SetPowerPolicy(Device); if (!NT_SUCCESS (status)) { PSDrv_DbgPrint(3, ("SetPowerPolicy failed! (Status = %x)\n", status)); return status; } } PSDrv_DbgPrint(3, ("PSDrv_EvtDevicePrepareHardware - ends\n")); return status; }
/*++ Routine Description: This routine resets the pipe. Arguments: Pipe - framework pipe handle Return Value: NT status value --*/ NTSTATUS ResetPipe(IN WDFUSBPIPE Pipe) { NTSTATUS status; PAGED_CODE(); // This routine synchronously submits a URB_FUNCTION_RESET_PIPE request down the stack. status = WdfUsbTargetPipeResetSynchronously(Pipe, WDF_NO_HANDLE, NULL); if (NT_SUCCESS(status)) { PSDrv_DbgPrint(3, ("ResetPipe success!\n")); status = STATUS_SUCCESS; } else { PSDrv_DbgPrint(1, ("ResetPipe failed! (Status = %x)\n", status)); } return status; }
/*++ Routine Description: This helper routine selects the configuration, interface and creates a context for every pipe (end point) in that interface. Arguments: Device - Handle to a framework device Return Value: NT status value --*/ NTSTATUS SelectInterfaces(IN WDFDEVICE Device) { WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; UCHAR numInterfaces; PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); numInterfaces = WdfUsbTargetDeviceGetNumInterfaces(pDeviceContext->WdfUsbTargetDevice); if (numInterfaces == 1) { // The device has only 1 interface. PSDrv_DbgPrint(3, ("Device has a single interface!\n")); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&configParams); status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->WdfUsbTargetDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); if (NT_SUCCESS(status) && numInterfaces > 0) { pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; pDeviceContext->NumberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; } } else { // The device has more then one interface... PSDrv_DbgPrint(3, ("Device has multiple interfaces (%d) - this is not supported yet!\n", numInterfaces)); status = STATUS_NOT_SUPPORTED; } pDeviceContext->nCurrIf = 0; pDeviceContext->nCurrAltIf = 0; return status; }
/*++ Routine Description: This routine calls WdfUsbTargetDeviceResetPortSynchronously to reset the device if it's still connected. Arguments: Device - Handle to a framework device Return Value: NT status value --*/ NTSTATUS ResetDevice(IN WDFDEVICE Device) { PDEVICE_CONTEXT pDeviceContext; NTSTATUS status; PSDrv_DbgPrint(3, ("ResetDevice - begins\n")); PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); // A reset-device // request will be stuck in the USB until the pending transactions // have been canceled. Similarly, if there are pending transfers on the BULK // IN/OUT pipe cancel them. // To work around this issue, the driver should stop the continuous reader // (by calling WdfIoTargetStop) before resetting the device, and restart the // continuous reader (by calling WdfIoTargetStart) after the request completes. StopAllPipes(pDeviceContext); // It may not be necessary to check whether device is connected before // resetting the port. status = WdfUsbTargetDeviceIsConnectedSynchronous(pDeviceContext->WdfUsbTargetDevice); if(NT_SUCCESS(status)) { status = WdfUsbTargetDeviceResetPortSynchronously(pDeviceContext->WdfUsbTargetDevice); } StartAllPipes(pDeviceContext); PSDrv_DbgPrint(3, ("ResetDevice - ends\n")); return status; }
/*++ Routine Description: This routine sets a property on a pipe. Arguments: pFileContext - Pipe (which is actually a file) context handle pPipeProp - The pipe property struct Return Value: NT status value --*/ NTSTATUS SetPipeProperty(IN OUT PFILE_CONTEXT pFileContext, IN PSUSBDRV_PIPE_PROPERTY* pPipeProp) { NTSTATUS status = STATUS_SUCCESS; PAGED_CODE(); switch(pPipeProp->nIndex) { case PSUSBDRV_PIPE_PROPERTY_TIMEOUT: pFileContext->nTimeOut = pPipeProp->nValue; PSDrv_DbgPrint(3, ("SetPipeProperty: Timeout is set to: %d.\n", pPipeProp->nValue)); break; default: status = STATUS_INVALID_PARAMETER; PSDrv_DbgPrint(3, ("SetPipeProperty: Invalid Property! (Property = %d)\n", pPipeProp->nIndex)); break; } return status; }
VOID StartAllPipes(IN PDEVICE_CONTEXT DeviceContext) { NTSTATUS status; UCHAR count; UCHAR i; count = DeviceContext->NumberConfiguredPipes; for (i = 0; i < count; i++) { WDFUSBPIPE pipe; pipe = WdfUsbInterfaceGetConfiguredPipe(DeviceContext->UsbInterface, i, NULL); status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pipe)); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("StartAllPipes failed on pipe %d! (Status = %x)\n", i, status)); } } }
/*++ Routine Description: This routine configures the USB device. In this routines we get the device descriptor, the configuration descriptor and select the configuration. Arguments: Device - Handle to a framework device Return Value: NTSTATUS - NT status value. --*/ NTSTATUS ReadAndSelectDescriptors(IN WDFDEVICE Device) { NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; PAGED_CODE(); // initialize variables pDeviceContext = GetDeviceContext(Device); // Create a USB device handle so that we can communicate with the // underlying USB stack. The WDFUSBDEVICE handle is used to query, // configure, and manage all aspects of the USB device. // These aspects include device properties, bus properties, // and I/O creation and synchronization. We only create device the first // the PrepareHardware is called. If the device is restarted by pnp manager // for resource re-balance, we will use the same device handle but then select // the interfaces again because the USB stack could reconfigure the device on // restart. if (pDeviceContext->WdfUsbTargetDevice == NULL) { status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &pDeviceContext->WdfUsbTargetDevice); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(3, ("WdfUsbTargetDeviceCreate failed! (Status = %x)\n", status)); return status; } } WdfUsbTargetDeviceGetDeviceDescriptor(pDeviceContext->WdfUsbTargetDevice, &pDeviceContext->UsbDeviceDescriptor); ASSERT(pDeviceContext->UsbDeviceDescriptor.bNumConfigurations); status = ConfigureDevice(Device); return status; }
/*++ Routine Description: This event is called when the framework receives IRP_MJ_DEVICE_CONTROL requests from the system. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ VOID PSDrv_EvtIoDeviceControl(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode) { WDFDEVICE device; PVOID ioBuffer; size_t bufLength; NTSTATUS status; PDEVICE_CONTEXT pDevContext; PFILE_CONTEXT pFileContext; ULONG length = 0; PSUSBDRV_PIPE_PROPERTY* pPipeProp; PSUSBDRV_CONTROL_TRANSFER* pControlTransfer; PSUSBDRV_DRIVER_VERSION* pDriverVersion; PSUSBDRV_INTERFACE_PROPERTY* pInterfaceProperty; unsigned int* pnDeviceSpeed; WDFMEMORY WdfMem = NULL; PUCHAR pControlBuffer; WDFMEMORY WdfMemOut = NULL; WDF_USB_INTERFACE_SELECT_SETTING_PARAMS selectSettingParams; UNREFERENCED_PARAMETER(InputBufferLength); PSDrv_DbgPrint(3, ("PSDrv_EvtIoDeviceControl - begins\n")); PAGED_CODE(); // initialize variables device = WdfIoQueueGetDevice(Queue); pDevContext = GetDeviceContext(device); switch(IoControlCode) { case IOCTL_PSDRV_RESET_PIPE: PSDrv_DbgPrint(3, ("IOControl: ResetPipe\n")); pFileContext = GetFileContext(WdfRequestGetFileObject(Request)); if (pFileContext->Pipe == NULL) { PSDrv_DbgPrint(3, ("Invalid pipe!\n")); status = STATUS_INVALID_PARAMETER; } else { status = ResetPipe(pFileContext->Pipe); } break; case IOCTL_PSDRV_ABORT_PIPE: PSDrv_DbgPrint(3, ("IOControl: AbortPipe\n")); pFileContext = GetFileContext(WdfRequestGetFileObject(Request)); if (pFileContext->Pipe == NULL) { PSDrv_DbgPrint(3, ("Invalid pipe!\n")); status = STATUS_INVALID_PARAMETER; } else { status = AbortPipe(pFileContext->Pipe); } break; case IOCTL_PSDRV_GET_CONFIG_DESCRIPTOR: PSDrv_DbgPrint(3, ("IOControl: GetConfigDescriptor\n")); if (pDevContext->UsbConfigurationDescriptor) { length = pDevContext->UsbConfigurationDescriptor->wTotalLength; status = WdfRequestRetrieveOutputBuffer(Request, length, &ioBuffer, &bufLength); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } RtlCopyMemory(ioBuffer, pDevContext->UsbConfigurationDescriptor, length); status = STATUS_SUCCESS; } else { PSDrv_DbgPrint(3, ("UsbConfigurationDescriptor is NULL!\n")); status = STATUS_INVALID_DEVICE_STATE; } break; case IOCTL_PSDRV_RESET_DEVICE: PSDrv_DbgPrint(3, ("IOControl: ResetDevice\n")); status = ResetDevice(device); break; case IOCTL_PSDRV_CONTROL_TRANSFER: PSDrv_DbgPrint(3, ("IOControl: ControlTransfer\n")); //Get a pointer to the input buffer status = WdfRequestRetrieveInputMemory(Request, &WdfMem); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputMemory failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } if (WdfMem == NULL) { PSDrv_DbgPrint(1, ("WdfMem is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } pControlTransfer = WdfMemoryGetBuffer(WdfMem, NULL); if (pControlTransfer == NULL) { PSDrv_DbgPrint(1, ("pControlTransfer is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } //Get a pointer to the output buffer if (OutputBufferLength != 0) { status = WdfRequestRetrieveOutputMemory(Request, &WdfMemOut); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputMemory failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } if (WdfMemOut == NULL) { PSDrv_DbgPrint(1, ("WdfMemOut is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } pControlBuffer = WdfMemoryGetBuffer(WdfMemOut, NULL); if (pControlBuffer == NULL) { PSDrv_DbgPrint(1, ("pControlBuffer is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } } else { PSDrv_DbgPrint(1, ("This control request has no buffer...\n")); pControlBuffer = NULL; } // Call the control transfer function status = ControlTransfer(pDevContext, pControlTransfer, pControlBuffer, OutputBufferLength, &length); break; case IOCTL_PSDRV_SET_PIPE_PROPERTY: PSDrv_DbgPrint(3, ("IOControl: SetPipeProperty\n")); status = WdfRequestRetrieveInputMemory(Request, &WdfMem); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputMemory failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } if (WdfMem == NULL) { PSDrv_DbgPrint(1, ("WdfMem is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } pPipeProp = WdfMemoryGetBuffer(WdfMem, NULL); if (pPipeProp == NULL) { PSDrv_DbgPrint(1, ("pPipeProp is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } pFileContext = GetFileContext(WdfRequestGetFileObject(Request)); if (pFileContext->Pipe == NULL) { PSDrv_DbgPrint(3, ("Invalid pipe!\n")); status = STATUS_INVALID_PARAMETER; } else { status = SetPipeProperty(pFileContext, pPipeProp); } break; case IOCTL_PSDRV_SET_INTERFACE: PSDrv_DbgPrint(3, ("IOControl: SetInterface\n")); status = WdfRequestRetrieveInputMemory(Request, &WdfMem); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputMemory failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } if (WdfMem == NULL) { PSDrv_DbgPrint(1, ("WdfMem is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } pInterfaceProperty = WdfMemoryGetBuffer(WdfMem, NULL); if (pInterfaceProperty == NULL) { PSDrv_DbgPrint(1, ("pInterfaceProperty is NULL!\n")); status = STATUS_INVALID_PARAMETER; break; } PSDrv_DbgPrint(3, ("SetInterface: Going to change AltIF to %d...\n", pInterfaceProperty->nAltIF)); WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&selectSettingParams, pInterfaceProperty->nAltIF); status = WdfUsbInterfaceSelectSetting(pDevContext->UsbInterface, WDF_NO_OBJECT_ATTRIBUTES, &selectSettingParams); if (status == STATUS_SUCCESS) { pDevContext->nCurrIf = 0; pDevContext->nCurrAltIf = pInterfaceProperty->nAltIF; PSDrv_DbgPrint(3, ("SetInterface: AltIF is now %d...\n", pInterfaceProperty->nAltIF)); } break; case IOCTL_PSDRV_GET_INTERFACE: PSDrv_DbgPrint(3, ("IOControl: GetInterface\n")); length = sizeof(PSUSBDRV_INTERFACE_PROPERTY); status = WdfRequestRetrieveOutputBuffer(Request, length, &pInterfaceProperty, &bufLength); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } pInterfaceProperty->nIF = pDevContext->nCurrIf; pInterfaceProperty->nAltIF = pDevContext->nCurrAltIf; status = STATUS_SUCCESS; break; case IOCTL_PSDRV_GET_DRIVER_VERSION: PSDrv_DbgPrint(3, ("IOControl: GetDriverVersion\n")); length = sizeof(PSUSBDRV_DRIVER_VERSION); status = WdfRequestRetrieveOutputBuffer(Request, length, &pDriverVersion, &bufLength); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } pDriverVersion->nMajor = PSUSBDRV_MAJOR_VERSION; pDriverVersion->nMinor = PSUSBDRV_MINOR_VERSION; pDriverVersion->nMaintenance = PSUSBDRV_MAINTENANCE_VERSION; pDriverVersion->nBuild = PSUSBDRV_BUILD_VERSION; status = STATUS_SUCCESS; break; case IOCTL_PSDRV_GET_DEVICE_SPEED: PSDrv_DbgPrint(3, ("IOControl: GetDeviceSpeed\n")); length = sizeof(unsigned int); status = WdfRequestRetrieveOutputBuffer(Request, length, &pnDeviceSpeed, &bufLength); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputBuffer failed! (Status = %x)\n", status)); status = STATUS_INVALID_PARAMETER; break; } if (pDevContext->IsDeviceHighSpeed == TRUE) { *pnDeviceSpeed = PSUSBDRV_DEVICE_HIGH_SPEED; } else { *pnDeviceSpeed = PSUSBDRV_DEVICE_FULL_SPEED; } break; default: PSDrv_DbgPrint(3, ("Unknown IOControl! (ControlCode = %x)\n", IoControlCode)); status = STATUS_INVALID_DEVICE_REQUEST; break; } WdfRequestCompleteWithInformation(Request, status, length); PSDrv_DbgPrint(3, ("PSDrv_EvtIoDeviceControl - ends\n")); return; }
/*++ Routine Description: This is the completion routine for reads/writes If the irp completes with success, we check if we need to recirculate this irp for another stage of transfer. Arguments: Context - Driver supplied context Device - Device handle Request - Request handle Params - request completion params Return Value: None --*/ VOID ReadWriteCompletion(IN WDFREQUEST Request, IN WDFIOTARGET Target, PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, IN WDFCONTEXT Context) { PMDL requestMdl; WDFUSBPIPE pipe; ULONG stageLength; NTSTATUS status; PREQUEST_CONTEXT rwContext; PURB urb; PCHAR operation; ULONG bytesReadWritten; UNREFERENCED_PARAMETER(Context); rwContext = GetRequestContext(Request); PSDrv_DbgPrint(3, ("ReadWriteCompletion - begins\n")); if (rwContext->Read) { operation = "Read"; } else { operation = "Write"; } pipe = (WDFUSBPIPE)Target; status = CompletionParams->IoStatus.Status; if (!NT_SUCCESS(status)) { goto End; } urb = (PURB)WdfMemoryGetBuffer(rwContext->UrbMemory, NULL); bytesReadWritten = urb->UrbBulkOrInterruptTransfer.TransferBufferLength; rwContext->Numxfer += bytesReadWritten; // If there is anything left to transfer. if (rwContext->Length == 0) { // this is the last transfer WdfRequestSetInformation(Request, rwContext->Numxfer); goto End; } // Start another transfer PSDrv_DbgPrint(3, ("Stage next %s transfer...\n", operation)); if (rwContext->Length > MAX_TRANSFER_SIZE) { stageLength = MAX_TRANSFER_SIZE; } else { stageLength = rwContext->Length; } // Following call is required to free any mapping made on the partial MDL and reset internal MDL state. MmPrepareMdlForReuse(rwContext->Mdl); if (rwContext->Read) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl for Read failed! (Status = %x)\n", status)); goto End; } } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl for Write failed! (Status = %x)\n", status)); goto End; } } IoBuildPartialMdl(requestMdl, rwContext->Mdl, (PVOID)rwContext->VirtualAddress, stageLength); // Reinitialize the urb urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength; rwContext->VirtualAddress += stageLength; rwContext->Length -= stageLength; // Format the request to send a URB to a USB pipe. status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, rwContext->UrbMemory, NULL); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfUsbTargetPipeFormatRequestForUrb failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto End; } WdfRequestSetCompletionRoutine(Request, ReadWriteCompletion, NULL); // Send the request asynchronously. if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { PSDrv_DbgPrint(1, ("WdfRequestSend for %s failed!\n", operation)); status = WdfRequestGetStatus(Request); goto End; } // Else when the request completes, this completion routine will be called again. PSDrv_DbgPrint(3, ("ReadWriteCompletion - ends 1\n")); return; End: // Dump the request context, complete the request and return. PSDrv_DbgPrint(3, ("rwContext->UrbMemory = %p\n", rwContext->UrbMemory)); PSDrv_DbgPrint(3, ("rwContext->Mdl = %p\n", rwContext->Mdl)); PSDrv_DbgPrint(3, ("rwContext->Length = %d\n", rwContext->Length)); PSDrv_DbgPrint(3, ("rwContext->Numxfer = %d\n", rwContext->Numxfer)); PSDrv_DbgPrint(3, ("rwContext->VirtualAddress = %p\n", rwContext->VirtualAddress)); IoFreeMdl(rwContext->Mdl); PSDrv_DbgPrint(3, ("Bulk or Interrupt %s request has finished. (Status = %x)\n", operation, status)); WdfRequestComplete(Request, status); PSDrv_DbgPrint(3, ("ReadWriteCompletion - ends 2\n")); return; }
/*++ Routine Description: This callback is invoked when the framework received WdfRequestTypeRead or WdfRequestTypeWrite request. This read/write is performed in stages of MAX_TRANSFER_SIZE. Once a stage of transfer is complete, then the request is circulated again, until the requested length of transfer is performed. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. This one represents the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. Length - Length of the input/output buffer. Return Value: VOID --*/ VOID ReadWriteBulkEndPoints(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG Length, IN WDF_REQUEST_TYPE RequestType) { PMDL newMdl = NULL; PMDL requestMdl = NULL; PURB urb = NULL; WDFMEMORY urbMemory; ULONG totalLength = Length; ULONG stageLength = 0; ULONG urbFlags = 0; NTSTATUS status; ULONG_PTR virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDF_OBJECT_ATTRIBUTES objectAttribs; USBD_PIPE_HANDLE usbdPipeHandle; PDEVICE_CONTEXT deviceContext; WDF_REQUEST_SEND_OPTIONS sendOptions; PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - begins\n")); // First validate input parameters. deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { PSDrv_DbgPrint(1, ("Transfer length (%d) is bigger then MaximumTransferSize (%d)!\n", totalLength, deviceContext->MaximumTransferSize)); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { PSDrv_DbgPrint(1, ("RequestType has to be either Read or Write! (RequestType = %d)\n", RequestType)); status = STATUS_INVALID_PARAMETER; goto Exit; } // Get the pipe associate with this request. fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if((WdfUsbPipeTypeBulk != pipeInfo.PipeType) && (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType)) { PSDrv_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt! (PipeType = %d)\n", pipeInfo.PipeType)); status = STATUS_INVALID_DEVICE_REQUEST; goto Exit; } rwContext = GetRequestContext(Request); if(RequestType == WdfRequestTypeRead) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed! (Status = %x)\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_IN; rwContext->Read = TRUE; PSDrv_DbgPrint(3, ("This is a read operation...\n")); } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed! (Status = %x)\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_OUT; rwContext->Read = FALSE; PSDrv_DbgPrint(3, ("This is a write operation...\n")); } urbFlags |= USBD_SHORT_TRANSFER_OK; virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); // The transfer request is for totalLength. We can perform a max of MAX_TRANSFER_SIZE in each stage. if (totalLength > MAX_TRANSFER_SIZE) { stageLength = MAX_TRANSFER_SIZE; } else { stageLength = totalLength; } newMdl = IoAllocateMdl((PVOID)virtualAddress, totalLength, FALSE, FALSE, NULL); if (newMdl == NULL) { PSDrv_DbgPrint(1, ("IoAllocateMdl failed! (newMdl is NULL)\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } // Map the portion of user-buffer described by an mdl to another mdl IoBuildPartialMdl(requestMdl, newMdl, (PVOID)virtualAddress, stageLength); WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfMemoryCreate(&objectAttribs, NonPagedPool, POOL_TAG, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), &urbMemory, (PVOID*)&urb); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfMemoryCreate for urbMemory failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, urbFlags, NULL); status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfUsbTargetPipeFormatRequestForUrb failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } WdfRequestSetCompletionRoutine(Request, ReadWriteCompletion, NULL); // Set REQUEST_CONTEXT parameters. rwContext->UrbMemory = urbMemory; rwContext->Mdl = newMdl; rwContext->Length = totalLength - stageLength; rwContext->Numxfer = 0; rwContext->VirtualAddress = virtualAddress + stageLength; // Set the timeout if (fileContext->nTimeOut != 0) { WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(fileContext->nTimeOut)); PSDrv_DbgPrint(3, ("Pipe timeout is set to: %d\n", fileContext->nTimeOut)); if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), &sendOptions)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } } else { if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); if (newMdl != NULL) { IoFreeMdl(newMdl); } } PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - ends\n")); return; }
/*++ Routine Description: This routine sets a property on a pipe. Arguments: pDeviceContext - Device context handle pControlTransfer - The control transfer property struct Return Value: NT status value --*/ NTSTATUS ControlTransfer(IN PDEVICE_CONTEXT pDeviceContext, IN PSUSBDRV_CONTROL_TRANSFER* pControlTransfer, IN OUT PUCHAR pControlBuffer, IN size_t nControlBufferSize, OUT ULONG* pLength) { NTSTATUS status = STATUS_SUCCESS; unsigned int nTimeout = PSUSBDRV_DEFAULT_CONTROL_TIMEOUT; WDF_REQUEST_SEND_OPTIONS sendOptions; WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; WDF_MEMORY_DESCRIPTOR memDesc; PAGED_CODE(); RtlZeroMemory(&controlSetupPacket, sizeof(WDF_USB_CONTROL_SETUP_PACKET)); controlSetupPacket.Packet.bm.Request.Dir = pControlTransfer->cDirection; controlSetupPacket.Packet.bm.Request.Type = pControlTransfer->cRequestType; controlSetupPacket.Packet.bm.Request.Recipient = BmRequestToDevice; controlSetupPacket.Packet.bRequest = pControlTransfer->cRequest; controlSetupPacket.Packet.wValue.Value = pControlTransfer->nValue; controlSetupPacket.Packet.wIndex.Value = pControlTransfer->nIndex; PSDrv_DbgPrint(3, ("ControlTransfer: Dir:%d Type:%d Request:%d Value:%d Index:%d.\n", pControlTransfer->cDirection, pControlTransfer->cRequestType, pControlTransfer->cRequest, pControlTransfer->nValue, pControlTransfer->nIndex)); if (pControlTransfer->nTimeout != 0) { if (pControlTransfer->nTimeout > PSUSBDRV_DEFAULT_CONTROL_TIMEOUT) { PSDrv_DbgPrint(3, ("ControlTransfer: Timeout was truncated from %d to %d!\n", pControlTransfer->nTimeout, PSUSBDRV_DEFAULT_CONTROL_TIMEOUT)); nTimeout = PSUSBDRV_DEFAULT_CONTROL_TIMEOUT; } else { nTimeout = pControlTransfer->nTimeout; } } WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(nTimeout)); PSDrv_DbgPrint(3, ("ControlTransfer: Timeout is set to: %d.\n", nTimeout)); PSDrv_DbgPrint(3, ("ControlTransfer: Performing the control transfer...\n")); if (pControlBuffer != NULL) { PSDrv_DbgPrint(3, ("ControlTransfer: Buffer:%x Length:%d\n", pControlBuffer, nControlBufferSize)); if (nControlBufferSize == 0) { PSDrv_DbgPrint(3, ("ControlTransfer: pControlBuffer is not NULL but nControlBufferSize is 0!\n")); return (STATUS_INVALID_PARAMETER); } WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, pControlBuffer, (ULONG)nControlBufferSize); status = WdfUsbTargetDeviceSendControlTransferSynchronously(pDeviceContext->WdfUsbTargetDevice, WDF_NO_HANDLE, &sendOptions, &controlSetupPacket, &memDesc, pLength); } else { status = WdfUsbTargetDeviceSendControlTransferSynchronously(pDeviceContext->WdfUsbTargetDevice, WDF_NO_HANDLE, &sendOptions, &controlSetupPacket, NULL, pLength); } PSDrv_DbgPrint(3, ("ControlTransfer: Finished! Status=%x BytesTransferred=%d\n", status, *pLength)); return status; }
/*++ Routine Description: EvtDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. We create and initialize a device object to represent a new instance of the device. All the software resources should be allocated in this callback. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ NTSTATUS PSDrv_EvtDeviceAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit) { WDF_FILEOBJECT_CONFIG fileConfig; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_OBJECT_ATTRIBUTES fdoAttributes; WDF_OBJECT_ATTRIBUTES fileObjectAttributes; WDF_OBJECT_ATTRIBUTES requestAttributes; NTSTATUS status; WDFDEVICE device; WDF_DEVICE_PNP_CAPABILITIES pnpCaps; WDF_IO_QUEUE_CONFIG ioQueueConfig; PDEVICE_CONTEXT pDevContext; WDFQUEUE queue; ULONG maximumTransferSize; UNREFERENCED_PARAMETER(Driver); PSDrv_DbgPrint (3, ("PSDrv_EvtDeviceAdd - begins\n")); PAGED_CODE(); // Initialize the pnpPowerCallbacks structure. Callback events for PNP // and Power are specified here. If you don't supply any callbacks, // the Framework will take appropriate default actions based on whether // DeviceInit is initialized to be an FDO, a PDO or a filter device // object. WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); pnpPowerCallbacks.EvtDevicePrepareHardware = PSDrv_EvtDevicePrepareHardware; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); // Initialize the request attributes to specify the context size and type // for every request created by framework for this device. WDF_OBJECT_ATTRIBUTES_INIT(&requestAttributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&requestAttributes, REQUEST_CONTEXT); WdfDeviceInitSetRequestAttributes(DeviceInit, &requestAttributes); // Initialize WDF_FILEOBJECT_CONFIG_INIT struct to tell the // framework whether you are interested in handle Create, Close and // Cleanup requests that gets generate when an application or another // kernel component opens an handle to the device. If you don't register // the framework default behaviour would be complete these requests // with STATUS_SUCCESS. A driver might be interested in registering these // events if it wants to do security validation and also wants to maintain // per handle (fileobject) context. WDF_FILEOBJECT_CONFIG_INIT(&fileConfig, PSDrv_EvtDeviceFileCreate, WDF_NO_EVENT_CALLBACK, WDF_NO_EVENT_CALLBACK); // Specify a context for FileObject. If you register FILE_EVENT callbacks, // the framework by default creates a framework FILEOBJECT corresponding // to the WDM fileobject. If you want to track any per handle context, // use the context for FileObject. Driver that typically use FsContext // field should instead use Framework FileObject context. WDF_OBJECT_ATTRIBUTES_INIT(&fileObjectAttributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&fileObjectAttributes, FILE_CONTEXT); WdfDeviceInitSetFileObjectConfig(DeviceInit, &fileConfig, &fileObjectAttributes); // We can do iso transfer only if the io type is directio. WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); // Now specify the size of device extension where we track per device // context.DeviceInit is completely initialized. So call the framework // to create the device and attach it to the lower stack. WDF_OBJECT_ATTRIBUTES_INIT(&fdoAttributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&fdoAttributes, DEVICE_CONTEXT); status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfDeviceCreate failed! (Status = %x)\n", status)); return status; } // Get the DeviceObject context by using accessory function specified in // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_CONTEXT. pDevContext = GetDeviceContext(device); //Get MaximumTransferSize from registry maximumTransferSize=0; status = ReadFdoRegistryKeyValue(Driver, L"MaximumTransferSize", &maximumTransferSize); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("ReadFdoRegistryKeyValue failed with Status code %!STATUS!\n", status)); return status; } if (maximumTransferSize) { pDevContext->MaximumTransferSize = maximumTransferSize; } else { pDevContext->MaximumTransferSize = DEFAULT_REGISTRY_TRANSFER_SIZE; } // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so // that you don't get the popup in usermode (on Win2K) when you surprise // remove the device. WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); // Do not show the little green remove icon pnpCaps.SurpriseRemovalOK = WdfTrue; /* // Show the little green remove icon... pnpCaps.SurpriseRemovalOK = WdfFalse; pnpCaps.Removable = WdfTrue; */ WdfDeviceSetPnpCapabilities(device, &pnpCaps); // Register I/O callbacks to tell the framework that you are interested // in handling WdfRequestTypeRead, WdfRequestTypeWrite, and IRP_MJ_DEVICE_CONTROL requests. // WdfIoQueueDispatchParallel means that we are capable of handling // all the I/O request simultaneously and we are responsible for protecting // data that could be accessed by these callbacks simultaneously. // This queue will be, by default, auto managed by the framework with // respect to PNP and Power events. That is, framework will take care // of queuing, failing, dispatching incoming requests based on the current // pnp/power state of the device. WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchParallel); ioQueueConfig.EvtIoRead = PSDrv_EvtIoRead; ioQueueConfig.EvtIoWrite = PSDrv_EvtIoWrite; ioQueueConfig.EvtIoDeviceControl = PSDrv_EvtIoDeviceControl; ioQueueConfig.EvtIoStop = PSDrvEvtIoStop; ioQueueConfig.EvtIoResume = PSDrvEvtIoResume; status = WdfIoQueueCreate(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfIoQueueCreate failed! (Status = %x)\n", status)); return status; } // Register a device interface so that app can find our device and talk to it. status = WdfDeviceCreateDeviceInterface(device, (LPGUID)&GUID_CLASS_PSDRV_USB, NULL); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfDeviceCreateDeviceInterface failed! (Status = %x)\n", status)); return status; } PSDrv_DbgPrint(3, ("PSDrv_EvtDeviceAdd - ends\n")); return status; }