Esempio n. 1
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;
}
Esempio n. 2
0
File: device.c Progetto: MHesham/bsp
/*++

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;
}
Esempio n. 3
0
NTSTATUS
RegistersCreate(
    _In_ WDFDEVICE Device,
    _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR  RegistersResource
    )
/*++

Routine Description:

    Helper function to map the memory resources to the HW registers.

Arguments:

    Device - Wdf device object corresponding to the FDO

    RegisterResource -  Raw resource for the memory

Return Value:

    Appropriate NTSTATUS value

--*/
{
    NTSTATUS Status;
    PREGISTERS_CONTEXT Context;
    WDF_OBJECT_ATTRIBUTES Attributes;

    TraceEntry();

    PAGED_CODE();

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, REGISTERS_CONTEXT);

    Status = WdfObjectAllocateContext(Device, &Attributes, &Context);
    if (Status == STATUS_OBJECT_NAME_EXISTS) {
        //
        // In the case of a resource rebalance, the context allocated
        // previously still exists.
        //
        Status = STATUS_SUCCESS;
        RtlZeroMemory(Context, sizeof(*Context));
    }
    CHK_NT_MSG(Status, "Failed to allocate context for registers");

    Context->RegisterBase = MmMapIoSpaceEx(
                                RegistersResource->u.Memory.Start,
                                RegistersResource->u.Memory.Length,
                                PAGE_NOCACHE | PAGE_READWRITE);

    if (Context->RegisterBase == NULL) {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        CHK_NT_MSG(Status, "MmMapIoSpaceEx failed");
    }

    Context->RegistersLength = RegistersResource->u.Memory.Length;

End:

    TraceExit();
    return Status;
}