void dc_dbg_init() { #ifdef DBG_COM u32 divisor; u8 lcr; /* set baud rate and data format (8N1) */ /* turn on DTR and RTS */ WRITE_PORT_UCHAR(pv(SER_MCR(COM_BASE)), SR_MCR_DTR | SR_MCR_RTS); /* set DLAB */ lcr = READ_PORT_UCHAR(pv(SER_LCR(COM_BASE))) | SR_LCR_DLAB; WRITE_PORT_UCHAR(pv(SER_LCR(COM_BASE)), lcr); /* set baud rate */ divisor = 115200 / DEFAULT_BAUD_RATE; WRITE_PORT_UCHAR(pv(SER_DLL(COM_BASE)), divisor & 0xff); WRITE_PORT_UCHAR(pv(SER_DLM(COM_BASE)), (divisor >> 8) & 0xff); /* reset DLAB and set 8N1 format */ WRITE_PORT_UCHAR(pv(SER_LCR(COM_BASE)), SR_LCR_CS8 | SR_LCR_ST1 | SR_LCR_PNO); /* read junk out of the RBR */ READ_PORT_UCHAR(pv(SER_RBR(COM_BASE))); #endif /* DBG_COM */ #ifdef DBG_HAL_DISPLAY InbvAcquireDisplayOwnership(); InbvEnableDisplayString(TRUE); #endif /* DBG_HAL_DISPLAY */ }
NTSTATUS NTAPI SerialSetBaudRate( IN PSERIAL_DEVICE_EXTENSION DeviceExtension, IN ULONG NewBaudRate) { ULONG BaudRate; USHORT divisor; PUCHAR ComPortBase = ULongToPtr(DeviceExtension->BaseAddress); NTSTATUS Status = STATUS_SUCCESS; if (NewBaudRate == 0) return STATUS_INVALID_PARAMETER; divisor = (USHORT)(BAUD_CLOCK / (CLOCKS_PER_BIT * NewBaudRate)); BaudRate = BAUD_CLOCK / (CLOCKS_PER_BIT * divisor); Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (NT_SUCCESS(Status)) { UCHAR Lcr; TRACE_(SERIAL, "SerialSetBaudRate(COM%lu, %lu Bauds)\n", DeviceExtension->ComPort, BaudRate); /* Set Bit 7 of LCR to expose baud registers */ Lcr = READ_PORT_UCHAR(SER_LCR(ComPortBase)); WRITE_PORT_UCHAR(SER_LCR(ComPortBase), Lcr | SR_LCR_DLAB); /* Write the baud rate */ WRITE_PORT_UCHAR(SER_DLL(ComPortBase), divisor & 0xff); WRITE_PORT_UCHAR(SER_DLM(ComPortBase), divisor >> 8); /* Switch back to normal registers */ WRITE_PORT_UCHAR(SER_LCR(ComPortBase), Lcr); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); } if (NT_SUCCESS(Status)) DeviceExtension->BaudRate = BaudRate; return Status; }
NTSTATUS NTAPI SerialSetLineControl( IN PSERIAL_DEVICE_EXTENSION DeviceExtension, IN PSERIAL_LINE_CONTROL NewSettings) { PUCHAR ComPortBase; UCHAR Lcr = 0; NTSTATUS Status; ASSERT(DeviceExtension); ASSERT(NewSettings); TRACE_(SERIAL, "SerialSetLineControl(COM%lu, Settings { %lu %lu %lu })\n", DeviceExtension->ComPort, NewSettings->StopBits, NewSettings->Parity, NewSettings->WordLength); /* Verify parameters */ switch (NewSettings->WordLength) { case 5: Lcr |= SR_LCR_CS5; break; case 6: Lcr |= SR_LCR_CS6; break; case 7: Lcr |= SR_LCR_CS7; break; case 8: Lcr |= SR_LCR_CS8; break; default: return STATUS_INVALID_PARAMETER; } if (NewSettings->WordLength < 5 || NewSettings->WordLength > 8) return STATUS_INVALID_PARAMETER; switch (NewSettings->Parity) { case NO_PARITY: Lcr |= SR_LCR_PNO; break; case ODD_PARITY: Lcr |= SR_LCR_POD; break; case EVEN_PARITY: Lcr |= SR_LCR_PEV; break; case MARK_PARITY: Lcr |= SR_LCR_PMK; break; case SPACE_PARITY: Lcr |= SR_LCR_PSP; break; default: return STATUS_INVALID_PARAMETER; } switch (NewSettings->StopBits) { case STOP_BIT_1: Lcr |= SR_LCR_ST1; break; case STOP_BITS_1_5: if (NewSettings->WordLength != 5) return STATUS_INVALID_PARAMETER; Lcr |= SR_LCR_ST2; break; case STOP_BITS_2: if (NewSettings->WordLength < 6 || NewSettings->WordLength > 8) return STATUS_INVALID_PARAMETER; Lcr |= SR_LCR_ST2; break; default: return STATUS_INVALID_PARAMETER; } /* Update current parameters */ ComPortBase = ULongToPtr(DeviceExtension->BaseAddress); Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (!NT_SUCCESS(Status)) return Status; WRITE_PORT_UCHAR(SER_LCR(ComPortBase), Lcr); /* Read junk out of RBR */ READ_PORT_UCHAR(SER_RBR(ComPortBase)); IoReleaseRemoveLock(&DeviceExtension->RemoveLock, ULongToPtr(DeviceExtension->ComPort)); if (NT_SUCCESS(Status)) DeviceExtension->SerialLineControl = *NewSettings; return Status; }
UART_TYPE SerialDetectUartType( IN PUCHAR BaseAddress) { UCHAR Lcr, TestLcr; UCHAR OldScr, Scr5A, ScrA5; BOOLEAN FifoEnabled; UCHAR NewFifoStatus; Lcr = READ_PORT_UCHAR(SER_LCR(BaseAddress)); WRITE_PORT_UCHAR(SER_LCR(BaseAddress), Lcr ^ 0xFF); TestLcr = READ_PORT_UCHAR(SER_LCR(BaseAddress)) ^ 0xFF; WRITE_PORT_UCHAR(SER_LCR(BaseAddress), Lcr); /* Accessing the LCR must work for a usable serial port */ if (TestLcr != Lcr) return UartUnknown; /* Ensure that all following accesses are done as required */ READ_PORT_UCHAR(SER_RBR(BaseAddress)); READ_PORT_UCHAR(SER_IER(BaseAddress)); READ_PORT_UCHAR(SER_IIR(BaseAddress)); READ_PORT_UCHAR(SER_LCR(BaseAddress)); READ_PORT_UCHAR(SER_MCR(BaseAddress)); READ_PORT_UCHAR(SER_LSR(BaseAddress)); READ_PORT_UCHAR(SER_MSR(BaseAddress)); READ_PORT_UCHAR(SER_SCR(BaseAddress)); /* Test scratch pad */ OldScr = READ_PORT_UCHAR(SER_SCR(BaseAddress)); WRITE_PORT_UCHAR(SER_SCR(BaseAddress), 0x5A); Scr5A = READ_PORT_UCHAR(SER_SCR(BaseAddress)); WRITE_PORT_UCHAR(SER_SCR(BaseAddress), 0xA5); ScrA5 = READ_PORT_UCHAR(SER_SCR(BaseAddress)); WRITE_PORT_UCHAR(SER_SCR(BaseAddress), OldScr); /* When non-functional, we have a 8250 */ if (Scr5A != 0x5A || ScrA5 != 0xA5) return Uart8250; /* Test FIFO type */ FifoEnabled = (READ_PORT_UCHAR(SER_IIR(BaseAddress)) & 0x80) != 0; WRITE_PORT_UCHAR(SER_FCR(BaseAddress), SR_FCR_ENABLE_FIFO); NewFifoStatus = READ_PORT_UCHAR(SER_IIR(BaseAddress)) & 0xC0; if (!FifoEnabled) WRITE_PORT_UCHAR(SER_FCR(BaseAddress), 0); switch (NewFifoStatus) { case 0x00: return Uart16450; case 0x40: case 0x80: /* Not sure about this but the documentation says that 0x40 * indicates an unusable FIFO but my tests only worked * with 0x80 */ return Uart16550; } /* FIFO is only functional for 16550A+ */ return Uart16550A; }