NTSTATUS bareflankCreateDevice( _Inout_ PWDFDEVICE_INIT DeviceInit ) { NTSTATUS status; WDFDEVICE device; WDF_OBJECT_ATTRIBUTES deviceAttributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT); status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); if (!NT_SUCCESS(status)) return status; status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_bareflank, NULL); if (!NT_SUCCESS(status)) return status; status = bareflankQueueInitialize(device); if (!NT_SUCCESS(status)) return status; DEBUG("bareflankCreateDevice: success\n"); return status; }
NTSTATUS EvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) { WDF_OBJECT_ATTRIBUTES attributes; NTSTATUS status; WDFDEVICE device; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; UNREFERENCED_PARAMETER(Driver); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); pnpPowerCallbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if (!NT_SUCCESS(status)) { KdPrint(("WdfDeviceCreate failed 0x%x\n", status)); return status; } status = WdfDeviceCreateDeviceInterface(device, (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, NULL);// Reference String if (!NT_SUCCESS(status)) { KdPrint(("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); return status; } return status; }
NTSTATUS EvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) { WDF_OBJECT_ATTRIBUTES attributes; NTSTATUS status; WDFDEVICE device; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_IO_QUEUE_CONFIG ioQueueConfig; UNREFERENCED_PARAMETER(Driver); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); pnpPowerCallbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if (!NT_SUCCESS(status)) { KdPrint(("WdfDeviceCreate failed %!STATUS!\n", status)); return status; } status = WdfDeviceCreateDeviceInterface(device, (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, NULL);// Reference String if (!NT_SUCCESS(status)) { KdPrint(("WdfDeviceCreateDeviceInterface failed %!STATUS!\n", status)); return status; } WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchParallel); ioQueueConfig.EvtIoDeviceControl = EvtIoDeviceControl; ioQueueConfig.EvtIoRead = EvtIoRead; ioQueueConfig.EvtIoWrite = EvtIoWrite; // // 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. // Please see 'final' step for implementation of EvtIoStop. // __analysis_assume(ioQueueConfig.EvtIoStop != 0); status = WdfIoQueueCreate(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE); __analysis_assume(ioQueueConfig.EvtIoStop == 0); if (!NT_SUCCESS(status)) { KdPrint(("WdfIoQueueCreate failed %!STATUS!\n", status)); return status; } return status; }
// 添加设备回调 NTSTATUS EvtDriverDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) { NTSTATUS status; WDFDEVICE device; // 设备对象 WDF_IO_QUEUE_CONFIG ioQueueConfig; WDF_FILEOBJECT_CONFIG fileConfig; PAGED_CODE(); // 互斥访问,同时刻只能一个应用程序与设备通信 WdfDeviceInitSetExclusive(DeviceInit, TRUE); // 缓冲IO方式 WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); // 初始化文件对象 WDF_FILEOBJECT_CONFIG_INIT(&fileConfig, EvtDeviceFileCreate, EvtFileClose, WDF_NO_EVENT_CALLBACK); WdfDeviceInitSetFileObjectConfig(DeviceInit, &fileConfig, WDF_NO_OBJECT_ATTRIBUTES); // 创建设备 status = WdfDeviceCreate(&DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &device); if( !NT_SUCCESS(status) ) { KdPrint(("[EvtDriverDeviceAdd] WdfDeviceCreate failed!")); return status; } //使用缺省队列,设置I/O请求分发处理方式为串行 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential); // 设置EvtIoRead回调例程 ioQueueConfig.EvtIoRead = EvtIoRead; // 设置EvtIoWrite回调例程 ioQueueConfig.EvtIoWrite = EvtIoWrite; //设置EvtIoDeviceControl回调例程 ioQueueConfig.EvtIoDeviceControl = EvtIoDeviceControl; // 创建队列 status = WdfIoQueueCreate(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE); if( !NT_SUCCESS(status) ) { KdPrint(("[EvtDriverDeviceAdd] WdfIoQueueCreate failed!")); return status; } // 创建设备接口 status = WdfDeviceCreateDeviceInterface(device,(LPGUID)&IOSample_DEVINTERFACE_GUID ,NULL); if( !NT_SUCCESS(status) ) { KdPrint(("[EvtDriverDeviceAdd] WdfDeviceCreateDeviceInterface failed!")); } return status; }
NTSTATUS XenUsb_EvtDriverDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init) { NTSTATUS status; WDF_CHILD_LIST_CONFIG child_list_config; WDFDEVICE device; PXENUSB_DEVICE_DATA xudd; //UNICODE_STRING reference; WDF_OBJECT_ATTRIBUTES device_attributes; PNP_BUS_INFORMATION pbi; WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks; WDF_DEVICE_POWER_CAPABILITIES power_capabilities; WDF_IO_QUEUE_CONFIG queue_config; UCHAR pnp_minor_functions[] = { IRP_MN_QUERY_INTERFACE }; DECLARE_CONST_UNICODE_STRING(symbolicname_name, L"SymbolicName"); WDFSTRING symbolicname_value_wdfstring; WDFKEY device_key; UNICODE_STRING symbolicname_value; UNREFERENCED_PARAMETER(driver); FUNCTION_ENTER(); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks); pnp_power_callbacks.EvtDeviceD0Entry = XenUsb_EvtDeviceD0Entry; pnp_power_callbacks.EvtDeviceD0Exit = XenUsb_EvtDeviceD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks); status = WdfDeviceInitAssignWdmIrpPreprocessCallback(device_init, XenUsb_EvtDeviceWdmIrpPreprocessQUERY_INTERFACE, IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions)); if (!NT_SUCCESS(status)) { return status; } WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_BUS_EXTENDER); WdfDeviceInitSetExclusive(device_init, FALSE); WDF_CHILD_LIST_CONFIG_INIT(&child_list_config, sizeof(XENUSB_PDO_IDENTIFICATION_DESCRIPTION), XenUsb_EvtChildListCreateDevice); child_list_config.EvtChildListScanForChildren = XenUsb_EvtChildListScanForChildren; WdfFdoInitSetDefaultChildListConfig(device_init, &child_list_config, WDF_NO_OBJECT_ATTRIBUTES); WdfDeviceInitSetIoType(device_init, WdfDeviceIoBuffered); WdfDeviceInitSetPowerNotPageable(device_init); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENUSB_DEVICE_DATA); status = WdfDeviceCreate(&device_init, &device_attributes, &device); if (!NT_SUCCESS(status)) { FUNCTION_MSG("Error creating device %08x\n", status); return status; } xudd = GetXudd(device); xudd->pdo = WdfDeviceWdmGetPhysicalDevice(device); xudd->child_list = WdfFdoGetDefaultChildList(device); KeInitializeEvent(&xudd->backend_event, SynchronizationEvent, FALSE); InitializeListHead(&xudd->partial_pvurb_queue); InitializeListHead(&xudd->partial_pvurb_ring); KeInitializeDpc(&xudd->event_dpc, XenUsb_HandleEventDpc, xudd); KeInitializeSpinLock(&xudd->urb_ring_lock); WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchParallel); queue_config.PowerManaged = FALSE; /* ? */ queue_config.EvtIoDeviceControl = XenUsb_EvtIoDeviceControl; queue_config.EvtIoInternalDeviceControl = XenUsb_EvtIoInternalDeviceControl; queue_config.EvtIoDefault = XenUsb_EvtIoDefault; status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xudd->io_queue); if (!NT_SUCCESS(status)) { FUNCTION_MSG("Error creating io_queue 0x%x\n", status); return status; } WDF_IO_QUEUE_CONFIG_INIT(&queue_config, WdfIoQueueDispatchParallel); queue_config.PowerManaged = FALSE; /* ? */ //queue_config.EvtIoDeviceControl = XenUsb_EvtIoDeviceControl; queue_config.EvtIoInternalDeviceControl = XenUsb_EvtIoInternalDeviceControl_PVURB; //queue_config.EvtIoDefault = XenUsb_EvtIoDefault; queue_config.Settings.Parallel.NumberOfPresentedRequests = USB_URB_RING_SIZE; /* the queue controls if the ring is full */ status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xudd->pvurb_queue); if (!NT_SUCCESS(status)) { FUNCTION_MSG("Error creating urb_queue 0x%x\n", status); return status; } WDF_DEVICE_POWER_CAPABILITIES_INIT(&power_capabilities); power_capabilities.DeviceD1 = WdfTrue; power_capabilities.WakeFromD1 = WdfTrue; power_capabilities.DeviceWake = PowerDeviceD1; power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0; power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1; power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2; power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2; power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3; power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3; WdfDeviceSetPowerCapabilities(device, &power_capabilities); WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE); WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE); WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE); pbi.BusTypeGuid = GUID_BUS_TYPE_XEN; pbi.LegacyBusType = PNPBus; pbi.BusNumber = 0; WdfDeviceSetBusInformationForChildren(device, &pbi); status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL); if (!NT_SUCCESS(status)) { FUNCTION_MSG("WdfDeviceCreateDeviceInterface returned %08x\n"); return status; } /* USB likes to have a registry key with the symbolic link name in it */ status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &symbolicname_value_wdfstring); if (!NT_SUCCESS(status)) { FUNCTION_MSG("WdfStringCreate returned %08x\n"); return status; } status = WdfDeviceRetrieveDeviceInterfaceString(device, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL, symbolicname_value_wdfstring); if (!NT_SUCCESS(status)) { FUNCTION_MSG("WdfDeviceRetrieveDeviceInterfaceString returned %08x\n"); return status; } WdfStringGetUnicodeString(symbolicname_value_wdfstring, &symbolicname_value); status = WdfDeviceOpenRegistryKey(device, PLUGPLAY_REGKEY_DEVICE, KEY_SET_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &device_key); if (!NT_SUCCESS(status)) { FUNCTION_MSG("WdfDeviceOpenRegistryKey returned %08x\n"); return status; } WdfRegistryAssignUnicodeString(device_key, &symbolicname_name, &symbolicname_value); FUNCTION_EXIT(); return status; }
NTSTATUS PLxEvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. Here the driver should register all the PNP, power and Io callbacks, register interfaces and allocate other software resources required by the device. The driver can query any interfaces or get the config space information from the bus driver but cannot access hardware registers or initialize the device. Arguments: Return Value: --*/ { KdPrint(("Entry PLxEvtDeviceAdd Routine")); NTSTATUS status = STATUS_SUCCESS; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_OBJECT_ATTRIBUTES attributes; WDFDEVICE device; PDEVICE_EXTENSION devExt = NULL; UNREFERENCED_PARAMETER( Driver ); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> PLxEvtDeviceAdd"); PAGED_CODE(); WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); // // Zero out the PnpPowerCallbacks structure. // WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); // // Set Callbacks for any of the functions we are interested in. // If no callback is set, Framework will take the default action // by itself. // pnpPowerCallbacks.EvtDevicePrepareHardware = PLxEvtDevicePrepareHardware; pnpPowerCallbacks.EvtDeviceReleaseHardware = PLxEvtDeviceReleaseHardware; // // These two callbacks set up and tear down hardware state that must be // done every time the device moves in and out of the D0-working state. // pnpPowerCallbacks.EvtDeviceD0Entry = PLxEvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0Exit = PLxEvtDeviceD0Exit; // // Register the PnP Callbacks.. // WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); // // Initialize Fdo Attributes. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_EXTENSION); // // By opting for SynchronizationScopeDevice, we tell the framework to // synchronize callbacks events of all the objects directly associated // with the device. In this driver, we will associate queues and // and DpcForIsr. By doing that we don't have to worrry about synchronizing // access to device-context by Io Events and DpcForIsr because they would // not concurrently ever. Framework will serialize them by using an // internal device-lock. // attributes.SynchronizationScope = WdfSynchronizationScopeDevice; // // Create the device // status = WdfDeviceCreate( &DeviceInit, &attributes, &device ); if (!NT_SUCCESS(status)) { // // Device Initialization failed. // TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "DeviceCreate failed %!STATUS!", status); return status; } // // Get the DeviceExtension and initialize it. PLxGetDeviceContext is an inline function // defined by WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in the // private header file. This function will do the type checking and return // the device context. If you pass a wrong object a wrong object handle // it will return NULL and assert if run under framework verifier mode. // devExt = PLxGetDeviceContext(device); devExt->Device = device; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, " AddDevice PDO (0x%p) FDO (0x%p), DevExt (0x%p)", WdfDeviceWdmGetPhysicalDevice(device), WdfDeviceWdmGetDeviceObject(device), devExt); // // Tell the Framework that this device will need an interface // // NOTE: See the note in Public.h concerning this GUID value. // status = WdfDeviceCreateDeviceInterface( device, (LPGUID) &GUID_PLX_INTERFACE, NULL ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "<-- DeviceCreateDeviceInterface " "failed %!STATUS!", status); return status; } // // Set the idle and wait-wake policy for this device. // status = PLxSetIdleAndWakeSettings(devExt); if (!NT_SUCCESS (status)) { // // NOTE: The attempt to set the Idle and Wake options // is a best-effort try. Failure is probably due to // the non-driver environmentals, such as the system, // bus or OS indicating that Wake is not supported for // this case. // All that being said, it probably not desirable to // return the failure code as it would cause the // AddDevice to fail and Idle and Wake are probably not // "must-have" options. // // You must decide for your case whether Idle/Wake are // "must-have" options...but my guess is probably not. // #if 1 status = STATUS_SUCCESS; #else return status; #endif } // // Initalize the Device Extension. // status = PLxInitializeDeviceExtension(devExt); if (!NT_SUCCESS(status)) { return status; } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- PLxEvtDeviceAdd %!STATUS!", status); KdPrint(("Leave PLxEvtDeviceAdd Routine")); return status; }
NTSTATUS OsrFxEvtDeviceAdd( WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit ) /*++ 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 --*/ { WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_OBJECT_ATTRIBUTES attributes; NTSTATUS status; WDFDEVICE device; WDF_DEVICE_PNP_CAPABILITIES pnpCaps; WDF_IO_QUEUE_CONFIG ioQueueConfig; PDEVICE_CONTEXT pDevContext; WDFQUEUE queue; GUID activity; UNREFERENCED_PARAMETER(Driver); PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> OsrFxEvtDeviceAdd routine\n"); // // 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); // // For usb devices, PrepareHardware callback is the to place select the // interface and configure the device. // pnpPowerCallbacks.EvtDevicePrepareHardware = OsrFxEvtDevicePrepareHardware; // // These two callbacks start and stop the wdfusb pipe continuous reader // as we go in and out of the D0-working state. // pnpPowerCallbacks.EvtDeviceD0Entry = OsrFxEvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0Exit = OsrFxEvtDeviceD0Exit; pnpPowerCallbacks.EvtDeviceSelfManagedIoFlush = OsrFxEvtDeviceSelfManagedIoFlush; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); // // 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_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreate failed with Status code %!STATUS!\n", status); return status; } // // Setup the activity ID so that we can log events using it. // activity = DeviceToActivityId(device); // // Get the DeviceObject context by using accessor function specified in // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_CONTEXT. // pDevContext = GetDeviceContext(device); // // Get the device's friendly name and location so that we can use it in // error logging. If this fails then it will setup dummy strings. // GetDeviceEventLoggingNames(device); // // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so // that you don't get the popup in usermodewhen you surprise remove the device. // WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); pnpCaps.SurpriseRemovalOK = WdfTrue; WdfDeviceSetPnpCapabilities(device, &pnpCaps); // // Create a parallel default queue and register an event callback to // receive ioctl requests. We will create separate queues for // handling read and write requests. All other requests will be // completed with error status automatically by the framework. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchParallel); ioQueueConfig.EvtIoDeviceControl = OsrFxEvtIoDeviceControl; // // 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 for // long time or forward them to other drivers. // 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(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue);// pointer to default queue __analysis_assume(ioQueueConfig.EvtIoStop == 0); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed %!STATUS!\n", status); goto Error; } // // We will create a separate sequential queue and configure it // to receive read requests. We also need to register a EvtIoStop // handler so that we can acknowledge requests that are pending // at the target driver. // WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoRead = OsrFxEvtIoRead; ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; status = WdfIoQueueCreate( device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue // queue handle ); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed 0x%x\n", status); goto Error; } status = WdfDeviceConfigureRequestDispatching( device, queue, WdfRequestTypeRead); if(!NT_SUCCESS (status)){ assert(NT_SUCCESS(status)); TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); goto Error; } // // We will create another sequential queue and configure it // to receive write requests. // WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoWrite = OsrFxEvtIoWrite; ioQueueConfig.EvtIoStop = OsrFxEvtIoStop; status = WdfIoQueueCreate( device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue // queue handle ); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed 0x%x\n", status); goto Error; } status = WdfDeviceConfigureRequestDispatching( device, queue, WdfRequestTypeWrite); if(!NT_SUCCESS (status)){ assert(NT_SUCCESS(status)); TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceConfigureRequestDispatching failed 0x%x\n", status); goto Error; } // // Register a manual I/O queue for handling Interrupt Message Read Requests. // This queue will be used for storing Requests that need to wait for an // interrupt to occur before they can be completed. // WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchManual); // // This queue is used for requests that dont directly access the device. The // requests in this queue are serviced only when the device is in a fully // powered state and sends an interrupt. So we can use a non-power managed // queue to park the requests since we dont care whether the device is idle // or fully powered up. // ioQueueConfig.PowerManaged = WdfFalse; status = WdfIoQueueCreate(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pDevContext->InterruptMsgQueue ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed 0x%x\n", status); goto Error; } // // Register a device interface so that app can find our device and talk to it. // status = WdfDeviceCreateDeviceInterface(device, (LPGUID) &GUID_DEVINTERFACE_OSRUSBFX2, NULL); // Reference String if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreateDeviceInterface failed %!STATUS!\n", status); goto Error; } // // Create the lock that we use to serialize calls to ResetDevice(). As an // alternative to using a WDFWAITLOCK to serialize the calls, a sequential // WDFQUEUE can be created and reset IOCTLs would be forwarded to it. // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = device; status = WdfWaitLockCreate(&attributes, &pDevContext->ResetDeviceWaitLock); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfWaitLockCreate failed %!STATUS!\n", status); goto Error; } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- OsrFxEvtDeviceAdd\n"); return status; Error: // // Log fail to add device to the event log // EventWriteFailAddDevice(pDevContext->DeviceName, pDevContext->Location, status); return status; }
NTSTATUS VIOSerialDeviceListCreatePdo( IN WDFCHILDLIST DeviceList, IN PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, IN PWDFDEVICE_INIT ChildInit ) { PVIOSERIAL_PORT pport = NULL; NTSTATUS status = STATUS_SUCCESS; WDFDEVICE hChild = NULL; WDF_OBJECT_ATTRIBUTES attributes; WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks; WDF_DEVICE_PNP_CAPABILITIES pnpCaps; WDF_DEVICE_STATE deviceState; WDF_IO_QUEUE_CONFIG queueConfig; PRAWPDO_VIOSERIAL_PORT rawPdo = NULL; WDF_FILEOBJECT_CONFIG fileConfig; DECLARE_CONST_UNICODE_STRING(deviceId, PORT_DEVICE_ID ); DECLARE_CONST_UNICODE_STRING(deviceLocation, L"RedHat VIOSerial Port" ); DECLARE_UNICODE_STRING_SIZE(buffer, DEVICE_DESC_LENGTH); UNREFERENCED_PARAMETER(DeviceList); PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); pport = CONTAINING_RECORD(IdentificationDescription, VIOSERIAL_PORT, Header ); WdfDeviceInitSetDeviceType(ChildInit, FILE_DEVICE_SERIAL_PORT); WdfDeviceInitSetIoType(ChildInit, WdfDeviceIoDirect); do { WdfDeviceInitSetExclusive(ChildInit, TRUE); status = WdfPdoInitAssignRawDevice(ChildInit, &GUID_DEVCLASS_PORT_DEVICE); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfPdoInitAssignRawDevice failed - 0x%x\n", status); break; } status = WdfDeviceInitAssignSDDLString(ChildInit, &SDDL_DEVOBJ_SYS_ALL_ADM_ALL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceInitAssignSDDLString failed - 0x%x\n", status); break; } status = WdfPdoInitAssignDeviceID(ChildInit, &deviceId); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfPdoInitAssignDeviceID failed - 0x%x\n", status); break; } status = WdfPdoInitAddHardwareID(ChildInit, &deviceId); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfPdoInitAddHardwareID failed - 0x%x\n", status); break; } status = RtlUnicodeStringPrintf( &buffer, L"%02u", pport->PortId ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "RtlUnicodeStringPrintf failed - 0x%x\n", status); break; } status = WdfPdoInitAssignInstanceID(ChildInit, &buffer); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfPdoInitAssignInstanceID failed - 0x%x\n", status); break; } status = RtlUnicodeStringPrintf( &buffer, L"vport%up%u", pport->DeviceId, pport->PortId ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "RtlUnicodeStringPrintf failed 0x%x\n", status); break; } status = WdfPdoInitAddDeviceText( ChildInit, &buffer, &deviceLocation, 0x409 ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfPdoInitAddDeviceText failed 0x%x\n", status); break; } WdfPdoInitSetDefaultLocale(ChildInit, 0x409); WDF_FILEOBJECT_CONFIG_INIT( &fileConfig, VIOSerialPortCreate, VIOSerialPortClose, WDF_NO_EVENT_CALLBACK ); WdfDeviceInitSetFileObjectConfig( ChildInit, &fileConfig, WDF_NO_OBJECT_ATTRIBUTES ); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks); PnpPowerCallbacks.EvtDeviceD0Entry = VIOSerialPortEvtDeviceD0Entry; PnpPowerCallbacks.EvtDeviceD0ExitPreInterruptsDisabled = VIOSerialPortEvtDeviceD0ExitPreInterruptsDisabled; PnpPowerCallbacks.EvtDeviceD0Exit = VIOSerialPortEvtDeviceD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(ChildInit, &PnpPowerCallbacks); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, RAWPDO_VIOSERIAL_PORT); attributes.SynchronizationScope = WdfSynchronizationScopeDevice; attributes.ExecutionLevel = WdfExecutionLevelPassive; status = WdfDeviceCreate( &ChildInit, &attributes, &hChild ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreate failed 0x%x\n", status); break; } rawPdo = RawPdoSerialPortGetData(hChild); rawPdo->port = pport; pport->Device = hChild; WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchSequential ); queueConfig.EvtIoDeviceControl = VIOSerialPortDeviceControl; status = WdfIoQueueCreate(hChild, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pport->IoctlQueue ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed (IoCtrl Queue): 0x%x\n", status); break; } status = WdfDeviceConfigureRequestDispatching( hChild, pport->IoctlQueue, WdfRequestTypeDeviceControl ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "DeviceConfigureRequestDispatching failed (IoCtrl Queue): 0x%x\n", status); break; } WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchSequential); queueConfig.EvtIoRead = VIOSerialPortRead; queueConfig.EvtIoStop = VIOSerialPortIoStop; status = WdfIoQueueCreate(hChild, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pport->ReadQueue ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate (Read Queue) failed 0x%x\n", status); break; } status = WdfDeviceConfigureRequestDispatching( hChild, pport->ReadQueue, WdfRequestTypeRead ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "DeviceConfigureRequestDispatching failed (Read Queue): 0x%x\n", status); break; } WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchSequential); queueConfig.AllowZeroLengthRequests = WdfFalse; queueConfig.EvtIoWrite = VIOSerialPortWrite; status = WdfIoQueueCreate(hChild, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &pport->WriteQueue); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfIoQueueCreate failed (Write Queue): 0x%x\n", status); break; } status = WdfDeviceConfigureRequestDispatching( hChild, pport->WriteQueue, WdfRequestTypeWrite ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "DeviceConfigureRequestDispatching failed (Write Queue): 0x%x\n", status); break; } WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); pnpCaps.NoDisplayInUI = WdfTrue; pnpCaps.Removable = WdfTrue; pnpCaps.EjectSupported = WdfTrue; pnpCaps.SurpriseRemovalOK= WdfTrue; pnpCaps.Address = pport->DeviceId; pnpCaps.UINumber = pport->PortId; WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); WDF_DEVICE_STATE_INIT(&deviceState); deviceState.DontDisplayInUI = WdfTrue; WdfDeviceSetDeviceState(hChild, &deviceState); status = WdfDeviceCreateDeviceInterface( hChild, &GUID_VIOSERIAL_PORT, NULL ); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreateDeviceInterface failed 0x%x\n", status); break; } WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = hChild; status = WdfSpinLockCreate( &attributes, &pport->InBufLock ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfSpinLockCreate failed 0x%x\n", status); break; } WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = hChild; status = WdfSpinLockCreate( &attributes, &pport->OutVqLock ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfSpinLockCreate failed 0x%x\n", status); break; } } while (0); if (!NT_SUCCESS(status)) { // We can send this before PDO is PRESENT since the device won't send any response. VIOSerialSendCtrlMsg(pport->BusDevice, pport->PortId, VIRTIO_CONSOLE_PORT_READY, 0); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s status 0x%x\n", __FUNCTION__, status); 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; }
NTSTATUS VIOSerialEvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit) { NTSTATUS status = STATUS_SUCCESS; WDF_OBJECT_ATTRIBUTES Attributes; WDFDEVICE hDevice; WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks; WDF_CHILD_LIST_CONFIG ChildListConfig; PNP_BUS_INFORMATION busInfo; PPORTS_DEVICE pContext = NULL; UNREFERENCED_PARAMETER(Driver); PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks); PnpPowerCallbacks.EvtDevicePrepareHardware = VIOSerialEvtDevicePrepareHardware; PnpPowerCallbacks.EvtDeviceReleaseHardware = VIOSerialEvtDeviceReleaseHardware; PnpPowerCallbacks.EvtDeviceD0Entry = VIOSerialEvtDeviceD0Entry; PnpPowerCallbacks.EvtDeviceD0Exit = VIOSerialEvtDeviceD0Exit; PnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = VIOSerialEvtDeviceD0EntryPostInterruptsEnabled; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PnpPowerCallbacks); WDF_CHILD_LIST_CONFIG_INIT( &ChildListConfig, sizeof(VIOSERIAL_PORT), VIOSerialDeviceListCreatePdo ); ChildListConfig.EvtChildListIdentificationDescriptionDuplicate = VIOSerialEvtChildListIdentificationDescriptionDuplicate; ChildListConfig.EvtChildListIdentificationDescriptionCompare = VIOSerialEvtChildListIdentificationDescriptionCompare; ChildListConfig.EvtChildListIdentificationDescriptionCleanup = VIOSerialEvtChildListIdentificationDescriptionCleanup; WdfFdoInitSetDefaultChildListConfig( DeviceInit, &ChildListConfig, WDF_NO_OBJECT_ATTRIBUTES ); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, PORTS_DEVICE); Attributes.SynchronizationScope = WdfSynchronizationScopeDevice; Attributes.ExecutionLevel = WdfExecutionLevelPassive; status = WdfDeviceCreate(&DeviceInit, &Attributes, &hDevice); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreate failed - 0x%x\n", status); return status; } status = VIOSerialInitInterruptHandling(hDevice); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIOSerialInitInterruptHandling failed - 0x%x\n", status); } status = WdfDeviceCreateDeviceInterface( hDevice, &GUID_VIOSERIAL_CONTROLLER, NULL ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreateDeviceInterface failed - 0x%x\n", status); return status; } pContext = GetPortsDevice(hDevice); pContext->DeviceId = gDeviceCount++; busInfo.BusTypeGuid = GUID_DEVCLASS_PORT_DEVICE; busInfo.LegacyBusType = PNPBus; busInfo.BusNumber = pContext->DeviceId; WdfDeviceSetBusInformationForChildren(hDevice, &busInfo); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__); return status; }
NTSTATUS vJoy_CreateRawPdo( WDFDEVICE Device, ULONG InstanceNo ) /*++ Routine Description: This routine creates and initialize a PDO. Arguments: Return Value: NT Status code. --*/ { NTSTATUS status; PWDFDEVICE_INIT pDeviceInit = NULL; PRPDO_DEVICE_DATA pdoData = NULL; WDFDEVICE hChild = NULL; WDF_OBJECT_ATTRIBUTES pdoAttributes; WDF_DEVICE_PNP_CAPABILITIES pnpCaps; WDF_IO_QUEUE_CONFIG ioQueueConfig; WDFQUEUE queue; WDF_DEVICE_STATE deviceState; PDEVICE_EXTENSION devExt; DECLARE_CONST_UNICODE_STRING(deviceId,VJOY_RAW_DEVICE_ID ); //DECLARE_CONST_UNICODE_STRING(hardwareId,VJOY_HARDWARE_ID ); DECLARE_CONST_UNICODE_STRING(deviceLocation,L"vJoy Raw Device\0" ); DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN); PDEVICE_OBJECT ChildDeviceObject; PDEVICE_OBJECT ParentDeviceObject; DECLARE_CONST_UNICODE_STRING( SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R_RES_R, L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GR;;;WD)(A;;GR;;;RC)" ); DECLARE_CONST_UNICODE_STRING( SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_R, L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGWGX;;;WD)(A;;GR;;;RC)" ); int iInterface; WCHAR RefStr[20]; UNICODE_STRING RefStr2; WDF_FILEOBJECT_CONFIG FileObjInit; WDF_OBJECT_ATTRIBUTES FileObjAttributes; WDF_OBJECT_ATTRIBUTES LockAttributes; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Entered vJoy_CreateRawPdo\n"); // // Allocate a WDFDEVICE_INIT structure and set the properties // so that we can create a device object for the child. // pDeviceInit = WdfPdoInitAllocate(Device); if (pDeviceInit == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAllocate", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Mark the device RAW so that the child device can be started // and accessed without requiring a function driver. Since we are // creating a RAW PDO, we must provide a class guid. // status = WdfPdoInitAssignRawDevice(pDeviceInit, &GUID_DEVINTERFACE_VJOY); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAssignRawDevice", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // TODO: Assign correct SDDL //// status = WdfDeviceInitAssignSDDLString(pDeviceInit, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_R); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfDeviceInitAssignSDDLString", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Assign DeviceID - This will be reported to IRP_MN_QUERY_ID/BusQueryDeviceID // status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAssignDeviceID", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // We could be enumerating more than one children if the filter attaches // to multiple instances of keyboard, so we must provide a // BusQueryInstanceID. If we don't, system will throw CA bugcheck. // status = RtlUnicodeStringPrintf(&buffer, VJOY_DEVICE_INSTANCE, InstanceNo); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"RtlUnicodeStringPrintf (1)", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAssignInstanceID", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Provide a description about the device. This text is usually read from // the device. This text is displayed momentarily by the PnP manager while // it's looking for a matching INF. If it finds one, it uses the Device // Description from the INF file to display in the device manager. // Since our device is raw device and we don't provide any hardware ID // to match with an INF, this text will be displayed in the device manager. // status = RtlUnicodeStringPrintf(&buffer,VJOY_DEVICE_TEXT_409 ); // English - United States if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"RtlUnicodeStringPrintf (2)", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // You can call WdfPdoInitAddDeviceText multiple times, adding device // text for multiple locales. When the system displays the text, it // chooses the text that matches the current locale, if available. // Otherwise it will use the string for the default locale. // The driver can specify the driver's default locale by calling // WdfPdoInitSetDefaultLocale. // status = WdfPdoInitAddDeviceText(pDeviceInit, &buffer, &deviceLocation, 0x409 // English - United States ); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAddDeviceText (1)", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } #if 0 // Hebrew (No real ned - just for fun) status = RtlUnicodeStringPrintf(&buffer,VJOY_DEVICE_TEXT_40D, InstanceNo ); // Hebrew if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"RtlUnicodeStringPrintf (3)", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } status = WdfPdoInitAddDeviceText(pDeviceInit, &buffer, &deviceLocation, 0x40D // Hebrew ); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfPdoInitAddDeviceText (2)", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } #endif // 0 WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409); // English - United States WdfDeviceInitSetExclusive(pDeviceInit, FALSE); // Create a WDFFILEOBJECT WDF_OBJECT_ATTRIBUTES_INIT(&FileObjAttributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&FileObjAttributes, FILEOBJECT_EXTENSION); WDF_FILEOBJECT_CONFIG_INIT(&FileObjInit, vJoy_EvtDeviceFileCreate, WDF_NO_EVENT_CALLBACK, vJoy_EvtFileCleanup); WdfDeviceInitSetFileObjectConfig(pDeviceInit, &FileObjInit, &FileObjAttributes); // // Initialize the attributes to specify the size of PDO device extension. // All the state information private to the PDO will be tracked here. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, RPDO_DEVICE_DATA); pdoAttributes.EvtCleanupCallback = rawEvtCleanupCallback; // // Set up our queue to allow forwarding of requests to the parent // This is done so that the cached data can be retrieved // //WdfPdoInitAllowForwardingRequestToParent(pDeviceInit); // TODO: Replace the above because it is needed for WdfRequestForwardToParentDeviceIoQueue() status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfDeviceCreate", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Get the device context. // pdoData = PdoGetData(hChild); pdoData->InstanceNo = InstanceNo; pdoData->hParentDevice = Device; // // Save the I/O target handle and adjust the I/O stack size: // devExt = GetDeviceContext(Device); pdoData->IoTargetToParent = devExt->IoTargetToSelf; ChildDeviceObject = WdfDeviceWdmGetDeviceObject(hChild); ParentDeviceObject = WdfDeviceWdmGetDeviceObject(Device); ChildDeviceObject->StackSize = ParentDeviceObject->StackSize+1; // Create a wait-lock object that will be used to synch access to positions[i] // The lock is created when the raw device is created so the raw device is set to be its parent WDF_OBJECT_ATTRIBUTES_INIT(&LockAttributes); LockAttributes.ParentObject = hChild; status = WdfWaitLockCreate(&LockAttributes, &(devExt->positionLock)); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfWaitLockCreate failed 0x%x\n", status); LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfWaitLockCreate", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Configure the default queue associated with the control device object // to be Serial so that request passed to EvtIoDeviceControl are serialized. // A default queue gets all the requests that are not // configure-fowarded using WdfDeviceConfigureRequestDispatching. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoDeviceControl = vJoy_EvtIoDeviceControlForRawPdo; status = WdfIoQueueCreate(hChild, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue // pointer to default queue ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfIoQueueCreate failed 0x%x\n", status); LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfIoQueueCreate", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } // // Set some properties for the child device. // WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); pnpCaps.Removable = WdfTrue; // Remove Icon from " Devices and Printers" pnpCaps.SurpriseRemovalOK = WdfTrue; pnpCaps.NoDisplayInUI = WdfTrue; // pnpCaps.Address = InstanceNo; pnpCaps.UINumber = 0; WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); // // TODO: In addition to setting NoDisplayInUI in DeviceCaps, we // have to do the following to hide the device. Following call // tells the framework to report the device state in // IRP_MN_QUERY_DEVICE_STATE request. // WDF_DEVICE_STATE_INIT(&deviceState); deviceState.DontDisplayInUI = WdfTrue; // Remove Icon from Device manager WdfDeviceSetDeviceState(hChild, &deviceState); // // Create 16 interfaces // for (iInterface=1 ; iInterface <= MAX_N_DEVICES; iInterface++) { RtlStringCchPrintfW((NTSTRSAFE_PWSTR)RefStr, 20, VJOY_INTERFACE L"%03d", iInterface); RtlInitUnicodeString(&RefStr2, (PCWSTR)RefStr); status = WdfDeviceCreateDeviceInterface(hChild,&GUID_DEVINTERFACE_VJOY,&RefStr2); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfDeviceCreateDeviceInterface number %d failed 0x%x\n", iInterface, status); LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfDeviceCreateDeviceInterface", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } }; // Mark all interfaces as unused pdoData->UsedInterfacesMask=0; // // Add this device to the FDO's collection of children. // After the child device is added to the static collection successfully, // driver must call WdfPdoMarkMissing to get the device deleted. It // shouldn't delete the child device directly by calling WdfObjectDelete. // status = WdfFdoAddStaticChild(Device, hChild); if (!NT_SUCCESS(status)) { LogEventWithStatus(ERRLOG_RAW_DEV_FAILED ,L"WdfFdoAddStaticChild", WdfDriverWdmGetDriverObject(WdfGetDriver()), status); goto Cleanup; } return STATUS_SUCCESS; Cleanup: TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "KbFiltr_CreatePdo failed %x\n", status); // // Call WdfDeviceInitFree if you encounter an error while initializing // a new framework device object. If you call WdfDeviceInitFree, // do not call WdfDeviceCreate. // if (pDeviceInit != NULL) { WdfDeviceInitFree(pDeviceInit); } if(hChild) { WdfObjectDelete(hChild); } return status; }
NTSTATUS CVWindowsInternalsCreateDevice( _Inout_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Worker routine called to create a device and its software resources. Arguments: DeviceInit - 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 --*/ { WDF_OBJECT_ATTRIBUTES deviceAttributes; PDEVICE_CONTEXT deviceContext; WDFDEVICE device; NTSTATUS status; PAGED_CODE(); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT); status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); if (NT_SUCCESS(status)) { // // Get a pointer to the device context structure that we just associated // with the device object. We define this structure in the device.h // header file. DeviceGetContext is an inline function generated by // using the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in device.h. // This function will do the type checking and return the device context. // If you pass a wrong object handle it will return NULL and assert if // run under framework verifier mode. // deviceContext = DeviceGetContext(device); // // Initialize the context. // deviceContext->PrivateDeviceData = 0; // // Create a device interface so that applications can find and talk // to us. // status = WdfDeviceCreateDeviceInterface( device, &GUID_DEVINTERFACE_CVWindowsInternals, NULL // ReferenceString ); if (NT_SUCCESS(status)) { // // Initialize the I/O Package and any Queues // status = CVWindowsInternalsQueueInitialize(device); } } return status; }
NTSTATUS FmEvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: FmEvtDeviceAdd 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 Fm device. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { NTSTATUS status = STATUS_SUCCESS; PFM_DEVICE_DATA fmDeviceData; WDF_IO_QUEUE_CONFIG queueConfig; WDF_OBJECT_ATTRIBUTES fdoAttributes; WDFDEVICE hDevice; WDFQUEUE defQueue; UNREFERENCED_PARAMETER(Driver); KdPrint( ("FmEvtDeviceAdd routine \n")); PAGED_CODE(); // // Modem type is serial port. // WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SERIAL_PORT); // // Use Buffered IO. // WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); // // Specify the size of device extension where we track per device // context. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FM_DEVICE_DATA); // // Register a cleanup callback on the device to free up some resources at the // time the device is deleted. // fdoAttributes.EvtCleanupCallback = FmDeviceCleanup; // // By opting for SynchronizationScopeDevice, we tell the framework to // synchronize callbacks events of all the objects directly associated // with the device. In this driver, we will associate queues. // By doing that we don't have to worrry about synchronizing // access to device-context by various io Events. // Framework will serialize them by using an internal device-lock. // fdoAttributes.SynchronizationScope = WdfSynchronizationScopeDevice; // // Create a framework device object.This call will inturn create // a WDM deviceobject, attach to the lower stack and set the // appropriate flags and attributes. // status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &hDevice); if (!NT_SUCCESS(status)) { KdPrint( ("WdfDeviceCreate failed with Status code 0x%x\n", status)); return status; } // // Get the DeviceExtension and initialize it. // fmDeviceData = FmDeviceDataGet(hDevice); // // Tell the Framework that this device will need an interface // status = WdfDeviceCreateDeviceInterface( hDevice, (LPGUID) &GUID_DEVINTERFACE_MODEM, NULL ); if (!NT_SUCCESS (status)) { KdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); return status; } fmDeviceData->Flags = 0; status = FmCreateDosDevicesSymbolicLink(hDevice, fmDeviceData); if (!NT_SUCCESS(status)) { KdPrint( ("FmCreateDosDevicesSymbolicLink failed with Status code 0x%x\n", status)); return status; } // // Initialize the context // fmDeviceData->BaudRate=1200; fmDeviceData->LineControl = SERIAL_7_DATA | SERIAL_EVEN_PARITY | SERIAL_NONE_PARITY; // // Register I/O callbacks to tell the framework that you are interested // in handling IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests. // In case a specific handler is not specified for one of these, // the request will be dispatched to the EvtIoDefault handler, if any. // If there is no EvtIoDefault handler, the request will be failed with // STATUS_INVALID_DEVICE_REQUEST. // 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. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); queueConfig.EvtIoRead = FmEvtIoRead; queueConfig.EvtIoWrite = FmEvtIoWrite; queueConfig.EvtIoDeviceControl = FmEvtIoDeviceControl; status = WdfIoQueueCreate( hDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &defQueue // pointer to default queue ); if (!NT_SUCCESS (status)) { // // We don't need to cleanup symbolic link here. The destroy callback for // the device object will do it. // return status; } // // Create a manual queue to hold pending read requests. By keeping // them in the queue, framework takes care of cancelling them if the app exits // WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); status = WdfIoQueueCreate(hDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &fmDeviceData->FmReadQueue ); if (!NT_SUCCESS (status)) { KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); return status; } // // Create a manual queue to hold pending ioctl wait mask requests. By keeping // them in the queue, framework takes care of cancelling them if the app exits // WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); status = WdfIoQueueCreate(hDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &fmDeviceData->FmMaskWaitQueue ); if (!NT_SUCCESS (status)) { KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); return status; } return status; }
NTSTATUS ToasterEvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: ToasterEvtDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. We create and initialize a WDF device object to represent a new instance of toaster device. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { NTSTATUS status = STATUS_SUCCESS; PFDO_DATA fdoData; WDF_IO_QUEUE_CONFIG queueConfig; WDF_OBJECT_ATTRIBUTES fdoAttributes; WDFDEVICE hDevice; WDFQUEUE queue; UNREFERENCED_PARAMETER(Driver); PAGED_CODE(); KdPrint(("ToasterEvtDeviceAdd called\n")); // // Initialize attributes and a context area for the device object. // // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DATA); // // Create a framework device object.This call will in turn create // a WDM device object, attach to the lower stack, and set the // appropriate flags and attributes. // status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &hDevice); if (!NT_SUCCESS(status)) { KdPrint( ("WdfDeviceCreate failed with status code 0x%x\n", status)); return status; } // // Get the device context by using the accessor function specified in // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for FDO_DATA. // fdoData = ToasterFdoGetData(hDevice); // // Tell the Framework that this device will need an interface // status = WdfDeviceCreateDeviceInterface( hDevice, (LPGUID) &GUID_DEVINTERFACE_TOASTER, NULL // ReferenceString ); if (!NT_SUCCESS (status)) { KdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); return status; } // // Register I/O callbacks to tell the framework that you are interested // in handling IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests. // If a specific callback function is not specified for one ofthese, // the request will be dispatched to the EvtIoDefault handler, if any. // If there is no EvtIoDefault handler, the request will be failed with // STATUS_INVALID_DEVICE_REQUEST. // WdfIoQueueDispatchParallel means that we are capable of handling // all the I/O requests simultaneously and we are responsible for protecting // data that could be accessed by these callbacks simultaneously. // A default queue gets all the requests that are not // configured for forwarding using WdfDeviceConfigureRequestDispatching. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); queueConfig.EvtIoRead = ToasterEvtIoRead; queueConfig.EvtIoWrite = ToasterEvtIoWrite; queueConfig.EvtIoDeviceControl = ToasterEvtIoDeviceControl; // // 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(queueConfig.EvtIoStop != 0); status = WdfIoQueueCreate( hDevice, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue ); __analysis_assume(queueConfig.EvtIoStop == 0); if (!NT_SUCCESS (status)) { KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); return status; } return status; }
NTSTATUS MarsEvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { NTSTATUS status = STATUS_SUCCESS; PFDO_DATA fdoData; WDF_IO_QUEUE_CONFIG queueConfig; WDF_OBJECT_ATTRIBUTES fdoAttributes; WDFDEVICE device; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; SDBUS_INTERFACE_PARAMETERS interfaceParameters = {0}; UNREFERENCED_PARAMETER(Driver); PAGED_CODE(); WdfDeviceInitSetPowerPageable(DeviceInit); WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); // // Register PNP callbacks. // pnpPowerCallbacks.EvtDevicePrepareHardware = MarsEvtDevicePrepareHardware; pnpPowerCallbacks.EvtDeviceReleaseHardware = MarsEvtDeviceReleaseHardware; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); WDF_OBJECT_ATTRIBUTES_INIT(&fdoAttributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&fdoAttributes, FDO_DATA); status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device); if (!NT_SUCCESS(status)) { return status; } fdoData = MarsFdoGetData(device); //Gets device context // // Open an interface to the SD bus driver // status = SdBusOpenInterface(WdfDeviceWdmGetPhysicalDevice (device), &fdoData->BusInterface, sizeof(SDBUS_INTERFACE_STANDARD), SDBUS_INTERFACE_VERSION); if (!NT_SUCCESS(status)) { return status; } interfaceParameters.Size = sizeof(SDBUS_INTERFACE_PARAMETERS); interfaceParameters.TargetObject = WdfDeviceWdmGetAttachedDevice(device); interfaceParameters.DeviceGeneratesInterrupts = TRUE; //change to true eventually interfaceParameters.CallbackRoutine = MarsEventCallback; interfaceParameters.CallbackRoutineContext = fdoData; status = STATUS_UNSUCCESSFUL; if (fdoData->BusInterface.InitializeInterface) { status = (fdoData->BusInterface.InitializeInterface)(fdoData->BusInterface.Context, &interfaceParameters); } if (!NT_SUCCESS(status)) { return status; } // // Register New device // status = WdfDeviceCreateDeviceInterface(device, (LPGUID) &GUID_DEVINTERFACE_MARS, NULL ); if (!NT_SUCCESS(status)) { return status; } fdoData->WdfDevice = device; WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchSequential); queueConfig.EvtIoRead = MarsEvtIoRead; queueConfig.EvtIoWrite = MarsEvtIoWrite; queueConfig.EvtIoDeviceControl = MarsEvtIoDeviceControl; status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &fdoData->IoctlQueue ); return status; }
NTSTATUS TpmEvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) { NTSTATUS status = STATUS_SUCCESS; WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks; WDF_OBJECT_ATTRIBUTES DeviceAttributes; WDFDEVICE device; PTPM_CONTEXT TpmContext; WDF_IO_QUEUE_CONFIG IoQueueConfig; WDFQUEUE hQueue; WDF_QUERY_INTERFACE_CONFIG InterfaceConfig; TPM_INTERFACE_STANDARD TpmInterface; WDF_DEVICE_POWER_CAPABILITIES PowerCaps; PAGED_CODE(); UNREFERENCED_PARAMETER( Driver ); RtlZeroMemory(&PnpPowerEventCallbacks,sizeof(PnpPowerEventCallbacks)); RtlZeroMemory(&PowerCaps,sizeof(PowerCaps)); KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "TpmEvtDeviceAdd routine PDO: %p (%p)\n", WdfDriverWdmGetDriverObject(Driver))); // // Zero out the PnpPowerCallbacks structure. // WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerEventCallbacks); // // These two callbacks set up and tear down hardware state that must be // done every time the device moves in and out of the D0-working state. // PnpPowerEventCallbacks.EvtDeviceD0Entry = TpmEvtDeviceD0Entry; PnpPowerEventCallbacks.EvtDeviceD0Exit = TpmEvtDeviceD0Exit; // // Set Callbacks for any of the functions we are interested in. // If no callback is set, Framework will take the default action // by itself. // PnpPowerEventCallbacks.EvtDevicePrepareHardware = TpmEvtDevicePrepareHardware; PnpPowerEventCallbacks.EvtDeviceReleaseHardware = TpmEvtDeviceReleaseHardware; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit,&PnpPowerEventCallbacks); // // Specify the context type and size for the device we are about to create. // RtlZeroMemory(&DeviceAttributes,sizeof(DeviceAttributes)); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&DeviceAttributes, TPM_CONTEXT); DeviceAttributes.Size = sizeof(WDF_OBJECT_ATTRIBUTES); DeviceAttributes.SynchronizationScope = WdfSynchronizationScopeInheritFromParent; DeviceAttributes.ExecutionLevel = WdfExecutionLevelPassive; status = WdfDeviceCreate(&DeviceInit,&DeviceAttributes,&device); if(NT_SUCCESS(status)) { TpmContext = GetTpmContext(device); RtlZeroMemory(TpmContext,sizeof(TPM_CONTEXT)); TpmContext->Device = device; TpmContext->AccessRegister = FALSE; KeInitializeSpinLock(&TpmContext->SpinLock); TpmContext->TpmState = StSuspend; TpmInitStateTable(); KeInitializeEvent(&TpmContext->Event,NotificationEvent,TRUE); status = WdfDeviceCreateDeviceInterface(device,&GUID_DEVINTERFACE_TPM,NULL); if(NT_SUCCESS(status)) { WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &IoQueueConfig, WdfIoQueueDispatchParallel ); IoQueueConfig.EvtIoDeviceControl = TpmEvtIoDeviceControl; status = WdfIoQueueCreate( device, &IoQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &hQueue ); if(NT_SUCCESS(status)) { WDF_DEVICE_POWER_CAPABILITIES_INIT(&PowerCaps); WdfDeviceSetPowerCapabilities(device,&PowerCaps); // TpmGetRegistryFlags(device,TpmContext); // RtlZeroMemory(&TpmInterface,sizeof(TpmInterface)); TpmInterface.InterfaceHeader.Size = sizeof(TpmInterface); TpmInterface.InterfaceHeader.Version = 1; TpmInterface.InterfaceHeader.Context = (PVOID)TpmContext; TpmInterface.InterfaceHeader.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; TpmInterface.InterfaceHeader.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; TpmInterface.pfn_TpmSetMorBitState = TpmSetMorBitState; // // Initialize the InterfaceConfig structure. // WDF_QUERY_INTERFACE_CONFIG_INIT( &InterfaceConfig, (PINTERFACE)&TpmInterface, &GUID_TPM_INTERFACE_STANDARD, NULL ); // // Create the interface. // status = WdfDeviceAddQueryInterface( device, &InterfaceConfig ); if(!NT_SUCCESS(status)) { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "WdfDeviceAddQueryInterface failed with NTSTATUS 0x%x\n",status)); } } else { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "WdfIoQueueCreate failed with Status code 0x%x\n",status)); } } else { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "WdfDeviceCreateDeviceInterface failed with Status code 0x%x\n",status)); } } else { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "WdfDeviceCreate failed with Status code 0x%x\n",status)); } KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "TpmEvtDeviceAdd exited with Status code 0x%x\n",status)); return status; }
// Sets up a new device. NTSTATUS DeviceContext::DeviceAdd( _Inout_ PWDFDEVICE_INIT DeviceInit ) { TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE); NTSTATUS status; NFC_CX_CLIENT_CONFIG nfcCxConfig; NFC_CX_CLIENT_CONFIG_INIT(&nfcCxConfig, NFC_CX_TRANSPORT_CUSTOM); nfcCxConfig.EvtNfcCxWriteNciPacket = WriteNciPacketCallback; nfcCxConfig.EvtNfcCxDeviceIoControl = DeviceIoCallback; nfcCxConfig.DriverFlags = NFC_CX_DRIVER_ENABLE_EEPROM_WRITE_PROTECTION | NFC_CX_DRIVER_POWER_AND_LINK_CONTROL_SUPPORTED; status = NfcCxDeviceInitConfig(DeviceInit, &nfcCxConfig); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "NfcCxDeviceInitConfig failed. %!STATUS!", status); return status; } WDF_OBJECT_ATTRIBUTES deviceObjectAttributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceObjectAttributes, DeviceContext); deviceObjectAttributes.EvtCleanupCallback = ShutdownCallback; deviceObjectAttributes.EvtDestroyCallback = DestroyCallback; WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); pnpCallbacks.EvtDeviceD0Entry = D0EntryCallback; pnpCallbacks.EvtDeviceD0Exit = D0ExitCallback; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); FileObjectContext::DeviceInit(DeviceInit); WDFDEVICE device; status = WdfDeviceCreate(&DeviceInit, &deviceObjectAttributes, &device); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "WdfDeviceCreate failed. %!STATUS!", status); return status; } // Initialize device context. DeviceContext* deviceContext = DeviceGetContext(device); new (deviceContext) DeviceContext(); deviceContext->_Device = device; status = NfcCxDeviceInitialize(device); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "NfcCxDeviceInitialize failed. %!STATUS!", status); return status; } // Create lock for clients (and sequence handling). WDF_OBJECT_ATTRIBUTES lockAttributes; WDF_OBJECT_ATTRIBUTES_INIT(&lockAttributes); lockAttributes.ParentObject = device; status = WdfWaitLockCreate(&lockAttributes, &deviceContext->_ClientLock); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "WdfWaitLockCreate failed. %!STATUS!", status); return status; } // Initialize RF discovery config (enable everything). NFC_CX_RF_DISCOVERY_CONFIG discoveryConfig; NFC_CX_RF_DISCOVERY_CONFIG_INIT(&discoveryConfig); discoveryConfig.PollConfig = NFC_CX_POLL_NFC_A | NFC_CX_POLL_NFC_B | NFC_CX_POLL_NFC_F_212 | NFC_CX_POLL_NFC_F_424 | NFC_CX_POLL_NFC_15693 | NFC_CX_POLL_NFC_ACTIVE | NFC_CX_POLL_NFC_A_KOVIO; discoveryConfig.NfcIPMode = NFC_CX_NFCIP_NFC_A | NFC_CX_NFCIP_NFC_F_212 | NFC_CX_NFCIP_NFC_F_424 | NFC_CX_NFCIP_NFC_ACTIVE | NFC_CX_NFCIP_NFC_ACTIVE_A | NFC_CX_NFCIP_NFC_ACTIVE_F_212 | NFC_CX_NFCIP_NFC_ACTIVE_F_424; discoveryConfig.NfcIPTgtMode = NFC_CX_NFCIP_TGT_NFC_A | NFC_CX_NFCIP_TGT_NFC_F | NFC_CX_NFCIP_TGT_NFC_ACTIVE_A | NFC_CX_NFCIP_TGT_NFC_ACTIVE_F; discoveryConfig.NfcCEMode = NFC_CX_CE_NFC_A | NFC_CX_CE_NFC_B | NFC_CX_CE_NFC_F; status = NfcCxSetRfDiscoveryConfig(device, &discoveryConfig); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "NfcCxSetRfDiscoveryConfig failed. %!STATUS!", status); return status; } // Set the sequence handlers. for (int sequenceType = 0; sequenceType != SequenceMaximum; ++sequenceType) { status = NfcCxRegisterSequenceHandler(device, NFC_CX_SEQUENCE(sequenceType), SequenceHandlerCallback); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "NfcCxRegisterSequenceHandler failed. %!STATUS!", status); return status; } } // Initialize callbacks manager. status = deviceContext->_ApiCallbacksManager.Initialize(device); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "CallbacksManager::Initialize failed. %!STATUS!", status); return status; } // Create device interface for NciSim DECLARE_CONST_UNICODE_STRING(interfaceName, FILE_NAMESPACE_NCI_SIMULATOR); status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_NCI_SIMULATOR, &interfaceName); if (!NT_SUCCESS(status)) { TRACE_LINE(LEVEL_ERROR, "WdfDeviceCreateDeviceInterface failed. %!STATUS!", status); return status; } TRACE_FUNCTION_SUCCESS(LEVEL_VERBOSE); return STATUS_SUCCESS; }
NTSTATUS KbFiltr_CreateRawPdo( WDFDEVICE Device, ULONG InstanceNo ) /*++ Routine Description: This routine creates and initialize a PDO. Arguments: Return Value: NT Status code. --*/ { NTSTATUS status; PWDFDEVICE_INIT pDeviceInit = NULL; PRPDO_DEVICE_DATA pdoData = NULL; WDFDEVICE hChild = NULL; WDF_OBJECT_ATTRIBUTES pdoAttributes; WDF_DEVICE_PNP_CAPABILITIES pnpCaps; WDF_IO_QUEUE_CONFIG ioQueueConfig; WDFQUEUE queue; WDF_DEVICE_STATE deviceState; PDEVICE_EXTENSION devExt; DECLARE_CONST_UNICODE_STRING(deviceId,KBFILTR_DEVICE_ID ); DECLARE_CONST_UNICODE_STRING(hardwareId,KBFILTR_DEVICE_ID ); DECLARE_CONST_UNICODE_STRING(deviceLocation,L"Keyboard Filter\0" ); DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN); DebugPrint(("Entered KbFiltr_CreateRawPdo\n")); // // Allocate a WDFDEVICE_INIT structure and set the properties // so that we can create a device object for the child. // pDeviceInit = WdfPdoInitAllocate(Device); if (pDeviceInit == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } // // Mark the device RAW so that the child device can be started // and accessed without requiring a function driver. Since we are // creating a RAW PDO, we must provide a class guid. // status = WdfPdoInitAssignRawDevice(pDeviceInit, &GUID_DEVCLASS_KEYBOARD); if (!NT_SUCCESS(status)) { goto Cleanup; } // // Since keyboard is secure device, we must protect ourselves from random // users sending ioctls and creating trouble. // status = WdfDeviceInitAssignSDDLString(pDeviceInit, &SDDL_DEVOBJ_SYS_ALL_ADM_ALL); if (!NT_SUCCESS(status)) { goto Cleanup; } // // Assign DeviceID - This will be reported to IRP_MN_QUERY_ID/BusQueryDeviceID // status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId); if (!NT_SUCCESS(status)) { goto Cleanup; } // // For RAW PDO, there is no need to provide BusQueryHardwareIDs // and BusQueryCompatibleIDs IDs unless we are running on // Windows 2000. // if (!RtlIsNtDdiVersionAvailable(NTDDI_WINXP)) { // // On Win2K, we must provide a HWID for the device to get enumerated. // Since we are providing a HWID, we will have to provide a NULL inf // to avoid the "found new device" popup and get the device installed // silently. // status = WdfPdoInitAddHardwareID(pDeviceInit, &hardwareId); if (!NT_SUCCESS(status)) { goto Cleanup; } } // // We could be enumerating more than one children if the filter attaches // to multiple instances of keyboard, so we must provide a // BusQueryInstanceID. If we don't, system will throw CA bugcheck. // status = RtlUnicodeStringPrintf(&buffer, L"%02d", InstanceNo); if (!NT_SUCCESS(status)) { goto Cleanup; } status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer); if (!NT_SUCCESS(status)) { goto Cleanup; } // // Provide a description about the device. This text is usually read from // the device. In the case of USB device, this text comes from the string // descriptor. This text is displayed momentarily by the PnP manager while // it's looking for a matching INF. If it finds one, it uses the Device // Description from the INF file to display in the device manager. // Since our device is raw device and we don't provide any hardware ID // to match with an INF, this text will be displayed in the device manager. // status = RtlUnicodeStringPrintf(&buffer,L"Keyboard_Filter_%02d", InstanceNo ); if (!NT_SUCCESS(status)) { goto Cleanup; } // // You can call WdfPdoInitAddDeviceText multiple times, adding device // text for multiple locales. When the system displays the text, it // chooses the text that matches the current locale, if available. // Otherwise it will use the string for the default locale. // The driver can specify the driver's default locale by calling // WdfPdoInitSetDefaultLocale. // status = WdfPdoInitAddDeviceText(pDeviceInit, &buffer, &deviceLocation, 0x409 ); if (!NT_SUCCESS(status)) { goto Cleanup; } WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409); // // Initialize the attributes to specify the size of PDO device extension. // All the state information private to the PDO will be tracked here. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, RPDO_DEVICE_DATA); // // Set up our queue to allow forwarding of requests to the parent // This is done so that the cached Keyboard Attributes can be retrieved // WdfPdoInitAllowForwardingRequestToParent(pDeviceInit); status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild); if (!NT_SUCCESS(status)) { goto Cleanup; } // // Get the device context. // pdoData = PdoGetData(hChild); pdoData->InstanceNo = InstanceNo; // // Get the parent queue we will be forwarding to // devExt = FilterGetData(Device); pdoData->ParentQueue = devExt->rawPdoQueue; // // Configure the default queue associated with the control device object // to be Serial so that request passed to EvtIoDeviceControl are serialized. // A default queue gets all the requests that are not // configure-fowarded using WdfDeviceConfigureRequestDispatching. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoDeviceControl = KbFilter_EvtIoDeviceControlForRawPdo; status = WdfIoQueueCreate(hChild, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue // pointer to default queue ); if (!NT_SUCCESS(status)) { DebugPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); goto Cleanup; } // // Set some properties for the child device. // WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); pnpCaps.Removable = WdfTrue; pnpCaps.SurpriseRemovalOK = WdfTrue; pnpCaps.NoDisplayInUI = WdfTrue; pnpCaps.Address = InstanceNo; pnpCaps.UINumber = InstanceNo; WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); // // TODO: In addition to setting NoDisplayInUI in DeviceCaps, we // have to do the following to hide the device. Following call // tells the framework to report the device state in // IRP_MN_QUERY_DEVICE_STATE request. // WDF_DEVICE_STATE_INIT(&deviceState); deviceState.DontDisplayInUI = WdfTrue; WdfDeviceSetDeviceState(hChild, &deviceState); // // Tell the Framework that this device will need an interface so that // application can find our device and talk to it. // status = WdfDeviceCreateDeviceInterface( hChild, &GUID_DEVINTERFACE_KBFILTER, NULL ); if (!NT_SUCCESS (status)) { DebugPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); goto Cleanup; } // // Add this device to the FDO's collection of children. // After the child device is added to the static collection successfully, // driver must call WdfPdoMarkMissing to get the device deleted. It // shouldn't delete the child device directly by calling WdfObjectDelete. // status = WdfFdoAddStaticChild(Device, hChild); if (!NT_SUCCESS(status)) { goto Cleanup; } // // pDeviceInit will be freed by WDF. // return STATUS_SUCCESS; Cleanup: DebugPrint(("KbFiltr_CreatePdo failed %x\n", status)); // // Call WdfDeviceInitFree if you encounter an error while initializing // a new framework device object. If you call WdfDeviceInitFree, // do not call WdfDeviceCreate. // if (pDeviceInit != NULL) { WdfDeviceInitFree(pDeviceInit); } if(hChild) { WdfObjectDelete(hChild); } return status; }
NTSTATUS DeviceConfigure( _In_ PDEVICE_CONTEXT DeviceContext ) /*++ Routine Description: This method is called after the device callback object has been initialized and returned to the driver. It would setup the device's queues and their corresponding callback objects. Arguments: FxDevice - the framework device object for which we're handling events. Return Value: status --*/ { NTSTATUS status; WDFDEVICE device = DeviceContext->Device; WDFKEY key; LPGUID guid; errno_t errorNo; DECLARE_CONST_UNICODE_STRING(portName, REG_VALUENAME_PORTNAME); DECLARE_UNICODE_STRING_SIZE (comPort, 10); DECLARE_UNICODE_STRING_SIZE (symbolicLinkName, SYMBOLIC_LINK_NAME_LENGTH); #ifdef _FAKE_MODEM // // Compiled as fake modem // guid = (LPGUID) &GUID_DEVINTERFACE_MODEM; #else // // Compiled as virtual serial port // guid = (LPGUID) &GUID_DEVINTERFACE_COMPORT; #endif // // Create device interface // status = WdfDeviceCreateDeviceInterface( device, guid, NULL); if (!NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "Error: Cannot create device interface"); goto Exit; } // // Read the COM port number from the registry, which has been automatically // created by "MsPorts!PortsClassInstaller" if INF file says "Class=Ports" // status = WdfDeviceOpenRegistryKey( device, PLUGPLAY_REGKEY_DEVICE, KEY_QUERY_VALUE, WDF_NO_OBJECT_ATTRIBUTES, &key); if (!NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "Error: Failed to retrieve device hardware key root"); goto Exit; } status = WdfRegistryQueryUnicodeString( key, &portName, NULL, &comPort); if (!NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "Error: Failed to read PortName"); goto Exit; } // // Manually create the symbolic link name. Length is the length in // bytes not including the NULL terminator. // // 6054 and 26035 are code analysis warnings that comPort.Buffer might // not be NULL terminated, while we know that they are. // #pragma warning(suppress: 6054 26035) symbolicLinkName.Length = (USHORT)((wcslen(comPort.Buffer) * sizeof(wchar_t)) + sizeof(SYMBOLIC_LINK_NAME_PREFIX) - sizeof(UNICODE_NULL)); if (symbolicLinkName.Length >= symbolicLinkName.MaximumLength) { Trace(TRACE_LEVEL_ERROR, "Error: Buffer overflow when creating COM port name. Size" " is %d, buffer length is %d", symbolicLinkName.Length, symbolicLinkName.MaximumLength); status = STATUS_BUFFER_OVERFLOW; goto Exit; } errorNo = wcscpy_s(symbolicLinkName.Buffer, SYMBOLIC_LINK_NAME_LENGTH, SYMBOLIC_LINK_NAME_PREFIX); if (errorNo != 0) { Trace(TRACE_LEVEL_ERROR, "Failed to copy %ws to buffer with error %d", SYMBOLIC_LINK_NAME_PREFIX, errorNo); status = STATUS_INVALID_PARAMETER; goto Exit; } errorNo = wcscat_s(symbolicLinkName.Buffer, SYMBOLIC_LINK_NAME_LENGTH, comPort.Buffer); if (errorNo != 0) { Trace(TRACE_LEVEL_ERROR, "Failed to copy %ws to buffer with error %d", comPort.Buffer, errorNo); status = STATUS_INVALID_PARAMETER; goto Exit; } // // Create symbolic link // status = WdfDeviceCreateSymbolicLink( device, &symbolicLinkName); if (!NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "Error: Cannot create symbolic link %ws", symbolicLinkName.Buffer); goto Exit; } status = DeviceGetPdoName(DeviceContext); if (!NT_SUCCESS(status)) { goto Exit; } status = DeviceWriteLegacyHardwareKey( DeviceContext->PdoName, comPort.Buffer, DeviceContext->Device); if (NT_SUCCESS(status)) { DeviceContext->CreatedLegacyHardwareKey = TRUE; } status = QueueCreate(DeviceContext); if (!NT_SUCCESS(status)) { goto Exit; } Exit: return status; }
NTSTATUS kmdf1394_EvtDeviceAdd ( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit) /*++ Routine Description: EvtDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { NTSTATUS ntStatus = STATUS_SUCCESS; PDEVICE_EXTENSION deviceExtension; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_OBJECT_ATTRIBUTES fdoAttributes,lockAttributes; WDFDEVICE device; WDF_DEVICE_PNP_CAPABILITIES pnpCaps; WDF_IO_QUEUE_CONFIG ioQueueConfig; UNREFERENCED_PARAMETER (Driver); PAGED_CODE(); Enter(); // // Zero out the PnpPowerCallbacks structure. // WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); // // Set Callbacks for any of the functions we are interested in. // If no callback is set, Framework will take the default action // by itself. // // These two callbacks set up and tear down hardware state, // specifically that which only has to be done once. // pnpPowerCallbacks.EvtDevicePrepareHardware = kmdf1394_EvtPrepareHardware; pnpPowerCallbacks.EvtDeviceReleaseHardware = kmdf1394_EvtReleaseHardware; pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = \ kmdf1394_EvtDeviceSelfManagedIoCleanup; pnpPowerCallbacks.EvtDeviceD0Entry = kmdf1394_EvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0Exit = kmdf1394_EvtDeviceD0Exit; // // Register the PnP and power callbacks. Power policy related callbacks // will be registered// later in SotwareInit. // WdfDeviceInitSetPnpPowerEventCallbacks (DeviceInit, &pnpPowerCallbacks); if (!NT_SUCCESS (ntStatus)) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "WdfDeviceInitSetPnpPowerEventCallbacks failed %!STATUS!\n", ntStatus); return ntStatus; } // // We'll allow multiple handles to be opened to this device driver // so we'll set exclusivity to FALSE. // WdfDeviceInitSetExclusive (DeviceInit, FALSE); // // Specify the size and type of device context. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE (&fdoAttributes, DEVICE_EXTENSION); ntStatus = WdfDeviceCreate (&DeviceInit, &fdoAttributes, &device); if (!NT_SUCCESS (ntStatus)) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "WdfDeviceInitialize failed %!STATUS!\n", ntStatus); return ntStatus; } deviceExtension = GetDeviceContext (device); deviceExtension->WdfDevice = device; DoTraceLevelMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, "PDO(0x%p) FDO(0x%p), Lower(0x%p) DevExt (0x%p)\n", WdfDeviceWdmGetPhysicalDevice (device), WdfDeviceWdmGetDeviceObject (device), WdfDeviceWdmGetAttachedDevice(device), deviceExtension); // // Tell the Framework that this device will need an interface so that // application can interact with it. // ntStatus = WdfDeviceCreateDeviceInterface ( device, (LPGUID) &GUID_KMDF_VDEV, NULL); if (!NT_SUCCESS (ntStatus)) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "WdfDeviceCreateDeviceInterface failed %!STATUS!\n", ntStatus); return ntStatus; } // // 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); pnpCaps.SurpriseRemovalOK = WdfTrue; WdfDeviceSetPnpCapabilities (device, &pnpCaps); // // save the device object we created as our physical device object // deviceExtension->PhysicalDeviceObject = \ WdfDeviceWdmGetPhysicalDevice (device); if (NULL == deviceExtension->PhysicalDeviceObject) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "WdfDeviceWdmGetPhysicalDevice: NULL DeviceObject\n"); return STATUS_UNSUCCESSFUL; } // // This is our default IoTarget representing the deviceobject // we are attached to. // deviceExtension->StackIoTarget = WdfDeviceGetIoTarget(device); deviceExtension->StackDeviceObject = WdfDeviceWdmGetAttachedDevice(device); if (NULL == deviceExtension->StackDeviceObject) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "WdfDeviceWdmGetAttachedDevice: NULL DeviceObject\n"); return STATUS_UNSUCCESSFUL; } // // Create a automanaged queue for dispatching ioctl requests. // All other requests are automatically failed by the framework. // By creating an automanaged queue we don't have to worry about // PNP/Power synchronization. // A default queue gets all the requests that are not // configure-fowarded using WdfDeviceConfigureRequestDispatching. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE ( &ioQueueConfig, WdfIoQueueDispatchParallel); ioQueueConfig.EvtIoDeviceControl = kmdf1394_EvtIoDeviceControl; __analysis_assume(ioQueueConfig.EvtIoStop != 0); ntStatus = WdfIoQueueCreate ( deviceExtension->WdfDevice, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &deviceExtension->IoctlQueue); __analysis_assume(ioQueueConfig.EvtIoStop == 0); if (!NT_SUCCESS (ntStatus)) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "WdfIoQueueCreate failed %!STATUS!\n", ntStatus); return ntStatus; } // // Create an additional queue to hold bus reset requests. // WDF_IO_QUEUE_CONFIG_INIT (&ioQueueConfig, WdfIoQueueDispatchManual); __analysis_assume(ioQueueConfig.EvtIoStop != 0); ntStatus = WdfIoQueueCreate ( deviceExtension->WdfDevice, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &deviceExtension->BusResetRequestsQueue); __analysis_assume(ioQueueConfig.EvtIoStop == 0); if(!NT_SUCCESS (ntStatus)) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "Error Creating Reset Request Queue %!STATUS!\n", ntStatus); return ntStatus; } WDF_OBJECT_ATTRIBUTES_INIT (&lockAttributes); lockAttributes.ParentObject = device; ntStatus = WdfSpinLockCreate (&lockAttributes,&deviceExtension->CromSpinLock); if(!NT_SUCCESS (ntStatus)) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "WdfSpinLockCreate CromSpinLock failed %!STATUS!\n", ntStatus); return ntStatus; } WDF_OBJECT_ATTRIBUTES_INIT (&lockAttributes); lockAttributes.ParentObject = device; ntStatus = WdfSpinLockCreate ( &lockAttributes, &deviceExtension->AsyncSpinLock); if(!NT_SUCCESS (ntStatus)) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "WdfSpinLockCreate AsyncSpinLock failed %!STATUS!\n", ntStatus); return ntStatus; } WDF_OBJECT_ATTRIBUTES_INIT (&lockAttributes); lockAttributes.ParentObject = device; ntStatus = WdfSpinLockCreate ( &lockAttributes, &deviceExtension->IsochSpinLock ); if(!NT_SUCCESS (ntStatus)) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "WdfSpinLockCreate IsochSpinLock failed %!STATUS!\n", ntStatus); return ntStatus; } WDF_OBJECT_ATTRIBUTES_INIT (&lockAttributes); lockAttributes.ParentObject = device; ntStatus = WdfSpinLockCreate ( &lockAttributes, &deviceExtension->IsochResourceSpinLock); if(!NT_SUCCESS (ntStatus)) { DoTraceLevelMessage(TRACE_LEVEL_ERROR, TRACE_FLAG_PNP, "WdfSpinLockCreate IsochResourceSpinLock failed %!STATUS!\n", ntStatus); return ntStatus; } InitializeListHead (&deviceExtension->CromData); InitializeListHead (&deviceExtension->AsyncAddressData); InitializeListHead (&deviceExtension->IsochDetachData); InitializeListHead (&deviceExtension->IsochResourceData); ExitS(ntStatus); return(ntStatus); } // kmdf1394_PnpAddDevice
/////////////////////////////////////////////////////////////////////////////// // // BasicUsbEvtDeviceAdd // // This routine is called by the framework when a device of // the type we support is found in the system. // // INPUTS: // // DriverObject - Our WDFDRIVER object // // DeviceInit - The device iniitalization structure we'll // be using to create our WDFDEVICE // // OUTPUTS: // // None. // // RETURNS: // // STATUS_SUCCESS, otherwise an error indicating why the driver could not // load. // // IRQL: // // This routine is called at IRQL == PASSIVE_LEVEL. // // NOTES: // // /////////////////////////////////////////////////////////////////////////////// NTSTATUS BasicUsbEvtDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit) { NTSTATUS status; WDF_OBJECT_ATTRIBUTES objAttributes; WDFDEVICE device; WDF_IO_QUEUE_CONFIG queueConfig; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; PBASICUSB_DEVICE_CONTEXT devContext; #if DBG DbgPrint("BasicUsbEvtDeviceAdd\n"); #endif // // Our "internal" (native) and user-accessible device names // DECLARE_CONST_UNICODE_STRING(nativeDeviceName, L"\\Device\\BasicUsb"); DECLARE_CONST_UNICODE_STRING(userDeviceName, L"\\Global??\\BasicUsb"); UNREFERENCED_PARAMETER(Driver); // // Life is a bit more complicated in this driver... // // We need an EvtPrepareHardware to configure our device. In addition, we // must handle EvtD0Entry and EvtD0Exit in order to manage our continuous // reader. // // // Prepare for WDFDEVICE creation // // Initialize standard WDF Object Attributes structure // WDF_OBJECT_ATTRIBUTES_INIT(&objAttributes); // // Specify our device context // WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&objAttributes, BASICUSB_DEVICE_CONTEXT); // // We want our device object NAMED, thank you very much // status = WdfDeviceInitAssignName(DeviceInit, &nativeDeviceName); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfDeviceInitAssignName failed 0x%0x\n", status); #endif return(status); } // // Set our I/O type to DIRECT, meaning that we want to receive // MDLs for both read and write requests. // // While we are not obligated to choose direct, USB drivers // typically do so because the USB bus driver needs MDLs to // actually perform the transfer. If we select DIRECT I/O, the // bus driver can just use the MDL that we're given as opposed // to creating his own. // WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); // // In this driver we need to be notified of some Pnp/Power // events, so initialize a pnp power callbacks structure. // WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); // // USB drivers configure their device within prepare hardware, // so register an EvtDevicePrepareHardware callback. // pnpPowerCallbacks.EvtDevicePrepareHardware = BasicUsbEvtDevicePrepareHardware; // // Our driver uses a continuous reader on the interrupt pipe to // be notified asynchronously of changes to the OSRFX2's // switchpack. We need to start the reader in D0Entry and stop // it in D0Exit, so register for EvtDeviceD0Entry and // EvtDeviceD0Exit callbacks // pnpPowerCallbacks.EvtDeviceD0Entry = BasicUsbEvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0Exit = BasicUsbEvtDeviceD0Exit; // // Update the DeviceInit structure to contain the new callbacks. // WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); // // We want to send control transfers synchronously from within // EvtIoDeviceControl, so we'll apply a PASSIVE_LEVEL constraint // to our device // objAttributes.ExecutionLevel = WdfExecutionLevelPassive; // // Now let's create our device object // status = WdfDeviceCreate(&DeviceInit, &objAttributes, &device); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfDeviceCreate failed 0x%0x\n", status); #endif return status; } // // Create a symbolic link for the control object so that usermode can open // the device by name. // status = WdfDeviceCreateSymbolicLink(device, &userDeviceName); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfDeviceCreateSymbolicLink failed 0x%0x\n", status); #endif return(status); } // // ALSO create a device interface for the device // This allows usage of the lovely SetupApiXxxx functions to locate // the device // status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_BASICUSB, NULL); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfDeviceCreateDeviceInterface failed 0x%0x\n", status); #endif return(status); } // // Configure our queue of incoming requests // // We only use the default queue, and we set it for parallel processing. // We chose this because we may have, say, a bulk read hanging on the bus // driver that won't get completed until we send down a bulk write. // // If we chose a sequential queue we wouldn't be presented the write from // the user until the read completed, but the read wouldn't complete // until we were presented the write from the user - resulting in an "I/O // deadlock". // // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); // // Declare our I/O Event Processing callbacks // // We handle, read, write, and device control requests. // // WDF will automagically handle Create and Close requests for us and will // will complete any OTHER request types with STATUS_INVALID_DEVICE_REQUEST. // queueConfig.EvtIoRead = BasicUsbEvtRead; queueConfig.EvtIoWrite = BasicUsbEvtWrite; queueConfig.EvtIoDeviceControl = BasicUsbEvtDeviceControl; // // Because this is a queue for a real hardware // device, indicate that the queue needs to be // power managed // queueConfig.PowerManaged = WdfTrue; status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, NULL); // optional pointer to receive queue handle if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfIoQueueCreate for default queue failed 0x%0x\n", status); #endif return(status); } devContext = BasicUsbGetContextFromDevice(device); WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &devContext->SwitchPackStateChangeQueue); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfIoQueueCreate for manual queue failed 0x%0x\n", status); #endif return(status); } return(STATUS_SUCCESS); }
/** * @brief Called by the framework when a new PDO has arrived that this driver manages. * The device in question is not operational at this point in time. * * @param[in] Driver handle to WDFDRIVER object created by DriverEntry() * @param[in,out] DeviceInit device init object provided by framework. * * @returns NTSTATUS value indicating success or failure. * */ NTSTATUS FdoEvtDeviceAdd( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit ) { UNREFERENCED_PARAMETER(Driver); WDF_OBJECT_ATTRIBUTES attributes; NTSTATUS status; TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DEVICE, __FUNCTION__"\n"); WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER); WdfDeviceInitSetExclusive(DeviceInit, FALSE); WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, USB_FDO_CONTEXT); attributes.EvtCleanupCallback = FdoEvtDeviceContextCleanup; // // Device state callbacks. // WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); pnpPowerCallbacks.EvtDevicePrepareHardware = FdoEvtDevicePrepareHardware; pnpPowerCallbacks.EvtDeviceReleaseHardware = FdoEvtDeviceReleaseHardware; pnpPowerCallbacks.EvtDeviceD0Entry = FdoEvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = FdoEvtDeviceD0EntryPostInterruptsEnabled; pnpPowerCallbacks.EvtDeviceD0Exit = FdoEvtDeviceD0Exit; pnpPowerCallbacks.EvtDeviceSurpriseRemoval = FdoEvtDeviceSurpriseRemoval; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); // // establish a request context // WDF_OBJECT_ATTRIBUTES requestAttributes; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&requestAttributes, FDO_REQUEST_CONTEXT); WdfDeviceInitSetRequestAttributes(DeviceInit, &requestAttributes); // // static verifier seems to have a rule that the FDO must call // WdfFdoInitSetDefaultChildListConfig if any component in the driver has // dynamic child devices, and the roothub has one if it is not operating in // connect usb hub mode. // WDF_CHILD_LIST_CONFIG config; WDF_CHILD_LIST_CONFIG_INIT(&config, sizeof(PDO_INDENTIFICATION_DESCRIPTION), FdoEvtChildListCreateDevice); WdfFdoInitSetDefaultChildListConfig(DeviceInit, &config, WDF_NO_OBJECT_ATTRIBUTES); // // add a preprocess callback for QueryInterface to support multi-version USBDI intefaces // UCHAR MinorFunctionTable[1] = {IRP_MN_QUERY_INTERFACE}; status = WdfDeviceInitAssignWdmIrpPreprocessCallback( DeviceInit, FdoPreProcessQueryInterface, IRP_MJ_PNP, MinorFunctionTable, 1); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": WdfDeviceInitAssignWdmIrpPreprocessCallback failed error %x\n", status); return status; } // // Add create/close handlers // WDF_OBJECT_ATTRIBUTES fileAttributes; WDF_OBJECT_ATTRIBUTES_INIT(&fileAttributes); fileAttributes.SynchronizationScope = WdfSynchronizationScopeNone; WDF_FILEOBJECT_CONFIG FileObjectConfig; WDF_FILEOBJECT_CONFIG_INIT( &FileObjectConfig, FdoEvtDeviceFileCreate, FdoEvtFileClose, WDF_NO_EVENT_CALLBACK); WdfDeviceInitSetFileObjectConfig( DeviceInit, &FileObjectConfig, &fileAttributes); WDFDEVICE device; status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": WdfDeviceCreate failed error %x\n", status); return status; } PUSB_FDO_CONTEXT fdoContext = DeviceGetFdoContext(device); RtlZeroMemory(fdoContext, sizeof(USB_FDO_CONTEXT)); fdoContext->WdfDevice = device; KeInitializeEvent(&fdoContext->resetCompleteEvent, SynchronizationEvent, FALSE); // // allocate the dpc request collection. // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = device; status = WdfCollectionCreate(&attributes, &fdoContext->RequestCollection); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": WdfCollectionCreate failed\n"); return status; }; // // The FDO is the USB Controller, create a device interface for that. // status = WdfDeviceCreateDeviceInterface( device, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": WdfDeviceCreateDeviceInterface for device %p error %x\n", device, status); return status; } WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = device; status = WdfStringCreate(NULL, &attributes, &fdoContext->hcdsymlink); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": WdfStringCreate for device %p error %x\n", device, status); return status; } status = WdfDeviceRetrieveDeviceInterfaceString(device, &GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL, fdoContext->hcdsymlink); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": WdfStringCreate for device %p error %x\n", device, status); return status; } // // Some of our resources are independent of the device state and // can be allocated/initialized here. // status = InitScratchpad(fdoContext); if (!NT_SUCCESS(status)) { return status; } // // Initialize the I/O Package and any Queues // status = FdoQueueInitialize(device); if (!NT_SUCCESS(status)) { return status; } // // --XT-- All of the WDF ISR and DPC setup code was removed // here. The DPC is now setup through the Xen interface in the // previous call. Note the event channel is setup but not active // until the backend is connected. // // // Allocate a watchdog timer for our Xen interface. // WDF_TIMER_CONFIG timerConfig; WDF_OBJECT_ATTRIBUTES timerAttributes; WDF_TIMER_CONFIG_INIT( &timerConfig, FdoEvtTimerFunc); WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); timerAttributes.ParentObject = device; timerAttributes.ExecutionLevel = WdfExecutionLevelPassive; status = WdfTimerCreate( &timerConfig, &timerAttributes, &fdoContext->WatchdogTimer); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": WdfTimerCreate error %x\n", status); return status; } // // Create a collection of work items. // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = device; status = WdfCollectionCreate(&attributes, &fdoContext->FreeWorkItems); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": WdfCollectionCreate error %x\n", status); return status; } for (ULONG index = 0; index < INIT_WORK_ITEM_COUNT; index++) { WDFWORKITEM workitem = NewWorkItem(fdoContext, NULL, 0,0,0,0); if (workitem) { status = WdfCollectionAdd(fdoContext->FreeWorkItems, workitem); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": WdfCollectionAdd for workitem index %d error %x\n", index, status); WdfObjectDelete(workitem); return status; } } } PNP_BUS_INFORMATION busInformation; busInformation.BusNumber = 0; busInformation.BusTypeGuid = GUID_BUS_TYPE_USB; busInformation.LegacyBusType = PNPBus; WdfDeviceSetBusInformationForChildren( device, &busInformation); if (NT_SUCCESS(status)) { status = LateSetup(device); } return status; }
NTSTATUS RoboDeviceCreateDevice( _Inout_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Worker routine called to create a device and its software resources. Arguments: DeviceInit - 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 --*/ { DEVICE_CONTEXT* pCtx; WDF_OBJECT_ATTRIBUTES attributes; WDFDEVICE device; NTSTATUS status; PAGED_CODE(); scope { // pnpPowerCallbacks structure WDF_PNPPOWER_EVENT_CALLBACKS pnpPwrCallbacks; WDF_PNPPOWER_EVENT_CALLBACKS_INIT( &pnpPwrCallbacks ); pnpPwrCallbacks.EvtDevicePrepareHardware = RoboDeviceEvtDevicePrepareHardware; pnpPwrCallbacks.EvtDeviceReleaseHardware = RoboDeviceEvtDeviceReleaseHardware; pnpPwrCallbacks.EvtDeviceD0Entry = RoboDeviceEvtDeviceD0Entry; pnpPwrCallbacks.EvtDeviceD0Exit = RoboDeviceEvtDeviceD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPwrCallbacks); } { // power policy callback used to arm/disarm hardware to handle wait-wake WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks; WDF_POWER_POLICY_EVENT_CALLBACKS_INIT( &powerPolicyCallbacks ); powerPolicyCallbacks.EvtDeviceArmWakeFromS0 = RoboDeviceEvtDeviceArmWakeFromS0; powerPolicyCallbacks.EvtDeviceDisarmWakeFromS0 = RoboDeviceEvtDeviceDisarmWakeFromS0; powerPolicyCallbacks.EvtDeviceWakeFromS0Triggered = RoboDeviceEvtDeviceWakeFromS0Triggered; powerPolicyCallbacks.EvtDeviceArmWakeFromSx = RoboDeviceEvtDeviceArmWakeFromSx; powerPolicyCallbacks.EvtDeviceDisarmWakeFromSx = RoboDeviceEvtDeviceDisarmWakeFromSx; powerPolicyCallbacks.EvtDeviceWakeFromSxTriggered = RoboDeviceEvtDeviceWakeFromSxTriggered; WdfDeviceInitSetPowerPolicyEventCallbacks( DeviceInit, &powerPolicyCallbacks ); } WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( &attributes, DEVICE_CONTEXT ); attributes.EvtCleanupCallback = RoboDeviceEvtDeviceContextCleanup; status = WdfDeviceCreate( &DeviceInit, &attributes, &device ); if( !NT_SUCCESS(status) ) { DbgPrintEx( DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "WdfDeviceCreate failed: 0x%x", status ); return status; } // Initialize the context pCtx = DeviceGetContext( device ); pCtx->PrivateDeviceData = 0; status = WdfDeviceCreateDeviceInterface( device, &GUID_DEVINTERFACE_RoboDevice, NULL ); if( !NT_SUCCESS(status) ) { DbgPrintEx( DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Error Create device interface: 0x%x", status ); return status; } status = RoboDeviceQueueInitialize( device ); /* scope { WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT( &idleSettings, IdleCannotWakeFromS0 ); idleSettings.IdleTimeout = 60000; status = WdfDeviceAssignS0IdleSettings( device, &idleSettings ); } scope { WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT( &wakeSettings ); WdfDeviceAssignSxWakeSettings( device, &wakeSettings ); } */ return status; }
NTSTATUS Bus_EvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Bus_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 toaster bus. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { WDF_CHILD_LIST_CONFIG config; WDF_OBJECT_ATTRIBUTES fdoAttributes; NTSTATUS status; WDFDEVICE device; WDF_IO_QUEUE_CONFIG queueConfig; PNP_BUS_INFORMATION busInfo; //PFDO_DEVICE_DATA deviceData; WDFQUEUE queue; UNREFERENCED_PARAMETER(Driver); PAGED_CODE (); KdPrint(("Bus_EvtDeviceAdd: 0x%p\n", Driver)); // // Initialize all the properties specific to the device. // Framework has default values for the one that are not // set explicitly here. So please read the doc and make sure // you are okay with the defaults. // WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER); WdfDeviceInitSetExclusive(DeviceInit, TRUE); // // Since this is pure software bus enumerator, we don't have to register for // any PNP/Power callbacks. Framework will take the default action for // all the PNP and Power IRPs. // // // WDF_ DEVICE_LIST_CONFIG describes how the framework should handle // dynamic child enumeration on behalf of the driver writer. // Since we are a bus driver, we need to specify identification description // for our child devices. This description will serve as the identity of our // child device. Since the description is opaque to the framework, we // have to provide bunch of callbacks to compare, copy, or free // any other resources associated with the description. // WDF_CHILD_LIST_CONFIG_INIT(&config, sizeof(PDO_IDENTIFICATION_DESCRIPTION), Bus_EvtDeviceListCreatePdo // callback to create a child device. ); // // This function pointer will be called when the framework needs to copy a // identification description from one location to another. An implementation // of this function is only necessary if the description contains description // relative pointer values (like LIST_ENTRY for instance) . // If set to NULL, the framework will use RtlCopyMemory to copy an identification . // description. In this sample, it's not required to provide these callbacks. // they are added just for illustration. // config.EvtChildListIdentificationDescriptionDuplicate = Bus_EvtChildListIdentificationDescriptionDuplicate; // // This function pointer will be called when the framework needs to compare // two identificaiton descriptions. If left NULL a call to RtlCompareMemory // will be used to compare two identificaiton descriptions. // config.EvtChildListIdentificationDescriptionCompare = Bus_EvtChildListIdentificationDescriptionCompare; // // This function pointer will be called when the framework needs to free a // identification description. An implementation of this function is only // necessary if the description contains dynamically allocated memory // (by the driver writer) that needs to be freed. The actual identification // description pointer itself will be freed by the framework. // config.EvtChildListIdentificationDescriptionCleanup = Bus_EvtChildListIdentificationDescriptionCleanup; // // Tell the framework to use the built-in childlist to track the state // of the device based on the configuration we just created. // WdfFdoInitSetDefaultChildListConfig(DeviceInit, &config, WDF_NO_OBJECT_ATTRIBUTES); // // Initialize attributes structure to specify size and accessor function // for storing device context. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DEVICE_DATA); // // Create a framework device object. In response to this call, framework // creates a WDM deviceobject and attach to the PDO. // status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device); if (!NT_SUCCESS(status)) { KdPrint(("Error creating device 0x%x\n", status)); return status; } // // 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( &queueConfig, WdfIoQueueDispatchParallel ); queueConfig.EvtIoDeviceControl = Bus_EvtIoDeviceControl; // // 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(queueConfig.EvtIoStop != 0); status = WdfIoQueueCreate( device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue ); __analysis_assume(queueConfig.EvtIoStop == 0); if (!NT_SUCCESS(status)) { KdPrint(("WdfIoQueueCreate failed status 0x%x\n", status)); return status; } // // Get the device context. // //deviceData = FdoGetData(device); // // Create device interface for this device. The interface will be // enabled by the framework when we return from StartDevice successfully. // Clients of this driver will open this interface and send ioctls. // status = WdfDeviceCreateDeviceInterface( device, &GUID_DEVINTERFACE_BUSENUM_TOASTER, NULL // No Reference String. If you provide one it will appended to the ); // symbolic link. Some drivers register multiple interfaces for the same device // and use the reference string to distinguish between them if (!NT_SUCCESS(status)) { return status; } // // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION // for the child devices. This is an optional information provided to // uniquely idenitfy the bus the device is connected. // busInfo.BusTypeGuid = GUID_DEVCLASS_TOASTER; busInfo.LegacyBusType = PNPBus; busInfo.BusNumber = 0; WdfDeviceSetBusInformationForChildren(device, &busInfo); status = Bus_WmiRegistration(device); if (!NT_SUCCESS(status)) { return status; } // // Check the registry to see if we need to enumerate child devices during // start. // status = Bus_DoStaticEnumeration(device); return status; }
NTSTATUS AmccPciAddDevice( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. It is responsible for initializing and creating a WDFDEVICE object. Any work that should be done after the object is created should be deferred until EvtDeviceSoftwareInit, as that callback will be made with the device lock held (if there is one.) Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { NTSTATUS status = STATUS_SUCCESS; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_OBJECT_ATTRIBUTES fdoAttributes; WDF_INTERRUPT_CONFIG interruptConfig; WDF_OBJECT_ATTRIBUTES interruptAttributes; WDF_IO_QUEUE_CONFIG ioQueueConfig; PAMCC_DEVICE_EXTENSION devExt; WDFQUEUE hQueue; WDFDEVICE device; PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_INIT, "AmccPciAddDevice: 0x%p", Driver); // // Zero out the PnpPowerCallbacks structure. // WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); // // Set Callbacks for any of the functions we are interested in. // If no callback is set, Framework will take the default action // by itself. // pnpPowerCallbacks.EvtDevicePrepareHardware = AmccPciEvtDevicePrepareHardware; pnpPowerCallbacks.EvtDeviceReleaseHardware = AmccPciEvtDeviceReleaseHardware; pnpPowerCallbacks.EvtDeviceD0Entry = AmccPciEvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0Exit = AmccPciEvtDeviceD0Exit; // // Register the PnP Callbacks.. // WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); // // Set various attributes for this device // WdfDeviceInitSetIoType( DeviceInit, WdfDeviceIoDirect ); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, AMCC_DEVICE_EXTENSION); fdoAttributes.EvtCleanupCallback = AmccPciContextCleanup; // // We want all the queue callbacks, cancel routine, and DpcForIsr to be serialized // at the device level, so we don't have worry about any synchronization issues. // fdoAttributes.SynchronizationScope = WdfSynchronizationScopeDevice; status = WdfDeviceCreate( &DeviceInit, &fdoAttributes, &device ); if ( !NT_SUCCESS(status) ) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfDeviceInitialize failed 0x%X", status); return status; } // // Device Initialization is complete. // Get the Device Extension and initialize it. // devExt = AmccPciGetDevExt(device); devExt->Device = device; TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_INIT, "PDO 0x%p, FDO 0x%p, DevExt 0x%p", WdfDeviceWdmGetPhysicalDevice(device), WdfDeviceWdmGetDeviceObject( device ), devExt); // // This device generates an interrupt. So create an interrupt object which // will later be associated with the devices resources and connected // by the Framework. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&interruptAttributes, INTERRUPT_DATA); // // Configure the Interrupt object // WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, AmccPciEvtInterruptIsr, AmccPciEvtInterruptDpc); status = WdfInterruptCreate(device, &interruptConfig, &interruptAttributes, &devExt->WdfInterrupt); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfInterruptCreate failed: %!STATUS!\n", status); return status; } // // The S5933 requires DMA buffers be aligned on a 32-bit boundary // // NOTE: Read the existing alignment value. If it is greater than // or equal then keep it. If it is less then update the // alignment requirement field with this device's required // value. // // NOTE: See the MSDN section titled "Initializing a Device Object" // for details on how to specify this alignment value. // // NOTE: AMCC5933_ALIGNMENT__32BITS is equated to (4-1) for 32-bit // alignment. // { ULONG alignReq; alignReq = WdfDeviceGetAlignmentRequirement( device ); if (alignReq < AMCC5933_ALIGNMENT__32BITS) { // // Set the S5933 alignment requirement as new value. // WdfDeviceSetAlignmentRequirement( device, AMCC5933_ALIGNMENT__32BITS); } } // // Register I/O callbacks. // // Create a sequential IO Queue for serial operation. That means all the requests (Read/Write // & IOCTL) are serialized to the device. Until the driver completes the request presented to it, // the framework will not schedule another one. The requests held in the framework will be // cancelled automatically if the source of request (application) terminate or cancels it. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoDefault = AmccPciEvtIoDefault; // // 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 for // long time or forward them to other drivers. // 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( device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &hQueue ); __analysis_assume(ioQueueConfig.EvtIoStop == 0); if (!NT_SUCCESS (status)) { // // We don't have worry about deleting the device here because framework will automatically // cleanup that when the driver unloads. // TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfIoQueueCreate failed %!STATUS!", status); return status; } // // Register an interface so that application can find and talk to us. // NOTE: See the note in Public.h concerning this GUID value. // status = WdfDeviceCreateDeviceInterface( device, (LPGUID) &GUID_DEVINTERFACE_AMCC_PCI, NULL ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "<-- AMCCAddDevice: WdfDeviceCreateDeviceInterface failed %!STATUS!", status); return status; } devExt->MaximumTransferLength = MAXIMUM_REQUEST_CONTEXT_LENGTH; // // Set the maximum physical pages for now, but this value may change if // there aren't enough map registers // devExt->MaximumPhysicalPages = MAXIMUM_PHYSICAL_PAGES; return status; }
NTSTATUS Bus_EvtDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Bus_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 toaster bus. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { WDF_IO_QUEUE_CONFIG queueConfig; WDF_OBJECT_ATTRIBUTES attributes; NTSTATUS status; WDFDEVICE device; PFDO_DEVICE_DATA deviceData; PNP_BUS_INFORMATION busInfo; WDFQUEUE queue; UNREFERENCED_PARAMETER(Driver); PAGED_CODE (); KdPrint(("Bus_EvtDeviceAdd: 0x%p\n", Driver)); // // Initialize all the properties specific to the device. // Framework has default values for the one that are not // set explicitly here. So please read the doc and make sure // you are okay with the defaults. // WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_BUS_EXTENDER); WdfDeviceInitSetExclusive(DeviceInit, TRUE); // // Initialize attributes structure to specify size and accessor function // for storing device context. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FDO_DEVICE_DATA); // // Create a framework device object. In response to this call, framework // creates a WDM deviceobject. // status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if (!NT_SUCCESS(status)) { return status; } // // Get the device context. // deviceData = FdoGetData(device); WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = device; // // Purpose of this lock is documented in Bus_PlugInDevice routine below. // status = WdfWaitLockCreate(&attributes, &deviceData->ChildLock); if (!NT_SUCCESS(status)) { return status; } // // 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( &queueConfig, WdfIoQueueDispatchParallel ); queueConfig.EvtIoDeviceControl = Bus_EvtIoDeviceControl; // // 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(queueConfig.EvtIoStop != 0); status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue ); __analysis_assume(queueConfig.EvtIoStop == 0); if (!NT_SUCCESS(status)) { KdPrint(("WdfIoQueueCreate failed with status 0x%x\n", status)); return status; } // // Create device interface for this device. The interface will be // enabled by the framework when we return from StartDevice successfully. // status = WdfDeviceCreateDeviceInterface( device, &GUID_DEVINTERFACE_BUSENUM_TOASTER, NULL // No Reference String ); if (!NT_SUCCESS(status)) { return status; } // // This value is used in responding to the IRP_MN_QUERY_BUS_INFORMATION // for the child devices. This is an optional information provided to // uniquely idenitfy the bus the device is connected. // busInfo.BusTypeGuid = GUID_DEVCLASS_TOASTER; busInfo.LegacyBusType = PNPBus; busInfo.BusNumber = 0; WdfDeviceSetBusInformationForChildren(device, &busInfo); status = Bus_WmiRegistration(device); if (!NT_SUCCESS(status)) { return status; } status = Bus_DoStaticEnumeration(device); return status; }
NTSTATUS EchoDeviceCreate( PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Worker routine called to create a device and its software resources. Arguments: DeviceInit - 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 --*/ { WDF_OBJECT_ATTRIBUTES attributes; PDEVICE_CONTEXT deviceContext; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDFDEVICE device; NTSTATUS status; PAGED_CODE(); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); // // Register pnp/power callbacks so that we can start and stop the timer as the device // gets started and stopped. // pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = EchoEvtDeviceSelfManagedIoStart; pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend; // // Function used for both Init and Restart Callbacks // #pragma warning(suppress: 28024) pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart; // // Register the PnP and power callbacks. Power policy related callbacks will be registered // later in SotwareInit. // WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); WdfDeviceInitSetRequestAttributes(DeviceInit, &attributes); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if (NT_SUCCESS(status)) { // // Get the device context and initialize it. WdfObjectGet_DEVICE_CONTEXT is an // inline function generated by WDF_DECLARE_CONTEXT_TYPE macro in the // device.h header file. This function will do the type checking and return // the device context. If you pass a wrong object handle // it will return NULL and assert if run under framework verifier mode. // deviceContext = WdfObjectGet_DEVICE_CONTEXT(device); deviceContext->PrivateDeviceData = 0; // // Create a device interface so that application can find and talk // to us. // status = WdfDeviceCreateDeviceInterface( device, &GUID_DEVINTERFACE_ECHO, NULL // ReferenceString ); if (NT_SUCCESS(status)) { // // Initialize the I/O Package and any Queues // status = EchoQueueInitialize(device); } } return status; }
NTSTATUS SmplDeviceCreateDevice( _Inout_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Worker routine called to create a device and its software resources. Arguments: DeviceInit - 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 --*/ { WDF_OBJECT_ATTRIBUTES deviceAttributes; PDEVICE_CONTEXT deviceContext; WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks; WDFDEVICE device; NTSTATUS status; PAGED_CODE(); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT); deviceAttributes.SynchronizationScope = WdfSynchronizationScopeQueue; WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerEventCallbacks); PnpPowerEventCallbacks.EvtDevicePrepareHardware = SmplDeviceEvtPrepareHardware; PnpPowerEventCallbacks.EvtDeviceReleaseHardware = SmplDeviceEvtReleaseHardware; PnpPowerEventCallbacks.EvtDeviceD0Entry = SmplDeviceEvtD0Entry; PnpPowerEventCallbacks.EvtDeviceD0Exit = SmplDeviceEvtD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks( DeviceInit, &PnpPowerEventCallbacks); status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); if (NT_SUCCESS(status)) { // // Get the device context and initialize it. DeviceGetContext is an // inline function generated by WDF_DECLARE_CONTEXT_TYPE macro in the // device.h header file. This function will do the type checking and return // the device context. If you pass a wrong object handle // it will return NULL and assert if run under framework verifier mode. // deviceContext = DeviceGetContext(device); // // Create a device interface so that applications can find and talk // to us. // status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_SMPLDEVICE, NULL); if (NT_SUCCESS(status)) { // // Initialize the I/O Package and any Queues // status = SmplDeviceQueueInitialize(device); } if (NT_SUCCESS(status)) { WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS PowerPolicyIdleSettings; WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&PowerPolicyIdleSettings, IdleCannotWakeFromS0); PowerPolicyIdleSettings.IdleTimeoutType = SystemManagedIdleTimeout; status = WdfDeviceAssignS0IdleSettings(device, &PowerPolicyIdleSettings); if (!NT_SUCCESS(status)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"WdfDeviceAssignS0IdleSettings failed! 0x%x\n", status); } } if (NT_SUCCESS(status)) { SmplPoFxSingleComponentInitialize(device); } if (NT_SUCCESS(status)) { WDFINTERRUPT Interrupt; WDF_INTERRUPT_CONFIG Configuration; WDF_INTERRUPT_CONFIG_INIT(&Configuration, SmplInterruptEvtIsr, SmplInterruptEvtDpc); Configuration.EvtInterruptEnable = SmplInterruptEvtEnable; Configuration.EvtInterruptDisable = SmplInterruptEvtDisable; status = WdfInterruptCreate(device, &Configuration, WDF_NO_OBJECT_ATTRIBUTES, &Interrupt); if (!NT_SUCCESS(status)) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234, "WdfInterruptCreate failed! 0x%x\n", status); } } } return status; }
NTSTATUS SingleCompEvtDeviceAdd( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDeviceAdd is called by UMDF in response to AddDevice call from the PnP manager. Arguments: Driver - Handle to the UMDF driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: An NTSTATUS value representing success or failure of the function. --*/ { NTSTATUS status; WDFDEVICE device; WDFQUEUE queue; WDF_IO_QUEUE_CONFIG queueConfig; FDO_DATA *fdoContext = NULL; WDF_OBJECT_ATTRIBUTES objectAttributes; WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; UNREFERENCED_PARAMETER(Driver); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes, FDO_DATA); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); pnpCallbacks.EvtDeviceD0Entry = SingleCompEvtDeviceD0Entry; pnpCallbacks.EvtDeviceD0Exit = SingleCompEvtDeviceD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); status = WdfDeviceCreate(&DeviceInit, &objectAttributes, &device); if (!NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceCreate failed with %!status!.", status); goto exit; } fdoContext = FdoGetContext(device); // // Our initial state is active // fdoContext->IsActive = TRUE; // // Create a power-managed queue for IOCTL requests. // WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchParallel); queueConfig.EvtIoDeviceControl = SingleCompEvtIoDeviceControl; // // 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(queueConfig.EvtIoStop != 0); status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue); __analysis_assume(queueConfig.EvtIoStop == 0); if (FALSE == NT_SUCCESS (status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfIoQueueCreate for IoDeviceControl failed with %!status!.", status); goto exit; } status = WdfDeviceConfigureRequestDispatching(device, queue, WdfRequestTypeDeviceControl); if (FALSE == NT_SUCCESS (status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceConfigureRequestDispatching for " "WdfRequestTypeDeviceControl failed with %!status!.", status); goto exit; } status = AssignS0IdleSettings(device); if (!NT_SUCCESS(status)) { goto exit; } // // Create a device interface so that applications can open a handle to this // device. // status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_POWERFX, NULL /* ReferenceString */); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceCreateDeviceInterface failed with %!status!.", status); goto exit; } // // Initialize the hardware simulator // status = HwSimInitialize(device); if (FALSE == NT_SUCCESS(status)) { goto exit; } exit: return status; }
NTSTATUS BalloonDeviceAdd( IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit) { NTSTATUS status = STATUS_SUCCESS; WDFDEVICE device; PDEVICE_CONTEXT devCtx = NULL; WDF_INTERRUPT_CONFIG interruptConfig; WDF_FILEOBJECT_CONFIG fileConfig; WDF_OBJECT_ATTRIBUTES attributes; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; UNREFERENCED_PARAMETER(Driver); PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); pnpPowerCallbacks.EvtDevicePrepareHardware = BalloonEvtDevicePrepareHardware; pnpPowerCallbacks.EvtDeviceReleaseHardware = BalloonEvtDeviceReleaseHardware; pnpPowerCallbacks.EvtDeviceD0Entry = BalloonEvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0Exit = BalloonEvtDeviceD0Exit; pnpPowerCallbacks.EvtDeviceD0ExitPreInterruptsDisabled = BalloonEvtDeviceD0ExitPreInterruptsDisabled; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); WDF_FILEOBJECT_CONFIG_INIT( &fileConfig, WDF_NO_EVENT_CALLBACK, BalloonEvtFileClose, WDF_NO_EVENT_CALLBACK ); WdfDeviceInitSetFileObjectConfig(DeviceInit, &fileConfig, WDF_NO_OBJECT_ATTRIBUTES); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); attributes.EvtCleanupCallback = BalloonEvtDeviceContextCleanup; status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreate failed with status 0x%08x\n", status); return status; } devCtx = GetDeviceContext(device); WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, BalloonInterruptIsr, BalloonInterruptDpc); interruptConfig.EvtInterruptEnable = BalloonInterruptEnable; interruptConfig.EvtInterruptDisable = BalloonInterruptDisable; status = WdfInterruptCreate(device, &interruptConfig, WDF_NO_OBJECT_ATTRIBUTES, &devCtx->WdfInterrupt); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfInterruptCreate failed: 0x%08x\n", status); return status; } status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_BALLOON, NULL); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfDeviceCreateDeviceInterface failed with status 0x%08x\n", status); return status; } devCtx->bShutDown = FALSE; devCtx->num_pages = 0; devCtx->PageListHead.Next = NULL; ExInitializeNPagedLookasideList( &devCtx->LookAsideList, NULL, NULL, 0, sizeof(PAGE_LIST_ENTRY), BALLOON_MGMT_POOL_TAG, 0 ); devCtx->bListInitialized = TRUE; devCtx->pfns_table = (PPFN_NUMBER) ExAllocatePoolWithTag( NonPagedPool, PAGE_SIZE, BALLOON_MGMT_POOL_TAG ); if(devCtx->pfns_table == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,"ExAllocatePoolWithTag failed\n"); status = STATUS_INSUFFICIENT_RESOURCES; return status; } devCtx->MemStats = (PBALLOON_STAT) ExAllocatePoolWithTag( NonPagedPool, sizeof (BALLOON_STAT) * VIRTIO_BALLOON_S_NR, BALLOON_MGMT_POOL_TAG ); if(devCtx->MemStats == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,"ExAllocatePoolWithTag failed\n"); status = STATUS_INSUFFICIENT_RESOURCES; return status; } RtlFillMemory (devCtx->MemStats, sizeof (BALLOON_STAT) * VIRTIO_BALLOON_S_NR, -1); KeInitializeEvent(&devCtx->HostAckEvent, SynchronizationEvent, FALSE ); status = BalloonQueueInitialize(device); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "BalloonQueueInitialize failed with status 0x%08x\n", status); return status; } KeInitializeEvent(&devCtx->WakeUpThread, SynchronizationEvent, FALSE ); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__); return status; }