⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tsksio.c

📁 一个多任务操作系统CTask的源代码 用C语言编写
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
   --- Version 2.2 91-05-17 00:04 ---

   TSKSIO.C - CTask - Serial I/O interface routines.

   Public Domain Software written by
      Thomas Wagner
      Ferrari electronic Gmbh
      Beusselstrasse 27
      D-1000 Berlin 21
      Germany

   With version 1.1, support for shared IRQ lines and dynamically
   defined ports was added. 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.

   With Version 1.2, special interrupt handler functions have been added
   in a separate assembler file, TSKSIOI.ASM. These functions switch to
   a local stack, and then call the sioint-functions defined here, which
   no longer have the interrupt attribute.

*/

#include "tsk.h"
#include "tsklocal.h"
#include "sio.h"

#if (DOS)

#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 TSRE      0x40

#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 both siointx
   here and _tsksio_intx in the TSKSIOI.ASM file, and place the
   entry for the _tsksio_intx function into the irq_procs array.

   Note that ports may also be defined on-line if TSK_DYNAMIC is enabled.
*/

#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 */

/*-------------------------------------------------------------------------*/


extern void interrupt far tsksio_int2 (void);
extern void interrupt far tsksio_int3 (void);
extern void interrupt far tsksio_int4 (void);
extern void interrupt far tsksio_int5 (void);
extern void interrupt far tsksio_int7 (void);
extern void interrupt far tsksio_int10 (void);
extern void interrupt far tsksio_int11 (void);
extern void interrupt far tsksio_int12 (void);
extern void interrupt far tsksio_int15 (void);

/* 
   Table of Interrupt handler functions for each IRQ line.
*/

local intprocptr irq_procs [MAX_IRQ] = {  LNULL,         /* IRQ 0 */
                                          LNULL,         /* IRQ 1 */
                                          tsksio_int2,   /* IRQ 2 */
                                          tsksio_int3,   /* IRQ 3 */
                                          tsksio_int4,   /* IRQ 4 */
                                          tsksio_int5,   /* IRQ 5 */
                                          LNULL,         /* IRQ 6 */
                                          tsksio_int7,   /* IRQ 7 */
                                          LNULL,         /* IRQ 8 */
                                          LNULL,         /* IRQ 9 */
                                          tsksio_int10,  /* IRQ 10 */
                                          tsksio_int11,  /* IRQ 11 */
                                          tsksio_int12,  /* IRQ 12 */
                                          LNULL,         /* IRQ 13 */
                                          LNULL,         /* IRQ 14 */
                                          tsksio_int15   /* 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, LNULL, com1_base, com1_irq, com1_vect },
     { LNULL,          1, LNULL, com2_base, com2_irq, com2_vect }
                                            };

local sioptr  irq_array [MAX_IRQ] = { LNULL };

local portptr port_list = &port_descr [0];
local portptr port_last = &port_descr [1];

local int ports = STATIC_PORTS;
local callchain remove_chain = { LNULL, LNULL };

/*-------------------------------------------------------------------------*/


local void Staticfunc change_rts (sioptr data, int on)
{
   data->rtsoff = (byte)(!on);
   data->cmodcontrol = (byte)((data->cmodcontrol & ~RTS) | ((on) ? RTS : 0));
   tsk_outp (data->port_base + modemcontrol, data->cmodcontrol);
}


local void Staticfunc transmit_ready (sioptr data)
{
   int i;
#if (TSK_MSC)
   int temp;
#endif

   force_transmit_ready = 0;

   if ((i = data->r_xoff) < 0)
      {
#if (TSK_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)) == 0)
      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 Staticfunc modem_status_int (sioptr data)
{
   data->modstat = tsk_inp (data->port_base + modemstatus);

   if (data->wait_xmit)
      transmit_ready (data);
}


local void Staticfunc receive_ready (sioptr data)
{
   word status;
   word ch;

   while ((status = tsk_inp (data->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 (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 && 
             wpipe_free (&data->rcv_pipe) < data->xoff_threshold)
            {
            data->r_xoff = -1;
            if (!data->xmit_pending)
               transmit_ready (data);
            }
         }

      if (data->flags & RTSCTS && !data->rtsoff)
         if (wpipe_free (&data->rcv_pipe) < data->xoff_threshold)
            change_rts (data, 0);

      status = (status & ERR_MASK) << 8;
      if (c_write_wpipe (&data->rcv_pipe, ch | status) < 0)
         data->overrun = 1;
      }
}


/*-------------------------------------------------------------------------*/


local void Staticfunc sioint (sioptr data)
{
   int id;

   force_transmit_ready = 0;

   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;

/*       case 0x06:  line_status_int (data); (currently not used)
                     break;
*/
         }
      if (force_transmit_ready)
         transmit_ready (data);
}


void Localfunc tsk_sio_int (int irq)
{
   sioptr curr;

   for (curr = irq_array [irq]; curr != LNULL; curr = curr->next)
      sioint (curr);
}


/*-------------------------------------------------------------------------*/

local void Taskfunc v24_chain_remove (callchainptr chain)
{
   /* 
      We just assume here that all local data is in the same segment.
      This should be true for all compilers and memory models
      unless you define an extremely low data threshold.
   */
   v24_remove_all ();
}


int Globalfunc v24_define_port (int base, byte irq, byte vector)
{
#if (TSK_DYNAMIC)
   portptr portp;

   if (irq >= MAX_IRQ)
      return -1; 
   if (irq_procs [irq] == LNULL)
      return -1; 

   if ((portp = (portptr)tsk_palloc (sizeof (port_data))) == LNULL)
      return -1;
   portp->pnum = ports;
   portp->base = base;
   portp->irq = irq;
   portp->vector = vector;
   portp->next = LNULL;
   portp->sio = LNULL;

   if (port_list == LNULL)
      port_list = portp;
   else
      port_last->next = portp;

   port_last = portp;
   ports++;

   return portp->pnum;

#else
   return -1;
#endif
}


local sioptr Staticfunc ret_error (sioptr sio)
{
   sio->port->sio = LNULL;
#if (TSK_DYNAMIC)
   if (sio->port->pnum >= STATIC_PORTS)
      tsk_pfree (sio);
#endif
   return LNULL; 
}


sioptr Globalfunc v24_install (int port, int init,
                        farptr rcvbuf, word rcvsize,
                        farptr xmitbuf, word xmitsize)
{
   sioptr sio;
   portptr portp;
   int pbase;
   intprocptr far *intptr;
   int 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 LNULL;

   portp = port_list;

   if (port & 0x80)     /* Relative port number */
      {
      port &= 0x7f;
      if (port > 4)
         return LNULL; 
      pbase = *((wordptr)(TMK_FP (0x40, port * 2)));
      if (!pbase)
         return LNULL;

      for (port = 0; port < ports; port++, portp = portp->next)
         if (portp->base == pbase)
            break;

      if (port >= ports)
         return LNULL;
      }
   else 
      {
      if (port > ports)
         return LNULL;
      for (i = 0; i < port; i++)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -