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

📄 usbs_at91.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 3 页
字号:
  int epn;
  const usb_endpoint_descriptor *usb_endpoints;
  cyg_uint8 endpoint_type;
  
   cyg_uint8 endpoint_number;

  usbs_end_all_transfers (-EPIPE);
  
  HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_IDR, 0xffffffff);
  HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_ICR, 0xffffffff);
  HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_RST_EP, 0xffffffff);
  HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_RST_EP, 0x00000000);
  
  HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_FADDR, AT91_UDP_FADDR_FEN);
  HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_CSR0,
                    AT91_UDP_CSR_EPEDS | AT91_UDP_CSR_EPTYPE_CTRL);
  HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_IER, AT91_UDP_ALLOWED_IRQs);
  
  for (epn=1; epn < AT91_USB_ENDPOINTS; epn++) {
    usbs_at91_endpoint_init ((usbs_rx_endpoint *)usbs_at91_endpoints[epn], 
                             0, false);
  }

  // Now walk the endpoints configuring them correctly. This only
  // works if there is one interface.
  usb_endpoints = usbs_at91_ep0.enumeration_data->endpoints;
  
  for (epn = 1; 
       epn <= usbs_at91_ep0.enumeration_data->total_number_endpoints; 
       epn++) {
    
    endpoint_type = (usb_endpoints[epn-1].attributes |
                     (usb_endpoints[epn-1].endpoint & 
                      USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN ?
                      USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN : 
                      USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT));
    endpoint_number = usb_endpoints[epn-1].endpoint & ~(USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN); 
    if ( endpoint_number < AT91_USB_ENDPOINTS )
    {
        usbs_at91_endpoint_init((usbs_rx_endpoint *)usbs_at91_endpoints[endpoint_number],
                                endpoint_type,
                                true);
    }
  }
}

static void
usbs_at91_ep0_start (usbs_control_endpoint * endpoint)
{
  usbs_at91_handle_reset ();

  // If there is additional platform-specific initialization to
  // perform, do it now. This macro can come from the platform HAL,
  // but may not be available on all platforms.
#ifdef AT91_USB_PLATFORM_INIT
  AT91_USB_PLATFORM_INIT ();
#endif
  
  usbs_at91_set_pullup (true);
}

static void
usbs_at91_endpoint_start (usbs_rx_endpoint * pep)
{  
  int epn = usbs_at91_pep_to_number(pep);
  cyg_addrword_t pCSR = pCSRn(epn);
  cyg_addrword_t pFDR = pFDRn(epn);
  cyg_uint16 space = 0;
  cyg_uint16 endpoint_size = usbs_at91_endpoint_fifo_size[epn];
  cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[epn];
  cyg_uint8 **ppend = &usbs_at91_endpoint_pend[epn];
  
  CYG_ASSERT (pep->complete_fn, "No complete_fn()");

  cyg_drv_dsr_lock ();
  if (usbs_at91_ep0.state != USBS_STATE_CONFIGURED) {   
    /* If not configured it means there is nothing to do */
    cyg_drv_dsr_unlock ();
    
    if (pep->complete_fn) {
      (*pep->complete_fn) (pep->complete_data, -EPIPE);
    }
    return;
  }
  
  if (pep->halted) {            
    /* Halted means nothing to do */
    cyg_drv_dsr_unlock ();

    if (pep->complete_fn) {
      (*pep->complete_fn) (pep->complete_data, -EAGAIN);
    }
    return;
  }

  if (BITS_ARE_SET (pIMR, 1 << epn)) {
    cyg_drv_dsr_unlock ();

    if (pep->complete_fn) {
      (*pep->complete_fn) (pep->complete_data, -EIO);
    }
    
    return;
  }
  
  CYG_ASSERT (BITS_ARE_SET (pCSR, 1 << 9), "Wrong endpoint type");
  
  *ppbegin = pep->buffer;       /* Set the working pointers */
  *ppend = (cyg_uint8 *) ((cyg_uint32) pep->buffer + pep->buffer_size);
  
  if (BITS_ARE_SET (pCSR, 0x400)) {     /* IN: tx_endpoint */
    space = (cyg_uint32) * ppend - (cyg_uint32) * ppbegin;
    if (space == endpoint_size) {
      *ppend = *ppbegin;        /* Send zero-packet */
    }
    
    *ppbegin =
      write_fifo_uint8 (pFDR, *ppbegin,
                        (cyg_uint8 *) ((cyg_uint32) * ppbegin +
                                       MIN (space, endpoint_size)));
    SET_BITS (pCSR, AT91_UDP_CSR_TXPKTRDY);
    
    if (*ppend == *ppbegin) {   /* Last packet ? */
      *ppend = *ppbegin - 1;    /* The packet hasn't been sent yet */
    }
  }
  
  usbs_at91_endpoint_interrupt_enable (epn, true);
  
  cyg_drv_dsr_unlock ();
}

// Perform transmit handling on an endpoint
static bool 
usbs_at91_endpoint_isr_tx(cyg_uint8 epn)
{
  cyg_addrword_t pCSR = pCSRn(epn);
  cyg_addrword_t pFDR = pFDRn(epn);
  cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[epn];
  cyg_uint8 **ppend = &usbs_at91_endpoint_pend[epn];
  cyg_uint32 space = 0;
  cyg_uint16 endpoint_size = usbs_at91_endpoint_fifo_size[epn];

  CLEAR_BITS (pCSR, AT91_UDP_CSR_TXCOMP);

  if (BITS_ARE_CLEARED (pCSR, AT91_UDP_CSR_TXPKTRDY)) {       
    /* Ready to transmit ? */
    if (*ppend > *ppbegin) {  
      /* Something to send */
      
      space = (cyg_uint32) * ppend - (cyg_uint32) * ppbegin;
      if (space == endpoint_size) {
        *ppend = *ppbegin;            /* Send zero-packet */
      }
      
      *ppbegin =
        write_fifo_uint8 (pFDR, *ppbegin,
                          (cyg_uint8 *) ((cyg_uint32) * ppbegin +
                                         MIN (space, endpoint_size)));
      SET_BITS (pCSR, AT91_UDP_CSR_TXPKTRDY);
      
      if (*ppend == *ppbegin) {       /* Last packet ? */
        *ppend = *ppbegin - 1;        /* The packet isn't sent yet */
      }
    } else {
      if (*ppend + 1 == *ppbegin) {
        *ppend = *ppbegin;    /* Flag for DSR */
        return true;
      } else {
        *ppend = *ppbegin - 1;        /* Flag for zero-packet */
        SET_BITS (pCSR, AT91_UDP_CSR_TXPKTRDY);       /* Send no data */
      }
    }
  }
  
  CLEAR_BITS (pCSR,
              AT91_UDP_CSR_RX_DATA_BK0 | AT91_UDP_CSR_RX_DATA_BK1 |
              AT91_UDP_CSR_RXSETUP | AT91_UDP_CSR_ISOERROR);
  return false;
}

static bool
usbs_at91_endpoint_isr_rx(cyg_uint8 epn)
{
  cyg_addrword_t pCSR = pCSRn(epn);
  cyg_addrword_t pFDR = pFDRn(epn);
  cyg_uint16 *pinfifo = &usbs_at91_endpoint_bytes_in_fifo[epn];
  cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[epn];
  cyg_uint8 **ppend = &usbs_at91_endpoint_pend[epn];
  cyg_uint16 *preceived = &usbs_at91_endpoint_bytes_received[epn];
  cyg_uint16 endpoint_size = usbs_at91_endpoint_fifo_size[epn];

  if (*preceived == THERE_IS_A_NEW_PACKET_IN_THE_UDP) {      
    /* There is a new packet */
    *preceived = ((*(cyg_uint32 *)pCSR) >> 16) & 0x7ff;    
    *pinfifo = *preceived;           
  }

  while ((*ppbegin < *ppend) && *pinfifo) { 
    /* If we have buffer-space AND data in the FIFO */
    HAL_READ_UINT8(pFDR, **ppbegin);
    (*ppbegin)++;
    (*pinfifo)--;
  }
  
  if (*ppbegin == *ppend) { 
    /* The buffer is full... call the DSR */
    return true;
  }
  
  if (*pinfifo == 0) {      
    /* If the FIFO is empty, then we can release it */
    if (usbs_at91_endpoint_pingpong[epn]) { 
      /* Time to clear the interrupt flag */
      
      if (usbs_at91_endpoint_bank1[epn]) {
        CLEAR_BITS (pCSR, AT91_UDP_CSR_RX_DATA_BK1);
      } else {
        CLEAR_BITS (pCSR, AT91_UDP_CSR_RX_DATA_BK0);
      }
      usbs_at91_endpoint_bank1[epn] = !usbs_at91_endpoint_bank1[epn];
    } else {
      CLEAR_BITS (pCSR, AT91_UDP_CSR_RX_DATA_BK0);
    }
    
    if (*preceived < endpoint_size) {
      /* If the last packet was smaller then the endpoint-size... */
      *ppend = *ppbegin;
      *preceived = THERE_IS_A_NEW_PACKET_IN_THE_UDP; /* Set flag */
      
      return true;     /* We can call the completion-function in the DSR */
    }
    
    *preceived = THERE_IS_A_NEW_PACKET_IN_THE_UDP;   /* Set flag */
  }
  return false;
}
    
// ISR for an endpoint. Handle receive and transmit interrupts.
static bool
usbs_at91_endpoint_isr (cyg_uint8 epn)
{                               
  cyg_addrword_t pCSR = pCSRn(epn);
  
  CYG_ASSERT (AT91_USB_ENDPOINTS > epn && epn, "Invalid end point");
  
  if (BITS_ARE_SET (pCSR, 0x400)) {      /* IN: tx_endpoint */
    if (usbs_at91_endpoint_isr_tx(epn))
      return true;  // Call the DSR
  } else {                               /* OUT: rx_endpoint */
    if (!BITS_ARE_CLEARED (pCSR, AT91_UDP_CSR_RX_DATA_BK0) || 
        !BITS_ARE_CLEARED (pCSR, AT91_UDP_CSR_RX_DATA_BK1)) {   
      /* Sometime something received ? */
      if(usbs_at91_endpoint_isr_rx(epn))
        return true; // Call the DSR;
    }
        
        CLEAR_BITS (pCSR,
                AT91_UDP_CSR_TXCOMP | AT91_UDP_CSR_RXSETUP |
                AT91_UDP_CSR_ISOERROR);
  }

  return false;
}

// Handle a DSR for an endpoint
static void
usbs_at91_endpoint_dsr (cyg_uint8 epn)
{
  usbs_rx_endpoint *pep = (usbs_rx_endpoint *) usbs_at91_endpoints[epn];
  cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[epn];
  cyg_uint8 **ppend = &usbs_at91_endpoint_pend[epn];

  CYG_ASSERT (AT91_USB_ENDPOINTS > epn && epn, "Invalid end point");
  CYG_ASSERT (pep->complete_fn, "No complete_fn()");

  if (*ppend == *ppbegin) {     /* Transmitted/Received ? */
    
    pep->buffer_size = (cyg_uint32) * ppbegin - (cyg_uint32) pep->buffer;
    if (pep->buffer_size && pep->complete_fn) {
      if (!pep->halted) {
        (*pep->complete_fn) (pep->complete_data, pep->buffer_size);
      } else {
        (*pep->complete_fn) (pep->complete_data, -EAGAIN);
      }
    }
    usbs_at91_endpoint_interrupt_enable (epn, false);
  }
}

// Handle an error condition on the control endpoint
static ep0_low_level_status_t
usbs_at91_control_error(ep0_low_level_status_t status)
{
  cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[0];
  cyg_uint8 **ppend = &usbs_at91_endpoint_pend[0];

  usbs_at91_ep0.buffer_size = 0;
  usbs_at91_ep0.fill_buffer_fn = 0;
  usbs_at91_ep0.complete_fn = 0;
  
  *ppbegin = usbs_at91_ep0.buffer;
  *ppend = *ppbegin;
  
  if (status == EP0_LL_IDLE) {
    if (usbs_at91_ep0.complete_fn) {
      (*usbs_at91_ep0.complete_fn) (&usbs_at91_ep0,
                                    USBS_CONTROL_RETURN_STALL);
    }
  }
  
  status = EP0_LL_IDLE;
  
  CLEAR_BITS (pCSR0, AT91_UDP_CSR_ISOERROR | AT91_UDP_CSR_FORCESTALL);
  
  return status;
}

// Handle a get status setup message on the control end point
static ep0_low_level_status_t 
usbs_at91_control_setup_get_status(void)
{
  ep0_low_level_status_t status;
  usb_devreq *req = (usb_devreq *)usbs_at91_ep0.control_buffer;
  cyg_uint8 recipient = req->type & USB_DEVREQ_RECIPIENT_MASK;
  cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[0];
  cyg_uint8 **ppend = &usbs_at91_endpoint_pend[0];
  cyg_uint16 word = 0;
  
  status = EP0_LL_SEND_READY;
  
  switch (recipient) {
    case USB_DEVREQ_RECIPIENT_DEVICE:
    case USB_DEVREQ_RECIPIENT_INTERFACE:
      // Nothing to do
      break;
    case USB_DEVREQ_RECIPIENT_ENDPOINT: 
      if ((usbs_at91_ep0.state == USBS_STATE_CONFIGURED) && 
          (req->index_lo > 0) && 
          (req->index_lo < AT91_USB_ENDPOINTS)) {
        cyg_uint32 CSR;
        
        HAL_READ_UINT32(pCSRn(req->index_lo), CSR);
        if (CSR & AT91_UDP_CSR_EPEDS) {
          word = 1;
        }
      } else {
        status = EP0_LL_STALL;
      }
      break;
    default:
      status = EP0_LL_STALL;
  }
  
  *ppbegin = (cyg_uint8 *)&word;
  *ppend = *ppbegin + sizeof (word);
  return status;
}

// Setup the begin and end pointers such that an ACK is sent
static void
usbs_at91_control_setup_send_ack(void)
{
  cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[0];
  cyg_uint8 **ppend = &usbs_at91_endpoint_pend[0];
  
  *ppbegin = usbs_at91_ep0.buffer;
  *ppend = *ppbegin;
}

// Handle a get status set feature message on the control endpoint
static ep0_low_level_status_t 
usbs_at91_control_setup_set_feature(void)
{
  ep0_low_level_status_t status;
  usb_devreq *req = (usb_devreq *)usbs_at91_ep0.control_buffer;
  cyg_uint8 recipient = req->type & USB_DEVREQ_RECIPIENT_MASK;
  
  usbs_at91_control_setup_send_ack();
  status = EP0_LL_SEND_READY;
  
  switch(recipient) {
    case USB_DEVREQ_RECIPIENT_DEVICE:
      status = EP0_LL_STALL;
      break;
    case USB_DEVREQ_RECIPIENT_INTERFACE:
      // Nothing to do
      break;
    case USB_DEVREQ_RECIPIENT_ENDPOINT: 
      if ((usbs_at91_ep0.state == USBS_STATE_CONFIGURED) && 
          (req->index_lo > 0) && 
          (req->index_lo < AT91_USB_ENDPOINTS)) {
        cyg_uint32 CSR;
        
        HAL_READ_UINT32(pCSRn(req->index_lo), CSR);
        if (CSR & AT91_UDP_CSR_EPEDS) {
          /* TODO */
        }
      } else {
        status = EP0_LL_STALL;
      }
    default:
      status = EP0_LL_STALL;
  }
  return status;
}

// Handle a get status clear feature message on the control endpoint
static ep0_low_level_status_t 
usbs_at91_control_setup_clear_feature(void)
{
  ep0_low_level_status_t status;
  usb_devreq *req = (usb_devreq *)usbs_at91_ep0.control_buffer;
  cyg_uint8 recipient = req->type & USB_DEVREQ_RECIPIENT_MASK;
  
  usbs_at91_control_setup_send_ack();
  status = EP0_LL_SEND_READY;

  switch (recipient) {
    case USB_DEVREQ_RECIPIENT_DEVICE:
      status = EP0_LL_STALL;
      break;
    case USB_DEVREQ_RECIPIENT_INTERFACE:
      // Nothing to do
      break;
    case USB_DEVREQ_RECIPIENT_ENDPOINT: 
      if ((usbs_at91_ep0.state == USBS_STATE_CONFIGURED) && 
          (req->index_lo > 0) && 
          (req->index_lo < AT91_USB_ENDPOINTS)) {
        cyg_uint32 CSR;
        
        HAL_READ_UINT32(pCSRn(req->index_lo), CSR);
        if (CSR & AT91_UDP_CSR_EPEDS) {
          /* TODO */
        }
      } else {
        status = EP0_LL_STALL;
      }
    default:
      status = EP0_LL_STALL;
  }
  return status;
}

// Handle a setup message from the host
static ep0_low_level_status_t
usbs_at91_control_setup(ep0_low_level_status_t status)
{
  cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[0];
  cyg_uint8 **ppend = &usbs_at91_endpoint_pend[0];
  usb_devreq *req = (usb_devreq *) usbs_at91_ep0.control_buffer;
  cyg_uint8   protocol;
  cyg_uint16 length;
  bool dev_to_host;
  usbs_control_return usbcode;
  bool handled = false;
  
  usbs_at91_ep0.buffer_size = 0;
  usbs_at91_ep0.fill_buffer_fn = 0;
  usbs_at91_ep0.complete_fn = 0;
  
  read_fifo_uint8 ((cyg_uint8 *)req, pFDR0, sizeof (usb_devreq));

  length = (req->length_hi << 8) | req->length_lo;;
  dev_to_host = req->type & USB_DEVREQ_DIRECTION_IN;
  
  CLEAR_BITS (pCSR0, AT91_UDP_CSR_DTGLE);

  status = EP0_LL_REQUEST;

⌨️ 快捷键说明

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