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

📄 usb.c

📁 freescale badge board 开发板测试 源程序
💻 C
📖 第 1 页 / 共 4 页
字号:
 * In:
 *    addr  - endpoint address
 *    type  - endpoint type (control, bulk, interrupt, iso). This is the value
 *            of the endpoint type filed of the endpoint descriptor.
 *    ep    - number of endpoint
 *    psize - maximum packet size allowed for this endpoint.
 *    db    - nonzer of endpoint shall be double buffered. Note: only iso and
 *            bulk endpoints can be double buffered (this is hardware
 *            specific).
 * Out:
 *    0  - all ok
 *    !0 - initialisation failed
 *
 * Description:
 *    Configures the spcified endpoint.
 *****************************************************************************/
static hcc_u8 usb_setup_ep(hcc_u8 addr, hcc_u8 type, hcc_u8 ep, hcc_u16 psize)
{
  hcc_u8 endpt;
   /* Disable endpoint. */
  disable_ep_tx(ep);
  disable_ep_rx(ep);

  if (ep_info[ep].state!=EPST_IDLE)
  {
    ep_info[ep].error=USBEPERR_HOST_ABORT;
  }
  else
  {
    ep_info[ep].error=USBEPERR_NONE;
  }

  ep_info[ep].state=EPST_IDLE;
  ep_info[ep].flags=0;
  ep_info[ep].data_func=(void*)0;
  ep_info[ep].address=0;
  ep_info[ep].tlength=0;
  ep_info[ep].maxlength=0;
  ep_info[ep].psize=psize;
  ep_info[ep].data0_tx=0;
  ep_info[ep].data0_rx=0;
  if (type == EP_TYPE_DISABLE)
  {
    return(0);
  }

  endpt =0;

  /* if RX side of the endpoint needs to be configured */
  if (!(addr & DIR_TX) || type == EP_TYPE_CONTROL)
  {
    endpt |=MCF_USB_ENDPT_EP_RX_EN;

    /* Set BDT_CTL to default value. Set packet size, buffer is owned by the CPU,
       enable data toggle synchronisation, expect data0 packet. Note: data0/1
       will be set when the buffer is given to the USB. */
	WR_LE32(&BDT_CTL_RX(ep, 0), (hcc_u32)((psize << 16) | BDT_CTL_DTS));
    /* Set BDT_CTL to default value. */
    WR_LE32(&BDT_CTL_RX(ep, 1), (hcc_u32)((psize << 16) | BDT_CTL_DTS));

    /* Set RX buffer address. */
    WR_LE32(&BDT_ADR_RX(ep, 0), (hcc_u32)get_ep_rx_buffer(ep, 0));
    WR_LE32(&BDT_ADR_RX(ep, 1), (hcc_u32)get_ep_rx_buffer(ep, 1));
  }
  if ((addr & DIR_TX) || type == EP_TYPE_CONTROL)
  {
    endpt |= MCF_USB_ENDPT_EP_TX_EN;
    /* Set BDT_CTL to default value. Set buffer owned by the CPU. Value of other
       fileds is not important. Those will get a correct value when the buffer is
       made ready for transmission. */
    WR_LE32(&BDT_CTL_TX(ep, 0), 0);
    /* Set BDT_CTL to default value. */
	WR_LE32(&BDT_CTL_TX(ep, 1), 0);
    /* Set TX buffer address. */
  }

  if (type != EP_TYPE_ISO)
  { /* Non ISO endpoints need handhaking. */
    endpt |= MCF_USB_ENDPT_EP_HSHK;
  }
  else
  { /* ISO endpoints do not need handshaking, and retry. */
    endpt |= MCF_USB_ENDPT_RETRY_DIS;
  }

  /* If a non control endpoint uses both directions (e.g. two endpoint is
    implemented in the same hardware slot), then CTL_DIS shall be set. */
  if (type != EP_TYPE_CONTROL)
  {
    endpt |= MCF_USB_ENDPT_EP_CTL_DIS;
  }
  else
  { /* Reception on control endpoints shall be enabled by default. */
    /* Set maximum packet size. */
    WR_LE32(&BDT_CTL_RX(ep, ep_info[ep].next_rx), (hcc_u32)ep_info[ep].psize<<16u);
    ready_ep_rx(ep, ep_info[ep].next_rx);
  }

  MCF_USB_ENDPT(ep)=endpt;

  return(0);
}

/*****************************************************************************
 * Name:
 *    set_config
 * In:
 *    cfg_ndx - index of the configuration to be activated. The value shall
 *              shall equal to one defined in a configuration descriptor.
 * Out:
 *    N/A
 *
 * Description:
 *    Configures the USB module according to the specifyed configuration.
 * Assumptions:
 *    the spefified configuration exists.
 *    the first interface descriptor is for the default alternate setting.
 *    interfaces must be numbered from 0 increasing continously (0,1,2,3...)
 *    configurations must be numbered from 0 increasing continously
 *****************************************************************************/
static void set_config(hcc_u8 cfg_ndx)
{
  hcc_u8 cfg_ep=0;

  usb_current_config=cfg_ndx;

  /* All endpoint shall use buffer 0 now. */
  if (cfg_ndx != 0)
  {
    /* For all interfaces in this configuration. */
    hcc_u8 ifc=0;
    while(is_ifc_ndx(cfg_ndx, ifc, 0))
    { /* Emdpoint descriptor index in configuration descriptor. */
      hcc_u8 ifc_ep=0;
      while(is_ep_ndx(cfg_ndx, ifc, 0, ifc_ep))
      {
        const hcc_u8 *epd=get_ep_descriptor(cfg_ndx, ifc, 0, ifc_ep);
        /* Endpoint index and address is the same. */
        usb_setup_ep(epd[2], epd[3], (hcc_u8)(epd[2] & 0x7fu), RD_LE16(&epd[4]));
        ifc_ep++;
        cfg_ep++;
      }
      ifc++;
    }
    usb_state = USBST_CONFIGURED;
  }
  else
  {
    usb_state=USBST_ADDRESSED;
    /* No endpoints to configure. The loop below will disable all except 0. */
  }

  cfg_ep++;

  while(cfg_ep < 16)
  {
    usb_setup_ep(0, EP_TYPE_DISABLE, cfg_ep++, 0);
  }
}

/*****************************************************************************
 * Name:
 *    enter_default_state
 * In:
 *    N/A
 * Out:
 *    N/A
 *
 * Description:
 *    Configure USB driver to reflect the default state. In this state only
 *    standard requests on the default pipe are answered, all other endpoints
 *    are disabled.
 *****************************************************************************/
static void enter_default_state(void)
{
  int ep;
  /* In this state the USB module responds to the default address.
     Only EP0 is configured. */

  MCF_USB_CTL |= MCF_USB_CTL_ODD_RST;

  for(ep=0; ep<sizeof(ep_info)/sizeof(ep_info[0]); ep++)
  {
    ep_info[ep].next_rx=0;
    ep_info[ep].next_tx=0;
  }
  MCF_USB_CTL &= ~MCF_USB_CTL_ODD_RST;

  /* Configure ep 0. */
  usb_setup_ep(0, EP_TYPE_CONTROL, 0, EP0_PACKET_SIZE);
  /* Disable all other endpoints. */
  set_config(0);

  /* Set address to default address. */
  MCF_USB_ADDR = 0;

  usb_state=USBST_DEFAULT;
  new_address=0;
}


/*****************************************************************************
 * Name:
 *    usb_stop_ep_tx
 * In:
 *    ep - endpoint number
 * Out:
 *    N/A
 * Description:
 *    Will stall a tx endpoint (endpoint will not transmit any more packages,
 *    all IN request from the host will be denyed with error handsake).
 *****************************************************************************/
void usb_stop_ep_tx(hcc_u8 ep)
{
  /* This cal needs to be protected againt USB interrupts, to
     make BDT_CTL assecc atomic. */
  hcc_imask im=_irq_disable();

  /* To enforce stall handshake, we stop both buffers. */
  WR_LE32(&BDT_CTL_TX(ep, 0), BDT_CTL_OWN | BDT_CTL_STALL);
  WR_LE32(&BDT_CTL_TX(ep, 1), BDT_CTL_OWN | BDT_CTL_STALL);

  _irq_restore(im);
}

/*****************************************************************************
 * Name:
 *    usb_stop_ep_rx
 * In:
 *    ep - endpoint number
 * Out:
 *    N/A
 * Description:
 *    Will stall a rx endpoint (endpoint will not treceive any more packages,
 *    all OUT request from the host will be denyed with error handsake).
 *****************************************************************************/
void usb_stop_ep_rx(hcc_u8 ep)
{
  /* This cal needs to be protected againt USB interrupts, to
     make BDT_CTL assecc atomic. */
  hcc_imask im=_irq_disable();

  /* To enforce stall handshake, we stop both buffers. */
  WR_LE32(&BDT_CTL_RX(ep, 0), BDT_CTL_OWN | BDT_CTL_STALL);
  WR_LE32(&BDT_CTL_RX(ep, 1), BDT_CTL_OWN | BDT_CTL_STALL);

  _irq_restore(im);
}

/*****************************************************************************
 * Name:
 *    ready_ep_tx
 * In:
 *    ep - endpoint number
 * Out:
 *    N/A
 * Description:
 *    Make tx endpoint ready for transmission.
 *****************************************************************************/
static void ready_ep_tx(hcc_u8 ep, hcc_u8 buf)
{ /* Simply give buffer to USB. */
  hcc_u32 ctl;

  /* Give buffer to USB, set correct data0/1 flag, configure if data toggle
     synchronisation shall be used or not. */
  ctl=RD_LE32(&BDT_CTL_TX(ep, buf)) & ~0xff;
  ctl |= BDT_CTL_OWN | ep_info[ep].data0_tx | BDT_CTL_DTS;
  WR_LE32(&BDT_CTL_TX(ep, buf), ctl);
}

/*****************************************************************************
 * Name:
 *    ready_ep_rx
 * In:
 *    ep - endpoint number
 * Out:
 *    N/A
 * Description:
 *    Make rx endpoint ready for reception.
 *****************************************************************************/
static void ready_ep_rx(hcc_u8 ep, hcc_u8 buf)
{ /* Simply give buffer to USB. */
  hcc_u32 ctl;

  /* Give buffer to USB, set correct data0/1 flag, configure if data toggle
     synchronisation shall be used or not. */
  ctl = (ep_info[ep].psize << 16) | BDT_CTL_OWN | ep_info[ep].data0_rx | BDT_CTL_DTS;

  ep_info[ep].data0_rx ^= BDT_CTL_DATA;

  WR_LE32(&BDT_CTL_RX(ep, buf), ctl);
}

/*****************************************************************************
 * Name:
 *    disable_ep_tx
 * In:
 *    ep - endpoint number
 * Out:
 *    N/A
 * Description:
 *    Disable TX endpoint. Endpoint behaves as it would not exist (it will not
 *    affect the USB and will not generate any events).
 *****************************************************************************/
static void disable_ep_tx(hcc_u8 ep)
{
  MCF_USB_ENDPT(ep) &= ~MCF_USB_ENDPT_EP_TX_EN;
  while(MCF_USB_ENDPT(ep) & MCF_USB_ENDPT_EP_TX_EN)
    ;
  WR_LE32(&BDT_CTL_TX(ep, 0), 0);
  WR_LE32(&BDT_CTL_TX(ep, 1), 0);
}


/*****************************************************************************
 * Name:
 *    disable_ep_rx
 * In:
 *    ep - endpoint number
 * Out:
 *    N/A
 * Description:
 *    Disable RX endpoint. Endpoint behaves as it would not exist (it will not
 *    affect the USB and will not generate any events).
 *****************************************************************************/
static void disable_ep_rx(hcc_u8 ep)
{
  MCF_USB_ENDPT(ep) &= ~MCF_USB_ENDPT_EP_RX_EN;
}

/*****************************************************************************
 * Name:
 *    _usb_send
 * In:
 *    ep - endpoint number
 * Out:
 *    N/A
 * Description:
 *    This fucntion inmplements the basic state machine for transmit (IN)
 *    endpoints. It will
 *        - call user callback functions if neccessary,
 *        - set endpoint specific error codes
 *        - split data to be sent to packet sized pieces
 *    Note: it is called from the interrupt handler routine and from "user
 *          space" too. The function needs to be reentrant!
 *****************************************************************************/
static void _usb_send(hcc_u8 ep)
{
  hcc_u32 l;
  hcc_u8 buf;
  hcc_u32 length;

  switch (ep_info[ep].state)
  {
  case EPST_DATA_TX:
    l=MIN(ep_info[ep].tlength, ep_info[ep].psize);
    CMX_ASSERT(l == ep_info[ep].psize || l==ep_info[ep].tlength);      

    /* Select next ep buffer. */
    buf=select_tx_buf(ep);
    /* Set-up UBS module to directly send from applications buffer. */
    WR_LE32(&BDT_ADR_TX(ep, buf), (hcc_u32)ep_info[ep].address);

    /* Set tx packet length. */
    length=MIN(ep_info[ep].psize, ep_info[ep].tlength);
    WR_LE32(&BDT_CTL_TX(ep, buf), (hcc_u32)(length<<16u));

    /* Make buffer ready for transmission. */
    ready_ep_tx(ep, buf);
    /* Invert the data toggle bit. */
    ep_info[ep].data0_tx ^= BDT_CTL_DATA;

    /* Calculate transfer status. */
    ep_info[ep].tlength -= l;
    ep_info[ep].address = (hcc_u8*)ep_info[ep].address + l;

    /* Is the just created packet the last one? */
    if (ep_info[ep].tlength == 0)
    { /* Do we need to send a zero length packet to terminate the transmission? */
      if ((l == ep_info[ep].psize) && (ep_info[ep].flags & EPFL_ZPACKET))
      {
        ep_info[ep].state=EPST_TX_STOP;
      }
      else
      {
        ep_info[ep].state=EPST_DATA_TX_LAST;
      }
      /* Warning: when getting there, an additional interrupt is needed to advance the
         state succesfully. */
      break;
    }
    break;
  case EPST_DATA_TX_WAIT_DB:
    /* Let second buffer get empty while waiting for a new buffer. */
    ep_info[ep].state=EPST_DATA_TX_EMPTY_DB;
    break;
  case EPST_TX_STOP:
    /* Send a sort packet. */
    ep_info[ep].state=EPST_DATA_TX_LAST;
    send_zero_packet(ep);

⌨️ 快捷键说明

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