mirror of https://github.com/lianthony/NT4.0
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
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 */
|
|
/********************************************************/
|