bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, uint8_t * buf, iram_size_t buf_size, udd_callback_trans_t callback) { udd_ep_job_t *ptr_job; irqflags_t flags; UDD_EP_t *ep_ctrl; Assert(udd_ep_is_valid(ep)); // Get control & job about this endpoint ptr_job = udd_ep_get_job(ep); ep_ctrl = udd_ep_get_ctrl(ep); if (!udd_endpoint_is_enable(ep_ctrl)) { return false; // Endpoint not allocated } if (udd_endpoint_get_type(ep_ctrl)!=USB_EP_TYPE_ISOCHRONOUS_gc && udd_endpoint_is_stall(ep_ctrl)) { return false; // Endpoint is halted } flags = cpu_irq_save(); if (ptr_job->busy == true) { cpu_irq_restore(flags); return false; // Job already on going } ptr_job->busy = true; cpu_irq_restore(flags); // Update Job information ptr_job->buf = buf; ptr_job->buf_size = buf_size; ptr_job->nb_trans = 0; ptr_job->call_trans = callback; // Need to enable shortpacket to send a ZLP (buf_size==0) ptr_job->b_shortpacket = b_shortpacket || (buf_size==0); ptr_job->b_use_out_cache_buffer = false; // Initialize value to simulate a empty transfer if (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)) { udd_endpoint_in_reset_nb_sent(ep_ctrl); } else { if ((USB_EP_TYPE_ISOCHRONOUS_gc == udd_endpoint_get_type(ep_ctrl)) && (0 != (buf_size % udd_ep_get_size(ep_ctrl)))) { // The user must use a buffer size modulo endpoint size ptr_job->busy = false; return false; } udd_endpoint_out_reset_nb_received(ep_ctrl); udd_endpoint_out_set_nbbyte(ep_ctrl, 0); } // Request next transfer udd_ep_trans_complet(ep); return true; }
void udd_ep_free(udd_ep_id_t ep) { UDD_EP_t *ep_ctrl; Assert(udd_ep_is_valid(ep)); udd_ep_abort(ep); ep_ctrl = udd_ep_get_ctrl(ep); udd_endpoint_disable(ep_ctrl); }
bool udd_ep_set_halt(udd_ep_id_t ep) { UDD_EP_t *ep_ctrl; Assert(udd_ep_is_valid(ep)); ep_ctrl = udd_ep_get_ctrl(ep); udd_endpoint_enable_stall(ep_ctrl); udd_ep_abort(ep); return true; }
bool udd_ep_clear_halt(udd_ep_id_t ep) { udd_ep_job_t *ptr_job; UDD_EP_t *ep_ctrl; Assert(udd_ep_is_valid(ep)); ep_ctrl = udd_ep_get_ctrl(ep); if (!udd_endpoint_is_stall(ep_ctrl)) { return true; // No stall on going } udd_endpoint_disable_stall(ep_ctrl); // If a job is register on clear halt action // then execute callback ptr_job = udd_ep_get_job(ep); if (ptr_job->busy == true) { ptr_job->busy = false; ptr_job->call_nohalt(); } return true; }
bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize) { UDD_EP_t *ep_ctrl; Assert(udd_ep_is_valid(ep)); ep_ctrl = udd_ep_get_ctrl(ep); if (udd_endpoint_is_enable(ep_ctrl)) { return false; // Already allocated } udd_ep_init(ep, bmAttributes, MaxEndpointSize); // Do not use multipacket mode with isochronous 1023 bytes endpoint if (udd_endpoint_get_type(ep_ctrl)==USB_EP_TYPE_ISOCHRONOUS_gc && (udd_endpoint_get_size_field(ep_ctrl) ==USB_EP_BUFSIZE_1023_gc)) { return true; } udd_endpoint_set_multipacket(ep_ctrl); return true; }
bool udd_ep_wait_stall_clear(udd_ep_id_t ep, udd_callback_halt_cleared_t callback) { udd_ep_job_t *ptr_job; UDD_EP_t *ep_ctrl; Assert(udd_ep_is_valid(ep)); ep_ctrl = udd_ep_get_ctrl(ep); ptr_job = udd_ep_get_job(ep); if (udd_endpoint_is_stall(ep_ctrl)) { // Wait clear halt endpoint if (ptr_job->busy == true) { return false; // Job already on going } ptr_job->busy = true; ptr_job->call_nohalt = callback; } else { // endpoint not halted then call directly callback callback(); } return true; }
void udd_ep_abort(udd_ep_id_t ep) { UDD_EP_t *ep_ctrl; udd_ep_job_t *ptr_job; Assert(udd_ep_is_valid(ep)); ep_ctrl = udd_ep_get_ctrl(ep); ptr_job = udd_ep_get_job(ep); // Stop transfer udd_endpoint_set_NACK0(ep_ctrl); if (ptr_job->busy == false) { return; // No job on going } ptr_job->busy = false; if (NULL != ptr_job->call_trans) { ptr_job->call_trans(UDD_EP_TRANSFER_ABORT, (ep & USB_EP_DIR_IN) ? udd_endpoint_in_nb_sent(ep_ctrl) : udd_endpoint_out_nb_receiv(ep_ctrl), ep); } }
static void udd_ep_init(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize) { USB_EP_TYPE_t type; USB_EP_BUFSIZE_t size; UDD_EP_t *ep_ctrl; #if (0!=USB_DEVICE_MAX_EP) // Translate USB attribute to hardware defines switch (bmAttributes & USB_EP_TYPE_MASK) { case USB_EP_TYPE_CONTROL: type = USB_EP_TYPE_CONTROL_gc; break; case USB_EP_TYPE_ISOCHRONOUS: type = USB_EP_TYPE_ISOCHRONOUS_gc; break; case USB_EP_TYPE_BULK: case USB_EP_TYPE_INTERRUPT: //interrupt behaves as bulk type = USB_EP_TYPE_BULK_gc; break; default: Assert(false); // Wrong value return; } #else type = USB_EP_TYPE_CONTROL_gc; #endif // Translate USB endpoint size to hardware defines switch (MaxEndpointSize) { default: Assert(false); // Wrong value case 8: size = USB_EP_BUFSIZE_8_gc; break; case 16: size = USB_EP_BUFSIZE_16_gc; break; case 32: size = USB_EP_BUFSIZE_32_gc; break; case 64: size = USB_EP_BUFSIZE_64_gc; break; #if (0!=USB_DEVICE_MAX_EP) case 128: size = USB_EP_BUFSIZE_128_gc; break; case 256: size = USB_EP_BUFSIZE_256_gc; break; case 512: size = USB_EP_BUFSIZE_512_gc; break; case 1023: size =USB_EP_BUFSIZE_1023_gc; break; #endif } // Enable endpoint ep_ctrl = udd_ep_get_ctrl(ep); udd_endpoint_disable(ep_ctrl); udd_endpoint_clear_status(ep_ctrl); udd_endpoint_set_control(ep_ctrl, (uint8_t) type | (uint8_t) size); }
static void udd_ep_trans_complet(udd_ep_id_t ep) { UDD_EP_t *ep_ctrl; udd_ep_job_t *ptr_job; uint16_t ep_size, nb_trans; iram_size_t next_trans; ptr_job = udd_ep_get_job(ep); ep_ctrl = udd_ep_get_ctrl(ep); ep_size = udd_ep_get_size(ep_ctrl); if (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)) { // Transfer complete on IN nb_trans = udd_endpoint_in_nb_sent(ep_ctrl); // Update number of data transfered ptr_job->nb_trans += nb_trans; // Need to send other data if (ptr_job->nb_trans != ptr_job->buf_size) { next_trans = ptr_job->buf_size - ptr_job->nb_trans; if (UDD_ENDPOINT_MAX_TRANS < next_trans) { // The USB hardware support a maximum // transfer size of UDD_ENDPOINT_MAX_TRANS Bytes next_trans = UDD_ENDPOINT_MAX_TRANS - (UDD_ENDPOINT_MAX_TRANS % ep_size); } // Need ZLP, if requested and last packet is not a short packet ptr_job->b_shortpacket = ptr_job->b_shortpacket && (0==(next_trans % ep_size)); udd_endpoint_in_reset_nb_sent(ep_ctrl); udd_endpoint_in_set_bytecnt(ep_ctrl, next_trans); // Link the user buffer directly on USB hardware DMA udd_endpoint_set_buf(ep_ctrl, &ptr_job->buf[ptr_job->nb_trans]); udd_endpoint_clear_NACK0(ep_ctrl); return; } // Need to send a ZLP after all data transfer if (ptr_job->b_shortpacket) { ptr_job->b_shortpacket = false; udd_endpoint_in_reset_nb_sent(ep_ctrl); udd_endpoint_in_set_bytecnt(ep_ctrl, 0); udd_endpoint_clear_NACK0(ep_ctrl); return; } } else { // Transfer complete on OUT nb_trans = udd_endpoint_out_nb_receiv(ep_ctrl); // Can be necessary to copy data receive from cache buffer to user buffer if (ptr_job->b_use_out_cache_buffer) { memcpy(&ptr_job->buf[ptr_job->nb_trans] , udd_ep_out_cache_buffer[ep - 1] , ptr_job->buf_size % ep_size); } // Update number of data transfered ptr_job->nb_trans += nb_trans; if (ptr_job->nb_trans > ptr_job->buf_size) { ptr_job->nb_trans = ptr_job->buf_size; } // If all previous data requested are received and user buffer not full // then need to receive other data if ((nb_trans == udd_endpoint_out_get_nbbyte_requested(ep_ctrl)) && (ptr_job->nb_trans != ptr_job->buf_size)) { next_trans = ptr_job->buf_size - ptr_job->nb_trans; if (UDD_ENDPOINT_MAX_TRANS < next_trans) { // The USB hardware support a maximum transfer size // of UDD_ENDPOINT_MAX_TRANS Bytes next_trans = UDD_ENDPOINT_MAX_TRANS - (UDD_ENDPOINT_MAX_TRANS % ep_size); } else { next_trans -= next_trans % ep_size; } udd_endpoint_out_reset_nb_received(ep_ctrl); if (next_trans < ep_size) { // Use the cache buffer for Bulk or Interrupt size endpoint ptr_job->b_use_out_cache_buffer = true; udd_endpoint_set_buf( ep_ctrl, udd_ep_out_cache_buffer[ep - 1]); udd_endpoint_out_set_nbbyte(ep_ctrl, ep_size); } else { // Link the user buffer directly on USB hardware DMA udd_endpoint_set_buf(ep_ctrl, &ptr_job->buf[ptr_job->nb_trans]); udd_endpoint_out_set_nbbyte(ep_ctrl, next_trans); } // Start transfer udd_endpoint_clear_NACK0(ep_ctrl); return; } } // Job complete then call callback if (ptr_job->busy) { ptr_job->busy = false; if (NULL != ptr_job->call_trans) { ptr_job->call_trans(UDD_EP_TRANSFER_OK, ptr_job->nb_trans, ep); } } return; }