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

📄 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 页
字号:
  rs_tmp2 = inportb(rs_ss.ier);     /* save ier */
  outportb(rs_ss.ier,'\0');         /* disable interrupts at UART */
  inportb(rs_ss.rbr);               /* read rcv buffer register */
  inportb(rs_ss.lsr);               /* read lsr */
  inportb(rs_ss.msr);               /* read msr */
  inportb(rs_ss.iir);               /* read iir */
  if(inportb(rs_ss.iir) != '\x01')  /* read it again, should indicate... */
    return 0;                       /* ...no interrupt pending */
  outportb(rs_ss.lcr,'\0');         /* make sure out2 is 0 */
  outportb(rs_ss.ier,'\x02');       /* enable thre interrupt indication */
  outportb(rs_ss.ier,'\x02');       /* do it again for 8250 */
  goto rs_J1;                       /* give UART some time */
  rs_J1:
  rs_tmp3 = inportb(rs_ss.iir);     /* get iir */
  outportb(rs_ss.ier,rs_tmp2);      /* restore original values */
  outportb(rs_ss.mcr,rs_tmp1);
  if(rs_tmp3 != '\x02')             /* should have seen thre interrupt... */
    return 0;                       /* ...else port is unavailable */

  /* find out what kind of UART it is */
  rs_ss.xmitfifo = 1; /* initialize for no FIFO */
  outportb(rs_portbase + 7,'\x55');  /* try writing scratch register */
  if(inportb(rs_portbase + 7) != '\x55')  /* and then reading it */
    rs_ret = 1; /* if value written wasn't read it's an 8250B */
  else{
    /* check for presence of 16550, if 16550A,C,CF, enable FIFOs */
    outportb(rs_ss.fcr,'\x41'); /* enable FIFO's with 4 byte RCVR trig. level */
    rs_tmp1 = inportb(rs_ss.iir);
    rs_tmp1 &= '\xC0';
    if(rs_tmp1 == (unsigned char)'\xC0'){ /* 16550A,C,CF bits 6 & 7 are set */
      rs_ret = 4;
      rs_ss.xmitfifo = 16;   /* #of bytes to write to XMIT FIFO per interrupt */
      }
    else{                 /* otherwise, it's an 8250A, 16450 or 16550 */
      outportb(rs_ss.fcr,'\x0');
      if(rs_tmp1 == (unsigned char)'\x80') /* 16550 */
        rs_ret = 3;
      else                                 /* 8250A or 16450 */
        rs_ret = 2;
      }
    }

  /* get the baud rate divisor values */
  rs_dvsrh = 0;
  switch(rs_baud){
    case 110L:
      rs_dvsrh = '\x04';
      rs_dvsrl = '\x17';
      break;
    case 300L:
      rs_dvsrh = '\x01';
      rs_dvsrl = '\x80';
      break;
    case 600L:
      rs_dvsrl = '\xC0';
      break;
    case 1200L:
      rs_dvsrl = '\x60';
      break;
    case 2400L:
      rs_dvsrl = '\x30';
      break;
    case 4800L:
      rs_dvsrl = '\x18';
      break;
    case 9600L:
      rs_dvsrl = '\x0C';
      break;
    case 19200L:
      rs_dvsrl = '\x06';
      break;
    case 38400L:
      rs_dvsrl = '\x03';
      break;
    case 57600L:
      rs_dvsrl = '\x02';
      break;
    case 115200L:
      rs_dvsrl = '\x01';
      break;
    default:
      return -7;
    }

  rs_oldvec = getvect(rs_ss.int_no); /* get the old interrupt vector */
  setvect(rs_ss.int_no,rs_inthndlr); /* plug in the new one */

  outportb(rs_ss.ier,0);      /* disable UART interrupts */
  outportb(rs_ss.lcr,'\x80'); /* enable baud rate divisor registers */
  outportb(rs_dll,rs_dvsrl);  /* write divisor lo byte */
  outportb(rs_dlm,rs_dvsrh);  /* write divisor hi byte */
  outportb(rs_ss.lcr,(rs_parity | rs_bits | rs_stop)); /* characteristics */
  /* enable interrupts at UART, do not change modem control lines */

  outportb(rs_ss.mcr,(inportb(rs_ss.mcr) | '\x08')); /* set out2 */
  inportb(rs_ss.iir); /* clear out any data...*/
  inportb(rs_ss.lsr); /*...left in...*/
  inportb(rs_ss.rbr); /*...UART's status...*/
  inportb(rs_ss.msr); /*...registers */

  disable();
  outportb(rs_ss.ier,'\x0D'); /* enable UART interrupts */
  inportb(rs_ss.iir);
  rs_ss.oldmask = inportb(rs_ss.pic + 1); /* save old interrupt mask */
  rs_mask &= rs_ss.oldmask;

  outportb(rs_ss.pic + 1,rs_mask); /* interrupt now enabled */
  rs_ds.msr_cod = inportb(rs_ss.msr) & '\xF0'; /* initialize modem status */
  enable();

  rs_timer(0);             /* zero out tick counter */
  rs_ss.flow = 0;          /* initialize flow control */
  rs_ds.rcv_cnt = 0;       /* initialize receive count */
  rs_ds.err_cod = '\x00';  /* initialize error flags */
  rs_ds.ier_msk = '\x0F'; /* insure that xmit interrupts stay enabled */
  rs_portopen = 1;         /* set port open flag */
  rs_ss.uart = rs_ret - 1; /* set UART type */
  return rs_ret;

}

/* rs_close: Restore original 8259 interrupt controller mask value,
   disable UART interrupts and restore original interrupt vector. */
void rs_close(void)
{

  extern struct rs_statics rs_ss;
  extern volatile struct rs_dynamics rs_ds;
  extern int rs_portopen;
  extern void interrupt (*rs_oldvec)(void);
  unsigned rs_time,rs_tail;

  if(! rs_portopen) /* no port to close */
    return;

  /* if buffer xmit in progress, wait til it's done */
  if(rs_ds.ier_msk == '\x0F'){
    rs_time = rs_timer(1);
    rs_tail = rs_ds.out_tail;
    while(rs_ds.out_head != rs_ds.out_tail)
      /* make sure output is moving else time out (wait one char period) */
      if(rs_timer(1) - rs_time > 4 && rs_tail == rs_ds.out_tail)
        break;
    }

  /* insure that tranmitter is empty before continuing */
  rs_time = rs_timer(1);
  while(! (inportb(rs_ss.lsr) & '\x40'))
    if(rs_timer(1) - rs_time > 4)
      break;

  if(rs_ss.oldmask){
    disable();
    outportb(0x20,'\xC7');           /* restore interrupt priorities */
    enable();
    }

  /* disable UART interrupts */
  outportb(rs_ss.ier,0);
  outportb(rs_ss.mcr,inportb(rs_ss.mcr) & '\xF7');

  /* restore old interrupt vector */
  if(rs_oldvec != NULL)
    setvect(rs_ss.int_no,rs_oldvec);
  rs_oldvec = NULL;

  rs_portopen = 0; /* signal port closed */

}

/* rs_sndbyt: Output byte via output buffer.  If no space in output buffer,
   wait til there is unless output is disabled via flow control, in which
   case return -1.  If RS_POLLED_XMIT is defined, the byte is written to
   the port when the transmit holding register becomes empy.  THRE interrupt
   and output buffer are not used.  Return -1 if output disabled via flow
   control. */

int rs_sndbyt(int rs_snd)
{

  extern int rs_portopen;
  extern volatile struct rs_dynamics rs_ds;
  extern struct rs_statics rs_ss;


  if(! rs_portopen) /* is a port open ? */
    return -1;

#ifndef RS_POLLED_XMIT /* interrupt driven output */
  while(((rs_ds.out_head + 1)  & rs_ss.obuf_siz) == rs_ds.out_tail){
    /* make sure there's room in the buffer */
    /* if xmit disabled via flow control, don't wait */
    if(rs_ds.ier_msk == '\x0D')
      return -1;
    }
  disable();
  *(rs_ss.out_buf + rs_ds.out_head++) = (unsigned char)rs_snd;
  rs_ds.out_head &= rs_ss.obuf_siz;
  enable();
  if(rs_ds.ier_msk != '\x0D'){
    outportb(rs_ss.ier,'\x0D');
    if(! rs_ss.uart)           /* if it's an 8250 or 8250B... */
      while(! (inportb(rs_ss.lsr) & '\x20')) /* ...wait for THRE */
        ;
    outportb(rs_ss.ier,'\x0F'); /* generate an interrupt if needed */
    }
#else /* polled mode output */
  if(rs_ds.ier_msk == '\x0D')
    return -1;
  while(! (inportb(rs_ss.lsr) & '\x20')) /* wait for THRE */
    ;
  outportb(rs_ss.thr,(unsigned char)rs_snd);
#endif
  return 0;

}


/* rs_sndstr: Output rs_sndcnt chars from rs_str to output buffer.  If not
   enough space in output buffer, wait til there is.  If output disabled
   via flow control, return count of characters written to output buffer
   if less than string length.  If rs_sndcnt is 0, output characters from
   rs_str until nul character is reached.  If RS_POLLED_XMIT is defined,
   string is written to port by polling the line status register for THRE
   and the buffer is not used.  If output is disabled via flow control,
   return count of characters sent */

int rs_sndstr(int rs_sndcnt, char *rs_str)
{

  extern struct rs_statics rs_ss;
  extern volatile struct rs_dynamics rs_ds;
  int rs_x,rs_y;

  if(! rs_portopen) /* is a port open? */
    return -1;

  if(rs_sndcnt) /* string length specified? */
    rs_y = rs_sndcnt;
  else
    rs_y = 0x7FFF; /* max buffer length (`11/2) */

#ifndef RS_POLLED_XMIT /* interrupt driven transmit */
  for(rs_x = 0;rs_x < rs_y;rs_x++){
    /* if no string length specified, stop when nul is encountered */
    if(! rs_sndcnt){
      if(*(rs_str + rs_x) == '\0')
        break;
      }
    while(((rs_ds.out_head + 1)  & rs_ss.obuf_siz) == rs_ds.out_tail){
      /* if xmit disabled via flow control,don't wait */
      if(rs_ds.ier_msk == '\x0D')
        return rs_x;
      else{ /* otherwise, may need to get xmit interrupts going (`11/2) */
        outportb(rs_ss.ier,'\x0D');
        if(! rs_ss.uart)           /* if it's an 8250 or 8250B... */
          while(! (inportb(rs_ss.lsr) & '\x20'))  /* wait for THRE */
            ;
        outportb(rs_ss.ier,'\x0F'); /* kick transmit interrupt */
        }
      }
    disable();
    *(rs_ss.out_buf + rs_ds.out_head++) = (unsigned char)*(rs_str + rs_x);
    rs_ds.out_head &= rs_ss.obuf_siz;
    enable();
    }
  if(rs_ds.ier_msk != '\x0D'){
    outportb(rs_ss.ier,'\x0D');
    if(! rs_ss.uart)
      while(! (inportb(rs_ss.lsr) & '\x20'))
        ;
    outportb(rs_ss.ier,'\x0F'); /* generate an interrupt if needed */
    }
#else /* polled transmit */
  for(rs_x = 0;rs_x < rs_y;rs_x++){
    /* if xmit disabled via flow control,don't wait */
    if(rs_ds.ier_msk == '\x0D')
      return rs_x;
    /* if no string length specified, stop when nul is encountered */
    if(! rs_sndcnt){
      if(*(rs_str + rs_x) == '\0')
        break;
      }
    while(! (inportb(rs_ss.lsr) & '\x20'))
      ;
    outportb(rs_ss.thr,(unsigned char)*(rs_str + rs_x));
    }
#endif
  return 0;

}


/* rs_outfre: Return amount of free space available in output buffer.
   This function does not return a meaningful value if RS_POLLED_XMIT is
   defined because transmission does not use the buffer */
unsigned rs_outfre(void)
{

  extern struct rs_statics rs_ss;
  extern volatile struct rs_dynamics rs_ds;

  return(rs_ss.obuf_siz + 1 - ((rs_ds.out_head - rs_ds.out_tail) &
                                                       rs_ss.obuf_siz));

}

/* rs_scanin: Scan for first occurance of string rs_scan_str in input buffer.
   Return -1 if not found, offset into buffer if found */
int rs_scanin(char *rs_scan_str)
{

  extern struct rs_statics rs_ss;
  extern volatile struct rs_dynamics rs_ds;
  extern int rs_portopen;
  int rs_off,rs_incnt,rs_flg = 0,rs_len = 0;

  while(*(rs_scan_str + rs_len))
    rs_len++;

  if((! rs_portopen) || (! rs_ds.rcv_cnt) || (! rs_len))
    return -1;

  for(rs_off = 0;rs_off < rs_ds.rcv_cnt;rs_off++){
    if(*(rs_ss.in_buf + ((rs_ds.in_tail + rs_off) & rs_ss.ibuf_siz)) ==
         *(rs_scan_str + rs_flg)){
      rs_flg++;
      if(rs_flg == rs_len)
        return((rs_off - (rs_len - 1)) & rs_ss.ibuf_siz);
      }
    else
      rs_flg = 0;
    }

  return -1;

}

/* rs_peek: Return next available character from input buffer, leave
   character in buffer. Return -1 if none are available */
int rs_peek(void)
{

  extern struct rs_statics rs_ss;
  extern volatile struct rs_dynamics rs_ds;
  extern int rs_portopen;

⌨️ 快捷键说明

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