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) { bool b_dir_in; uint32_t udd_dma_ctrl = 0; udd_ep_job_t *ptr_job; irqflags_t flags; b_dir_in = (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)); ep &= USB_EP_ADDR_MASK; if (USB_DEVICE_MAX_EP < ep) return false; // Get job about endpoint ptr_job = &udd_ep_job[ep - 1]; if ((!Is_udd_endpoint_enabled(ep)) || Is_udd_endpoint_stall_requested(ep) || ptr_job->stall_requested) 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); // The USBB supports a maximum transfer size of 64KB if (0x10000 <= buf_size) { // Transfer size = 64KB ptr_job->buf_size = 0x10000; buf_size = 0; } else { ptr_job->buf_size = buf_size; if (b_dir_in && (0 != buf_size % udd_get_endpoint_size(ep))) { // Force short packet option to send a shortpacket on IN, // else the DMA transfer is accepted and interrupt DMA valid but nothing is sent. b_shortpacket = true; } } ptr_job->buf = buf; ptr_job->call_trans = callback; // Start USB DMA to fill or read fifo of the selected endpoint udd_endpoint_dma_set_addr(ep, (U32) buf); if (b_shortpacket) { if (b_dir_in) { udd_dma_ctrl = AVR32_USBB_UDDMA1_CONTROL_DMAEND_EN_MASK; } else { udd_dma_ctrl = AVR32_USBB_UDDMA1_CONTROL_EOT_IRQ_EN_MASK | AVR32_USBB_UDDMA1_CONTROL_BUFF_CLOSE_IN_EN_MASK; } } udd_dma_ctrl |= (buf_size << AVR32_USBB_UDDMA1_CONTROL_CH_BYTE_LENGTH_OFFSET) & AVR32_USBB_UDDMA1_CONTROL_CH_BYTE_LENGTH_MASK; udd_dma_ctrl |= AVR32_USBB_UDDMA1_CONTROL_EOBUFF_IRQ_EN_MASK | AVR32_USBB_UDDMA1_CONTROL_CH_EN_MASK; udd_enable_endpoint_bank_autoswitch(ep); udd_endpoint_dma_set_control(ep, udd_dma_ctrl); flags = cpu_irq_save(); udd_enable_endpoint_dma_interrupt(ep); cpu_irq_restore(flags); return true; }
bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize) { bool b_dir_in; uint16_t ep_allocated; uint8_t bank, i; b_dir_in = ep & USB_EP_DIR_IN; ep = ep & USB_EP_ADDR_MASK; if (ep > USB_DEVICE_MAX_EP) return false; if (Is_udd_endpoint_enabled(ep)) return false; // Bank choise switch(bmAttributes&USB_EP_TYPE_MASK) { case USB_EP_TYPE_ISOCHRONOUS: bank = UDD_ISOCHRONOUS_NB_BANK; break; case USB_EP_TYPE_INTERRUPT: bank = UDD_INTERRUPT_NB_BANK; break; case USB_EP_TYPE_BULK: bank = UDD_BULK_NB_BANK; break; default: Assert(false); return false; } switch(bank) { case 1: bank = AVR32_USBB_UECFG0_EPBK_SINGLE; break; case 2: bank = AVR32_USBB_UECFG0_EPBK_DOUBLE; break; case 3: bank = AVR32_USBB_UECFG0_EPBK_TRIPLE; break; } // Check if endpoint size is 8,16,32,64,128,256,512 or 1023 Assert(MaxEndpointSize < 1024); Assert((MaxEndpointSize == 1023) || !(MaxEndpointSize & (MaxEndpointSize - 1))); Assert(MaxEndpointSize >= 8); // Set configuration of new endpoint udd_configure_endpoint(ep, bmAttributes, (b_dir_in ? 1 : 0), MaxEndpointSize, bank); ep_allocated = 1 << ep; // Unalloc endpoints superior for (i = USB_DEVICE_MAX_EP; i > ep; i--) { if (Is_udd_endpoint_enabled(i)) { ep_allocated |= 1 << i; udd_disable_endpoint(i); udd_unallocate_memory(i); } } // Realloc/Enable endpoints for (i = ep; i <= USB_DEVICE_MAX_EP; i++) { if (ep_allocated & (1 << i)) { udd_allocate_memory(i); udd_enable_endpoint(i); if (!Is_udd_endpoint_configured(i)) return false; } } return true; }
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) { uint16_t ep_size, trans_size, short_packet; bool b_dir_in; udd_ep_job_t *ptr_job; irqflags_t flags; b_dir_in = (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)); ep &= USB_EP_ADDR_MASK; if (USB_DEVICE_MAX_EP < ep) return false; // Get job about endpoint ptr_job = &udd_ep_job[ep - 1]; if ((!Is_udd_endpoint_enabled(ep)) || Is_udd_endpoint_stall_requested(ep)) 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); // No job running. Let's setup a new one. // // The USB hardware support a maximum transfer size of 0x7FFF Bytes ep_size = udd_get_endpoint_size(ep); if (0x7FFF < buf_size) { trans_size = 0x7FFF - (0x7FFF % ep_size); short_packet = 0; } else { trans_size = buf_size; short_packet = trans_size % ep_size; } if (b_dir_in) { // Need ZLP, if requested and last packet is not a short packet udd_udesc_set_buf0_autozlp(ep, b_shortpacket); udd_udesc_set_buf0_ctn(ep, trans_size); udd_udesc_rst_buf0_size(ep); // Link the user buffer directly on USB hardware DMA udd_udesc_set_buf0_addr(ep, buf); } else { udd_udesc_rst_buf0_ctn(ep); ptr_job->nb_trans = 0; if (trans_size < ep_size) { // The user buffer is smaller than endpoint size if (AVR32_USBC_PTYPE_ISOCHRONOUS == udd_get_endpoint_type(ep)) { ptr_job->busy = false; return false; // The user must use a buffer corresponding at isochrnous endpoint size } // Use the cache buffer for Bulk or Interrupt size endpoint ptr_job->b_use_out_cache_buffer = true; udd_udesc_set_buf0_addr(ep, udd_ep_out_cache_buffer[ep - 1]); udd_udesc_set_buf0_size(ep, ep_size); } else { // Link the user buffer directly on USB hardware DMA ptr_job->b_use_out_cache_buffer = false; udd_udesc_set_buf0_addr(ep, buf); udd_udesc_set_buf0_size(ep, trans_size - short_packet); } } // Update Job information ptr_job->buf = buf; ptr_job->buf_size = trans_size; ptr_job->call_trans = callback; ptr_job->busy = true; // Start transfer udd_disable_busy_bank0(ep); // Enable interrupt flags = cpu_irq_save(); if (b_dir_in) { udd_ack_fifocon(ep); udd_ack_in_send(ep); udd_enable_in_send_interrupt(ep); } else { udd_enable_out_received_interrupt(ep); } udd_enable_endpoint_interrupt(ep); cpu_irq_restore(flags); return true; }
bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize) { bool b_dir_in; uint16_t ep_allocated; uint8_t bank, i; b_dir_in = ep & USB_EP_DIR_IN; ep = ep & USB_EP_ADDR_MASK; if (ep > USB_DEVICE_MAX_EP) { return false; } if (Is_udd_endpoint_enabled(ep)) { return false; } // Bank choice switch(bmAttributes&USB_EP_TYPE_MASK) { case USB_EP_TYPE_ISOCHRONOUS: bank = UDD_ISOCHRONOUS_NB_BANK(ep); break; case USB_EP_TYPE_INTERRUPT: bank = UDD_INTERRUPT_NB_BANK(ep); break; case USB_EP_TYPE_BULK: bank = UDD_BULK_NB_BANK(ep); break; default: Assert(false); return false; } switch(bank) { case 1: bank = AVR32_USBB_UECFG0_EPBK_SINGLE; break; case 2: bank = AVR32_USBB_UECFG0_EPBK_DOUBLE; break; case 3: bank = AVR32_USBB_UECFG0_EPBK_TRIPLE; break; default: Assert(false); return false; } // Check if endpoint size is 8,16,32,64,128,256,512 or 1023 Assert(MaxEndpointSize < 1024); Assert((MaxEndpointSize == 1023) || !(MaxEndpointSize & (MaxEndpointSize - 1))); Assert(MaxEndpointSize >= 8); // Set configuration of new endpoint udd_configure_endpoint(ep, bmAttributes, (b_dir_in ? 1 : 0), MaxEndpointSize, bank); ep_allocated = 1 << ep; // Unalloc endpoints superior for (i = USB_DEVICE_MAX_EP; i > ep; i--) { if (Is_udd_endpoint_enabled(i)) { ep_allocated |= 1 << i; udd_disable_endpoint(i); udd_unallocate_memory(i); } } // Realloc/Enable endpoints for (i = ep; i <= USB_DEVICE_MAX_EP; i++) { if (ep_allocated & (1 << i)) { udd_ep_job_t *ptr_job = &udd_ep_job[i - 1]; bool b_restart = ptr_job->busy; ptr_job->busy = false; udd_allocate_memory(i); udd_enable_endpoint(i); if (!Is_udd_endpoint_configured(i)) { if (NULL == ptr_job->call_trans) { return false; } if (Is_udd_endpoint_in(i)) { i |= USB_EP_DIR_IN; } ptr_job->call_trans(UDD_EP_TRANSFER_ABORT, ptr_job->buf_size, i); return false; } udd_enable_endpoint_bank_autoswitch(i); if (b_restart) { // Re-run the job udd_ep_run(i, ptr_job->b_shortpacket, ptr_job->buf, ptr_job->buf_size, ptr_job->call_trans); } } } return true; }
bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes, uint16_t MaxEndpointSize) { bool b_dir_in; uint16_t ep_allocated; uint8_t nb_bank, bank, i; b_dir_in = ep & USB_EP_DIR_IN; ep = ep & USB_EP_ADDR_MASK; if (ep > USB_DEVICE_MAX_EP) { return false; } if (Is_udd_endpoint_enabled(ep)) { return false; } dbg_print("alloc(%x, %d) ", ep, MaxEndpointSize); // Bank choice switch (bmAttributes & USB_EP_TYPE_MASK) { case USB_EP_TYPE_ISOCHRONOUS: nb_bank = UDD_ISOCHRONOUS_NB_BANK(ep); break; case USB_EP_TYPE_INTERRUPT: nb_bank = UDD_INTERRUPT_NB_BANK(ep); break; case USB_EP_TYPE_BULK: nb_bank = UDD_BULK_NB_BANK(ep); break; default: Assert(false); return false; } switch (nb_bank) { case 1: bank = UOTGHS_DEVEPTCFG_EPBK_1_BANK >> UOTGHS_DEVEPTCFG_EPBK_Pos; break; case 2: bank = UOTGHS_DEVEPTCFG_EPBK_2_BANK >> UOTGHS_DEVEPTCFG_EPBK_Pos; break; case 3: bank = UOTGHS_DEVEPTCFG_EPBK_3_BANK >> UOTGHS_DEVEPTCFG_EPBK_Pos; break; default: Assert(false); return false; } // Check if endpoint size is 8,16,32,64,128,256,512 or 1023 Assert(MaxEndpointSize < 1024); Assert((MaxEndpointSize == 1023) || !(MaxEndpointSize & (MaxEndpointSize - 1))); Assert(MaxEndpointSize >= 8); // Set configuration of new endpoint udd_configure_endpoint(ep, bmAttributes, (b_dir_in ? 1 : 0), MaxEndpointSize, bank); ep_allocated = 1 << ep; // Unalloc endpoints superior for (i = USB_DEVICE_MAX_EP; i > ep; i--) { if (Is_udd_endpoint_enabled(i)) { ep_allocated |= 1 << i; udd_disable_endpoint(i); udd_unallocate_memory(i); } } // Realloc/Enable endpoints for (i = ep; i <= USB_DEVICE_MAX_EP; i++) { if (ep_allocated & (1 << i)) { udd_ep_job_t *ptr_job = &udd_ep_job[i - 1]; bool b_restart = ptr_job->busy; // Restart running job because // memory window slides up and its data is lost ptr_job->busy = false; // Re-allocate memory udd_allocate_memory(i); udd_enable_endpoint(i); if (!Is_udd_endpoint_configured(i)) { dbg_print("ErrRealloc%d ", i); if (NULL == ptr_job->call_trans) { return false; } if (Is_udd_endpoint_in(i)) { i |= USB_EP_DIR_IN; } ptr_job->call_trans(UDD_EP_TRANSFER_ABORT, ptr_job->buf_cnt, i); return false; } udd_enable_endpoint_bank_autoswitch(i); if (b_restart) { // Re-run the job remaining part ptr_job->buf_cnt -= ptr_job->buf_load; b_restart = udd_ep_run(Is_udd_endpoint_in(i) ? (i | USB_EP_DIR_IN) : i, ptr_job->b_shortpacket, &ptr_job->buf[ptr_job->buf_cnt], ptr_job->buf_size - ptr_job->buf_cnt, ptr_job->call_trans); if (!b_restart) { dbg_print("ErrReRun%d ", i); return false; } } } } return true; }