udp fifo stuff
This commit is contained in:
parent
23be9b58b9
commit
6422cf0bd8
@ -23,6 +23,9 @@ uint32_t fifo_remove(struct fifo *fifo, uint32_t len);
|
|||||||
uint32_t fifo_rxpdc(struct fifo *fifo, AT91S_PDC *pdc, uint16_t maxsize);
|
uint32_t fifo_rxpdc(struct fifo *fifo, AT91S_PDC *pdc, uint16_t maxsize);
|
||||||
uint32_t fifo_txpdc(struct fifo *fifo, AT91S_PDC *pdc, uint16_t maxsize);
|
uint32_t fifo_txpdc(struct fifo *fifo, AT91S_PDC *pdc, uint16_t maxsize);
|
||||||
|
|
||||||
|
uint32_t fifo_txudp(struct fifo *fifo, uint32_t ep, uint32_t maxsize);
|
||||||
|
uint32_t fifo_rxudp(struct fifo *fifo, uint32_t ep, uint32_t maxsize);
|
||||||
|
|
||||||
uint32_t fifo_putbyte(struct fifo *fifo, char c);
|
uint32_t fifo_putbyte(struct fifo *fifo, char c);
|
||||||
uint32_t fifo_getbyte(struct fifo *fifo, char *p);
|
uint32_t fifo_getbyte(struct fifo *fifo, char *p);
|
||||||
|
|
||||||
|
7
main.c
7
main.c
@ -38,7 +38,7 @@ static uint32_t pitc_test(struct pitc_timer *timer)
|
|||||||
*AT91C_PIOA_SODR = i;
|
*AT91C_PIOA_SODR = i;
|
||||||
i = i ^ LED_GREEN;
|
i = i ^ LED_GREEN;
|
||||||
*AT91C_PIOA_CODR = i;
|
*AT91C_PIOA_CODR = i;
|
||||||
|
/*
|
||||||
struct rc_values rc;
|
struct rc_values rc;
|
||||||
uint32_t count = rcontrol_getvalues(&rc);
|
uint32_t count = rcontrol_getvalues(&rc);
|
||||||
|
|
||||||
@ -48,11 +48,12 @@ static uint32_t pitc_test(struct pitc_timer *timer)
|
|||||||
printf("%+5d ", rc.chan[j]);
|
printf("%+5d ", rc.chan[j]);
|
||||||
|
|
||||||
printf("\r");
|
printf("\r");
|
||||||
|
*/
|
||||||
return PITC_RESTART_TIMER;
|
return PITC_RESTART_TIMER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pitc_timer pitc_test_timer = {
|
static struct pitc_timer pitc_test_timer = {
|
||||||
.interval = 1,
|
.interval = 10,
|
||||||
.func = &pitc_test,
|
.func = &pitc_test,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ int main(void)
|
|||||||
at91_twi_init();
|
at91_twi_init();
|
||||||
|
|
||||||
/* usb */
|
/* usb */
|
||||||
// at91_udp_init();
|
at91_udp_init();
|
||||||
|
|
||||||
printf("static alloc: %5ld bytes\n\r", static_alloc_used());
|
printf("static alloc: %5ld bytes\n\r", static_alloc_used());
|
||||||
|
|
||||||
|
299
src/at91_udp.c
299
src/at91_udp.c
@ -17,14 +17,13 @@
|
|||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "AT91SAM7S256.h"
|
#include "AT91SAM7S256.h"
|
||||||
#include "at91_pio.h"
|
#include "at91_pio.h"
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
#include "fifo.h"
|
||||||
|
|
||||||
#include "usb_ch9.h"
|
#include "usb_ch9.h"
|
||||||
#include "usb_cdc.h"
|
#include "usb_cdc.h"
|
||||||
#include "usb_dfu.h"
|
|
||||||
|
|
||||||
#define csr_clear_flags(csr, flags) \
|
#define csr_clear_flags(csr, flags) \
|
||||||
while ((csr) & (flags)) \
|
while ((csr) & (flags)) \
|
||||||
@ -34,25 +33,37 @@
|
|||||||
while (((csr) & (flags)) != (flags)) \
|
while (((csr) & (flags)) != (flags)) \
|
||||||
(csr) |= (flags);
|
(csr) |= (flags);
|
||||||
|
|
||||||
// TODO: name?
|
struct ep_transfer {
|
||||||
struct udp_transfer {
|
|
||||||
uint16_t address;
|
|
||||||
uint16_t maxpkt;
|
|
||||||
// TODO: last bank used / ping pong
|
|
||||||
|
|
||||||
// TODO: direction (IN/OUT)
|
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
uint16_t curpos;
|
uint16_t curpos;
|
||||||
|
|
||||||
char *data;
|
char *data;
|
||||||
void (*complete_cb)(void);
|
void (*complete_cb)(void);
|
||||||
// TODO: privdata?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ep_ctx {
|
||||||
|
uint16_t maxpktsize;
|
||||||
|
uint16_t flags;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct ep_transfer *transfer;
|
||||||
|
struct fifo *fifo;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CTX_TRANSFER 0x01 /* ctx use ep_transfer struct */
|
||||||
|
#define CTX_FIFO 0x02 /* ctx use fifo */
|
||||||
|
#define CTX_IN 0x04 /* write to the host */
|
||||||
|
#define CTX_OUT 0x08 /* read from the host */
|
||||||
|
#define CTX_RXBANK0 0x10
|
||||||
|
#define CTX_RXBANK1 0x20
|
||||||
|
|
||||||
|
static struct ep_transfer ep0_transfer;
|
||||||
|
static struct ep_ctx ep_ctx[4];
|
||||||
|
|
||||||
static uint16_t current_address;
|
static uint16_t current_address;
|
||||||
static uint16_t current_config;
|
static uint16_t current_config;
|
||||||
static uint16_t current_interface;
|
static uint16_t current_interface;
|
||||||
static struct udp_transfer ep_transfer[4];
|
|
||||||
|
|
||||||
static const struct usb_device_descriptor dev_descriptor = {
|
static const struct usb_device_descriptor dev_descriptor = {
|
||||||
.bLength = sizeof(struct usb_device_descriptor),
|
.bLength = sizeof(struct usb_device_descriptor),
|
||||||
@ -76,8 +87,6 @@ struct my_config {
|
|||||||
struct usb_interface_descriptor data_iface;
|
struct usb_interface_descriptor data_iface;
|
||||||
struct usb_endpoint_descriptor dataout_ep;
|
struct usb_endpoint_descriptor dataout_ep;
|
||||||
struct usb_endpoint_descriptor datain_ep;
|
struct usb_endpoint_descriptor datain_ep;
|
||||||
struct usb_interface_descriptor dfu_iface;
|
|
||||||
struct usb_dfu_descriptor dfu;
|
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
static const struct my_config cfg_descriptor = {
|
static const struct my_config cfg_descriptor = {
|
||||||
@ -85,7 +94,7 @@ static const struct my_config cfg_descriptor = {
|
|||||||
.bLength = sizeof(struct usb_config_descriptor),
|
.bLength = sizeof(struct usb_config_descriptor),
|
||||||
.bDescriptorType = USB_DT_CONFIG,
|
.bDescriptorType = USB_DT_CONFIG,
|
||||||
.wTotalLength = sizeof(struct my_config),
|
.wTotalLength = sizeof(struct my_config),
|
||||||
.bNumInterfaces = 3,
|
.bNumInterfaces = 2,
|
||||||
.bConfigurationValue = 1,
|
.bConfigurationValue = 1,
|
||||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP,
|
.bmAttributes = USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP,
|
||||||
.bMaxPower = 50,
|
.bMaxPower = 50,
|
||||||
@ -154,88 +163,79 @@ static const struct my_config cfg_descriptor = {
|
|||||||
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||||
.wMaxPacketSize = 64,
|
.wMaxPacketSize = 64,
|
||||||
},
|
},
|
||||||
.dfu_iface = {
|
|
||||||
.bLength = sizeof(struct usb_interface_descriptor),
|
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
|
||||||
.bInterfaceNumber = 2,
|
|
||||||
.bNumEndpoints = 0,
|
|
||||||
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
|
||||||
.bInterfaceSubClass = 0x01, /* DFU */
|
|
||||||
},
|
|
||||||
.dfu = {
|
|
||||||
.bLength = sizeof(struct usb_dfu_descriptor),
|
|
||||||
.bDescriptorType = USB_TYPE_DFU,
|
|
||||||
.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_CAN_UPLOAD,
|
|
||||||
.wDetachTimeOut = 0xff00,
|
|
||||||
.wTransferSize = AT91C_IFLASH_PAGE_SIZE,
|
|
||||||
.bcdDFUVersion = 0x0100,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct dfu_status dfu_status = {
|
static void ep_transfer_send(uint32_t ep, char *data, uint32_t length,
|
||||||
.bStatus = DFU_STATUS_OK,
|
void (*complete_cb)(void))
|
||||||
.bwPollTimeout = {0x00, 0x04, 0x00},
|
|
||||||
.bState = DFU_STATE_appIDLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void udp_configure_ep(const struct usb_endpoint_descriptor *desc)
|
|
||||||
{
|
{
|
||||||
/* get endpoint type (ctrl, iso, bulb, int) */
|
struct ep_ctx *ctx = &ep_ctx[ep];
|
||||||
uint32_t eptype = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
|
// printf("ep_transfer_send(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags);
|
||||||
if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT)))
|
||||||
eptype |= 0x04;
|
|
||||||
|
|
||||||
/* get endpoint address, set Max Packet Size */
|
|
||||||
uint32_t address = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
|
|
||||||
ep_transfer[address].maxpkt = desc->wMaxPacketSize;
|
|
||||||
|
|
||||||
/* configure UDP endpoint and enable interrupt */
|
|
||||||
AT91C_UDP_CSR[address] = AT91C_UDP_EPEDS | (eptype << 8);
|
|
||||||
*AT91C_UDP_IER = (1 << address);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void udp_fill_fifo(struct udp_transfer *trans)
|
|
||||||
{
|
|
||||||
uint16_t ep = trans->address;
|
|
||||||
|
|
||||||
if (AT91C_UDP_CSR[ep] & AT91C_UDP_TXPKTRDY) {
|
|
||||||
printf("TX!RDY\n\r");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* fill fifo */
|
/* from buffer to usb */
|
||||||
uint16_t max = trans->maxpkt;
|
ctx->flags |= CTX_IN;
|
||||||
while (trans->curpos < trans->length && max--)
|
|
||||||
AT91C_UDP_FDR[ep] = trans->data[trans->curpos++];
|
|
||||||
|
|
||||||
/* trigger transmission */
|
struct ep_transfer *transfer = ctx->transfer;
|
||||||
|
transfer->length = length;
|
||||||
|
transfer->curpos = 0;
|
||||||
|
transfer->data = data;
|
||||||
|
transfer->complete_cb = complete_cb;
|
||||||
|
|
||||||
|
uint32_t maxsize = ctx->maxpktsize;
|
||||||
|
|
||||||
|
/* get data from transfer */
|
||||||
|
while (transfer->curpos < transfer->length && maxsize--)
|
||||||
|
AT91C_UDP_FDR[ep] = transfer->data[transfer->curpos++];
|
||||||
|
|
||||||
|
/* trigger tx */
|
||||||
AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
|
AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udp_send_data(struct udp_transfer *trans, const char *data,
|
static void ep_transfer_receive(uint32_t ep, char *data, uint32_t length,
|
||||||
uint32_t length, void (*complete_cb)(void))
|
void (*complete_cb)(void))
|
||||||
{
|
{
|
||||||
if (trans->length != trans->curpos) {
|
struct ep_ctx *ctx = &ep_ctx[ep];
|
||||||
printf("TXOVF\n\r");
|
// printf("ep_transfer_receive(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags);
|
||||||
|
if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT)))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* setup data transmission */
|
/* from usb to buffer */
|
||||||
trans->length = length;
|
ctx->flags |= CTX_OUT;
|
||||||
trans->curpos = 0;
|
|
||||||
trans->data = (char *)data;
|
|
||||||
trans->complete_cb = complete_cb;
|
|
||||||
|
|
||||||
udp_fill_fifo(trans);
|
struct ep_transfer *transfer = ctx->transfer;
|
||||||
|
transfer->length = length;
|
||||||
|
transfer->curpos = 0;
|
||||||
|
transfer->data = data;
|
||||||
|
transfer->complete_cb = complete_cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stalls the endpoint */
|
/* stalls the endpoint */
|
||||||
static void udp_send_stall(uint32_t ep)
|
static void ep_send_stall(uint32_t ep)
|
||||||
{
|
{
|
||||||
printf("stall\n\r");
|
printf("stall\n\r");
|
||||||
AT91C_UDP_CSR[ep] |= AT91C_UDP_FORCESTALL;
|
AT91C_UDP_CSR[ep] |= AT91C_UDP_FORCESTALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void udp_configure_ep(const struct usb_endpoint_descriptor *desc)
|
||||||
|
{
|
||||||
|
/* get endpoint address, set Max Packet Size */
|
||||||
|
uint32_t ep = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
|
||||||
|
ep_ctx[ep].maxpktsize = desc->wMaxPacketSize;
|
||||||
|
|
||||||
|
/* get endpoint type (ctrl, iso, bulb, int) */
|
||||||
|
uint32_t eptype = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
|
||||||
|
if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
|
||||||
|
eptype |= 0x04;
|
||||||
|
} else {
|
||||||
|
ep_ctx[ep].flags |= CTX_RXBANK0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* configure UDP endpoint and enable interrupt */
|
||||||
|
AT91C_UDP_CSR[ep] = AT91C_UDP_EPEDS | (eptype << 8);
|
||||||
|
*AT91C_UDP_IER = (1 << ep);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set local address
|
* set local address
|
||||||
* (USB_REQ_SET_ADDRESS callback)
|
* (USB_REQ_SET_ADDRESS callback)
|
||||||
@ -265,7 +265,7 @@ static void udp_txcb_setinterface(void)
|
|||||||
printf("claim interface %d\n\r", current_interface);
|
printf("claim interface %d\n\r", current_interface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udp_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
||||||
{
|
{
|
||||||
printf("typ:0x%02x req:0x%02x val:0x%04x idx:0x%04x len:0x%04x\n\r",
|
printf("typ:0x%02x req:0x%02x val:0x%04x idx:0x%04x len:0x%04x\n\r",
|
||||||
req->bRequestType, req->bRequest, req->wValue, req->wIndex, req->wLength);
|
req->bRequestType, req->bRequest, req->wValue, req->wIndex, req->wLength);
|
||||||
@ -275,34 +275,36 @@ static void udp_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
|||||||
switch (req->bRequest) {
|
switch (req->bRequest) {
|
||||||
case USB_REQ_SET_ADDRESS: /* 0x05 */
|
case USB_REQ_SET_ADDRESS: /* 0x05 */
|
||||||
current_address = req->wValue;
|
current_address = req->wValue;
|
||||||
udp_send_data(&ep_transfer[0], NULL, 0, udp_txcb_setaddress);
|
ep_transfer_send(0, NULL, 0, udp_txcb_setaddress);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_REQ_GET_DESCRIPTOR: /* 0x06 */
|
case USB_REQ_GET_DESCRIPTOR: /* 0x06 */
|
||||||
switch (req->wValue >> 8) {
|
switch (req->wValue >> 8) {
|
||||||
case USB_DT_DEVICE: /* 0x01 */
|
case USB_DT_DEVICE: /* 0x01 */
|
||||||
udp_send_data(&ep_transfer[0], (const char *)&dev_descriptor,
|
ep_transfer_send(0, (char *)&dev_descriptor,
|
||||||
MIN(sizeof(dev_descriptor), req->wLength), NULL);
|
MIN(sizeof(dev_descriptor), req->wLength),
|
||||||
|
NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_DT_CONFIG: /* 0x02 */
|
case USB_DT_CONFIG: /* 0x02 */
|
||||||
udp_send_data(&ep_transfer[0], (const char *)&cfg_descriptor,
|
ep_transfer_send(0, (char *)&cfg_descriptor,
|
||||||
MIN(sizeof(cfg_descriptor), req->wLength), NULL);
|
MIN(sizeof(cfg_descriptor), req->wLength),
|
||||||
|
NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
udp_send_stall(0);
|
ep_send_stall(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_REQ_SET_CONFIGURATION: /* 0x09 */
|
case USB_REQ_SET_CONFIGURATION: /* 0x09 */
|
||||||
current_config = req->wValue;
|
current_config = req->wValue;
|
||||||
udp_send_data(&ep_transfer[0], NULL, 0, udp_txcb_setconfig);
|
ep_transfer_send(0, NULL, 0, udp_txcb_setconfig);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
udp_send_stall(0);
|
ep_send_stall(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -312,11 +314,11 @@ static void udp_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
|||||||
switch (req->bRequest) {
|
switch (req->bRequest) {
|
||||||
case USB_REQ_SET_INTERFACE: /* 0x0b */
|
case USB_REQ_SET_INTERFACE: /* 0x0b */
|
||||||
current_interface = req->wValue;
|
current_interface = req->wValue;
|
||||||
udp_send_data(&ep_transfer[0], NULL, 0, udp_txcb_setinterface);
|
ep_transfer_send(0, NULL, 0, udp_txcb_setinterface);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
udp_send_stall(0);
|
ep_send_stall(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -324,40 +326,30 @@ static void udp_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
|||||||
case (USB_TYPE_CLASS | USB_RECIP_INTERFACE): /* 0x21/0xA1 */
|
case (USB_TYPE_CLASS | USB_RECIP_INTERFACE): /* 0x21/0xA1 */
|
||||||
// TODO: follow current_interface
|
// TODO: follow current_interface
|
||||||
switch (req->bRequest) {
|
switch (req->bRequest) {
|
||||||
case USB_REQ_DFU_DETACH: /* 0x00 */
|
|
||||||
udp_send_data(&ep_transfer[0], NULL, 0, NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_REQ_DFU_GETSTATUS: /* 0x03 */
|
|
||||||
udp_send_data(&ep_transfer[0], (const char *)&dfu_status,
|
|
||||||
MIN(sizeof(struct dfu_status), req->wLength), NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_CDC_REQ_SET_LINE_CODING: /* 0x20 */
|
case USB_CDC_REQ_SET_LINE_CODING: /* 0x20 */
|
||||||
// TODO: read 7 data bytes
|
/* read 7 bytes */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: /* 0x22 */
|
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: /* 0x22 */
|
||||||
udp_send_data(&ep_transfer[0], NULL, 0, NULL);
|
ep_transfer_send(0, NULL, 0, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
udp_send_stall(0);
|
ep_send_stall(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
udp_send_stall(0);
|
ep_send_stall(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udp_handle_ep(uint32_t ep)
|
static void udp_handle_ep(uint32_t ep)
|
||||||
{
|
{
|
||||||
AT91_REG *csr = &AT91C_UDP_CSR[ep];
|
|
||||||
|
|
||||||
/* endpoint enabled? */
|
/* endpoint enabled? */
|
||||||
|
AT91_REG *csr = &AT91C_UDP_CSR[ep];
|
||||||
if (!(*csr & AT91C_UDP_EPEDS))
|
if (!(*csr & AT91C_UDP_EPEDS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -372,23 +364,42 @@ static void udp_handle_ep(uint32_t ep)
|
|||||||
if (req.bRequestType & USB_DIR_IN)
|
if (req.bRequestType & USB_DIR_IN)
|
||||||
*csr |= AT91C_UDP_DIR;
|
*csr |= AT91C_UDP_DIR;
|
||||||
|
|
||||||
/* clear interrupt (THIS MUST USE csr_clear_flags()!) */
|
/* clear interrupt - *MUST* use csr_clear_flags() here */
|
||||||
csr_clear_flags(*csr, AT91C_UDP_RXSETUP);
|
csr_clear_flags(*csr, AT91C_UDP_RXSETUP);
|
||||||
|
|
||||||
udp_handle_ctrlrequest(&req);
|
ep_handle_ctrlrequest(&req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* transmit complete? */
|
/* transmit complete? */
|
||||||
if (*csr & AT91C_UDP_TXCOMP) {
|
if (*csr & AT91C_UDP_TXCOMP) {
|
||||||
struct udp_transfer *trans = &ep_transfer[ep];
|
struct ep_ctx *ctx = &ep_ctx[ep];
|
||||||
|
|
||||||
/* refill fifo, if transfer is incomplete */
|
if (ctx->flags & CTX_FIFO) {
|
||||||
if (trans->length != trans->curpos)
|
/* get data from fifo */
|
||||||
udp_fill_fifo(trans);
|
if (fifo_txudp(ctx->fifo, ep, ctx->maxpktsize))
|
||||||
|
AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
|
||||||
|
|
||||||
/* execute callback when transfer is complete */
|
} else if ((ctx->flags & (CTX_TRANSFER | CTX_IN)) == (CTX_TRANSFER | CTX_IN)) {
|
||||||
else if (trans->complete_cb)
|
/* transfer not complete */
|
||||||
trans->complete_cb();
|
struct ep_transfer *transfer = ctx->transfer;
|
||||||
|
if (transfer->length != transfer->curpos) {
|
||||||
|
uint32_t maxsize = ctx->maxpktsize;
|
||||||
|
|
||||||
|
/* get data from transfer */
|
||||||
|
while (transfer->curpos < transfer->length && maxsize--)
|
||||||
|
AT91C_UDP_FDR[ep] = transfer->data[transfer->curpos++];
|
||||||
|
|
||||||
|
/* trigger tx */
|
||||||
|
AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
|
||||||
|
|
||||||
|
/* transfer complete, execute callback */
|
||||||
|
} else {
|
||||||
|
ctx->flags &= ~CTX_IN;
|
||||||
|
|
||||||
|
if (transfer->complete_cb)
|
||||||
|
transfer->complete_cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* clear interrupt */
|
/* clear interrupt */
|
||||||
*csr &= ~(AT91C_UDP_TXCOMP);
|
*csr &= ~(AT91C_UDP_TXCOMP);
|
||||||
@ -400,33 +411,59 @@ static void udp_handle_ep(uint32_t ep)
|
|||||||
|
|
||||||
/* data ready to read? */
|
/* data ready to read? */
|
||||||
if (*csr & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)) {
|
if (*csr & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)) {
|
||||||
|
struct ep_ctx *ctx = &ep_ctx[ep];
|
||||||
|
|
||||||
uint16_t len = (*csr & AT91C_UDP_RXBYTECNT) >> 16;
|
uint16_t len = (*csr & AT91C_UDP_RXBYTECNT) >> 16;
|
||||||
if (len) {
|
|
||||||
printf("rx: ");
|
|
||||||
while (len--)
|
|
||||||
printf("0x%02x ", AT91C_UDP_FDR[ep]);
|
|
||||||
|
|
||||||
printf("\n\r");
|
// TODO: only ep0 status OUT?
|
||||||
|
if (!len && (ctx->flags & CTX_TRANSFER)) {
|
||||||
} else {
|
ctx->flags &= ~(CTX_OUT | CTX_IN);
|
||||||
/* clear a pending transfer! */
|
ctx->transfer->length = 0;
|
||||||
ep_transfer[ep].length = 0;
|
ctx->transfer->curpos = 0;
|
||||||
ep_transfer[ep].curpos = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: ping pong FIFOs */
|
if (ctx->flags & CTX_FIFO) {
|
||||||
|
fifo_rxudp(ctx->fifo, ep, len);
|
||||||
|
|
||||||
|
} else if ((ctx->flags & (CTX_TRANSFER | CTX_OUT)) == (CTX_TRANSFER | CTX_OUT)) {
|
||||||
|
|
||||||
|
/* transfer not complete */
|
||||||
|
struct ep_transfer *transfer = ctx->transfer;
|
||||||
|
if (transfer->length != transfer->curpos) {
|
||||||
|
/* get data from transfer */
|
||||||
|
while (transfer->curpos < transfer->length && len--)
|
||||||
|
transfer->data[transfer->curpos++] = AT91C_UDP_FDR[ep];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* test again */
|
||||||
|
if (transfer->length == transfer->curpos) {
|
||||||
|
ctx->flags &= ~CTX_OUT;
|
||||||
|
|
||||||
|
if (transfer->complete_cb)
|
||||||
|
transfer->complete_cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->flags & CTX_RXBANK0) {
|
||||||
if (*csr & AT91C_UDP_RX_DATA_BK0)
|
if (*csr & AT91C_UDP_RX_DATA_BK0)
|
||||||
csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK0);
|
csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK0);
|
||||||
|
|
||||||
|
/* all but ep0 have ping pong buffers */
|
||||||
|
if (ep > 0)
|
||||||
|
ctx->flags = (ctx->flags & ~CTX_RXBANK0) | CTX_RXBANK1;
|
||||||
|
|
||||||
|
} else if (ctx->flags & CTX_RXBANK1) {
|
||||||
if (*csr & AT91C_UDP_RX_DATA_BK1)
|
if (*csr & AT91C_UDP_RX_DATA_BK1)
|
||||||
csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK1);
|
csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK1);
|
||||||
|
|
||||||
|
ctx->flags = (ctx->flags & ~CTX_RXBANK1) | CTX_RXBANK0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udp_isr(void)
|
static void udp_isr(void)
|
||||||
{
|
{
|
||||||
uint32_t isr = *AT91C_UDP_ISR;
|
uint32_t isr = *AT91C_UDP_ISR;
|
||||||
|
|
||||||
if (isr & AT91C_UDP_ENDBUSRES) {
|
if (isr & AT91C_UDP_ENDBUSRES) {
|
||||||
AT91S_UDP *udp = AT91C_BASE_UDP;
|
AT91S_UDP *udp = AT91C_BASE_UDP;
|
||||||
|
|
||||||
@ -435,15 +472,13 @@ static void udp_isr(void)
|
|||||||
AT91C_UDP_EP2 | AT91C_UDP_EP3) ;
|
AT91C_UDP_EP2 | AT91C_UDP_EP3) ;
|
||||||
udp->UDP_RSTEP = 0;
|
udp->UDP_RSTEP = 0;
|
||||||
|
|
||||||
/* clear all transfers, set default values */
|
/* init ep0 */
|
||||||
uint32_t i;
|
struct ep_ctx *ctx = &ep_ctx[0];
|
||||||
for (i = 0; i < 4; i++) {
|
ctx->maxpktsize = 8;
|
||||||
ep_transfer[i].address = i;
|
ctx->flags = CTX_TRANSFER | CTX_RXBANK0;
|
||||||
ep_transfer[i].maxpkt = 64;
|
ctx->transfer = &ep0_transfer;
|
||||||
ep_transfer[i].length = 0;
|
ctx->transfer->length = 0;
|
||||||
ep_transfer[i].curpos = 0;
|
ctx->transfer->curpos = 0;
|
||||||
}
|
|
||||||
ep_transfer[0].maxpkt = 8;
|
|
||||||
|
|
||||||
/* Configure endpoint0 as Control EP */
|
/* Configure endpoint0 as Control EP */
|
||||||
udp->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);
|
udp->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);
|
||||||
@ -458,7 +493,7 @@ static void udp_isr(void)
|
|||||||
/* Handle Endpoint Interrupts */
|
/* Handle Endpoint Interrupts */
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
if (isr & (1<<i))
|
if (isr & *AT91C_UDP_IMR & (1<<i))
|
||||||
udp_handle_ep(i);
|
udp_handle_ep(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
src/fifo.c
27
src/fifo.c
@ -174,6 +174,33 @@ uint32_t fifo_txpdc(struct fifo *fifo, AT91S_PDC *pdc, uint16_t maxsize)
|
|||||||
return fifo->pdc_tx;
|
return fifo->pdc_tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t fifo_rxudp(struct fifo *fifo, uint32_t ep, uint32_t maxsize)
|
||||||
|
{
|
||||||
|
uint32_t left = fifo->size - fifo_used(fifo);
|
||||||
|
if (left > maxsize)
|
||||||
|
left = maxsize;
|
||||||
|
|
||||||
|
uint32_t count = left;
|
||||||
|
while (count--)
|
||||||
|
fifo->buf[fifo->in++ & FIFO_MASK(fifo)] = AT91C_UDP_FDR[ep];
|
||||||
|
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t fifo_txudp(struct fifo *fifo, uint32_t ep, uint32_t maxsize)
|
||||||
|
{
|
||||||
|
uint32_t size = fifo_used(fifo);
|
||||||
|
if (size > maxsize)
|
||||||
|
size = maxsize;
|
||||||
|
|
||||||
|
uint32_t count = size;
|
||||||
|
while (count--)
|
||||||
|
AT91C_UDP_FDR[ep] = fifo->buf[fifo->out++ & FIFO_MASK(fifo)];
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* put one byte into the fifo
|
* put one byte into the fifo
|
||||||
* returns 0 if fifo was full
|
* returns 0 if fifo was full
|
||||||
|
Loading…
Reference in New Issue
Block a user