static bool udd_ctrl_interrupt(void) { if (!Is_udd_endpoint_interrupt(0)) return false; // No interrupt events on control endpoint // Search event on control endpoint if (Is_udd_setup_received(0)) { // SETUP packet received udd_ctrl_setup_received(); return true; } if (Is_udd_in_sent(0)) { // IN packet sent udd_ctrl_in_sent(); return true; } if (Is_udd_bank0_received(0)) { // OUT packet received udd_ctrl_out_received(); return true; } if (Is_udd_stall(0)) { // STALLed udd_ack_stall(0); return true; } return false; }
static void udd_ep_ack_out_received(udd_ep_id_t ep) { bool bank0_received, bank1_received; udd_ep_job_t *ptr_job = &udd_ep_job[ep - 1]; bank0_received = Is_udd_bank0_received(ep); bank1_received = Is_udd_bank1_received(ep); if (bank0_received && bank1_received) { // The only way is to use ptr_job->bank } else if (bank0_received) { // Must be bank0 ptr_job->bank = 0; } else { // Must be bank1 ptr_job->bank = 1; } if (ptr_job->bank == 0) { udd_ack_bank0_received(ep); if (udd_get_endpoint_bank_max_nbr(ep) > 1) { ptr_job->bank = 1; } } else { udd_ack_bank1_received(ep); ptr_job->bank = 0; } }
static void udd_ctrl_in_sent(void) { static bool b_shortpacket = false; uint16_t nb_remain; uint8_t i; uint8_t *ptr_src; irqflags_t flags; if (UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) { // Ack udd_ack_in_sent(0); // ZLP on IN is sent, then valid end of setup request udd_ctrl_endofrequest(); // Reinitializes control endpoint management udd_ctrl_init(); return; } Assert(udd_ep_control_state == UDD_EPCTRL_DATA_IN); nb_remain = udd_g_ctrlreq.payload_size - udd_ctrl_payload_nb_trans; if (0 == nb_remain) { // All content of current buffer payload are sent // Update number of total data sending by previous payload buffer udd_ctrl_prev_payload_nb_trans += udd_ctrl_payload_nb_trans; if ((udd_g_ctrlreq.req.wLength == udd_ctrl_prev_payload_nb_trans) || b_shortpacket) { // All data requested are transfered or a short packet has been sent // then it is the end of data phase. // Generate an OUT ZLP for handshake phase. udd_ctrl_send_zlp_out(); udd_ack_in_sent(0); return; } // Need of new buffer because the data phase is not complete if ((!udd_g_ctrlreq.over_under_run) || (!udd_g_ctrlreq.over_under_run())) { // Underrun then send zlp on IN // Here nb_remain=0 and allows to send a IN ZLP } else { // A new payload buffer is given udd_ctrl_payload_nb_trans = 0; nb_remain = udd_g_ctrlreq.payload_size; } } // Continue transfer and send next data if (nb_remain >= USB_DEVICE_EP_CTRL_SIZE) { nb_remain = USB_DEVICE_EP_CTRL_SIZE; b_shortpacket = false; } else { b_shortpacket = true; } // Fill buffer of endpoint control ptr_src = udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans; //** Critical section // Only in case of DATA IN phase abort without USB Reset signal after. // The IN data don't must be written in endpoint 0 DPRAM during // a next setup reception in same endpoint 0 DPRAM. // Thereby, an OUT ZLP reception must check before IN data write // and if no OUT ZLP is received the data must be written quickly (800us) // before an eventually ZLP OUT and SETUP reception flags = cpu_irq_save(); if (Is_udd_bank0_received(0)) { // IN DATA phase aborted by OUT ZLP cpu_irq_restore(flags); udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP; udd_ack_in_sent(0); return; // Exit of IN DATA phase } // Write quickly the IN data for (i = 0; i < nb_remain; i++) { udd_endpoint_fifo_write(0, *ptr_src++); } udd_ctrl_payload_nb_trans += nb_remain; // Validate and send the data available in the control endpoint buffer udd_set_transmit_ready(0); udd_ack_in_sent(0); // In case of abort of DATA IN phase, no need to enable nak OUT interrupt // because OUT endpoint is already free and ZLP OUT accepted. cpu_irq_restore(flags); }