// Schedule an already filled-in transfer descriptor for execution on // the given endpoint, waiting until the endpoint has finished. void usb_endpoint_schedule_wait( const usb_endpoint_t* const endpoint, usb_transfer_descriptor_t* const td ) { // Ensure that endpoint is ready to be primed. // It may have been flushed due to an aborted transaction. // TODO: This should be preceded by a flush? while( usb_endpoint_is_ready(endpoint) ); td->next_dtd_pointer = USB_TD_NEXT_DTD_POINTER_TERMINATE; usb_endpoint_prime(endpoint, td); }
void usb_endpoint_schedule_no_int( const usb_endpoint_t* const endpoint, usb_transfer_descriptor_t* const td ) { // Ensure that endpoint is ready to be primed. // It may have been flushed due to an aborted transaction. // TODO: This should be preceded by a flush? while( usb_endpoint_is_ready(endpoint) ); // Configure a transfer. td->total_bytes = USB_TD_DTD_TOKEN_TOTAL_BYTES(16384) /*| USB_TD_DTD_TOKEN_IOC*/ | USB_TD_DTD_TOKEN_MULTO(0) | USB_TD_DTD_TOKEN_STATUS_ACTIVE ; usb_endpoint_prime(endpoint, td); }
// Schedule an already filled-in transfer descriptor for execution on // the given endpoint, appending to the end of the endpoint's queue if // there are pending TDs. Note that this requires that one knows the // tail of the endpoint's TD queue. Moreover, the user is responsible // for setting the TERMINATE bit of next_dtd_pointer if needed. void usb_endpoint_schedule_append( const usb_endpoint_t* const endpoint, usb_transfer_descriptor_t* const tail_td, usb_transfer_descriptor_t* const new_td ) { bool done; tail_td->next_dtd_pointer = new_td; if (usb_endpoint_is_priming(endpoint)) { return; } do { USB0_USBCMD_D |= USB0_USBCMD_D_ATDTW; done = usb_endpoint_is_ready(endpoint); } while (!(USB0_USBCMD_D & USB0_USBCMD_D_ATDTW)); USB0_USBCMD_D &= ~USB0_USBCMD_D_ATDTW; if(!done) { usb_endpoint_prime(endpoint, new_td); } }