示例#1
0
//
// Internal Function: UartCtlSetFifoControl
//
VOID
UartCtlSetFifoControl(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    UCHAR fifoControlRegister = 0;
    UCHAR fifoControlRegisterSaved = 0;
    PUCHAR pFifoControl = NULL;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveInputBuffer(Request, 
                    sizeof(UCHAR), 
                    (PVOID*)(& pFifoControl), 
                    NULL);

    if (!NT_SUCCESS(status))
    {
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "Failed to retrieve input buffer for WDFREQUEST %p - "
            "%!STATUS!",
            Request,
            status);
    }

    if (NT_SUCCESS(status))
    {
        // This value is not verified.  This is as specified in the documentation.
        fifoControlRegister = *pFifoControl;

        // Save the value of the FCR to be written, with the reset bits unset.
        fifoControlRegisterSaved = fifoControlRegister & 
                        (~(SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET));

        // Acquires the interrupt lock and writes the FCR.
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
        WRITE_FIFO_CONTROL(pDevExt, pDevExt->Controller, fifoControlRegister);
        pDevExt->FifoControl = fifoControlRegisterSaved;
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}
示例#2
0
文件: IsrDpc.c 项目: PaulJing/Sora
/*++

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:

--*/
VOID PCIEEvtInterruptDpc(IN WDFINTERRUPT Interrupt,IN WDFDEVICE Device)
{
    NTSTATUS            Status;
    PDEVICE_EXTENSION   pDevExt;
    BOOLEAN             fTxInterrupt = FALSE;
    BOOLEAN             fRxInterrupt = FALSE;
    
    UNREFERENCED_PARAMETER(Device);

    pDevExt  = PCIEGetDeviceContext(WdfInterruptGetDevice(Interrupt));
    
    do
    {
        //
        // Acquire this device's InterruptSpinLock.
        //
        WdfInterruptAcquireLock( Interrupt );

        WdfInterruptReleaseLock( Interrupt );

      
    }while (FALSE);
    
    return;
}
示例#3
0
//
// Internal Function: UartCtlClearStats
//
VOID
UartCtlClearStats(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);
  
    WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
    RtlZeroMemory(&pDevExt->PerfStats, sizeof(SERIALPERF_STATS));
    WdfInterruptReleaseLock(pDevExt->WdfInterrupt);

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}
示例#4
0
BOOLEAN 
DeviceInterrupt_EvtAttachDetachInterruptIsr (
    _In_ WDFINTERRUPT Interrupt,
    _In_ ULONG MessageID
    )
/*++

Routine Description:

    'EvtInterruptIsr' handler for the attach/detach interrupt object.
    http://msdn.microsoft.com/en-us/library/windows/hardware/ff541735(v=vs.85).aspx

Arguments:

    Interrupt - Associated interrupt object.

    MessageID - Message IDs for MSI

Return Value:

    BOOLEAN

--*/
{
    PCONTROLLER_CONTEXT ControllerContext;

    UNREFERENCED_PARAMETER(MessageID);

    TraceEntry();

    ControllerContext = DeviceGetControllerContext(WdfInterruptGetDevice(Interrupt));
    
    WdfInterruptAcquireLock(ControllerContext->DeviceInterrupt);

    //
    // This is an ActiveBoth interrupt used for attach/detach.  State is determined
    // by counting interrupts.  Previous state was attached, so this is a detach.
    //
    if (!ControllerContext->Attached) {
        ControllerContext->Attached = TRUE;
        ControllerContext->GotAttachOrDetach = TRUE;

        (void) WdfInterruptQueueDpcForIsr(Interrupt);
    } else  {
        ControllerContext->Attached = FALSE;
        ControllerContext->GotAttachOrDetach = TRUE;
        (void) WdfInterruptQueueDpcForIsr(Interrupt);
    }
        
    WdfInterruptReleaseLock(ControllerContext->DeviceInterrupt);
        
    TraceExit();
    return TRUE;
}
示例#5
0
//
// Internal Function: UartCtlGetModemControl
//
VOID
UartCtlGetModemControl(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    PULONG pBuffer;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveOutputBuffer(Request, 
                    sizeof(ULONG), 
                    (PVOID*)(&pBuffer), 
                    NULL);

    if (!NT_SUCCESS(status))
    {
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "Failed to retrieve output buffer for WDFREQUEST %p - "
            "%!STATUS!",
            Request,
            status);
    }

    if (NT_SUCCESS(status))
    {
        // Acquires the interrupt lock and reads the modem control register.
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
        *pBuffer = READ_MODEM_CONTROL(pDevExt, pDevExt->Controller);
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);

        WdfRequestSetInformation(Request, sizeof(ULONG));
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}
示例#6
0
//
// Internal Function: UartCtlGetBaudRate
//
VOID
UartCtlGetBaudRate(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    PSERIAL_BAUD_RATE pBaudRate = NULL;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveOutputBuffer(Request, 
                    sizeof(SERIAL_BAUD_RATE), 
                    (PVOID*)(& pBaudRate), 
                    NULL);

    if (!NT_SUCCESS(status))
    {
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "Failed to retrieve output buffer for WDFREQUEST %p - "
            "%!STATUS!",
            Request,
            status);
    }

    if (NT_SUCCESS(status))
    {
        // Acquires the interrupt lock and retrieves the current baud rate.
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
        pBaudRate->BaudRate = pDevExt->CurrentBaud;
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);

        WdfRequestSetInformation(Request, sizeof(SERIAL_BAUD_RATE));
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}
示例#7
0
//
// Internal Function: UartCtlGetStats
//
VOID
UartCtlGetStats(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    PSERIALPERF_STATS pStats = NULL;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveOutputBuffer(Request, 
                    sizeof(SERIALPERF_STATS), 
                    (PVOID*)(& pStats), 
                    NULL);

    if (!NT_SUCCESS(status))
    {
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "Failed to retrieve output buffer for WDFREQUEST %p - "
            "%!STATUS!",
            Request,
            status);
    }

    if (NT_SUCCESS(status))
    {
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
        *pStats = pDevExt->PerfStats;
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);

        WdfRequestSetInformation(Request, sizeof(SERIALPERF_STATS));
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}
示例#8
0
//
// Internal Function: UartCtlClrRts
//
VOID
UartCtlClrRts(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    UCHAR regModemControl;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    if (((pDevExt->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
        SERIAL_RTS_HANDSHAKE) ||
        ((pDevExt->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
        SERIAL_TRANSMIT_TOGGLE))
    {
        status = STATUS_INVALID_PARAMETER;
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "RTS cannot be cleared when automatic RTS flow control or "
            "transmit toggling is used - %!STATUS!",
            status);
    }

    if (NT_SUCCESS(status))
    {
        // Acquires the interrupt lock and sets the MCR.
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
        regModemControl = READ_MODEM_CONTROL(pDevExt, pDevExt->Controller);
        regModemControl &= ~SERIAL_MCR_RTS;
        WRITE_MODEM_CONTROL(pDevExt, pDevExt->Controller, regModemControl);
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}
示例#9
0
//
// Internal Function: UartCtlSetDtr
//
VOID
UartCtlSetDtr(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    UCHAR regModemControl;
    NTSTATUS status = STATUS_SUCCESS;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    if ((pDevExt->HandFlow.ControlHandShake & SERIAL_DTR_MASK) ==
        SERIAL_DTR_HANDSHAKE)
    {
        status = STATUS_INVALID_PARAMETER;
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "DTR cannot be set when automatic DTR flow control is used - "
            "%!STATUS!",
            status);
    }

    if (NT_SUCCESS(status))
    {
        // Acquires the interrupt lock and sets the MCR.
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
        regModemControl = READ_MODEM_CONTROL(pDevExt, pDevExt->Controller);
        regModemControl |= SERIAL_MCR_DTR;
        WRITE_MODEM_CONTROL(pDevExt, pDevExt->Controller, regModemControl);
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}
示例#10
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;
}
示例#11
0
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
VOID
HSACEvtIoDeviceControl(
    __in WDFQUEUE      Queue,
    __in WDFREQUEST    Request,
    __in size_t         OutputBufferLength,
    __in size_t         InputBufferLength,
    __in ULONG         IoControlCode
    )
/*++
Routine Description:

    This event is called when the framework receives IRP_MJ_DEVICE_CONTROL
    requests from the system.

Arguments:

    Queue - Handle to the framework queue object that is associated
            with the I/O request.
    Request - Handle to a framework request object.

    OutputBufferLength - length of the request output buffer,
                        if an output buffer is available.
    InputBufferLength - length of the request input buffer,
                        if an input buffer is available.

    IoControlCode - the driver-defined or system-defined I/O control code
                    (IOCTL) that is associated with the request.
Return Value:

    VOID

--*/
{
    PDEVICE_EXTENSION		devExt;
    size_t                  length = 0;
    NTSTATUS                status = STATUS_SUCCESS;
    PVOID                   pInputBuffer = NULL;
	PVOID					pOutputBuffer = NULL;

	ULONG a1 = 0,a2 = 0;
	ULONG readIndex = 0, readNum = 0;

    UNREFERENCED_PARAMETER( InputBufferLength  );
    UNREFERENCED_PARAMETER( OutputBufferLength  );

    //
    // Get the device extension.
    //
    devExt = HSACGetDeviceContext(WdfIoQueueGetDevice( Queue ));
#if (DBG != 0)
	TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
		"HSACEvtIoDeviceControl InputBufferLength: 0x%x, OutputBufferLength: 0x%x\n", 
		InputBufferLength, OutputBufferLength);
#endif
    //
    // Handle this request specific code.
    //
    switch (IoControlCode) {
	case IOCTL_GET_REGISTER:
		{
#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
				"IOCTL_GET_REGISTER-->require length: 0x%x\n", sizeof(ULONG));
#endif

			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			status = WdfRequestRetrieveOutputBuffer(Request, 0, &pOutputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			readIndex = *(PULONG)pInputBuffer;
			readNum = *((PULONG)pInputBuffer + 1);
#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"readIndex: %d, readNum: %d\n", readIndex, readNum);
#endif
			if (readNum == 0)
			{
				length = 0;
				break;
			}
			//if (readNum > 1)
			//{
				if (readIndex + readNum > (sizeof(HSAC_REGS)/sizeof(unsigned int) ))
				{
					readNum = (sizeof(HSAC_REGS)/sizeof(unsigned int) ) - readIndex;
				}
				WdfInterruptAcquireLock( devExt->Interrupt );
				READ_REGISTER_BUFFER_ULONG(((PULONG) devExt->Regs) + readIndex, (PULONG)pOutputBuffer, readNum);
				WdfInterruptReleaseLock( devExt->Interrupt );
			//}
			//else
			//{
			//	*(PULONG)pOutputBuffer = READ_REGISTER_ULONG( ((PULONG) devExt->Regs) + readIndex );
			//}
			
			length = readNum;
			break;
		}
	case IOCTL_GET_SINGLE_REGISTER:
		{
#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
				"IOCTL_GET_REGISTER-->require length: 0x%x\n", sizeof(ULONG));
#endif

			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			status = WdfRequestRetrieveOutputBuffer(Request, 0, &pOutputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			readIndex = *(PULONG)pInputBuffer;
#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"readIndex: %d\n", readIndex);
#endif
			WdfInterruptAcquireLock( devExt->Interrupt );
			*(PULONG)pOutputBuffer = READ_REGISTER_ULONG( ((PULONG) devExt->Regs) + readIndex );
			WdfInterruptReleaseLock( devExt->Interrupt );

			length = sizeof(ULONG);
			break;
		}
	case IOCTL_SET_REGISTER:
		{
			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}
			WdfInterruptAcquireLock( devExt->Interrupt );
			WRITE_REGISTER_ULONG( ((PULONG) devExt->Regs) + (*(PULONG)pInputBuffer), *((PULONG)pInputBuffer + 1) );
			WdfInterruptReleaseLock( devExt->Interrupt );

//			//a1 = *(PULONG)pInputBuffer;
//			//a2 = *((PULONG)pInputBuffer + 1);
//
//#if (DBG != 0)
//			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
//				"IOCTL_SET_REGISTER-->offset:0x%x, value:0x%x\n", a1, a2);
//#endif
//
//			//a2 = READ_REGISTER_ULONG( ((PULONG) devExt->Regs) + (*(PULONG)pInputBuffer) );
//
//#if (DBG != 0)
//			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
//				"IOCTL_SET_REGISTER-->offset:0x%x, value:0x%x\n", a1, a2);
//#endif

			length = 0;
			break;
		}
	case IOCTL_GET_SRAM:
		{
#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
				"IOCTL_GET_SRAM-->require length: 0x%x\n", sizeof(ULONG));
#endif

			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			status = WdfRequestRetrieveOutputBuffer(Request, 0, &pOutputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			readIndex = *(PULONG)pInputBuffer;
			readNum = *((PULONG)pInputBuffer + 1);

			if (readNum == 0)
			{
				length = 0;
				break;
			}
			//if (readNum > 1)
			//{
			if (readIndex + readNum > (devExt->SRAMLength/sizeof(ULONG) ))
			{
				readNum = (devExt->SRAMLength/sizeof(ULONG) ) - readIndex;
			}

#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"readIndex: %d, readNum: %d\n", readIndex, readNum);
#endif

			WdfInterruptAcquireLock( devExt->Interrupt );
			READ_REGISTER_BUFFER_ULONG(((PULONG) devExt->SRAMBase) + readIndex, (PULONG)pOutputBuffer, readNum);
			WdfInterruptReleaseLock( devExt->Interrupt );
			//}
			//else
			//{
			//	*(PULONG)pOutputBuffer = READ_REGISTER_ULONG( ((PULONG) devExt->Regs) + readIndex );
			//}

			length = readNum;
			break;
		}
	case IOCTL_SET_SRAM:
		{
			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			readIndex = *(PULONG)pInputBuffer;
			readNum = *((PULONG)pInputBuffer + 1);

			if (readNum == 0)
			{
				length = 0;
				break;
			}
			//if (readNum > 1)
			//{
			if (readIndex + readNum > (devExt->SRAMLength/sizeof(ULONG) ))
			{
				readNum = (devExt->SRAMLength/sizeof(ULONG) ) - readIndex;
			}

#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"readIndex: %d, readNum: %d\n", readIndex, readNum);
#endif

			WdfInterruptAcquireLock( devExt->Interrupt );
			WRITE_REGISTER_BUFFER_ULONG( ((PULONG) devExt->SRAMBase) + readIndex, (PULONG)pInputBuffer + 2, readNum);
			WdfInterruptReleaseLock( devExt->Interrupt );
			//			//a1 = *(PULONG)pInputBuffer;
			//			//a2 = *((PULONG)pInputBuffer + 1);
			//
			//#if (DBG != 0)
			//			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
			//				"IOCTL_SET_REGISTER-->offset:0x%x, value:0x%x\n", a1, a2);
			//#endif
			//
			//			//a2 = READ_REGISTER_ULONG( ((PULONG) devExt->Regs) + (*(PULONG)pInputBuffer) );
			//
			//#if (DBG != 0)
			//			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
			//				"IOCTL_SET_REGISTER-->offset:0x%x, value:0x%x\n", a1, a2);
			//#endif

			length = readNum;
			break;
		}
	case IOCTL_MAP_DMA_BUF_ADDR:
		{
			ULONG_PTR address = 0;

			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}
			status = WdfRequestRetrieveOutputBuffer(Request, 0, &pOutputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			if (devExt->MapFlag == 1)
			{
				HSACUnmapUserAddress(devExt);
				devExt->MapFlag = 0;
			}
			HSACMapUserAddress( devExt );
			devExt->MapFlag = 1;

#if (CACHE_MODE == MULTI_DISCRETE_CACHE)
			if (*(PULONG)pInputBuffer == 0)
			{
				length = devExt->readCommonBufferNum * sizeof(PVOID);
				RtlCopyMemory(pOutputBuffer, devExt->pReadUserAddress, length);
			} 
			else if (*(PULONG)pInputBuffer == 1)
			{
				length = devExt->writeCommonBufferNum * sizeof(PVOID);
				RtlCopyMemory(pOutputBuffer, devExt->pWriteUserAddress, length);
			}
			else
			{
				status = STATUS_INVALID_DEVICE_REQUEST;
			}
#else
			if (*(PULONG)pInputBuffer == 0)
			{
				address = (ULONG_PTR)devExt->ReadUserAddress0;
			} 
			else if (*(PULONG)pInputBuffer == 1)
			{
				address = (ULONG_PTR)devExt->WriteUserAddress0;
			}
			else
			{
				status = STATUS_INVALID_DEVICE_REQUEST;
			}

#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"UserAddress: 0x%I64x", address);
#endif

			RtlCopyMemory(pOutputBuffer, &address, sizeof(PVOID));
#endif
			break;
		}
	case IOCTL_UNMAP_DMA_BUF_ADDR:
		{
			if (devExt->MapFlag == 1)
			{
				HSACUnmapUserAddress(devExt);
				devExt->MapFlag = 0;
			}
			break;
		}
	case IOCTL_SET_DMA_PROFILE:
		{
			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			devExt->dmaProfile = (WDF_DMA_PROFILE)(*(PULONG)pInputBuffer);

#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"dmaProfile: %d\n", devExt->dmaProfile);
#endif
			length = 0;
			break;
		}
	case IOCTL_DIRECT_DMA_READ:
		{
//			ULONG dma1Ctl = 0;
//			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
//			devExt->ReadSize = *(PULONG)pInputBuffer;
//
//#if (DBG != 0)
//			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
//				"devExt->ReadSize: %d\n", devExt->ReadSize);
//#endif
//
//			WdfInterruptAcquireLock( devExt->Interrupt );
//
//			WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA1_ADDR32,
//				devExt->ReadCommonBufferBaseLA.LowPart);
//			WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA1_ADDR64,
//				devExt->ReadCommonBufferBaseLA.HighPart );
//
//			WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA1_SIZE, devExt->ReadSize);
//			devExt->ReadSize = 0;
//
//			dma1Ctl = DMA_CTRL_START;
//			//WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA1_CTRL, dma1Ctl);
//
//			WdfInterruptReleaseLock( devExt->Interrupt );
			break;
		}
	case IOCTL_DIRECT_DMA_WRITE:
		{
			//ULONG dma0Ctl = 0;
			//status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			//devExt->WriteSize = *(PULONG)pInputBuffer;

			//WdfInterruptAcquireLock( devExt->Interrupt );

			//WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA0_ADDR32,
			//	devExt->WriteCommonBufferBaseLA.LowPart );
			//WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA0_ADDR64,
			//	devExt->WriteCommonBufferBaseLA.HighPart );

			//WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA0_SIZE, devExt->WriteSize);

			//dma0Ctl = DMA_CTRL_START;
			//WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA0_CTRL, dma0Ctl);

			//WdfInterruptReleaseLock( devExt->Interrupt );
			break;
		}
	case IOCTL_RESET: // code == 0x801
		{
			status = WdfRequestRetrieveOutputBuffer(Request, 0, &pOutputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
								"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
#endif
				break;
			}
			//*(PULONG) buffer = 0x0004000A;

			//status = STATUS_SUCCESS;
			length = sizeof(ULONG);
			break;
		}

	default:
		status = STATUS_INVALID_DEVICE_REQUEST;
		break;
    }

    WdfRequestCompleteWithInformation(Request, status, length);
}
示例#12
0
VOID 
DeviceInterrupt_EvtInterruptDpc (
    _In_ WDFINTERRUPT Interrupt,
    _In_ WDFOBJECT AssociatedObject
    )
/*++

Routine Description:

    'EvtInterruptDpc' handler for the device interrupt object.
    http://msdn.microsoft.com/en-us/library/windows/hardware/ff541721(v=vs.85).aspx

Arguments:

    Interrupt - Associated interrupt object.

    AssociatedObject - FDO Object

--*/
{
    WDFDEVICE WdfDevice;
    PDEVICE_INTERRUPT_CONTEXT InterruptContext;
    PCONTROLLER_CONTEXT ControllerContext;
    BOOLEAN Attached;
    BOOLEAN GotAttachOrDetach;
    CONTROLLER_EVENT ControllerEvent;

    UNREFERENCED_PARAMETER(Interrupt);

    TraceEntry();

    WdfDevice = (WDFDEVICE) AssociatedObject;
    ControllerContext = DeviceGetControllerContext(WdfDevice);

    WdfSpinLockAcquire(ControllerContext->DpcLock);

    WdfInterruptAcquireLock(ControllerContext->DeviceInterrupt);
    Attached = ControllerContext->Attached;
    GotAttachOrDetach = ControllerContext->GotAttachOrDetach;
    ControllerContext->GotAttachOrDetach = FALSE;
    WdfInterruptReleaseLock(ControllerContext->DeviceInterrupt);

    //
    // Handle attach/detach events
    //
    if (GotAttachOrDetach) {
        if (Attached && ControllerContext->WasAttached) {
            //
            // We must have gotten at least one detach. Need to reset the state.
            //        
            ControllerContext->RemoteWakeupRequested = FALSE;
            ControllerContext->Suspended = FALSE;
            UfxDeviceNotifyDetach(ControllerContext->UfxDevice);
        }

        if (Attached) {
            ControllerContext->RemoteWakeupRequested = FALSE;
            ControllerContext->Suspended = FALSE;
            UfxDeviceNotifyAttach(ControllerContext->UfxDevice);
        }
    }

    ControllerContext->WasAttached = Attached;

    InterruptContext = DeviceInterruptGetContext(ControllerContext->DeviceInterrupt);

    //
    // #### TODO: Insert code to read and dispatch events from the controller ####
    // 

    // The sample will assume an endpoint event of EndpointEventTransferComplete
    ControllerEvent.Type = EventTypeEndpoint;
    ControllerEvent.u.EndpointEvent = EndpointEventTransferComplete;
    
    //
    // Handle events from the controller
    //
    switch (ControllerEvent.Type) {
    case EventTypeDevice:
        HandleDeviceEvent(WdfDevice,  ControllerEvent.u.DeviceEvent);
        break;

    case EventTypeEndpoint:
        HandleEndpointEvent(WdfDevice, ControllerEvent.u.EndpointEvent);
        break;
    }

    WdfSpinLockRelease(ControllerContext->DpcLock);

    TraceExit();
}
示例#13
0
//
// Internal Function: UartCtlSetBaudRate
//
VOID
UartCtlSetBaudRate(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    PSERIAL_BAUD_RATE pBaudRate = NULL;
    USHORT DivisorLatchRegs = 0;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveInputBuffer(Request, 
                    sizeof(SERIAL_BAUD_RATE), 
                    (PVOID*)(& pBaudRate), 
                    NULL);

    if (!NT_SUCCESS(status))
    {
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "Failed to retrieve input buffer for WDFREQUEST %p - "
            "%!STATUS!",
            Request,
            status);
    }

    if (NT_SUCCESS(status))
    {
        status = UartRegConvertAndValidateBaud(
            pBaudRate->BaudRate, 
            &DivisorLatchRegs);

        if (!NT_SUCCESS(status))
        {
            TraceMessage(
                TRACE_LEVEL_ERROR,
                TRACE_FLAG_CONTROL,
                "Failed to convert and validate baudrate %lu - "
                "%!STATUS!",
                pBaudRate->BaudRate,
                status);
        }
    }

    if (NT_SUCCESS(status))
    {        
        // Acquires the interrupt lock and writes the Divisor Latch.
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);

        pDevExt->CurrentBaud = pBaudRate->BaudRate;
        WRITE_DIVISOR_LATCH(pDevExt, pDevExt->Controller, DivisorLatchRegs);

        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);
    
    FuncExit(TRACE_FLAG_CONTROL);
}
示例#14
0
//
// Internal Function: UartCtlGetLineControl
//
VOID
UartCtlGetLineControl(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    UCHAR lineControlRegister = 0;
    PSERIAL_LINE_CONTROL pLineControl = NULL;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveOutputBuffer(Request, 
                    sizeof(SERIAL_LINE_CONTROL), 
                    (PVOID*)(& pLineControl), 
                    NULL);

    if (!NT_SUCCESS(status))
    {
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "Failed to retrieve output buffer for WDFREQUEST %p - "
            "%!STATUS!",
            Request,
            status);
    }

    if (NT_SUCCESS(status))
    {
        // Acquires the interrupt lock and reads the LCR.
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);
        lineControlRegister = READ_LINE_CONTROL(pDevExt, pDevExt->Controller);
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);   

        status = UartRegLCRToStruct(lineControlRegister, pLineControl);

        if (!NT_SUCCESS(status))
        {
            TraceMessage(
                TRACE_LEVEL_ERROR,
                TRACE_FLAG_CONTROL,
                "Failed to calculate SERIAL_LINE_CONTROL from LCR %c  - "
                "%!STATUS!",
                lineControlRegister,
                status);
        }
    }

    if (NT_SUCCESS(status))
    {
        WdfRequestSetInformation(Request, sizeof(SERIAL_LINE_CONTROL));
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}
示例#15
0
//
// Internal Function: UartCtlSetLineControl
//
VOID
UartCtlSetLineControl(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    UCHAR lineControlRegister = 0;
    PSERIAL_LINE_CONTROL pLineControl = NULL;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveInputBuffer(Request, 
                    sizeof(SERIAL_LINE_CONTROL), 
                    (PVOID*)(& pLineControl), 
                    NULL);

    if (!NT_SUCCESS(status))
    {
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "Failed to retrieve input buffer for WDFREQUEST %p - "
            "%!STATUS!",
            Request,
            status);
    }

    if (NT_SUCCESS(status))
    {
        status = UartRegStructToLCR(pLineControl, &lineControlRegister);

        if (!NT_SUCCESS(status))
        {
            TraceMessage(
                TRACE_LEVEL_ERROR,
                TRACE_FLAG_CONTROL,
                "Failed to calculate LCR from SERIAL_LINE_CONTROL %p  - "
                "%!STATUS!",
                pLineControl,
                status);
        }
    }

    if (NT_SUCCESS(status))
    {
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);

        // Set line control, save break setting
        lineControlRegister = lineControlRegister | 
            (READ_LINE_CONTROL(pDevExt, pDevExt->Controller) & SERIAL_LCR_BREAK);
        WRITE_LINE_CONTROL(pDevExt, pDevExt->Controller, lineControlRegister);

        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}
示例#16
0
//
// Internal Function: UartCtlSetHandflow
//
VOID
UartCtlSetHandflow(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    PSERIAL_HANDFLOW pHandFlow = NULL;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveInputBuffer(Request, 
                    sizeof(SERIAL_HANDFLOW), 
                    (PVOID*)(& pHandFlow), 
                    NULL);

    if (!NT_SUCCESS(status))
    {
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "Failed to retrieve input buffer for WDFREQUEST %p - "
            "%!STATUS!",
            Request,
            status);
    }

    if (NT_SUCCESS(status))
    {
        //
        // Make sure there are no invalid bits set in
        // the control and handshake
        //

        if ((pHandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) ||
            (pHandFlow->FlowReplace & SERIAL_FLOW_INVALID))
        {
            status = STATUS_INVALID_PARAMETER;
            TraceMessage(
                TRACE_LEVEL_ERROR,
                TRACE_FLAG_CONTROL,
                "Invalid bit in SERIAL_HANDFLOW %p - "
                "%!STATUS!",
                pHandFlow,
                status);
        }
    }

    if (NT_SUCCESS(status))
    {
        //
        // Software flow control and in-band signaling 
        // have not been implemented in this sample.
        //

        if ((pHandFlow->ControlHandShake & SERIAL_DSR_SENSITIVITY) ||
            (pHandFlow->ControlHandShake & SERIAL_ERROR_ABORT) ||
            (pHandFlow->ControlHandShake & SERIAL_DCD_HANDSHAKE) ||
            (pHandFlow->FlowReplace & SERIAL_AUTO_TRANSMIT) ||
            (pHandFlow->FlowReplace & SERIAL_AUTO_RECEIVE) ||
            (pHandFlow->FlowReplace & SERIAL_ERROR_CHAR) ||
            (pHandFlow->FlowReplace & SERIAL_NULL_STRIPPING) ||
            (pHandFlow->FlowReplace & SERIAL_BREAK_CHAR) ||
            (pHandFlow->FlowReplace & SERIAL_XOFF_CONTINUE) ||
            ((pHandFlow->FlowReplace & SERIAL_RTS_MASK) == 
                SERIAL_TRANSMIT_TOGGLE))
        {
            status = STATUS_NOT_IMPLEMENTED;
            TraceMessage(
                TRACE_LEVEL_WARNING,
                TRACE_FLAG_CONTROL,
                "Specified SERIAL_HANDFLOW %p has not been implemented - "
                "%!STATUS!",
                pHandFlow,
                status);
        }
    }

    if (NT_SUCCESS(status))
    {
        //
        // Make sure the DTR mode is valid
        //

        if ((pHandFlow->ControlHandShake & SERIAL_DTR_MASK) ==
            SERIAL_DTR_MASK)
        {
            status = STATUS_INVALID_PARAMETER;
            TraceMessage(
                TRACE_LEVEL_ERROR,
                TRACE_FLAG_CONTROL,
                "Cannot set handflow with invalid DTR mode %lu - "
                "%!STATUS!",
                pHandFlow->ControlHandShake,
                status);
        }
    }

    if (NT_SUCCESS(status))
    {
        WdfSpinLockAcquire(pDevExt->ReceiveBufferSpinLock);
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);

        BOOLEAN newFlowControl;
        BOOLEAN prevFlowControl = UsingRXFlowControl(pDevExt);

        pDevExt->HandFlow = *pHandFlow;

        newFlowControl = UsingRXFlowControl(pDevExt);
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);

        // Empty software FIFO before changing flow control
        if (newFlowControl != prevFlowControl)
        {
            if (!newFlowControl)
            {
                if (pDevExt->FIFOBufferBytes > 0)
                {
                    // If switching from flow control to no flow control,
                    // read bytes from the software FIFO to ring buffer before
                    // asserting flow control lines.

                    // Shouldn't have a cached buffer and bytes in the software FIFO
                    NT_ASSERT(!HasCachedReceiveBuffer(pDevExt));
                
                    // Using a new status variable so the IOCTL doesn't fail if
                    // the driver can't read the software FIFO to SerCx ring buffer, which
                    // may happen after the file has closed.
                    NTSTATUS fifoStatus = SerCxRetrieveReceiveBuffer(Device, SERIAL_SOFTWARE_FIFO_SIZE, &pDevExt->PIOReceiveBuffer);

                    // Read bytes from software FIFO and return the buffer
                    if (NT_SUCCESS(fifoStatus))
                    {
                        // Read the software FIFO bytes into the ring buffer.
                        // This function won't return the buffer.
                        UartReceiveBytesFromSoftwareFIFO(pDevExt);

                        // The software FIFO has been read out and should be empty now.
                        NT_ASSERT(pDevExt->FIFOBufferBytes == 0);

                        fifoStatus = SerCxProgressReceive(
                            Device, 
                            pDevExt->ReceiveProgress, 
                            SerCxStatusSuccess);

                        if (!NT_SUCCESS(fifoStatus))
                        {
                            TraceMessage(
                                TRACE_LEVEL_ERROR,
                                TRACE_FLAG_CONTROL,
                                "%!FUNC! Failed to return buffer - %!STATUS!",
                                fifoStatus);
                            NT_ASSERTMSG("SerCxProgressReceive shouldn't fail", NT_SUCCESS(fifoStatus));
                        }

                        pDevExt->PerfStats.ReceivedCount += pDevExt->ReceiveProgress;
                        pDevExt->ReceiveProgress = 0;
                        pDevExt->PIOReceiveBuffer.Buffer = NULL;
                    }
                    else
                    {
                        TraceMessage(
                            TRACE_LEVEL_WARNING,
                            TRACE_FLAG_CONTROL,
                            "SerCxRetrieveReceiveBuffer failed - %!STATUS!",
                            fifoStatus);
                    }
                }
            }
            else
            {
                // If switching from no flow control to flow control,
                // the software FIFO should already be empty.
                NT_ASSERT(pDevExt->FIFOBufferBytes == 0);
            }
        }

        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);

        // If software FIFO empty, re-assert flow control
        // Automatic flow control MUST be re-enabled here if it's being used.
        if (pDevExt->FIFOBufferBytes == 0)
        {
            UartFlowReceiveAvailable(Device);
        }        
        
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
        WdfSpinLockRelease(pDevExt->ReceiveBufferSpinLock);
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}