Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3254 lines
78 KiB

#include "insignia.h"
#include "host_def.h"
/*
* SoftPC Version 3.0
*
* Title : com.c
*
* Description : Asynchronous Adaptor I/O functions.
*
* Notes : Refer to the PC-XT Tech Ref Manual Section 1-185
* For a detailed description of the Asynchronous Adaptor Card.
*
*/
#ifdef SCCSID
static char SccsID[]="@(#)com.c 1.45 04/26/94 Copyright Insignia Solutions Ltd.";
#endif
#ifdef SEGMENTATION
/*
* The following #include specifies the code segment into which this
* module will by placed by the MPW C compiler on the Mac II running
* MultiFinder.
*/
#include "SOFTPC_COMMS.seg"
#endif
/*
* O/S include files.
*/
#include <stdio.h>
#include <ctype.h>
#if defined(NTVDM) && defined(MONITOR)
#include <malloc.h>
#endif
#include TypesH
#include StringH
/*
* SoftPC include files
*/
#include "xt.h"
#include CpuH
#include "sas.h"
#include "bios.h"
#include "ios.h"
#include "rs232.h"
#include "trace.h"
#include "error.h"
#include "config.h"
#include "host_com.h"
#include "ica.h"
#include "debug.h"
#include "timer.h"
#include "quick_ev.h"
#include "idetect.h"
#include "ckmalloc.h"
#ifdef GISP_CPU
#include "hg_cpu.h" /* GISP CPU interface */
#endif /* GISP_CPU */
LOCAL UTINY selectBits[4] = { 0x1f, 0x3f, 0x7f, 0xff } ;
/*
* =====================================================================
* The rs232 adaptor state
* =====================================================================
*/
/*
* batch_size, current_count
* The IRET_HOOKS parameters batch_size and curr_count are used to prevent
* the number of interrupts that are emulated in one batch getting too
* large. When we reach the batch size we'll unhook the interrupt, and
* wait a while.
* batch_running, qev_running
* These variables are used to prevent multiple quick events or batches
* running at once on a single adapter.
*/
static struct ADAPTER_STATE
{
BUFFER_REG tx_buffer;
BUFFER_REG rx_buffer;
DIVISOR_LATCH divisor_latch;
INT_ENABLE_REG int_enable_reg;
INT_ID_REG int_id_reg;
LINE_CONTROL_REG line_control_reg;
MODEM_CONTROL_REG modem_control_reg;
LINE_STATUS_REG line_status_reg;
MODEM_STATUS_REG modem_status_reg;
#if defined(NTVDM) && defined(FIFO_ON)
FIFO_CONTROL_REG fifo_control_reg;
FIFORXDATA rx_fifo[FIFO_BUFFER_SIZE];
half_word rx_fifo_write_counter;
half_word rx_fifo_read_counter;
half_word fifo_trigger_counter;
int fifo_timeout_interrupt_state;
#endif
half_word scratch; /* scratch register */
int break_state; /* either OFF or ON */
int loopback_state; /* either OFF or ON */
int dtr_state; /* either OFF or ON */
int rts_state; /* either OFF or ON */
int out1_state; /* either OFF or ON */
int out2_state; /* either OFF or ON */
int receiver_line_status_interrupt_state;
int data_available_interrupt_state;
int tx_holding_register_empty_interrupt_state;
int modem_status_interrupt_state;
int hw_interrupt_priority;
int com_baud_ind;
int had_first_read;
#ifdef IRET_HOOKS
IUM32 batch_size;
IUM32 current_count;
IBOOL batch_running;
IBOOL qev_running;
#endif /* IRET_HOOKS */
#ifdef NTVDM
MODEM_STATUS_REG last_modem_status_value;
int modem_status_changed;
#endif
} adapter_state[NUM_SERIAL_PORTS];
#ifdef NTVDM
#define MODEM_STATE_CHANGE() asp->modem_status_changed = TRUE;
#else
#define MODEM_STATE_CHANGE()
#endif
#ifdef IRET_HOOKS
/*
* Also have an overall quick events running flag that is set, if either
* adapter has an event running.
*/
IBOOL qev_running = FALSE;
#endif /* IRET_HOOKS */
/*
* For synchronisation of adapter input.
* Note this code is essential for the VMS equivalent of the async
* event manager. Removing it causes characters to be lost on reception.
*/
static int com_critical[NUM_SERIAL_PORTS];
#define is_com_critical(adapter) (com_critical[adapter] != 0)
#define com_critical_start(adapter) (++com_critical[adapter])
#define com_critical_end(adapter) (--com_critical[adapter])
#define com_critical_reset(adapter) (com_critical[adapter] = 0)
/*
* Used to determine whether a flush input is needed for a LCR change
*/
static LINE_CONTROL_REG LCRFlushMask;
/*
* Please note that the following arrays have been made global in order
* that they can be accessed from some SUN_VA code. Please do not make
* them static.
*/
#if defined(NTVDM) && defined(FIFO_ON)
static half_word level_to_counter[4] = { 1, 4, 8, 14};
#endif
/*
* The delay needed in microseconds between receiving 2 characters
* note this time is about 10% less than the time for actual reception.
*
* These delays have been heavily fudged and are now based on the idea that
* most of the comms interrupt handlers can handle 9600 baud. So as a
* result the delays between 2 characters are now always set for 9600 baud.
* Also note the delays of the faster baud rates have been decreased to
* 1/2 of original delays, again this is to try to empty the host buffers
* quickly enough to avoid buffer overflows.
* NB these figures are heuristic.
*
* Finally it may be possible that the transmit delays will have to
* be similarly fudged.
*/
unsigned long RX_delay[] =
{
34, /* 115200 baud */
67, /* 57600 baud */
103, /* 38400 baud */
900, /* 19200 baud */
900, /* 9600 baud */
900, /* 7200 baud */
900, /* 4800 baud */
900, /* 3600 baud */
900, /* 2400 baud */
900, /* 2000 baud */
900, /* 1800 baud */
900, /* 1200 baud */
900, /* 600 baud */
900, /* 300 baud */
900, /* 150 baud */
900, /* 134 baud */
900, /* 110 baud */
900, /* 75 baud */
900 /* 50 baud */
};
/*
* the delay needed in microseconds between transmitting 2 characters
* note this time is about 10% more than the time for actual transmission.
*/
unsigned long TX_delay[] =
{
83, /* 115200 baud */
165, /* 57600 baud */
253, /* 38400 baud */
495, /* 19200 baud */
1100, /* 9600 baud */
1375, /* 7200 baud */
2063, /* 4800 baud */
2750, /* 3600 baud */
4125, /* 2400 baud */
5042, /* 2000 baud */
5500, /* 1800 baud */
8250, /* 1200 baud */
16500, /* 600 baud */
33000, /* 300 baud */
66000, /* 150 baud */
73920, /* 134 baud */
89980, /* 110 baud */
132000, /* 75 baud */
198000 /* 50 baud */
};
#ifndef PROD
FILE *com_trace_fd = NULL;
int com_dbg_pollcount = 0;
#endif /* !PROD */
/*
* =====================================================================
* Other variables
* =====================================================================
*/
#if !defined(PROD) || defined(SHORT_TRACE)
static char buf[80]; /* Buffer for diagnostic prints */
#endif /* !PROD || SHORT_TRACE */
#ifdef PS_FLUSHING
LOCAL IBOOL psFlushEnabled[NUM_SERIAL_PORTS]; /* TRUE if PostScript flushing
is enabled */
#endif /* PS_FLUSHING */
/* Control TX pacing */
IBOOL tx_pacing_enabled = FALSE;
/*
* =====================================================================
* Static forward declarations
* =====================================================================
*/
static void raise_rls_interrupt IPT1(struct ADAPTER_STATE *, asp);
static void raise_rda_interrupt IPT1(struct ADAPTER_STATE *, asp);
static void raise_ms_interrupt IPT1(struct ADAPTER_STATE *,asp);
static void raise_thre_interrupt IPT1(struct ADAPTER_STATE *, asp);
static void generate_iir IPT1(struct ADAPTER_STATE *, asp);
static void raise_interrupt IPT1(struct ADAPTER_STATE *, asp);
static void clear_interrupt IPT1(struct ADAPTER_STATE *, asp);
static void com_flush_input IPT1(int, adapter);
static void com_send_not_finished IPT1(int, adapter);
#ifndef NTVDM
static void do_wait_on_send IPT1(long, adapter);
#endif
void com_inb IPT2(io_addr, port, half_word *, value);
void com_outb IPT2(io_addr, port, half_word, value);
void com_recv_char IPT1(int, adapter);
GLOBAL void recv_char IPT1(long, adapter);
void com_modem_change IPT1(int, adapter);
static void modem_change IPT1(int, adapter);
static void set_recv_char_status IPT1(struct ADAPTER_STATE *, asp);
static void set_xmit_char_status IPT1(struct ADAPTER_STATE *, asp);
static void set_break IPT1(int, adapter);
static void set_baud_rate IPT1(int, adapter);
static void set_line_control IPT2(int, adapter, int, value);
static void set_dtr IPT1(int, adapter);
static void set_rts IPT1(int, adapter);
static void set_out1 IPT1(int, adapter);
static void set_out2 IPT1(int, adapter);
static void set_loopback IPT1(int, adapter);
static void super_trace IPT1(char *, string);
void com1_flush_printer IPT0();
void com2_flush_printer IPT0();
static void com_reset IPT1(int, adapter);
GLOBAL VOID com_init IPT1(int, adapter);
void com_post IPT1(int, adapter);
void com_close IPT1(int, adapter);
LOCAL void next_batch IPT1(long, l_adapter);
#ifdef NTVDM
static void lsr_change(struct ADAPTER_STATE *asp, unsigned int error);
#ifdef FIFO_ON
static void recv_char_from_fifo(struct ADAPTER_STATE *asp);
#endif
#endif
/*
* =====================================================================
* Subsidiary functions - for interrupt emulation
* =====================================================================
*/
static void raise_rls_interrupt IFN1(struct ADAPTER_STATE *, asp)
{
/*
* Follow somewhat dubious advice on Page 1-188 of XT Tech Ref
* regarding the adapter card sending interrupts to the system.
* Apparently confirmed by the logic diagram.
*/
if ( asp->modem_control_reg.bits.OUT2 == 0 )
return;
/*
* Check if receiver line status interrupt is enabled
*/
if ( asp->int_enable_reg.bits.rx_line == 0 )
return;
/*
* Raise interrupt
*/
raise_interrupt(asp);
asp->receiver_line_status_interrupt_state = ON;
}
static void raise_rda_interrupt IFN1(struct ADAPTER_STATE *, asp)
{
if (( asp->modem_control_reg.bits.OUT2 == 0 ) &&
( asp->loopback_state == OFF ))
return;
/*
* Check if data available interrupt is enabled
*/
if ( asp->int_enable_reg.bits.data_available == 0 )
return;
/*
* Raise interrupt
*/
raise_interrupt(asp);
asp->data_available_interrupt_state = ON;
}
static void raise_ms_interrupt IFN1(struct ADAPTER_STATE *, asp)
{
if ( asp->modem_control_reg.bits.OUT2 == 0 )
return;
/*
* Check if modem status interrupt is enabled
*/
if ( asp->int_enable_reg.bits.modem_status == 0 )
return;
/*
* Raise interrupt
*/
raise_interrupt(asp);
asp->modem_status_interrupt_state = ON;
}
static void raise_thre_interrupt IFN1(struct ADAPTER_STATE *, asp)
{
if ( asp->modem_control_reg.bits.OUT2 == 0 )
return;
/*
* Check if tx holding register empty interrupt is enabled
*/
if ( asp->int_enable_reg.bits.tx_holding == 0 )
return;
/*
* Raise interrupt
*/
raise_interrupt(asp);
asp->tx_holding_register_empty_interrupt_state = ON;
}
static void generate_iir IFN1(struct ADAPTER_STATE *, asp)
{
/*
* Set up interrupt identification register with highest priority
* pending interrupt.
*/
if ( asp->receiver_line_status_interrupt_state == ON )
{
asp->int_id_reg.bits.interrupt_ID = RLS_INT;
asp->int_id_reg.bits.no_int_pending = 0;
}
else if ( asp->data_available_interrupt_state == ON )
{
asp->int_id_reg.bits.interrupt_ID = RDA_INT;
asp->int_id_reg.bits.no_int_pending = 0;
}
#if defined(NTVDM) && defined(FIFO_ON)
else if (asp->fifo_timeout_interrupt_state == ON)
{
asp->int_id_reg.bits.interrupt_ID = FIFO_INT;
asp->int_id_reg.bits.no_int_pending = 0;
}
#endif
else if ( asp->tx_holding_register_empty_interrupt_state == ON )
{
asp->int_id_reg.bits.interrupt_ID = THRE_INT;
asp->int_id_reg.bits.no_int_pending = 0;
}
else if ( asp->modem_status_interrupt_state == ON )
{
asp->int_id_reg.bits.interrupt_ID = MS_INT;
asp->int_id_reg.bits.no_int_pending = 0;
}
else
{
/* clear interrupt */
asp->int_id_reg.bits.no_int_pending = 1;
asp->int_id_reg.bits.interrupt_ID = 0;
}
}
static void raise_interrupt IFN1(struct ADAPTER_STATE *, asp)
{
/*
* Make sure that some thing else has not raised an interrupt
* already.
*/
if ( ( asp->receiver_line_status_interrupt_state == OFF )
&& ( asp->data_available_interrupt_state == OFF )
&& ( asp->tx_holding_register_empty_interrupt_state == OFF )
&& ( asp->modem_status_interrupt_state == OFF )
#if defined(NTVDM) && defined(FIFO_ON)
&& (asp->fifo_timeout_interrupt_state == OFF )
#endif
)
{
#ifndef DELAYED_INTS
ica_hw_interrupt(0, asp->hw_interrupt_priority, 1);
#else
ica_hw_interrupt_delay(0, asp->hw_interrupt_priority, 1,
HOST_COM_INT_DELAY);
#endif
}
}
static void clear_interrupt IFN1(struct ADAPTER_STATE *, asp)
{
/*
* Make sure that some thing else has not raised an interrupt
* already. If so then we cant drop the line.
*/
if ( ( asp->receiver_line_status_interrupt_state == OFF )
&& ( asp->data_available_interrupt_state == OFF )
&& ( asp->tx_holding_register_empty_interrupt_state == OFF )
&& ( asp->modem_status_interrupt_state == OFF )
#if defined(NTVDM) && defined(FIFO_ON)
&& ( asp->fifo_timeout_interrupt_state == OFF )
#endif
)
{
ica_clear_int(0, asp->hw_interrupt_priority);
}
}
#if defined(NTVDM) && defined(FIFO_ON)
static void raise_fifo_timeout_interrupt(struct ADAPTER_STATE *asp)
{
if (( asp->modem_control_reg.bits.OUT2 == 0 ) &&
( asp->loopback_state == OFF ))
return;
/*
* Check if data available interrupt is enabled
*/
if ( asp->int_enable_reg.bits.data_available == 0 )
return;
/*
* Raise interrupt
*/
raise_interrupt(asp);
asp->fifo_timeout_interrupt_state = ON;
}
#endif
/*
* =====================================================================
* The Adaptor functions
* =====================================================================
*/
static void com_flush_input IFN1(int, adapter)
{
struct ADAPTER_STATE *asp = &adapter_state[adapter];
int finished, error_mask;
long input_ready = 0;
sure_note_trace1(RS232_VERBOSE, "flushing the input for COM%c",
adapter+'1');
finished=FALSE;
while(!finished)
{
host_com_ioctl(adapter, HOST_COM_INPUT_READY,
(long)&input_ready);
if (input_ready)
{
host_com_read(adapter, (UTINY *)&asp->rx_buffer,
&error_mask);
}
else
{
finished=TRUE;
}
}
set_xmit_char_status(asp);
}
static void com_send_not_finished IFN1(int, adapter)
{
struct ADAPTER_STATE *asp = &adapter_state[adapter];
asp->line_status_reg.bits.tx_holding_empty=0;
asp->line_status_reg.bits.tx_shift_empty=0;
}
#ifndef NTVDM
static void do_wait_on_send IFN1(long, adapter)
{
extern void host_com_send_delay_done IPT2(long, p1, int, p2);
struct ADAPTER_STATE *asp;
asp= &adapter_state[adapter];
set_xmit_char_status(asp);
host_com_send_delay_done(adapter, TX_delay[asp->com_baud_ind]);
}
#endif
void com_inb IFN2(io_addr, port, half_word *, value)
{
int adapter = adapter_for_port(port);
struct ADAPTER_STATE *asp = &adapter_state[adapter];
long input_ready = 0;
boolean adapter_was_critical;
#ifdef NTVDM
if((port & 0x7) != RS232_MSR) host_com_lock(adapter);
#endif /* NTVDM */
switch(port & 0x7)
{
case RS232_TX_RX:
IDLE_comlpt();
if (asp->line_control_reg.bits.DLAB == 0)
{
/*
* Read of rx buffer
*/
#ifndef NTVDM
if (!(asp->had_first_read))
{
com_flush_input(adapter);
asp->had_first_read=TRUE;
}
#else /* NTVDM is defined */
//Flushing on first read removes characters from
//the communications system that are needed !!!!
//This assumes that the first read from the comms
//system will return one character only. This is
//a false assumption under NT windows.
#endif /* !NTVDM */
*value = asp->rx_buffer;
adapter_was_critical =
(asp->line_status_reg.bits.data_ready == 1);
asp->line_status_reg.bits.data_ready = 0;
asp->data_available_interrupt_state = OFF;
clear_interrupt(asp);
if ( asp->loopback_state == OFF )
{
/*
* Adapter out of critical region,
* check for further input. For IRET_HOOKS
* we don't need to do this, as receipt
* of the next character is kicked off
* by the IRET, however we do something
* else instead. If this is the first
* character of a batch, we kick off a quick
* event for what will eventually be the
* start of the next batch (assuming there
* isn't already a quick event running).
* In any case we increment the count of
* characters in this batch.
*/
if (adapter_was_critical)
{
#ifdef NTVDM
#ifdef FIFO_ON
if (asp->fifo_control_reg.bits.enabled) {
recv_char_from_fifo(asp);
*value = asp->rx_buffer;
host_com_fifo_char_read(adapter);
if (asp->rx_fifo_write_counter)
/* say this if we have more char in
the buffer to be deliveried
*/
asp->line_status_reg.bits.data_ready = 1;
else
host_com_char_read(adapter,
asp->int_enable_reg.bits.data_available);
}
else
host_com_char_read(adapter,
asp->int_enable_reg.bits.data_available
);
#else /* !FIFO_ON */
host_com_char_read(adapter,
asp->int_enable_reg.bits.data_available
);
#endif /* !FIFO_ON */
#endif /* NTVDM */
#ifndef NTVDM
#ifdef IRET_HOOKS
if (!asp->batch_running) {
asp->batch_running = TRUE;
asp->current_count = 1;
asp->qev_running = TRUE;
if (!qev_running) {
qev_running = TRUE;
#ifdef GISP_CPU
hg_add_comms_cb(next_batch, MIN_COMMS_RX_QEV);
#else
add_q_event_t(next_batch, MIN_COMMS_RX_QEV, adapter);
#endif
}
} else { /* batch running */
asp->current_count++;
}
#else /* IRET_HOOKS */
host_com_ioctl(adapter, HOST_COM_INPUT_READY,
(long)&input_ready);
if (input_ready)
#ifdef DELAYED_INTS
recv_char((long)adapter);
#else
add_q_event_t(recv_char,
RX_delay[asp->com_baud_ind],
adapter);
#endif /* DELAYED_INTS */
else
com_critical_reset(adapter);
#endif /* IRET_HOOKS */
#endif /* !NTVDM */
}
}
else
{
set_xmit_char_status(asp);
}
#ifdef IRET_HOOKS
{
LOCAL IBOOL com_hook_again IPT1(IUM32, adapter);
GLOBAL IBOOL is_hooked IPT1(IUM8, line_number);
if(!is_hooked(asp->hw_interrupt_priority))
com_hook_again(adapter);
}
#endif /* IRET_HOOKS */
}
else
*value = asp->divisor_latch.byte.LSByte;
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf, "%cRX -> %x (%c)\n",
id_for_adapter(adapter), *value,
isprint(toascii(*value))?toascii(*value):'?');
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"RX %x (%c)\n",*value,
isprint(toascii(*value))?toascii(*value):'?');
}
#endif
break;
case RS232_IER:
if (asp->line_control_reg.bits.DLAB == 0)
*value = asp->int_enable_reg.all;
else
*value = asp->divisor_latch.byte.MSByte;
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cIER -> %x\n", id_for_adapter(adapter),
*value);
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"IER read %x \n",*value);
}
#endif
break;
case RS232_IIR:
generate_iir(asp);
*value = asp->int_id_reg.all;
if ( asp->int_id_reg.bits.interrupt_ID == THRE_INT )
{
asp->tx_holding_register_empty_interrupt_state = OFF;
clear_interrupt(asp);
}
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cIIR -> %x\n", id_for_adapter(adapter),
*value);
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"IIR read %x \n",*value);
}
#endif
break;
case RS232_LCR:
#ifdef NTVDM
/* Before returning the information on the current configuation
of the serial link make sure the System comms port is open */
{
extern int host_com_open(int adapter);
host_com_open(adapter);
}
#endif
*value = asp->line_control_reg.all;
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cLCR -> %x\n", id_for_adapter(adapter),
*value);
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"LCR read %x \n",*value);
}
#endif
break;
case RS232_MCR:
*value = asp->modem_control_reg.all;
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cMCR -> %x\n", id_for_adapter(adapter),
*value);
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"MCR read %x \n",*value);
}
#endif
break;
case RS232_LSR:
*value = asp->line_status_reg.all;
asp->line_status_reg.bits.overrun_error = 0;
asp->line_status_reg.bits.parity_error = 0;
asp->line_status_reg.bits.framing_error = 0;
asp->line_status_reg.bits.break_interrupt = 0;
asp->receiver_line_status_interrupt_state = OFF;
clear_interrupt(asp);
#if defined(NTVDM) && defined(FIFO_ON)
asp->fifo_timeout_interrupt_state = OFF;
#endif
#ifdef SHORT_TRACE
if ((!asp->line_status_reg.bits.tx_holding_empty) ||
(!asp->line_status_reg.bits.tx_shift_empty))
{
IDLE_comlpt();
}
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cLSR -> %x\n", id_for_adapter(adapter),
*value);
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if ((*value & 0x9f) != 0x0)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"LSR read %x \n",*value);
}
else
{
com_dbg_pollcount++;
if (*value == 0)
fprintf(com_trace_fd,"0");
else
fprintf(com_trace_fd,".");
if (com_dbg_pollcount > 19)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
}
}
#endif
break;
case RS232_MSR:
#ifndef NTVDM
if (asp->loopback_state == OFF)
{
com_modem_change(adapter);
}
else
{
asp->modem_status_reg.bits.CTS = asp->modem_control_reg.bits.RTS;
asp->modem_status_reg.bits.DSR = asp->modem_control_reg.bits.DTR;
asp->modem_status_reg.bits.RI = asp->modem_control_reg.bits.OUT1;
asp->modem_status_reg.bits.RLSD = asp->modem_control_reg.bits.OUT2;
}
*value = asp->modem_status_reg.all;
asp->modem_status_reg.bits.delta_CTS = 0;
asp->modem_status_reg.bits.delta_DSR = 0;
asp->modem_status_reg.bits.delta_RLSD = 0;
asp->modem_status_reg.bits.TERI = 0;
asp->modem_status_interrupt_state = OFF;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
clear_interrupt(asp);
#else
if(!asp->modem_status_changed && asp->loopback_state == OFF)
{
*value = asp->last_modem_status_value.all;
}
else
{
host_com_lock(adapter);
asp->modem_status_changed = TRUE;
/* if the adapter is not opened yet, just return POST
value.
*/
if (host_com_check_adapter(adapter)) {
if(asp->loopback_state == OFF)
{
com_modem_change(adapter);
asp->modem_status_changed = FALSE;
}
else
{
asp->modem_status_reg.bits.CTS = asp->modem_control_reg.bits.RTS;
asp->modem_status_reg.bits.DSR = asp->modem_control_reg.bits.DTR;
asp->modem_status_reg.bits.RI = asp->modem_control_reg.bits.OUT1;
asp->modem_status_reg.bits.RLSD = asp->modem_control_reg.bits.OUT2;
}
}
*value = asp->modem_status_reg.all;
asp->modem_status_reg.bits.delta_CTS = 0;
asp->modem_status_reg.bits.delta_DSR = 0;
asp->modem_status_reg.bits.delta_RLSD = 0;
asp->modem_status_reg.bits.TERI = 0;
asp->modem_status_interrupt_state = OFF;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
clear_interrupt(asp);
asp->last_modem_status_value.all = asp->modem_status_reg.all;
host_com_unlock(adapter);
}
#endif /* ifndef NTVDM */
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cMSR -> %x\n", id_for_adapter(adapter),
*value);
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"MSR read %x \n",*value);
}
#endif
break;
/*
* Scratch register. Just output the value stored.
*/
case RS232_SCRATCH:
*value = asp->scratch;
break;
}
#ifndef PROD
if (io_verbose & RS232_VERBOSE)
{
if (((port & 0xf) == 0xd) && (*value == 0x60))
fprintf(trace_file,".");
else
{
sprintf(buf, "com_inb() - port %x, returning val %x", port,
*value);
trace(buf, DUMP_REG);
}
}
#endif
#ifdef NTVDM
if((port & 0x7) != RS232_MSR) host_com_unlock(adapter);
#endif NTVDM
}
void com_outb IFN2(io_addr, port, half_word, value)
{
int adapter = adapter_for_port(port);
struct ADAPTER_STATE *asp = &adapter_state[adapter];
int i;
#ifdef NTVDM
host_com_lock(adapter);
#endif NTVDM
#ifndef PROD
if (io_verbose & RS232_VERBOSE)
{
sprintf(buf, "com_outb() - port %x, set to value %x",
port, value);
trace(buf, DUMP_REG);
}
#endif
switch(port & 0x7)
{
case RS232_TX_RX:
IDLE_comlpt();
if (asp->line_control_reg.bits.DLAB == 0)
{
/*
* Write char from tx buffer
*/
asp->tx_holding_register_empty_interrupt_state = OFF;
clear_interrupt(asp);
asp->tx_buffer = value;
asp->line_status_reg.bits.tx_holding_empty = 0;
asp->line_status_reg.bits.tx_shift_empty = 0;
if ( asp->loopback_state == OFF )
{
#ifdef PS_FLUSHING
/*
* If PostScript flushing is enabled for this
* port then we flush on a Ctrl-D
*/
if ( psFlushEnabled[adapter] &&
asp->tx_buffer == 0x04 /* ^D */ )
host_com_ioctl(adapter,HOST_COM_FLUSH,
0);
else {
#endif /* PS_FLUSHING */
host_com_write(adapter, asp->tx_buffer);
#if defined (DELAYED_INTS) || defined (NTVDM)
set_xmit_char_status(asp);
#else
if(tx_pacing_enabled)
add_q_event_t(do_wait_on_send,
TX_delay[asp->com_baud_ind], adapter);
else
do_wait_on_send(adapter);
#endif /* DELAYED_INTS || NTVDM */
#ifdef PS_FLUSHING
}
#endif /* PS_FLUSHING */
}
else
{ /* Loopback case requires masking off */
/* of bits based upon word length. */
asp->rx_buffer = asp->tx_buffer & selectBits[asp->line_control_reg.bits.word_length] ;
set_xmit_char_status(asp);
set_recv_char_status(asp);
}
}
else
{
asp->divisor_latch.byte.LSByte = value;
#ifndef NTVDM
set_baud_rate(adapter);
#endif
}
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cTX <- %x (%c)\n",
id_for_adapter(adapter), value,
isprint(toascii(value))?toascii(value):'?');
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"TX %x (%c)\n",value,
isprint(toascii(value))?toascii(value):'?');
}
#endif
break;
case RS232_IER:
if (asp->line_control_reg.bits.DLAB == 0)
{
#ifdef NTVDM
int org_da = asp->int_enable_reg.bits.data_available;
#endif
asp->int_enable_reg.all = value & 0xf;
/*
* Kill off any pending interrupts for those items
* which are set now as disabled
*/
if ( asp->int_enable_reg.bits.data_available == 0 )
asp->data_available_interrupt_state = OFF;
if ( asp->int_enable_reg.bits.tx_holding == 0 )
asp->tx_holding_register_empty_interrupt_state =
OFF;
if ( asp->int_enable_reg.bits.rx_line == 0 )
asp->receiver_line_status_interrupt_state = OFF;
if ( asp->int_enable_reg.bits.modem_status == 0 )
asp->modem_status_interrupt_state = OFF;
/*
* Check for immediately actionable interrupts
* If you change these, change the code for out2 as well.
*/
if ( asp->line_status_reg.bits.data_ready == 1 )
raise_rda_interrupt(asp);
if ( asp->line_status_reg.bits.tx_holding_empty == 1 )
raise_thre_interrupt(asp);
/* lower int line if no outstanding interrupts */
clear_interrupt(asp);
#ifdef NTVDM
// Inform the host interface if the status of the
// data available interrupt has changed
if(org_da != asp->int_enable_reg.bits.data_available)
{
host_com_da_int_change(adapter,
asp->int_enable_reg.bits.data_available,
asp->line_status_reg.bits.data_ready);
}
#endif /* NTVDM */
}
else
{
asp->divisor_latch.byte.MSByte = value;
#ifndef NTVDM
set_baud_rate(adapter);
#endif /* NTVDM */
}
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cIER <- %x\n", id_for_adapter(adapter),
value);
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"IER write %x \n",value);
}
#endif
break;
#if defined(NTVDM) && defined(FIFO_ON)
case RS232_FIFO:
{
FIFO_CONTROL_REG new_reg;
new_reg.all = value;
if (new_reg.bits.enabled != asp->fifo_control_reg.bits.enabled)
{
/* fifo enable state change, clear the fifo */
asp->rx_fifo_write_counter = 0;
asp->rx_fifo_read_counter = 0;
}
if (new_reg.bits.enabled != 0) {
asp->fifo_trigger_counter = level_to_counter[new_reg.bits.trigger_le
vel];
if (new_reg.bits.rx_reset) {
asp->rx_fifo_write_counter = 0;
asp->rx_fifo_read_counter = 0;
}
asp->int_id_reg.bits.fifo_enabled = 3;
}
else {
asp->fifo_control_reg.bits.enabled = 0;
asp->int_id_reg.bits.fifo_enabled = 0;
}
asp->fifo_control_reg.all = new_reg.all;
break;
}
#else /* !(NTVDM && FIFO_ON) */
case RS232_IIR:
/*
* Essentially a READ ONLY register
*/
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cIIR <- READ ONLY\n",
id_for_adapter(adapter));
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"IIR write %x \n",value);
}
#endif
break;
#endif /* NTVDM && FIFO_ON */
case RS232_LCR:
#ifdef NTVDM
/* The NT host code attempts to distinguish between applications
that probe the UART and those that use it. Probes of the UART
will not cause the systems comms port to be opened. The NT
host code inherits the line settings from NT when the system
comms port is opened. Therefore before an application reads
or writes to the divisor bytes or the LCR the system
comms port must be opened. This prevents the application
reading incorrect values for the divisor bytes and writes
to the divisor bytes getting overwritten by the system
defaults. */
{
extern int host_com_open(int adapter);
host_com_open(adapter);
}
#endif /* NTVDM */
if ((value & LCRFlushMask.all)
!= (asp->line_control_reg.all & LCRFlushMask.all))
com_flush_input(adapter);
set_line_control(adapter, value);
set_break(adapter);
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cLCR <- %x\n", id_for_adapter(adapter),
value);
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"LCR write %x \n",value);
}
#endif
break;
case RS232_MCR:
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cMCR <- %x\n", id_for_adapter(adapter),
value);
super_trace(buf);
}
#endif
/*
* Optimisation - DOS keeps re-writing this register
*/
if ( asp->modem_control_reg.all == value )
break;
asp->modem_control_reg.all = value;
asp->modem_control_reg.bits.pad = 0;
/* Must be called before set_dtr */
set_loopback(adapter);
set_dtr(adapter);
set_rts(adapter);
set_out1(adapter);
set_out2(adapter);
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"MCR write %x \n",value);
}
#endif
break;
case RS232_LSR:
i = asp->line_status_reg.bits.tx_shift_empty; /* READ ONLY */
asp->line_status_reg.all = value;
asp->line_status_reg.bits.tx_shift_empty = i;
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cLSR <- %x\n", id_for_adapter(adapter),
value);
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"LSR write %x \n",value);
}
#endif
break;
case RS232_MSR:
/*
* Essentially a READ ONLY register.
*/
#ifdef SHORT_TRACE
if ( io_verbose & RS232_VERBOSE )
{
sprintf(buf,"%cMSR <- READ ONLY\n",
id_for_adapter(adapter));
super_trace(buf);
}
#endif
#ifndef PROD
if (com_trace_fd)
{
if (com_dbg_pollcount)
{
fprintf(com_trace_fd,"\n");
com_dbg_pollcount = 0;
}
fprintf(com_trace_fd,"MSR write %x \n",value);
}
#endif
/* DrDOS writes to this reg after setting int on MSR change
* and expects to get an interrupt back!!! So we will oblige.
* Writing to this reg only seems to affect the delta bits
* (bits 0-3) of the reg.
*/
if ((value & 0xf) != (asp->modem_status_reg.all & 0xf))
{
asp->modem_status_reg.all &= 0xf0;
asp->modem_status_reg.all |= value & 0xf;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
if (asp->loopback_state == OFF)
raise_ms_interrupt(asp);
MODEM_STATE_CHANGE();
}
break;
/*
* Scratch register. Just store the value.
*/
case RS232_SCRATCH:
asp->scratch = value;
break;
}
#ifdef NTVDM
host_com_unlock(adapter);
#endif
}
#ifdef IRET_HOOKS
/*(
*========================== com_hook_again() ==================================
* com_hook_again
*
* Purpose
* This is the function that we tell the ica to call when a comms
* interrupt service routine IRETs.
*
* Input
* adapter_id The adapter id for the line. (Note the caller doesn't
* know what this is, he's just returning something
* we gave him earlier).
*
* Outputs
* return TRUE if there are more interrupts to service, FALSE otherwise.
*
* Description
* First we call host_com_ioctl to find out if there are characters
* waiting. If not, or we have reached the end of the current batch,
* we mark the end of batch and return FALSE.
* Otherwise we call recv_char() to kick-off the next character
* and return TRUE.
)*/
LOCAL IBOOL /* local because we pass a pointer to it */
com_hook_again IFN1(IUM32, adapter)
{
int input_ready; /* the host wants a pointer to an 'int'! */
struct ADAPTER_STATE *asp = &adapter_state[adapter];
host_com_ioctl(adapter, HOST_COM_INPUT_READY, (long)&input_ready);
#ifndef PROD
if ((input_ready) && (asp->current_count >= asp->batch_size)) {
sure_note_trace1(RS232_VERBOSE, "In hook again, adapter %d", adapter);
}
#endif
if((!input_ready) || (asp->current_count >= asp->batch_size)) {
asp->batch_running = FALSE;
return(FALSE);
} else {
recv_char((long)adapter);
return(TRUE); /* more to do */
}
}
/*(
*========================== next_batch() ==================================
* next_batch
*
* Purpose
* This function is called by the quick event system to kick-off the
* next batch of characters.
*
* Input
* dummy Sometimes the adapter id, sometimes not. Don't
* use it!
*
* Outputs
* None.
*
* Description
* If a batch is already running, now would not be a good time
* to start another, so we simply press the snooze button.
* Otherwise we check whether there is any data to process,
* and if so kick-off the next batch.
)*/
LOCAL void
next_batch IFN1 (long, dummy)
{
int input_ready; /* the host wants a pointer to an 'int'! */
IUM8 adapter; /* check all adapters */
struct ADAPTER_STATE *asp;
IBOOL new_qe_reqd; /* Do we need to restart the quick event */
UNUSED(dummy);
new_qe_reqd = FALSE; /* Dont need another by default */
for (adapter = 0; adapter < NUM_SERIAL_PORTS; adapter++) {
asp = &adapter_state[adapter];
if (asp->batch_running) {
new_qe_reqd = TRUE; /* not finished yet */
} else if (asp->qev_running) {
/*
* We need to set qev running to false, as it has now
* finished. If there is data to process, we call
* recv_char() which will start-off a new batch (and
* set the batch_running flag).
*/
asp->qev_running = FALSE;
host_com_ioctl((int)adapter,HOST_COM_INPUT_READY, (long)&input_ready);
if(input_ready) {
recv_char((int)adapter);
}
}
}
if (new_qe_reqd) {
#ifdef GISP_CPU
hg_add_comms_cb(next_batch, MIN_COMMS_RX_QEV);
#else
add_q_event_t(next_batch, MIN_COMMS_RX_QEV, 0);
#endif
sure_note_trace0(RS232_VERBOSE, "Reset batch quick event");
} else {
qev_running = FALSE;
}
}
#endif /* of ifdef IRET_HOOKS */
/*
* =====================================================================
* Subsidiary functions - for transmitting characters
* =====================================================================
*/
#ifdef NTVDM
// This code has been added for the MS project!!!!!!!
void com_recv_char(int adapter)
{
struct ADAPTER_STATE *asp = &adapter_state[adapter];
int error;
#ifdef FIFO_ON
if(asp->fifo_control_reg.bits.enabled) {
/* pull data from serial driver until the fifo is full or
there are no more data
*/
asp->rx_fifo_read_counter = 0;
asp->rx_fifo_write_counter = host_com_read_char(adapter,
asp->rx_fifo,
FIFO_BUFFER_SIZE
);
/* if the total chars in the fifo is more than or equalt to the trigger
count, raise a RDA int, otherwise, raise a fifo time out int.
We will continue to delivery char available in the fifo until
the rx_fifo_write_counter reaches zero every time the application
read out the byte we put in rx_buffer
*/
if (asp->rx_fifo_write_counter) {
/* we have at least one byte to delivery */
asp->line_status_reg.bits.data_ready = 1;
if (asp->rx_fifo_write_counter >= asp->fifo_trigger_counter)
raise_rda_interrupt(asp);
else
raise_fifo_timeout_interrupt(asp);
}
}
else
#endif
{
error = 0;
host_com_read(adapter, (char *)&asp->rx_buffer, &error);
if (error != 0)
{
lsr_change(asp, error);
raise_rls_interrupt(asp);
}
set_recv_char_status(asp);
}
}
#ifdef FIFO_ON
static void recv_char_from_fifo(struct ADAPTER_STATE *asp)
{
int error;
asp->rx_buffer = asp->rx_fifo[asp->rx_fifo_read_counter].data;
error = asp->rx_fifo[asp->rx_fifo_read_counter++].error;
if (error != 0) {
lsr_change(asp, error);
raise_rls_interrupt(asp);
}
asp->rx_fifo_write_counter--;
}
#endif
#else /* NTVDM */
void com_recv_char IFN1(int, adapter)
{
/*
* Character available on input device; process character if adapter
* is ready to receive it
*/
/* Check adapter not already in critical region */
if (!is_com_critical(adapter))
{
com_critical_start(adapter);
recv_char((long)adapter);
}
}
#endif /* NTVDM */
/*
* BCN 2151 - recv_char must use long param to match add_event function prototype
*/
GLOBAL void
recv_char IFN1(long, adapt_long)
{
int adapter = adapt_long;
/*
* Character available on input device, read char, format char
* checking for parity and overrun errors, raise the appropriate
* interrupt.
*/
struct ADAPTER_STATE *asp = &adapter_state[adapter];
int error_mask = 0;
host_com_read(adapter, (UTINY *)&asp->rx_buffer, &error_mask);
if (error_mask)
{
/*
* Set line status register and raise line status interrupt
*/
if (error_mask & HOST_COM_OVERRUN_ERROR)
asp->line_status_reg.bits.overrun_error = 1;
if (error_mask & HOST_COM_FRAMING_ERROR)
asp->line_status_reg.bits.framing_error = 1;
if (error_mask & HOST_COM_PARITY_ERROR)
asp->line_status_reg.bits.parity_error = 1;
if (error_mask & HOST_COM_BREAK_RECEIVED)
asp->line_status_reg.bits.break_interrupt = 1;
raise_rls_interrupt(asp);
}
set_recv_char_status(asp);
#ifdef DOCUMENTATION
/*
* I think this is wrong for polled comms applications WTGC BCN 354
*/
/*
* If the data available interrupt is not to be delivered to the CPU,
* then the adapter must come out of the critical region at once
*/
if (asp->data_available_interrupt_state != ON)
{
long input_ready = 0;
/* check for further input */
host_com_ioctl(adapter, HOST_COM_INPUT_READY,
(long)&input_ready);
if (input_ready)
recv_char((long)adapter);
else
com_critical_reset(adapter);
}
#endif
}
#ifdef NTVDM
static void lsr_change(struct ADAPTER_STATE *asp, unsigned int new_lsr)
{
if (new_lsr & HOST_COM_OVERRUN_ERROR)
asp->line_status_reg.bits.overrun_error = 1;
if (new_lsr & HOST_COM_FRAMING_ERROR)
asp->line_status_reg.bits.framing_error = 1;
if (new_lsr & HOST_COM_PARITY_ERROR)
asp->line_status_reg.bits.parity_error = 1;
if (new_lsr & HOST_COM_BREAK_RECEIVED)
asp->line_status_reg.bits.break_interrupt = 1;
/* we have no control of serial driver fifo enable/disabled states
we may receive a fifo error even the application doesn't enable it.
fake either framing or parity error
*/
if (new_lsr & HOST_COM_FIFO_ERROR)
#ifdef FIFO_ON
if (asp->fifo_control_reg.bits.enabled)
asp->line_status_reg.bits.fifo_error = 1;
else if (asp->line_control_reg.bits.parity_enabled == PARITYENABLE_OFF)
asp->line_status_reg.bits.framing_error = 1;
else
asp->line_status_reg.bits.parity_error = 1;
#else
if (asp->line_control_reg.bits.parity_enabled == PARITYENABLE_OFF)
asp->line_status_reg.bits.framing_error = 1;
else
asp->line_status_reg.bits.parity_error = 1;
#endif
}
void com_lsr_change(int adapter)
{
int new_lsr;
struct ADAPTER_STATE *asp = &adapter_state[adapter];
new_lsr = -1;
host_com_ioctl(adapter, HOST_COM_LSR, (long)&new_lsr);
if (new_lsr != -1)
lsr_change(asp, new_lsr);
}
#endif /* NTVDM */
/*
* One of the modem control input lines has changed state
*/
void com_modem_change IFN1(int, adapter)
{
modem_change(adapter);
}
static void modem_change IFN1(int, adapter)
{
/*
* Update the modem status register after a change to one of the
* modem control input lines
*/
struct ADAPTER_STATE *asp = &adapter_state[adapter];
long modem_status = 0;
int cts_state, dsr_state, rlsd_state, ri_state;
if (asp->loopback_state == OFF)
{
/* get current modem input state */
host_com_ioctl(adapter, HOST_COM_MODEM, (long)&modem_status);
cts_state = (modem_status & HOST_COM_MODEM_CTS) ? ON : OFF;
dsr_state = (modem_status & HOST_COM_MODEM_DSR) ? ON : OFF;
rlsd_state = (modem_status & HOST_COM_MODEM_RLSD) ? ON : OFF;
ri_state = (modem_status & HOST_COM_MODEM_RI) ? ON : OFF;
/*
* Establish CTS state
*/
switch(change_state(cts_state, asp->modem_status_reg.bits.CTS))
{
case ON:
asp->modem_status_reg.bits.CTS = ON;
asp->modem_status_reg.bits.delta_CTS = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
MODEM_STATE_CHANGE();
break;
case OFF:
asp->modem_status_reg.bits.CTS = OFF;
asp->modem_status_reg.bits.delta_CTS = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
MODEM_STATE_CHANGE();
break;
case LEAVE_ALONE:
break;
}
/*
* Establish DSR state
*/
switch(change_state(dsr_state, asp->modem_status_reg.bits.DSR))
{
case ON:
asp->modem_status_reg.bits.DSR = ON;
asp->modem_status_reg.bits.delta_DSR = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
MODEM_STATE_CHANGE();
break;
case OFF:
asp->modem_status_reg.bits.DSR = OFF;
asp->modem_status_reg.bits.delta_DSR = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
MODEM_STATE_CHANGE();
break;
case LEAVE_ALONE:
break;
}
/*
* Establish RLSD state
*/
switch(change_state(rlsd_state,
asp->modem_status_reg.bits.RLSD))
{
case ON:
asp->modem_status_reg.bits.RLSD = ON;
asp->modem_status_reg.bits.delta_RLSD = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
MODEM_STATE_CHANGE();
break;
case OFF:
asp->modem_status_reg.bits.RLSD = OFF;
asp->modem_status_reg.bits.delta_RLSD = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
MODEM_STATE_CHANGE();
break;
case LEAVE_ALONE:
break;
}
/*
* Establish RI state
*/
switch(change_state(ri_state, asp->modem_status_reg.bits.RI))
{
case ON:
asp->modem_status_reg.bits.RI = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
MODEM_STATE_CHANGE();
break;
case OFF:
asp->modem_status_reg.bits.RI = OFF;
asp->modem_status_reg.bits.TERI = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
MODEM_STATE_CHANGE();
break;
case LEAVE_ALONE:
break;
}
}
}
static void set_recv_char_status IFN1(struct ADAPTER_STATE *, asp)
{
/*
* Check for data overrun and set up correct interrupt
*/
if ( asp->line_status_reg.bits.data_ready == 1 )
{
sure_note_trace0(RS232_VERBOSE, "overrun error in set_recv_char_status");
asp->line_status_reg.bits.overrun_error = 1;
raise_rls_interrupt(asp);
}
else
{
asp->line_status_reg.bits.data_ready = 1;
raise_rda_interrupt(asp);
}
}
static void set_xmit_char_status IFN1(struct ADAPTER_STATE *, asp)
{
/*
* Set line status register and raise interrupt
*/
asp->line_status_reg.bits.tx_holding_empty = 1;
asp->line_status_reg.bits.tx_shift_empty = 1;
raise_thre_interrupt(asp);
}
#ifdef NTVDM
GLOBAL void tx_shift_register_empty(int adapter)
{
struct ADAPTER_STATE *asp = &adapter_state[adapter];
asp->line_status_reg.bits.tx_shift_empty = 1;
}
GLOBAL void tx_holding_register_empty(int adapter)
{
struct ADAPTER_STATE *asp = &adapter_state[adapter];
asp->line_status_reg.bits.tx_holding_empty = 1;
raise_thre_interrupt(asp);
}
#endif
/*
* =====================================================================
* Subsidiary functions - for setting comms parameters
* =====================================================================
*/
static void set_break IFN1(int, adapter)
{
/*
* Process the set break control bit. Bit 6 of the Line Control
* Register.
*/
struct ADAPTER_STATE *asp = &adapter_state[adapter];
switch ( change_state((int)asp->line_control_reg.bits.set_break,
asp->break_state) )
{
case ON:
asp->break_state = ON;
host_com_ioctl(adapter, HOST_COM_SBRK, 0);
break;
case OFF:
asp->break_state = OFF;
host_com_ioctl(adapter, HOST_COM_CBRK, 0);
break;
case LEAVE_ALONE:
break;
}
}
/*
* The following table is derived from page 1-200 of the XT Tech Ref 1st Ed
* (except rates above 9600 which are not OFFICIALLY supported on the XT and
* AT, but are theoretically possible) */
static word valid_latches[] =
{
1, 2, 3, 6, 12, 16, 24, 32,
48, 58, 64, 96, 192, 384, 768, 857,
1047, 1536, 2304
};
#if !defined(PROD) || defined(IRET_HOOKS)
static IUM32 bauds[] =
{
115200, /* 115200 baud */
57600, /* 57600 baud */
38400, /* 38400 baud */
19200, /* 19200 baud */
9600, /* 9600 baud */
7200, /* 7200 baud */
4800, /* 4800 baud */
3600, /* 3600 baud */
2400, /* 2400 baud */
2000, /* 2000 baud */
1800, /* 1800 baud */
1200, /* 1200 baud */
600, /* 600 baud */
300, /* 300 baud */
150, /* 150 baud */
134, /* 134 baud */
110, /* 110 baud */
75, /* 75 baud */
50 /* 50 baud */
};
#endif /* !PROD or IRET_HOOKS*/
static word speeds[] =
{
HOST_COM_B115200,
HOST_COM_B57600,
HOST_COM_B38400,
HOST_COM_B19200,
HOST_COM_B9600,
HOST_COM_B7200,
HOST_COM_B4800,
HOST_COM_B3600,
HOST_COM_B2400,
HOST_COM_B2000,
HOST_COM_B1800,
HOST_COM_B1200,
HOST_COM_B600,
HOST_COM_B300,
HOST_COM_B150,
HOST_COM_B134,
HOST_COM_B110,
HOST_COM_B75,
HOST_COM_B50
};
static int no_valid_latches =
(int)(sizeof(valid_latches)/sizeof(valid_latches[0]));
static void set_baud_rate IFN1(int, adapter)
{
/*
* Map divisor latch into a valid line speed and set our Unix
* device accordingly. Note as the sixteen bit divisor latch is
* likely to be written in two eight bit bytes, we ignore illegal
* values of the sixteen bit divisor latch - hoping a second
* byte will be written to produce a legal value. In addition
* the reset value (0) is illegal!
*
* For IRET hooks, we need to determine the batch size from
* the line speed, and an idea of how many quick events
* we can get per second. We add one to alow us to catch-up!
* Hence
* batch size = line_speed (in bits per second)
* / number of bits in a byte
* * number of quick events ticks per second (normally 1000000)
* / the length in quick event ticks of a batch
* + 1
*/
struct ADAPTER_STATE *asp = &adapter_state[adapter];
int i;
com_flush_input(adapter);
#ifndef NTVDM
/*
* Check for valid divisor latch
*/
for (i = 0; i < no_valid_latches && asp->divisor_latch.all !=
valid_latches[i]; i++)
;
if (i < no_valid_latches) /* ie map found */
{
host_com_ioctl(adapter, HOST_COM_BAUD, speeds[i]);
asp->com_baud_ind = i;
sure_note_trace3(RS232_VERBOSE,
" delay for baud %d RX:%d TX:%d", bauds[i],
RX_delay[i], TX_delay[i]);
#ifdef IRET_HOOKS
#ifdef VARIABLE_TICK_COMMS
asp->batch_size = ((bauds[i] / BITS_PER_ASYNC_CHAR) /
(COMMS_QEV_PER_SEC/2)) + 1;
sure_note_trace2(RS232_VERBOSE,
"baud %d asp->batch_size =%d",bauds[i],asp->batch_size);
#else /* VARIABLE_TICK_COMMS */
asp->batch_size = ((bauds[i] / BITS_PER_ASYNC_CHAR) /
COMMS_QEV_PER_SEC) + 1;
#endif /* VARIABLE_TICK_COMMS */
#endif /* IRET_HOOKS */
}
#else /* NTVDM */
//The host is not limited in the baud rates that it supports
if(asp->divisor_latch.all)
/* baudrate = clock frequency / (diviso * 16) by taking
frequency as 1.8432 MHZ
*/
host_com_ioctl(adapter,HOST_COM_BAUD,115200/asp->divisor_latch.all);
#endif /* NTVDM */
}
static void set_line_control IFN2(int, adapter, int, value)
{
/*
* Set Number of data bits
* Parity bits
* Number of stop bits
*/
struct ADAPTER_STATE *asp = &adapter_state[adapter];
LINE_CONTROL_REG newLCR;
int newParity, parity;
newLCR.all = value;
/*
* Set up the number of data bits
*/
if (asp->line_control_reg.bits.word_length != newLCR.bits.word_length)
host_com_ioctl(adapter, HOST_COM_DATABITS,
newLCR.bits.word_length + 5);
/*
* Set up the number of stop bits
*/
if (asp->line_control_reg.bits.no_of_stop_bits
!= newLCR.bits.no_of_stop_bits)
host_com_ioctl(adapter, HOST_COM_STOPBITS,
newLCR.bits.no_of_stop_bits + 1);
/* What are new settings to check for a difference */
#ifdef NTVDM
if (newLCR.bits.parity_enabled == PARITYENABLE_OFF)
#else
if (newLCR.bits.parity_enabled == PARITY_OFF)
#endif
{
newParity = HOST_COM_PARITY_NONE;
}
else if (newLCR.bits.stick_parity == PARITY_STICK)
{
#ifdef NTVDM
newParity = newLCR.bits.even_parity == EVENPARITY_ODD ?
#else
newParity = newLCR.bits.even_parity == PARITY_ODD ?
#endif
HOST_COM_PARITY_MARK : HOST_COM_PARITY_SPACE;
}
else /* regular parity */
{
#ifdef NTVDM
newParity = newLCR.bits.even_parity == EVENPARITY_ODD ?
#else
newParity = newLCR.bits.even_parity == PARITY_ODD ?
#endif
HOST_COM_PARITY_ODD : HOST_COM_PARITY_EVEN;
}
/*
* Try to make sense of the current parity setting
*/
#ifdef NTVDM
if (asp->line_control_reg.bits.parity_enabled == PARITYENABLE_OFF)
#else
if (asp->line_control_reg.bits.parity_enabled == PARITY_OFF)
#endif
{
parity = HOST_COM_PARITY_NONE;
}
else if (asp->line_control_reg.bits.stick_parity == PARITY_STICK)
{
#ifdef NTVDM
parity = asp->line_control_reg.bits.even_parity == EVENPARITY_ODD ?
#else
parity = asp->line_control_reg.bits.even_parity == PARITY_ODD ?
#endif
HOST_COM_PARITY_MARK : HOST_COM_PARITY_SPACE;
}
else /* regular parity */
{
#ifdef NTVDM
parity = asp->line_control_reg.bits.even_parity == EVENPARITY_ODD ?
#else
parity = asp->line_control_reg.bits.even_parity == PARITY_ODD ?
#endif
HOST_COM_PARITY_ODD : HOST_COM_PARITY_EVEN;
}
if (newParity != parity)
host_com_ioctl(adapter, HOST_COM_PARITY, newParity);
#ifdef NTVDM
//Change in the status of the DLAB selection bit, now is the time
//to change the baud rate.
if(!newLCR.bits.DLAB && asp->line_control_reg.bits.DLAB)
set_baud_rate(adapter);
#endif
/* finally update the current line control settings */
asp->line_control_reg.all = value;
}
static void set_dtr IFN1(int, adapter)
{
/*
* Process the DTR control bit, Bit 0 of the Modem Control
* Register.
*/
struct ADAPTER_STATE *asp = &adapter_state[adapter];
switch ( change_state((int)asp->modem_control_reg.bits.DTR,
asp->dtr_state) )
{
case ON:
asp->dtr_state = ON;
if (asp->loopback_state == OFF)
{
/* set the real DTR modem output */
host_com_ioctl(adapter, HOST_COM_SDTR, 0);
}
else
{
/*
* loopback the DTR modem output into the
* DSR modem input
*/
asp->modem_status_reg.bits.DSR = ON;
asp->modem_status_reg.bits.delta_DSR = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
}
MODEM_STATE_CHANGE();
break;
case OFF:
asp->dtr_state = OFF;
if (asp->loopback_state == OFF)
{
/* clear the real DTR modem output */
host_com_ioctl(adapter, HOST_COM_CDTR, 0);
}
else
{
/*
* loopback the DTR modem output into the
* DSR modem input
*/
asp->modem_status_reg.bits.DSR = OFF;
asp->modem_status_reg.bits.delta_DSR = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
}
MODEM_STATE_CHANGE();
break;
case LEAVE_ALONE:
break;
}
}
static void set_rts IFN1(int, adapter)
{
/*
* Process the RTS control bit, Bit 1 of the Modem Control
* Register.
*/
struct ADAPTER_STATE *asp = &adapter_state[adapter];
switch ( change_state((int)asp->modem_control_reg.bits.RTS,
asp->rts_state) )
{
case ON:
asp->rts_state = ON;
if (asp->loopback_state == OFF)
{
/* set the real RTS modem output */
host_com_ioctl(adapter, HOST_COM_SRTS, 0);
}
else
{
/* loopback the RTS modem out into the CTS modem in */
asp->modem_status_reg.bits.CTS = ON;
asp->modem_status_reg.bits.delta_CTS = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
}
MODEM_STATE_CHANGE();
break;
case OFF:
asp->rts_state = OFF;
if (asp->loopback_state == OFF)
{
/* clear the real RTS modem output */
host_com_ioctl(adapter, HOST_COM_CRTS, 0);
}
else
{
/* loopback the RTS modem out into the CTS modem in */
asp->modem_status_reg.bits.CTS = OFF;
asp->modem_status_reg.bits.delta_CTS = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
}
MODEM_STATE_CHANGE();
break;
case LEAVE_ALONE:
break;
}
}
static void set_out1 IFN1(int, adapter)
{
/*
* Process the OUT1 control bit, Bit 2 of the Modem Control
* Register.
*/
struct ADAPTER_STATE *asp = &adapter_state[adapter];
switch ( change_state((int)asp->modem_control_reg.bits.OUT1,
asp->out1_state) )
{
case ON:
asp->out1_state = ON;
if (asp->loopback_state == OFF)
{
/*
* In the real adapter, this modem control output
* signal is not connected; so no real modem
* control change is required
*/
}
else
{
/* loopback the OUT1 modem out into the RI modem in */
asp->modem_status_reg.bits.RI = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
}
MODEM_STATE_CHANGE();
break;
case OFF:
asp->out1_state = OFF;
if (asp->loopback_state == OFF)
{
/*
* In the real adapter, this modem control output
* signal is not connected; so no real modem control
* change is required
*/
}
else
{
/* loopback the OUT1 modem out into the RI modem in */
asp->modem_status_reg.bits.RI = OFF;
asp->modem_status_reg.bits.TERI = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
}
MODEM_STATE_CHANGE();
break;
case LEAVE_ALONE:
break;
}
}
static void set_out2 IFN1(int, adapter)
{
/*
* Process the OUT2 control bit, Bit 3 of the Modem Control
* Register.
*/
struct ADAPTER_STATE *asp = &adapter_state[adapter];
switch ( change_state((int)asp->modem_control_reg.bits.OUT2,
asp->out2_state) )
{
case ON:
asp->out2_state = ON;
if (asp->loopback_state == OFF)
{
/*
* In the real adapter, this modem control output
* signal is used to determine whether the
* communications card should send interrupts; so
* check for immediately actionable interrupts.
* If you change this code, change the equivalent code
* for the interrupt enable register.
*/
if ( asp->line_status_reg.bits.data_ready == 1 )
raise_rda_interrupt(asp);
if ( asp->line_status_reg.bits.tx_holding_empty == 1 )
raise_thre_interrupt(asp);
}
else
{
/* loopback the OUT2 modem output into the RLSD modem input */
asp->modem_status_reg.bits.RLSD = ON;
asp->modem_status_reg.bits.delta_RLSD = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
}
MODEM_STATE_CHANGE();
break;
case OFF:
asp->out2_state = OFF;
if (asp->loopback_state == OFF)
{
/*
* In the real adapter, this modem control output signal
* is used to determine whether the communications
* card should send interrupts; so no real modem
* control change is required
*/
}
else
{
/* loopback the OUT2 modem out into the RLSD modem in */
asp->modem_status_reg.bits.RLSD = OFF;
asp->modem_status_reg.bits.delta_RLSD = ON;
host_com_msr_callback (adapter, asp->modem_status_reg.all);
raise_ms_interrupt(asp);
}
MODEM_STATE_CHANGE();
break;
case LEAVE_ALONE:
break;
}
}
static void set_loopback IFN1(int, adapter)
{
/*
* Process the loopback control bit, Bit 4 of the Modem Control
* Register.
*/
struct ADAPTER_STATE *asp = &adapter_state[adapter];
switch ( change_state((int)asp->modem_control_reg.bits.loop,
asp->loopback_state) )
{
case ON:
asp->loopback_state = ON;
/*
* Subsequent calls to set_dtr(), set_rts(), set_out1() and
* set_out2() will cause the modem control inputs to be set
* according to the the modem control outputs
*/
break;
case OFF:
asp->loopback_state = OFF;
/*
* Set the modem control inputs according to the real
* modem state
*/
modem_change(adapter);
break;
case LEAVE_ALONE:
break;
}
}
#ifdef SHORT_TRACE
static char last_buffer[80];
static int repeat_count = 0;
static void super_trace IFN1(char *, string)
{
if ( strcmp(string, last_buffer) == 0 )
repeat_count++;
else
{
if ( repeat_count != 0 )
{
fprintf(trace_file,"repeated %d\n",repeat_count);
repeat_count = 0;
}
fprintf(trace_file, "%s", string);
strcpy(last_buffer, string);
}
}
#endif
void com1_flush_printer IFN0()
{
#ifdef NTVDM
host_com_lock(COM1);
#endif
host_com_ioctl(COM1, HOST_COM_FLUSH, 0);
#ifdef NTVDM
host_com_unlock(COM1);
#endif
}
void com2_flush_printer IFN0()
{
#ifdef NTVDM
host_com_lock(COM2);
#endif
host_com_ioctl(COM2, HOST_COM_FLUSH, 0);
#ifdef NTVDM
host_com_unlock(COM2);
#endif
}
#ifdef SEGMENTATION
/*
* The following #include specifies the code segment into which this
* module will by placed by the MPW C compiler on the Mac II running
* MultiFinder.
*/
#include "SOFTPC_INIT.seg"
#endif
static void com_reset IFN1(int, adapter)
{
struct ADAPTER_STATE *asp = &adapter_state[adapter];
/* setup the LCRFlushMask if it has not already been setup */
if (!LCRFlushMask.all)
{
LCRFlushMask.all = ~0; /* turn all bits on */
/*
* Now turn off the bits that should NOT cause the input
* to be flushed. Note set_break is handled seperately by
* the set_break() routine.
*/
LCRFlushMask.bits.DLAB = 0;
LCRFlushMask.bits.no_of_stop_bits = 0;
LCRFlushMask.bits.set_break = 0;
}
/*
* Set default state of all adapter registers
*/
asp->int_enable_reg.all = 0;
#ifdef NTVDM
// Tell host side the state of the data available interrupt
host_com_da_int_change(adapter,asp->int_enable_reg.bits.data_available,0);
#endif /* NTVDM */
asp->int_id_reg.all = 0;
asp->int_id_reg.bits.no_int_pending = 1;
/* make sure a change occurs to 0 */
asp->line_control_reg.all = ~0;
/*
* set up modem control reg so next set_dtr etc.
* Will produce required status
*/
asp->modem_control_reg.all = 0;
asp->modem_control_reg.bits.DTR = ON;
asp->modem_control_reg.bits.RTS = ON;
asp->modem_control_reg.bits.OUT1 = ON;
asp->modem_control_reg.bits.OUT2 = ON;
host_com_ioctl(adapter, HOST_COM_SDTR, 0);
host_com_ioctl(adapter, HOST_COM_SRTS, 0);
asp->line_status_reg.all = 0;
asp->line_status_reg.bits.tx_holding_empty = 1;
asp->line_status_reg.bits.tx_shift_empty = 1;
asp->modem_status_reg.all = 0;
MODEM_STATE_CHANGE();
host_com_msr_callback (adapter, asp->modem_status_reg.all);
/*
* Set up default state of our state variables
*/
asp->receiver_line_status_interrupt_state = OFF;
asp->data_available_interrupt_state = OFF;
asp->tx_holding_register_empty_interrupt_state = OFF;
asp->modem_status_interrupt_state = OFF;
asp->break_state = OFF;
asp->loopback_state = OFF;
asp->dtr_state = ON;
asp->rts_state = ON;
asp->out1_state = ON;
asp->out2_state = ON;
#if defined(NTVDM) && defined(FIFO_ON)
/* disable fifo */
asp->fifo_control_reg.all = 0;
asp->int_id_reg.bits.fifo_enabled = 0;
asp->rx_fifo_write_counter = 0;
asp->rx_fifo_read_counter = 0;
asp->fifo_trigger_counter = 1;
asp->fifo_timeout_interrupt_state = OFF;
#endif
/*
* Reset adapter synchronisation
*/
com_critical_reset(adapter);
/*
* Set Unix devices to default state
*/
set_baud_rate(adapter);
set_line_control(adapter, 0);
set_break(adapter);
/* Must be called before set_dtr */
set_loopback(adapter);
set_dtr(adapter);
set_rts(adapter);
set_out1(adapter);
set_out2(adapter);
#ifdef IRET_HOOKS
/*
* Remove any existing hook call-back, and re-instate it afresh.
*/
Ica_enable_hooking(asp->hw_interrupt_priority, NULL, adapter);
Ica_enable_hooking(asp->hw_interrupt_priority, com_hook_again, adapter);
/*
* Clear the IRET status flags.
*/
asp->batch_running = FALSE;
asp->qev_running = FALSE;
asp->batch_size = 10; /* sounds like a safe default ! */
#endif /* IRET_HOOKS */
}
#ifndef COM3_ADAPTOR
#define COM3_ADAPTOR 0
#endif
#ifndef COM4_ADAPTOR
#define COM4_ADAPTOR 0
#endif
static int com_adaptor[4] = {COM1_ADAPTOR,COM2_ADAPTOR,
COM3_ADAPTOR,COM4_ADAPTOR};
static int port_start[4] = {RS232_COM1_PORT_START,
RS232_COM2_PORT_START,
RS232_COM3_PORT_START,
RS232_COM4_PORT_START};
static int port_end[4] = {RS232_COM1_PORT_END,
RS232_COM2_PORT_END,
RS232_COM3_PORT_END,
RS232_COM4_PORT_END};
static int int_pri[4] = {CPU_RS232_PRI_INT,
CPU_RS232_SEC_INT,
CPU_RS232_PRI_INT,
CPU_RS232_SEC_INT};
static int timeout[4] = {RS232_COM1_TIMEOUT,
RS232_COM2_TIMEOUT,
RS232_COM3_TIMEOUT,
RS232_COM4_TIMEOUT};
GLOBAL VOID com_init IFN1(int, adapter)
{
io_addr i;
#ifdef NTVDM
host_com_lock(adapter);
host_com_disable_open(adapter,TRUE);
#endif
adapter_state[adapter].had_first_read = FALSE;
/* Set up the IO chip select logic for this adaptor */
#ifdef NTVDM
{
extern BOOL VDMForWOW;
extern void wow_com_outb(io_addr port, half_word value);
extern void wow_com_inb(io_addr port, half_word *value);
io_define_inb(com_adaptor[adapter],VDMForWOW ? wow_com_inb: com_inb)
;
io_define_outb(com_adaptor[adapter],VDMForWOW ? wow_com_outb: com_outb);
}
#else
io_define_inb(com_adaptor[adapter], com_inb);
io_define_outb(com_adaptor[adapter], com_outb);
#endif /* NTVDM */
for(i = port_start[adapter]; i <= port_end[adapter]; i++)
io_connect_port(i, com_adaptor[adapter], IO_READ_WRITE);
adapter_state[adapter].hw_interrupt_priority = int_pri[adapter];
/* reset adapter state */
host_com_reset(adapter);
/* reset adapter state */
com_reset(adapter);
#ifndef NTVDM
/* Should we enable TX pacing ? */
tx_pacing_enabled = host_getenv("TX_PACING_ENABLED") ? TRUE : FALSE;
#else /* not NTVDM */
host_com_disable_open(adapter,FALSE);
host_com_unlock(adapter);
#endif
return;
}
void com_post IFN1(int, adapter)
{
/* Set up BIOS data area. */
sas_storew( BIOS_VAR_START + (2*adapter), port_start[adapter]);
sas_store(timeout[adapter] , (half_word)1 );
}
void com_close IFN1(int, adapter)
{
#ifdef NTVDM
host_com_lock(adapter);
#endif
#ifndef PROD
if (com_trace_fd)
fclose (com_trace_fd);
com_trace_fd = NULL;
#endif
/* reset host specific communications channel */
config_activate(C_COM1_NAME + adapter, FALSE);
#ifdef NTVDM
host_com_unlock(adapter);
#endif
}
#ifdef NTVDM
/*********************************************************/
/* Com extentions - DAB (MS-project) */
GLOBAL void SyncBaseLineSettings(int adapter,DIVISOR_LATCH *divisor_latch,
LINE_CONTROL_REG *LCR_reg)
{
register struct ADAPTER_STATE *asp = &adapter_state[adapter];
//Setup baud rate control register
asp->divisor_latch.all = (*divisor_latch).all;
//Setup line control settings
asp->line_control_reg.bits.word_length = (*LCR_reg).bits.word_length;
asp->line_control_reg.bits.no_of_stop_bits = (*LCR_reg).bits.no_of_stop_bits
;
asp->line_control_reg.bits.parity_enabled = (*LCR_reg).bits.parity_enabled;
asp->line_control_reg.bits.stick_parity = (*LCR_reg).bits.stick_parity;
asp->line_control_reg.bits.even_parity = (*LCR_reg).bits.even_parity;
}
GLOBAL void setup_RTSDTR(int adapter)
{
struct ADAPTER_STATE *asp = &adapter_state[adapter];
host_com_ioctl(adapter,asp->dtr_state == ON ? HOST_COM_SDTR : HOST_COM_CDTR,
0);
host_com_ioctl(adapter,asp->rts_state == ON ? HOST_COM_SRTS : HOST_COM_CRTS,
0);
}
GLOBAL int AdapterReadyForCharacter(int adapter)
{
BOOL AdapterReady = FALSE;
/*......................................... Are RX interrupts enabled */
if(adapter_state[adapter].line_status_reg.bits.data_ready == 0 &&
adapter_state[adapter].data_available_interrupt_state == OFF)
{
AdapterReady = TRUE;
}
return(AdapterReady);
}
// This function returns the ICA controller and line used to generate
// interrupts on a adapter. This information is used to register a EOI
// hook.
GLOBAL void com_int_data(int adapter,int *controller, int *line)
{
struct ADAPTER_STATE *asp = &adapter_state[adapter];
*controller = 0; // Controller ints raised on
*line = (int) asp->hw_interrupt_priority; // Line ints raised on
}
#endif /* NTVDM */
#ifdef PS_FLUSHING
/*(
=========================== com_psflush_change ================================
PURPOSE:
Handle change of PostScript flush configuration option for a serial
port.
INPUT:
hostID - Configuration item I.D.
apply - TRUE if change to be applied
OUTPUT:
None
ALGORITHM:
If PostScript flushing is being enabled then;
set the PostScript flush enable flag for the port;
disable autoflush for the port;
else;
reset the PostScript flush enable flag for the port;
enable autoflush for the port;
===============================================================================
)*/
GLOBAL void com_psflush_change IFN2(
IU8, hostID,
IBOOL, apply
) {
IS32 adapter = hostID - C_COM1_PSFLUSH;
assert1(adapter < NUM_SERIAL_PORTS,"Bad hostID %d",hostID);
if ( apply )
if ( psFlushEnabled[adapter] = (IBOOL)config_inquire(hostID,NULL) )
host_com_disable_autoflush(adapter);
else
host_com_enable_autoflush(adapter);
}
#endif /* PS_FLUSHING */
/********************************************************/
/* Com debugging shell - Ade Brownlow / Ian Wellock
* NB: This stuff only works for COM1. It is called from yoda using 'cd'
* - comdebug - from the yoda command line....
*/
#ifndef PROD
#define YODA_LOOP 2
#define RX_BYTE 1
#define TX_BYTE 2
int srxcount = 0, stxcount = 0;
int com_save_rx = 0, com_save_tx = 0;
unsigned char *rxtx_buff = NULL;
int com_debug_help ();
void psaved();
static char *port_debugs[] =
{
"txrx","ier","iir", "lcr", "mcr","lsr", "msr"
};
static int do_inbs = 0; /* start with inb reporting OFF */
static unsigned char *locate_register ()
{
int i;
char ref[10];
struct ADAPTER_STATE *asp = &adapter_state[COM1];
printf ("COM.. reg? ");
scanf ("%s", ref);
for (i=0; i<7; i++)
{
if (!strcmp (ref, port_debugs[i]))
{
switch (i)
{
case 0:
return (&asp->tx_buffer);
case 1:
return (&(asp->int_enable_reg.all));
case 2:
return (&(asp->int_id_reg.all));
case 3:
return (&(asp->line_control_reg.all));
case 4:
return (&(asp->modem_control_reg.all));
case 5:
return (&(asp->line_status_reg.all));
case 6:
return (&(asp->modem_status_reg.all));
default:
return (NULL);
}
}
}
return (NULL);
}
int com_debug_stat ()
{
printf ("DEBUG STATUS...\n");
printf ("INB mismatch reporting .... %s\n", do_inbs ? "ON" : "OFF");
printf ("INB/OUTB tracing .......... %s\n", com_trace_fd ? "ON" : "OFF");
return (0);
}
int com_reg_dump ()
{
/* dump com1 emulations registers */
struct ADAPTER_STATE *asp = &adapter_state[COM1];
printf ("TX %2x RX %2x IER %2x IIR %2x LCR %2x MCR %2x LSR %2x MSR %2x \n",
(asp->tx_buffer), (asp->rx_buffer), (asp->int_enable_reg.all),
(asp->int_id_reg.all), (asp->line_control_reg.all),
(asp->modem_control_reg.all), (asp->line_status_reg.all),
(asp->modem_status_reg.all));
printf (" break_state %d\n loopback_state %d\n",
asp->break_state, asp->loopback_state);
printf(" dtr_state %d\n rts_state %d\n",
asp->dtr_state, asp->rts_state);
printf(" out1_state %d\n out2_state %d\n",
asp->out1_state, asp->out2_state);
printf(" receiver_line_status_interrupt_state %d\n",
asp->receiver_line_status_interrupt_state);
printf(" data_available_interrupt_state %d\n",
asp->data_available_interrupt_state);
printf(" tx_holding_register_empty_interrupt_state %d\n",
asp->tx_holding_register_empty_interrupt_state);
printf(" modem_status_interrupt_state %d\n",
asp->modem_status_interrupt_state);
printf(" hw_interrupt_priority %d\n",
asp->hw_interrupt_priority);
printf(" com_baud_delay %d\n had_first_read %d\n",
TX_delay[asp->com_baud_ind], asp->had_first_read);
return (0);
}
int com_s_reg ()
{
unsigned char *creg;
int val1;
if (creg = locate_register())
{
printf ("SET to > ");
scanf ("%x", &val1);
*creg = (unsigned char)val1;
}
else
printf ("Unknown reg\n");
return (0);
}
int com_p_reg ()
{
unsigned char *creg;
if (creg = locate_register())
printf ("%x\n", *creg);
else
printf ("Unknown reg\n");
return (0);
}
int conv_com_reg (com_reg)
char *com_reg;
{
int loop;
for (loop = 0; loop < 7; loop++)
if (!strcmp (port_debugs[loop], com_reg))
return (loop+RS232_COM1_PORT_START);
return (0);
}
int com_do_inb ()
{
char com_reg[10];
half_word val;
io_addr port;
printf ("Port > ");
scanf ("%s", com_reg);
if (!(port = conv_com_reg (com_reg)))
{
printf ("funny port %s\n", com_reg);
return (0);
}
com_inb (port, &val);
printf ("%s = %x\n", val);
return (0);
}
int com_do_outb ()
{
char com_reg[10];
half_word val;
io_addr port;
printf ("Port > ");
scanf ("%s", com_reg);
if (!(port = conv_com_reg (com_reg)))
{
printf ("funny port %s\n", com_reg);
return (0);
}
printf ("Value >> ");
scanf ("%x", &val);
com_outb (port, val);
return (0);
}
int com_run_file ()
{
char filename[100], com_reg[10], dir;
int val, line;
half_word spare_val;
io_addr port;
FILE *fd = NULL;
printf ("FILE > ");
scanf ("%s", filename);
if (!(fd = fopen (filename, "r")))
{
printf ("Cannot open %s\n", filename);
return (0);
}
line = 1;
/* dump file is of format : %c-%x-%s
* 1 char I or O denotes inb or outb
* -
* Hex value the value expected in case of inb or value to write in
* case of outb.
* -
* string representing the register port to use..
*
* A typical entry would be
* O-txrx-60 - which translates to outb(START_OF_COM1+txrx, 0x60);
*
* Files for this feature can be generated using the comdebug 'open' command.
*/
while (fscanf (fd, "%c-%x-%s", &dir, &val, com_reg) != EOF)
{
if (!(port = conv_com_reg (com_reg)))
{
printf ("funny port %s at line %d\n", com_reg, line);
break;
}
switch (dir)
{
case 'I':
/* inb */
com_inb (port, &spare_val);
if (spare_val != val && do_inbs)
{
printf ("INB no match at line %d %c-%s-%x val= %x\n",
line, dir, com_reg, val, spare_val);
}
break;
case 'O':
/* outb */
/* convert com_register to COM1 address com_register */
com_outb (port, val);
printf ("outb (%s, %x)\n", com_reg, val);
break;
default:
/* crap */
break;
}
line ++;
}
fclose (fd);
return (0);
}
int com_debug_quit ()
{
printf ("Returning to YODA\n");
return (1);
}
int com_o_debug_file ()
{
char filename[100];
printf ("FILE > ");
scanf ("%s", filename);
if (!(com_trace_fd = fopen (filename, "w")))
{
printf ("Cannot open %s\n", filename);
return (0);
}
printf ("Com debug file = '%s'\n", filename);
return (0);
}
int com_c_debug_file ()
{
if (com_trace_fd)
fclose (com_trace_fd);
com_trace_fd = NULL;
return (0);
}
int com_forget_inb ()
{
do_inbs = 1- do_inbs;
if (do_inbs)
printf ("INB mismatch reporting ON\n");
else
printf ("INB mismatch reporting OFF\n");
return (0);
}
int com_s_rx()
{
srxcount = stxcount = 0;
com_save_rx = 1 - com_save_rx;
printf("Save and Dump Received Bytes ");
if (com_save_rx)
printf("ON\n");
else
printf("OFF\n");
return(0);
}
int com_s_tx()
{
srxcount = stxcount = 0;
com_save_tx = 1 - com_save_tx;
printf("Save and Dump Transmitted Bytes ");
if (com_save_tx)
printf("ON\n");
else
printf("OFF\n");
return(0);
}
int com_p_rx()
{
printf("There are %d received bytes, out of %d bytes saved.\n",
srxcount, srxcount + stxcount);
psaved(RX_BYTE, stdout);
return(0);
}
int com_p_tx()
{
printf("There are %d transmitted bytes, out of %d bytes saved.\n",
stxcount, srxcount + stxcount);
psaved(TX_BYTE, stdout);
return(0);
}
int com_p_all()
{
printf("There are %d bytes saved.\n", srxcount + stxcount);
psaved(RX_BYTE + TX_BYTE, stdout);
return(0);
}
int com_d_all()
{
int cl_fin = 0;
if (!com_trace_fd)
{
com_o_debug_file();
cl_fin = 1;
}
fprintf(com_trace_fd, "There are %d bytes saved.\n", srxcount + stxcount);
psaved(RX_BYTE + TX_BYTE, com_trace_fd);
if (cl_fin)
com_c_debug_file();
return(0);
}
void psaved(typ, fd)
int typ;
FILE *fd;
{
int c, nc = 0;
for (c = 0; c < srxcount + stxcount; c++)
{
if (rxtx_buff[c * 2] & typ)
{
if (typ == RX_BYTE + TX_BYTE)
if (rxtx_buff[c * 2] & RX_BYTE)
fprintf(fd, "R ");
else
fprintf(fd, "T ");
fprintf(fd, "%2x ",rxtx_buff[c * 2 + 1]);
nc++;
if ((nc % 16) == 0)
fprintf(fd, "\n");
}
}
fprintf(fd, "\nAll bytes dumped.\n");
}
com_save_rxbytes IFN2(int, n, CHAR *, buf)
{
int tc, bs;
if (com_save_rx)
{
bs = srxcount + stxcount;
for (tc = 0; tc < n; tc++)
{
rxtx_buff[(tc + bs) * 2] = RX_BYTE;
rxtx_buff[(tc + bs) * 2 + 1] = buf[tc];
}
srxcount += n;
}
}
com_save_txbyte IFN1(CHAR, value)
{
if (com_save_tx)
{
rxtx_buff[(srxcount + stxcount) * 2] = TX_BYTE;
rxtx_buff[(srxcount + stxcount) * 2 + 1] = value;
stxcount++;
}
}
static struct
{
char *name;
int (*fn)();
char *comment;
} comtab[]=
{
{"q", com_debug_quit, " QUIT comdebug return to YODA"},
{"h", com_debug_help, " Print this message"},
{"stat", com_debug_stat, " Print status of comdebug"},
{"s", com_s_reg, " Set the specified register"},
{"p", com_p_reg, " Print specified register"},
{"dump", com_reg_dump, " Print all registers"},
{"open", com_o_debug_file, " Open a debug file"},
{"close", com_c_debug_file, " Close current debug file"},
{"runf", com_run_file, " 'Run' a trace file"},
{"toginb", com_forget_inb, " Toggle INB mismatch reporting"},
{"inb", com_do_inb, " Perform INB on port"},
{"outb", com_do_outb, " Perform OUTB on port"},
{"srx", com_s_rx, " Save all received bytes"},
{"stx", com_s_tx, " Save all transmitted bytes"},
{"prx", com_p_rx, " Print all received bytes"},
{"ptx", com_p_tx, " Print all transmitted bytes"},
{"pall", com_p_all, " Print all received/transmitted bytes"},
{"dall", com_d_all, " Dump all received/transmitted bytes"},
{"", NULL, ""}
};
int com_debug_help ()
{
int i;
printf ("COMDEBUG COMMANDS\n");
for (i=0; comtab[i].name[0]; i++)
printf ("%s\t%s\n", comtab[i].name, comtab[i].comment);
printf ("recognised registers :\n");
for (i=0; i<7; i++)
printf ("%s\n", port_debugs[i]);
return (0);
}
int com_debug()
{
char com[100];
int i;
if (rxtx_buff == NULL)
check_malloc(rxtx_buff, 50000, unsigned char);
printf ("COM1 debugging stuff...\n");
while (TRUE)
{
printf ("COM> ");
scanf ("%s", com);
for (i=0; comtab[i].name[0]; i++)
{
if (!strcmp (comtab[i].name, com))
{
if ((*comtab[i].fn) ())
return(YODA_LOOP);
break;
}
}
if (comtab[i].name[0])
continue;
printf ("Unknown command %s\n", com);
}
}
#endif /* !PROD */
/********************************************************/