/* TCSIO.C - TCtask - Serial I/O interface routines. V1.1 T.Wagner V1.2 TECON Ltd. 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. sio_data Contains the statically defined sio control blocks. 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 v24- 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 "tsk.h" #include "sio.h" #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 */ typedef void (interrupt * intprocptr)(void); #define RTS 0x02 #define DTR 0x01 #define OUT2 0x08 #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 }; /*-------------------------------------------------------------------------*/ /* 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. Note that ports may also be defined on-line if TSK_DYNAMIC is enabled. */ #define STATIC_PORTS 4 /* 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 com3_base 0x3e8 /* COM3 port base */ #define com4_base 0x2e8 /* COM4 port base */ #define com1_irq 4 /* IRQ-Line for COM1 */ #define com2_irq 3 /* IRQ-Line for COM2 */ #define com3_irq 4 /* IRQ-Line for COM3 */ #define com4_irq 3 /* IRQ-Line for COM4 */ #define com1_vect 0x0c /* Interrupt vector for COM1 */ #define com2_vect 0x0b /* Interrupt vector for COM2 */ #define com3_vect 0x0c /* Interrupt vector for COM3 */ #define com4_vect 0x0b /* Interrupt vector for COM4 */ /*-------------------------------------------------------------------------*/ local void interrupt sioint3 (void); local void interrupt sioint4 (void); local void interrupt sioint5 (void); local void interrupt sioint7 (void); local void interrupt sioint10 (void); local void interrupt sioint11 (void); local void interrupt sioint12 (void); local void interrupt sioint15 (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 */ sioint3, /* IRQ 3 */ sioint4, /* IRQ 4 */ sioint5, /* IRQ 5 */ NULL, /* IRQ 6 */ sioint7, /* IRQ 7 */ NULL, /* IRQ 8 */ NULL, /* IRQ 9 */ sioint10, /* IRQ 10 */ sioint11, /* IRQ 11 */ sioint12, /* IRQ 12 */ NULL, /* IRQ 13 */ NULL, /* IRQ 14 */ sioint15 }; /* IRQ 15 */ local sio_datarec sio_data [STATIC_PORTS]; /* 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 }, { &port_descr[2], 1, NULL, com2_base, com2_irq, com2_vect }, { &port_descr[3], 2, NULL, com3_base, com3_irq, com3_vect }, { NULL, 3, NULL, com4_base, com4_irq, com4_vect } }; local sioptr irq_array [MAX_IRQ] = { NULL }; local portptr port_list = &port_descr [0]; local portptr port_last = &port_descr [3]; local word_s ports = STATIC_PORTS; extern funcptr v24_remove_func; /*----------------------------------------------------------------------*/ local void near change_rts (sioptr data, word_s on) { data->rtsoff = (byte)(!on); data->cmodcontrol = (data->cmodcontrol & ~RTS) | ((on) ? RTS : 0); tsk_outp (data->port_base + modemcontrol, data->cmodcontrol); } /*----------------------------------------------------------------------*/ local void near transmit_ready (sioptr data) { word_s i; //#if (MSC) // word_s temp; //#endif if ((i = data->r_xoff) < 0) { //#if (MSC) // temp = (i == -1) ? XOFF : XON; // tsk_outp (data->port_base + transmitdata, temp); //#else // NOTE: Microsoft C 5.0 generates an "Internal Compiler Error" // when compiling the following statement. tsk_outp (data->port_base + transmitdata, (i == -1) ? XOFF : XON); //#endif data->r_xoff = (i == -1) ? 1 : 0; data->xmit_pending = 1; return; } data->xmit_pending = 0; if (!(data->wait_xmit = (byte)(check_pipe (&data->xmit_pipe) != -1))) return; if ((data->modem_flags & data->modstat) ^ data->modem_flags) return; if (data->flags & XONXOFF && data->t_xoff) return; data->wait_xmit = 0; if ((i = c_read_pipe (&data->xmit_pipe)) < 0) return; tsk_outp (data->port_base + transmitdata, (byte)i); data->xmit_pending = 1; } /*----------------------------------------------------------------------*/ local void near modem_status_int (sioptr data) { data->modstat = tsk_inp (data->port_base + modemstatus); if(data->modstat & 0x22 == 0x22) data->modem_off=1; /* если выключался */ if (data->wait_xmit) transmit_ready (data); } /*----------------------------------------------------------------------*/ local void near receive_ready (sioptr data) { byte ch; while (tsk_inp (data->port_base + linestatus) & rxreadybit) { /*** tsk_nop (); это мешает обработке IRQ с более высокими номерами ***/ ch = tsk_inp (data->port_base + receivedata); if (data->flags & XONXOFF) { if (ch == XON) { data->t_xoff = 0; if (data->wait_xmit) transmit_ready (data); continue; } else if (ch == XOFF) { data->t_xoff = 1; continue; } if (!data->r_xoff && pipe_free (&data->rcv_pipe) < (word)data->xoff_threshold) { data->r_xoff = -1; if (!data->xmit_pending) transmit_ready (data); } } if (data->flags & RTSCTS && !data->rtsoff) if (pipe_free (&data->rcv_pipe) < (word)data->xoff_threshold) change_rts (data, 0); if (c_write_pipe (&data->rcv_pipe, ch) < 0) data->overrun = 1; } } /*-------------------------------------------------------------------------*/ local void near sioint (sioptr data) { word_s id; while (!((id = tsk_inp (data->port_base + intid)) & 1)) switch (id & 0x07) { case 0x00: modem_status_int (data); break; case 0x02: transmit_ready (data); break; case 0x04: receive_ready (data); break; } } /*----------------------------------------------------------------------*/ local void interrupt sioint3(void) { sioptr curr; tsk_sti (); for (curr=irq_array[3]; curr != NULL; curr=curr->next) sioint(curr); /*** tsk_cli (); ***/ tsk_outp (inta00, eoi); } /*----------------------------------------------------------------------*/ local void interrupt sioint4(void) { sioptr curr; tsk_sti (); for (curr=irq_array[4]; curr != NULL; curr=curr->next) sioint (curr); /*** tsk_cli (); ***/ tsk_outp (inta00, eoi); } /*-------------------------------------------------------------------------*/ local void interrupt sioint5(void) { sioptr curr; tsk_sti (); for (curr=irq_array[5]; curr != NULL; curr=curr->next) sioint (curr); /*** tsk_cli (); ***/ tsk_outp (inta00, eoi); } /*-------------------------------------------------------------------------*/ local void interrupt sioint7(void) { sioptr curr; tsk_sti (); for (curr=irq_array[7]; curr != NULL; curr=curr->next) sioint (curr); /*** tsk_cli (); ***/ tsk_outp (inta00, eoi); } /*-------------------------------------------------------------------------*/ local void interrupt sioint10(void) { sioptr curr; tsk_sti (); for (curr=irq_array[10]; curr != NULL; curr=curr->next) sioint (curr); /*** tsk_cli (); ***/ tsk_outp (inta10, eoi); tsk_outp (inta00, eoi); } /*-------------------------------------------------------------------------*/ local void interrupt sioint11(void) { sioptr curr; tsk_sti (); for (curr=irq_array[11]; curr != NULL; curr=curr->next) sioint (curr); /*** tsk_cli (); ***/ tsk_outp (inta10, eoi); tsk_outp (inta00, eoi); } /*-------------------------------------------------------------------------*/ local void interrupt sioint12(void) { sioptr curr; tsk_sti (); for (curr=irq_array[12]; curr != NULL; curr=curr->next) sioint (curr); /*** tsk_cli (); ***/ tsk_outp (inta10, eoi); tsk_outp (inta00, eoi); } /*-------------------------------------------------------------------------*/ local void interrupt sioint15(void) { sioptr curr; tsk_sti (); for (curr=irq_array[15]; curr != NULL; curr=curr->next) sioint (curr); /*** tsk_cli (); ***/ tsk_outp (inta10, eoi); tsk_outp (inta00, eoi); } /*-------------------------------------------------------------------------*/ word_s v24_define_port (word_s base, byte irq, byte vector) { #if (TSK_DYNAMIC) portptr portp; if (irq >= MAX_IRQ) return -1; if (irq_procs [irq] == NULL) return -1; if ((portp = tsk_alloc (sizeof (port_data))) == NULL) return -1; portp->pnum = ports; portp->base = base; portp->irq = irq; portp->vector = vector; portp->next = NULL; portp->sio = NULL; if (port_list == NULL) port_list = portp; else port_last->next = portp; port_last = portp; ports++; return portp->pnum; #else return -1; #endif } /*----------------------------------------------------------------------*/ local sioptr ret_error (sioptr sio) { sio->port->sio = NULL; #if (TSK_DYNAMIC) if (sio->port->pnum >= STATIC_PORTS) tsk_free (sio); #endif return NULL; } /*----------------------------------------------------------------------*/ sioptr v24_install (word_s port, word_s init, nearptr rcvbuf, word rcvsize, nearptr xmitbuf, word xmitsize) { sioptr sio; portptr portp; word pbase; // intprocptr *intptr; word_s i, inta; #if (TSK_NAMEPAR) static char xname [] = "SIOnXMIT", rname [] = "SIOnRCV"; xname [3] = rname [3] = (char)(port & 0x7f) + '0'; #endif if (port < 0 || !rcvsize || !xmitsize) return NULL; portp = port_list; if (port & 0x80) /* Relative port number */ { port &= 0x7f; if (port > 4) return NULL; pbase = *((wordptr)(0x400+port * 2)); if (!pbase) return NULL; for (port = 0; port < ports; port++, portp = portp->next) if (portp->base == pbase) break; if (port >= ports) return NULL; } else { if (port > ports) return NULL; for (i=0; inext; } if (portp->sio != NULL) /* Port already in use ? */ return NULL; if (port < STATIC_PORTS) portp->sio = sio = &sio_data [port]; else #if (TSK_DYNAMIC) if ((portp->sio = sio = tsk_alloc (sizeof (sio_datarec))) == NULL) return NULL; #else return NULL; #endif pbase = sio->port_base = portp->base; sio->port = portp; /* Check if port accessible by modifying the modem control register */ i = sio->cmodcontrol = sio->save_mcon = tsk_inp (pbase + modemcontrol); /* if (i & 0xe0) */ if (i & 0xc0) return ret_error (sio); tsk_nop (); tsk_outp (pbase + modemcontrol, /* 0xe0 */ 0xc0 | i); tsk_nop (); if (tsk_inp (pbase + modemcontrol) != (byte) i) return ret_error (sio); /* Port seems OK */ if (create_pipe (&sio->xmit_pipe, xmitbuf, xmitsize #if (TSK_NAMEPAR) , xname #endif ) == NULL) return ret_error (sio); if (create_pipe (&sio->rcv_pipe, rcvbuf, rcvsize #if (TSK_NAMEPAR) , rname #endif ) == NULL) { delete_pipe (&sio->xmit_pipe); return ret_error (sio); } sio->civect = portp->vector; sio->irqbit = (byte)(1 << (portp->irq & 0x07)); sio->wait_xmit = sio->xmit_pending = 0; sio->overrun = 0; sio->flags = 0; sio->modem_flags = 0; sio->r_xoff = sio->t_xoff = 0; sio->rtsoff = 0; sio->clcontrol = sio->save_lcon = tsk_inp (pbase + linecontrol); tsk_nop (); sio->save_inten = tsk_inp (pbase + intenable); tsk_nop (); if (init) { sio->clcontrol = dflt_lcon; sio->cmodcontrol = dflt_modcon; } tsk_outp (pbase + linecontrol, sio->clcontrol | 0x80); tsk_nop (); sio->save_bd1 = tsk_inp (pbase + baudreg_dll); tsk_nop (); sio->save_bd2 = tsk_inp (pbase + baudreg_dlm); tsk_nop (); tsk_outp (pbase + linecontrol, sio->clcontrol); tsk_nop (); tsk_outp (pbase + intenable, 0); if (irq_array [portp->irq] == NULL) { sio->savvect=get_vect_d (sio->civect); set_vect_d(sio->civect,irq_procs [portp->irq]); // intptr = (intprocptr *)(sio->civect * 4); // tsk_cli (); // sio->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 (); sio->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); } sio->save_irq = (byte)((i = tsk_inp (inta)) & sio->irqbit); tsk_nop (); tsk_outp (inta, i & ~sio->irqbit); } else sio->save_irq = (irq_array [portp->irq])->save_irq; tsk_cli (); sio->next = irq_array [portp->irq]; irq_array [portp->irq] = sio; tsk_sti (); v24_remove_func = (funcptr)v24_remove_all; tsk_outp (pbase + intenable, intdata); return sio; } /*----------------------------------------------------------------------*/ void v24_remove (sioptr sio, word_s restore) { // intprocptr *intptr; word_s pbase, i, inta; portptr portp; sioptr curr, last; pbase = sio->port_base; portp = sio->port; last = NULL; curr = irq_array [portp->irq]; while (curr != sio && 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] = sio->next; else last->next = sio->next; tsk_sti (); inta = (portp->irq > 7) ? inta11 : inta01; if (restore) { tsk_outp (pbase + modemcontrol, sio->save_mcon); tsk_nop (); tsk_outp (pbase + linecontrol, sio->save_lcon | 0x80); tsk_nop (); tsk_outp (pbase + baudreg_dll, sio->save_bd1); tsk_nop (); tsk_outp (pbase + baudreg_dlm, sio->save_bd2); tsk_nop (); tsk_outp (pbase + linecontrol, sio->save_lcon); tsk_nop (); if (irq_array [portp->irq] == NULL) { tsk_cli (); tsk_outp (pbase + intenable, sio->save_inten); i = tsk_inp (inta) & ~sio->irqbit; tsk_nop (); tsk_outp (inta, i | sio->save_irq); } } else if (irq_array [portp->irq] == NULL) { tsk_cli (); i = tsk_inp (inta) | sio->irqbit; tsk_nop (); tsk_outp (inta, i); } if (irq_array [portp->irq] == NULL) { set_vect_d(sio->civect,sio->savvect); // tsk_cli (); // intptr = (intprocptr *)(sio->civect * 4); // *intptr = sio->savvect; } // tsk_sti (); portp->sio = NULL; delete_pipe (&sio->xmit_pipe); delete_pipe (&sio->rcv_pipe); #if (TSK_DYNAMIC) if (portp->pnum >= STATIC_PORTS) tsk_free (sio); #endif } /*----------------------------------------------------------------------*/ void v24_remove_all (void) { word_s i; sioptr sio; for (i = 0; i < MAX_IRQ; i++) { while ((sio = irq_array [i]) != NULL) v24_remove (sio, RESTORE_DEFAULT); } } /*-------------------------------------------------------------------------*/ void v24_change_baud (sioptr sio, long rate) { word_s i; tsk_outp (sio->port_base + intenable, 0); tsk_nop (); for (i = 0; baud_table [i]; i += 2) if (baud_table [i] == rate) break; if (!(i = (word_s)baud_table [i + 1])) return; tsk_outp (sio->port_base + linecontrol, sio->clcontrol | (byte)0x80); tsk_nop (); tsk_outp (sio->port_base + baudreg_dll, (byte)i); tsk_nop (); tsk_outp (sio->port_base + baudreg_dlm, (byte)(i >> 8)); tsk_nop (); tsk_outp (sio->port_base + linecontrol, sio->clcontrol); tsk_nop (); tsk_outp (sio->port_base + intenable, intdata); tsk_nop (); } /*----------------------------------------------------------------------*/ void v24_change_parity (sioptr sio, word_s par) { tsk_outp (sio->port_base + intenable, 0); tsk_nop (); sio->clcontrol = (sio->clcontrol & 0xc7) | par; tsk_outp (sio->port_base + linecontrol, sio->clcontrol); tsk_outp (sio->port_base + intenable, intdata); tsk_nop (); } /*----------------------------------------------------------------------*/ void v24_change_wordlength (sioptr sio, word_s len) { word_s i; tsk_outp (sio->port_base + intenable, 0); tsk_nop (); switch (len) { case 5: i = 0x00; break; case 6: i = 0x01; break; case 7: i = 0x02; break; case 8: i = 0x03; break; default: return; } sio->clcontrol = (sio->clcontrol & 0xfc) | i; tsk_outp (sio->port_base + linecontrol, sio->clcontrol); tsk_nop (); tsk_outp (sio->port_base + intenable, intdata); tsk_nop (); } /*----------------------------------------------------------------------*/ void v24_change_stopbits (sioptr sio, word_s n) { word_s i; tsk_outp (sio->port_base + intenable, 0); tsk_nop (); switch (n) { case 1: i = 0x00; break; case 2: i = 0x04; break; default: return; } sio->clcontrol = (sio->clcontrol & 0xfb) | i; tsk_outp (sio->port_base + linecontrol, sio->clcontrol); tsk_nop (); tsk_outp (sio->port_base + intenable, intdata); tsk_nop (); } /*-------------------------------------------------------------------------*/ word_s v24_send (sioptr sio, byte ch, dword timeout) { word_s res; if ((res = write_pipe (&sio->xmit_pipe, ch, timeout)) < 0) return res; tsk_cli (); if (!sio->xmit_pending) transmit_ready (sio); tsk_sti (); return 0; } /*----------------------------------------------------------------------*/ word_s v24_receive (sioptr sio, dword timeout) { word_s res; if ((res = (word_s)read_pipe (&sio->rcv_pipe, timeout)) < 0) return res; if (!sio->flags) return res; if (pipe_free (&sio->rcv_pipe) > (word)sio->xon_threshold) { tsk_cli (); if (sio->r_xoff) { sio->r_xoff = -2; if (!sio->xmit_pending) transmit_ready (sio); } tsk_sti (); if (sio->rtsoff) change_rts (sio, 1); } return res; } /*----------------------------------------------------------------------*/ word_s v24_check (sioptr sio) { return check_pipe (&sio->rcv_pipe); } /*----------------------------------------------------------------------*/ word_s v24_complete (sioptr sio) { return (check_pipe (&sio->xmit_pipe) == -1); } /*----------------------------------------------------------------------*/ word_s v24_wait_complete (sioptr sio, dword timeout) { return wait_pipe_empty (&sio->xmit_pipe, timeout); } /*----------------------------------------------------------------------*/ void v24_change_rts (sioptr sio, word_s on) { sio->cmodcontrol = (sio->cmodcontrol & ~RTS) | ((on) ? RTS : 0); tsk_outp (sio->port_base + modemcontrol, sio->cmodcontrol); } /*-------------------------------------------------------------------*/ void v24_change_dtr (sioptr sio, word_s on) { sio->cmodcontrol = (sio->cmodcontrol & ~DTR) | ((on) ? DTR : 0); tsk_outp (sio->port_base + modemcontrol, sio->cmodcontrol); } /*-------------------------------------------------------------------*/ void v24_watch_modem (sioptr sio, byte flags) { sio->modem_flags = flags & (CTS | DSR | RI | CD); } /*-------------------------------------------------------------------*/ void v24_protocol (sioptr sio, word_s prot, word offthresh, word onthresh) { byte old; old = sio->flags; sio->flags = (byte)prot; if (prot) { if (!offthresh) offthresh = 10; sio->xoff_threshold = offthresh; if (onthresh <= offthresh) onthresh = offthresh + 10; sio->xon_threshold = onthresh; } if ((old & RTSCTS) != ((byte)prot & RTSCTS)) { change_rts (sio, 1); sio->modem_flags = (sio->modem_flags & ~CTS) | ((prot & RTSCTS) ? CTS : 0); } if (!(prot & XONXOFF)) { if (sio->r_xoff) sio->r_xoff = -2; sio->t_xoff = 0; } if (!sio->xmit_pending) transmit_ready (sio); } /*-------------------------------------------------------------------*/ word_s v24_modem_status (sioptr sio) { return sio->modstat; } /*-------------------------------------------------------------------*/