From 6422cf0bd8eede383d69edfa8a705d0ec00a8751 Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Wed, 6 Feb 2008 22:18:33 +0100 Subject: [PATCH] udp fifo stuff --- include/fifo.h | 3 + main.c | 7 +- src/at91_udp.c | 331 +++++++++++++++++++++++++++---------------------- src/fifo.c | 27 ++++ 4 files changed, 217 insertions(+), 151 deletions(-) diff --git a/include/fifo.h b/include/fifo.h index 7d2ac3e..0c0b46a 100644 --- a/include/fifo.h +++ b/include/fifo.h @@ -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_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_getbyte(struct fifo *fifo, char *p); diff --git a/main.c b/main.c index e6fd27f..45ce538 100644 --- a/main.c +++ b/main.c @@ -38,7 +38,7 @@ static uint32_t pitc_test(struct pitc_timer *timer) *AT91C_PIOA_SODR = i; i = i ^ LED_GREEN; *AT91C_PIOA_CODR = i; - +/* struct rc_values 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("\r"); +*/ return PITC_RESTART_TIMER; } static struct pitc_timer pitc_test_timer = { - .interval = 1, + .interval = 10, .func = &pitc_test, }; @@ -83,7 +84,7 @@ int main(void) at91_twi_init(); /* usb */ -// at91_udp_init(); + at91_udp_init(); printf("static alloc: %5ld bytes\n\r", static_alloc_used()); diff --git a/src/at91_udp.c b/src/at91_udp.c index 5f89201..ec2554a 100644 --- a/src/at91_udp.c +++ b/src/at91_udp.c @@ -17,14 +17,13 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include - #include "AT91SAM7S256.h" #include "at91_pio.h" #include "board.h" +#include "fifo.h" #include "usb_ch9.h" #include "usb_cdc.h" -#include "usb_dfu.h" #define csr_clear_flags(csr, flags) \ while ((csr) & (flags)) \ @@ -34,25 +33,37 @@ while (((csr) & (flags)) != (flags)) \ (csr) |= (flags); -// TODO: name? -struct udp_transfer { - uint16_t address; - uint16_t maxpkt; - // TODO: last bank used / ping pong - - // TODO: direction (IN/OUT) +struct ep_transfer { uint16_t length; uint16_t curpos; char *data; 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_config; static uint16_t current_interface; -static struct udp_transfer ep_transfer[4]; static const struct usb_device_descriptor dev_descriptor = { .bLength = sizeof(struct usb_device_descriptor), @@ -76,8 +87,6 @@ struct my_config { struct usb_interface_descriptor data_iface; struct usb_endpoint_descriptor dataout_ep; struct usb_endpoint_descriptor datain_ep; - struct usb_interface_descriptor dfu_iface; - struct usb_dfu_descriptor dfu; } __attribute__ ((packed)); static const struct my_config cfg_descriptor = { @@ -85,7 +94,7 @@ static const struct my_config cfg_descriptor = { .bLength = sizeof(struct usb_config_descriptor), .bDescriptorType = USB_DT_CONFIG, .wTotalLength = sizeof(struct my_config), - .bNumInterfaces = 3, + .bNumInterfaces = 2, .bConfigurationValue = 1, .bmAttributes = USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP, .bMaxPower = 50, @@ -154,88 +163,79 @@ static const struct my_config cfg_descriptor = { .bmAttributes = USB_ENDPOINT_XFER_BULK, .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 = { - .bStatus = DFU_STATUS_OK, - .bwPollTimeout = {0x00, 0x04, 0x00}, - .bState = DFU_STATE_appIDLE, -}; - -static void udp_configure_ep(const struct usb_endpoint_descriptor *desc) +static void ep_transfer_send(uint32_t ep, char *data, uint32_t length, + void (*complete_cb)(void)) { - /* 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; - - /* 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"); + struct ep_ctx *ctx = &ep_ctx[ep]; +// printf("ep_transfer_send(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags); + if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT))) return; - } - /* fill fifo */ - uint16_t max = trans->maxpkt; - while (trans->curpos < trans->length && max--) - AT91C_UDP_FDR[ep] = trans->data[trans->curpos++]; + /* from buffer to usb */ + ctx->flags |= CTX_IN; - /* 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; } -static void udp_send_data(struct udp_transfer *trans, const char *data, - uint32_t length, void (*complete_cb)(void)) +static void ep_transfer_receive(uint32_t ep, char *data, uint32_t length, + void (*complete_cb)(void)) { - if (trans->length != trans->curpos) { - printf("TXOVF\n\r"); + struct ep_ctx *ctx = &ep_ctx[ep]; +// 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; - } - /* setup data transmission */ - trans->length = length; - trans->curpos = 0; - trans->data = (char *)data; - trans->complete_cb = complete_cb; + /* from usb to buffer */ + ctx->flags |= CTX_OUT; - 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 */ -static void udp_send_stall(uint32_t ep) +static void ep_send_stall(uint32_t ep) { printf("stall\n\r"); 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 * (USB_REQ_SET_ADDRESS callback) @@ -265,7 +265,7 @@ static void udp_txcb_setinterface(void) 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", req->bRequestType, req->bRequest, req->wValue, req->wIndex, req->wLength); @@ -275,89 +275,81 @@ static void udp_handle_ctrlrequest(struct usb_ctrlrequest *req) switch (req->bRequest) { case USB_REQ_SET_ADDRESS: /* 0x05 */ 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; case USB_REQ_GET_DESCRIPTOR: /* 0x06 */ switch (req->wValue >> 8) { case USB_DT_DEVICE: /* 0x01 */ - udp_send_data(&ep_transfer[0], (const char *)&dev_descriptor, - MIN(sizeof(dev_descriptor), req->wLength), NULL); + ep_transfer_send(0, (char *)&dev_descriptor, + MIN(sizeof(dev_descriptor), req->wLength), + NULL); break; case USB_DT_CONFIG: /* 0x02 */ - udp_send_data(&ep_transfer[0], (const char *)&cfg_descriptor, - MIN(sizeof(cfg_descriptor), req->wLength), NULL); + ep_transfer_send(0, (char *)&cfg_descriptor, + MIN(sizeof(cfg_descriptor), req->wLength), + NULL); break; default: - udp_send_stall(0); + ep_send_stall(0); break; } break; case USB_REQ_SET_CONFIGURATION: /* 0x09 */ 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; default: - udp_send_stall(0); + ep_send_stall(0); break; - } - break; + } + break; case (USB_TYPE_STANDARD | USB_RECIP_INTERFACE): /* 0x01/0x81 */ // TODO: follow current_interface - switch (req->bRequest) { - case USB_REQ_SET_INTERFACE: /* 0x0b */ - current_interface = req->wValue; - udp_send_data(&ep_transfer[0], NULL, 0, udp_txcb_setinterface); + switch (req->bRequest) { + case USB_REQ_SET_INTERFACE: /* 0x0b */ + current_interface = req->wValue; + ep_transfer_send(0, NULL, 0, udp_txcb_setinterface); break; default: - udp_send_stall(0); + ep_send_stall(0); break; - } - break; + } + break; case (USB_TYPE_CLASS | USB_RECIP_INTERFACE): /* 0x21/0xA1 */ // TODO: follow current_interface - 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); + switch (req->bRequest) { + case USB_CDC_REQ_SET_LINE_CODING: /* 0x20 */ + /* read 7 bytes */ break; - case USB_CDC_REQ_SET_LINE_CODING: /* 0x20 */ - // TODO: read 7 data bytes - break; - - case USB_CDC_REQ_SET_CONTROL_LINE_STATE: /* 0x22 */ - udp_send_data(&ep_transfer[0], NULL, 0, NULL); + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: /* 0x22 */ + ep_transfer_send(0, NULL, 0, NULL); break; default: - udp_send_stall(0); + ep_send_stall(0); break; - } - break; + } + break; default: - udp_send_stall(0); + ep_send_stall(0); break; } } static void udp_handle_ep(uint32_t ep) { - AT91_REG *csr = &AT91C_UDP_CSR[ep]; - /* endpoint enabled? */ + AT91_REG *csr = &AT91C_UDP_CSR[ep]; if (!(*csr & AT91C_UDP_EPEDS)) return; @@ -372,23 +364,42 @@ static void udp_handle_ep(uint32_t ep) if (req.bRequestType & USB_DIR_IN) *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); - udp_handle_ctrlrequest(&req); + ep_handle_ctrlrequest(&req); } /* transmit complete? */ 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 (trans->length != trans->curpos) - udp_fill_fifo(trans); + if (ctx->flags & CTX_FIFO) { + /* get data from fifo */ + if (fifo_txudp(ctx->fifo, ep, ctx->maxpktsize)) + AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY; - /* execute callback when transfer is complete */ - else if (trans->complete_cb) - trans->complete_cb(); + } else if ((ctx->flags & (CTX_TRANSFER | CTX_IN)) == (CTX_TRANSFER | CTX_IN)) { + /* transfer not complete */ + 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 */ *csr &= ~(AT91C_UDP_TXCOMP); @@ -400,33 +411,59 @@ static void udp_handle_ep(uint32_t ep) /* data ready to read? */ 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; - if (len) { - printf("rx: "); - while (len--) - printf("0x%02x ", AT91C_UDP_FDR[ep]); - printf("\n\r"); - - } else { - /* clear a pending transfer! */ - ep_transfer[ep].length = 0; - ep_transfer[ep].curpos = 0; + // TODO: only ep0 status OUT? + if (!len && (ctx->flags & CTX_TRANSFER)) { + ctx->flags &= ~(CTX_OUT | CTX_IN); + ctx->transfer->length = 0; + ctx->transfer->curpos = 0; } - /* TODO: ping pong FIFOs */ - if (*csr & AT91C_UDP_RX_DATA_BK0) - csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK0); + if (ctx->flags & CTX_FIFO) { + fifo_rxudp(ctx->fifo, ep, len); - if (*csr & AT91C_UDP_RX_DATA_BK1) - csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK1); + } 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) + 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) + csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK1); + + ctx->flags = (ctx->flags & ~CTX_RXBANK1) | CTX_RXBANK0; + } } } static void udp_isr(void) { uint32_t isr = *AT91C_UDP_ISR; - if (isr & AT91C_UDP_ENDBUSRES) { AT91S_UDP *udp = AT91C_BASE_UDP; @@ -435,15 +472,13 @@ static void udp_isr(void) AT91C_UDP_EP2 | AT91C_UDP_EP3) ; udp->UDP_RSTEP = 0; - /* clear all transfers, set default values */ - uint32_t i; - for (i = 0; i < 4; i++) { - ep_transfer[i].address = i; - ep_transfer[i].maxpkt = 64; - ep_transfer[i].length = 0; - ep_transfer[i].curpos = 0; - } - ep_transfer[0].maxpkt = 8; + /* init ep0 */ + struct ep_ctx *ctx = &ep_ctx[0]; + ctx->maxpktsize = 8; + ctx->flags = CTX_TRANSFER | CTX_RXBANK0; + ctx->transfer = &ep0_transfer; + ctx->transfer->length = 0; + ctx->transfer->curpos = 0; /* Configure endpoint0 as Control EP */ udp->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); @@ -458,7 +493,7 @@ static void udp_isr(void) /* Handle Endpoint Interrupts */ uint32_t i; for (i = 0; i < 4; i++) { - if (isr & (1<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 * returns 0 if fifo was full