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