// Typically on IRP_MN_START_DEVICE NTSTATUS RoboDeviceEvtDevicePrepareHardware( WDFDEVICE Device, WDFCMRESLIST ResourcesRaw, WDFCMRESLIST ResourcesTranslated ) { NTSTATUS status = STATUS_SUCCESS; ULONG i; // pCtx UNREFERENCED_PARAMETER(Device); UNREFERENCED_PARAMETER(ResourcesRaw); DbgPrint( "RoboDeviceEvtDevicePrepareHardware called" ); PAGED_CODE(); // // Get the number item that are currently in Resources collection and // iterate thru as many times to get more information about the each items // for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); switch(descriptor->Type) { case CmResourceTypePort: DbgPrintEx( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "I/O Port: (%x) Lenth: (%d)\n", descriptor->u.Port.Start.LowPart, descriptor->u.Port.Length ); break; case CmResourceTypeMemory: DbgPrintEx( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Memory: (%x) Lenth: (%d)\n", descriptor->u.Memory.Start.LowPart, descriptor->u.Memory.Length ); break; case CmResourceTypeInterrupt: DbgPrintEx( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Interrupt level: 0x%0x, Vector: 0x%0x, Affinity: 0x%0Ix\n", descriptor->u.Interrupt.Level, descriptor->u.Interrupt.Vector, descriptor->u.Interrupt.Affinity ); break; default: break; } } return status; }
NTSTATUS fscc_card_delete(struct fscc_card *card, WDFCMRESLIST ResourcesTranslated) { unsigned bar_counter = 0; unsigned i = 0; for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); if (!descriptor) return STATUS_DEVICE_CONFIGURATION_ERROR; switch (descriptor->Type) { case CmResourceTypePort: bar_counter++; break; case CmResourceTypeMemory: MmUnmapIoSpace(card->bar[bar_counter].address, descriptor->u.Memory.Length); bar_counter++; break; } } return STATUS_SUCCESS; }
NTSTATUS AmccPciEvtDevicePrepareHardware( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST Resources, _In_ WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: EvtDevicePrepareHardware event callback performs operations that are necessary to use the device's control registers. Arguments: Device - Handle to a framework device object. Resources - Handle to a collection of framework resource objects. This collection identifies the raw (bus-relative) hardware resources that have been assigned to the device. ResourcesTranslated - Handle to a collection of framework resource objects. This collection identifies the translated (system-physical) hardware resources that have been assigned to the device. The resources appear from the CPU's point of view. Use this list of resources to map I/O space and device-accessible memory into virtual address space Return Value: WDF status code. Let us not worry about cleaning up the resources here if we fail start, because the PNP manager will send a remove-request and we will free all the allocated resources in AmccPciEvtDeviceReleaseHardware. --*/ { ULONG i; NTSTATUS status = STATUS_SUCCESS; PAMCC_DEVICE_EXTENSION devExt = NULL; BOOLEAN foundPort = FALSE; PHYSICAL_ADDRESS portBasePA = {0}; ULONG portCount = 0; WDF_DMA_ENABLER_CONFIG dmaConfig; PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; PAGED_CODE(); // // The Resources collection is not used for PCI devices, since the PCI // bus driver manages the device's PCI Base Address Registers. // UNREFERENCED_PARAMETER( Resources ); devExt = AmccPciGetDevExt(Device); // // Parse the resource list and save the resource information. // for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { desc = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); if(!desc) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfResourceCmGetDescriptor failed"); return STATUS_DEVICE_CONFIGURATION_ERROR; } switch (desc->Type) { case CmResourceTypePort: portBasePA = desc->u.Port.Start; portCount = desc->u.Port.Length; devExt->PortMapped = (desc->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE; foundPort = TRUE; // // Map in the single IO Space resource. // if (devExt->PortMapped) { devExt->PortBase = (PUCHAR) MmMapIoSpace( portBasePA, portCount, MmNonCached ); if (!devExt->PortBase) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "Unable to map port range 0x%p, length %d", devExt->PortBase, devExt->PortCount); return STATUS_INSUFFICIENT_RESOURCES; } devExt->PortCount = portCount; } else { devExt->PortBase = (PUCHAR)(ULONG_PTR) portBasePA.QuadPart; devExt->PortCount = portCount; } devExt->Regs = (PREG5933) devExt->PortBase; break; default: TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_INIT, "Unknown resource type %d", desc->Type); break; } } if (!foundPort) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "Missing hardware resources"); return STATUS_DEVICE_CONFIGURATION_ERROR; } // // Configure the DMA object // WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig, WdfDmaProfilePacket, devExt->MaximumTransferLength ); status = WdfDmaEnablerCreate( devExt->Device, &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &devExt->DmaEnabler ); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfDmaEnablerCreate failed %08X", status); return status; } return STATUS_SUCCESS; }
/////////////////////////////////////////////////////////////////////////////// // Private local helper function that parses the translated resource list // and extracts the data needed for the port address. /////////////////////////////////////////////////////////////////////////////// NTSTATUS SmplDeviceHwResourcesGet( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceListTranslated ) { NTSTATUS Status = STATUS_SUCCESS; ULONG index = 0; PCM_PARTIAL_RESOURCE_DESCRIPTOR pCMResourceDescPartial; PDEVICE_CONTEXT pSmplDeviceContext = NULL; pSmplDeviceContext = DeviceGetContext(Device); DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"SmplDeviceHwResourcesGet >>\n"); if (NULL != pSmplDeviceContext) { for (index = 0; index < WdfCmResourceListGetCount(ResourceListTranslated); index++) { pCMResourceDescPartial = WdfCmResourceListGetDescriptor(ResourceListTranslated, index); if (NULL == pCMResourceDescPartial) { DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"pCMResourceDescPartial is NULL!!!\n"); return STATUS_DEVICE_CONFIGURATION_ERROR; } switch (pCMResourceDescPartial->Type) { case CmResourceTypePort: // // Handle port resources here. // DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"CmResourceTypePort 0x%x %d\n", pCMResourceDescPartial->u.Port.Start.LowPart, pCMResourceDescPartial->u.Port.Length); pSmplDeviceContext->pPortAddress = (PUCHAR) pCMResourceDescPartial->u.Port.Start.LowPart; pSmplDeviceContext->PortAddressLength = pCMResourceDescPartial->u.Port.Length; break; case CmResourceTypeMemory: // // Handle memory resources here. // DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"CmResourceTypeMemory Desc\n"); break; case CmResourceTypeInterrupt: // // Handle interrupt resources here. // DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"CmResourceTypeInterrupt\n"); break; default: // // Ignore all other descriptors. // DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"CmResourceType unknown\n"); break; } // end switch } // end for loop } // end if return Status; } // end SmplDeviceHwResourcesGet
NTSTATUS PortIOEvtDevicePrepareHardware( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesRaw, _In_ WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: This event is called by the Framework when the device is started or restarted after a suspend operation. Arguments: Device - Handle to a framework device object. Return Value: NTSTATUS - Failures will result in the device stack being torn down. --*/ { ULONG i; PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; PCM_PARTIAL_RESOURCE_DESCRIPTOR descTranslated; PDEVICE_CONTEXT deviceContext = NULL; NTSTATUS status = STATUS_SUCCESS; PAGED_CODE(); if ((NULL == ResourcesRaw) || (NULL == ResourcesTranslated)){ return STATUS_DEVICE_CONFIGURATION_ERROR; } deviceContext = PortIOGetDeviceContext(Device); for (i=0; i < WdfCmResourceListGetCount(ResourcesRaw); i++) { desc = WdfCmResourceListGetDescriptor(ResourcesRaw, i); descTranslated = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); switch(desc ->Type) { case CmResourceTypePort: switch(descTranslated -> Type) { case CmResourceTypePort: deviceContext -> PortWasMapped = FALSE; deviceContext -> PortBase = ULongToPtr(descTranslated->u.Port.Start.LowPart); deviceContext -> PortCount = descTranslated ->u.Port.Length; KdPrint(("Resource Translated Port: (%x) Length: (%d)\n", descTranslated->u.Port.Start.LowPart, descTranslated->u.Port.Length)); break; case CmResourceTypeMemory: // // Map the memory // deviceContext-> PortBase = (PVOID) MmMapIoSpace(descTranslated->u.Memory.Start, descTranslated->u.Memory.Length, MmNonCached); deviceContext-> PortCount = descTranslated->u.Memory.Length; deviceContext-> PortWasMapped = TRUE; KdPrint(("Resource Translated Memory: (%x) Length: (%d)\n", descTranslated->u.Memory.Start.LowPart, descTranslated->u.Memory.Length)); break; default: KdPrint(("Unhandled resource_type (0x%x)\n", descTranslated->Type)); status = STATUS_UNSUCCESSFUL; ASSERTMSG("Unhandled resource_type in start request\n", FALSE); } break; case CmResourceTypeMemory: deviceContext-> PortBase = (PVOID) MmMapIoSpace (descTranslated->u.Memory.Start, descTranslated->u.Memory.Length, MmNonCached); deviceContext-> PortCount = descTranslated->u.Memory.Length; deviceContext-> PortWasMapped = TRUE; KdPrint(("Resource Translated Memory: (%x) Length: (%d)\n", descTranslated->u.Memory.Start.LowPart, descTranslated->u.Memory.Length)); break; case CmResourceTypeInterrupt: default: KdPrint(("Unhandled resource type (0x%x)\n", desc->Type)); status = STATUS_UNSUCCESSFUL; break; } } return status; }
NTSTATUS fscc_card_init(struct fscc_card *card, WDFCMRESLIST ResourcesTranslated, WDFDEVICE port_device) { unsigned bar_num = 0; unsigned i = 0; PDEVICE_OBJECT pdo; card->device_id = 0; for (i = 0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); if (!descriptor) return STATUS_DEVICE_CONFIGURATION_ERROR; switch (descriptor->Type) { case CmResourceTypePort: switch (i) { case 0: bar_num = 2; break; case 2: bar_num = 0; break; } card->bar[bar_num].address = ULongToPtr(descriptor->u.Port.Start.LowPart); card->bar[bar_num].memory_mapped = FALSE; break; case CmResourceTypeMemory: switch (i) { case 0: bar_num = 2; break; case 2: bar_num = 0; break; } card->bar[bar_num].address = MmMapIoSpace(descriptor->u.Memory.Start, descriptor->u.Memory.Length, MmNonCached); card->bar[bar_num].memory_mapped = TRUE; break; } } pdo = WdfDeviceWdmGetDeviceObject(port_device); PCIReadConfigWord(pdo, 0x02, &card->device_id); return STATUS_SUCCESS; }
_Use_decl_annotations_ NTSTATUS PrepareHardware( WDFDEVICE Device, WDFCMRESLIST ResourceList, WDFCMRESLIST ResourceListTranslated ) /*++ Routine Description: PrepareHardware parses the device resource description and assigns default values in device context. Arguments: Device - Pointer to the device object ResourceList - Pointer to the devices resource list ResourceListTranslated - Ponter to the translated resource list of the device Return Value: Status --*/ { PAGED_CODE(); UNREFERENCED_PARAMETER(ResourceList); PDEVICE_CONTEXT deviceContext; NTSTATUS status = STATUS_SUCCESS; ULONG resourceCount; ULONG memoryResources = 0; ULONG interruptResources = 0; ULONG dmaResources = 0; deviceContext = GetContext(Device); resourceCount = WdfCmResourceListGetCount(ResourceListTranslated); for (ULONG i = 0; i < resourceCount && NT_SUCCESS(status); ++i) { PCM_PARTIAL_RESOURCE_DESCRIPTOR res; res = WdfCmResourceListGetDescriptor(ResourceListTranslated, i); switch (res->Type) { case CmResourceTypeMemory: if (memoryResources == 0) { // // DMA channel registers // if (res->u.Memory.Length < sizeof(DMA_CHANNEL_REGS)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "DMA channel memory region too small (start:0x%llX, length:0x%X)", res->u.Memory.Start.QuadPart, res->u.Memory.Length ); status = STATUS_DEVICE_CONFIGURATION_ERROR; break; } deviceContext->dmaChannelRegs = (PDMA_CHANNEL_REGS)MmMapIoSpaceEx( res->u.Memory.Start, res->u.Memory.Length, PAGE_READWRITE | PAGE_NOCACHE ); if (deviceContext->dmaChannelRegs == NULL) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "Unable to map DMA channel registers."); status = STATUS_INSUFFICIENT_RESOURCES; break; } deviceContext->dmaChannelRegsPa = res->u.Memory.Start; } else if (memoryResources == 1) { // // PWM registers // if (res->u.Memory.Length < sizeof(PWM_REGS)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "PWM control register memory region too small (start:0x%llX, length:0x%X)", res->u.Memory.Start.QuadPart, res->u.Memory.Length ); status = STATUS_DEVICE_CONFIGURATION_ERROR; break; } deviceContext->pwmRegs = (PPWM_REGS)MmMapIoSpaceEx( res->u.Memory.Start, res->u.Memory.Length, PAGE_READWRITE | PAGE_NOCACHE ); if (deviceContext->pwmRegs == NULL) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "Unable to map PWM control registers."); status = STATUS_INSUFFICIENT_RESOURCES; break; } deviceContext->pwmRegsPa = res->u.Memory.Start; } else if (memoryResources == 2) { // // PWM control registers bus address // deviceContext->pwmRegsBusPa = res->u.Memory.Start; } else if (memoryResources == 3) { // // PWM control registers uncached address // PHYSICAL_ADDRESS pa = res->u.Memory.Start; deviceContext->memUncachedOffset = pa.LowPart - deviceContext->pwmRegsPa.LowPart; } else if (memoryResources == 4) { // // PWM clock registers // if (res->u.Memory.Length < sizeof(CM_PWM_REGS)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "PWM clock register memory region too small (start:0x%llX, length:0x%X)", res->u.Memory.Start.QuadPart, res->u.Memory.Length ); status = STATUS_DEVICE_CONFIGURATION_ERROR; break; } deviceContext->cmPwmRegs = (PCM_PWM_REGS)MmMapIoSpaceEx( res->u.Memory.Start, res->u.Memory.Length, PAGE_READWRITE | PAGE_NOCACHE ); if (deviceContext->cmPwmRegs == NULL) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "Unable to map PWM clock registers."); status = STATUS_INSUFFICIENT_RESOURCES; break; } deviceContext->cmPwmRegsPa = res->u.Memory.Start; } else { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "Too many ACPI memory entries. Only 5 memory entries are allowed. Please verify ACPI configuration."); status = STATUS_DEVICE_CONFIGURATION_ERROR; break; } memoryResources++; break; case CmResourceTypeInterrupt: // // Interrupt for used DMA channel. No setup required. // interruptResources++; break; case CmResourceTypeDma: // // Get the used DMA channel. // deviceContext->dmaChannel = res->u.DmaV3.Channel; deviceContext->dmaDreq = res->u.DmaV3.RequestLine; deviceContext->dmaTransferWidth = (DMA_WIDTH)res->u.DmaV3.TransferWidth; // // Sanity check DREQ, transfer width. // if (deviceContext->dmaDreq != DMA_DREQ_PWM) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "PWM DREQ configuration invalid (DREQ:%d)", res->u.DmaV3.RequestLine); status = STATUS_DEVICE_CONFIGURATION_ERROR; break; } if (deviceContext->dmaTransferWidth != Width32Bits) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "PWM DMA transfer width setting (width setting:%d)", (ULONG)res->u.DmaV3.TransferWidth); status = STATUS_DEVICE_CONFIGURATION_ERROR; break; } // // Allocate and initialize contiguous DMA buffer logic. // status = AllocateDmaBuffer(deviceContext); if (NT_ERROR(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "Error allocating DMA buffer (0x%08x)", status); } dmaResources++; break; default: TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "Resource type not allowed for PWM. Please verify ACPI configuration."); status = STATUS_DEVICE_CONFIGURATION_ERROR; break; } } // // Sanity check ACPI resources. // if (memoryResources != 5) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "Too less ACPI memory entries. 5 memory entries are required. Please verify ACPI configuration."); status = STATUS_DEVICE_CONFIGURATION_ERROR; } if (interruptResources != 1) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "Exactly 1 interrupt entry is required and allowed. Please verify ACPI configuration."); status = STATUS_DEVICE_CONFIGURATION_ERROR; } if (dmaResources != 1) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_INIT, "Exactly 1 DMA entry is required and allowed. Please verify ACPI configuration."); status = STATUS_DEVICE_CONFIGURATION_ERROR; } if (NT_SUCCESS(status)) { // // Initialize device context and set default values. // deviceContext->pwmClockConfig.ClockSource = BCM_PWM_CLOCKSOURCE_PLLC; deviceContext->pwmClockConfig.Divisor = CM_PWMCTL_DIVI_PLLC_1MHZ; deviceContext->pwmChannel1Config.Channel = BCM_PWM_CHANNEL_CHANNEL1; deviceContext->pwmChannel1Config.Range = 0x20; deviceContext->pwmChannel1Config.DutyMode = BCM_PWM_DUTYMODE_PWM; deviceContext->pwmChannel1Config.Mode = BCM_PWM_MODE_PWM; deviceContext->pwmChannel1Config.Polarity = BCM_PWM_POLARITY_NORMAL; deviceContext->pwmChannel1Config.Repeat = BCM_PWM_REPEATMODE_OFF; deviceContext->pwmChannel1Config.Silence = BCM_PWM_SILENCELEVEL_LOW; deviceContext->pwmDuty1 = 0; deviceContext->pwmChannel2Config.Channel = BCM_PWM_CHANNEL_CHANNEL2; deviceContext->pwmChannel2Config.Range = 0x20; deviceContext->pwmChannel2Config.DutyMode = BCM_PWM_DUTYMODE_PWM; deviceContext->pwmChannel2Config.Mode = BCM_PWM_MODE_PWM; deviceContext->pwmChannel2Config.Polarity = BCM_PWM_POLARITY_NORMAL; deviceContext->pwmChannel2Config.Repeat = BCM_PWM_REPEATMODE_OFF; deviceContext->pwmChannel2Config.Silence = BCM_PWM_SILENCELEVEL_LOW; deviceContext->pwmDuty2 = 0; deviceContext->pwmMode = PWM_MODE_REGISTER; InitializeListHead(&deviceContext->notificationList); deviceContext->dmaDpcForIsrErrorCount = 0; deviceContext->dmaUnderflowErrorCount = 0; deviceContext->dmaLastKnownCompletedPacket = NO_LAST_COMPLETED_PACKET; deviceContext->dmaPacketsInUse = 0; deviceContext->dmaPacketsToPrime = 0; deviceContext->dmaPacketsToPrimePreset = 0; deviceContext->dmaPacketsProcessed = 0; deviceContext->dmaAudioNotifcationCount = 0; deviceContext->dmaRestartRequired = FALSE; } else { ReleaseHardware(Device, ResourceListTranslated); } return status; }
NTSTATUS BalloonEvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN foundPort = FALSE; PHYSICAL_ADDRESS PortBasePA = {0}; ULONG PortLength = 0; ULONG i; WDF_INTERRUPT_INFO interruptInfo; PDEVICE_CONTEXT devCtx = NULL; PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); UNREFERENCED_PARAMETER(ResourceList); PAGED_CODE(); devCtx = GetDeviceContext(Device); for (i=0; i < WdfCmResourceListGetCount(ResourceListTranslated); i++) { desc = WdfCmResourceListGetDescriptor( ResourceListTranslated, i ); if(!desc) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfResourceCmGetDescriptor failed\n"); return STATUS_DEVICE_CONFIGURATION_ERROR; } switch (desc->Type) { case CmResourceTypePort: if (!foundPort && desc->u.Port.Length >= 0x20) { devCtx->PortMapped = (desc->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE; PortBasePA = desc->u.Port.Start; PortLength = desc->u.Port.Length; foundPort = TRUE; if (devCtx->PortMapped) { devCtx->PortBase = (PUCHAR) MmMapIoSpace( PortBasePA, PortLength, MmNonCached ); if (!devCtx->PortBase) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " Unable to map port range %08I64X, length %d\n", PortBasePA.QuadPart, PortLength); return STATUS_INSUFFICIENT_RESOURCES; } devCtx->PortCount = PortLength; } else { devCtx->PortBase = (PUCHAR)(ULONG_PTR) PortBasePA.QuadPart; devCtx->PortCount = PortLength; } } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-> Port Resource [%08I64X-%08I64X]\n", desc->u.Port.Start.QuadPart, desc->u.Port.Start.QuadPart + desc->u.Port.Length); break; default: break; } } if (!foundPort) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " Missing resources\n"); return STATUS_DEVICE_CONFIGURATION_ERROR; } WDF_INTERRUPT_INFO_INIT(&interruptInfo); WdfInterruptGetInfo(devCtx->WdfInterrupt, &interruptInfo); VirtIODeviceInitialize(&devCtx->VDevice, (ULONG_PTR)devCtx->PortBase, sizeof(devCtx->VDevice)); VirtIODeviceSetMSIXUsed(&devCtx->VDevice, interruptInfo.MessageSignaled); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__); return status; }
NTSTATUS OnEvtDevicePrepareHardware ( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesRaw, _In_ WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: EvtDevicePrepareHardware callback handler for the controller FDO. It expects Register memory and two interrupts - Device and Wake. Arguments: Device - WDFDEVICE object representing the controller. ResourcesRaw - Raw resources relative to the parent bus driver. ResourcesTranslated - Translated resources available for the controller. Return Value: Appropriate NTSTATUS value --*/ { NTSTATUS Status; ULONG ResCount; ULONG ResIndex; PCONTROLLER_CONTEXT ControllerContext; BOOLEAN MemoryResourceMapped; PAGED_CODE(); TraceEntry(); ControllerContext = DeviceGetControllerContext(Device); MemoryResourceMapped = FALSE; ResCount = WdfCmResourceListGetCount(ResourcesRaw); Status = STATUS_SUCCESS; for (ResIndex = 0; ResIndex < ResCount; ResIndex++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptorRaw; PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptorTranslated; ResourceDescriptorRaw = WdfCmResourceListGetDescriptor( ResourcesRaw, ResIndex); switch (ResourceDescriptorRaw->Type) { case CmResourceTypeMemory: if (MemoryResourceMapped == FALSE) { MemoryResourceMapped = TRUE; Status = RegistersCreate(Device, ResourceDescriptorRaw); CHK_NT_MSG(Status, "Failed to read the HW registers"); } break; case CmResourceTypeInterrupt: ResourceDescriptorTranslated = WdfCmResourceListGetDescriptor( ResourcesTranslated, ResIndex); Status = InterruptCreate( Device, ResourceDescriptorRaw, ResourceDescriptorTranslated); CHK_NT_MSG(Status, "Failed to create WDFINTERRUPT object"); break; default: break; } } NT_ASSERT(ControllerContext->DeviceInterrupt != NULL); End: TraceExit(); return STATUS_SUCCESS; }
NTSTATUS SampleDrvEvtDevicePrepareHardware ( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesRaw, _In_ WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: This routine is called by the framework when the PnP manager sends an IRP_MN_START_DEVICE request to the driver stack. Arguments: Device - Supplies a handle to a framework device object. ResourcesRaw - Supplies a handle to a collection of framework resource objects. This collection identifies the raw (bus-relative) hardware resources that have been assigned to the device. ResourcesTranslated - Supplies a handle to a collection of framework resource objects. This collection identifies the translated (system-physical) hardware resources that have been assigned to the device. The resources appear from the CPU's point of view. Return Value: NT status code. --*/ { PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; PSAMPLE_DRV_DEVICE_EXTENSION SampleDrvExtension; ULONG Index; ULONG ResourceCount; NTSTATUS Status; ULONG IoResourceIndex; UNREFERENCED_PARAMETER(Device); UNREFERENCED_PARAMETER(ResourcesRaw); PAGED_CODE(); SampleDrvExtension = SampleDrvGetDeviceExtension(Device); Status = STATUS_SUCCESS; IoResourceIndex = 0; SampleDrvExtension->InterruptCount = 0; // // Walk through the resource list and map all the resources. Only one // memory resource and one interrupt is expected. // ResourceCount = WdfCmResourceListGetCount(ResourcesTranslated); for (Index = 0; Index < ResourceCount; Index += 1) { Descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, Index); switch(Descriptor->Type) { // // This memory resource supplies the base of the device registers. // case CmResourceTypeConnection: // // Check against expected connection type // if ((Descriptor->u.Connection.Class == CM_RESOURCE_CONNECTION_CLASS_GPIO) && (Descriptor->u.Connection.Type == CM_RESOURCE_CONNECTION_TYPE_GPIO_IO)) { SampleDrvExtension->ConnectionIds[IoResourceIndex].LowPart = Descriptor->u.Connection.IdLowPart; SampleDrvExtension->ConnectionIds[IoResourceIndex].HighPart = Descriptor->u.Connection.IdHighPart; IoResourceIndex++; } else { Status = STATUS_UNSUCCESSFUL; } break; // // Interrupt resource // case CmResourceTypeInterrupt: SampleDrvExtension->InterruptCount++; default: break; } if (!NT_SUCCESS(Status)) { goto DevicePrepareHardwareEnd; } } // // Ensure that at least two interrupt resources are defined. One for DIRQL // and another for the passive level ISR // NT_ASSERT(SampleDrvExtension->InterruptCount > 0); if (SampleDrvExtension->InterruptCount < 1) { Status = STATUS_UNSUCCESSFUL; goto DevicePrepareHardwareEnd; } // // Store the number of GPIO IO connection strings // SampleDrvExtension->IoResourceCount = IoResourceIndex; DevicePrepareHardwareEnd: return Status; }
// 此函数类似于WDM中的PNP_MN_START_DEVICE函数,紧接着PnpAdd之后被调用。 // 此时PNP管理器经过甄别之后,已经决定将那些系统资源分配给当前设备。 // 参数ResourceList和ResourceListTranslated代表了这些系统资源。 // 当个函数被调用时候,设备已经进入了D0电源状态;函数完成后,设备即正式进入工作状态。 NTSTATUS DrvClass::PnpPrepareHardware(IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated) { NTSTATUS status; PDEVICE_CONTEXT pContext = NULL; ULONG ulNumRes = 0; ULONG ulIndex; CM_PARTIAL_RESOURCE_DESCRIPTOR* pResDes = NULL; KDBG(DPFLTR_INFO_LEVEL, "[PnpPrepareHardware]"); pContext = GetDeviceContext(m_hDevice); // 配置设备 status = ConfigureUsbDevice(); if(!NT_SUCCESS(status)) return status; // 获取Pipe句柄 status = GetUsbPipes(); if(!NT_SUCCESS(status)) return status; // 初始电源策略, status = InitPowerManagement(); // 获取USB总线驱动接口。总线接口中包含总线驱动提供的回调函数和其他信息。 // 总线接口由系统共用GUID标识。 status = WdfFdoQueryForInterface( m_hDevice, &USB_BUS_INTERFACE_USBDI_GUID1, // 总线接口ID (PINTERFACE)&m_busInterface, // 保存在设备环境块中 sizeof(USB_BUS_INTERFACE_USBDI_V1), 1, NULL); // 调用接口函数,判断USB版本。 if(NT_SUCCESS(status) && m_busInterface.IsDeviceHighSpeed){ if(m_busInterface.IsDeviceHighSpeed(m_busInterface.BusContext)) KDBG(DPFLTR_INFO_LEVEL, "USB 2.0"); else KDBG(DPFLTR_INFO_LEVEL, "USB 1.1"); } // 对系统资源列表,我们不做实质性的操作,仅仅打印一些信息。 // 读者完全可以把下面的这些代码都注释掉。 ulNumRes = WdfCmResourceListGetCount(ResourceList); KDBG(DPFLTR_INFO_LEVEL, "ResourceListCount:%d\n", ulNumRes); // 下面我们饶有兴致地枚举这些系统资源,并打印出它们的相关名称信息。 for(ulIndex = 0; ulIndex < ulNumRes; ulIndex++) { pResDes = WdfCmResourceListGetDescriptor(ResourceList, ulIndex); if(!pResDes)continue; // 取得失败,则跳到下一个 switch (pResDes->Type) { case CmResourceTypeMemory: KDBG(DPFLTR_INFO_LEVEL, "System Resource:CmResourceTypeMemory\n"); break; case CmResourceTypePort: KDBG(DPFLTR_INFO_LEVEL, "System Resource:CmResourceTypePort\n"); break; case CmResourceTypeInterrupt: KDBG(DPFLTR_INFO_LEVEL, "System Resource:CmResourceTypeInterrupt\n"); break; default: KDBG(DPFLTR_INFO_LEVEL, "System Resource:Others %d\n", pResDes->Type); break; } } return STATUS_SUCCESS; }
NTSTATUS VIOSerialEvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourcesRaw, IN WDFCMRESLIST ResourcesTranslated) { int nListSize = 0; PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDescriptor; WDF_INTERRUPT_INFO interruptInfo; int i = 0; PPORTS_DEVICE pContext = GetPortsDevice(Device); bool bPortFound = FALSE; NTSTATUS status = STATUS_SUCCESS; UINT nr_ports, max_queues, size_to_allocate; UNREFERENCED_PARAMETER(ResourcesRaw); PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "<--> %s\n", __FUNCTION__); max_queues = 64; // 2 for each of max 32 ports size_to_allocate = VirtIODeviceSizeRequired((USHORT)max_queues); pContext->pIODevice = (VirtIODevice *)ExAllocatePoolWithTag( NonPagedPool, size_to_allocate, VIOSERIAL_DRIVER_MEMORY_TAG); if (NULL == pContext->pIODevice) { return STATUS_INSUFFICIENT_RESOURCES; } nListSize = WdfCmResourceListGetCount(ResourcesTranslated); for (i = 0; i < nListSize; i++) { if(pResDescriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i)) { switch(pResDescriptor->Type) { case CmResourceTypePort : pContext->bPortMapped = (pResDescriptor->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE; pContext->PortBasePA = pResDescriptor->u.Port.Start; pContext->uPortLength = pResDescriptor->u.Port.Length; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IO Port Info [%08I64X-%08I64X]\n", pResDescriptor->u.Port.Start.QuadPart, pResDescriptor->u.Port.Start.QuadPart + pResDescriptor->u.Port.Length); if (pContext->bPortMapped ) { pContext->pPortBase = MmMapIoSpace(pContext->PortBasePA, pContext->uPortLength, MmNonCached); if (!pContext->pPortBase) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "%s>>> Failed to map IO port!\n", __FUNCTION__); return STATUS_INSUFFICIENT_RESOURCES; } } else { pContext->pPortBase = (PVOID)(ULONG_PTR)pContext->PortBasePA.QuadPart; } bPortFound = TRUE; break; case CmResourceTypeInterrupt: break; } } } if(!bPortFound) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "%s>>> %s", __FUNCTION__, "IO port wasn't found!\n"); return STATUS_DEVICE_CONFIGURATION_ERROR; } WDF_INTERRUPT_INFO_INIT(&interruptInfo); WdfInterruptGetInfo(pContext->WdfInterrupt, &interruptInfo); VirtIODeviceInitialize(pContext->pIODevice, (ULONG_PTR)pContext->pPortBase, size_to_allocate); VirtIODeviceSetMSIXUsed(pContext->pIODevice, interruptInfo.MessageSignaled); VirtIODeviceReset(pContext->pIODevice); VirtIODeviceAddStatus(pContext->pIODevice, VIRTIO_CONFIG_S_ACKNOWLEDGE); pContext->consoleConfig.max_nr_ports = 1; if(pContext->isHostMultiport = VirtIODeviceGetHostFeature(pContext->pIODevice, VIRTIO_CONSOLE_F_MULTIPORT)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "We have multiport host\n"); VirtIODeviceEnableGuestFeature(pContext->pIODevice, VIRTIO_CONSOLE_F_MULTIPORT); VirtIODeviceGet(pContext->pIODevice, FIELD_OFFSET(CONSOLE_CONFIG, max_nr_ports), &pContext->consoleConfig.max_nr_ports, sizeof(pContext->consoleConfig.max_nr_ports)); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VirtIOConsoleConfig->max_nr_ports %d\n", pContext->consoleConfig.max_nr_ports); if (pContext->consoleConfig.max_nr_ports > pContext->pIODevice->maxQueues / 2) { pContext->consoleConfig.max_nr_ports = pContext->pIODevice->maxQueues / 2; TraceEvents(TRACE_LEVEL_WARNING, DBG_PNP, "VirtIOConsoleConfig->max_nr_ports limited to %d\n", pContext->consoleConfig.max_nr_ports); } } if(pContext->isHostMultiport) { WDF_OBJECT_ATTRIBUTES attributes; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = Device; status = WdfSpinLockCreate( &attributes, &pContext->CVqLock ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfSpinLockCreate failed 0x%x\n", status); return status; } } else { //FIXME // VIOSerialAddPort(Device, 0); } nr_ports = pContext->consoleConfig.max_nr_ports; pContext->in_vqs = (struct virtqueue**)ExAllocatePoolWithTag( NonPagedPool, nr_ports * sizeof(struct virtqueue*), VIOSERIAL_DRIVER_MEMORY_TAG); if(pContext->in_vqs == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,"ExAllocatePoolWithTag failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } memset(pContext->in_vqs, 0, nr_ports * sizeof(struct virtqueue*)); pContext->out_vqs = (struct virtqueue**)ExAllocatePoolWithTag( NonPagedPool, nr_ports * sizeof(struct virtqueue*), VIOSERIAL_DRIVER_MEMORY_TAG ); if(pContext->out_vqs == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "ExAllocatePoolWithTag failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } memset(pContext->out_vqs, 0, nr_ports * sizeof(struct virtqueue*)); pContext->DeviceOK = TRUE; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__); return status; }
NTSTATUS TpmEvtDevicePrepareHardware ( WDFDEVICE Device, WDFCMRESLIST Resources, WDFCMRESLIST ResourcesTranslated ) { NTSTATUS status; ULONG ListCount = 0; ULONG MemLen = 0; // ULONG NumberOfBytes; PTPM_CONTEXT TpmContext; PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDesc; ULONG ListIndex; PHYSICAL_ADDRESS MemoryAddr; BOOLEAN bMemAddr = FALSE; PAGED_CODE(); TpmContext = GetTpmContext(Device); KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "TpmEvtDevicePrepareHardware (raw count = %u, trans count = %u)\n", WdfCmResourceListGetCount(Resources), WdfCmResourceListGetCount(ResourcesTranslated))); ListIndex = 0; ListCount = WdfCmResourceListGetCount(ResourcesTranslated); if(ListCount) { while(ListIndex < ListCount) { ResourceDesc = WdfCmResourceListGetDescriptor(ResourcesTranslated,ListIndex); if(!ResourceDesc) break; if(ResourceDesc->Type == CmResourceTypePort) { if(TpmContext->UsePortBasedIO) { TpmContext->PortAddr = (PUCHAR)ResourceDesc->u.Port.Start.u.LowPart; } } else if(ResourceDesc->Type == CmResourceTypeMemory && TpmContext->UsePortBasedIO == 0) { MemoryAddr.u.LowPart = ResourceDesc->u.Memory.Start.u.LowPart; MemoryAddr.u.HighPart = ResourceDesc->u.Memory.Start.u.HighPart; MemLen = ResourceDesc->u.Memory.Length; bMemAddr = TRUE; } ListIndex++; } do { if(ListIndex < WdfCmResourceListGetCount( ResourcesTranslated)) { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "WdfCmResourceListGetDescriptor failed.\n")); status = STATUS_DEVICE_CONFIGURATION_ERROR; // 0xC0000182; break; } if(TpmContext->UsePortBasedIO) { if(!TpmContext->PortAddr) { if(TpmContext->UsePortBasedIO != TRUE) { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_WARNING_LEVEL, "Port I/O resources required but not allocated for Vendor index %u", TpmContext->UsePortBasedIO)); status = STATUS_DEVICE_CONFIGURATION_ERROR; // 0xC0000182; goto Exit; } KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_WARNING_LEVEL, "No resources allocated for Port-based I/O.")); status = STATUS_DEVICE_CONFIGURATION_ERROR; break; } } else { if(!bMemAddr) { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "Physical address resource not provided via ACPI; using default address and size.\n")); MemLen = 1024; MemoryAddr.u.LowPart = TPM_DEFAULT_ADDRESS; MemoryAddr.u.HighPart = 0; } if(MemLen < 1024) { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "Physical address length provided is too small (%d)\n",MemLen)); status = STATUS_DEVICE_CONFIGURATION_ERROR; //0xC0000182; break; } if(MemoryAddr.u.LowPart != TPM_DEFAULT_ADDRESS || MemoryAddr.u.HighPart) { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "Physical address provided is incorrect: 0x%08x`%08x\n",MemoryAddr.u.HighPart,MemoryAddr.u.LowPart)); status = STATUS_DEVICE_CONFIGURATION_ERROR; //0xC0000182; break; } TpmContext->MemAddr = MmMapIoSpace(MemoryAddr,MemLen,MmNonCached); if(!TpmContext->MemAddr) { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "MmMapIoSpace couldn't map the TPM device: 0x%x.\n", MemoryAddr.u.LowPart)); status = STATUS_INSUFFICIENT_RESOURCES; //0xC000009A; break; } TpmContext->MemLen = MemLen; } status = TpmSetDefaultTimingValues(TpmContext); if(!NT_SUCCESS(status)) { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "TpmSetDefaultTimingValues failed with status 0x%x",status)); break; } if(TpmContext->SkipInitCommands) { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "Skipping initialization commands\n")); } else { TpmGetTimeoutInfo(TpmContext); TpmGetDurations(TpmContext); // 获取硬件厂商信息 TpmGetManufacturer(TpmContext); } status = TpmVerifyAccessRegister(TpmContext,TpmINB(TpmContext,0),0); if(!NT_SUCCESS(status)) { break; } #if _NT_TARGET_VERSION >= 0x601 status = TpmEntropyInit(TpmContext); #endif } while(FALSE); } else { KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "Physical address resource not provided via ACPI; using default address and size.\n")); } Exit: KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "TpmEvtDevicePrepareHardware exited with Status code 0x%x\n",status)); return status; }
NTSTATUS I2CInitialize( _In_ PDEVICE_CONTEXT DeviceContext, _In_ WDFCMRESLIST ResourcesRaw, _In_ WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: Initialize the I2C resource that provides a communications channel to the port controller hardware. Arguments: DeviceContext - Context for a framework device. ResourcesRaw - A handle to a framework resource-list object that identifies the raw hardware resources that the Plug and Play manager has assigned to the device. ResourcesTranslated - A handle to a framework resource-list object that identifies the translated hardware resources that the Plug and Play manager has assigned to the device. Return Value: NTSTATUS --*/ { TRACE_FUNC_ENTRY(TRACE_I2C); UNREFERENCED_PARAMETER(ResourcesRaw); PAGED_CODE(); NTSTATUS status = STATUS_SUCCESS; WDF_INTERRUPT_CONFIG interruptConfig; PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor = nullptr; ULONG interruptIndex = 0; BOOLEAN connFound = FALSE; BOOLEAN interruptFound = FALSE; ULONG resourceCount; // Check for I2C and Interrupt resources from the resources that PnP manager has // allocated to our device. resourceCount = WdfCmResourceListGetCount(ResourcesTranslated); for (ULONG i = 0; ((connFound == FALSE) || (interruptFound == FALSE)) && (i < resourceCount); i++) { descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); switch (descriptor->Type) { case CmResourceTypeConnection: // Check for I2C resource if (descriptor->u.Connection.Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL && descriptor->u.Connection.Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C) { DeviceContext->I2CConnectionId.LowPart = descriptor->u.Connection.IdLowPart; DeviceContext->I2CConnectionId.HighPart = descriptor->u.Connection.IdHighPart; connFound = TRUE; TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_I2C, "I2C resource found with connection id: 0x%llx", DeviceContext->I2CConnectionId.QuadPart); } break; case CmResourceTypeInterrupt: // We've found an interrupt resource. interruptFound = TRUE; interruptIndex = i; TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_I2C, "Interrupt resource found at index: %lu", interruptIndex); break; default: // We don't care about other descriptors. break; } } // Fail if either connection or interrupt resource was not found. if (!connFound) { status = STATUS_INSUFFICIENT_RESOURCES; TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "Failed finding required I2C resource. Status: %!STATUS!", status); goto Exit; } if (!interruptFound) { status = STATUS_INSUFFICIENT_RESOURCES; TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "Failed finding required interrupt resource. Status: %!STATUS!", status); goto Exit; } // The alerts from the port controller hardware will be handled in a passive ISR. // The ISR performs hardware read and write operations which block until the hardware access is complete. // Waiting is unacceptable at DIRQL, so we perform our ISR at PASSIVE_LEVEL. WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, OnInterruptPassiveIsr, NULL); interruptConfig.PassiveHandling = TRUE; interruptConfig.InterruptTranslated = WdfCmResourceListGetDescriptor(ResourcesTranslated, interruptIndex); interruptConfig.InterruptRaw = WdfCmResourceListGetDescriptor(ResourcesRaw, interruptIndex); status = WdfInterruptCreate( DeviceContext->Device, &interruptConfig, WDF_NO_OBJECT_ATTRIBUTES, &DeviceContext->AlertInterrupt); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_I2C, "WdfInterruptCreate failed. status: %!STATUS!", status); goto Exit; } Exit: TRACE_FUNC_EXIT(TRACE_I2C); return status; }
NTSTATUS OnPrepareHardware( _In_ WDFDEVICE FxDevice, _In_ WDFCMRESLIST FxResourcesRaw, _In_ WDFCMRESLIST FxResourcesTranslated ) /*++ Routine Description: This routine caches the SPB resource connection ID. Arguments: FxDevice - a handle to the framework device object FxResourcesRaw - list of translated hardware resources that the PnP manager has assigned to the device FxResourcesTranslated - list of raw hardware resources that the PnP manager has assigned to the device Return Value: Status --*/ { FuncEntry(TRACE_FLAG_WDFLOADING); PDEVICE_CONTEXT pDevice = GetDeviceContext(FxDevice); BOOLEAN fSpbResourceFound = FALSE; NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; UNREFERENCED_PARAMETER(FxResourcesRaw); // // Parse the peripheral's resources. // ULONG resourceCount = WdfCmResourceListGetCount(FxResourcesTranslated); for(ULONG i = 0; i < resourceCount; i++) { PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; UCHAR Class; UCHAR Type; pDescriptor = WdfCmResourceListGetDescriptor( FxResourcesTranslated, i); switch (pDescriptor->Type) { case CmResourceTypeConnection: // // Look for I2C or SPI resource and save connection ID. // Class = pDescriptor->u.Connection.Class; Type = pDescriptor->u.Connection.Type; if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL && Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C) { if (fSpbResourceFound == FALSE) { status = STATUS_SUCCESS; pDevice->I2CContext.I2cResHubId.LowPart = pDescriptor->u.Connection.IdLowPart; pDevice->I2CContext.I2cResHubId.HighPart = pDescriptor->u.Connection.IdHighPart; fSpbResourceFound = TRUE; Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_WDFLOADING, "SPB resource found with ID=0x%llx", pDevice->I2CContext.I2cResHubId.QuadPart); } else { Trace( TRACE_LEVEL_WARNING, TRACE_FLAG_WDFLOADING, "Duplicate SPB resource found with ID=0x%llx", pDevice->I2CContext.I2cResHubId.QuadPart); } } break; default: // // Ignoring all other resource types. // break; } } // // An SPB resource is required. // if (fSpbResourceFound == FALSE) { status = STATUS_NOT_FOUND; Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_WDFLOADING, "SPB resource not found - %!STATUS!", status); } status = SpbTargetInitialize(FxDevice, &pDevice->I2CContext); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_WDFLOADING, "Error in Spb initialization - %!STATUS!", status); return status; } FuncExit(TRACE_FLAG_WDFLOADING); return status; }
NTSTATUS PLxPrepareHardware( IN PDEVICE_EXTENSION DevExt, IN WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: Gets the HW resources assigned by the bus driver from the start-irp and maps it to system address space. Arguments: DevExt Pointer to our DEVICE_EXTENSION Return Value: None --*/ { ULONG i; NTSTATUS status = STATUS_SUCCESS; CHAR * bar; BOOLEAN foundRegs = FALSE; PHYSICAL_ADDRESS regsBasePA = {0}; ULONG regsLength = 0; BOOLEAN foundSRAM = FALSE; PHYSICAL_ADDRESS SRAMBasePA = {0}; ULONG SRAMLength = 0; BOOLEAN foundSRAM2 = FALSE; //PHYSICAL_ADDRESS SRAM2BasePA = {0}; //ULONG SRAM2Length = 0; BOOLEAN foundPort = FALSE; PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; PAGED_CODE(); // // Parse the resource list and save the resource information. // for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i ); if(!desc) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfResourceCmGetDescriptor failed"); return STATUS_DEVICE_CONFIGURATION_ERROR; } switch (desc->Type) { case CmResourceTypeMemory: bar = NULL; if (foundSRAM && !foundSRAM2 && desc->u.Memory.Length == PCI9656_SRAM_SIZE) { //SRAM2BasePA = desc->u.Memory.Start; //SRAM2Length = desc->u.Memory.Length; foundSRAM2 = TRUE; bar = "BAR3"; } if (foundRegs && !foundSRAM && desc->u.Memory.Length == PCI9656_SRAM_SIZE) { SRAMBasePA = desc->u.Memory.Start; SRAMLength = desc->u.Memory.Length; foundSRAM = TRUE; bar = "BAR2"; } if (!foundRegs && desc->u.Memory.Length == 0x200) { regsBasePA = desc->u.Memory.Start; regsLength = desc->u.Memory.Length; foundRegs = TRUE; bar = "BAR0"; } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, " - Memory Resource [%I64X-%I64X] %s", desc->u.Memory.Start.QuadPart, desc->u.Memory.Start.QuadPart + desc->u.Memory.Length, (bar) ? bar : "<unrecognized>" ); break; case CmResourceTypePort: bar = NULL; if (!foundPort && desc->u.Port.Length >= 0x100) { foundPort = TRUE; bar = "BAR1"; } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, " - Port Resource [%08I64X-%08I64X] %s", desc->u.Port.Start.QuadPart, desc->u.Port.Start.QuadPart + desc->u.Port.Length, (bar) ? bar : "<unrecognized>" ); break; default: // // Ignore all other descriptors // break; } } if (!(foundRegs && foundSRAM)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "PLxMapResources: Missing resources"); return STATUS_DEVICE_CONFIGURATION_ERROR; } // // Map in the Registers Memory resource: BAR0 // DevExt->RegsBase = (PUCHAR) MmMapIoSpace( regsBasePA, regsLength, MmNonCached ); if (!DevExt->RegsBase) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " - Unable to map Registers memory %08I64X, length %d", regsBasePA.QuadPart, regsLength); return STATUS_INSUFFICIENT_RESOURCES; } DevExt->RegsLength = regsLength; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, " - Registers %p, length %d", DevExt->RegsBase, DevExt->RegsLength ); // // Set seperated pointer to PCI9656_REGS structure. // DevExt->Regs = (PPCI9656_REGS) DevExt->RegsBase; // // Map in the SRAM Memory Space resource: BAR2 // DevExt->SRAMBase = (PUCHAR) MmMapIoSpace( SRAMBasePA, SRAMLength, MmNonCached ); if (!DevExt->SRAMBase) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " - Unable to map SRAM memory %08I64X, length %d", SRAMBasePA.QuadPart, SRAMLength); return STATUS_INSUFFICIENT_RESOURCES; } DevExt->SRAMLength = SRAMLength; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, " - SRAM %p, length %d", DevExt->SRAMBase, DevExt->SRAMLength ); return status; }
/*++ Routine Description: In this callback, the driver does whatever is necessary to make the hardware ready to use. Arguments: Device - A handle to a framework device object. ResourcesRaw - A handle to a framework resource-list object that identifies the raw hardware resources that the Plug and Play manager has assigned to the device. ResourcesTranslated - A handle to a framework resource-list object that identifies the translated hardware resources that the Plug and Play manager has assigned to the device. Return Value: NTSTATUS value --*/ _Use_decl_annotations_ NTSTATUS VchiqPrepareHardware ( WDFDEVICE Device, WDFCMRESLIST ResourcesRaw, WDFCMRESLIST ResourcesTranslated ) { NTSTATUS status; DEVICE_CONTEXT* deviceContextPtr; ULONG resourceCount; ULONG MemoryResourceCount = 0; ULONG InterruptResourceCount = 0; PAGED_CODE(); deviceContextPtr = VchiqGetDeviceContext(Device); resourceCount = WdfCmResourceListGetCount(ResourcesTranslated); for (ULONG i = 0; i < resourceCount; ++i) { PCM_PARTIAL_RESOURCE_DESCRIPTOR res; res = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); switch (res->Type) { case CmResourceTypeMemory: { VCHIQ_LOG_INFORMATION( "Memory Resource Start: 0x%08x, Length: 0x%08x", res->u.Memory.Start.LowPart, res->u.Memory.Length); deviceContextPtr->VchiqRegisterPtr = MmMapIoSpaceEx( res->u.Memory.Start, res->u.Memory.Length, PAGE_READWRITE | PAGE_NOCACHE); if (deviceContextPtr->VchiqRegisterPtr == NULL) { VCHIQ_LOG_ERROR("Failed to map VCHIQ register"); status = STATUS_UNSUCCESSFUL; goto End; } deviceContextPtr->VchiqRegisterLength = res->u.Memory.Length; ++MemoryResourceCount; } break; case CmResourceTypeInterrupt: { VCHIQ_LOG_INFORMATION( "Interrupt Level: 0x%08x, Vector: 0x%08x\n", res->u.Interrupt.Level, res->u.Interrupt.Vector); WDF_INTERRUPT_CONFIG interruptConfig; WDF_INTERRUPT_CONFIG_INIT ( &interruptConfig, VchiqIsr, VchiqDpc); interruptConfig.InterruptRaw = WdfCmResourceListGetDescriptor (ResourcesRaw, i); interruptConfig.InterruptTranslated = res; status = WdfInterruptCreate( Device, &interruptConfig, WDF_NO_OBJECT_ATTRIBUTES, &deviceContextPtr->VchiqIntObj); if (!NT_SUCCESS (status)) { VCHIQ_LOG_ERROR ( "Fail to initialize VCHIQ interrupt object"); return status; } ++InterruptResourceCount; } break; default: { VCHIQ_LOG_WARNING("Unsupported resources, ignoring"); } break; } if (MemoryResourceCount && InterruptResourceCount) break; } if (MemoryResourceCount != VCHIQ_MEMORY_RESOURCE_TOTAL && InterruptResourceCount != VCHIQ_INT_RESOURCE_TOTAL) { status = STATUS_UNSUCCESSFUL; VCHIQ_LOG_ERROR("Unknown resource assignment"); goto End; } status = STATUS_SUCCESS; End: if (!NT_SUCCESS(status)) { VCHIQ_LOG_ERROR("VchiqPrepareHardware failed %!STATUS!", status); } return status; }
NTSTATUS PCIAllocBars(WDFCMRESLIST ResourcesTranslated, PVIRTIO_WDF_DRIVER pWdfDriver) { PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDescriptor; ULONG nInterrupts = 0, nMSIInterrupts = 0; int nListSize = WdfCmResourceListGetCount(ResourcesTranslated); int i; PVIRTIO_WDF_BAR pBar; PCI_COMMON_HEADER PCIHeader; /* read the PCI config header */ if (pWdfDriver->PCIBus.GetBusData( pWdfDriver->PCIBus.Context, PCI_WHICHSPACE_CONFIG, &PCIHeader, 0, sizeof(PCIHeader)) != sizeof(PCIHeader)) { return STATUS_DEVICE_CONFIGURATION_ERROR; } for (i = 0; i < nListSize; i++) { pResDescriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); if (pResDescriptor) { switch (pResDescriptor->Type) { case CmResourceTypePort: case CmResourceTypeMemory: pBar = (PVIRTIO_WDF_BAR)ExAllocatePoolWithTag( NonPagedPool, sizeof(VIRTIO_WDF_BAR), pWdfDriver->MemoryTag); if (pBar == NULL) { /* undo what we've done so far */ PCIFreeBars(pWdfDriver); return STATUS_INSUFFICIENT_RESOURCES; } /* unfortunately WDF doesn't tell us BAR indices */ pBar->iBar = virtio_get_bar_index(&PCIHeader, pResDescriptor->u.Memory.Start); if (pBar->iBar < 0) { /* undo what we've done so far */ PCIFreeBars(pWdfDriver); return STATUS_NOT_FOUND; } pBar->bPortSpace = !!(pResDescriptor->Flags & CM_RESOURCE_PORT_IO); pBar->BasePA = pResDescriptor->u.Memory.Start; pBar->uLength = pResDescriptor->u.Memory.Length; if (pBar->bPortSpace) { pBar->pBase = (PVOID)(ULONG_PTR)pBar->BasePA.QuadPart; } else { /* memory regions are mapped into the virtual memory space on demand */ pBar->pBase = NULL; } PushEntryList(&pWdfDriver->PCIBars, &pBar->ListEntry); break; case CmResourceTypeInterrupt: nInterrupts++; if (pResDescriptor->Flags & (CM_RESOURCE_INTERRUPT_LATCHED | CM_RESOURCE_INTERRUPT_MESSAGE)) { nMSIInterrupts++; } break; } } } pWdfDriver->nInterrupts = nInterrupts; pWdfDriver->nMSIInterrupts = nMSIInterrupts; return STATUS_SUCCESS; }