VOID UartEvaluateLineStatus( _In_ WDFDEVICE Device, _Out_ PBOOLEAN CanReceive, _Out_ PBOOLEAN CanTransmit, _Out_ PBOOLEAN HasErrors ) { UCHAR regLineStatus = 0; UCHAR oldErrorBits = 0; PUART_DEVICE_EXTENSION pDevExt = NULL; FuncEntry(TRACE_FLAG_REGUTIL); pDevExt = UartGetDeviceExtension(Device); regLineStatus = READ_LINE_STATUS(pDevExt, pDevExt->Controller); if (pDevExt->LineStatus != regLineStatus) { // LSR changed. // If there is an error indicated, binary OR it with the previous error. oldErrorBits = pDevExt->LineStatus & SERIAL_LSR_ERROR; pDevExt->LineStatus = regLineStatus | oldErrorBits; } pDevExt->HoldingEmpty = ((pDevExt->LineStatus & SERIAL_LSR_THRE) != 0); *CanReceive = ((pDevExt->LineStatus & SERIAL_LSR_DR) != 0); *CanTransmit = pDevExt->HoldingEmpty && UartFlowCanTransmit(Device); *HasErrors = ((pDevExt->LineStatus & SERIAL_LSR_ERROR) != 0); FuncExit(TRACE_FLAG_REGUTIL); }
// // 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); }
// // 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); }
// // Internal Function: UartCtlSetChars // VOID UartCtlSetChars( _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_CHARS pSpecialChars = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveInputBuffer(Request, sizeof(SERIAL_CHARS), (PVOID*)(& pSpecialChars), 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)) { // // Software flow control and in-band signaling // have not been implemented in this sample. Characters // are not checked for valid range or values. // pDevExt->SpecialChars.EofChar = pSpecialChars->EofChar; pDevExt->SpecialChars.ErrorChar = pSpecialChars->ErrorChar; pDevExt->SpecialChars.BreakChar = pSpecialChars->BreakChar; pDevExt->SpecialChars.EventChar = pSpecialChars->EventChar; pDevExt->SpecialChars.XonChar = pSpecialChars->XonChar; pDevExt->SpecialChars.XoffChar = pSpecialChars->XoffChar; } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // Internal Function: UartCtlGetDtrrts // VOID UartCtlGetDtrrts( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PULONG pBuffer; UCHAR regModemControl; 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)) { regModemControl = READ_MODEM_CONTROL(pDevExt, pDevExt->Controller); regModemControl &= SERIAL_DTR_STATE | SERIAL_RTS_STATE; *pBuffer = regModemControl; WdfRequestSetInformation(Request, sizeof(ULONG)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // 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); }
USHORT UartWaitableEvents( _In_ WDFDEVICE Device ) { PUART_DEVICE_EXTENSION pDevExt = NULL; USHORT someEvent = 0; pDevExt = UartGetDeviceExtension(Device); FuncEntry(TRACE_FLAG_REGUTIL); // Note that each if statement here is consistent in that it compares // LineStatus to SERIAL_LSR_* and compares ModemStatus to SERIAL_MSR_*. if ((pDevExt->LineStatus & SERIAL_LSR_DR) != 0) someEvent = someEvent | SERIAL_EV_RXCHAR; // SERIAL_EV_RXFLAG is not handled in this function. if ((pDevExt->LineStatus & SERIAL_LSR_TEMT) != 0) someEvent = someEvent | SERIAL_EV_TXEMPTY; if ((pDevExt->LineStatus & SERIAL_LSR_BI) != 0) someEvent = someEvent | SERIAL_EV_BREAK; if ((pDevExt->LineStatus & SERIAL_LSR_ERROR) != 0) someEvent = someEvent | SERIAL_EV_ERR; if ((pDevExt->ModemStatus & SERIAL_MSR_DCTS) != 0) someEvent = someEvent | SERIAL_EV_CTS; if ((pDevExt->ModemStatus & SERIAL_MSR_DDSR) != 0) someEvent = someEvent | SERIAL_EV_DSR; if ((pDevExt->ModemStatus & SERIAL_MSR_TERI) != 0) someEvent = someEvent | SERIAL_EV_RLSD; if ((pDevExt->ModemStatus & SERIAL_MSR_RI) != 0) someEvent = someEvent | SERIAL_EV_RING; // SERIAL_EV_PERR is not possible. // SERIAL_EV_RX80FULL is not handled in this function. // SERIAL_EV_EVENT1 is not possible. // SERIAL_EV_EVENT2 is not possible. // Clear the modem status events pDevExt->ModemStatus &= ~(SERIAL_MSR_EVENTS); FuncExit(TRACE_FLAG_REGUTIL); return someEvent; }
// // 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); }
// // 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); }
// // 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); }
// // Internal Function: UartCtlGetHandflow // VOID UartCtlGetHandflow( _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 = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIAL_HANDFLOW), (PVOID*)(& pHandFlow), 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)) { *pHandFlow = pDevExt->HandFlow; WdfRequestSetInformation(Request, sizeof(SERIAL_HANDFLOW)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // 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); }
BOOLEAN UartRecordInterrupt( _In_ WDFDEVICE Device ) { BOOLEAN servicedAnInterrupt = FALSE; UCHAR regInterruptId = 0; UCHAR regLineStatus = 0; UCHAR regModemStatus = 0; UCHAR oldErrorBits = 0; PUART_DEVICE_EXTENSION pDevExt; FuncEntry(TRACE_FLAG_REGUTIL); pDevExt = UartGetDeviceExtension(Device); regInterruptId = READ_INTERRUPT_ID_REG(pDevExt, pDevExt->Controller); // If an interrupt actually happened, record the registers... // While the NO_INTERRUPT_PENDING bit is NOT set, while ((regInterruptId & SERIAL_IIR_NO_INTERRUPT_PENDING) == 0) { BYTE ier = 0x00; servicedAnInterrupt = TRUE; pDevExt->InterruptIdentifier = regInterruptId; // TODO: Fix // IIR indicates a single interrupt ordered by priority. // This switch statement ensures that interrupts are not // confused with one another. switch (regInterruptId & SERIAL_IIR_MASK) { case SERIAL_IIR_RLS: regLineStatus = READ_LINE_STATUS(pDevExt, pDevExt->Controller); oldErrorBits = pDevExt->LineStatus & SERIAL_LSR_ERROR; pDevExt->LineStatus = regLineStatus | oldErrorBits; break; case SERIAL_IIR_RDA: case SERIAL_IIR_CTI: // Issue flow control UartFlowReceiveFull(Device); // Clear the RDA interrupt for now. We will // read the data in the DPC. ier = READ_INTERRUPT_ENABLE(pDevExt, pDevExt->Controller); ier &= (~SERIAL_IER_RDA); WRITE_INTERRUPT_ENABLE(pDevExt, pDevExt->Controller, ier); break; case SERIAL_IIR_THR: pDevExt->HoldingEmpty = TRUE; // Clear the THR interrupt for now ier = READ_INTERRUPT_ENABLE(pDevExt, pDevExt->Controller); ier &= ~(SERIAL_IER_THR); WRITE_INTERRUPT_ENABLE(pDevExt, pDevExt->Controller, ier); break; case SERIAL_IIR_MS: regModemStatus = READ_MODEM_STATUS(pDevExt, pDevExt->Controller); pDevExt->ModemStatus = (pDevExt->ModemStatus & SERIAL_MSR_EVENTS) | regModemStatus; break; default: break; } regInterruptId = READ_INTERRUPT_ID_REG(pDevExt, pDevExt->Controller); } FuncExit(TRACE_FLAG_REGUTIL); return servicedAnInterrupt; }
// // 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); }
// // Internal Function: UartCtlGetCommstatus // VOID UartCtlGetCommstatus( _In_ WDFDEVICE Device, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength ) { NTSTATUS status; PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device); PSERIAL_STATUS pStat = NULL; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); FuncEntry(TRACE_FLAG_CONTROL); status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SERIAL_STATUS), (PVOID*)(& pStat), 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)) { WdfSpinLockAcquire(pDevExt->DpcSpinLock); pStat->Errors = pDevExt->ErrorWord; pDevExt->ErrorWord = 0; WdfSpinLockRelease(pDevExt->DpcSpinLock); // // Software flow control and in-band signaling // have not been implemented in this samples. Parameters // such as HoldReasons, AmountInIn/OutQueue, and // WaitForImmediate have not been populated. // WdfRequestSetInformation(Request, sizeof(SERIAL_STATUS)); } TraceMessage(TRACE_LEVEL_INFORMATION, TRACE_FLAG_CONTROL, "WdfRequestComplete( %!HANDLE! => %!STATUS! )", Request, status); WdfRequestComplete(Request, status); FuncExit(TRACE_FLAG_CONTROL); }
// // 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); }
// // 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); }
// // 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); }