usbs_d12.c

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

C
1,974
字号
// both buffers are full, and if so, read them both.
//
// Side Effects:
//              - Leaves endp_idx as the currently selected endpoint.
//
// Parameters:
//      endp_idx    the endpoint from which to read
//      buf         buffer to receive the data. This MUST be at least the size
//                  of the chip's RAM buffer for the specified endpoint.
//                  For the Main endp, it must be 2x the buffer size (128 total)
//
// Returns: the # of bytes read.

static uint8 
d12_read_endp_buf(d12_addr_type base_addr, byte endp_idx, byte *buf)
{
  return (d12_select_endp(base_addr, endp_idx) & SEL_ENDP_FULL)
    ? d12_read_selected_endp_buf(base_addr, buf) : 0;
}

// ------------------------------------------------------------------------
// Does a read of the "main" endpoint (#2). Since it's double buffered,
// this will check if both buffers are full, and if so it will read them
// both. Thus the caller's buffer, buf, must be large enough to hold all
// the data - 128 bytes total.
// 
// If either buffer contains less than the full amount, the done flag
// is set indicating that a Bulk OUT transfer is complete.
// 
// This determines if a bulk transfer is done, since the caller can't 
// necessarily determine this from the size of the return buffer.
// If either buffer is less than full, '*done' is set to a non-zero value.

static uint8 
d12_read_main_endp_buf(d12_addr_type base_addr, byte *buf, int *done)
{
  int             nBuf = 1;
  uint8   n = 0;
  byte    stat = d12_read_endp_status(base_addr, D12_RX_MAIN_ENDP) & 
    D12_ENDP_STAT_ANY_BUF_FULL;
  
  if (stat == 0)
    return 0;
  
  if (stat == D12_ENDP_STAT_BOTH_BUF_FULL)
    nBuf++;
  
  *done = false;
  
  while (nBuf--) {
    if (d12_select_endp(base_addr, D12_RX_MAIN_ENDP) & SEL_ENDP_FULL) {
      uint8 n1 = d12_read_selected_endp_buf(base_addr, buf+n);
      n += n1;
      if (n1 < D12_MAIN_ENDP_SIZE) {
	*done = true;
	break;
      }
    }
    else
      *done = true;
  }
  return n;
}

// ------------------------------------------------------------------------
// Writes the contents of the buf[] array to the currently selected 
// endpoint's RAM buffer. The host will get the data on the on the next IN
// packet from the endpoint.
//
// Note:
//      - The length of the buffer, n, must be no more than the size of the
//      endpoint's RAM space, though, currently, this is not checked.
//      - It's feasible that the application needs to send an empty (NULL) 
//      packet. It's valid for 'n' to be zero, and/or buf NULL.

static uint8 
d12_write_selected_endp_buf(d12_addr_type base_addr, const byte *buf, uint8 n)
{
  d12_write_byte(base_addr, CMD_WRITE_BUF, 0);
  d12_write_data_byte(base_addr, n);
  d12_write_data(base_addr, buf, n);
  d12_validate_buffer(base_addr);
  
  return n;
}

// ------------------------------------------------------------------------
// Writes the contents of the buf[] array to the specified endoint's RAM
// buffer. The host will get this data on the next IN packet from the 
// endpoint.
//
// Side Effects:
//      - Leaves endp_idx as the currently selected endpoint.

static uint8 
d12_write_endp_buf(d12_addr_type base_addr, byte endp_idx, 
		   const byte *buf, uint8 n)
{
  d12_select_endp(base_addr, endp_idx);
  return d12_write_selected_endp_buf(base_addr, buf, n);
}

// ------------------------------------------------------------------------
// Reads & returns the contents of the Chip ID register.

static inline uint16 
d12_read_chip_id(d12_addr_type base_addr)
{
  return d12_read_word(base_addr, CMD_READ_CHIP_ID);
}


// ==========================================================================
// eCos-Specific Device Driver Code
// ==========================================================================

static void usbs_d12_reset(void);

// Make some abbreviations for the configuration options.

#if defined(CYGPKG_DEVS_USB_D12_RX_EP1)
#define _RX_EP1
#endif

#if defined(CYGPKG_DEVS_USB_D12_TX_EP1)
#define _TX_EP1
#endif

#if defined(CYGPKG_DEVS_USB_D12_RX_EP2)
#define _RX_EP2
#endif

#if defined(CYGPKG_DEVS_USB_D12_TX_EP2)
#define _TX_EP2
#endif

// --------------------------------------------------------------------------
// Endpoint 0 Data
// --------------------------------------------------------------------------

static cyg_interrupt    usbs_d12_intr_data;
static cyg_handle_t     usbs_d12_intr_handle;

static byte ep0_tx_buffer[CYGNUM_DEVS_USB_D12_EP0_TXBUFSIZE];

static void usbs_d12_start(usbs_control_endpoint*);
static void usbs_d12_poll(usbs_control_endpoint*);

typedef enum endp_state {
  ENDP_STATE_IDLE,
  ENDP_STATE_IN,
  ENDP_STATE_OUT
} endp_state;

typedef struct ep0_impl {
  usbs_control_endpoint   common;
  endp_state              ep_state;
  int                     length;
  int                     transmitted;
  bool                    tx_empty;
} ep0_impl;

static ep0_impl ep0 = {
 common:
 {
 state:                  USBS_STATE_POWERED,
 enumeration_data:       (usbs_enumeration_data*) 0,
 start_fn:               &usbs_d12_start,
 poll_fn:                &usbs_d12_poll,
 interrupt_vector:       CYGNUM_DEVS_USB_D12_IRQ,
 control_buffer:         { 0, 0, 0, 0, 0, 0, 0, 0 },
 state_change_fn:        0,
 state_change_data:      0,
 standard_control_fn:    0,
 standard_control_data:  0,
 class_control_fn:       0,
 class_control_data:     0,
 vendor_control_fn:      0,
 vendor_control_data:    0,
 reserved_control_fn:    0,
 reserved_control_data:  0,
 buffer:                 0,
 buffer_size:            0,
 fill_buffer_fn:         0,
 fill_data:              0,
 fill_index:             0,
 complete_fn:            0
 },
 ep_state:               ENDP_STATE_IDLE,
 length:                 0,
 transmitted:    0,
 tx_empty:               0
};

extern usbs_control_endpoint usbs_d12_ep0 __attribute__((alias ("ep0")));

// --------------------------------------------------------------------------
// Rx Endpoints 1 & 2 Data
// --------------------------------------------------------------------------

#if defined(_RX_EP1) || defined(_RX_EP2)

typedef struct rx_endpoint {
  usbs_rx_endpoint        common;
  int                     endp, received;
} rx_endpoint;

static void usbs_d12_api_start_rx_ep(usbs_rx_endpoint*);
static void usbs_d12_api_stall_rx_ep(usbs_rx_endpoint*, cyg_bool);

static void usbs_d12_ep_rx_complete(rx_endpoint *ep, int result);
static void usbs_d12_stall_rx_ep(rx_endpoint*, cyg_bool);

#endif


#if defined(_RX_EP1)

static rx_endpoint rx_ep1 = {
 common: {
  start_rx_fn:    &usbs_d12_api_start_rx_ep,
  set_halted_fn:  &usbs_d12_api_stall_rx_ep,
  halted:         0
 },
 endp:            1
};

extern usbs_rx_endpoint usbs_d12_rx_ep1 __attribute__((alias ("rx_ep1")));

#endif


#if defined(_RX_EP2)

static rx_endpoint rx_ep2 = {
 common: {
  start_rx_fn:    &usbs_d12_api_start_rx_ep,
  set_halted_fn:  &usbs_d12_api_stall_rx_ep,
  halted:         0
 },
 endp:            2
};

extern usbs_rx_endpoint usbs_d12_rx_ep2 __attribute__((alias ("rx_ep2")));

#endif

// --------------------------------------------------------------------------
// Tx Endpoints 1 & 2 Data
// --------------------------------------------------------------------------

#if defined(_TX_EP1) || defined(_TX_EP2)

typedef struct tx_endpoint {
  usbs_tx_endpoint        common;
  int                     endp, transmitted;
  bool                    tx_empty;
} tx_endpoint;

static void usbs_d12_api_start_tx_ep(usbs_tx_endpoint*);
static void usbs_d12_api_stall_tx_ep(usbs_tx_endpoint*, cyg_bool);

static void usbs_d12_ep_tx_complete(tx_endpoint *ep, int result);
static void usbs_d12_stall_tx_ep(tx_endpoint*, cyg_bool);
#endif

#if defined(_TX_EP1)

static tx_endpoint tx_ep1 = {
 common: {
  start_tx_fn:    &usbs_d12_api_start_tx_ep,
  set_halted_fn:  &usbs_d12_api_stall_tx_ep,
  halted:         0
 },
 endp:            1
};

extern usbs_tx_endpoint usbs_d12_tx_ep1 __attribute__((alias ("tx_ep1")));
#endif

#if defined(_TX_EP2)

static tx_endpoint tx_ep2 = {
 common: {
  start_tx_fn:    &usbs_d12_api_start_tx_ep,
  set_halted_fn:  &usbs_d12_api_stall_tx_ep,
  halted:         0
 },
 endp:            2
};

extern usbs_tx_endpoint usbs_d12_tx_ep2 __attribute__((alias ("tx_ep2")));

#endif

// --------------------------------------------------------------------------
// Synchronization

static inline void usbs_d12_lock(void)          { cyg_scheduler_lock(); }
static inline void usbs_d12_unlock(void)        { cyg_scheduler_unlock(); }

// --------------------------------------------------------------------------
// Control Endpoint
// --------------------------------------------------------------------------

// Fills the EP0 transmit buffer with a packet. Partial data packets are 
// retrieved by repeatedly calling the fill function.

static int 
ep0_fill_tx_buffer(void)
{
  int nFilled = 0;
  
  while (nFilled < CYGNUM_DEVS_USB_D12_EP0_TXBUFSIZE) {
    if (ep0.common.buffer_size != 0) {
      if ((nFilled + ep0.common.buffer_size) < 
	  CYGNUM_DEVS_USB_D12_EP0_TXBUFSIZE) {
	memcpy(&ep0_tx_buffer[nFilled], ep0.common.buffer, 
	       ep0.common.buffer_size);
	nFilled += ep0.common.buffer_size;
	ep0.common.buffer_size = 0;
      }
      else {
	break;
      }
    }
    else if (ep0.common.fill_buffer_fn) {
      (*ep0.common.fill_buffer_fn)(&ep0.common);
    }
    else {
      break;
    }
  }
  CYG_ASSERT((ep0.common.buffer_size == 0) && (!ep0.common.fill_buffer_fn), 
	     "EP0 transmit buffer overflow");
  TRACE_D12("EP0: Filled Tx Buf with %d bytes\n", nFilled);
  
  ep0.length = nFilled;
  
  ep0.common.fill_buffer_fn       = 0;
  ep0.common.fill_data            = 0;
  ep0.common.fill_index           = 0;
  
  return nFilled;
}

// --------------------------------------------------------------------------
// Called when a transfer is complete on the control endpoint EP0. 
// It resets the endpoint's data structure and calls the completion function,
// if any.
//
// PARAMETERS:
// result          0, on success
//                 -EPIPE or -EIO to indicate a cancellation

static usbs_control_return 
usbs_d12_ep0_complete(int result)
{
  usbs_control_return ret = USBS_CONTROL_RETURN_UNKNOWN;
  
  ep0.ep_state = ENDP_STATE_IDLE;
  
  if (ep0.common.complete_fn)
    ret = (*ep0.common.complete_fn)(&ep0.common, result);
  
  ep0.common.buffer                       = 0;
  ep0.common.buffer_size          = 0;
  ep0.common.complete_fn          = 0;
  //ep0.common.fill_buffer_fn     = 0;
  
  return ret;
}

// --------------------------------------------------------------------------
// This routine is called when we want to send the next packet to the tx ep0
// on the chip. It is used to start a new transfer, and is also called when
// the chip interrupts to indicate that the ep0 tx buffer is empty and ready
// to receive a new packet.
//
// NOTE:
//      On the D12, when you send a zero-length packet to a tx endpoint, the
//      chip transmits the empty packet to the host, but doesn't interrupt 
//      indicating that it is complete. So immediately after sending the
//      empty packet we complete the transfer.

static void 
usbs_d12_ep0_tx(void)
{
  int     nRemaining = ep0.length - ep0.transmitted;
  uint8   n;
  
  // ----- Intermittent interrupt? Get out -----
  
  if (!ep0.common.buffer) {
    TRACE_D12("EP0: Tx no buffer (%d)\n", nRemaining);

⌨️ 快捷键说明

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