VOID SerialSaveDeviceState(IN PSERIAL_DEVICE_EXTENSION PDevExt) /*++ Routine Description: This routine saves the device state of the UART Arguments: PDevExt - Pointer to the device extension for the devobj to save the state for. Return Value: VOID --*/ { PSERIAL_DEVICE_STATE pDevState = &PDevExt->DeviceState; PAGED_CODE(); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "Entering SerialSaveDeviceState\n"); // // Read necessary registers direct // pDevState->IER = READ_INTERRUPT_ENABLE(PDevExt, PDevExt->Controller); pDevState->MCR = READ_MODEM_CONTROL(PDevExt, PDevExt->Controller); pDevState->LCR = READ_LINE_CONTROL(PDevExt, PDevExt->Controller); SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "Leaving SerialSaveDeviceState\n"); }
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; }
/*++ Routine Description: This is the dispatch routine for write. It validates the parameters for the write request and if all is ok then it places the request on the work queue. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Pointer to the WDFREQUEST for the current request Length - Length of the IO operation The default property of the queue is to not dispatch zero lenght read & write requests to the driver and complete is with status success. So we will never get a zero length request. Return Value: --*/ _Use_decl_annotations_ VOID SerialEvtIoWrite( WDFQUEUE Queue, WDFREQUEST Request, size_t Length ) { PSERIAL_DEVICE_EXTENSION extension; NTSTATUS status; WDFDEVICE hDevice; WDF_REQUEST_PARAMETERS params; PREQUEST_CONTEXT reqContext; size_t bufLen; UCHAR tempIER=0x00; hDevice = WdfIoQueueGetDevice(Queue); extension = SerialGetDeviceExtension(hDevice); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "++SerialEvtIoWrite(%p, 0x%I64x)\r\n", Request, Length); if (SerialCompleteIfError(extension, Request) != STATUS_SUCCESS) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--SerialEvtIoWrite 1 %Xh\r\n", (ULONG)STATUS_CANCELLED); return; } WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters(Request, ¶ms); // Initialize the scratch area of the request. reqContext = SerialGetRequestContext(Request); reqContext->MajorFunction = params.Type; reqContext->Length = (ULONG) Length; status = WdfRequestRetrieveInputBuffer (Request, Length, &reqContext->SystemBuffer, &bufLen); if (!NT_SUCCESS (status)) { SerialCompleteRequest(Request , status, 0); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--SerialEvtIoWrite 2 %Xh\r\n", status); return; } SerialStartOrQueue(extension, Request, extension->WriteQueue, &extension->CurrentWriteRequest, SerialStartWrite); // enable mini Uart Tx interrupt TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, "SerialEvtIoWrite() - enable Tx interrupt\r\n"); tempIER=READ_INTERRUPT_ENABLE(extension, extension->Controller); WRITE_INTERRUPT_ENABLE(extension, extension->Controller, (tempIER | SERIAL_IER_THR)); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, "--SerialEvtIoWrite()=%X\r\n", status); return; }