usbs_d12.c

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

C
1,974
字号
// ----- Set Endpoint Enable Register -----

enum {
  ENDP_DISABLE,
  ENDP_ENABLE
};

// ----- Select Endpoint Results -----

enum {
  SEL_ENDP_FULL   = 0x01,
  SEL_ENDP_STALL  = 0x02
};

// ----- Error Codes from ReadLastTrans (need to be bit shifter) -----

enum {
  ERROR_NO_ERROR,
  ERROR_PID_ENCODING,
  ERROR_PID_UNKNOWN,
  ERROR_UNEXPECTED_PACKET,
  ERROR_TOKEN_CRC,
  ERROR_DATA_CRC,
  ERROR_TIMEOUT,
  ERROR_BABBLE,
  ERROR_UNEXPECTED_EOP,
  ERROR_NAK,
  ERROR_PACKET_ON_STALL,
  ERROR_OVERFLOW,
  ERROR_BITSTUFF,
  ERROR_WRONG_DATA_PID
};

// ------------------------------------------------------------------------
// Routines to access the D12 registers. The hardware specific driver 
// provides 8bit access functions and block access functions.

#include CYGIMP_DEVS_USB_D12_HW_ACCESS_HEADER


static inline uint16 
make_word(byte hi, byte lo)
{
  return ((uint16) hi << 8) | lo;
}

// These routines read or write 16 bit values to the data area.

static inline uint16 
d12_read_data_word(d12_addr_type base_addr)
{
  uint16 val = d12_read_data_byte(base_addr);
  val |= ((uint16) d12_read_data_byte(base_addr)) << 8;
  return val;
}

static inline void 
d12_write_data_word(d12_addr_type base_addr, uint16 val)
{
  d12_write_data_byte(base_addr, (byte) val);
  d12_write_data_byte(base_addr, (byte) (val >> 8));
}

// ------------------------------------------------------------------------
// Command & Data I/O
// ------------------------------------------------------------------------
//
// These routines read & write the registers in the D12. The procedure is
// to write a register/command value to the command address (A0=1) then
// read or write any required data a byte at a time to the data address
// (A0=0). The data can be one byte or two. If two, the low byte is read/
// written first.

// NOTE: These MUST be atomic operations. It's up to the caller 
//       to insure this.

// The hardware specific driver provides the basic access function.
//      

static inline void 
d12_write_byte(d12_addr_type base_addr, byte cmd, byte val)
{
  d12_write_cmd(base_addr, cmd);
  d12_write_data_byte(base_addr, val);
}

static inline void 
d12_write_word(d12_addr_type base_addr, byte cmd, uint16 val)
{
  d12_write_cmd(base_addr, cmd);
  d12_write_data_word(base_addr, val);
}

static inline byte 
d12_read_byte(d12_addr_type base_addr, byte cmd)
{
  d12_write_cmd(base_addr, cmd);
  return d12_read_data_byte(base_addr);
}

static inline uint16 
d12_read_word(d12_addr_type base_addr, byte cmd)
{
  d12_write_cmd(base_addr, cmd);
  return d12_read_data_word(base_addr);
}

// ------------------------------------------------------------------------
// Higher Level Commands
// ------------------------------------------------------------------------

// Stalls or Unstalls the endpoint. Bit0=1 for stall, =0 to unstall.

static inline void 
d12_set_endp_status(d12_addr_type base_addr, byte endp_idx, byte stat)
{
  d12_write_byte(base_addr, CMD_SET_ENDP_STAT + endp_idx, stat);
}

// ------------------------------------------------------------------------
// Stalls the control endpoint (both in & out).

static void 
d12_stall_ctrl_endp(d12_addr_type base_addr, bool stall)
{
  d12_set_endp_status(base_addr, D12_TX_CTRL_ENDP, stall ? 1 : 0);
  d12_set_endp_status(base_addr, D12_RX_CTRL_ENDP, stall ? 1 : 0);
}

// ------------------------------------------------------------------------
// Stalls/unstalls the specified endpoint. 

void inline 
d12_stall_endp(d12_addr_type base_addr, byte endp_idx, bool stall)
{
  d12_set_endp_status(base_addr, endp_idx, stall ? 1 : 0);
}

// ------------------------------------------------------------------------ */
// Tells the chip that the selected endpoint buffer has been completely
// read. This should be called after the application reads all the data
// from an endpoint.  While there's data in the buffer the chip will 
// automatically NAK any additional OUT packets from the host. 

static inline void 
d12_clear_buffer(d12_addr_type base_addr)
{
  d12_write_cmd(base_addr, CMD_CLEAR_BUF);
}

// ------------------------------------------------------------------------
// Tells the chip that the data in the selected endpoint buffer is complete
// and ready to be sent to the host.

static inline void 
d12_validate_buffer(d12_addr_type base_addr)
{
  d12_write_cmd(base_addr, CMD_VALIDATE_BUF);
}

// ------------------------------------------------------------------------
// Sends an upstream resume signal for 10ms. This command is normally 
// issued when the device is in suspend.

static inline void 
d12_send_resume(d12_addr_type base_addr)
{
  d12_write_cmd(base_addr, CMD_SEND_RESUME);
}

// ------------------------------------------------------------------------
// Gets the frame number of the last successfully received 
// start-of-frame (SOF).

static inline uint16 
d12_read_curr_frame_num(d12_addr_type base_addr)
{
  return d12_read_word(base_addr, CMD_READ_CURR_FRAME_NUM);
}

// ------------------------------------------------------------------------
// This routine acknowledges a setup packet by writing an Ack Setup command
// to the currently selected Endpoint. This must be done for both EP0 out
// and EP0 IN whenever a setup packet is received.

static inline void 
d12_ack_setup(d12_addr_type base_addr)
{
  d12_write_cmd(base_addr, CMD_ACK_SETUP);
}

// ------------------------------------------------------------------------
// Gets the value of the 16-bit interrupt register, which indicates the 
// source of an interrupt (if interrupts are not used, this reg can be 
// polled to find when service is required).

static inline uint16 
d12_read_intr_reg(d12_addr_type base_addr)
{
  return d12_read_word(base_addr, CMD_READ_INTR_REG) & 0x01FF;
}

// ------------------------------------------------------------------------
// Gets/Sets the contents of the DMA register.

static inline byte 
d12_get_dma(d12_addr_type base_addr)
{
  return d12_read_byte(base_addr, CMD_SET_DMA);
}

static inline void 
d12_set_dma(d12_addr_type base_addr, byte mode)
{
  d12_write_byte(base_addr, CMD_SET_DMA, mode);
}

// ------------------------------------------------------------------------
// Sends the "Select Endpoint" command (0x00 - 0x0D) to the chip.
// This command initializes an internal pointer to the start of the 
// selected buffer.
// 
// Returns: Bitfield containing status of the endpoint

static byte 
d12_select_endp(d12_addr_type base_addr, byte endp_idx)
{
  return d12_read_byte(base_addr, CMD_SEL_ENDP + endp_idx);
}

// ------------------------------------------------------------------------
// Gets the status of the last transaction of the endpoint. It also resets 
// the corresponding interrupt flag in the interrupt register, and clears 
// the status, indicating that it was read.
//
// Returns: Bitfield containing the last transaction status.

static inline byte 
d12_read_last_trans_status(d12_addr_type base_addr, byte endp_idx)
{
  return d12_read_byte(base_addr, CMD_READ_LAST_TRANS_STAT + endp_idx);
}

// ------------------------------------------------------------------------
// Reads the status of the requested endpoint. 
// Just for the heck of it, we mask off the reserved bits.
//
// Returns: Bitfield containing the endpoint status.

static inline byte 
d12_read_endp_status(d12_addr_type base_addr, byte endp_idx)
{
  return d12_read_byte(base_addr, CMD_READ_ENDP_STAT + endp_idx) & 0xE4;
}

// ------------------------------------------------------------------------
// Returns true if there is data available in the specified endpoint's
// ram buffer. This is determined by the buf full flags in the endp status
// register.

static inline bool 
d12_data_available(d12_addr_type base_addr, byte endp_idx)
{
  byte by = d12_read_endp_status(base_addr, endp_idx);
  return (bool) (by & D12_ENDP_STAT_ANY_BUF_FULL);
}

// ------------------------------------------------------------------------
// Clears the transaction status for each of the endpoints by calling the
// d12_read_last_trans_status() function for each. 

static void 
d12_clear_all_intr(d12_addr_type base_addr)
{
  uint8 endp;
  
  d12_read_intr_reg(base_addr);
  
  for (endp=D12_ENDP_MIN; endp<=D12_ENDP_MAX; ++endp)
    d12_read_last_trans_status(base_addr, endp);
}

// ------------------------------------------------------------------------
// Loads a value into the Set Address / Enable register. This sets the 
// device's USB address (lower 7 bits) and enables/disables the function
// (msb).

static void 
d12_set_addr_enable(d12_addr_type base_addr, byte usb_addr, bool enable)
{
  if (enable) 
    usb_addr |= 0x80;
  
  d12_write_byte(base_addr, CMD_SET_ADDR_EN, usb_addr);
}

// ------------------------------------------------------------------------
// Enables/disables the generic endpoints.

static inline void 
d12_set_endp_enable(d12_addr_type base_addr, bool enable)
{
  d12_write_byte(base_addr, CMD_SET_ENDP_EN, 
		 (enable) ? ENDP_ENABLE : ENDP_DISABLE);
}

// ------------------------------------------------------------------------
// Sets the device's configuration and CLKOUT frequency.

static void 
d12_set_mode(d12_addr_type base_addr, byte config, byte clk_div)
{
  uint16 w = make_word(clk_div, config);
  d12_write_word(base_addr, CMD_SET_MODE, w);
}

// ------------------------------------------------------------------------
// Reads a setup packet from the control endpoint. This procedure is 
// somewhat different than reading a data packet. By the USB standard, a 
// setup packet can not be NAK'ed or STALL'ed, so when the chip receives a 
// setup packet, it flushes the Ctrl (EP0) IN buffer and disables the 
// Validate and Clear Buffer commands. The processor must send an 
// acknowledge setup to both EP0 IN and OUT before a Validate or Clear
// Buffer command is effective.
//
// Parameters:
//      buf     buffer to receive the contents of the setup packet. Must
//              be at least 8 bytes.
// Returns:
//      true    if there are 8 bytes waiting in the EP0 OUT RAM buffer
//              on the D12 (i.e., true if successful)
//      false   otherwise

static bool 
d12_read_setup_packet(d12_addr_type base_addr, byte *buf)
{
  uint8 n;
  
  d12_select_endp(base_addr, D12_RX_CTRL_ENDP);
  
  d12_read_byte(base_addr, CMD_READ_BUF);   // Read & discard reserved byte
  n = d12_read_data_byte(base_addr);        // # bytes available
  
  if (n > USB_SETUP_PACKET_LEN) {
    //TRACE("* Warning: Setup Packet too large: %u *\n", (unsigned) n);
    n = USB_SETUP_PACKET_LEN;
  }
  
  n = d12_read_data(base_addr, buf, n);
  
  d12_ack_setup(base_addr);
  d12_clear_buffer(base_addr);
  
  // ----- Ack Setup to EP0 IN ------
  
  d12_select_endp(base_addr, D12_TX_CTRL_ENDP);
  d12_ack_setup(base_addr);
  
  return n == USB_SETUP_PACKET_LEN;
}

// ------------------------------------------------------------------------
// Reads the contents of the currently selected endpoint's RAM buffer into 
// the buf[] array.
//
// The D12's buffer comes in as follows:
//     [0]     junk ("reserved" - can be anything). Just disregard
//     [1]     # data bytes to follow
//     [2] data byte 0, ...
//     up to
//     [N+2] data byte N-1
//
// Parameters:
//      buf  byte array to receive data. This MUST be at least the size
//           of the chip's RAM buffer for the currently selected endpoint.
//           If buf is NULL, the data is read & discarded.
//
// Returns: the actual number of bytes read (could be <= n)

static uint8 
d12_read_selected_endp_buf(d12_addr_type base_addr, byte *buf)
{
  uint8 n;

  d12_read_byte(base_addr, CMD_READ_BUF);   // Read & discard reserved byte
  n = d12_read_data_byte(base_addr);        // # bytes in chip's buf
  d12_read_data(base_addr, buf, n);
  d12_clear_buffer(base_addr);

  return n;
}

// ------------------------------------------------------------------------
// Selects the specified endpoint and reads the contents of it's RAM buffer
// into the buf[] array. For the Main OUT endpoint, it will check whether 

⌨️ 快捷键说明

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