/* Defaults to EP0 for now */ __noinline static int usb_tx_next(struct usbd_ep_pipe_state_t *s) { /** * Us being here means the previous transfer just completed * successfully. That means the host just toggled its data * sync bit, and so do we. */ s->data01 ^= 1; if (s->transfer_size > 0) { size_t thislen = s->transfer_size; if (thislen > s->ep_maxsize) thislen = s->ep_maxsize; else if (thislen != s->ep_maxsize) s->short_transfer = 0; void *addr = s->data_buf + s->pos; if (s->copy_source) { /* Bounce buffer mode */ addr = s->data_buf; memcpy(addr, s->copy_source + s->pos, thislen); } s->pos += thislen; s->transfer_size -= thislen; usb_queue_next(s, addr, thislen); s->pingpong ^= 1; return (1); } /** * All data has been shipped. Do we need to send a short * packet? */ if (s->short_transfer) { s->short_transfer = 0; usb_queue_next(s, NULL, 0); s->pingpong ^= 1; return (1); } if (s->callback) s->callback(s->data_buf, s->pos, s->callback_data); return (0); }
/** * Receive USB data (OUT device transaction) * * Returns: size to be received, or -1 on error. */ int usb_rx(struct usbd_ep_pipe_state_t *s, void *buf, size_t len, ep_callback_t cb, void *cb_data) { s->data_buf = buf; s->transfer_size = len; s->pos = 0; s->callback = cb; s->callback_data = cb_data; size_t thislen = s->transfer_size; if (thislen > s->ep_maxsize) thislen = s->ep_maxsize; usb_queue_next(s, s->data_buf, thislen); return (len); }
/* XXX pass usb_stat to validate pingpong */ __noinline static int usb_rx_next(struct usbd_ep_pipe_state_t *s) { /** * Us being here means the previous transfer just completed * successfully. That means the host just toggled its data * sync bit, and so do we. */ s->data01 ^= 1; size_t thislen = usb_ep_get_transfer_size(s); s->transfer_size -= thislen; s->pos += thislen; /** * We're done with this buffer now. Switch the pingpong now * before we might have to receive the next piece of data. */ s->pingpong ^= 1; /** * If this is a short transfer, or we received what we * expected, we're done. */ if (thislen < s->ep_maxsize || s->transfer_size == 0) { if (s->callback) s->callback(s->data_buf, s->pos, s->callback_data); return (0); } /** * Otherwise we still need to receive more data. */ size_t nextlen = s->transfer_size; if (nextlen > s->ep_maxsize) nextlen = s->ep_maxsize; void *addr = s->data_buf + s->pos; usb_queue_next(s, addr, nextlen); return (1); }