quicc2_scc_serial.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 852 行 · 第 1/3 页

C
852
字号
  int cache_state;
                                       
  HAL_DCACHE_IS_ENABLED(cache_state);
  if (cache_state) {
    HAL_DCACHE_FLUSH(txbd->buffer, scc_chan->txsize);
  }

  if ((txbd->length > 0) && 
      ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == 0)) {
    txbd->ctrl |= QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int;  // Signal buffer ready
    if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
      txbd = scc_chan->tbase;
    } else {
      txbd++;
    }
    scc_chan->txbd = (scc_bd *) txbd;
  }
}

// Send a character to the device output buffer.
// Return 'true' if character is sent to device
static bool
quicc2_scc_serial_putc(serial_channel *chan, unsigned char c)
{
    quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
    volatile struct scc_bd *txbd, *txfirst;
    bool res;

    cyg_drv_dsr_lock();  // Avoid race condition testing pointers

    txbd = (scc_bd *)(QUICC2_VADS_IMM_BASE + ((int) scc_chan->scc_pram->tbptr));
    txfirst = txbd;

    // Scan for a non-busy buffer
    while (txbd->ctrl & QUICC2_BD_CTL_Ready) {
      // This buffer is busy, move to next one
      if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
        txbd = scc_chan->tbase;
      } else {
        txbd++;
      }
      if (txbd == txfirst) break;  // Went all the way around
    }
    
    scc_chan->txbd = (scc_bd *) txbd;
    if ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == 0) {
      // Transmit buffer is not full/busy
      txbd->buffer[txbd->length++] = c;
      if (txbd->length == scc_chan->txsize) {
        // This buffer is now full, tell SCC to start processing it
        quicc2_scc_serial_flush(scc_chan);
      }
      res = true;
    } else {
      // No space
      res = false;
    }

    cyg_drv_dsr_unlock();
    return res;
}

// Fetch a character from the device input buffer, waiting if necessary
static unsigned char 
quicc2_scc_serial_getc(serial_channel *chan)
{
  unsigned char c;
  quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
  volatile scc_bd *rxbd = scc_chan->rxbd;

  while ((rxbd->ctrl & QUICC2_BD_CTL_Ready) != 0) ; // WAIT ...

  c = rxbd->buffer[0];
  rxbd->length = scc_chan->rxsize;
  rxbd->ctrl |= QUICC2_BD_CTL_Ready;
  if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
    rxbd = scc_chan->rbase;
  } else {
    rxbd++;
  }
  scc_chan->rxbd = (scc_bd *) rxbd;
  return c;
}

// Set up the device characteristics; baud rate, etc.
static Cyg_ErrNo
quicc2_scc_serial_set_config(serial_channel *chan, cyg_uint32 key,
                            const void *xbuf, cyg_uint32 *len)
{
  switch (key) {
  case CYG_IO_SET_CONFIG_SERIAL_INFO:
    {
      // FIXME - The documentation says that you can't change the baud rate
      // again until at least two BRG input clocks have occurred.
      cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
      if ( *len < sizeof(cyg_serial_info_t) ) {
        return -EINVAL;
      }
      *len = sizeof(cyg_serial_info_t);
      if ( true != quicc2_scc_serial_config_port(chan, config, false) )
        return -EINVAL;
    }
    break;
  default:
    return -EINVAL;
  }
  return ENOERR;
}

// Enable the transmitter (interrupt) on the device
static void
quicc2_scc_serial_start_xmit(serial_channel *chan)
{
  quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;

  cyg_drv_dsr_lock();

  if (scc_chan->txbd->length == 0) {
    // See if there is anything to put in this buffer, just to get it going
    (chan->callbacks->xmt_char)(chan);
  }
  if (scc_chan->txbd->length != 0) {
    // Make sure it gets started
    quicc2_scc_serial_flush(scc_chan);
  }

  cyg_drv_dsr_unlock();
}

// Disable the transmitter on the device
static void 
quicc2_scc_serial_stop_xmit(serial_channel *chan)
{
  quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
  // If anything is in the last buffer, need to get it started
  if (scc_chan->txbd->length != 0) {
    quicc2_scc_serial_flush(scc_chan);
  }
}

// Serial I/O - low level interrupt handler (ISR)
static cyg_uint32 
quicc2_scc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
  serial_channel *chan = (serial_channel *)data;
  quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
  cyg_drv_interrupt_mask(scc_chan->int_vector);
  return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Cause DSR to be run
}

// Serial I/O - high level interrupt handler (DSR)
static void       
quicc2_scc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    serial_channel *chan = (serial_channel *)data;
    quicc2_scc_serial_info *scc_chan = (quicc2_scc_serial_info *)chan->dev_priv;
    volatile struct scc_regs_8260 *regs = scc_chan->scc_regs;
    volatile scc_bd *txbd;
    volatile scc_bd *rxbd = scc_chan->rxbd;
    scc_bd *rxlast;
    int i, cache_state;

#ifdef CYGDBG_DIAG_BUF
    int _time, _stime;
    externC cyg_tick_count_t cyg_current_time(void);
    cyg_drv_isr_lock();
    enable_diag_uart = 0;
    HAL_CLOCK_READ(&_time);
    _stime = (int)cyg_current_time();
    diag_printf("DSR start - CE: %x, time: %x.%x\n", 
               regs->scce, _stime, _time);
    enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF

    if (regs->scce & QUICC2_SCCE_TX) { // Tx Event

#ifdef XX_CYGDBG_DIAG_BUF
      enable_diag_uart = 0;
      txbd = scc_chan->tbase;
      for (i = 0;  i < CYGNUM_IO_SERIAL_POWERPC_QUICC2_SCC_SCC1_TxNUM;  i++, txbd++) {
        diag_printf("Tx BD: %x, length: %d, ctl: %x\n", txbd, txbd->length, txbd->ctrl);
      }
      enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF

      regs->scce = QUICC2_SCCE_TX;  // Reset Tx Event
      txbd = scc_chan->tbase;  // First buffer
      while (true) {
        if ((txbd->ctrl & (QUICC2_BD_CTL_Ready|QUICC2_BD_CTL_Int)) == QUICC2_BD_CTL_Int) {
#ifdef XX_CYGDBG_DIAG_BUF
          enable_diag_uart = 0;
          HAL_CLOCK_READ(&_time);
          _stime = (int)cyg_current_time();
          diag_printf("TX Done - Tx: %x, length: %d, time: %x.%x\n", 
                      txbd, txbd->length, _stime, _time);
          enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
          txbd->length = 0;
          txbd->ctrl &= ~QUICC2_BD_CTL_Int;  // Reset interrupt bit
        }

        if (txbd->ctrl & QUICC2_BD_CTL_Wrap) {
          txbd = scc_chan->tbase;
          break;
        } else {
          txbd++;
        }
      }
      (chan->callbacks->xmt_char)(chan);
    }

    while (regs->scce & QUICC2_SCCE_RX) { // Rx Event

      regs->scce = QUICC2_SCCE_RX;  // Reset interrupt state;
      rxlast = (scc_bd *) ((char *)QUICC2_VADS_IMM_BASE + scc_chan->scc_pram->rbptr );

#ifdef CYGDBG_DIAG_BUF
      enable_diag_uart = 0;
      HAL_CLOCK_READ(&_time);
      _stime = (int)cyg_current_time();
      diag_printf("Scan RX - rxbd: %x, rbptr: %x, time: %x.%x\n", 
                  rxbd, rxlast, _stime, _time);
#endif // CYGDBG_DIAG_BUF
      while (rxbd != rxlast) {
        if ((rxbd->ctrl & QUICC2_BD_CTL_Ready) == 0) {
#ifdef CYGDBG_DIAG_BUF
          diag_printf("rxbuf: %x, flags: %x, length: %d\n", 
                      rxbd, rxbd->ctrl, rxbd->length);
          diag_dump_buf(rxbd->buffer, rxbd->length);
#endif // CYGDBG_DIAG_BUF

          for (i = 0;  i < rxbd->length;  i++) {
            (chan->callbacks->rcv_char)(chan, rxbd->buffer[i]);
          }
          // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
          HAL_DCACHE_IS_ENABLED(cache_state);
          if (cache_state) {
            HAL_DCACHE_INVALIDATE(rxbd->buffer, scc_chan->rxsize);  // Make sure no stale data
          }
          
          rxbd->length = 0;
          rxbd->ctrl |= QUICC2_BD_CTL_Ready;
        }
         
        if (rxbd->ctrl & QUICC2_BD_CTL_Wrap) {
          rxbd = scc_chan->rbase;
        } else {
          rxbd++;
        }
      }
#ifdef CYGDBG_DIAG_BUF
      enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
      scc_chan->rxbd = (scc_bd *) rxbd;
    }

    if (regs->scce & QUICC2_SCCE_BSY) {
#ifdef CYGDBG_DIAG_BUF
      enable_diag_uart = 0;
      diag_printf("RX BUSY interrupt\n");
      enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
      regs->scce = QUICC2_SCCE_BSY;  // Reset interrupt state;
    }
#ifdef CYGDBG_DIAG_BUF
    enable_diag_uart = 0;
    HAL_CLOCK_READ(&_time);
    _stime = (int)cyg_current_time();
    diag_printf("DSR done - CE: %x, time: %x.%x\n", 
                regs->scce, _stime, _time);
    enable_diag_uart = 1;
#endif // CYGDBG_DIAG_BUF
    cyg_drv_interrupt_acknowledge(scc_chan->int_vector);
    cyg_drv_interrupt_unmask(scc_chan->int_vector);
#ifdef CYGDBG_DIAG_BUF
    cyg_drv_isr_unlock();
#endif // CYGDBG_DIAG_BUF
}

#endif // CYGPKG_IO_SERIAL_POWERPC_QUICC2_SCC

// ------------------------------------------------------------------------
// EOF powerpc/quicc2_scc_serial.c

⌨️ 快捷键说明

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