Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencport.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS ComPort Library 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: lib/reactos/cportlib/cport.c 00005 * PURPOSE: Provides a serial port library for KDCOM, INIT, and FREELDR 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 */ 00008 00009 /* NOTE: This library follows the precise serial port intialization steps documented 00010 * by Microsoft in some of their Server hardware guidance. Because they've clearly 00011 * documented their serial algorithms, we use the same ones to stay "compliant". 00012 * Do not change this code to "improve" it. It's done this way on purpose, at least on x86. 00013 * -- sir_richard 00014 */ 00015 00016 /* NOTE: This code is used by Headless Support (Ntoskrnl.exe and Osloader.exe) and 00017 Kdcom.dll in Windows. It may be that WinDBG depends on some of these quirks. 00018 */ 00019 00020 /* NOTE: The original code supports Modem Control. We currently do not */ 00021 00022 /* FIXMEs: 00023 - Make this serial-port specific (NS16550 vs other serial port types) 00024 - Get x64 KDCOM, KDBG, FREELDR, and other current code to use this 00025 */ 00026 00027 /* INCLUDES *******************************************************************/ 00028 00029 #include <cportlib/cportlib.h> 00030 #include <drivers/serial/ns16550.h> 00031 #include <intrin.h> 00032 #include <ioaccess.h> 00033 #include <debug.h> 00034 00035 /* GLOBALS ********************************************************************/ 00036 00037 UCHAR RingIndicator; 00038 00039 /* FUNCTIONS ******************************************************************/ 00040 00041 VOID 00042 NTAPI 00043 CpInitialize(IN PCPPORT Port, 00044 IN PUCHAR Address, 00045 IN ULONG Rate) 00046 { 00047 /* Reset port data */ 00048 Port->Address = Address; 00049 Port->Baud = 0; 00050 00051 /* Set the baud rate */ 00052 CpSetBaud(Port, Rate); 00053 00054 /* Enable on DTR and RTS */ 00055 WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, 00056 SERIAL_MCR_DTR | SERIAL_MCR_RTS); 00057 00058 /* Disable interrupts */ 00059 WRITE_PORT_UCHAR(Address + INTERRUPT_ENABLE_REGISTER, 0); 00060 } 00061 00062 VOID 00063 NTAPI 00064 CpEnableFifo(IN PUCHAR Address, 00065 IN BOOLEAN Enable) 00066 { 00067 /* Set FIFO */ 00068 WRITE_PORT_UCHAR(Address + FIFO_CONTROL_REGISTER, Enable ? SERIAL_FCR_ENABLE : 0); 00069 } 00070 00071 BOOLEAN 00072 NTAPI 00073 CpDoesPortExist(IN PUCHAR Address) 00074 { 00075 UCHAR Old; 00076 /* 00077 * See "Building Hardware and Firmware to Complement Microsoft Windows Headless Operation" 00078 * Out-of-Band Management Port Device Requirements: 00079 * The device must act as a 16550 or 16450 UART. 00080 * Windows Server 2003 will test this device using the following process. 00081 * 1. Save off the current modem status register. 00082 * 2. Place the UART into diagnostic mode (The UART is placed into loopback mode 00083 * by writing SERIAL_MCR_LOOP to the modem control register). 00084 * 3. The modem status register is read and the high bits are checked. This means 00085 * SERIAL_MSR_CTS, SERIAL_MSR_DSR, SERIAL_MSR_RI and SERIAL_MSR_DCD should 00086 * all be clear. 00087 * 4. Place the UART in diagnostic mode and turn on OUTPUT (Loopback Mode and 00088 * OUTPUT are both turned on by writing (SERIAL_MCR_LOOP | SERIAL_MCR_OUT1) 00089 * to the modem control register). 00090 * 5. The modem status register is read and the ring indicator is checked. 00091 * This means SERIAL_MSR_RI should be set. 00092 * 6. Restore original modem status register. 00093 */ 00094 Old = READ_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER); 00095 WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, SERIAL_MCR_LOOP); 00096 WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, SERIAL_MCR_LOOP); 00097 if (!(READ_PORT_UCHAR(Address + MODEM_STATUS_REGISTER) & 00098 (SERIAL_MSR_CTS | SERIAL_MSR_DSR | SERIAL_MSR_RI | SERIAL_MSR_DCD))) 00099 { 00100 WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, 00101 (SERIAL_MCR_OUT1 | SERIAL_MCR_LOOP)); 00102 if (READ_PORT_UCHAR(Address + MODEM_STATUS_REGISTER) & SERIAL_MSR_RI) 00103 { 00104 WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, Old); 00105 return TRUE; 00106 } 00107 } 00108 WRITE_PORT_UCHAR(Address + MODEM_CONTROL_REGISTER, Old); 00109 return FALSE; 00110 } 00111 00112 UCHAR 00113 NTAPI 00114 CpReadLsr(IN PCPPORT Port, 00115 IN UCHAR ExpectedValue) 00116 { 00117 UCHAR Lsr, Msr; 00118 00119 /* Read the LSR and check if the expected value is present */ 00120 Lsr = READ_PORT_UCHAR(Port->Address + LINE_STATUS_REGISTER); 00121 if (!(Lsr & ExpectedValue)) 00122 { 00123 /* Check the MSR for ring indicator toggle */ 00124 Msr = READ_PORT_UCHAR(Port->Address + MODEM_STATUS_REGISTER); 00125 00126 /* If the indicator reaches 3, we've seen this on/off twice */ 00127 RingIndicator |= (Msr & SERIAL_MSR_RI) ? 1 : 2; 00128 if (RingIndicator == 3) Port->Flags |= CPPORT_FLAG_MODEM_CONTROL; 00129 } 00130 00131 return Lsr; 00132 } 00133 00134 VOID 00135 NTAPI 00136 CpSetBaud(IN PCPPORT Port, 00137 IN ULONG Rate) 00138 { 00139 UCHAR Lcr; 00140 USHORT Mode; 00141 00142 /* Add DLAB */ 00143 Lcr = READ_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER); 00144 WRITE_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER, Lcr | SERIAL_LCR_DLAB); 00145 00146 /* Set baud rate */ 00147 Mode = 115200 / Rate; 00148 WRITE_PORT_UCHAR(Port->Address + DIVISOR_LATCH_MSB, (UCHAR)((Mode >> 8) & 0xff)); 00149 WRITE_PORT_UCHAR(Port->Address + DIVISOR_LATCH_LSB, (UCHAR)(Mode & 0xff)); 00150 00151 /* Reset DLAB and set 8 data bits, 1 stop bit, no parity, no break */ 00152 WRITE_PORT_UCHAR(Port->Address + LINE_CONTROL_REGISTER, 00153 SERIAL_8_DATA | SERIAL_1_STOP | SERIAL_NONE_PARITY); 00154 00155 /* Save baud rate in port */ 00156 Port->Baud = Rate; 00157 } 00158 00159 USHORT 00160 NTAPI 00161 CpGetByte(IN PCPPORT Port, 00162 IN PUCHAR Byte, 00163 IN BOOLEAN Wait, 00164 IN BOOLEAN Poll) 00165 { 00166 UCHAR Lsr; 00167 ULONG i; 00168 00169 /* Handle early read-before-init */ 00170 if (!Port->Address) return CP_GET_NODATA; 00171 00172 /* If "wait" mode enabled, spin many times, otherwise attempt just once */ 00173 i = Wait ? 204800 : 1; 00174 while (i--) 00175 { 00176 /* Read LSR for data ready */ 00177 Lsr = CpReadLsr(Port, SERIAL_LSR_DR); 00178 if ((Lsr & SERIAL_LSR_DR) == SERIAL_LSR_DR) 00179 { 00180 /* If an error happened, clear the byte and fail */ 00181 if (Lsr & (SERIAL_LSR_FE | SERIAL_LSR_PE)) 00182 { 00183 *Byte = 0; 00184 return CP_GET_ERROR; 00185 } 00186 00187 /* If only polling was requested by caller, return now */ 00188 if (Poll) return CP_GET_SUCCESS; 00189 00190 /* Otherwise read the byte and return it */ 00191 *Byte = READ_PORT_UCHAR(Port->Address + RECEIVE_BUFFER_REGISTER); 00192 00193 /* Handle CD if port is in modem control mode */ 00194 if (Port->Flags & CPPORT_FLAG_MODEM_CONTROL) 00195 { 00196 /* Not implemented yet */ 00197 DPRINT1("CP: CPPORT_FLAG_MODEM_CONTROL unexpected\n"); 00198 } 00199 00200 /* Byte was read */ 00201 return CP_GET_SUCCESS; 00202 } 00203 } 00204 00205 /* Reset LSR, no data was found */ 00206 CpReadLsr(Port, 0); 00207 return CP_GET_NODATA; 00208 } 00209 00210 VOID 00211 NTAPI 00212 CpPutByte(IN PCPPORT Port, 00213 IN UCHAR Byte) 00214 { 00215 /* Check if port is in modem control to handle CD */ 00216 while (Port->Flags & CPPORT_FLAG_MODEM_CONTROL) 00217 { 00218 /* Not implemented yet */ 00219 DPRINT1("CP: CPPORT_FLAG_MODEM_CONTROL unexpected\n"); 00220 } 00221 00222 /* Wait for LSR to say we can go ahead */ 00223 while (!(CpReadLsr(Port, SERIAL_LSR_THRE) & SERIAL_LSR_THRE)); 00224 00225 /* Send the byte */ 00226 WRITE_PORT_UCHAR(Port->Address + RECEIVE_BUFFER_REGISTER, Byte); 00227 } Generated on Sun May 27 2012 04:35:57 for ReactOS by
1.7.6.1
|