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

📄 rs232.c

📁 RS232.C was written to provide all of the basic functionality needed to employ serial I/O in any a
💻 C
📖 第 1 页 / 共 4 页
字号:
  int thr;
  int rbr;
  int iir;
  int fcr;
  int ier;
  int mcr;
  int lsr;
  int lcr;
  int msr;
  int uart;
  int pic;
  unsigned ibuf_siz;
  unsigned obuf_siz;
  char xon;
  char xoff;
  char hdw_flw;
  unsigned char *in_buf;
  unsigned char *out_buf;
  unsigned char oldmask;
  }rs_ss;

volatile struct rs_dynamics{           /* dynamic variables */
  unsigned in_head;
  unsigned in_tail;
  unsigned out_head;
  unsigned out_tail;
  unsigned rcv_cnt;
  unsigned char ier_msk;
  unsigned char msr_cod;
  unsigned char err_cod;
  }rs_ds;

int rs_portopen = 0;
struct rs_userport rs_user = {0,'\0'};
void interrupt (*rs_oldvec)(void) = NULL;

/* Interrupt service routine - Get received character from port rs_ss.rbr,
   store in rs_ss.in_buf and increment rs_inrcv.  If flow control enabled,
   update global variable rs_ss.iermsk to enable or disable output as
   required */
void interrupt rs_inthndlr(void)
{

  extern struct rs_statics rs_ss;
  extern volatile struct rs_dynamics rs_ds;
  extern void interrupt (*rs_oldvec)(void);
  int rs_xmitcnt;

#ifndef RS_POLLED_XMIT
  if(rs_ss.uart)
    outportb(rs_ss.ier,rs_ds.ier_msk);   /* nudge xmit intrpt if not 8250B */
#endif
  _AL = (inportb(rs_ss.iir) & '\x07');   /* get interrupt id */
  if(!(_AL & '\x01')){     /* interrupt pending ? */
    do{
      if(_AL == '\x06'){   /* receive error ? */
        rs_ds.err_cod = inportb(rs_ss.lsr); /* record error */
        }
      else if((_AL & '\x04')){  /* data received interrupt ? */
        do{
          _AL = inportb(rs_ss.rbr); /* get the byte */
          _CL = _AL;
          if(rs_ss.flow == 2){
            if(_CL == rs_ss.xon){
#ifndef RS_POLLED_XMIT
              outportb(rs_ss.ier,'\x0F');
#endif
              rs_ds.ier_msk = '\x0F';
              }
            else if(_CL == rs_ss.xoff){
#ifndef RS_POLLED_XMIT
              outportb(rs_ss.ier,'\x0D');
#endif
              rs_ds.ier_msk = '\x0D';
              }
            else
              goto rs_J1;
            }
          else{
            /* store incoming byte */
          rs_J1:
            *(rs_ss.in_buf + rs_ds.in_head++) = _CL;
            /* in case head ptr wrapped around */
            rs_ds.in_head &= rs_ss.ibuf_siz;
            rs_ds.rcv_cnt++; /* track rcv buffer overflow */
            }
          }while(inportb(rs_ss.lsr) & '\x01'); /* loop while data avail. */
        }
#ifndef RS_POLLED_XMIT
      else if(_AL & '\x02'){  /* transmit holding reg. empty ? */
        for(rs_xmitcnt = 0;rs_xmitcnt < rs_ss.xmitfifo;rs_xmitcnt++){
          /* send a byte if any to send */
          if(rs_ds.out_tail != rs_ds.out_head){
            outportb(rs_ss.thr,*(rs_ss.out_buf + rs_ds.out_tail++));
            /* in case tail pointer wrapped around */
            rs_ds.out_tail &= rs_ss.obuf_siz;
            }
          else
            break;
          }
        }
#endif
      else{ /* change in one of the modem control lines */
        rs_ds.msr_cod = inportb(rs_ss.msr); /* record modem status */
        if(rs_ss.flow == 1){
          if(rs_ds.msr_cod & rs_ss.hdw_flw)
            rs_ds.ier_msk = '\x0F'; /* enable xmit interrupts */
          else
            rs_ds.ier_msk = '\x0D'; /* disable xmit interrupts */
#ifndef RS_POLLED_XMIT
          outportb(rs_ss.ier,rs_ds.ier_msk);
#endif
          }
        }
      }while(!((_AL = inportb(rs_ss.iir)) & '\x01')); /* loop if int. pending */
    }
  else
    rs_oldvec(); /* no interrupt pending on entry - call old isr */


  enable();  /* enable interrupts */
  outportb(rs_ss.pic,'\x20'); /* non-specific EOI to 8259 */
  if(rs_ss.pic == 0xA0)
    outportb(0x20,'\x20');

}

/* rs_initport: Initialize port, interrupt vector and interrupt mask (see
   description with function prototype for details on arguments). */
int rs_initport(char rs_port,long rs_baud,char rs_parity,char rs_bits,
                char rs_stop,unsigned rs_userinbufsiz, char *rs_userinbuf,
                unsigned rs_useroutbufsiz,char *rs_useroutbuf)
{

  extern struct rs_statics rs_ss;
  extern volatile struct rs_dynamics rs_ds;
  extern int rs_portopen;
  extern void interrupt (*rs_oldvec)(void);
  int rs_init[] = {0x6328,0x2029,0x2E43,0x4B20,0x7261,0x6863,0x7265,
                   0x3120,0x3939,0x2033,0x3439};
  int rs_dll,rs_dlm,rs_portbase,rs_ret;
  int far *rs_bda;
  unsigned char rs_dvsrl,rs_dvsrh,rs_mask,rs_irq,rs_tmp1,rs_tmp2,rs_tmp3;


  if(rs_portopen) /* if there's already a port open, close it */
    rs_close();
  rs_ss.oldmask = '\0';

  /* make sure buffer size is valid */
  if((rs_userinbufsiz - 1) & rs_userinbufsiz)
    return -1;
  rs_ss.ibuf_siz = rs_userinbufsiz - 1;
  if((rs_ss.in_buf = (unsigned char *)rs_userinbuf) == NULL)
    return -1;
#ifndef RS_POLLED_XMIT
  if((rs_useroutbufsiz - 1) & rs_useroutbufsiz)
    return -2;
  rs_ss.obuf_siz = rs_useroutbufsiz - 1;
  if((rs_ss.out_buf = (unsigned char *)rs_useroutbuf) == NULL)
    return -2;
#endif

  /* initialize buffer head and tail pointers */
  rs_ds.in_head = rs_ds.in_tail = rs_ds.out_head = rs_ds.out_tail = 0;

  if(rs_init[1])
    rs_bda = (int far*)MK_FP(0x40,0); /* get far pointer to BIOS data area */

  switch(rs_port){ /* find i/o port address and irq */
    case '1':
      rs_portbase = *rs_bda;
      if(rs_portbase == 0)
        rs_portbase = 0x3F8;
      rs_irq = 4;
      break;
    case '2':
      rs_portbase = *(rs_bda + 1);
      if(rs_portbase == 0)
        rs_portbase = 0x2F8;
      rs_irq = 3;
      break;
    case '3':
      rs_portbase = *(rs_bda + 2);
      if(rs_portbase == 0)
        rs_portbase = 0x3E8;
      if(rs_portbase == 0x3220) /* if it's a PS/2 */
        rs_irq = 3;
      else
        rs_irq = 4;
      break;
    case '4':
      rs_portbase = *(rs_bda + 3);
      if(rs_portbase == 0)
        rs_portbase = 0x2E8;
      if(rs_portbase == 0x3228) /* if it's a PS/2 */
        rs_irq = 4;
      else
        rs_irq = 3;
      break;
    case '0': /* user defined IRQ and base address defined by struct rs_user */
      if(! rs_user.base) /* make sure it's been init'd */
        return -3;
      rs_portbase = rs_user.base;
      rs_irq = rs_user.irq;
      break;
    default:
      return -3;
    }

  if(rs_irq <= 7){ /* find interrupt number and PIC address */
    rs_ss.int_no = rs_irq + 8;
    rs_ss.pic = 0x20;
    }
  else if(rs_irq <= 15){
    rs_irq -= 8;
    rs_ss.int_no = rs_irq + 0x70;
    rs_ss.pic = 0xA0;
    }
  else
    return -3;
  rs_mask = ('\x01' << rs_irq) ^ '\xFF';

  switch(rs_parity){
    case 'N':
      rs_parity = 0;
      break;
    case 'E':
      rs_parity = '\x18';
      break;
    case 'O':
      rs_parity = '\x08';
      break;
    case 'S':
      rs_parity = '\x38';
      break;
    case 'M':
      rs_parity = '\x28';
      break;
    default:
      return -4;
    }

  if(rs_bits == '7')
    rs_bits = 2;
  else if(rs_bits == '8')
    rs_bits = 3;
  else
    return -5;

  if(rs_stop == '1')
    rs_stop = 0;
  else if(rs_stop == '2')
    rs_stop = 4;
  else
    return -6;

  /* 8250 (or 16x50) registers: */
  /* out, bit 7 of LCR = 0, (Transmit Holding Register) */
  rs_ss.thr = rs_portbase + 0;
  /* in, bit 7 of LCR = 0, (Receive Buffer Register) */
  rs_ss.rbr = rs_portbase + 0;
  /* out, bit 7 of LCR = 1, (Divisor Latch LSB) */
  rs_dll = rs_portbase + 0;
  /* out, bit 7 of LCR = 1, (Divisor Latch MSB) */
  rs_dlm = rs_portbase + 1;
  /* out, bit 7 of LCR = 0, (Interrupt Enable Register)
                        bit 0 = 1 data rcvd
                        bit 1 = 1 transmit holding reg. empty
                        bit 2 = 1 data reception error
                        bit 3 = 1 change in modem status
                        bit 4-7 unused */
  rs_ss.ier = rs_portbase + 1;
  /* in, (Interrupt ID register)
                        bit  0  :  0 = interrupt pending
                        bits 2-1: 00 = modem status change - read status
                                  01 = transmit ready - output character or
                                       read iir to clear
                                  10 = data rcvd - read data
                                  11 = break or error
                        bits 7-6: 11 = 16550 in FIFO mode */
  rs_ss.iir = rs_portbase + 2;
  /* out, (FIFO control register - 16550)
                        bit 0: 1 = FIFO enable
                        bit 1: 1 = RCVR FIFO reset
                        bit 2: 1 = XMIT FIFO reset
                        bit 6 & 7: RCVR trigger level
                        (00 = 1, 01 = 4, 10 = 8, 11 = 14) */
  rs_ss.fcr = rs_portbase + 2;
  /* out, (Line Control Register)
                        bits 0-1: Character Length
                                     00 = 5 bits
                                     01 = 6 bits
                                     10 = 7 bits
                                     11 = 8 bits
                        bit 2: Number of stop bits
                                      0 = 1 (1.5 if character length 5)
                                      1 = 2
                        bit 3: Parity
                                      0 = no parity
                                      1 = parity generated
                        bit 4: Parity type
                                      0 = odd
                                      1 = even
                        bit 5: Stick Parity
                                      0 = disabled
                                      1 = always 1 if bit 3 = 1 & bit 4 = 0 or
                                          always 0 if bit 3 = 1 & bit 4 = 1 or
                                          no parity if bit 3 = 0
                        bit 6: Set Break
                                      0 = disabled
                                      1 = output string of 0s
                        bit 7: Enable write to baud divisor regs. if 1 */
  rs_ss.lcr = rs_portbase + 3;
  /* out, (Modem Control Register)
                        bit 0:        1 = data terminal ready
                        bit 1:        1 = request to send
                        bit 2:        1 = aux. output 1
                        bit 3:        1 = aux. output 2 - enables hdwr intrrpts.
                        bit 4:        1 = UART loopback mode
                        bit 5-7:      always 0 */
  rs_ss.mcr = rs_portbase + 4;
  /* in, (Line Status Register)
                        bit 0:        1 = character received
                        bit 1:        1 = rcvd data overrun
                        bit 2:        1 = parity error
                        bit 3:        1 = framing error
                        bit 4:        1 = break detected
                        bit 5:        1 = transmit holding reg. empty
                        bit 6:        1 = transmitter empty
                        bit 7:        1 = rcvr FIFO error (16550) */
  rs_ss.lsr = rs_portbase + 5;
  /* in, (Modem Status Register)
                        bit 0:        1 = delta clear to send
                        bit 1:        1 = delta data set ready
                        bit 2:        1 = delta ring indicator
                        bit 3:        1 = delta data carrier detect
                        bit 4:        1 = clear to send
                        bit 5:        1 = data set ready
                        bit 6:        1 = ring indicator
                        bit 7:        1 = data carrier detect */
  rs_ss.msr = rs_portbase + 6;

  /* check for existence of UART */
  outportb(rs_ss.fcr,'\0');         /* if 16550, make it a 16450 */
  rs_tmp1 = inportb(rs_ss.mcr);     /* save mcr */

⌨️ 快捷键说明

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