summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halx86/i386/ixkdcom.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halx86/i386/ixkdcom.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/nthals/halx86/i386/ixkdcom.c')
-rw-r--r--private/ntos/nthals/halx86/i386/ixkdcom.c684
1 files changed, 684 insertions, 0 deletions
diff --git a/private/ntos/nthals/halx86/i386/ixkdcom.c b/private/ntos/nthals/halx86/i386/ixkdcom.c
new file mode 100644
index 000000000..644d3590b
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixkdcom.c
@@ -0,0 +1,684 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ixkdcom.c
+
+Abstract:
+
+ This module contains a very simply package to do com I/O on machines
+ with standard AT com-ports. It is C code derived from the debugger's
+ com code. Likely does not work on a PS/2. (Only rewrote the thing
+ into C so we wouldn't have to deal with random debugger macros.)
+
+ Procedures to init a com object, set and query baud rate, output
+ character, input character.
+
+Author:
+
+ Bryan M. Willman (bryanwi) 24-Sep-1990
+
+Revision History:
+
+ John Vert (jvert) 12-Jun-1991
+ Added ability to check for com-port's existence and hook onto the
+ highest com-port available.
+
+ John Vert (jvert) 19-Jul-1991
+ Moved into HAL
+
+--*/
+
+#include "halp.h"
+#include "ixkdcom.h"
+#define TIMEOUT_COUNT 1024 * 200
+
+UCHAR CpReadLsr (PCPPORT, UCHAR);
+
+extern BOOLEAN HalpOwnsDisplay;
+static UCHAR LastLsr, LastMsr;
+
+
+VOID
+CpInitialize (
+ PCPPORT Port,
+ PUCHAR Address,
+ ULONG Rate
+ )
+
+/*++
+
+ Routine Description:
+
+ Fill in the com port port object, set the initial baud rate,
+ turn on the hardware.
+
+ Arguments:
+
+ Port - address of port object
+
+ Address - port address of the com port
+ (CP_COM1_PORT, CP_COM2_PORT)
+
+ Rate - baud rate (CP_BD_150 ... CP_BD_19200)
+
+--*/
+
+{
+ PUCHAR hwport;
+ UCHAR mcr, ier;
+
+ Port->Address = Address;
+ Port->Baud = 0;
+
+ CpSetBaud(Port, Rate);
+
+ //
+ // Assert DTR, RTS.
+ //
+
+ hwport = Port->Address;
+ hwport += COM_MCR;
+
+ mcr = MC_DTRRTS;
+ WRITE_PORT_UCHAR(hwport, mcr);
+
+ hwport = Port->Address;
+ hwport += COM_IEN;
+
+ ier = 0;
+ WRITE_PORT_UCHAR(hwport, ier);
+
+}
+
+
+
+
+VOID
+CpSetBaud (
+ PCPPORT Port,
+ ULONG Rate
+ )
+
+/*++
+
+ Routine Description:
+
+ Set the baud rate for the port and record it in the port object.
+
+ Arguments:
+
+ Port - address of port object
+
+ Rate - baud rate (CP_BD_150 ... CP_BD_56000)
+
+--*/
+
+{
+ ULONG divisorlatch;
+ PUCHAR hwport;
+ UCHAR lcr;
+
+ //
+ // compute the divsor
+ //
+
+ divisorlatch = CLOCK_RATE / Rate;
+
+ //
+ // set the divisor latch access bit (DLAB) in the line control reg
+ //
+
+ hwport = Port->Address;
+ hwport += COM_LCR; // hwport = LCR register
+
+ lcr = READ_PORT_UCHAR(hwport);
+
+ lcr |= LC_DLAB;
+ WRITE_PORT_UCHAR(hwport, lcr);
+
+ //
+ // set the divisor latch value.
+ //
+
+ hwport = Port->Address;
+ hwport += COM_DLM; // divisor latch msb
+ WRITE_PORT_UCHAR(hwport, (UCHAR)((divisorlatch >> 8) & 0xff));
+
+ hwport--; // divisor latch lsb
+ WRITE_PORT_UCHAR(hwport, (UCHAR)(divisorlatch & 0xff));
+
+
+ //
+ // Set LCR to 3. (3 is a magic number in the original assembler)
+ //
+
+ hwport = Port->Address;
+ hwport += COM_LCR;
+ WRITE_PORT_UCHAR(hwport, 3);
+
+
+ //
+ // Remember the baud rate
+ //
+
+ Port->Baud = Rate;
+}
+
+
+
+USHORT
+CpQueryBaud (
+ PCPPORT Port
+ )
+
+/*++
+
+ Routine Description:
+
+ Return the last value baud rate was set to.
+
+ Arguments:
+
+ Port - address of cpport object which describes the hw port of interest.
+
+ Return Value:
+
+ Baud rate. 0 = none has been set.
+
+--*/
+
+{
+ return (USHORT) Port->Baud;
+}
+
+VOID
+CpSendModemString (
+ PCPPORT Port,
+ IN PUCHAR String
+ )
+/*++
+
+ Routine Description:
+
+ Sends a command string to the modem.
+ This is down in order to aid the modem in determining th
+ baud rate the local connect is at.
+
+ Arguments:
+
+ Port - Address of CPPORT
+ String - String to send to modem
+
+--*/
+{
+ static ULONG Delay;
+ TIME_FIELDS CurrentTime;
+ UCHAR i;
+ ULONG l;
+
+ if (Port->Flags & PORT_SENDINGSTRING)
+ return ;
+
+ Port->Flags |= PORT_SENDINGSTRING;
+ if (!Delay) {
+ // see how long 1 second is
+ HalQueryRealTimeClock (&CurrentTime);
+ l = CurrentTime.Second;
+ while (l == (ULONG) CurrentTime.Second) {
+ CpReadLsr(Port, 0);
+ HalQueryRealTimeClock (&CurrentTime);
+ Delay++;
+ }
+ Delay = Delay / 3;
+ }
+
+ l = Delay;
+ while (*String) {
+ HalQueryRealTimeClock (&CurrentTime);
+ i = CpReadLsr (Port, 0);
+ if (i & COM_OUTRDY) {
+ if ((--l) == 0) {
+ WRITE_PORT_UCHAR(Port->Address+COM_DAT, *String);
+ String++;
+ l = Delay;
+ }
+ }
+ if (i & COM_DATRDY)
+ READ_PORT_UCHAR(Port->Address + COM_DAT);
+ }
+ Port->Flags &= ~PORT_SENDINGSTRING;
+}
+
+UCHAR
+CpReadLsr (
+ PCPPORT Port,
+ UCHAR waiting
+ )
+
+/*++
+
+ Routine Description:
+
+ Read LSR byte from specified port. If HAL owns port & display
+ it will also cause a debug status to be kept up to date.
+
+ Handles entering & exiting modem control mode for debugger.
+
+ Arguments:
+
+ Port - Address of CPPORT
+
+ Returns:
+
+ Byte read from port
+
+--*/
+{
+ static UCHAR ringflag = 0;
+ static UCHAR diagout[3];
+ static ULONG diagmsg[3] = { 'TRP ', 'LVO ', 'MRF ' };
+ static UCHAR ModemString[] = "\n\rAT\n\r";
+ TIME_FIELDS CurrentTime;
+ UCHAR lsr, msr, i;
+ ULONG diagstr[12];
+
+ lsr = READ_PORT_UCHAR(Port->Address + COM_LSR);
+
+ if (lsr & COM_PE)
+ diagout[0] = 8; // Parity error
+
+ if (lsr & COM_OE)
+ diagout[1] = 8; // Overflow error
+
+ if (lsr & COM_FE)
+ diagout[2] = 8; // Framing error
+
+ if (lsr & waiting) {
+ LastLsr = ~COM_DATRDY | (lsr & COM_DATRDY);
+ return lsr;
+ }
+
+ msr = READ_PORT_UCHAR (Port->Address + COM_MSR);
+
+ if (Port->Flags & PORT_MODEMCONTROL) {
+ if (msr & SERIAL_MSR_DCD) {
+
+ //
+ // In modem control mode with carrier detect
+ // Reset carrier lost time
+ //
+
+ Port->Flags |= PORT_NOCDLTIME | PORT_MDM_CD;
+
+ } else {
+
+ //
+ // In modem control mode, but no carrier detect. After
+ // 60 seconds drop out of modem control mode
+ //
+
+ if (Port->Flags & PORT_NOCDLTIME) {
+ HalQueryRealTimeClock (&Port->CarrierLostTime);
+ Port->Flags &= ~PORT_NOCDLTIME;
+ ringflag = 0;
+ }
+
+ HalQueryRealTimeClock (&CurrentTime);
+ if (CurrentTime.Minute != Port->CarrierLostTime.Minute &&
+ CurrentTime.Second >= Port->CarrierLostTime.Second) {
+
+ //
+ // It's been at least 60 seconds - drop out of
+ // modem control mode until next RI
+ //
+
+ Port->Flags &= ~PORT_MODEMCONTROL;
+ CpSendModemString (Port, ModemString);
+ }
+
+ if (Port->Flags & PORT_MDM_CD) {
+
+ //
+ // We had a connection - if it's the connection has been
+ // down for a few seconds, then send a string to the modem
+ //
+
+ if (CurrentTime.Second < Port->CarrierLostTime.Second)
+ CurrentTime.Second += 60;
+
+ if (CurrentTime.Second > Port->CarrierLostTime.Second + 10) {
+ Port->Flags &= ~PORT_MDM_CD;
+ CpSendModemString (Port, ModemString);
+ }
+ }
+ }
+ }
+
+ if ((lsr == LastLsr && msr == LastMsr) || !(Port->Flags & PORT_SAVED))
+ return lsr;
+
+ ringflag |= (msr & SERIAL_MSR_RI) ? 1 : 2;
+ if (ringflag == 3) {
+
+ //
+ // The ring indicate line has toggled
+ // Use modem control from now on
+ //
+
+ ringflag = 0;
+ Port->Flags |= PORT_MODEMCONTROL | PORT_NOCDLTIME;
+ Port->Flags &= ~PORT_MDM_CD;
+
+ if (Port->Flags & PORT_DEFAULTRATE && Port->Baud != BD_9600) {
+
+ //
+ // Baud rate was never specified switch
+ // to 9600 baud as default (for modem usage).
+ //
+
+ HalDisplayString (MSG_DEBUG_9600);
+ CpSetBaud (Port, BD_9600);
+ //Port->Flags |= PORT_DISBAUD;
+ }
+ }
+
+ for (i=0; i < 3; i++) {
+ if (diagout[i]) {
+ diagout[i]--;
+ diagstr[10-i] = diagmsg[i];
+ } else {
+ diagstr[10-i] = ' ';
+ }
+ }
+
+ diagstr[7] = (LastLsr & COM_DATRDY) ? 'VCR ' : ' ';
+ diagstr[6] = (lsr & COM_OUTRDY) ? ' ' : 'DNS ';
+ diagstr[5] = (msr & 0x10) ? 'STC ' : ' ';
+ diagstr[4] = (msr & 0x20) ? 'RSD ' : ' ';
+ diagstr[3] = (msr & 0x40) ? ' IR ' : ' ';
+ diagstr[2] = (msr & 0x80) ? ' DC ' : ' ';
+ diagstr[1] = (Port->Flags & PORT_MODEMCONTROL) ? 'MDM ' : ' ';
+ diagstr[0] = ' ';
+#if 0
+ if (Port->Flags & PORT_DISBAUD) {
+ switch (Port->Baud) {
+ case BD_9600: diagstr[0] = ' 69 '; break;
+ case BD_14400: diagstr[0] = 'K41 '; break;
+ case BD_19200: diagstr[0] = 'K91 '; break;
+ case BD_56000: diagstr[0] = 'K65 '; break;
+ }
+ }
+#endif
+
+ HalpDisplayDebugStatus ((PUCHAR) diagstr, 11*4);
+ LastLsr = lsr;
+ LastMsr = msr;
+ return lsr;
+}
+
+
+
+
+VOID
+CpPutByte (
+ PCPPORT Port,
+ UCHAR Byte
+ )
+
+/*++
+
+ Routine Description:
+
+ Write a byte out to the specified com port.
+
+ Arguments:
+
+ Port - Address of CPPORT object
+
+ Byte - data to emit
+
+--*/
+
+{
+ UCHAR msr, lsr;
+
+ //
+ // If modem control, make sure DSR, CTS and CD are all set before
+ // sending any data.
+ //
+
+ while ((Port->Flags & PORT_MODEMCONTROL) &&
+ (msr = READ_PORT_UCHAR(Port->Address + COM_MSR) & MS_DSRCTSCD) != MS_DSRCTSCD) {
+
+ //
+ // If no CD, and there's a charactor ready, eat it
+ //
+
+ lsr = CpReadLsr (Port, 0);
+ if ((msr & MS_CD) == 0 && (lsr & COM_DATRDY) == COM_DATRDY) {
+ READ_PORT_UCHAR(Port->Address + COM_DAT);
+ }
+ }
+
+ //
+ // Wait for port to not be busy
+ //
+
+ while (!(CpReadLsr(Port, COM_OUTRDY) & COM_OUTRDY)) ;
+
+ //
+ // Send the byte
+ //
+
+ WRITE_PORT_UCHAR(Port->Address + COM_DAT, Byte);
+}
+
+USHORT
+CpGetByte (
+ PCPPORT Port,
+ PUCHAR Byte,
+ BOOLEAN WaitForByte
+ )
+
+/*++
+
+ Routine Description:
+
+ Fetch a byte and return it.
+
+ Arguments:
+
+ Port - address of port object that describes hw port
+
+ Byte - address of variable to hold the result
+
+ WaitForByte - flag indicates wait for byte or not.
+
+ Return Value:
+
+ CP_GET_SUCCESS if data returned.
+
+ CP_GET_NODATA if no data available, but no error.
+
+ CP_GET_ERROR if error (overrun, parity, etc.)
+
+--*/
+
+{
+ UCHAR lsr;
+ UCHAR value;
+ ULONG limitcount;
+
+ //
+ // Make sure DTR and CTS are set
+ //
+ // (What does CTS have to do with reading from a full duplex line???)
+
+
+ //
+ // Check to make sure the CPPORT we were passed has been initialized.
+ // (The only time it won't be initialized is when the kernel debugger
+ // is disabled, in which case we just return.)
+ //
+ if (Port->Address == NULL) {
+ return(CP_GET_NODATA);
+ }
+
+ limitcount = WaitForByte ? TIMEOUT_COUNT : 1;
+ while (limitcount != 0) {
+ limitcount--;
+
+ lsr = CpReadLsr(Port, COM_DATRDY);
+ if ((lsr & COM_DATRDY) == COM_DATRDY) {
+
+ //
+ // Check for errors
+ //
+ if (lsr & (COM_FE | COM_PE | COM_OE)) {
+ *Byte = 0;
+ return(CP_GET_ERROR);
+ }
+
+ //
+ // fetch the byte
+ //
+
+ value = READ_PORT_UCHAR(Port->Address + COM_DAT);
+
+ if (Port->Flags & PORT_MODEMCONTROL) {
+
+ //
+ // Using modem control. If no CD, then skip this byte.
+ //
+
+ if ((READ_PORT_UCHAR(Port->Address + COM_MSR) & MS_CD) == 0) {
+ continue;
+ }
+ }
+
+ *Byte = value & (UCHAR)0xff;
+ return CP_GET_SUCCESS;
+ }
+ }
+
+ LastLsr = 0;
+ CpReadLsr (Port, 0);
+ return CP_GET_NODATA;
+}
+
+
+
+BOOLEAN
+CpDoesPortExist(
+ IN PUCHAR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will attempt to place the port into its
+ diagnostic mode. If it does it will twiddle a bit in
+ the modem control register. If the port exists this
+ twiddling should show up in the modem status register.
+
+ NOTE: This routine must be called before the device is
+ enabled for interrupts, this includes setting the
+ output2 bit in the modem control register.
+
+ This is blatantly stolen from TonyE's code in ntos\dd\serial\serial.c.
+
+Arguments:
+
+ Address - address of hw port.
+
+Return Value:
+
+ TRUE - Port exists. Party on.
+
+ FALSE - Port doesn't exist. Don't use it.
+
+--*/
+
+{
+ UCHAR OldModemStatus;
+ UCHAR ModemStatus;
+ BOOLEAN ReturnValue = TRUE;
+
+ //
+ // Save the old value of the modem control register.
+ //
+
+ OldModemStatus = READ_PORT_UCHAR(Address+COM_MCR);
+
+ //
+ // Set the port into diagnostic mode.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+COM_MCR,
+ SERIAL_MCR_LOOP
+ );
+
+ //
+ // Bang on it again to make sure that all the lower bits
+ // are clear.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+COM_MCR,
+ SERIAL_MCR_LOOP
+ );
+
+ //
+ // Read the modem status register. The high for bits should
+ // be clear.
+ //
+
+ ModemStatus = READ_PORT_UCHAR(Address+COM_MSR);
+
+ if (ModemStatus & (SERIAL_MSR_CTS | SERIAL_MSR_DSR |
+ SERIAL_MSR_RI | SERIAL_MSR_DCD)) {
+
+ ReturnValue = FALSE;
+ goto AllDone;
+
+ }
+
+ //
+ // So far so good. Now turn on OUT1 in the modem control register
+ // and this should turn on ring indicator in the modem status register.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+COM_MCR,
+ (SERIAL_MCR_OUT1 | SERIAL_MCR_LOOP)
+ );
+
+ ModemStatus = READ_PORT_UCHAR(Address+COM_MSR);
+
+ if (!(ModemStatus & SERIAL_MSR_RI)) {
+
+ ReturnValue = FALSE;
+ goto AllDone;
+
+ }
+
+AllDone: ;
+
+ //
+ // Put the modem control back into a clean state.
+ //
+
+ WRITE_PORT_UCHAR(
+ Address+COM_MCR,
+ OldModemStatus
+ );
+
+ return ReturnValue;
+
+}
+