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 + -
显示快捷键?