#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 #include #if defined(NTVDM) && defined(MONITOR) #include #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 */ /********************************************************/