/////////////////////////////////////////////////////////////////////////////// // SmplInterruptEvtDisable /////////////////////////////////////////////////////////////////////////////// NTSTATUS SmplInterruptEvtDisable( __in WDFINTERRUPT Interrupt, __in WDFDEVICE AssociatedDevice ) { PDEVICE_CONTEXT pDeviceContext = DeviceGetContext(WdfInterruptGetDevice(Interrupt)); DbgPrintEx(DPFLTR_IHVDRIVER_ID, 1234,"SmplInterruptEvtDisable\n"); WRITE_INTERRUPT_ENABLE( pDeviceContext->pPortAddress, 0); return STATUS_SUCCESS; } // end SmplInterruptEvtDisable
/////////////////////////////////////////////////////////////////////////////// // Does : Initializes the device. // Parameters : port - Port of a 8250 // baudrate - Baudrate to init 8250 to // dataBits - Number of data bits (5..8) // stopBits - Number of stop bits (1..2) // parity - 0 == NONE, 1 == ODD, 2 == EVEN // Returns : Status of the operation. // Postcondition : Ready to start interrupt processing when returning // STATUS_SUCCESS. /////////////////////////////////////////////////////////////////////////////// NTSTATUS Hw8250Init(PUCHAR port, ULONG baudRate, ULONG dataBits, ULONG stopBits, ULONG parity) { NTSTATUS result = STATUS_SUCCESS; ULONG divisor; UCHAR dataFormat; // disable all interrupts WRITE_INTERRUPT_ENABLE(port, 0x00); // set up baudrate divisor = Hw8550InternalGetDivisor(baudRate); WRITE_LINE_CONTROL(port, LCR_DLAB); WRITE_DIVISOR_LATCH(port, divisor); // set up data bits (defaults to 8 data bits) switch(dataBits) { case 5: dataFormat = LCR_DATA_5; break; case 6: dataFormat = LCR_DATA_6; break; case 7: dataFormat = LCR_DATA_7; break; case 8: default: dataFormat = LCR_DATA_8; break; } // set up stop bits (defaults to 1 stop bit) if(stopBits == 2) { dataFormat |= LCR_STOP_2; } else { dataFormat |= LCR_STOP_1; } // set up parity (defaults to none) switch(parity) { case 4: dataFormat |= LCR_PARITY_SPACE; break; case 3: dataFormat |= LCR_PARITY_MARK; break; case 2: dataFormat |= LCR_PARITY_EVEN; break; case 1: dataFormat |= LCR_PARITY_ODD; break; case 0: default: dataFormat |= LCR_PARITY_NONE; break; } WRITE_LINE_CONTROL(port, dataFormat); WRITE_MODEM_CONTROL(port, MCR_GPO1 | MCR_RTS | MCR_DTR); return result; } // end Hw8250Init
NTSTATUS SerialEvtDeviceD0Entry( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE PreviousState ) /*++ Routine Description: EvtDeviceD0Entry event callback must perform any operations that are necessary before the specified device is used. It will be called every time the hardware needs to be (re-)initialized. This includes after IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE, IRP_MN_SET_POWER-D0. 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. This function runs at PASSIVE_LEVEL, even though it is not paged. A driver can optionally make this function pageable if DO_POWER_PAGABLE is set. Even if DO_POWER_PAGABLE isn't set, this function still runs at PASSIVE_LEVEL. In this case, though, the function absolutely must not do anything that will cause a page fault. Arguments: Device - Handle to a framework device object. PreviousState - Device power state which the device was in most recently. If the device is being newly started, this will be PowerDeviceUnspecified. Return Value: NTSTATUS --*/ { PSERIAL_DEVICE_EXTENSION deviceExtension; PSERIAL_DEVICE_STATE pDevState; SHORT divisor; SERIAL_IOCTL_SYNC S; SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "-->SerialEvtDeviceD0Entry - coming from %s\n", DbgDevicePowerString(PreviousState)); deviceExtension = SerialGetDeviceExtension (Device); pDevState = &deviceExtension->DeviceState; // // Restore the state of the UART. First, that involves disabling // interrupts both via OUT2 and IER. // WRITE_MODEM_CONTROL(deviceExtension, deviceExtension->Controller, 0); DISABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller); // // Set the baud rate // SerialGetDivisorFromBaud(deviceExtension->ClockRate, deviceExtension->CurrentBaud, &divisor); S.Extension = deviceExtension; S.Data = (PVOID) (ULONG_PTR) divisor; #pragma prefast(suppress: __WARNING_INFERRED_IRQ_TOO_LOW, "PFD warning that we are calling interrupt synchronize routine directly. Suppress it because interrupt is disabled above.") SerialSetBaud(deviceExtension->WdfInterrupt, &S); // // Reset / Re-enable the FIFO's // if (deviceExtension->FifoPresent) { WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)0); READ_RECEIVE_BUFFER(deviceExtension, deviceExtension->Controller); WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)(SERIAL_FCR_ENABLE | deviceExtension->RxFifoTrigger | SERIAL_FCR_RCVR_RESET | SERIAL_FCR_TXMT_RESET)); } else { WRITE_FIFO_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)0); } // // Restore a couple more registers // WRITE_INTERRUPT_ENABLE(deviceExtension, deviceExtension->Controller, pDevState->IER); WRITE_LINE_CONTROL(deviceExtension, deviceExtension->Controller, pDevState->LCR); // // Clear out any stale interrupts // READ_INTERRUPT_ID_REG(deviceExtension, deviceExtension->Controller); READ_LINE_STATUS(deviceExtension, deviceExtension->Controller); READ_MODEM_STATUS(deviceExtension, deviceExtension->Controller); // // TODO: move this code to EvtInterruptEnable. // if (deviceExtension->DeviceState.Reopen == TRUE) { SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "Reopening device\n"); SetDeviceIsOpened(deviceExtension, TRUE, FALSE); // // This enables interrupts on the device! // WRITE_MODEM_CONTROL(deviceExtension, deviceExtension->Controller, (UCHAR)(pDevState->MCR | SERIAL_MCR_OUT2)); // // Refire the state machine // DISABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller); ENABLE_ALL_INTERRUPTS(deviceExtension, deviceExtension->Controller); } SerialDbgPrintEx(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--SerialEvtDeviceD0Entry\n"); return STATUS_SUCCESS; }
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; }