ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cport.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.