home *** CD-ROM | disk | FTP | other *** search
- /*
- CPPTask - A Multitasking Kernel For C++
-
- Version 1.0 08-12-91
-
- Ported by Rich Smith from:
-
- Public Domain Software written by
- Thomas Wagner
- Patschkauer Weg 31
- D-1000 Berlin 33
- West Germany
-
- TSKSIO.CPP - Serial I/O interface routines.
-
- Subroutines:
- sioint3
- sioint4
- commport::chng_rts
- commport::transmit_ready
- commport::modem_status_int
- commport::receive_ready
- commport::sioint
- commport::commport
- commport::~commport
- commport::change_rts
- commport::change_dtr
- commport::change_baud
- commport::change_parity
- commport::change_wordlength
- commport::change_stopbits
- commport::watch_modem
- commport::protocol
- commport::send
- commport::receive
- commport::rcv_overrun
- commport::check
- commport::modem_status
- commport::complete
- commport::wait_complete
- commport::flush_receive
-
- The tables used are:
-
- port_list The pointer to the list of defined ports. Newly
- defined ports are added to the end of the list.
- Ports can never be deleted. Each port descriptor
- contains the hardware info for the port, plus a
- pointer to the associated sio-control-block if the
- port was initialized.
-
- port_last The pointer to the last element in port_list.
-
- irq_array Is an array of pointers to sio-control-blocks. For
- each possible IRQ-line the entry in this table points
- to the first block active for this line. If the IRQ
- is shared, sio-blocks are chained into this list via
- their "next" pointer.
-
- irq_procs Contains the pointer to the interrupt handler function
- for the corresponding IRQ-line.
-
- port_descr Contains the statically defined port descriptor blocks.
-
- NOTE: You can not dynamically define ports for IRQ-lines that
- have no interrupt handler function defined. To be completely
- flexible, you would have to define sioint-handlers for all
- possible IRQs and enter the addresses into the irq_procs array.
-
- CAUTION: Please restrict the installation and removal of comm-
- ports to *one* task. The manipulation of the lists is
- not protected, so simultaneous install/remove calls
- may cause trouble. Since ports are normally installed and
- removed in the main task, the protection of critical regions
- seemed unnecessary.
-
- CAUTION: Shared interrupt logic and IRQ-lines above 4 were not
- tested due to the lack of suitable hardware. Changes may
- be necessary in the handling of the modem control register
- OUT2 line that normally controls interrupt enable, depending
- on the multiport-hardware installed in the target system.
-
- */
-
- #include "task.hpp"
- #include "sio.hpp"
-
- #define MAX_IRQ 16 /* Maximum number of interrupt lines,
- 16 for AT, 8 for XT. Can be left at 16 */
-
- #define CHAIN_IRQBIT 0x04 /* Chained int controller IRQ bit */
-
- #define RESTORE_DEFAULT 1 /* Restore parameter for remove_all */
-
- #define RTS 0x02
- #define DTR 0x01
- #define OUT2 0x08
-
- #define ERR_MASK 0x1e
-
- #define inta00 0x20 /* 8259 interrupt controller control-port */
- #define inta01 0x21 /* 8259 interrupt controller mask-port */
-
- #define inta10 0xa0 /* secondary 8259 control-port for IRQ 8-15 */
- #define inta11 0xa1 /* secondary 8259 mask-port for IRQ 8-15 */
-
- #define rdserv 0x0b /* read service register control value */
- #define eoi 0x20 /* end of interrupt signal for 8259 */
-
- #define intdata 0x0b /* Enable Interrupts except Line status */
-
- #define rxreadybit 0x01
- #define txemptybit 0x40
- #define txreadybit 0x20
- #define framingbit 0x08
- #define breakbit 0x10
-
- /* Note: In version 1.1, port offsets start at 0, not 8 */
-
- #define linecontrol 0x03
- #define linestatus 0x05
- #define intid 0x02
- #define intenable 0x01
- #define modemcontrol 0x04
- #define modemstatus 0x06
- #define receivedata 0x00
- #define transmitdata 0x00
-
- #define baudreg_dll 0x00 /* baud rate least significant byte */
- #define baudreg_dlm 0x01 /* baud rate most significant byte */
-
- /*
- Default values for initialising the ports.
- Change to your liking (but remember that OUT2 must be set in the
- modem control register to allow interrupts to come through with
- normal controllers).
- */
-
- #define dflt_modcon 0x0b /* Modem Control: Activate DTR, RTS, OUT2 */
- #define dflt_baud 96 /* Baud Rate Divisor: 1200 Baud */
- #define dflt_lcon 0x03 /* Line Control: No Parity, 1 Stop, 8 Data */
-
- /*
- Defined baud rates. You may expand this table with non-standard
- rates if desired.
- */
-
- local long baud_table [] = {
- 50L, 2304L,
- 75L, 1536L,
- 110L, 1047L,
- 134L, 857L,
- 150L, 768L,
- 300L, 384L,
- 600L, 192L,
- 1200L, 96L,
- 1800L, 64L,
- 2000L, 58L,
- 2400L, 48L,
- 3600L, 32L,
- 4800L, 24L,
- 7200L, 16L,
- 9600L, 12L,
- 19200L, 6L,
- 38400L, 3L,
- 0L, 0L };
-
- local byte force_transmit_ready; /* flag to indicate
- transmitter needs service */
-
- /*-------------------------------------------------------------------------*/
-
- /*
- To add static support for other COM-Ports, define
- - Port base
- - IRQ-Line
- - Interrupt vector
- here, and add the necessary data to the port_descr array.
- If the port does *not* share an IRQ with the predefined ports,
- define the corresponding interrupt function by duplicating siointx,
- and place the entry for this function into the irq_procs array.
-
- */
-
- #define STATIC_PORTS 2 /* Number of statically defined ports */
-
- /* Note: In version 1.1, port offsets start at 0, not 8 */
-
- #define com1_base 0x3f8 /* COM1 port base */
- #define com2_base 0x2f8 /* COM2 port base */
-
- #define com1_irq 4 /* IRQ-Line for COM1 */
- #define com2_irq 3 /* IRQ-Line for COM2 */
-
- #define com1_vect 0x0c /* Interrupt vector for COM1 */
- #define com2_vect 0x0b /* Interrupt vector for COM2 */
-
- /*-------------------------------------------------------------------------*/
-
-
- typedef void (interrupt far * intprocptr)(void);
-
- void interrupt far sioint3 (void);
- void interrupt far sioint4 (void);
-
- /*
- Table of Interrupt handler functions for each IRQ line.
- */
-
- local intprocptr irq_procs [MAX_IRQ] = { NULL, /* IRQ 0 */
- NULL, /* IRQ 1 */
- NULL, /* IRQ 2 */
- (intprocptr)sioint3, /* IRQ 3 */
- (intprocptr)sioint4, /* IRQ 4 */
- NULL, /* IRQ 5 */
- NULL, /* IRQ 6 */
- NULL, /* IRQ 7 */
- NULL, /* IRQ 8 */
- NULL, /* IRQ 9 */
- NULL, /* IRQ 10 */
- NULL, /* IRQ 11 */
- NULL, /* IRQ 12 */
- NULL, /* IRQ 13 */
- NULL, /* IRQ 14 */
- NULL }; /* IRQ 15 */
-
-
- /* When adding entries to port_descr, be sure to chain the
- elements in ascending order via the first field, and to
- increase the internal port number in the second field. */
-
- local port_data port_descr [STATIC_PORTS] = {
- { &port_descr[1], 0, NULL, com1_base, com1_irq, com1_vect },
- { NULL, 1, NULL, com2_base, com2_irq, com2_vect }
- };
-
- local commptr irq_array [MAX_IRQ] = { NULL };
-
- local portptr port_list = &port_descr [0];
- local portptr port_last = &port_descr [1];
-
- local int ports = STATIC_PORTS;
-
- extern funcptr v24_remove_func;
-
- /*-------------------------------------------------------------------------*/
-
-
- void commport::chng_rts (int on)
- {
- rtsoff = (byte)(!on);
- cmodcontrol = (cmodcontrol & ~RTS) | ((on) ? RTS : 0);
- tsk_outp (port_base + modemcontrol, cmodcontrol);
- }
-
-
- void commport::transmit_ready (void)
- {
- int i;
-
- force_transmit_ready = 0;
-
- if ((i = r_xoff) < 0)
- {
- tsk_outp (port_base + transmitdata, (i == -1) ? XOFF : XON);
- r_xoff = (i == -1) ? 1 : 0;
- xmit_pending = 1;
- return;
- }
-
- xmit_pending = 0;
-
- if (!(wait_xmit = (byte)(xmit_pipe.check_pipe () != -1)))
- return;
-
- if ((modem_flags & modstat) ^ modem_flags)
- return;
-
- if (flags & XONXOFF && t_xoff)
- return;
-
- wait_xmit = 0;
-
- if ((i = xmit_pipe.c_read_pipe ()) < 0)
- return;
-
- tsk_outp (port_base + transmitdata, (byte)i);
- xmit_pending = 1;
- }
-
-
- void commport::modem_status_int (void)
- {
- modstat = tsk_inp (port_base + modemstatus);
-
- if (wait_xmit)
- transmit_ready ();
- }
-
-
- void commport::receive_ready (void)
- {
- word status;
- word ch;
-
- while ((status = tsk_inp (port_base + linestatus)) & rxreadybit)
- {
- /* Correct for possible loss of transmit interrupt from IIR register */
- if (status & txreadybit)
- force_transmit_ready = 1;
-
- tsk_nop ();
- ch = tsk_inp (port_base + receivedata);
-
- if (flags & XONXOFF)
- {
- if (ch == XON)
- {
- t_xoff = 0;
- if (wait_xmit)
- transmit_ready ();
- continue;
- }
- else if (ch == XOFF)
- {
- t_xoff = 1;
- continue;
- }
- if (!r_xoff &&
- rcv_pipe.wpipe_free () < xoff_threshold)
- {
- r_xoff = -1;
- if (!xmit_pending)
- transmit_ready ();
- }
- }
-
- if (flags & RTSCTS && !rtsoff)
- if (rcv_pipe.wpipe_free () < xoff_threshold)
- chng_rts (0);
-
- status = (status & ERR_MASK) << 8;
- if (rcv_pipe.c_write_wpipe (ch | status) < 0)
- overrun = 1;
- }
- }
-
-
- /*-------------------------------------------------------------------------*/
-
-
- void commport::sioint (void)
- {
- int id;
-
- force_transmit_ready = 0;
-
- while (!((id = tsk_inp (port_base + intid)) & 1))
- switch (id & 0x07)
- {
- case 0x00: modem_status_int ();
- break;
-
- case 0x02: transmit_ready ();
- break;
-
- case 0x04: receive_ready ();
- break;
-
- /* case 0x06: line_status_int (); (currently not used)
- break;
- */
- }
- if (force_transmit_ready)
- transmit_ready ();
- }
-
-
- void interrupt far sioint3 (void)
- {
- commptr curr;
-
- tsk_sti ();
- for (curr = irq_array [3]; curr != NULL; curr = curr->next)
- curr->sioint ();
-
- tsk_cli ();
- /* NOTE: for IRQ's 8-15, add the following here:
- tsk_outp (inta10, eoi);
- */
- tsk_outp (inta00, eoi);
- }
-
-
- void interrupt far sioint4 (void)
- {
- commptr curr;
-
- tsk_sti ();
- for (curr = irq_array [4]; curr != NULL; curr = curr->next)
- curr->sioint ();
-
- tsk_cli ();
- /* NOTE: for IRQ's 8-15, add the following here:
- tsk_outp (inta10, eoi);
- */
- tsk_outp (inta00, eoi);
- }
-
- /*-------------------------------------------------------------------------*/
-
- commport::commport (int portnum, int init,
- farptr rcvbuf, word rcvsize,
- farptr xmitbuf, word xmitsize)
- :xmit_pipe(xmitbuf, xmitsize), rcv_pipe(rcvbuf, rcvsize)
- {
- portptr portp;
- int pbase;
- intprocptr far *intptr;
- int i, inta;
-
- if (port < 0 || !rcvsize || !xmitsize)
- return;
-
- portp = port_list;
-
- if (portnum & 0x80) /* Relative port number */
- {
- portnum &= 0x7f;
- if (portnum > 4)
- return;
- pbase = *((wordptr)(MK_FP (0x40, portnum * 2)));
- if (!pbase)
- return;
-
- for (portnum = 0; portnum < ports; portnum++, portp = portp->next)
- if (portp->base == pbase)
- break;
-
- if (portnum >= ports)
- return;
- }
- else
- {
- if (portnum > ports)
- return;
- for (i = 0; i < portnum; i++)
- portp = portp->next;
- }
-
- if (portp->sio != NULL) /* Port already in use ? */
- return;
-
- portp->sio = this;
-
- pbase = port_base = portp->base;
- port = portp;
-
- /* Check if port accessible by modifying the modem control register */
-
- i = cmodcontrol = save_mcon = tsk_inp (pbase + modemcontrol);
- if (i & 0xe0)
- {
- port->sio = NULL;
- return;
- }
- tsk_nop ();
- tsk_outp (pbase + modemcontrol, 0xe0 | i);
- tsk_nop ();
- if (tsk_inp (pbase + modemcontrol) != (byte) i)
- {
- port->sio = NULL;
- return;
- }
-
- /* Port seems OK */
-
- civect = portp->vector;
- irqbit = (byte)(1 << (portp->irq & 0x07));
-
- wait_xmit = xmit_pending = 0;
- overrun = 0;
- flags = 0;
- modem_flags = 0;
- r_xoff = t_xoff = 0;
- rtsoff = 0;
- restore = 1;
-
- clcontrol = save_lcon = tsk_inp (pbase + linecontrol);
- tsk_nop ();
- save_inten = tsk_inp (pbase + intenable);
- tsk_nop ();
-
- if (init)
- {
- clcontrol = dflt_lcon;
- cmodcontrol = dflt_modcon;
- }
-
- tsk_outp (pbase + linecontrol, clcontrol | 0x80);
- tsk_nop ();
- save_bd1 = tsk_inp (pbase + baudreg_dll);
- tsk_nop ();
- save_bd2 = tsk_inp (pbase + baudreg_dlm);
- tsk_nop ();
- tsk_outp (pbase + linecontrol, clcontrol);
- tsk_nop ();
-
- tsk_outp (pbase + intenable, 0);
-
- if (irq_array [portp->irq] == NULL)
- {
- intptr = (intprocptr far *)MK_FP (0, civect * 4);
- tsk_cli ();
- savvect = *intptr;
- *intptr = irq_procs [portp->irq];
- tsk_sti ();
- }
-
- if (init)
- {
- tsk_outp (pbase + linecontrol, dflt_lcon | 0x80);
- tsk_nop ();
- tsk_outp (pbase + baudreg_dll, dflt_baud);
- tsk_nop ();
- tsk_outp (pbase + baudreg_dlm, dflt_baud >> 8);
- tsk_nop ();
- tsk_outp (pbase + linecontrol, dflt_lcon);
- tsk_nop ();
- tsk_outp (pbase + modemcontrol, dflt_modcon);
- tsk_nop ();
- }
- else
- {
- i = tsk_inp (pbase + modemcontrol) | OUT2;
- tsk_nop ();
- tsk_outp (pbase + modemcontrol, i);
- tsk_nop ();
- }
-
- while (tsk_inp (pbase + linestatus) & rxreadybit)
- {
- tsk_nop ();
- tsk_inp (pbase + receivedata);
- tsk_nop ();
- }
- tsk_nop ();
-
- tsk_inp (pbase + linestatus);
- tsk_nop ();
- modstat = tsk_inp (pbase + modemstatus);
- tsk_nop ();
- tsk_inp (pbase + intid);
- tsk_nop ();
-
- inta = (portp->irq > 7) ? inta11 : inta01;
-
- if (irq_array [portp->irq] == NULL)
- {
- if (portp->irq > 7)
- {
- i = tsk_inp (inta01) & ~CHAIN_IRQBIT;
- tsk_nop ();
- tsk_outp (inta01, i);
- }
-
- save_irq = (byte)((i = tsk_inp (inta)) & irqbit);
- tsk_nop ();
- tsk_outp (inta, i & ~irqbit);
- }
- else
- save_irq = (irq_array [portp->irq])->save_irq;
-
- tsk_cli ();
- next = irq_array [portp->irq];
- irq_array [portp->irq] = this;
- tsk_sti ();
-
- /* Enable interrupts with correction for possible loss of the
- first tranmit interrupt on INS8250 and INS8250-B chips */
- for (;;)
- {
- if (tsk_inp (pbase + linestatus) & txreadybit)
- {
- break;
- }
- tsk_nop ();
- }
-
- tsk_nop ();
- tsk_cli ();
- tsk_outp (pbase + intenable, intdata);
- tsk_nop ();
- tsk_outp (pbase + intenable, intdata);
- tsk_sti ();
-
- }
-
-
- commport::~commport ()
- {
- intprocptr far *intptr;
- int pbase, i, inta;
- portptr portp;
- commptr curr, last;
-
- pbase = port_base;
- portp = port;
-
- last = NULL;
- curr = irq_array [portp->irq];
- while (curr != this && curr != NULL)
- {
- last = curr;
- curr = curr->next;
- }
- if (curr == NULL)
- return;
-
- tsk_outp (pbase + intenable, 0);
- tsk_cli ();
- if (last == NULL)
- irq_array [portp->irq] = next;
- else
- last->next = next;
- tsk_sti ();
-
- inta = (portp->irq > 7) ? inta11 : inta01;
-
- // ???? this was an input param, now a member that is set in constructor
- if (restore)
- {
- tsk_outp (pbase + modemcontrol, save_mcon);
- tsk_nop ();
- tsk_outp (pbase + linecontrol, save_lcon | 0x80);
- tsk_nop ();
- tsk_outp (pbase + baudreg_dll, save_bd1);
- tsk_nop ();
- tsk_outp (pbase + baudreg_dlm, save_bd2);
- tsk_nop ();
- tsk_outp (pbase + linecontrol, save_lcon);
- tsk_nop ();
- if (irq_array [portp->irq] == NULL)
- {
- tsk_cli ();
- tsk_outp (pbase + intenable, save_inten);
- i = tsk_inp (inta) & ~irqbit;
- tsk_nop ();
- tsk_outp (inta, i | save_irq);
- }
- }
- else if (irq_array [portp->irq] == NULL)
- {
- tsk_cli ();
- i = tsk_inp (inta) | irqbit;
- tsk_nop ();
- tsk_outp (inta, i);
- }
-
- if (irq_array [portp->irq] == NULL)
- {
- tsk_cli ();
- intptr = (intprocptr far *)MK_FP (0, civect * 4);
- *intptr = (intprocptr)savvect;
- }
- tsk_sti ();
-
- portp->sio = NULL;
- }
-
-
- /*-------------------------------------------------------------------------*/
-
- /*
- void change_rts (int on)
- */
-
- void far commport::change_rts (int on)
- {
- cmodcontrol = (cmodcontrol & ~RTS) | ((on) ? RTS : 0);
- tsk_outp (port_base + modemcontrol, cmodcontrol);
- }
-
- /*
- void change_dtr (int on)
- */
-
- void far commport::change_dtr (int on)
- {
- cmodcontrol = (cmodcontrol & ~DTR) | ((on) ? DTR : 0);
- tsk_outp (port_base + modemcontrol, cmodcontrol);
- }
-
-
- /*
- void far change_baud (int rate)
- */
-
- void far commport::change_baud (long rate)
- {
- int i;
-
- for (i = 0; baud_table [i]; i += 2)
- if (baud_table [i] == rate)
- break;
- if (!(i = (int)baud_table [i + 1]))
- return;
-
- tsk_outp (port_base + linecontrol, clcontrol | (byte)0x80);
- tsk_nop ();
- tsk_outp (port_base + baudreg_dll, (byte)i);
- tsk_nop ();
- tsk_outp (port_base + baudreg_dlm, (byte)(i >> 8));
- tsk_nop ();
- tsk_outp (port_base + linecontrol, clcontrol);
- }
-
-
- void far commport::change_parity (int par)
- {
- clcontrol = (clcontrol & 0xc7) | par;
- tsk_outp (port_base + linecontrol, clcontrol);
- }
-
-
- void far commport::change_wordlength (int len)
- {
- int i;
-
- switch (len)
- {
- case 5: i = 0x00; break;
- case 6: i = 0x01; break;
- case 7: i = 0x02; break;
- case 8: i = 0x03; break;
- default: return;
- }
- clcontrol = (clcontrol & 0xfc) | i;
- tsk_outp (port_base + linecontrol, clcontrol);
- }
-
-
- void far commport::change_stopbits (int n)
- {
- int i;
-
- switch (n)
- {
- case 1: i = 0x00; break;
- case 2: i = 0x04; break;
- default: return;
- }
- clcontrol = (clcontrol & 0xfb) | i;
- tsk_outp (port_base + linecontrol, clcontrol);
- }
-
-
- void far commport::watch_modem (byte flags)
- {
- modem_flags = flags & (CTS | DSR | RI | CD);
- }
-
-
- void far commport::protocol (int prot, word offthresh, word onthresh)
- {
- byte old;
-
- old = flags;
- flags = (byte)prot;
- if (prot)
- {
- if (!offthresh)
- offthresh = 10;
- xoff_threshold = offthresh;
- if (onthresh <= offthresh)
- onthresh = offthresh + 10;
- xon_threshold = onthresh;
- }
-
- if ((old & RTSCTS) != ((byte)prot & RTSCTS))
- {
- chng_rts (1);
- modem_flags = (modem_flags & ~CTS) |
- ((prot & RTSCTS) ? CTS : 0);
- }
-
- if (!(prot & XONXOFF))
- {
- if (r_xoff)
- r_xoff = -2;
- t_xoff = 0;
- }
-
- if (!xmit_pending)
- transmit_ready ();
- }
-
-
- /*-------------------------------------------------------------------------*/
-
-
- int far commport::send (byte ch, dword timeout)
- {
- int res;
-
- if ((res = xmit_pipe.write_pipe (ch, timeout)) < 0)
- return res;
- tsk_cli ();
- if (!xmit_pending)
- transmit_ready ();
- tsk_sti ();
- return 0;
- }
-
-
- int far commport::receive (dword timeout)
- {
- int res;
-
- if ((res = (int)rcv_pipe.read_wpipe (timeout)) < 0)
- return res;
-
- if (!flags)
- return res;
-
- if (rcv_pipe.wpipe_free () > xon_threshold)
- {
- tsk_cli ();
- if (r_xoff)
- {
- r_xoff = -2;
- if (!xmit_pending)
- transmit_ready ();
- }
- tsk_sti ();
-
- if (rtsoff)
- chng_rts (1);
- }
- return res;
- }
-
-
- int far commport::rcv_overrun (void)
- {
- int res;
-
- res = overrun;
- overrun = 0;
- return res;
- }
-
-
- int far commport::check (void)
- {
- return rcv_pipe.check_wpipe ();
- }
-
-
- int far commport::modem_status (void)
- {
- return modstat;
- }
-
-
- int far commport::complete (void)
- {
- return (xmit_pipe.check_pipe () == -1);
- }
-
-
- int far commport::wait_complete (dword timeout)
- {
- return xmit_pipe.wait_pipe_empty (timeout);
- }
-
-
- void far commport::flush_receive (void)
- {
- rcv_pipe.flush_wpipe ();
- }
-