Example #1
0
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;
}
Example #2
0
_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;
}