/cpu/arm/at91sam7s/usb-arch.c
C | 878 lines | 699 code | 108 blank | 71 comment | 114 complexity | 73bf9da120581f166268a305bb3dea6e MD5 | raw file
- #include <usb-arch.h>
- #include <usb-interrupt.h>
- #include <AT91SAM7S64.h>
- #include <stdio.h>
- #include <debug-uart.h>
- /* #define DEBUG */
- #ifdef DEBUG
- #define PRINTF(...) printf(__VA_ARGS__)
- #else
- #define PRINTF(...)
- #endif
- #define USB_PULLUP_PIN AT91C_PIO_PA16
- #ifndef AT91C_UDP_STALLSENT
- #define AT91C_UDP_STALLSENT AT91C_UDP_ISOERROR
- #endif
- /* Bits that won't effect the state if they're written at a specific level.
- */
- /* Bits that should be written as 1 */
- #define NO_EFFECT_BITS (AT91C_UDP_TXCOMP | AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP \
- | AT91C_UDP_ISOERROR | AT91C_UDP_RX_DATA_BK1)
- /* Also includes bits that should be written as 0 */
- #define NO_EFFECT_MASK (NO_EFFECT_BITS | AT91C_UDP_TXPKTRDY)
- #define RXBYTECNT(s) (((s)>>16)&0x7ff)
- static inline void
- udp_set_ep_ctrl_flags(AT91_REG *reg, unsigned int flags,
- unsigned int write_mask, unsigned int check_mask)
- {
- while ( (*reg & check_mask) != (flags & check_mask)) {
- *reg = (*reg & ~write_mask) | flags;
- }
- }
- #define UDP_SET_EP_CTRL_FLAGS(reg, flags, mask) \
- udp_set_ep_ctrl_flags((reg), \
- (NO_EFFECT_BITS & ~(mask)) | ((flags) & (mask)), (mask) | NO_EFFECT_MASK,\
- (mask))
- #define USB_DISABLE_INT *AT91C_AIC_IDCR = (1 << AT91C_ID_UDP)
- #define USB_ENABLE_INT *AT91C_AIC_IECR = (1 << AT91C_ID_UDP)
- #define USB_DISABLE_EP_INT(hw_ep) *AT91C_UDP_IDR = (1 << (hw_ep))
- #define USB_ENABLE_EP_INT(hw_ep) *AT91C_UDP_IER = (1 << (hw_ep))
- #if CTRL_EP_SIZE > 8
- #error Control endpoint size too big
- #endif
- #if USB_EP1_SIZE > 64
- #error Endpoint 1 size too big
- #endif
- #if USB_EP2_SIZE > 64
- #error Endpoint 2 size too big
- #endif
- #if USB_EP3_SIZE > 64
- #error Endpoint 3 size too big
- #endif
- static const uint16_t ep_xfer_size[8] =
- {
- CTRL_EP_SIZE,
- USB_EP1_SIZE,
- USB_EP2_SIZE,
- USB_EP3_SIZE
- };
- #define USB_EP_XFER_SIZE(ep) ep_xfer_size[ep]
- typedef struct _USBEndpoint USBEndpoint;
- struct _USBEndpoint
- {
- uint16_t status;
- uint8_t addr;
- uint8_t flags;
- USBBuffer *buffer; /* NULL if no current buffer */
- struct process *event_process;
- unsigned int events;
- uint16_t xfer_size;
- };
- #define USB_EP_FLAGS_TYPE_MASK 0x03
- #define USB_EP_FLAGS_TYPE_BULK 0x00
- #define USB_EP_FLAGS_TYPE_CONTROL 0x01
- #define USB_EP_FLAGS_TYPE_ISO 0x02
- #define USB_EP_FLAGS_TYPE_INTERRUPT 0x03
- #define EP_TYPE(ep) ((ep)->flags & USB_EP_FLAGS_TYPE_MASK)
- #define IS_EP_TYPE(ep, type) (EP_TYPE(ep) == (type))
- #define IS_CONTROL_EP(ep) IS_EP_TYPE(ep, USB_EP_FLAGS_TYPE_CONTROL)
- #define IS_BULK_EP(ep) IS_EP_TYPE(ep, USB_EP_FLAGS_TYPE_BULK)
- #define USB_EP_FLAGS_ENABLED 0x04
- /* A packet has been received but the data is still in hardware buffer */
- #define USB_EP_FLAGS_RECV_PENDING 0x08
- /* The pending packet is a SETUP packet */
- #define USB_EP_FLAGS_SETUP_PENDING 0x10
- /* The data in the hardware buffer is being transmitted */
- #define USB_EP_FLAGS_TRANSMITTING 0x20
- /* The receiver is waiting for a packet */
- #define USB_EP_FLAGS_RECEIVING 0x40
- /* For bulk endpoints. Both buffers are busy are in use, either by
- hardware or software. */
- #define USB_EP_FLAGS_DOUBLE 0x80
- /* The next packet received should be read from bank 1 if possible */
- #define USB_EP_FLAGS_BANK_1_RECV_NEXT 0x10
- /* States for double buffered reception:
- Packets being received 0 1 2 1 0 0
- Packets pending 0 0 0 1 2 1
- RECVING 0 1 1 1 0 0
- RECV_PENDING 0 0 0 1 1 1
- DOUBLE 0 0 1 0 1 0
- */
- /* States for double buffered transmission:
-
- Packets being transmitted 0 1 2
- TRANSMITTING 0 1 1
- DOUBLE 0 0 1
- */
- /* Index in endpoint array */
- #define EP_INDEX(addr) ((addr) & 0x7f)
- /* Get address of endpoint struct */
- #define EP_STRUCT(addr) &usb_endpoints[EP_INDEX(addr)];
- /* Number of hardware endpoint */
- #define EP_HW_NUM(addr) ((addr) & 0x7f)
- static USBEndpoint usb_endpoints[USB_MAX_ENDPOINTS];
- struct process *event_process = 0;
- volatile unsigned int events = 0;
- static void
- notify_process(unsigned int e)
- {
- events |= e;
- if (event_process) {
- process_poll(event_process);
- }
- }
- static void
- notify_ep_process(USBEndpoint *ep, unsigned int e)
- {
- ep->events |= e;
- if (ep->event_process) {
- process_poll(ep->event_process);
- }
- }
- static void
- usb_arch_reset(void)
- {
- unsigned int e;
- for (e = 0; e < USB_MAX_ENDPOINTS; e++) {
- if (usb_endpoints[e].flags &USB_EP_FLAGS_ENABLED) {
- USBBuffer *buffer = usb_endpoints[e].buffer;
- usb_endpoints[e].flags = 0;
- usb_disable_endpoint(e);
- while(buffer) {
- buffer->flags &= ~USB_BUFFER_SUBMITTED;
- buffer = buffer->next;
- }
- }
- }
- usb_arch_setup_control_endpoint(0);
- }
- void
- usb_arch_setup(void)
- {
- unsigned int i;
- /* Assume 96MHz PLL frequency */
- *AT91C_CKGR_PLLR = ((*AT91C_CKGR_PLLR & ~AT91C_CKGR_USBDIV)
- | AT91C_CKGR_USBDIV_1);
- /* Enable 48MHz USB clock */
- *AT91C_PMC_SCER = AT91C_PMC_UDP;
- /* Enable USB main clock */
- *AT91C_PMC_PCER = (1 << AT91C_ID_UDP);
-
- /* Enable pullup */
- *AT91C_PIOA_PER = USB_PULLUP_PIN;
- *AT91C_PIOA_OER = USB_PULLUP_PIN;
- *AT91C_PIOA_CODR = USB_PULLUP_PIN;
- for(i = 0; i < USB_MAX_ENDPOINTS; i++) {
- usb_endpoints[i].flags = 0;
- usb_endpoints[i].event_process = 0;
- }
-
- usb_arch_reset();
- /* Enable usb_interrupt */
- AT91C_AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 4;
- AT91C_AIC_SVR[AT91C_ID_UDP] = (unsigned long) usb_int;
- *AT91C_AIC_IECR = (1 << AT91C_ID_UDP);
- }
- static void
- usb_arch_setup_endpoint(unsigned char addr, unsigned int hw_type)
- {
- unsigned int ei = EP_HW_NUM(addr);
- USBEndpoint *ep = EP_STRUCT(addr);
- ep->status = 0;
- ep->flags = USB_EP_FLAGS_ENABLED;
- ep->buffer = 0;
- ep->addr = addr;
- ep->events = 0;
- ep->xfer_size = 0;
- *AT91C_UDP_IDR = 1<<ei;
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ei], hw_type | AT91C_UDP_EPEDS,
- AT91C_UDP_EPTYPE | AT91C_UDP_EPEDS);
-
- *AT91C_UDP_IER = 1<<ei;
- };
- void
- usb_arch_setup_control_endpoint(unsigned char addr)
- {
- unsigned int ei = EP_HW_NUM(addr);
- USBEndpoint *ep = EP_STRUCT(addr);
- usb_arch_setup_endpoint(addr, AT91C_UDP_EPTYPE_CTRL);
- ep->flags |= USB_EP_FLAGS_TYPE_CONTROL;
- ep->xfer_size = ep_xfer_size[ei];
- }
- void
- usb_arch_setup_bulk_endpoint(unsigned char addr)
- {
- unsigned int ei = EP_HW_NUM(addr);
- USBEndpoint *ep = EP_STRUCT(addr);
- usb_arch_setup_endpoint(addr, ((addr & 0x80)
- ? AT91C_UDP_EPTYPE_BULK_IN
- : AT91C_UDP_EPTYPE_BULK_OUT));
- ep->flags |= USB_EP_FLAGS_TYPE_BULK;
- ep->xfer_size = ep_xfer_size[ei];
- }
- void
- usb_arch_setup_interrupt_endpoint(unsigned char addr)
- {
- unsigned int ei = EP_HW_NUM(addr);
- USBEndpoint *ep = EP_STRUCT(addr);
- usb_arch_setup_endpoint(addr, ((addr & 0x80)
- ? AT91C_UDP_EPTYPE_INT_IN
- : AT91C_UDP_EPTYPE_INT_OUT));
- ep->flags |= USB_EP_FLAGS_TYPE_BULK;
- ep->xfer_size = ep_xfer_size[ei];
- }
- void
- usb_arch_disable_endpoint(uint8_t addr)
- {
- USBEndpoint *ep = EP_STRUCT(addr);
- ep->flags &= ~USB_EP_FLAGS_ENABLED;
-
- *AT91C_UDP_IDR = 1<<EP_HW_NUM(addr);
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(addr)], 0, AT91C_UDP_EPEDS);
- }
-
- #define USB_READ_BLOCK 0x01 /* The currently submitted buffers
- can't hold the received data, wait
- for more buffers. No data was read
- from the hardware buffer */
- #define USB_READ_NOTIFY 0x02 /* Some buffers that had the
- USB_BUFFER_NOTIFY flags set were
- released */
- #define USB_READ_FAIL 0x04 /* The received data doesn't match the
- submitted buffers. The hardware
- buffer is discarded. */
- /* Skip buffers until mask and flags matches*/
- static USBBuffer *
- skip_buffers_until(USBBuffer *buffer, unsigned int mask, unsigned int flags,
- unsigned int *resp)
- {
- while(buffer && !((buffer->flags & mask) == flags)) {
- USBBuffer *next = buffer->next;
- buffer->flags &= ~USB_BUFFER_SUBMITTED ;
- buffer->flags |= USB_BUFFER_FAILED;
- if (buffer->flags & USB_BUFFER_NOTIFY) *resp |= USB_READ_NOTIFY;
- buffer = next;
- }
- return buffer;
- }
- static void
- read_hw_buffer(uint8_t *data, unsigned int hw_ep, unsigned int len)
- {
- AT91_REG *fdr;
- fdr = &AT91C_UDP_FDR[hw_ep];
- while(len-- > 0) {
- *data++ = *fdr;
- }
- }
- #define USB_WRITE_BLOCK 0x01
- #define USB_WRITE_NOTIFY 0x02
- void
- write_hw_buffer(const uint8_t *data, unsigned int hw_ep, unsigned int len)
- {
- AT91_REG *fdr;
- fdr = &AT91C_UDP_FDR[hw_ep];
- /* PRINTF("Write %d\n", len); */
- while(len-- > 0) {
- *fdr = *data++;
- }
- }
- static unsigned int
- get_receive_capacity(USBBuffer *buffer)
- {
- unsigned int capacity = 0;
- while(buffer && !(buffer->flags & (USB_BUFFER_IN| USB_BUFFER_SETUP|USB_BUFFER_HALT))) {
- capacity += buffer->left;
- buffer = buffer->next;
- }
- return capacity;
- }
- static int
- handle_pending_receive(USBEndpoint *ep)
- {
- int short_packet;
- unsigned int len;
- unsigned int copy;
- unsigned int res = 0;
- unsigned int hw_ep = EP_HW_NUM(ep->addr);
- USBBuffer *buffer = ep->buffer;
- uint8_t *setup_data = NULL;
- unsigned int flags = ep->flags;
- if (!(flags & USB_EP_FLAGS_ENABLED) || !buffer) return USB_READ_BLOCK;
- len = RXBYTECNT(AT91C_UDP_CSR[hw_ep]);
- PRINTF("handle_pending_receive: %d\n", len);
- switch(flags & USB_EP_FLAGS_TYPE_MASK) {
- case USB_EP_FLAGS_TYPE_CONTROL:
- if (flags & USB_EP_FLAGS_SETUP_PENDING) {
- /* Discard buffers until we find a SETUP buffer */
- buffer =
- skip_buffers_until(buffer, USB_BUFFER_SETUP, USB_BUFFER_SETUP, &res);
- ep->buffer = buffer;
- if (!buffer || buffer->left < len) {
- res |= USB_READ_BLOCK;
- return res;
- }
- /* SETUP packet must fit in a single buffer */
- if (buffer->left < len) {
- buffer->flags |= USB_BUFFER_FAILED;
- buffer->flags &= ~USB_BUFFER_SUBMITTED ;
- if (buffer->flags & USB_BUFFER_NOTIFY) res |= USB_READ_NOTIFY;
- ep->buffer = buffer->next;
- res |= USB_READ_FAIL;
- return res;
- }
- setup_data = buffer->data;
- } else {
- if (buffer->flags & (USB_BUFFER_SETUP|USB_BUFFER_IN)) {
- buffer->flags |= USB_BUFFER_FAILED;
-
- buffer->flags &= ~USB_BUFFER_SUBMITTED ;
- if (buffer->flags & USB_BUFFER_NOTIFY) res |= USB_READ_NOTIFY;
- ep->buffer = buffer->next;
- res |= USB_READ_FAIL;
- return res;
- }
- if (len == 0) {
- /* Status OUT */
- if (buffer->left > 0) {
- buffer->flags |= USB_BUFFER_FAILED;
- res |= USB_READ_FAIL;
- }
- buffer->flags &= ~USB_BUFFER_SUBMITTED ;
- if (buffer->flags & USB_BUFFER_NOTIFY) res |= USB_READ_NOTIFY;
- ep->buffer = buffer->next;
- return res;
- }
- if (get_receive_capacity(buffer) < len) return USB_READ_BLOCK;
- }
- break;
- case USB_EP_FLAGS_TYPE_INTERRUPT:
- case USB_EP_FLAGS_TYPE_BULK:
- case USB_EP_FLAGS_TYPE_ISO:
- if (get_receive_capacity(buffer) < len) {
- return USB_READ_BLOCK;
- }
- break;
- }
- short_packet = len < ep->xfer_size;
- do {
- if (buffer->left < len) {
- copy = buffer->left;
- } else {
- copy = len;
- }
- len -= copy;
- buffer->left -= copy;
- read_hw_buffer(buffer->data, hw_ep, copy);
- buffer->data += copy;
- if (len == 0) break;
- /* Release buffer */
- buffer->flags &= ~(USB_BUFFER_SUBMITTED | USB_BUFFER_SHORT_PACKET);
- if (buffer->flags & USB_BUFFER_NOTIFY) res |= USB_READ_NOTIFY;
- /* Use next buffer. */
- buffer = buffer->next;
- } while(1);
-
- if (short_packet) {
- buffer->flags |= USB_BUFFER_SHORT_PACKET;
- }
-
- if ((buffer->left == 0)
- || (buffer->flags & USB_BUFFER_PACKET_END)
- || (short_packet && (buffer->flags & USB_BUFFER_SHORT_END))) {
- /* Release buffer */
- buffer->flags &= ~USB_BUFFER_SUBMITTED;
- if (buffer->flags & USB_BUFFER_NOTIFY) res |= USB_READ_NOTIFY;
- /* Use next buffer. */
- buffer = buffer->next;
- }
-
- ep->buffer = buffer;
- if (setup_data) {
- /* Set direction according to request */
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],
- ((setup_data[0] & 0x80)
- ? AT91C_UDP_DIR : 0), AT91C_UDP_DIR);
- }
- return res;
- }
- static void
- start_receive(USBEndpoint *ep)
- {
- ep->flags |= USB_EP_FLAGS_RECEIVING;
- }
- #if 0
- static unsigned int
- get_transmit_length(USBBuffer *buffer)
- {
- unsigned int length = 0;
- while(buffer && (buffer->flags & USB_BUFFER_IN)) {
- length += buffer->left;
- buffer = buffer->next;
- }
- return length;
- }
- #endif
- static int
- start_transmit(USBEndpoint *ep)
- {
- unsigned int res = 0;
- USBBuffer *buffer = ep->buffer;
- unsigned int len;
- unsigned int hw_ep = EP_HW_NUM(ep->addr);
- unsigned int ep_flags = ep->flags;
- len = ep->xfer_size;
- if (!(ep_flags & USB_EP_FLAGS_ENABLED) || !buffer) return USB_WRITE_BLOCK;
- switch(ep_flags & USB_EP_FLAGS_TYPE_MASK) {
- case USB_EP_FLAGS_TYPE_BULK:
- if (buffer->flags & USB_BUFFER_HALT) {
- if (ep->status & 0x01) return USB_WRITE_BLOCK;
- ep->status |= 0x01;
- if (!(ep->flags & USB_EP_FLAGS_TRANSMITTING)) {
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],
- AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
- PRINTF("HALT IN\n");
- }
- return USB_WRITE_BLOCK;
- }
- case USB_EP_FLAGS_TYPE_ISO:
- if (!(ep->flags & USB_EP_FLAGS_TRANSMITTING)) {
- if (AT91C_UDP_CSR[hw_ep] & AT91C_UDP_TXPKTRDY) return USB_WRITE_BLOCK;
- }
- break;
- default:
- if (AT91C_UDP_CSR[hw_ep] & AT91C_UDP_TXPKTRDY) return USB_WRITE_BLOCK;
- }
-
- while (buffer) {
- unsigned int copy;
- if (buffer->left < len) {
- copy = buffer->left;
- } else {
- copy = len;
- }
- len -= copy;
- buffer->left -= copy;
- write_hw_buffer(buffer->data, hw_ep, copy);
- buffer->data += copy;
- if (buffer->left == 0) {
- if (buffer->flags & USB_BUFFER_SHORT_END) {
- if (len == 0) {
- /* Send zero length packet. */
- break;
- } else {
- len = 0;
- }
- }
- /* Release buffer */
- buffer->flags &= ~USB_BUFFER_SUBMITTED;
- if (buffer->flags & USB_BUFFER_NOTIFY) res = USB_WRITE_NOTIFY;
- /* Use next buffer. */
- buffer = buffer->next;
- }
- if (len == 0) break;
- }
- ep->buffer = buffer;
- if (ep->flags & USB_EP_FLAGS_TRANSMITTING) {
- ep->flags |= USB_EP_FLAGS_DOUBLE;
- } else {
- ep->flags |= USB_EP_FLAGS_TRANSMITTING;
- }
-
- PRINTF("start_transmit: sent %08x\n",AT91C_UDP_CSR[hw_ep]);
- /* Start transmission */
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],
- AT91C_UDP_TXPKTRDY, AT91C_UDP_TXPKTRDY);
- return res;
- }
- static void
- start_transfer(USBEndpoint *ep)
- {
- unsigned int hw_ep = EP_HW_NUM(ep->addr);
- int res;
- while (1) {
- if (!(ep->addr & 0x80)) {
- if (ep->buffer && (ep->buffer->flags & USB_BUFFER_HALT)) {
- if (ep->status & 0x01) return ;
- ep->status |= 0x01;
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(ep->addr)],
- AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
- PRINTF("HALT OUT\n");
- *AT91C_UDP_IDR = 1<<hw_ep;
- return;
- }
- }
- if (!(ep->flags & USB_EP_FLAGS_RECV_PENDING)) break;
- res = handle_pending_receive(ep);
- if (res & USB_READ_NOTIFY) {
- notify_ep_process(ep, USB_EP_EVENT_NOTIFICATION);
- }
- PRINTF("received res = %d\n", res);
- if (res & USB_READ_BLOCK) {
- *AT91C_UDP_IDR = 1<<hw_ep;
- return;
- }
- if (AT91C_UDP_CSR[hw_ep] & AT91C_UDP_RXSETUP) {
- /* Acknowledge SETUP */
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],0, AT91C_UDP_RXSETUP);
- } else if (AT91C_UDP_CSR[hw_ep] & (AT91C_UDP_RX_DATA_BK1)) {
- /* Ping-pong */
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],0,
- (ep->flags & USB_EP_FLAGS_BANK_1_RECV_NEXT)
- ? AT91C_UDP_RX_DATA_BK1
- : AT91C_UDP_RX_DATA_BK0);
- ep->flags ^= USB_EP_FLAGS_BANK_1_RECV_NEXT;
- } else {
- /* Ping-pong or single buffer */
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],0,
- AT91C_UDP_RX_DATA_BK0);
- ep->flags |= USB_EP_FLAGS_BANK_1_RECV_NEXT;
- }
- if (ep->flags & USB_EP_FLAGS_DOUBLE) {
- ep->flags &= ~USB_EP_FLAGS_DOUBLE;
- } else if IS_CONTROL_EP(ep) {
- ep->flags &= ~(USB_EP_FLAGS_RECV_PENDING|USB_EP_FLAGS_SETUP_PENDING);
- } else {
- ep->flags &= ~USB_EP_FLAGS_RECV_PENDING;
- }
- if (res & USB_READ_FAIL) {
- /* Only fails for control endpoints */
- usb_arch_control_stall(ep->addr);
- return;
- }
- *AT91C_UDP_IER = 1<<hw_ep;
- }
- if (ep->flags & (USB_EP_FLAGS_TRANSMITTING | USB_EP_FLAGS_RECEIVING)) {
- #if 0
- if (!IS_BULK_EP(ep) || (ep->flags & USB_EP_FLAGS_DOUBLE)) {
- #else
- if(1) {
- #endif
- PRINTF("Busy\n");
- return;
- }
- }
- if (ep->status & 0x01) return; /* Don't start transfer if halted */
- if (ep->buffer) {
- if (ep->buffer->flags & USB_BUFFER_IN) {
- res = start_transmit(ep);
- if (res & USB_WRITE_NOTIFY) {
- notify_ep_process(ep, USB_EP_EVENT_NOTIFICATION);
- }
- } else {
- start_receive(ep);
- }
- }
- }
- void
- usb_arch_transfer_complete(unsigned int hw_ep)
- {
- unsigned int status = AT91C_UDP_CSR[hw_ep];
- USBEndpoint *ep = &usb_endpoints[hw_ep];
- PRINTF("transfer_complete: %d\n", hw_ep);
- if (status & AT91C_UDP_STALLSENT) {
- /* Acknowledge */
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],0, AT91C_UDP_STALLSENT);
- }
- if (status & (AT91C_UDP_RXSETUP
- | AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_RX_DATA_BK0)) {
- if (status & AT91C_UDP_RXSETUP) {
- PRINTF("SETUP\n");
- ep->flags |= USB_EP_FLAGS_SETUP_PENDING;
- }
- if (ep->flags & USB_EP_FLAGS_DOUBLE) {
- ep->flags &= ~USB_EP_FLAGS_DOUBLE;
- } else {
- ep->flags &= ~USB_EP_FLAGS_RECEIVING;
- }
- if ( ep->flags & USB_EP_FLAGS_RECV_PENDING) {
- ep->flags |= USB_EP_FLAGS_DOUBLE;
- } else {
- ep->flags |= USB_EP_FLAGS_RECV_PENDING;
- }
- start_transfer(ep);
- }
- if (status & AT91C_UDP_TXCOMP) {
- PRINTF("Sent packet\n");
- if (ep->flags & USB_EP_FLAGS_DOUBLE) {
- ep->flags &= ~USB_EP_FLAGS_DOUBLE;
- } else {
- ep->flags &= ~USB_EP_FLAGS_TRANSMITTING;
- }
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],0, AT91C_UDP_TXCOMP);
- if (ep->status & 0x01) {
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],
- AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
- PRINTF("HALT IN\n");
- } else {
- start_transfer(ep);
- }
- }
-
- }
- void
- usb_set_ep_event_process(unsigned char addr, struct process *p)
- {
- USBEndpoint *ep = &usb_endpoints[EP_INDEX(addr)];
- ep->event_process = p;
- }
- /* Select what process should be polled when a global event occurs */
- void
- usb_arch_set_global_event_process(struct process *p)
- {
- event_process = p;
- }
- unsigned int
- usb_arch_get_global_events(void)
- {
- unsigned int e;
- USB_DISABLE_INT;
- e = events;
- events = 0;
- USB_ENABLE_INT;
- return e;
- }
- unsigned int
- usb_get_ep_events(unsigned char addr)
- {
- unsigned int e;
- unsigned int ei = EP_HW_NUM(addr);
- USB_DISABLE_INT;
- e = usb_endpoints[ei].events;
- usb_endpoints[ei].events = 0;
- USB_ENABLE_INT;
- return e;
- }
- void
- usb_submit_recv_buffer(unsigned char ep_addr, USBBuffer *buffer)
- {
- USBBuffer **tailp;
- USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
- if (!(ep->flags & USB_EP_FLAGS_ENABLED)) return;
- /* PRINTF("buffer: %p\n", ep->buffer); */
- /* dbg_drain(); */
- USB_DISABLE_INT;
- tailp = (USBBuffer**)&ep->buffer;
- while(*tailp) {
- tailp = &(*tailp)->next;
- }
- *tailp = buffer;
- while(buffer) {
- buffer->flags |= USB_BUFFER_SUBMITTED;
- buffer = buffer->next;
- }
- start_transfer(ep);
-
- USB_ENABLE_INT;
- }
- void
- usb_submit_xmit_buffer(unsigned char ep_addr, USBBuffer *buffer)
- {
- USBBuffer **tailp;
- USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
- if (!(ep->flags & USB_EP_FLAGS_ENABLED)) return;
- /* PRINTF("usb_submit_xmit_buffer %d\n", buffer->left); */
- USB_DISABLE_INT;
- tailp = (USBBuffer**)&ep->buffer;
- while(*tailp) {
- tailp = &(*tailp)->next;
- }
- *tailp = buffer;
- while(buffer) {
- buffer->flags |= USB_BUFFER_SUBMITTED | USB_BUFFER_IN;
- buffer = buffer->next;
- }
- start_transfer(ep);
- USB_ENABLE_INT;
- }
- void
- usb_arch_discard_all_buffers(unsigned char ep_addr)
- {
- USBBuffer *buffer;
- volatile USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
- USB_DISABLE_EP_INT(EP_HW_NUM(ep_addr));
- buffer = ep->buffer;
- ep->buffer = NULL;
- USB_ENABLE_EP_INT(EP_HW_NUM(ep_addr));
- while(buffer) {
- buffer->flags &= ~USB_BUFFER_SUBMITTED;
- buffer = buffer->next;
- }
- }
- uint16_t
- usb_arch_get_ep_status(uint8_t addr)
- {
- if (EP_INDEX(addr) > USB_MAX_ENDPOINTS) return 0;
- return usb_endpoints[EP_INDEX(addr)].status;
- }
- void
- usb_arch_set_configuration(uint8_t usb_configuration_value)
- {
- /* Nothing needs to be done */
- }
- void
- usb_arch_control_stall(unsigned char addr)
- {
- if (EP_INDEX(addr) > USB_MAX_ENDPOINTS) return;
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(addr)],
- AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
- }
- /* Not for control endpoints */
- void
- usb_arch_halt_endpoint(unsigned char ep_addr, int halt)
- {
- if (EP_INDEX(ep_addr) > USB_MAX_ENDPOINTS) return;
- if (!usb_endpoints[EP_INDEX(ep_addr)].flags & USB_EP_FLAGS_ENABLED) return;
- *AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
- if (halt) {
- usb_endpoints[EP_INDEX(ep_addr)].status |= 0x01;
- /* Delay stall if a transmission is i progress */
- if (!(usb_endpoints[EP_INDEX(ep_addr)].flags & USB_EP_FLAGS_TRANSMITTING)){
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(ep_addr)],
- AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
- }
- } else {
- USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
- ep->status &= ~0x01;
- *AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
- UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(ep_addr)],
- 0, AT91C_UDP_FORCESTALL);
- *AT91C_UDP_RSTEP = 1<<EP_HW_NUM(ep_addr);
- *AT91C_UDP_RSTEP = 0;
-
- /* Release HALT buffer */
- if (ep->buffer && (ep->buffer->flags & USB_BUFFER_HALT)) {
- ep->buffer->flags &= ~USB_BUFFER_SUBMITTED;
- if (ep->buffer->flags & USB_BUFFER_NOTIFY) {
- notify_ep_process(ep,USB_EP_EVENT_NOTIFICATION);
- }
- ep->buffer = ep->buffer->next;
- }
-
- /* Restart transmission */
- start_transfer(&usb_endpoints[EP_INDEX(ep_addr)]);
- }
- *AT91C_UDP_IER = 1<<EP_HW_NUM(ep_addr);
- }
- int
- usb_arch_send_pending(uint8_t ep_addr)
- {
- return usb_endpoints[EP_INDEX(ep_addr)].flags & USB_EP_FLAGS_TRANSMITTING;
- }
- void
- usb_arch_set_address(unsigned char addr)
- {
- *AT91C_UDP_FADDR = AT91C_UDP_FEN | addr;
- *AT91C_UDP_GLBSTATE |= AT91C_UDP_FADDEN;
- }
- void
- usb_arch_reset_int()
- {
- usb_arch_reset();
- notify_process(USB_EVENT_RESET);
- }
- void
- usb_arch_suspend_int()
- {
- notify_process(USB_EVENT_SUSPEND);
- }
- void
- usb_arch_resume_int()
- {
- notify_process(USB_EVENT_RESUME);
- }