예제 #1
0
NTSTATUS
PLxEvtDeviceReleaseHardware(
    IN  WDFDEVICE Device,
    IN  WDFCMRESLIST ResourcesTranslated
    )
/*++

Routine Description:

    Unmap the resources that were mapped in PLxEvtDevicePrepareHardware.
    This will only be called when the device stopped for resource rebalance,
    surprise-removed or query-removed.

Arguments:

    Device - A handle to the WDFDEVICE

    ResourcesTranslated - The translated PnP resources associated with the
        device.  This is what is important to a PCI device.

Return Value:

    NT status code - failure will result in the device stack being torn down

--*/
{
	KdPrint(("Entry PLxEvtDeviceReleaseHardware Routine"));
    PDEVICE_EXTENSION   devExt;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(ResourcesTranslated);

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                "--> PLxEvtDeviceReleaseHardware");

    devExt = PLxGetDeviceContext(Device);

    if (devExt->RegsBase) {

        MmUnmapIoSpace(devExt->RegsBase, devExt->RegsLength);
        devExt->RegsBase = NULL;
    }

    if(devExt->SRAMBase){
        MmUnmapIoSpace(devExt->SRAMBase, devExt->SRAMLength);
        devExt->SRAMBase = NULL;
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                "<-- PLxEvtDeviceReleaseHardware");

	KdPrint(("Leave PLxEvtDeviceReleaseHardware Routine"));
    return status;
}
예제 #2
0
NTSTATUS
PLxEvtDeviceD0Entry(
    IN  WDFDEVICE Device,
    IN  WDF_POWER_DEVICE_STATE PreviousState
    )
/*++

Routine Description:

    This routine prepares the device for use.  It is called whenever the device
    enters the D0 state, which happens when the device is started, when it is
    restarted, and when it has been powered off.

    Note that interrupts will not be enabled at the time that this is called.
    They will be enabled after this callback completes.

    This function is not marked pageable because this function is in the
    device power up path. When a function is marked pagable and the code
    section is paged out, it will generate a page fault which could impact
    the fast resume behavior because the client driver will have to wait
    until the system drivers can service this page fault.

Arguments:

    Device  - The handle to the WDF device object

    PreviousState - The state the device was in before this callback was invoked.

Return Value:

    NTSTATUS

    Success implies that the device can be used.

    Failure will result in the    device stack being torn down.

--*/
{
    PDEVICE_EXTENSION   devExt;
    NTSTATUS            status;

    UNREFERENCED_PARAMETER(PreviousState);

    devExt = PLxGetDeviceContext(Device);

    status = PLxInitWrite( devExt );
    if (NT_SUCCESS(status)) {

        status = PLxInitRead( devExt );

    }

    return status;
}
예제 #3
0
NTSTATUS
PLxEvtDevicePrepareHardware (
    WDFDEVICE       Device,
    WDFCMRESLIST   Resources,
    WDFCMRESLIST   ResourcesTranslated
    )
/*++

Routine Description:

    Performs whatever initialization is needed to setup the device, setting up
    a DMA channel or mapping any I/O port resources.  This will only be called
    as a device starts or restarts, not every time the device moves into the D0
    state.  Consequently, most hardware initialization belongs elsewhere.

Arguments:

    Device - A handle to the WDFDEVICE

    Resources - The raw PnP resources associated with the device.  Most of the
        time, these aren't useful for a PCI device.

    ResourcesTranslated - The translated PnP resources associated with the
        device.  This is what is important to a PCI device.

Return Value:

    NT status code - failure will result in the device stack being torn down

--*/
{
    NTSTATUS            status = STATUS_SUCCESS;
    PDEVICE_EXTENSION   devExt;

    UNREFERENCED_PARAMETER(Resources);

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                "--> PLxEvtDevicePrepareHardware");

    devExt = PLxGetDeviceContext(Device);

    status = PLxPrepareHardware(devExt, ResourcesTranslated);
    if (!NT_SUCCESS (status)){
        return status;
    }


    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                "<-- PLxEvtDevicePrepareHardware, status %!STATUS!", status);

    return status;
}
예제 #4
0
NTSTATUS
PLxEvtInterruptDisable(
    IN WDFINTERRUPT Interrupt,
    IN WDFDEVICE    Device
    )
/*++

Routine Description:

    Called by the framework at DIRQL before Deregistering the ISR with the kernel
    by calling IoDisconnectInterrupt.

Return Value:

    NTSTATUS
--*/
{
    PDEVICE_EXTENSION  devExt;

    union {
        INT_CSR   bits;
        ULONG     ulong;
    } intCSR;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
                "PLxEvtInterruptDisable: Interrupt 0x%p, Device 0x%p\n",
                Interrupt, Device);

    devExt  = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt));

    intCSR.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr );

    intCSR.bits.PciIntEnable = FALSE;

    WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr,
                          intCSR.ulong );

    return STATUS_SUCCESS;
}
예제 #5
0
BOOLEAN
PLxEvtInterruptIsr(
    IN WDFINTERRUPT Interrupt,
    IN ULONG        MessageID
    )
/*++
Routine Description:

    Interrupt handler for this driver. Called at DIRQL level when the
    device or another device sharing the same interrupt line asserts
    the interrupt. The driver first checks the device to make sure whether
    this interrupt is generated by its device and if so clear the interrupt
    register to disable further generation of interrupts and queue a
    DPC to do other I/O work related to interrupt - such as reading
    the device memory, starting a DMA transaction, coping it to
    the request buffer and completing the request, etc.

Arguments:

    Interupt   - Handle to WDFINTERRUPT Object for this device.
    MessageID  - MSI message ID (always 0 in this configuration)

Return Value:

     TRUE   --  This device generated the interrupt.
     FALSE  --  This device did not generated this interrupt.

--*/
{
    PDEVICE_EXTENSION   devExt;
    BOOLEAN             isRecognized = FALSE;

    union {
        INT_CSR bits;
        ULONG   ulong;
    } intCsr;

    UNREFERENCED_PARAMETER(MessageID);

    //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
    //            "--> PLxInterruptHandler");

    devExt  = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt));

    //
    // Read the Interrupt CSR register (INTCSR)
    //
    intCsr.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr );

    //
    // Is DMA channel 0 (Write-side) Active?
    //
    if (intCsr.bits.DmaChan0IntActive) {

        TraceEvents(TRACE_LEVEL_INFORMATION,  DBG_INTERRUPT,
                    " Interrupt for DMA Channel 0 (write)");

        devExt->IntCsr.bits.DmaChan0IntActive = TRUE;

        //
        // Clear this interrupt.
        //
        devExt->Dma0Csr.uchar =
            READ_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma0_Csr );

        devExt->Dma0Csr.bits.Clear = TRUE;

        WRITE_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma0_Csr,
                              devExt->Dma0Csr.uchar );

        isRecognized = TRUE;
    }

    //
    // Is DMA channel 1 (Read-side) Active?
    //
    if (intCsr.bits.DmaChan1IntActive) {

        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
                    " Interrupt for DMA Channel 1 (read)");

        devExt->IntCsr.bits.DmaChan1IntActive = TRUE;

        //
        // Clear this interrupt.
        //
        devExt->Dma1Csr.uchar =
            READ_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma1_Csr );

        devExt->Dma1Csr.bits.Clear = TRUE;

        WRITE_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma1_Csr,
                              devExt->Dma1Csr.uchar );

        isRecognized = TRUE;
    }

    if ((isRecognized) &&
        ((devExt->Dma0Csr.bits.Done) ||
         (devExt->Dma1Csr.bits.Done))) {
        //
        // A read or a write or both is done. Queue a DPC.
        //
        WdfInterruptQueueDpcForIsr( devExt->Interrupt );
    }

    //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT,
    //            "<-- PLxInterruptHandler");

    return isRecognized;
}
예제 #6
0
_Use_decl_annotations_
VOID
PLxEvtInterruptDpc(
    WDFINTERRUPT Interrupt,
    WDFOBJECT    Device
    )
/*++

Routine Description:

    DPC callback for ISR. Please note that on a multiprocessor system,
    you could have more than one DPCs running simulataneously on
    multiple processors. So if you are accesing any global resources
    make sure to synchrnonize the accesses with a spinlock.

Arguments:

    Interupt  - Handle to WDFINTERRUPT Object for this device.
    Device    - WDFDEVICE object passed to InterruptCreate

Return Value:

--*/
{
    NTSTATUS            status;
    WDFDMATRANSACTION   dmaTransaction;
    PDEVICE_EXTENSION   devExt;
    BOOLEAN             writeInterrupt = FALSE;
    BOOLEAN             readInterrupt  = FALSE;

    UNREFERENCED_PARAMETER(Device);


    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "--> EvtInterruptDpc");

    devExt  = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt));

    //
    // Acquire this device's InterruptSpinLock.
    //
    WdfInterruptAcquireLock( Interrupt );


    if ((devExt->IntCsr.bits.DmaChan0IntActive) &&
        (devExt->Dma0Csr.bits.Done)) {

        //
        // If Dma0 channel 0 (write) is interrupting and the
        //  Done bit is set in the Dma0 CSR,
        //  we're interrupting because a WRITE is complete.
        // Clear the done bit and channel interrupting bit from
        //  our copies...
        //
        devExt->IntCsr.bits.DmaChan0IntActive = FALSE;
        devExt->Dma0Csr.uchar = 0;

        writeInterrupt = TRUE;
    }

    if ((devExt->IntCsr.bits.DmaChan1IntActive) &&
        (devExt->Dma1Csr.bits.Done)) {

        //
        // If DMA channel 1 is interrupting and the
        //  DONE bit is set in the DMA1 control/status
        //  register, we're interrupting because a READ
        //  is complete.
        // Clear the done bit and channel interrupting bit from
        //  our copies...
        //
        devExt->IntCsr.bits.DmaChan1IntActive = FALSE;
        devExt->Dma0Csr.uchar = 0;

        readInterrupt = TRUE;
    }

    //
    // Release our interrupt spinlock
    //
    WdfInterruptReleaseLock( Interrupt );

    //
    // Did a Write DMA complete?
    //
    if (writeInterrupt) {

        BOOLEAN transactionComplete;

        //
        // Get the current Write DmaTransaction.
        //
        dmaTransaction = devExt->WriteDmaTransaction;

        //
        // Indicate this DMA operation has completed:
        // This may drive the transfer on the next packet if
        // there is still data to be transfered in the request.
        //
        transactionComplete = WdfDmaTransactionDmaCompleted( dmaTransaction,
                                                         &status );

        if (transactionComplete) {
            //
            // Complete this DmaTransaction.
            //
            TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,
                                     "Completing Write request in the DpcForIsr");

            PLxWriteRequestComplete( dmaTransaction, status );

        }
    }

    //
    // Did a Read DMA complete?
    //
    if (readInterrupt) {

        BOOLEAN                transactionComplete;
        PDMA_TRANSFER_ELEMENT  dteVA;
        size_t                 length;

        //
        // Get the current Read DmaTransaction.
        //
        dmaTransaction = devExt->ReadDmaTransaction;

        //
        // Only on Read-side --
        //    Use "DMA Clear-Count Mode" to get complemetary
        //    transferred byte count.
        //
        length = WdfDmaTransactionGetCurrentDmaTransferLength( dmaTransaction );

        dteVA = (PDMA_TRANSFER_ELEMENT) devExt->ReadCommonBufferBase;

        while(dteVA->DescPtr.LastElement == FALSE) {
            length -= dteVA->TransferSize;
            dteVA++;
        }
        length -= dteVA->TransferSize;

        //
        // Indicate this DMA operation has completed:
        // This may drive the transfer on the next packet if
        // there is still data to be transfered in the request.
        //
        transactionComplete =
            WdfDmaTransactionDmaCompletedWithLength( dmaTransaction,
                                                     length,
                                                     &status );

        if (transactionComplete) {
            //
            // Complete this DmaTransaction.
            //
            TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,
                                    "Completing Read request in the DpcForIsr");

            PLxReadRequestComplete( dmaTransaction, status );

        }
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "<-- EvtInterruptDpc");

    return;
}
예제 #7
0
NTSTATUS
PLxEvtDeviceD0Exit(
    IN  WDFDEVICE Device,
    IN  WDF_POWER_DEVICE_STATE TargetState
    )
/*++

Routine Description:

    This routine undoes anything done in PLxEvtDeviceD0Entry.  It is called
    whenever the device leaves the D0 state, which happens when the device
    is stopped, when it is removed, and when it is powered off.

    The device is still in D0 when this callback is invoked, which means that
    the driver can still touch hardware in this routine.

    Note that interrupts have already been disabled by the time that this
    callback is invoked.

Arguments:

    Device  - The handle to the WDF device object

    TargetState - The state the device will go to when this callback completes.

Return Value:

    Success implies that the device can be used.  Failure will result in the
    device stack being torn down.

--*/
{
    PDEVICE_EXTENSION   devExt;

    PAGED_CODE();

    devExt = PLxGetDeviceContext(Device);

    switch (TargetState) {
    case WdfPowerDeviceD1:
    case WdfPowerDeviceD2:
    case WdfPowerDeviceD3:

        //
        // Fill in any code to save hardware state here.
        //

        //
        // Fill in any code to put the device in a low-power state here.
        //
        break;

    case WdfPowerDevicePrepareForHibernation:

        //
        // Fill in any code to save hardware state here.  Do not put in any
        // code to shut the device off.  If this device cannot support being
        // in the paging path (or being a parent or grandparent of a paging
        // path device) then this whole case can be deleted.
        //

        break;

    case WdfPowerDeviceD3Final:
    default:

        //
        // Reset the hardware, as we're shutting down for the last time.
        //
        PLxShutdown(devExt);
        break;
    }

    return STATUS_SUCCESS;
}
예제 #8
0
NTSTATUS
PLxEvtDeviceAdd(
    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 the driver should register all the
    PNP, power and Io callbacks, register interfaces and allocate other
    software resources required by the device. The driver can query
    any interfaces or get the config space information from the bus driver
    but cannot access hardware registers or initialize the device.

Arguments:

Return Value:

--*/
{
	KdPrint(("Entry PLxEvtDeviceAdd Routine"));
    NTSTATUS                   status = STATUS_SUCCESS;
    WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
    WDF_OBJECT_ATTRIBUTES       attributes;
    WDFDEVICE                   device;
    PDEVICE_EXTENSION           devExt = NULL;

    UNREFERENCED_PARAMETER( Driver );

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,  "--> PLxEvtDeviceAdd");

    PAGED_CODE();

    WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);

    //
    // Zero out the PnpPowerCallbacks structure.
    //
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);

    //
    // Set Callbacks for any of the functions we are interested in.
    // If no callback is set, Framework will take the default action
    // by itself.
    //
    pnpPowerCallbacks.EvtDevicePrepareHardware = PLxEvtDevicePrepareHardware;
    pnpPowerCallbacks.EvtDeviceReleaseHardware = PLxEvtDeviceReleaseHardware;

    //
    // These two callbacks set up and tear down hardware state that must be
    // done every time the device moves in and out of the D0-working state.
    //
    pnpPowerCallbacks.EvtDeviceD0Entry         = PLxEvtDeviceD0Entry;
    pnpPowerCallbacks.EvtDeviceD0Exit          = PLxEvtDeviceD0Exit;

    //
    // Register the PnP Callbacks..
    //
    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);

    //
    // Initialize Fdo Attributes.
    //
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_EXTENSION);
    //
    // By opting for SynchronizationScopeDevice, we tell the framework to
    // synchronize callbacks events of all the objects directly associated
    // with the device. In this driver, we will associate queues and
    // and DpcForIsr. By doing that we don't have to worrry about synchronizing
    // access to device-context by Io Events and DpcForIsr because they would
    // not concurrently ever. Framework will serialize them by using an
    // internal device-lock.
    //
    attributes.SynchronizationScope = WdfSynchronizationScopeDevice;

    //
    // Create the device
    //
    status = WdfDeviceCreate( &DeviceInit, &attributes, &device );

    if (!NT_SUCCESS(status)) {
        //
        // Device Initialization failed.
        //
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                    "DeviceCreate failed %!STATUS!", status);
        return status;
    }

    //
    // Get the DeviceExtension and initialize it. PLxGetDeviceContext is an inline function
    // defined by WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in the
    // private header file. This function will do the type checking and return
    // the device context. If you pass a wrong object a wrong object handle
    // it will return NULL and assert if run under framework verifier mode.
    //
    devExt = PLxGetDeviceContext(device);

    devExt->Device = device;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                "     AddDevice PDO (0x%p) FDO (0x%p), DevExt (0x%p)",
                WdfDeviceWdmGetPhysicalDevice(device),
                WdfDeviceWdmGetDeviceObject(device), devExt);

    //
    // Tell the Framework that this device will need an interface
    //
    // NOTE: See the note in Public.h concerning this GUID value.
    //
    status = WdfDeviceCreateDeviceInterface( device,
                                             (LPGUID) &GUID_PLX_INTERFACE,
                                             NULL );

    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                    "<-- DeviceCreateDeviceInterface "
                    "failed %!STATUS!", status);
        return status;
    }

    //
    // Set the idle and wait-wake policy for this device.
    //
    status = PLxSetIdleAndWakeSettings(devExt);

    if (!NT_SUCCESS (status)) {
        //
        // NOTE: The attempt to set the Idle and Wake options
        //       is a best-effort try. Failure is probably due to
        //       the non-driver environmentals, such as the system,
        //       bus or OS indicating that Wake is not supported for
        //       this case.
        //       All that being said, it probably not desirable to
        //       return the failure code as it would cause the
        //       AddDevice to fail and Idle and Wake are probably not
        //       "must-have" options.
        //
        //       You must decide for your case whether Idle/Wake are
        //       "must-have" options...but my guess is probably not.
        //
#if 1
        status = STATUS_SUCCESS;
#else
        return status;
#endif
    }

    //
    // Initalize the Device Extension.
    //
    status = PLxInitializeDeviceExtension(devExt);

    if (!NT_SUCCESS(status)) {
        return status;
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                "<-- PLxEvtDeviceAdd %!STATUS!", status);

	KdPrint(("Leave PLxEvtDeviceAdd Routine"));
    return status;
}