home *** CD-ROM | disk | FTP | other *** search
- /*
- * 8250XON.C
- *
- * NSC8250 RS232 Xon/Xoff ISR Routine
- *
- * 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 "delay.h"
- #include "8250nsc.h"
- #include "8250xon.h"
- #include "queue.h"
- #include "timer.h"
-
- #if (!defined (TRUE))
- # define TRUE (1)
- # define FALSE (0)
- #endif
-
-
- #define I_BUF_SIZE 4096 /* inbyteut Buffer Size */
- #define O_BUF_SIZE 4096 /* output Buffer Size */
-
- volatile unsigned XON_PORT_address = 0x03F8;
- volatile char xoff_enabled = FALSE,
- xoff_sent = FALSE,
- xoff_received = FALSE,
- XON_PORT_status = 0,
- XON_PORT_state = 0,
- XON_PORT_command = 0,
- XON_char = 0x11,
- XOFF_char = 0x13;
-
- char XON_PORT_channel = 1,
- SAVE_int_mask = 0, /* saved interrupt controller mask word */
-
- /*
- * 8250 register save locations and base address offsets
- */
- IER_save = 0, LCR_save = 0, MCR_save = 0, DL_lsb = 0, DL_msb = 0;
-
-
-
-
- QUEUE *xon8250_inqueue, *xon8250_outqueue;
-
- /*
- * XON8250_ISR - This is the interrupt handler for the
- * National Semiconducter 8250 Serial Chip.
- * 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. The original code
- * was written in assembler and provided about 80%
- * of the Port's Bandwidth at 9600 baud running
- * An Xmodem protocol. We'll see what this does...
- */
-
- #if (!defined (DLC))
- void (interrupt far * xon_save_vec) (void);
- void interrupt far
- xon8250_isr (void)
- #else
- int
- xon8250_isr ()
- #endif
- {
- int ch;
- char test_status;
-
- enable ();
- test_status = inbyte ((XON_PORT_address + IIR));
- do
- {
- switch (test_status)
- {
- case IIR_rls:
- XON_PORT_status |= inbyte ((XON_PORT_address + LSR));
- break;
-
- case IIR_receive:
- ch = inbyte (XON_PORT_address);
- if ((xoff_enabled && !xoff_sent) &&
- (ch == XOFF_char))
- {
- xoff_received = TRUE;
- }
- else
- if (xoff_received &&
- (ch == XON_char))
- {
- xoff_received = FALSE;
- outbyte (XON_PORT_address + IER, XON_PORT_command = RX_TX_enable);
- }
- else
- if ((en_queue (xon8250_inqueue, ch) < 10) &&
- xoff_enabled && !xoff_sent && !xoff_received)
- {
- xoff_sent = TRUE;
- while ((inbyte ((XON_PORT_address + LSR)) & 0x20) == 0)
- ;
- outbyte (XON_PORT_address + IER, XON_PORT_command = RX_TX_enable);
- outbyte (XON_PORT_address, XOFF_char);
- }
- break;
-
- case IIR_transmit:
- if (xoff_sent && (queue_avail (xon8250_inqueue) > 20))
- {
- xoff_sent = FALSE;
- outbyte (XON_PORT_address, XON_char);
- }
- else
- if (xoff_received)
- outbyte (XON_PORT_address + IER, XON_PORT_command = RX_enable);
- else
- if ((ch = de_queue (xon8250_outqueue)) != -1)
- {
- outbyte (XON_PORT_address, ch);
- }
- else
- {
- outbyte (XON_PORT_address + IER, XON_PORT_command = RX_enable);
- }
- break;
-
- case IIR_mstatus:
- test_status = inbyte ((XON_PORT_address + MSR));
- break;
- }
- } while ((test_status = inbyte (XON_PORT_address + IIR)) != IIR_complete);
- disable ();
- outbyte (INT_cntrl, EOI_word);
- #if (defined (DLC))
- return (1);
- #endif
- }
-
-
-
-
- /*
- * XON8250_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
- * xon8250_isr routine to the interrupt and
- * return the rt returned index for saving - it's
- * needed to terminate the interrupt.
- */
-
- #define XON8250_STACK_SIZE 512
- int xon8250_intno;
- static int xon_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 xon_intno [] = { 12, 11, 12, 11 };
- /*
- * The above interrupt number array is based on the algorithm
- * xon8250_intno = (13 - PORT_channel);
- */
-
-
- int
- xon8250_init (int channel, int buffer_size)
- {
- int Dos_address, mask;
- XON_PORT_channel = channel;
- xon8250_inqueue = alloc_queue (buffer_size);
- xon8250_outqueue = alloc_queue (buffer_size);
- Dos_address = (XON_PORT_channel - 1) * 2;
- peekmem (0x40, Dos_address, XON_PORT_address);
- mask = xon_intmask [XON_PORT_channel-1];
- SAVE_int_mask = inbyte (INT_mask);
- mask &= SAVE_int_mask;
- xon8250_intno = xon_intno [XON_PORT_channel-1];
- LCR_save = inbyte (XON_PORT_address + LCR);
- disable ();
- outbyte (XON_PORT_address + LCR, LCR_save | LCR_DLAB);
- MCR_save = inbyte (XON_PORT_address + MCR);
- DL_lsb = inbyte (XON_PORT_address);
- DL_msb = inbyte (XON_PORT_address + 1);
- outbyte (XON_PORT_address + LCR, LCR_save & 0x7F);
- IER_save = inbyte (XON_PORT_address + IER);
- enable ();
- #if (defined (DLC))
- int_intercept (xon8250_intno, &xon8250_isr, XON8250_STACK_SIZE);
- #else
- xon_save_vec = getvect (xon8250_intno);
- setvect (xon8250_intno, xon8250_isr);
- #endif
- DELAY_init ();
- outbyte (INT_mask, mask);
- }
-
-
-
-
- /*
- * XON8250_TERM - This routine restores the rs232xon 8250 back to its
- * state before xon8250_INIT was called and releases the
- * corresponding interrupt back to the system.
- */
-
- void
- xon8250_term (int restore)
- {
- disable ();
- outbyte (INT_mask, SAVE_int_mask);
- if (restore)
- {
- outbyte (XON_PORT_address + LCR, LCR_DLAB);
- outbyte (XON_PORT_address, DL_lsb);
- outbyte (XON_PORT_address + 1, DL_msb);
- outbyte (XON_PORT_address + MCR, MCR_save);
- outbyte (XON_PORT_address + LCR, 0x7F);
- outbyte (XON_PORT_address + IER, IER_save);
- outbyte (XON_PORT_address + LCR, LCR_save);
- }
- #if (defined (DLC))
- int_restore (xon8250_intno);
- #else
- setvect (xon8250_intno, xon_save_vec);
- #endif
- }
-
-
-
-
- /*
- * XON8250_READ - this routine looks in the xon8250_inqueue for a character
- */
-
- int
- xon8250_read (void)
- {
- int ch;
- disable ();
- ch = de_queue (xon8250_inqueue);
- enable ();
- if ((XON_PORT_command == RX_enable) &&
- ((!queue_empty (xon8250_outqueue)) || xoff_sent))
- outbyte (XON_PORT_address + IER, XON_PORT_command = RX_TX_enable);
- return (ch);
- }
-
-
-
-
- /*
- * XON8250_TIMED_READ - attempts to read rs232 port - if no char
- * available in number of seconds passed
- * returns -1
- */
-
- int
- xon8250_timed_read (int sec)
- {
- int ch;
-
- timer_set ();
- while ((ch = xon8250_read ()) == -1)
- if ((timer_read () / 18) > sec)
- break;
- return (ch);
- }
-
-
-
-
- /*
- * XON8250_WRITE - plain vanilla write to the port - check to see that
- * the chip may need a kick in the pants before returning
- */
-
- int
- xon8250_write (char ch)
- {
- int rval = -1;
- disable ();
- rval = en_queue (xon8250_outqueue, ch);
- enable ();
- if (XON_PORT_command != RX_TX_enable)
- outbyte (XON_PORT_address + IER, XON_PORT_command = RX_TX_enable);
- return (rval);
- }
-
-
-
-
- /*
- * XON8250_DTRNR - drop Data Terminal Ready Line
- */
- void
- xon8250_dtnr (void)
- {
- char mcr_save;
- disable ();
- mcr_save = inbyte (XON_PORT_address + MCR);
- outbyte (XON_PORT_address + MCR, 0);
- DELAY_loop (500);
- outbyte (XON_PORT_address + MCR, mcr_save);
- enable ();
- }
-
-
-
-
- /*
- * XON8250_GET_STATUS - returns the current rs232xon status and
- * resets any error condition.
- */
-
- int
- xon8250_get_status (void)
- {
- char rval = XON_PORT_status;
- XON_PORT_status &= ERROR_reset;
- return ((int) rval);
- }
-
-
-
-
- /*
- * XON8250_XOFF_SENT - did we send an Xoff char?
- */
-
- int
- xon8250_xoff_sent (void)
- {
- return (xoff_sent);
- }
-
-
-
-
-
- /*
- * XON8250_WRITE_BUFFER_EMPTY
- */
-
- xon8250_write_buffer_empty (void)
- {
- return (queue_empty (xon8250_outqueue));
- }
-
-
-
-
-
- /*
- * IOCTL_SET_XOFF
- * sets the rs232 xon/xoff protocol. It accepts a command string
- * of the form
- * "y n" or "n n" or "n y" or "y y" either upper or
- * lower case.
- * The 1st char enables or disables xon/xoff receive...
- * the 2d char enables or disables xon/xoff transmit
- */
-
- int
- ioctl_set_xoff (char *cmd)
- {
- char temp;
- char xrcv[2];
- sscanf (cmd, "%1s", xrcv);
- disable ();
- xoff_enabled = (toupper (*xrcv) == 'Y') ? TRUE : FALSE;
- enable ();
- }
-
-
-
-
- /*
- * XON8250_WRITE_BREAK - Write a BREAK Character
- */
-
- void
- xon8250_write_break (void)
- {
- int i;
- disable ();
- while ((inbyte (XON_PORT_address + LSR) & 0x40) == 0)
- ;
- outbyte (XON_PORT_address + LCR, inbyte (XON_PORT_address + LCR) | 0x40);
- DELAY_loop (500);
- outbyte (XON_PORT_address + LCR, inbyte (XON_PORT_address + LCR) & 0xBF);
- enable ();
- }
-
-
-
-
-
- /*
- * XON8250_XON_PORT_INIT (Cmd) configures the 8250
- * cmd is a string of the form baud parity stop data xon/xoff... i.e.
- * 300 n 1 8 y
- *
- * baud - 300, 600, 1200, 2400, 4800, 9600, 19200
- * 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
- */
-
- int
- xon8250_port_init (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 = 1;
- break;
- case 'O':
- parity = 3;
- 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 ();
- xoff_received = FALSE;
- outbyte (XON_PORT_address + LCR, inbyte (XON_PORT_address + LCR) | LCR_DLAB);
- outbyte (XON_PORT_address, baud % 256);
- outbyte (XON_PORT_address + 1, baud / 256);
- outbyte (XON_PORT_address + LCR, mode_word & 0x7F);
- outbyte (XON_PORT_address + IER, XON_PORT_command = RX_enable);
- outbyte (XON_PORT_address + MCR, 0x0F);
-
- inbyte (XON_PORT_address + LSR);
- inbyte (XON_PORT_address + MSR);
- inbyte (XON_PORT_address);
- enable ();
- }
-
-
-
-
- /*---------------------- xon8250_port_enable () ----------------------*/
- /*
- *
- */
- void
- xon8250_port_enable (void)
- {
- disable ();
- outbyte (XON_PORT_address + IER, XON_PORT_command = RX_enable);
- outbyte (XON_PORT_address + MCR, 0x0F);
-
- inbyte (XON_PORT_address + LSR);
- inbyte (XON_PORT_address + MSR);
- inbyte (XON_PORT_address);
- enable ();
- }
-