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

📄 usbs_at91.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 3 页
字号:
//==========================================================================
//
//      usbs_at91.c
//
//      Driver for the AT91 USB device
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 2006 eCosCentric
// Copyright (C) 2006 Andrew Lunn
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    Oliver Munz,
// Contributors: Andrew Lunn, bartv
// Date:         2006-02-22
//
// This code implements support for the on-chip USB port on the AT91
// family of processors. The code has been developed on the AT91SAM7S
// and may or may not work on other members of the AT91 family.
//
//####DESCRIPTIONEND####
//==========================================================================

#include <pkgconf/devs_usb_at91.h>
#include <cyg/io/usb/usb.h>
#include <cyg/io/usb/usbs.h>
#include <cyg/io/usb/usbs_at91.h>

#include <cyg/hal/hal_io.h>
#include <cyg/hal/drv_api.h>
#include <cyg/hal/hal_io.h>
#include <cyg/hal/hal_platform_ints.h>
#include <cyg/infra/cyg_ass.h>
#include <cyg/infra/diag.h>

#include "bitops.h"

#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif

#define AT91_UDP_CSR0 (AT91_UDP_CSR)
#define AT91_UDP_FDR0 (AT91_UDP_FDR)

#define pIER (AT91_UDP + AT91_UDP_IER)
#define pIDR (AT91_UDP + AT91_UDP_IDR)
#define pISR (AT91_UDP + AT91_UDP_ISR)
#define pIMR (AT91_UDP + AT91_UDP_IMR)
#define pICR (AT91_UDP + AT91_UDP_ICR)

#define pCSR0 (AT91_UDP + AT91_UDP_CSR0)
#define pFDR0 (AT91_UDP + AT91_UDP_FDR0)

#define pCSRn(N) (pCSR0 + (N * 4))
#define pFDRn(N) (pFDR0 + (N * 4))

#define AT91_UDP_ALLOWED_IRQs \
    (AT91_UDP_WAKEUP | AT91_UDP_ENDBUSRES | AT91_UDP_EXTRSM | \
     AT91_UDP_RXRSM  | AT91_UDP_RXSUSP    | AT91_UDP_EPINT0 | \
     AT91_UDP_EPINT1 | AT91_UDP_EPINT2    | AT91_UDP_EPINT3)

#define THERE_IS_A_NEW_PACKET_IN_THE_UDP 0xffff

// Fifo size for each end point.
static const cyg_uint16 usbs_at91_endpoint_fifo_size[AT91_USB_ENDPOINTS] = {
  8,
  64,
  64,
  64,
};

// Does an endpoint support ping pong buffering?
static const bool usbs_at91_endpoint_pingpong[AT91_USB_ENDPOINTS] = {
  false,
  true,
  true,
  false
};

static cyg_uint8 *usbs_at91_endpoint_pbegin[AT91_USB_ENDPOINTS] = 
  { 0, 0, 0, 0 };
static cyg_uint8 *usbs_at91_endpoint_pend[AT91_USB_ENDPOINTS] = 
  { 0, 0 ,0, 0 };
static bool usbs_at91_endpoint_bank1[AT91_USB_ENDPOINTS] = 
  { false, false, false, false };
static cyg_uint16 usbs_at91_endpoint_bytes_in_fifo[AT91_USB_ENDPOINTS] =
  { 0, 0, 0, 0 };
static cyg_uint16 usbs_at91_endpoint_bytes_received[AT91_USB_ENDPOINTS] =
  { THERE_IS_A_NEW_PACKET_IN_THE_UDP, THERE_IS_A_NEW_PACKET_IN_THE_UDP,
    THERE_IS_A_NEW_PACKET_IN_THE_UDP, THERE_IS_A_NEW_PACKET_IN_THE_UDP};

static cyg_interrupt usbs_at91_intr_data;
static cyg_handle_t usbs_at91_intr_handle;

static void usbs_at91_ep0_start(usbs_control_endpoint *);
static void usbs_at91_poll(usbs_control_endpoint *);

static void usbs_at91_endpoint_start(usbs_rx_endpoint * pep);
static void usbs_at91_endpoint_set_halted(usbs_rx_endpoint * pep, 
                                          cyg_bool new_value);
void usbs_at91_endpoint_init(usbs_rx_endpoint * pep, 
                             cyg_uint8 endpoint_type,
                             cyg_bool enable);

// Endpoint 0, the control endpoint, structure. 
usbs_control_endpoint usbs_at91_ep0 = {
  // The hardware does not distinguish  between detached, attached and powered.
  state:                  USBS_STATE_POWERED,   
  enumeration_data:       (usbs_enumeration_data *) 0,
  start_fn:               usbs_at91_ep0_start,
  poll_fn:                usbs_at91_poll,
  interrupt_vector:       CYGNUM_HAL_INTERRUPT_UDP,
  control_buffer:         {0, 0, 0, 0, 0, 0, 0, 0},
  state_change_fn:        (void (*) (usbs_control_endpoint *, 
                                     void *, usbs_state_change, int)) 0,
  state_change_data:      (void *) 0,
  standard_control_fn:    (usbs_control_return (*)
                          (usbs_control_endpoint *, void *)) 0,
  standard_control_data:  (void *) 0,
  class_control_fn:       (usbs_control_return (*)
                           (usbs_control_endpoint *, void *)) 0,
  class_control_data:     (void *) 0,
  vendor_control_fn:      (usbs_control_return (*) 
                           (usbs_control_endpoint *, void *)) 0,
  vendor_control_data:    (void *) 0,
  reserved_control_fn:    (usbs_control_return (*) 
                           (usbs_control_endpoint *, void *)) 0,
  reserved_control_data:  (void *) 0,
  buffer:                 (unsigned char *) 0,
  buffer_size:            0,
  fill_buffer_fn:         (void (*)(usbs_control_endpoint *)) 0,
  fill_data:              (void *) 0,
  fill_index:             0,
  complete_fn:            (usbs_control_return (*)(usbs_control_endpoint *, 
                                                   int)) 0
};

// Endpoint 1 receive control structure
usbs_rx_endpoint usbs_at91_ep1 = {
  start_rx_fn:    usbs_at91_endpoint_start,
  set_halted_fn:  usbs_at91_endpoint_set_halted,
  complete_fn:    (void (*)(void *, int)) 0,
  complete_data:  (void *) 0,
  buffer:         (unsigned char *) 0,
  buffer_size:    0,
  halted:         0,
}; 

// Endpoint 2 Receive control structure
usbs_rx_endpoint usbs_at91_ep2 = {
  start_rx_fn:    usbs_at91_endpoint_start,
  set_halted_fn:  usbs_at91_endpoint_set_halted,
  complete_fn:    (void (*)(void *, int)) 0,
  complete_data:  (void *) 0,
  buffer:         (unsigned char *) 0,
  buffer_size:    0,
  halted:         0,
};

// Endpoint 3 Receive control structure
usbs_rx_endpoint usbs_at91_ep3 = {
  start_rx_fn:    usbs_at91_endpoint_start,
  set_halted_fn:  usbs_at91_endpoint_set_halted,
  complete_fn:    (void (*)(void *, int)) 0,
  complete_data:  (void *) 0,
  buffer:         (unsigned char *) 0,
  buffer_size:    0,
  halted:         0,
};

// Array of end points. Used for translating end point pointer to an
// end point number
static const void *usbs_at91_endpoints[AT91_USB_ENDPOINTS] = {
  (void *) &usbs_at91_ep0,
  (void *) &usbs_at91_ep1,
  (void *) &usbs_at91_ep2,
  (void *) &usbs_at91_ep3
};

// Convert an endpoint pointer to an endpoint number, using the array
// of endpoint structures
static int
usbs_at91_pep_to_number(const usbs_rx_endpoint * pep)
{
  int epn;
  
  for(epn=0; epn < AT91_USB_ENDPOINTS; epn++) {
    if (pep == usbs_at91_endpoints[epn])
      return epn;
  }
  CYG_FAIL("Unknown endpoint");
  return 0;
}

typedef enum ep0_low_level_status_t {
  EP0_LL_IDLE = 0,
  EP0_LL_REQUEST,
  EP0_LL_SEND_READY,
  EP0_LL_ACK,
  EP0_LL_RECEIVE_READY,
  EP0_LL_ISOERROR,
  EP0_LL_STALL,
  EP0_LL_SET_ADDRESS,
} ep0_low_level_status_t;

// Enable/Disable interrupts for a specific endpoint.
static void
usbs_at91_endpoint_interrupt_enable (cyg_uint8 epn, bool enable)
{
  CYG_ASSERT (epn < AT91_USB_ENDPOINTS, "Invalid endpoint");
  
  if (enable) {
    HAL_WRITE_UINT32 (pIER, 1 << epn);
  } else {
    HAL_WRITE_UINT32 (pIDR, 1 << epn);
  }
}

static cyg_uint8 *
read_fifo_uint8 (cyg_uint8 * pdest, cyg_addrword_t psource, cyg_uint32 size)
{
  cyg_uint8 *preqbyte = pdest;
  cyg_uint8 reqbyte;
  
  while (size--) {
    HAL_READ_UINT8 (psource, reqbyte);
    *preqbyte = reqbyte;
    preqbyte++;
  }

  return preqbyte;
}

static cyg_uint8 *
write_fifo_uint8 (cyg_addrword_t pdest, cyg_uint8 * psource,
                      cyg_uint8 * psource_end)
{
  cyg_uint8 *preqbyte;

  for (preqbyte = psource; preqbyte < psource_end; preqbyte++) {
    HAL_WRITE_UINT8 (pdest, (*preqbyte));
  }
  
  return preqbyte;
}

/* Tell the host that the device is ready to start communication */
static void
usbs_at91_set_pullup (bool set)
{                

#ifndef CYGDAT_DEVS_USB_AT91_GPIO_SET_PULLUP_PIN_NONE
  if (
#ifdef CYGNUM_DEVS_USB_AT91_GPIO_SET_PULLUP_INVERTED
      !set
#else
      set
#endif
      ) {
     HAL_ARM_AT91_GPIO_SET(CYGDAT_DEVS_USB_AT91_GPIO_SET_PULLUP_PIN);
  } else {
     HAL_ARM_AT91_GPIO_RESET(CYGDAT_DEVS_USB_AT91_GPIO_SET_PULLUP_PIN);
  }
#endif
}
  
/* Is the USB powered? */
bool
usbs_at91_read_power (void)
{
#ifndef CYGDAT_DEVS_USB_AT91_GPIO_READ_POWER_PIN_NONE
  cyg_bool state;
  
  HAL_ARM_AT91_GPIO_GET(CYGDAT_DEVS_USB_AT91_GPIO_READ_POWER_PIN, state);
#ifdef CYGNUM_DEVS_USB_AT91_GPIO_READ_POWER_INVERTED
  return !state;
#else
  return state;
#endif
#endif
  return true;
}

// Stop all transfers that are currently active.
static void
usbs_end_all_transfers (usbs_control_return returncode)
{
  cyg_uint32 epn;
  usbs_rx_endpoint *pep;
  
  for (epn = 1; epn < AT91_USB_ENDPOINTS; epn++) {
    if (BITS_ARE_SET (pIMR, 1 << epn)) {
      // If the end point is transmitting, call the complete function
      // to terminate to transfer
      pep = (usbs_rx_endpoint *) usbs_at91_endpoints[epn];

      if (pep->complete_fn) {
        (*pep->complete_fn) (pep->complete_data, returncode);
      }
      // Disable interrupts from the endpoint
      usbs_at91_endpoint_interrupt_enable (epn, false);
    }
  }
}

// There has been a change in state. Update the end point.
static void
usbs_state_notify (usbs_control_endpoint * pcep)
{
  static int old_state = USBS_STATE_CHANGE_POWERED;
  int state = pcep->state & USBS_STATE_MASK;
  
  if (pcep->state != old_state) {
    usbs_end_all_transfers (-EPIPE);
    switch (state) {
      case USBS_STATE_DETACHED:
      case USBS_STATE_ATTACHED:
      case USBS_STATE_POWERED:
        // Nothing to do
        break;
      case USBS_STATE_DEFAULT:
        HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_GLB_STATE, 0);
        break;
      case USBS_STATE_ADDRESSED:
        HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_GLB_STATE, AT91_UDP_GLB_FADDEN);
        break;
      case USBS_STATE_CONFIGURED:
        HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_GLB_STATE, AT91_UDP_GLB_CONFG);
        break;
      default:
        CYG_FAIL("Unknown endpoint state");
    }
    
    if (pcep->state_change_fn) {
      (*pcep->state_change_fn) (pcep, 0, pcep->state, old_state);
    }
    
    old_state = pcep->state;
  }
}

static usbs_control_return
usbs_parse_host_get_command (usbs_control_endpoint * pcep)
{
  usbs_control_return retcode;
  cyg_uint8 dev_req_type =
    (((usb_devreq *) pcep->control_buffer)->type) & USB_DEVREQ_TYPE_MASK;
  
  switch (dev_req_type) {
    case USB_DEVREQ_TYPE_STANDARD: 
      if (!pcep->standard_control_fn) {
        return usbs_handle_standard_control (pcep);
      }

      retcode =
        (*pcep->standard_control_fn) (pcep, pcep->standard_control_data);
      
      if (retcode == USBS_CONTROL_RETURN_UNKNOWN) {
        return usbs_handle_standard_control (pcep);
      }
      return retcode;
    
    case USB_DEVREQ_TYPE_CLASS:
      if (!pcep->class_control_fn) {
        return USBS_CONTROL_RETURN_STALL;
      }
      return (*pcep->class_control_fn) (pcep, pcep->class_control_data);

    case USB_DEVREQ_TYPE_VENDOR: 
      if (!pcep->class_control_fn) {
        return USBS_CONTROL_RETURN_STALL;
      }
      return (*pcep->class_control_fn) (pcep, pcep->vendor_control_data);

    case USB_DEVREQ_TYPE_RESERVED:
      if (!pcep->reserved_control_fn) {
        return USBS_CONTROL_RETURN_STALL;
      }
      return (*pcep->reserved_control_fn) (pcep, pcep->reserved_control_data);
    default:
      return USBS_CONTROL_RETURN_STALL;
  }
}

static void
usbs_at91_endpoint_set_halted (usbs_rx_endpoint * pep, cyg_bool new_value)
{
  int epn = usbs_at91_pep_to_number(pep);
  cyg_addrword_t pCSR = pCSRn(epn);
  
  cyg_drv_dsr_lock ();
  
  if (pep->halted != new_value) {       
    /* There is something is to do */
    pep->halted = new_value;
    
    if (new_value && BITS_ARE_SET (pIMR, 1 << epn)) {   
      /* Ready to transmit */
      if (pep->complete_fn) {
        (*pep->complete_fn) (pep->complete_data, -EAGAIN);
      }
      usbs_at91_endpoint_interrupt_enable (epn, false);
      SET_BITS (pCSR, AT91_UDP_CSR_FORCESTALL);
    } else {
      CLEAR_BITS (pCSR, AT91_UDP_CSR_FORCESTALL);
    }
  }
  cyg_drv_dsr_unlock ();
}

void
usbs_at91_endpoint_init (usbs_rx_endpoint * pep, cyg_uint8 endpoint_type,
                         cyg_bool enable)
{  
  int epn = usbs_at91_pep_to_number(pep);
  cyg_addrword_t pCSR = pCSRn(epn);
  
  CYG_ASSERT (AT91_USB_ENDPOINTS > epn, "Invalid end point");
  
  usbs_at91_endpoint_interrupt_enable (epn, false);
  /* Reset endpoint */
  HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_RST_EP, 1 << epn);      
  HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_RST_EP, 0);
  
  pep->halted = false;

  /* Type | In */
  HAL_WRITE_UINT32 (pCSR, (((((cyg_uint32) endpoint_type) & 0x03) << 8) | 
                           ((((cyg_uint32) endpoint_type) & 0x80) << 3)));

  usbs_at91_endpoint_bytes_in_fifo[epn] = 0;
  usbs_at91_endpoint_bytes_received[epn] = THERE_IS_A_NEW_PACKET_IN_THE_UDP;
  usbs_at91_endpoint_bank1[epn] = false;

  if (enable) {
    SET_BITS (pCSR, AT91_UDP_CSR_EPEDS);
  }
}

static void
usbs_at91_handle_reset (void)
{

⌨️ 快捷键说明

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