home *** CD-ROM | disk | FTP | other *** search
- /*
- * DTR8250.C
- *
- * NSC8250 DTR Handshake ISR Module
- *
- * Written for the
- *
- * Datalight
- * Microsoft V 5.x
- * TurboC
- * &
- * Zortech
- *
- * C Compilers
- *
- * Copyright (c) John Birchfield 1987, 1988, 1989
- */
-
- #include <stdio.h>
- #include "dependnt.h"
- #include "queue.h"
- #include "8250nsc.h"
- #include "8250dtr.h"
- #include "timer.h"
-
- #if (!defined (TRUE))
- # define TRUE (1)
- # define FALSE (0)
- #endif
-
- unsigned DTR_PORT_channel; /* Either 1 or 2 for COM1 or COM2 */
- char dtr8250_SAVE_int_mask, /* saved interrupt controller mask word */
- dtr8250_IER_save = 0, /* Saved off Interrupt Enable Register */
- dtr8250_LCR_save = 0, /* Saved off Line Control Register */
- dtr8250_MCR_save = 0, /* Saved off Modem Control Register */
- dtr8250_DL_lsb = 0, /* Saved off Baud Rate LSB */
- dtr8250_DL_msb = 0; /* Saved off Baud Rate MSB */
-
-
-
- volatile unsigned DTR_PORT_addr;
- volatile char DTR_PORT_status, RCV_disabled = FALSE, XMIT_disabled = TRUE, dtr8250_MSR_reg = 0;
- volatile QUEUE *dtr8250_inqueue;
- #if (defined (DLC))
- extern void outp ();
- #endif
-
-
- #define DISABLE_xmit outbyte (DTR_PORT_addr+IER, RX_enable)
- #define ENABLE_xmit outbyte (DTR_PORT_addr+IER, RX_TX_enable)
- #define DROPPED_cts ((dtr8250_MSR_reg&0x10)==0)
- #define DROPPED_dsr ((dtr8250_MSR_reg&0x20)==0)
- #define DROPPED_dtr ((dtr8250_MSR_reg&0x30)!=0x30)
- #define ASSERT_dtr outbyte (inbyte (DTR_PORT_addr+MCR)|9, DTR_PORT_addr+MCR)
- #define DROP_dtr outbyte (inbyte (DTR_PORT_addr+MCR)&0x0A, DTR_PORT_addr+MCR)
- #define ASSERT_rts outbyte (inbyte (DTR_PORT_addr+MCR)|0x0A, DTR_PORT_addr+MCR)
- #define DROP_rts outbyte (inbyte (DTR_PORT_addr+MCR)&9, DTR_PORT_addr+MCR)
- #define TSRE_bit 0x40
-
-
-
- /*
- * DTR8250_ISR - This Interrupt Service Routine attached to either COM1
- * or COM2. It drives the NSC8250 with Hardware
- * Handshaking. i.e. Flow of Control is maintained by
- * RTS (Request to Send) CTS (Clear to Send) Logic.
- * After installation by Catch_Rt, it catches the
- * 8250 interrupts and en_queues incoming characters
- * from the Serial Port - and de-queues outgoing
- * characters to the Serial Port.
- */
-
- #if (!defined (DLC))
- void (interrupt far * dtr_save_vec) (void);
- void interrupt far
- dtr8250_isr (void)
- #else
- int
- dtr8250_isr ()
- #endif
- {
- int ch;
- char test_status;
-
- enable ();
- test_status = inbyte ((DTR_PORT_addr + IIR));
- do
- {
- switch (test_status)
- {
-
- case IIR_rls:
- DTR_PORT_status |= inbyte ((DTR_PORT_addr + LSR));
- break;
-
- case IIR_receive:
- ch = inbyte (DTR_PORT_addr);
- if ((en_queue (dtr8250_inqueue, ch) < 10) && !RCV_disabled)
- {
- RCV_disabled = TRUE;
- DROP_dtr;
- }
- else
- if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
- {
- RCV_disabled = FALSE;
- ASSERT_dtr;
- }
- break;
-
- case IIR_transmit:
- DISABLE_xmit;
- break;
-
- case IIR_mstatus:
- dtr8250_MSR_reg = inbyte (DTR_PORT_addr + MSR);
- if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
- {
- RCV_disabled = FALSE;
- ASSERT_dtr;
- }
- break;
- }
- } while ((test_status = inbyte (DTR_PORT_addr + IIR)) != IIR_complete);
- disable ();
- outbyte (INT_cntrl, EOI_word);
- #if (defined (DLC))
- return (1);
- #endif
- }
-
-
-
-
- /*
- * DTR8250_INIT - Here we get the address of the 8250 Port
- * which corresponds to the channel passed in.
- * We then massage the 8259 Interrupt Controller
- * calculate the Physical Interrupt and save off
- * the 8250's current contents. Then attach the
- * nsc8250_interrupt routine to the interrupt and
- * return the rt returned index for saving - it's
- * needed to terminate the interrupt.
- */
-
- #define DTR8250_STACK_SIZE 1024
- int dtr8250_intno;
- static int dtr_intmask [] = { 0xef, 0xf7, 0xef, 0xf7 };
- /*
- * The above 8259 mask bits are determined from the formula
- * mask = ~(1 << (5 - PORT_CHANNEL));
- * The array assumes that COM3 and COM4 use the same interrupts
- * as COM1 and COM2.
- */
- static int dtr_intno [] = { 12, 11, 12, 11 };
- /*
- * The above interrupt number array is based on the algorithm
- * dtr8250_intno = (13 - PORT_channel);
- */
-
-
- void
- dtr8250_init (channel, buf_size)
- int channel, buf_size;
- {
- int Dos_address, mask;
- DTR_PORT_channel = channel;
- dtr8250_inqueue = alloc_queue (buf_size);
- Dos_address = (DTR_PORT_channel - 1) * 2;
- peekmem (0x40, Dos_address, DTR_PORT_addr);
- mask = dtr_intmask [DTR_PORT_channel-1];
- dtr8250_SAVE_int_mask = inbyte (INT_mask);
- mask &= dtr8250_SAVE_int_mask;
- dtr8250_intno = dtr_intno [DTR_PORT_channel-1];
- dtr8250_LCR_save = inbyte (DTR_PORT_addr + LCR);
- disable ();
- outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save | LCR_DLAB);
- dtr8250_MCR_save = inbyte (DTR_PORT_addr + MCR);
- dtr8250_DL_lsb = inbyte (DTR_PORT_addr);
- dtr8250_DL_msb = inbyte (DTR_PORT_addr + 1);
- outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save & 0x7F);
- dtr8250_IER_save = inbyte (DTR_PORT_addr + IER);
- enable ();
- #if (defined (DLC))
- int_intercept (dtr8250_intno, &dtr8250_isr, DTR8250_STACK_SIZE);
- #else
- dtr_save_vec = getvect (dtr8250_intno);
- setvect (dtr8250_intno, dtr8250_isr);
- #endif
- DELAY_init ();
- outbyte (INT_mask, mask);
- }
-
-
-
-
- /*
- * DTR8250_TERM - This routine restores the RS232 Vector back to its
- * state before DTR8250_INIT was called.
- */
-
- void
- dtr8250_term (int restore)
- {
- disable ();
- outbyte (INT_mask, dtr8250_SAVE_int_mask);
- if (restore)
- {
- outbyte (DTR_PORT_addr + LCR, LCR_DLAB);
- outbyte (DTR_PORT_addr, dtr8250_DL_lsb);
- outbyte (DTR_PORT_addr + 1, dtr8250_DL_msb);
- outbyte (DTR_PORT_addr + MCR, dtr8250_MCR_save);
- outbyte (DTR_PORT_addr + LCR, 0x7F);
- outbyte (DTR_PORT_addr + IER, dtr8250_IER_save);
- outbyte (DTR_PORT_addr + LCR, dtr8250_LCR_save);
- }
- #if (defined (DLC))
- int_restore (dtr8250_intno);
- #else
- setvect (dtr8250_intno, dtr_save_vec);
- #endif
- }
-
-
-
-
- /*
- * DTR8250_READ - this routine looks in the RS232hw_inqueue for a character
- *
- */
-
- int
- dtr8250_read (void)
- {
- int ch;
- disable ();
- ch = de_queue (dtr8250_inqueue);
- enable ();
- return (ch);
- }
-
-
-
-
- /*
- * DTR8250_TIMED_READ - attempts to read rs232 port - if no char
- * available in number of seconds passed
- * returns -1
- */
-
- int
- dtr8250_timed_read (int sec)
- {
- int ch;
-
- timer_set ();
- while ((ch = dtr8250_read ()) == -1)
- if ((timer_read () / 18) > sec)
- break;
- return (ch);
- }
-
-
-
-
- /*
- * DTR8250_WRITE - plain vanilla write to the port - check to see that
- * the chip may need a kick in the pants before returning
- */
-
- int
- dtr8250_write (char ch)
- {
- while ((inbyte (DTR_PORT_addr + LSR) & TSRE_bit) == 0)
- ;
- dtr8250_MSR_reg = inbyte ((DTR_PORT_addr + MSR));
- if (DROPPED_dtr)
- return -1;
- outbyte (DTR_PORT_addr, ch);
- if (RCV_disabled && (queue_avail (dtr8250_inqueue) > 20))
- {
- RCV_disabled = FALSE;
- ASSERT_dtr;
- }
- }
-
-
-
-
- /*
- * DTR8250_DTRNR - drop Data Terminal Ready Line
- */
- void
- dtr8250_dtnr (void)
- {
- char mcr_save;
- disable ();
- mcr_save = inbyte (DTR_PORT_addr + MCR);
- outbyte (DTR_PORT_addr + MCR, 0);
- DELAY_loop (500);
- outbyte (DTR_PORT_addr + MCR, mcr_save);
- enable ();
- }
-
-
-
-
- /*
- * DTR8250_GET_STATUS - returns the current NSC8250 status and
- * resets any error condition.
- */
-
- int
- dtr8250_get_status (void)
- {
- char rval = DTR_PORT_status;
- DTR_PORT_status &= ERROR_reset;
- return ((int) rval);
- }
-
-
-
-
-
- /*
- * DTR8250_MODEM_STATUS - returns the current NSC8250 Modm Status Register
- * contents.
- */
-
- int
- dtr8250_modem_status (void)
- {
- dtr8250_MSR_reg = inbyte (DTR_PORT_addr + MSR);
- return ((int) dtr8250_MSR_reg);
- }
-
-
-
-
-
- /*
- * DTR8250_WRITE_BREAK - Write a BREAK Character
- */
-
- void
- dtr8250_write_break (void)
- {
- int i;
- disable ();
- while ((inbyte (DTR_PORT_addr + LSR) & 0x40) == 0)
- ;
- outbyte (DTR_PORT_addr + LCR, inbyte (DTR_PORT_addr + LCR) | 0x40);
- for (i = 0; i < 13000; i++)
- ;
- outbyte (DTR_PORT_addr + LCR, inbyte (DTR_PORT_addr + LCR) & 0xBF);
- enable ();
- }
-
-
-
-
-
- /*
- * DTR8250_PORT_INIT (Cmd) configures the 8250
- * cmd is a string of the form baud parity stop data i.e
- * 300 n 1 8
- *
- * baud - 300, 600, 1200, 2400, 4800, 9600
- * parity - n -> no parity check
- * o -> odd parity
- * e -> even parity
- * stop - 1 -> 1 stop bit
- * 2 -> 2 stop bits
- * data - 5, 6, 7, 8 data bits
- */
-
- void
- dtr8250_port_init (cmd)
- char *cmd;
- {
- unsigned baud, data, mode_word, parity, stop, xoff;
- char pty[2];
- sscanf (cmd, "%d %1s %d %d", &baud, pty, &stop, &data);
- *pty = toupper (*pty);
- switch (*pty)
- {
- case 'E':
- parity = 3;
- break;
- case 'O':
- parity = 1;
- break;
- case 'N':
- parity = 0;
- break;
- default:
- parity = 0;
- break;
- }
- stop = (--stop & 1);
- stop <<= 2;
- baud /= 10;
- baud = 11520 / baud;
- parity <<= 3;
- parity &= 0x018;
- data -= 5;
- data &= 3;
- mode_word = data | stop | parity;
- disable ();
- outbyte (DTR_PORT_addr + LCR, inbyte (DTR_PORT_addr + LCR) | LCR_DLAB);
- outbyte (DTR_PORT_addr, baud % 256);
- outbyte (DTR_PORT_addr + 1, baud / 256);
- outbyte (DTR_PORT_addr + LCR, mode_word & 0x7F);
- outbyte (DTR_PORT_addr + IER, RX_enable);
- outbyte (DTR_PORT_addr + MCR, 0x0B);
-
- inbyte (DTR_PORT_addr + LSR);
- dtr8250_MSR_reg = inbyte ((DTR_PORT_addr + MSR));
- inbyte (DTR_PORT_addr);
- enable ();
- }
-
-
-
-
- /*---------------------- dtr8250_port_enable () ----------------------*/
- /*
- *
- */
- void
- dtr8250_port_enable (void)
- {
- disable ();
- outbyte (DTR_PORT_addr + IER, RX_enable);
- outbyte (DTR_PORT_addr + MCR, 0x0B);
-
- inbyte (DTR_PORT_addr + LSR);
- dtr8250_MSR_reg = inbyte ((DTR_PORT_addr + MSR));
- inbyte (DTR_PORT_addr);
- enable ();
- }
-
-
-
-
- /*------------------------ dtr8250_lines () ------------------------*/
- /*
- *
- */
- void
- dtr8250_lines (void)
- {
- printf ("8250 DTR_PORT_addr = %04x\n", DTR_PORT_addr);
- printf ("8250 MSR = %02x\n", inbyte (DTR_PORT_addr + MSR));
- }
-