// Add device NTSTATUS GFilterAddDevice( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit) { NTSTATUS status; WDF_OBJECT_ATTRIBUTES deviceAttributes; WDFDEVICE device; PFILTER_EXTENSION filtExt; WDF_IO_QUEUE_CONFIG ioQueueConfig; WDFQUEUE ioDefaultQueue; DEBUG("Adding Device"); // Indicate we are a filter driver, This forwards all IRPs on to the lower filters WdfFdoInitSetFilter(DeviceInit); // Setup the actual filter for the IRPs #ifdef USE_SETIOINCALLERCONTEXTCALLBACK // Use built in KMDF filter WdfDeviceInitSetIoInCallerContextCallback( DeviceInit, GFilterIOCallback); #endif // Create a new device WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( &deviceAttributes, FILTER_EXTENSION); // no cleanup callback needed -- deviceAttributes.EvtCleanupCallback = GFilterDeviceCleanUp; // Set device unload callback status = WdfDeviceCreate( &DeviceInit, // Create the device &deviceAttributes, &device); CHECKSTATUS(status, return(status)); // Create the filter extension -- We don't really care about this really filtExt = FilterGetData(device); filtExt->Instance = 0x00; #ifndef USE_SETIOINCALLERCONTEXTCALLBACK // Create IO queue and set callbacks to be filtered. //!todo, we created a parrallel que here but some drivers may need multiple parallel queues which is not done WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &ioQueueConfig, // Create parallel IO queue in case the device we filter does not like sequential WdfIoQueueDispatchParallel ); ioQueueConfig.EvtIoRead = GFilterRead; // Read ioQueueConfig.EvtIoWrite = GFilterWrite; // Write status = WdfIoQueueCreate( device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &ioDefaultQueue); CHECKSTATUS(status, ERROR("Failed to create queues. status=0x%0.4x",status); goto GFilterAddDeviceCleanup); #endif // Create sideband communications to userspace #ifdef USE_CONTROL_DEVICE GFilterCreateControlDevice( device, ++DeviceInstances); //!todo, should we lock instance ?? #else GFilterCreateRawPDO( device, ++DeviceInstances); //!todo, should we lock instance ?? #endif GFilterAddDeviceCleanup: return(status); }
VCHIQ_PAGED_SEGMENT_BEGIN /*++ Routine Description: Worker routine called to create a device and its software resources. Arguments: DeviceInitPtr - Pointer to an opaque init structure. Memory for this structure will be freed by the framework when the WdfDeviceCreate succeeds. So don't access the structure after that point. Return Value: NTSTATUS --*/ _Use_decl_annotations_ NTSTATUS VchiqCreateDevice ( WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInitPtr ) { WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_OBJECT_ATTRIBUTES deviceAttributes; DEVICE_CONTEXT* deviceContextPtr; WDFDEVICE device; NTSTATUS status; WDF_IO_TYPE_CONFIG ioConfig; DECLARE_CONST_UNICODE_STRING(vchiqSymbolicLink, VCHIQ_SYMBOLIC_NAME); UNREFERENCED_PARAMETER(Driver); PAGED_CODE(); { WDF_FILEOBJECT_CONFIG fileobjectConfig; WDF_FILEOBJECT_CONFIG_INIT( &fileobjectConfig, WDF_NO_EVENT_CALLBACK, VchiqFileClose, WDF_NO_EVENT_CALLBACK); fileobjectConfig.FileObjectClass = WdfFileObjectWdfCanUseFsContext; WdfDeviceInitSetFileObjectConfig( DeviceInitPtr, &fileobjectConfig, WDF_NO_OBJECT_ATTRIBUTES); } WDF_IO_TYPE_CONFIG_INIT(&ioConfig); ioConfig.ReadWriteIoType = WdfDeviceIoDirect; ioConfig.DeviceControlIoType = WdfDeviceIoDirect; ioConfig.DirectTransferThreshold = 0; WdfDeviceInitSetIoTypeEx(DeviceInitPtr, &ioConfig); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); pnpPowerCallbacks.EvtDevicePrepareHardware = VchiqPrepareHardware; pnpPowerCallbacks.EvtDeviceReleaseHardware = VchiqReleaseHardware; pnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = VchiqInitOperation; WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInitPtr, &pnpPowerCallbacks); WdfDeviceInitSetIoInCallerContextCallback( DeviceInitPtr, VchiqInCallerContext); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( &deviceAttributes, DEVICE_CONTEXT); status = WdfDeviceCreate( &DeviceInitPtr, &deviceAttributes, &device); if (!NT_SUCCESS(status)) { VCHIQ_LOG_ERROR( "WdfDeviceCreate fail %!STATUS!", status); goto End; } { WDF_OBJECT_ATTRIBUTES attributes; WDF_IO_QUEUE_CONFIG queueConfig; WDFQUEUE queue; deviceContextPtr = VchiqGetDeviceContext(device); deviceContextPtr->Device = device; deviceContextPtr->VersionMajor = VCHIQ_VERSION_MAJOR; deviceContextPtr->VersionMinor = VCHIQ_VERSION_MINOR; deviceContextPtr->PhyDeviceObjectPtr = WdfDeviceWdmGetPhysicalDevice(device); WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &queueConfig, WdfIoQueueDispatchParallel); queueConfig.EvtIoDeviceControl = VchiqIoDeviceControl; queueConfig.EvtIoStop = VchiqIoStop; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ExecutionLevel = WdfExecutionLevelPassive; status = WdfIoQueueCreate( device, &queueConfig, &attributes, &queue); if (!NT_SUCCESS(status)) { VCHIQ_LOG_ERROR( "WdfIoQueueCreate fail %!STATUS!", status); goto End; } } // Create symbolic and device interface status = WdfDeviceCreateSymbolicLink( device, &vchiqSymbolicLink); if (!NT_SUCCESS(status)) { VCHIQ_LOG_ERROR( "Fail to register symbolic link %!STATUS!", status); goto End; } End: VCHIQ_LOG_INFORMATION("Exit Status %!STATUS!", status); return status; }
NTSTATUS NonPnpDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Called by the DriverEntry to create a control-device. This call is responsible for freeing the memory for DeviceInit. Arguments: DriverObject - a pointer to the object that represents this device driver. DeviceInit - Pointer to a driver-allocated WDFDEVICE_INIT structure. Return Value: STATUS_SUCCESS if initialized; an error otherwise. --*/ { NTSTATUS status; WDF_OBJECT_ATTRIBUTES attributes; WDF_IO_QUEUE_CONFIG ioQueueConfig; WDF_FILEOBJECT_CONFIG fileConfig; WDFQUEUE queue; WDFDEVICE controlDevice; DECLARE_CONST_UNICODE_STRING(ntDeviceName, NTDEVICE_NAME_STRING) ; DECLARE_CONST_UNICODE_STRING(symbolicLinkName, SYMBOLIC_NAME_STRING) ; UNREFERENCED_PARAMETER( Driver ); PAGED_CODE(); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "NonPnpDeviceAdd DeviceInit %p\n", DeviceInit); // // Set exclusive to TRUE so that no more than one app can talk to the // control device at any time. // WdfDeviceInitSetExclusive(DeviceInit, TRUE); WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceInitAssignName failed %!STATUS!", status); goto End; } WdfControlDeviceInitSetShutdownNotification(DeviceInit, NonPnpShutdown, WdfDeviceShutdown); // // Initialize WDF_FILEOBJECT_CONFIG_INIT struct to tell the // framework whether you are interested in handling Create, Close and // Cleanup requests that gets generated when an application or another // kernel component opens an handle to the device. If you don't register // the framework default behaviour would be to 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, NonPnpEvtDeviceFileCreate, NonPnpEvtFileClose, WDF_NO_EVENT_CALLBACK // not interested in Cleanup ); WdfDeviceInitSetFileObjectConfig(DeviceInit, &fileConfig, WDF_NO_OBJECT_ATTRIBUTES); // // In order to support METHOD_NEITHER Device controls, or // NEITHER device I/O type, we need to register for the // EvtDeviceIoInProcessContext callback so that we can handle the request // in the calling threads context. // WdfDeviceInitSetIoInCallerContextCallback(DeviceInit, NonPnpEvtDeviceIoInCallerContext); // // Specify the size of device context // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CONTROL_DEVICE_EXTENSION); status = WdfDeviceCreate(&DeviceInit, &attributes, &controlDevice); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreate failed %!STATUS!", status); goto End; } // // Create a symbolic link for the control object so that usermode can open // the device. // status = WdfDeviceCreateSymbolicLink(controlDevice, &symbolicLinkName); if (!NT_SUCCESS(status)) { // // Control device will be deleted automatically by the framework. // TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreateSymbolicLink failed %!STATUS!", status); goto End; } // // Configure a default queue so that requests that are not // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto // other queues get dispatched here. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoRead = FileEvtIoRead; ioQueueConfig.EvtIoWrite = FileEvtIoWrite; ioQueueConfig.EvtIoDeviceControl = FileEvtIoDeviceControl; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); // // Since we are using Zw function set execution level to passive so that // framework ensures that our Io callbacks called at only passive-level // even if the request came in at DISPATCH_LEVEL from another driver. // //attributes.ExecutionLevel = WdfExecutionLevelPassive; // // By default, Static Driver Verifier (SDV) displays a warning if it // doesn't find the EvtIoStop callback on a power-managed queue. // The 'assume' below causes SDV to suppress this warning. If the driver // has not explicitly set PowerManaged to WdfFalse, the framework creates // power-managed queues when the device is not a filter driver. Normally // the EvtIoStop is required for power-managed queues, but for this driver // it is not needed b/c the driver doesn't hold on to the requests or // forward them to other drivers. This driver completes the requests // directly in the queue's handlers. If the EvtIoStop callback is not // implemented, the framework waits for all driver-owned requests to be // done before moving in the Dx/sleep states or before removing the // device, which is the correct behavior for this type of driver. // If the requests were taking an indeterminate amount of time to complete, // or if the driver forwarded the requests to a lower driver/another stack, // the queue should have an EvtIoStop/EvtIoResume. // __analysis_assume(ioQueueConfig.EvtIoStop != 0); status = WdfIoQueueCreate(controlDevice, &ioQueueConfig, &attributes, &queue // pointer to default queue ); __analysis_assume(ioQueueConfig.EvtIoStop == 0); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfIoQueueCreate failed %!STATUS!", status); goto End; } // // Control devices must notify WDF when they are done initializing. I/O is // rejected until this call is made. // WdfControlFinishInitializing(controlDevice); End: // // If the device is created successfully, framework would clear the // DeviceInit value. Otherwise device create must have failed so we // should free the memory ourself. // if (DeviceInit != NULL) { WdfDeviceInitFree(DeviceInit); } return status; }