bool udd_ep_set_halt(udd_ep_id_t ep) { bool b_dir_in = ep & USB_EP_DIR_IN; uint8_t ep_index = ep & USB_EP_ADDR_MASK; udd_ep_job_t *ptr_job = &udd_ep_job[ep_index - 1]; irqflags_t flags; if (USB_DEVICE_MAX_EP < ep_index) { return false; } flags = cpu_irq_save(); if (b_dir_in && (Is_udd_transmit_ready(ep_index) || ptr_job->bank > 1)) { // Halt until banks sent ptr_job->b_stall_requested = true; udd_enable_endpoint_interrupt(ep_index); cpu_irq_restore(flags); return true; } else { // Stall endpoint udd_enable_stall_handshake(ep_index); udd_enable_endpoint_interrupt(ep_index); cpu_irq_restore(flags); } return true; }
bool udd_ep_set_halt(udd_ep_id_t ep) { udd_ep_job_t *ptr_job; uint8_t index = ep & USB_EP_ADDR_MASK; if (USB_DEVICE_MAX_EP < index) { return false; } ptr_job = &udd_ep_job[index - 1]; if (Is_udd_endpoint_stall_requested(index) // Endpoint stalled || ptr_job->stall_requested) { // Endpoint stall is requested return true; // Already STALL } if (ptr_job->busy == true) { return false; // Job on going, stall impossible } if ((ep & USB_EP_DIR_IN) && (0 != udd_nb_busy_bank(index))) { // Delay the stall after the end of IN transfer on USB line ptr_job->stall_requested = true; udd_enable_bank_interrupt(index); udd_enable_endpoint_interrupt(index); return true; } // Stall endpoint immediately udd_disable_endpoint_bank_autoswitch(index); udd_ack_stall(index); udd_enable_stall_handshake(index); return true; }
static bool udd_ep_interrupt(void) { udd_ep_id_t ep; udd_ep_job_t *ptr_job; // For each endpoint different of control endpoint (0) for (ep = 1; ep <= USB_DEVICE_MAX_EP; ep++) { // Get job corresponding at endpoint ptr_job = &udd_ep_job[ep - 1]; // Check DMA event if (Is_udd_endpoint_dma_interrupt_enabled(ep) && Is_udd_endpoint_dma_interrupt(ep)) { uint32_t nb_remaining; if( udd_endpoint_dma_get_status(ep) & AVR32_USBB_UDDMA1_STATUS_CH_EN_MASK) { return true; // Ignore EOT_STA interrupt } udd_disable_endpoint_dma_interrupt(ep); // Save number of data no transfered nb_remaining = (udd_endpoint_dma_get_status(ep) & AVR32_USBB_UDDMA1_STATUS_CH_BYTE_CNT_MASK) >> AVR32_USBB_UDDMA1_STATUS_CH_BYTE_CNT_OFFSET; if (nb_remaining) { // Transfer no complete (short packet or ZLP) then: // Update number of data transfered ptr_job->nb_trans -= nb_remaining; // Set transfer complete to stop the transfer ptr_job->buf_size = ptr_job->nb_trans; } udd_ep_trans_done(ep); return true; } // Check empty bank interrupt event if (Is_udd_endpoint_interrupt_enabled(ep)) { if (Is_udd_in_send_interrupt_enabled(ep) && Is_udd_in_send(ep)) { udd_disable_in_send_interrupt(ep); // One bank is free then send a ZLP udd_ack_in_send(ep); udd_ack_fifocon(ep); udd_ep_finish_job(ptr_job, false, ep); return true; } if (Is_udd_bank_interrupt_enabled(ep) && (0 == udd_nb_busy_bank(ep))) { // End of background transfer on IN endpoint udd_disable_bank_interrupt(ep); udd_disable_endpoint_interrupt(ep); Assert(ptr_job->stall_requested); // A stall has been requested during background transfer ptr_job->stall_requested = false; udd_disable_endpoint_bank_autoswitch(ep); udd_enable_stall_handshake(ep); udd_reset_data_toggle(ep); return true; } } }
static bool udd_ep_interrupt(void) { udd_ep_id_t ep; udd_ep_job_t *ptr_job; // For each endpoint different of control endpoint (0) for (ep = 1; ep <= USB_DEVICE_MAX_EP; ep++) { // Check DMA event if (Is_udd_endpoint_dma_interrupt_enabled(ep) && Is_udd_endpoint_dma_interrupt(ep)) { uint32_t nb_remaining; udd_disable_endpoint_dma_interrupt(ep); // Save number of data no transfered nb_remaining = (udd_endpoint_dma_get_status(ep) & AVR32_USBB_UDDMA1_STATUS_CH_BYTE_CNT_MASK) >> AVR32_USBB_UDDMA1_STATUS_CH_BYTE_CNT_OFFSET; // Get job corresponding at endpoint ptr_job = &udd_ep_job[ep - 1]; // Update number of data transfered ptr_job->buf_size -= nb_remaining; if (!Is_udd_endpoint_in(ep)) { // Disable autoswitch bank on OUT udd_disable_endpoint_bank_autoswitch(ep); } else { // Wait end of background transfer on IN endpoint before disabled autoswitch bank udd_enable_endpoint_interrupt(ep); udd_enable_bank_interrupt(ep); } // Call callback to signal end of transfer udd_ep_finish_job(&udd_ep_job[ep - 1], false); return true; } // Check empty bank interrupt event if (Is_udd_endpoint_interrupt_enabled(ep) && (0 == udd_nb_busy_bank(ep))) { // End of background transfer on IN endpoint udd_disable_bank_interrupt(ep); udd_disable_endpoint_interrupt(ep); // If no new transfer running then disable autoswitch bank if (!udd_ep_job[ep - 1].busy) { udd_disable_endpoint_bank_autoswitch(ep); } // If a stall has been requested during backgound transfer then execute it if (udd_ep_job[ep - 1].stall_requested) { udd_ep_job[ep - 1].stall_requested = false; udd_enable_stall_handshake(ep); udd_reset_data_toggle(ep); } return true; } }
bool udd_ep_set_halt(udd_ep_id_t ep) { uint8_t index = ep & USB_EP_ADDR_MASK; if (USB_DEVICE_MAX_EP < index) return false; // Stall endpoint udd_enable_stall_handshake(index); udd_reset_data_toggle(index); udd_ep_abort(ep); return true; }
static void udd_ctrl_overflow(void) { if (Is_udd_in_send(0)) return; // overflow ignored if IN data is received // The case of UDD_EPCTRL_DATA_IN is not managed // because the OUT endpoint is already free and OUT ZLP accepted if (UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) { // A IN handshake is waiting by device, // but host want extra OUT data then stall extra OUT data udd_enable_stall_handshake(0); } }
static void udd_ctrl_underflow(void) { if (Is_udd_out_received(0)) return; // underflow ignored if OUT data is received if (UDD_EPCTRL_DATA_OUT == udd_ep_control_state) { // Host want to stop OUT transaction // then stop to wait OUT data phase and wait IN ZLP handshake udd_ctrl_send_zlp_in(); } else if (UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP == udd_ep_control_state) { // A OUT handshake is waiting by device, // but host want extra IN data then stall extra IN data udd_enable_stall_handshake(0); } }
bool udd_ep_set_halt(udd_ep_id_t ep) { uint8_t index = ep & USB_EP_ADDR_MASK; if (USB_DEVICE_MAX_EP < index) return false; if (Is_udd_bank_interrupt_enabled(index)) { // Wait end of transfer (= no busy bank) before stall endpoint udd_ep_job[index - 1].stall_requested = true; } else { // Stall endpoint udd_enable_stall_handshake(index); udd_reset_data_toggle(index); } udd_ep_abort_job(ep); return true; }
static void udd_ctrl_stall_data(void) { // Stall all packets on IN & OUT control endpoint udd_ep_control_state = UDD_EPCTRL_STALL_REQ; udd_enable_stall_handshake(0); }
//! \brief Enables the control endpoint STALL after a SETUP packet reception static void main_usb_stall_after_setup_packet(void) { udd_enable_stall_handshake(0); udd_ack_setup_received(0); }
static bool udd_ep_interrupt(void) { udd_ep_id_t ep; udd_ep_job_t *ptr_job; // For each endpoint different of control endpoint (0) for (ep = 1; ep <= USB_DEVICE_MAX_EP; ep++) { // Check RXRDY and TXEMPTY event for none DMA endpoints if (!Is_udd_endpoint_interrupt_enabled(ep)) { continue; } // Get job corresponding at endpoint ptr_job = &udd_ep_job[ep - 1]; // RXOUT: Full packet received if (Is_udd_any_bank_received(ep)) { udd_ep_out_received(ep); return true; } // TXIN: packet sent if (Is_udd_in_sent(ep)) { ptr_job->bank--; // Stall when all banks free if (ptr_job->b_stall_requested) { if (ptr_job->bank) { // Send remaining udd_set_transmit_ready(ep); udd_ack_in_sent(ep); } else { // Ack last packet udd_ack_in_sent(ep); // Enable stall udd_enable_stall_handshake(ep); // Halt executed ptr_job->b_stall_requested = false; } return true; } // Finish Job when buffer end if (ptr_job->b_buf_end) { ptr_job->b_buf_end = false; ptr_job->buf_size = ptr_job->buf_cnt; // buf_size is passed to callback as XFR count udd_ep_finish_job(ptr_job, UDD_EP_TRANSFER_OK, ep); } if (ptr_job->buf_cnt >= ptr_job->buf_size && !ptr_job->b_shortpacket && ptr_job->bank == 0) { // All transfer done, including ZLP irqflags_t flags = cpu_irq_save(); udd_disable_endpoint_interrupt(ep); cpu_irq_restore(flags); // Ack last packet udd_ack_in_sent(ep); return true; } else if (udd_get_endpoint_bank_max_nbr(ep) > 1 && ptr_job->bank > 0) { // Already banks buffered, transmit while loading udd_set_transmit_ready(ep); udd_ack_in_sent(ep); udd_ep_in_sent(ep, false); } else if (udd_get_endpoint_bank_max_nbr(ep) > 1) { // Still bank free, load and transmit if (!udd_ep_in_sent(ep, true)) { ptr_job->b_buf_end = false; ptr_job->buf_size = ptr_job->buf_cnt; // buf_size is passed to callback as XFR count udd_ep_finish_job(ptr_job, UDD_EP_TRANSFER_OK, ep); } udd_ack_in_sent(ep); udd_ep_in_sent(ep, false); } else { // Single bank transfer, ack when ready udd_ep_in_sent(ep, true); udd_ack_in_sent(ep); } return true; } // Stall sent/CRC error if (Is_udd_stall(ep)) { udd_ack_stall(ep); if (udd_get_endpoint_type(ep) == UDP_CSR_EPTYPE_ISO_OUT || udd_get_endpoint_type(ep) == UDP_CSR_EPTYPE_ISO_IN) { } return true; } } return false; }