pascal ComponentResult __SoundComponentClose( void *dummy, ComponentInstance self) { ReleaseHardware(); /* close mixer */ if( GLOBAL.sourceComponent ) { CloseMixerSoundComponent( GLOBAL.sourceComponent ); GLOBAL.sourceComponent = NULL; } /* save preferences */ mol_audio_cleanup( self ); return noErr; }
_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; }