/** * @brief deallocate callback item. * Must be called with lock held. * *Note* this is called only to deal with error cases. The normal * callback function re-adds the work item to the collection. * * @param[in] WorkItem allocated WorkItem to be freed. * */ VOID FreeWorkItem( IN WDFWORKITEM WorkItem) { PUSB_FDO_WORK_ITEM_CONTEXT context = WorkItemGetContext(WorkItem); NTSTATUS Status = WdfCollectionAdd(context->FdoContext->FreeWorkItems, WorkItem); if (!NT_SUCCESS(Status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": Device %p WdfCollectionAdd error %x, deleting instead.\n", context->FdoContext->WdfDevice, Status); WdfObjectDelete(WorkItem); } }
/** * @brief generic workitem callback function * calls the specific callback function in the work item context. * * @param[in] WorkItem handle to the workitem object. * */ VOID EvtFdoDeviceGenericWorkItem ( IN WDFWORKITEM WorkItem) { PUSB_FDO_WORK_ITEM_CONTEXT context = WorkItemGetContext(WorkItem); // // NULL indicates somebody screwed up, log it and forget it. // if (context->CallBack) { context->CallBack(WorkItem); } else { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": %s Device %p WorkItem %p NULL callback\n", context->FdoContext->FrontEndPath, context->FdoContext->WdfDevice, WorkItem); } context->CallBack = NULL; // // put this workitem into our collection. // AcquireFdoLock(context->FdoContext); NTSTATUS Status = WdfCollectionAdd(context->FdoContext->FreeWorkItems, WorkItem); ReleaseFdoLock(context->FdoContext); if (!NT_SUCCESS(Status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, __FUNCTION__": %s Device %p WdfCollectionAdd error %x deleting workitem %p\n", context->FdoContext->FrontEndPath, context->FdoContext->WdfDevice, Status, WorkItem); // oh well delete it WdfObjectDelete(WorkItem); } }
NTSTATUS AddDefaultDeviceInterfaceGUID(__in PDEVICE_CONTEXT deviceContext) { WDF_OBJECT_ATTRIBUTES stringAttributes; UNICODE_STRING defaultDeviceInterfaceGUID_UnicodeString; WDFSTRING defaultDeviceInterfaceGUID = NULL; GUID guidTest = {0}; NTSTATUS status; WDF_OBJECT_ATTRIBUTES_INIT(&stringAttributes); stringAttributes.ParentObject = deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs; RtlInitUnicodeString(&defaultDeviceInterfaceGUID_UnicodeString, LibusbKDeviceGuidW); status = WdfStringCreate(&defaultDeviceInterfaceGUID_UnicodeString, &stringAttributes, &defaultDeviceInterfaceGUID); if (!NT_SUCCESS(status)) { USBERR("WdfStringCreate failed. status=%Xh\n", status); return status; } status = GUIDFromWdfString(defaultDeviceInterfaceGUID, &guidTest); if (!NT_SUCCESS(status)) { USBERR("GUIDFromWdfString failed. status=%Xh\n", status); return status; } USBWRN("using default GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n", guidTest.Data1, guidTest.Data2, guidTest.Data3, guidTest.Data4[0], guidTest.Data4[1], guidTest.Data4[2], guidTest.Data4[3], guidTest.Data4[4], guidTest.Data4[5], guidTest.Data4[6], guidTest.Data4[7]); return WdfCollectionAdd(deviceContext->DeviceRegSettings.DeviceInterfaceGUIDs, defaultDeviceInterfaceGUID); }
NTSTATUS PciDtfDeviceAllocDma(IN WDFDEVICE Device, IN WDFREQUEST Request) { PDEVICE_DATA DeviceData = GetDeviceData(Device); PCIDTF_DMA_INFO *ReqData; WDF_OBJECT_ATTRIBUTES ObjectAttributes; WDFCOMMONBUFFER CommonBuffer = NULL; PCOMMON_BUFFER_DATA CommonBufferData; NTSTATUS Status = STATUS_SUCCESS; __try { Status = WdfRequestRetrieveInputBuffer(Request, sizeof(PCIDTF_DMA_INFO), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveInputBuffer", Status); __leave; } Status = WdfRequestRetrieveOutputBuffer(Request, sizeof(PCIDTF_DMA_INFO), (PVOID *) & ReqData, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfRequestRetrieveOutputBuffer", Status); __leave; } WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&ObjectAttributes, COMMON_BUFFER_DATA); Status = WdfCommonBufferCreate(DeviceData->DmaEnabler, ReqData->len, &ObjectAttributes, &CommonBuffer); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfCommonBufferCreate", Status); __leave; } CommonBufferData = GetCommonBufferData(CommonBuffer); CommonBufferData->ID = PciDtfCommonBufferAssignId(DeviceData); Status = WdfCollectionAdd(DeviceData->CommonBuffers, CommonBuffer); if (!NT_SUCCESS(Status)) { TRACE_ERR("WdfCollectionAdd", Status); __leave; } ReqData->id = CommonBufferData->ID; ReqData->addr = WdfCommonBufferGetAlignedLogicalAddress (CommonBuffer).QuadPart; WdfRequestSetInformation(Request, sizeof(PCIDTF_DMA_INFO)); TRACE_MSG(TRACE_LEVEL_VERBOSE, TRACE_FLAG_QUEUE, "va 0x%p, pa 0x%llX, len 0x%X\n", WdfCommonBufferGetAlignedVirtualAddress(CommonBuffer), WdfCommonBufferGetAlignedLogicalAddress (CommonBuffer).QuadPart, WdfCommonBufferGetLength(CommonBuffer)); } __finally { if (!NT_SUCCESS(Status) && CommonBuffer != NULL) { WdfObjectDelete(CommonBuffer); } WdfRequestComplete(Request, Status); } return Status; }
NTSTATUS ToastMon_PnpNotifyInterfaceChange( IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION NotificationStruct, IN PVOID Context ) /*++ Routine Description: This routine is the PnP "interface change notification" callback routine. This gets called on a Toaster triggered device interface arrival or removal. - Interface arrival corresponds to a Toaster device being STARTED - Interface removal corresponds to a Toaster device being REMOVED On arrival: - Create a IoTarget and open it by using the symboliclink. WDF will Register for EventCategoryTargetDeviceChange notification on the fileobject so it can cleanup whenever associated device is removed. On removal: - This callback is a NO-OP for interface removal because framework registers for PnP EventCategoryTargetDeviceChange callbacks and uses that callback to clean up when the associated toaster device goes away. Arguments: NotificationStruct - Structure defining the change. Context - pointer to the device extension. (supplied as the "context" when we registered for this callback) Return Value: STATUS_SUCCESS - always, even if something goes wrong status is only used during query removal notifications and the OS ignores other cases --*/ { NTSTATUS status = STATUS_SUCCESS; PDEVICE_EXTENSION deviceExtension = Context; WDFIOTARGET ioTarget; PAGED_CODE(); KdPrint(("Entered ToastMon_PnpNotifyInterfaceChange\n")); // // Verify that interface class is a toaster device interface. // ASSERT(IsEqualGUID( (LPGUID)&(NotificationStruct->InterfaceClassGuid), (LPGUID)&GUID_DEVINTERFACE_TOASTER)); // // Check the callback event. // if(IsEqualGUID( (LPGUID)&(NotificationStruct->Event), (LPGUID)&GUID_DEVICE_INTERFACE_ARRIVAL )) { KdPrint(("Arrival Notification\n")); status = Toastmon_OpenDevice((WDFDEVICE)deviceExtension->WdfDevice, (PUNICODE_STRING)NotificationStruct->SymbolicLinkName, &ioTarget); if (!NT_SUCCESS(status)) { KdPrint( ("Unable to open control device 0x%x\n", status)); return status; } // // Add this one to the collection. // WdfWaitLockAcquire(deviceExtension->TargetDeviceCollectionLock, NULL); // // WdfCollectionAdd takes a reference on the request object and removes // it when you call WdfCollectionRemove. // status = WdfCollectionAdd(deviceExtension->TargetDeviceCollection, ioTarget); if (!NT_SUCCESS(status)) { KdPrint( ("WdfCollectionAdd failed 0x%x\n", status)); WdfObjectDelete(ioTarget); // Delete will also close the target } WdfWaitLockRelease(deviceExtension->TargetDeviceCollectionLock); } else { KdPrint(("Removal Interface Notification\n")); } 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 FilterEvtDeviceAdd( 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 you can query the device properties using WdfFdoInitWdmGetPhysicalDevice/IoGetDeviceProperty and based on that, decide to create a filter device object and attach to the function stack. If you are not interested in filtering this particular instance of the device, you can just return STATUS_SUCCESS without creating a framework device. Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { WDF_OBJECT_ATTRIBUTES deviceAttributes; PFILTER_EXTENSION filterExt; NTSTATUS status; WDFDEVICE device; ULONG serialNo; ULONG returnSize; PAGED_CODE (); UNREFERENCED_PARAMETER(Driver); // // Get some property of the device you are about to attach and check // to see if that's the one you are interested. For demonstration // we will get the UINumber of the device. The bus driver reports the // serial number as the UINumber. // status = WdfFdoInitQueryProperty(DeviceInit, DevicePropertyUINumber, sizeof(serialNo), &serialNo, &returnSize); if(!NT_SUCCESS(status)){ KdPrint(("Failed to get the property of PDO: 0x%p\n", DeviceInit)); } // // Tell the framework that you are filter driver. Framework // takes care of inherting all the device flags & characterstics // from the lower device you are attaching to. // WdfFdoInitSetFilter(DeviceInit); // // Specify the size of device extension where we track per device // context. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, FILTER_EXTENSION); // // We will just register for cleanup notification because we have to // delete the control-device when the last instance of the device goes // away. If we don't delete, the driver wouldn't get unloaded automatcially // by the PNP subsystem. // deviceAttributes.EvtCleanupCallback = FilterEvtDeviceContextCleanup; // // 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, &deviceAttributes, &device); if (!NT_SUCCESS(status)) { KdPrint( ("WdfDeviceCreate failed with status code 0x%x\n", status)); return status; } filterExt = FilterGetData(device); filterExt->SerialNo = serialNo; // // Add this device to the FilterDevice collection. // WdfWaitLockAcquire(FilterDeviceCollectionLock, NULL); // // WdfCollectionAdd takes a reference on the item object and removes // it when you call WdfCollectionRemove. // status = WdfCollectionAdd(FilterDeviceCollection, device); if (!NT_SUCCESS(status)) { KdPrint( ("WdfCollectionAdd failed with status code 0x%x\n", status)); } WdfWaitLockRelease(FilterDeviceCollectionLock); // // Create a control device // status = FilterCreateControlDevice(device); if (!NT_SUCCESS(status)) { KdPrint( ("FilterCreateControlDevice failed with status 0x%x\n", status)); // // Let us not fail AddDevice just because we weren't able to create the // control device. // status = STATUS_SUCCESS; } return status; }