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

📄 usb.c

📁 freescale badge board 开发板测试 源程序
💻 C
📖 第 1 页 / 共 4 页
字号:
    break;
  case EPST_DATA_TX_LAST:
    /* In this state we may have one or two packets in the packet buffers.
       We shall wait till both packets are sent, and both buffers are empty. */

    /* Check if both buffers are empty. */
    if ((RD_LE32(&BDT_CTL_TX(ep, 0)) & BDT_CTL_OWN) == 0
       && (RD_LE32(&BDT_CTL_TX(ep, 1)) & BDT_CTL_OWN) == 0)
    {
      /* Enter IDLE state. */
      ep_info[ep].state=EPST_IDLE;
    }
    break;
  default:
    CMX_ASSERT(0);

  }
}

/*****************************************************************************
 * Name:
 *    usb_send
 * In:
 *    ep          - endpoint number
 *    f           - pointer to user callback function. A callback will bemade
 *                  if:  - the buffer is empty and more data needs to be sent
 *                       - all transmission is finished
 *                       - in case of an error
 *    data        - pointer to data buffer
 *    buffer_size - size of data buffer
 *    tr_length   - number of bytes to be transferred.
 *    req_length  - the number of bytes the host wants to receive.
 *
 *    Note: since all packes transmission on USB are started by the host, it
 *          needs to know how many bytes shall be transferred during a
 *          transfer. Because of this the host will always tell the device
 *          how many bytes it can receive (req_length). On the other hand, the
 *          the device may have less data ready (tr_length).
 * Out:
 *    N/A
 * Description:
 *    Using this function an TX (IN) transfer can be enabled.
 *****************************************************************************/
void usb_send(hcc_u8 ep, usb_callback_t f, hcc_u8* data, hcc_u32 tr_length, hcc_u32 req_length)
{
  hcc_imask itst;

  ep_info[ep].tlength=tr_length <= req_length ? tr_length : req_length;
  ep_info[ep].maxlength=ep_info[ep].tlength;
  ep_info[ep].data_func=f;
  ep_info[ep].address=data;
  ep_info[ep].flags=req_length > tr_length ?   (hcc_u8)EPFL_ZPACKET : (hcc_u8)0;
  ep_info[ep].error = USBEPERR_NONE;
  ep_info[ep].state=EPST_DATA_TX;

  itst=_irq_disable();
  _usb_send(ep);
  _irq_restore(itst);
}

/*****************************************************************************
 * Name:
 *    _usb_receive
 * In:
 *    ep - endpoint number
 * Out:
 *    N/A
 * Description:
 *    This fucntion inmplements the basic state machine for receive (OUT)
 *    endpoints. It will
 *        - call user callback functions if neccessary,
 *        - set endpoint specific error codes
 *        - reassemble packets into the specified buffer
 *    Note: it is called from the interrupt handler routine and from "user
 *          space" too. The function needs to be reentrant!
 *****************************************************************************/
void _usb_receive(hcc_u8 ep)
{
  hcc_u8 loops=0;
  hcc_u8* buf;
  int x;

  /* Copy data to USER space, or call callback if no buffer is available. */
  do
  {
    hcc_u8 this_buf=(hcc_u8)((MCF_USB_STAT & MCF_USB_STAT_ODD) ? 1 : 0);
    hcc_u16 plength=(hcc_u16)(RD_LE32(&BDT_CTL_RX(ep, this_buf)) >> 16);

    /* Check if amount of received data is ok. */
    if (ep_info[ep].tlength < plength)
    { /* Host sent too many data! This is a protocol error. */
      usb_stop_ep_rx(ep);
      ep_info[ep].error = USBEPERR_TO_MANY_DATA;
      return;
    }

    /* Copy data to the user buffer. */

    /* Copy packet data to destination address. */
    /* Get next RX buffer address. */
    buf=(hcc_u8*)RD_LE32(&BDT_ADR_RX(ep, (MCF_USB_STAT & MCF_USB_STAT_ODD) ? 1 : 0));

    for(x=0; x < plength; x++)
    {
      ((hcc_u8*)(ep_info[ep].address))[x]=buf[x];
    }

    ep_info[ep].tlength -= plength;
    ep_info[ep].address = ((hcc_u8 *)ep_info[ep].address) + plength;

    /* Was this the last data packet? */
    if ((ep_info[ep].tlength == 0) || (ep_info[ep].psize != plength))
    {
      /* Uuuupps: at this point there sall be no RX buffer enabled. But
         if the hosts terminates the transfer early (by sending a short
         packet) then one buffer may remain enabled. So we may have an
         unexpected interrupt and an unexpected packet.
         We try to disable the buffer, but this is not safe. There is a
         race. If the host already sent additional data to this endpoint,
         then the first transfer will be dropped as a spurious packet.
         Note: control endpoints are not affected because befor enabling RX
         these don't need to know how much data will be transfered (setup
         transfer will tell this).
         Note1: we don't know if "aborting" the reception was succesfull or
         not. */
      WR_LE32(&BDT_CTL_RX(ep, ep_info[ep].next_rx ? 0 : 1), 0);
      ep_info[ep].state=EPST_IDLE;
      /* Control endpoints will execute the callback after the status stage. */
      /* Check if control endpoint. (Note: both ENDPT registers will have
         the same content, so we check reg0. )*/
      if (! MCF_USB_ENDPT(ep) & MCF_USB_ENDPT_EP_CTL_DIS)
      {
        /* Tell application transfer ended. */
        if (ep_info[ep].data_func != (void *) 0)
        {
          /* We don't care about the return valus since the transfer is already
             finished and we can do nothing in case of an error. */
          (void)(*ep_info[ep].data_func)();
        }
        /* Disable callbacks. */
        ep_info[ep].data_func = (void *)0;
      }
    }
    else
    {
	  /* Make buffer ready for reception if two buffers can be filled by the
	     USB module. */
      if (ep_info[ep].tlength > ep_info[ep].psize)
      {
        ready_ep_rx(ep, this_buf);
      }
    }
  }while(loops);
}

/*****************************************************************************
 * Name:
 *    usb_receive
 * In:
 *    ep          - endpoint number
 *    f           - pointer to user callback function. A callback will bemade
 *                  if:  - the buffer is empty and more data needs to be sent
 *                       - all transmission is finished
 *                       - in case of an error
 *    data        - pointer to data buffer
 *    buffer_size - size of data buffer
 *    tr_length   - number of bytes to be transferred. (This shal be the same
 *                  amount that the host wants to send).
 *
 * Out:
 *    N/A
 * Description:
 *    Using this function an RX (OUT) transfer can be enabled.
 *****************************************************************************/
void usb_receive(hcc_u8 ep, usb_callback_t f, hcc_u8* data, hcc_u32 tr_length)
{
  ep_info[ep].tlength=tr_length;
  ep_info[ep].maxlength=ep_info[ep].tlength;
  ep_info[ep].data_func=f;
  ep_info[ep].address=data;
  ep_info[ep].state=EPST_DATA_RX;
  ep_info[ep].error=USBEPERR_NONE;
  ep_info[ep].flags=0;

  /* Enable next rx buffer. */
  ready_ep_rx(ep, ep_info[ep].next_rx);

  if (ep_info[ep].tlength > ep_info[ep].psize)
  {
    ready_ep_rx(ep, (hcc_u8)(ep_info[ep].next_rx ^ 0x1));
  }
}

/*****************************************************************************
 * Name:
 *    usb_abort_ep
 * In:
 *    ep          - endpoint number
 *
 * Out:
 *    N/A
 * Description:
 *    A call to this function will stop the ongoing transfer on the selected
 *    endpoint (early stop). Early stop is only possible if there is some
 *    penging date left in the buffer. If not, then transfer willstop anyway.
 *****************************************************************************/
void usb_abort_ep(hcc_u8 ep)
{
  /* Get endpoint into a fixed state. */
  hcc_imask itst=_irq_disable();
  /* If the endpoint is busy. */
  switch(ep_info[ep].state)
  {
  case EPST_IDLE:
    /* If endpoint is idle, we can not stop it. */
    break;
    /* In these cases is is too late for an early stop since the transfer
       is already going to end. */
  case EPST_DATA_TX_LAST:
  case EPST_STATUS_TX:
  case EPST_STATUS_RX:
    break;

  case EPST_DATA_RX:
    ep_info[ep].error=USBEPERR_USER_ABORT;
    ep_info[ep].flags |= EPFL_ERROR;

    /* Disable following calbacks in case of an error. */
    ep_info[ep].data_func=(void *) 0;
    /* Stall endpoint. */
    usb_stop_ep_rx(ep);
    break;
  default:
    /* UPS! invalid or unknown state... */
    CMX_ASSERT(0);
  }
  _irq_restore(itst);
}

/*****************************************************************************
 * Name:
 *    cb_set_address
 * In:
 *    N/A
 *
 * Out:
 *    N/A
 *
 * Description:
 *    This callback is used by the state machine that handles the standard
 *    requests on the default pipe to set the device address after the
 *    status stage of the "set address" request.
 *****************************************************************************/
static callback_state_t cb_set_address()
{
  if (new_address != 0)
  {
    usb_state=USBST_ADDRESSED;
  }
  else
  {
    enter_default_state();
  }
  MCF_USB_ADDR = new_address;
  new_address = 0;
  return(clbst_ok);
}

/*****************************************************************************
 * Name:
 *    usb_stm_ctrl0
 * In:
 *    N/A
 * Out:
 *    status of callback execution
 *
 * Description:
 *    Will decode and handle setup packets on the default endpoint.
 * Assumptions:
 *    Is only called if a setup packet is received.
 *****************************************************************************/
static callback_state_t usb_stm_ctrl0()
{
  hcc_u8 *pdata=(hcc_u8 *)usb_get_rx_pptr(0);

  /* The return value shall reflect the direction of the transfer. */
  callback_state_t r=(STP_REQU_TYPE(pdata) & 1u<<7) ? clbst_in: clbst_out;

  switch (STP_REQU_TYPE(pdata) & 0x7f)
  {
  case 0: /* Standard request for the device. */
    /* Determine what request this is. */
    switch (STP_REQUEST(pdata))
    {
    case USBRQ_SET_ADDRESS:
      new_address=(hcc_u8)(STP_VALUE(pdata) & ((1u << 7)-1u));
      ep_info[0].data_func=cb_set_address;
      break;
    case USBRQ_GET_DESCRIPTOR:
      switch(STP_VALUE(pdata) & 0xff00u)
      {
      case STDD_DEVICE << 8:
        {
          hcc_u8 *p=(hcc_u8*)get_device_descriptor();
          usb_send(0, (void *) 0, p, p[0], STP_LENGTH(pdata));
        }
        break;
      case STDD_CONFIG << 8:
        /* Do we have a CFG descriptor with the requested index? */
        {
          hcc_u8 cfg=(hcc_u8)(STP_VALUE(pdata) & 0xffu);
          /* For index 0 we return the first config descriptor. */
          if (cfg == 0)
          {
            cfg++;
          }
          if (is_cfgd_index(cfg))
          {
            const hcc_u8 *cd;
            cd=get_cfg_descriptor(cfg);
            usb_send(0, (void *) 0, (void*)cd, RD_LE16(&cd[2])
                     , STP_LENGTH(pdata));
            break;
          }
        }
        /* No such descriptor, report error. */
        r=clbst_error;
        break;

      case STDD_STRING << 8:
        /* See if te required descriptor exists. */
        if (is_str_index((hcc_u8)(STP_VALUE(pdata) & 0xffu)))
        {
          usb_send(0, (void *) 0, (void *)get_str_descriptor((hcc_u8)(STP_VALUE(pdata) & 0xffu))
                   , *(hcc_u8*)get_str_descriptor((hcc_u8)(STP_VALUE(pdata) & 0xffu))
                   , STP_LENGTH(pdata));
          break;
        }
        /* No such string descriptor. */
        r=clbst_error;
        break;

      default:
        /* Call user callback if avaiable. */
        goto call_usercb;
      }
      break;
    case USBRQ_GET_CONFIGURATION:
      usb_send(0, (void *) 0, (void *)&usb_current_config
                 , 1
                 , STP_LENGTH(pdata));
      break;
    case USBRQ_SET_CONFIGURATION:
      if (STP_VALUE(pdata) == 0)
      {
        set_config(0);
        break;
      }
      else if (is_cfgd_index(STP_VALUE(pdata)))
      {

        set_config((hcc_u8)STP_VALUE(pdata));
        break;
      }
      r=clbst_error;
      break;
    case USBRQ_SYNCH_FRAME:
    case USBRQ_SET_FEATURE:
    case USBRQ_CLEAR_FEATURE:
    case USBRQ_GET_STATUS:
    case USBRQ_SET_DESCRIPTOR:
    default: /* Unknown or not implemented request. */
      /* Call user callback if avaiable. */
      goto call_usercb;
    }
    break;
  case 1: /* Standard request for an interface. */
      /* Call user callback. */
      goto call_usercb;
  case 2: /* Standard request for an endpoint. */
    switch(STP_REQUEST(pdata))
    {
    case USBRQ_CLEAR_FEATURE:
      switch(STP_VALUE(pdata))
      {
      case FEAT_ENDPOINT_HALT:
        {
          /* Find the endpoint with the address specified int pdata->index.
          assumption: endpoints are allocated after each other. */
          hcc_u8 adr=(hcc_u8)(STP_INDEX(pdata) & 0x7f);

          if (STP_INDEX(pdata) & 0x80)
          {
            hcc_u32 bdt;
            ep_info[adr].data0_tx=0;
            bdt=RD_LE32(&BDT_CTL_TX(adr, 0));
            bdt &= ~BDT_CTL_STALL;
          	WR_LE32(&BDT_CTL_TX(adr, 0), bdt);
            bdt=RD_LE32(&BDT_CTL_TX(adr, 1));
            bdt &= ~BDT_CTL_STALL;

⌨️ 快捷键说明

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