📄 usbs_at91.c
字号:
int epn;
const usb_endpoint_descriptor *usb_endpoints;
cyg_uint8 endpoint_type;
cyg_uint8 endpoint_number;
usbs_end_all_transfers (-EPIPE);
HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_IDR, 0xffffffff);
HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_ICR, 0xffffffff);
HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_RST_EP, 0xffffffff);
HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_RST_EP, 0x00000000);
HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_FADDR, AT91_UDP_FADDR_FEN);
HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_CSR0,
AT91_UDP_CSR_EPEDS | AT91_UDP_CSR_EPTYPE_CTRL);
HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_IER, AT91_UDP_ALLOWED_IRQs);
for (epn=1; epn < AT91_USB_ENDPOINTS; epn++) {
usbs_at91_endpoint_init ((usbs_rx_endpoint *)usbs_at91_endpoints[epn],
0, false);
}
// Now walk the endpoints configuring them correctly. This only
// works if there is one interface.
usb_endpoints = usbs_at91_ep0.enumeration_data->endpoints;
for (epn = 1;
epn <= usbs_at91_ep0.enumeration_data->total_number_endpoints;
epn++) {
endpoint_type = (usb_endpoints[epn-1].attributes |
(usb_endpoints[epn-1].endpoint &
USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN ?
USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN :
USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT));
endpoint_number = usb_endpoints[epn-1].endpoint & ~(USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN);
if ( endpoint_number < AT91_USB_ENDPOINTS )
{
usbs_at91_endpoint_init((usbs_rx_endpoint *)usbs_at91_endpoints[endpoint_number],
endpoint_type,
true);
}
}
}
static void
usbs_at91_ep0_start (usbs_control_endpoint * endpoint)
{
usbs_at91_handle_reset ();
// If there is additional platform-specific initialization to
// perform, do it now. This macro can come from the platform HAL,
// but may not be available on all platforms.
#ifdef AT91_USB_PLATFORM_INIT
AT91_USB_PLATFORM_INIT ();
#endif
usbs_at91_set_pullup (true);
}
static void
usbs_at91_endpoint_start (usbs_rx_endpoint * pep)
{
int epn = usbs_at91_pep_to_number(pep);
cyg_addrword_t pCSR = pCSRn(epn);
cyg_addrword_t pFDR = pFDRn(epn);
cyg_uint16 space = 0;
cyg_uint16 endpoint_size = usbs_at91_endpoint_fifo_size[epn];
cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[epn];
cyg_uint8 **ppend = &usbs_at91_endpoint_pend[epn];
CYG_ASSERT (pep->complete_fn, "No complete_fn()");
cyg_drv_dsr_lock ();
if (usbs_at91_ep0.state != USBS_STATE_CONFIGURED) {
/* If not configured it means there is nothing to do */
cyg_drv_dsr_unlock ();
if (pep->complete_fn) {
(*pep->complete_fn) (pep->complete_data, -EPIPE);
}
return;
}
if (pep->halted) {
/* Halted means nothing to do */
cyg_drv_dsr_unlock ();
if (pep->complete_fn) {
(*pep->complete_fn) (pep->complete_data, -EAGAIN);
}
return;
}
if (BITS_ARE_SET (pIMR, 1 << epn)) {
cyg_drv_dsr_unlock ();
if (pep->complete_fn) {
(*pep->complete_fn) (pep->complete_data, -EIO);
}
return;
}
CYG_ASSERT (BITS_ARE_SET (pCSR, 1 << 9), "Wrong endpoint type");
*ppbegin = pep->buffer; /* Set the working pointers */
*ppend = (cyg_uint8 *) ((cyg_uint32) pep->buffer + pep->buffer_size);
if (BITS_ARE_SET (pCSR, 0x400)) { /* IN: tx_endpoint */
space = (cyg_uint32) * ppend - (cyg_uint32) * ppbegin;
if (space == endpoint_size) {
*ppend = *ppbegin; /* Send zero-packet */
}
*ppbegin =
write_fifo_uint8 (pFDR, *ppbegin,
(cyg_uint8 *) ((cyg_uint32) * ppbegin +
MIN (space, endpoint_size)));
SET_BITS (pCSR, AT91_UDP_CSR_TXPKTRDY);
if (*ppend == *ppbegin) { /* Last packet ? */
*ppend = *ppbegin - 1; /* The packet hasn't been sent yet */
}
}
usbs_at91_endpoint_interrupt_enable (epn, true);
cyg_drv_dsr_unlock ();
}
// Perform transmit handling on an endpoint
static bool
usbs_at91_endpoint_isr_tx(cyg_uint8 epn)
{
cyg_addrword_t pCSR = pCSRn(epn);
cyg_addrword_t pFDR = pFDRn(epn);
cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[epn];
cyg_uint8 **ppend = &usbs_at91_endpoint_pend[epn];
cyg_uint32 space = 0;
cyg_uint16 endpoint_size = usbs_at91_endpoint_fifo_size[epn];
CLEAR_BITS (pCSR, AT91_UDP_CSR_TXCOMP);
if (BITS_ARE_CLEARED (pCSR, AT91_UDP_CSR_TXPKTRDY)) {
/* Ready to transmit ? */
if (*ppend > *ppbegin) {
/* Something to send */
space = (cyg_uint32) * ppend - (cyg_uint32) * ppbegin;
if (space == endpoint_size) {
*ppend = *ppbegin; /* Send zero-packet */
}
*ppbegin =
write_fifo_uint8 (pFDR, *ppbegin,
(cyg_uint8 *) ((cyg_uint32) * ppbegin +
MIN (space, endpoint_size)));
SET_BITS (pCSR, AT91_UDP_CSR_TXPKTRDY);
if (*ppend == *ppbegin) { /* Last packet ? */
*ppend = *ppbegin - 1; /* The packet isn't sent yet */
}
} else {
if (*ppend + 1 == *ppbegin) {
*ppend = *ppbegin; /* Flag for DSR */
return true;
} else {
*ppend = *ppbegin - 1; /* Flag for zero-packet */
SET_BITS (pCSR, AT91_UDP_CSR_TXPKTRDY); /* Send no data */
}
}
}
CLEAR_BITS (pCSR,
AT91_UDP_CSR_RX_DATA_BK0 | AT91_UDP_CSR_RX_DATA_BK1 |
AT91_UDP_CSR_RXSETUP | AT91_UDP_CSR_ISOERROR);
return false;
}
static bool
usbs_at91_endpoint_isr_rx(cyg_uint8 epn)
{
cyg_addrword_t pCSR = pCSRn(epn);
cyg_addrword_t pFDR = pFDRn(epn);
cyg_uint16 *pinfifo = &usbs_at91_endpoint_bytes_in_fifo[epn];
cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[epn];
cyg_uint8 **ppend = &usbs_at91_endpoint_pend[epn];
cyg_uint16 *preceived = &usbs_at91_endpoint_bytes_received[epn];
cyg_uint16 endpoint_size = usbs_at91_endpoint_fifo_size[epn];
if (*preceived == THERE_IS_A_NEW_PACKET_IN_THE_UDP) {
/* There is a new packet */
*preceived = ((*(cyg_uint32 *)pCSR) >> 16) & 0x7ff;
*pinfifo = *preceived;
}
while ((*ppbegin < *ppend) && *pinfifo) {
/* If we have buffer-space AND data in the FIFO */
HAL_READ_UINT8(pFDR, **ppbegin);
(*ppbegin)++;
(*pinfifo)--;
}
if (*ppbegin == *ppend) {
/* The buffer is full... call the DSR */
return true;
}
if (*pinfifo == 0) {
/* If the FIFO is empty, then we can release it */
if (usbs_at91_endpoint_pingpong[epn]) {
/* Time to clear the interrupt flag */
if (usbs_at91_endpoint_bank1[epn]) {
CLEAR_BITS (pCSR, AT91_UDP_CSR_RX_DATA_BK1);
} else {
CLEAR_BITS (pCSR, AT91_UDP_CSR_RX_DATA_BK0);
}
usbs_at91_endpoint_bank1[epn] = !usbs_at91_endpoint_bank1[epn];
} else {
CLEAR_BITS (pCSR, AT91_UDP_CSR_RX_DATA_BK0);
}
if (*preceived < endpoint_size) {
/* If the last packet was smaller then the endpoint-size... */
*ppend = *ppbegin;
*preceived = THERE_IS_A_NEW_PACKET_IN_THE_UDP; /* Set flag */
return true; /* We can call the completion-function in the DSR */
}
*preceived = THERE_IS_A_NEW_PACKET_IN_THE_UDP; /* Set flag */
}
return false;
}
// ISR for an endpoint. Handle receive and transmit interrupts.
static bool
usbs_at91_endpoint_isr (cyg_uint8 epn)
{
cyg_addrword_t pCSR = pCSRn(epn);
CYG_ASSERT (AT91_USB_ENDPOINTS > epn && epn, "Invalid end point");
if (BITS_ARE_SET (pCSR, 0x400)) { /* IN: tx_endpoint */
if (usbs_at91_endpoint_isr_tx(epn))
return true; // Call the DSR
} else { /* OUT: rx_endpoint */
if (!BITS_ARE_CLEARED (pCSR, AT91_UDP_CSR_RX_DATA_BK0) ||
!BITS_ARE_CLEARED (pCSR, AT91_UDP_CSR_RX_DATA_BK1)) {
/* Sometime something received ? */
if(usbs_at91_endpoint_isr_rx(epn))
return true; // Call the DSR;
}
CLEAR_BITS (pCSR,
AT91_UDP_CSR_TXCOMP | AT91_UDP_CSR_RXSETUP |
AT91_UDP_CSR_ISOERROR);
}
return false;
}
// Handle a DSR for an endpoint
static void
usbs_at91_endpoint_dsr (cyg_uint8 epn)
{
usbs_rx_endpoint *pep = (usbs_rx_endpoint *) usbs_at91_endpoints[epn];
cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[epn];
cyg_uint8 **ppend = &usbs_at91_endpoint_pend[epn];
CYG_ASSERT (AT91_USB_ENDPOINTS > epn && epn, "Invalid end point");
CYG_ASSERT (pep->complete_fn, "No complete_fn()");
if (*ppend == *ppbegin) { /* Transmitted/Received ? */
pep->buffer_size = (cyg_uint32) * ppbegin - (cyg_uint32) pep->buffer;
if (pep->buffer_size && pep->complete_fn) {
if (!pep->halted) {
(*pep->complete_fn) (pep->complete_data, pep->buffer_size);
} else {
(*pep->complete_fn) (pep->complete_data, -EAGAIN);
}
}
usbs_at91_endpoint_interrupt_enable (epn, false);
}
}
// Handle an error condition on the control endpoint
static ep0_low_level_status_t
usbs_at91_control_error(ep0_low_level_status_t status)
{
cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[0];
cyg_uint8 **ppend = &usbs_at91_endpoint_pend[0];
usbs_at91_ep0.buffer_size = 0;
usbs_at91_ep0.fill_buffer_fn = 0;
usbs_at91_ep0.complete_fn = 0;
*ppbegin = usbs_at91_ep0.buffer;
*ppend = *ppbegin;
if (status == EP0_LL_IDLE) {
if (usbs_at91_ep0.complete_fn) {
(*usbs_at91_ep0.complete_fn) (&usbs_at91_ep0,
USBS_CONTROL_RETURN_STALL);
}
}
status = EP0_LL_IDLE;
CLEAR_BITS (pCSR0, AT91_UDP_CSR_ISOERROR | AT91_UDP_CSR_FORCESTALL);
return status;
}
// Handle a get status setup message on the control end point
static ep0_low_level_status_t
usbs_at91_control_setup_get_status(void)
{
ep0_low_level_status_t status;
usb_devreq *req = (usb_devreq *)usbs_at91_ep0.control_buffer;
cyg_uint8 recipient = req->type & USB_DEVREQ_RECIPIENT_MASK;
cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[0];
cyg_uint8 **ppend = &usbs_at91_endpoint_pend[0];
cyg_uint16 word = 0;
status = EP0_LL_SEND_READY;
switch (recipient) {
case USB_DEVREQ_RECIPIENT_DEVICE:
case USB_DEVREQ_RECIPIENT_INTERFACE:
// Nothing to do
break;
case USB_DEVREQ_RECIPIENT_ENDPOINT:
if ((usbs_at91_ep0.state == USBS_STATE_CONFIGURED) &&
(req->index_lo > 0) &&
(req->index_lo < AT91_USB_ENDPOINTS)) {
cyg_uint32 CSR;
HAL_READ_UINT32(pCSRn(req->index_lo), CSR);
if (CSR & AT91_UDP_CSR_EPEDS) {
word = 1;
}
} else {
status = EP0_LL_STALL;
}
break;
default:
status = EP0_LL_STALL;
}
*ppbegin = (cyg_uint8 *)&word;
*ppend = *ppbegin + sizeof (word);
return status;
}
// Setup the begin and end pointers such that an ACK is sent
static void
usbs_at91_control_setup_send_ack(void)
{
cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[0];
cyg_uint8 **ppend = &usbs_at91_endpoint_pend[0];
*ppbegin = usbs_at91_ep0.buffer;
*ppend = *ppbegin;
}
// Handle a get status set feature message on the control endpoint
static ep0_low_level_status_t
usbs_at91_control_setup_set_feature(void)
{
ep0_low_level_status_t status;
usb_devreq *req = (usb_devreq *)usbs_at91_ep0.control_buffer;
cyg_uint8 recipient = req->type & USB_DEVREQ_RECIPIENT_MASK;
usbs_at91_control_setup_send_ack();
status = EP0_LL_SEND_READY;
switch(recipient) {
case USB_DEVREQ_RECIPIENT_DEVICE:
status = EP0_LL_STALL;
break;
case USB_DEVREQ_RECIPIENT_INTERFACE:
// Nothing to do
break;
case USB_DEVREQ_RECIPIENT_ENDPOINT:
if ((usbs_at91_ep0.state == USBS_STATE_CONFIGURED) &&
(req->index_lo > 0) &&
(req->index_lo < AT91_USB_ENDPOINTS)) {
cyg_uint32 CSR;
HAL_READ_UINT32(pCSRn(req->index_lo), CSR);
if (CSR & AT91_UDP_CSR_EPEDS) {
/* TODO */
}
} else {
status = EP0_LL_STALL;
}
default:
status = EP0_LL_STALL;
}
return status;
}
// Handle a get status clear feature message on the control endpoint
static ep0_low_level_status_t
usbs_at91_control_setup_clear_feature(void)
{
ep0_low_level_status_t status;
usb_devreq *req = (usb_devreq *)usbs_at91_ep0.control_buffer;
cyg_uint8 recipient = req->type & USB_DEVREQ_RECIPIENT_MASK;
usbs_at91_control_setup_send_ack();
status = EP0_LL_SEND_READY;
switch (recipient) {
case USB_DEVREQ_RECIPIENT_DEVICE:
status = EP0_LL_STALL;
break;
case USB_DEVREQ_RECIPIENT_INTERFACE:
// Nothing to do
break;
case USB_DEVREQ_RECIPIENT_ENDPOINT:
if ((usbs_at91_ep0.state == USBS_STATE_CONFIGURED) &&
(req->index_lo > 0) &&
(req->index_lo < AT91_USB_ENDPOINTS)) {
cyg_uint32 CSR;
HAL_READ_UINT32(pCSRn(req->index_lo), CSR);
if (CSR & AT91_UDP_CSR_EPEDS) {
/* TODO */
}
} else {
status = EP0_LL_STALL;
}
default:
status = EP0_LL_STALL;
}
return status;
}
// Handle a setup message from the host
static ep0_low_level_status_t
usbs_at91_control_setup(ep0_low_level_status_t status)
{
cyg_uint8 **ppbegin = &usbs_at91_endpoint_pbegin[0];
cyg_uint8 **ppend = &usbs_at91_endpoint_pend[0];
usb_devreq *req = (usb_devreq *) usbs_at91_ep0.control_buffer;
cyg_uint8 protocol;
cyg_uint16 length;
bool dev_to_host;
usbs_control_return usbcode;
bool handled = false;
usbs_at91_ep0.buffer_size = 0;
usbs_at91_ep0.fill_buffer_fn = 0;
usbs_at91_ep0.complete_fn = 0;
read_fifo_uint8 ((cyg_uint8 *)req, pFDR0, sizeof (usb_devreq));
length = (req->length_hi << 8) | req->length_lo;;
dev_to_host = req->type & USB_DEVREQ_DIRECTION_IN;
CLEAR_BITS (pCSR0, AT91_UDP_CSR_DTGLE);
status = EP0_LL_REQUEST;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -