static void udd_ctrl_setup_received(void) { irqflags_t flags; if (UDD_EPCTRL_SETUP != udd_ep_control_state) { // May be a hidden DATA or ZLP phase // or protocol abort udd_ctrl_endofrequest(); // Reinitializes control endpoint management udd_ctrl_init(); } // Fill setup request structure if (8 != udd_udesc_get_buf0_ctn(0)) { udd_ctrl_stall_data(); udd_ack_setup_received(0); return; // Error data number doesn't correspond to SETUP packet } memcpy((uint8_t *) & udd_g_ctrlreq.req, udd_ctrl_buffer, 8); // Manage LSB/MSB to fit with CPU usage udd_g_ctrlreq.req.wValue = le16_to_cpu(udd_g_ctrlreq.req.wValue); udd_g_ctrlreq.req.wIndex = le16_to_cpu(udd_g_ctrlreq.req.wIndex); udd_g_ctrlreq.req.wLength = le16_to_cpu(udd_g_ctrlreq.req.wLength); // Decode setup request if (udc_process_setup() == false) { // Setup request unknown then stall it udd_ctrl_stall_data(); udd_ack_setup_received(0); return; } udd_ack_setup_received(0); if (Udd_setup_is_in()) { // IN data phase requested udd_ctrl_prev_payload_nb_trans = 0; udd_ctrl_payload_nb_trans = 0; udd_ep_control_state = UDD_EPCTRL_DATA_IN; udd_ctrl_in_sent(); // Send first data transfer } else { if (0 == udd_g_ctrlreq.req.wLength) { // No data phase requested // Send IN ZLP to ACK setup request udd_ctrl_send_zlp_in(); return; } // OUT data phase requested udd_ctrl_prev_payload_nb_trans = 0; udd_ctrl_payload_nb_trans = 0; udd_ep_control_state = UDD_EPCTRL_DATA_OUT; // To detect a protocol error, enable nak interrupt on data IN phase udd_ack_nak_in(0); flags = cpu_irq_save(); udd_enable_nak_in_interrupt(0); cpu_irq_restore(flags); } }
static void udd_ctrl_setup_received(void) { uint8_t i; if (UDD_EPCTRL_SETUP != udd_ep_control_state) { // May be a hidden DATA or ZLP phase // or protocol abort udd_ctrl_endofrequest(); // Reinitializes control endpoint management udd_ctrl_init(); } // Fill setup request structure if (8 != udd_byte_count(0)) { udd_ack_setup_received(0); udd_ctrl_stall_data(); return; // Error data number doesn't correspond to SETUP packet } for (i = 0; i < 8; i++) { ((uint8_t *) & udd_g_ctrlreq.req)[i] = udd_endpoint_fifo_read(0); } // Manage LSB/MSB to fit with CPU usage udd_g_ctrlreq.req.wValue = le16_to_cpu(udd_g_ctrlreq.req.wValue); udd_g_ctrlreq.req.wIndex = le16_to_cpu(udd_g_ctrlreq.req.wIndex); udd_g_ctrlreq.req.wLength = le16_to_cpu(udd_g_ctrlreq.req.wLength); // Decode setup request if (udc_process_setup() == false) { // Setup request unknown then stall it udd_ack_setup_received(0); udd_ctrl_stall_data(); return; } if (Udd_setup_is_in()) { // Set DIR udd_set_endpoint_direction_in(0); udd_ack_setup_received(0); // IN data phase requested udd_ctrl_prev_payload_nb_trans = 0; udd_ctrl_payload_nb_trans = 0; udd_ep_control_state = UDD_EPCTRL_DATA_IN; udd_ctrl_in_sent(); // Send first data transfer } else { udd_ack_setup_received(0); if (0 == udd_g_ctrlreq.req.wLength) { // No data phase requested // Send IN ZLP to ACK setup request udd_ctrl_send_zlp_in(); return; } // OUT data phase requested udd_ctrl_prev_payload_nb_trans = 0; udd_ctrl_payload_nb_trans = 0; udd_ep_control_state = UDD_EPCTRL_DATA_OUT; } }
void udd_attach(void) { irqflags_t flags; flags = cpu_irq_save(); // At startup the USB bus state is unknown, // therefore the state is considered IDLE to not miss any USB event udd_sleep_mode(true); otg_unfreeze_clock(); // This section of clock check can be improved with a chek of // USB clock source via sysclk() #if UC3A3 // For parts with high speed feature, the "USABLE" clock is the UTMI clock, // and the UTMI clock is disabled in suspend mode. Thereby, the utmi clock // can't be checked when USB line is not attached or in suspend mode // But it is not a issue, because the clock source is the OSC #else // Check USB clock because the source can be a PLL while( !Is_clock_usable() ); #endif // Authorize attach if VBus is present udd_attach_device(); // (RESET_AND_WAKEUP) // After the attach and the first USB suspend, the following USB Reset time can be inferior to CPU restart clock time. // Thus, the USB Reset state is not detected and endpoint control is not allocated // In this case, a Reset is do automatically after attach. udc_reset(); // Reset USB Device Stack Core udd_reset_ep_ctrl(); // Reset endpoint control udd_ctrl_init(); // Reset endpoint control management // Enable USB line events udd_enable_reset_interrupt(); udd_enable_suspend_interrupt(); udd_enable_wake_up_interrupt(); #ifdef UDC_SOF_EVENT udd_enable_sof_interrupt(); #endif // Reset following interupts flag udd_ack_reset(); udd_ack_sof(); // The first suspend interrupt must be forced #if UC3A3 // With UTMI, the first suspend is detected but must be cleared to reoccur interrupt udd_ack_suspend(); #else // The first suspend interrupt is not detected else raise it udd_raise_suspend(); #endif udd_ack_wake_up(); otg_freeze_clock(); cpu_irq_restore(flags); }
static void udd_ctrl_in_sent(void) { static bool b_shortpacket = false; uint16_t nb_remain; if (UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) { // 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) { // Update number of total data sending by previous playload 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(); 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 // nb_remain == 0 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 an 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; } udd_control_in_set_bytecnt(nb_remain); // Link payload buffer directly on USB hardware udd_control_in_set_buf(udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans); udd_ctrl_payload_nb_trans += nb_remain; // Valid and sent the data available in control endpoint buffer udd_control_in_clear_NACK0(); }
static void udd_ctrl_setup_received(void) { if (UDD_EPCTRL_SETUP != udd_ep_control_state) { if ((UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) || (UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP == udd_ep_control_state)) { // Accept that ZLP event can be hidden by setup packet event // in case of setup packet sending quickly after a ZLP udd_ctrl_endofrequest(); } // Reinitializes control endpoint management udd_ctrl_init(); } // Fill setup request structure if (8 != udd_control_out_get_bytecnt()) return; // Error data number don't correspond to SETUP packet memcpy((uint8_t *) & udd_g_ctrlreq.req, udd_ctrl_buffer, 8); // To detect a protocol error on setup, enable nak interrupt on IN/OUT of control endpoint udd_enable_overflow_interrupt(); udd_enable_underflow_interrupt(); // Decode setup request if (udc_process_setup() == false) { // Setup request unknown then stall it udd_ctrl_stall_data(); return; } if (Udd_setup_is_in()) { udd_ctrl_prev_payload_nb_trans = 0; udd_ctrl_payload_nb_trans = 0; udd_ep_control_state = UDD_EPCTRL_DATA_IN; udd_ctrl_in_sent(); // Send first data transfer } else { if (0 == udd_g_ctrlreq.req.wLength) { // No data phase requested // Send IN ZLP to ACK setup request udd_ctrl_send_zlp_in(); return; } // OUT data phase requested udd_ctrl_prev_payload_nb_trans = 0; udd_ctrl_payload_nb_trans = 0; udd_ep_control_state = UDD_EPCTRL_DATA_OUT; // Clear packet to receive first packet udd_control_out_clear_NACK0(); udd_control_out_ack_tc(); } }
ISR(udd_interrupt, AVR32_USBB_IRQ_GROUP, UDD_USB_INT_LEVEL) # endif #endif { if (Is_udd_sof()) { udd_ack_sof(); if (Is_udd_full_speed_mode()) { udc_sof_notify(); } #ifdef UDC_SOF_EVENT UDC_SOF_EVENT(); #endif goto udd_interrupt_end; } if (Is_udd_msof()) { udd_ack_msof(); udc_sof_notify(); goto udd_interrupt_end; } if (udd_ctrl_interrupt()) goto udd_interrupt_end; // Interrupt acked by control endpoint managed #if (0 != USB_DEVICE_MAX_EP) if (udd_ep_interrupt()) goto udd_interrupt_end; // Interrupt acked by bulk/interrupt/isochronous endpoint managed #endif // USB bus reset detection if (Is_udd_reset()) { udd_ack_reset(); // Abort all jobs on-going #if (USB_DEVICE_MAX_EP != 0) udd_ep_job_table_kill(); #endif // Reset USB Device Stack Core udc_reset(); // Reset endpoint control udd_reset_ep_ctrl(); // Reset endpoint control management udd_ctrl_init(); goto udd_interrupt_end; } if (Is_udd_suspend_interrupt_enabled() && Is_udd_suspend()) { otg_unfreeze_clock(); // The suspend interrupt is automatic acked when a wakeup occur udd_disable_suspend_interrupt(); udd_enable_wake_up_interrupt(); otg_freeze_clock(); // Mandatory to exit of sleep mode after a wakeup event udd_sleep_mode(false); // Enter in SUSPEND mode #ifdef UDC_SUSPEND_EVENT UDC_SUSPEND_EVENT(); #endif goto udd_interrupt_end; } if (Is_udd_wake_up_interrupt_enabled() && Is_udd_wake_up()) { // Ack wakeup interrupt and enable suspend interrupt otg_unfreeze_clock(); // Check USB clock ready after suspend and eventually sleep USB clock while( !Is_otg_clock_usable() ); // The wakeup interrupt is automatic acked when a suspend occur udd_disable_wake_up_interrupt(); udd_enable_suspend_interrupt(); udd_sleep_mode(true); // Enter in IDLE mode #ifdef UDC_RESUME_EVENT UDC_RESUME_EVENT(); #endif goto udd_interrupt_end; } if (Is_otg_vbus_transition()) { // Ack Vbus transition and send status to high level otg_unfreeze_clock(); otg_ack_vbus_transition(); otg_freeze_clock(); #ifndef USB_DEVICE_ATTACH_AUTO_DISABLE if (Is_otg_vbus_high()) { udd_attach(); } else { udd_detach(); } #endif #ifdef UDC_VBUS_EVENT UDC_VBUS_EVENT(Is_otg_vbus_high()); #endif goto udd_interrupt_end; } udd_interrupt_end: otg_data_memory_barrier(); #if (defined FREERTOS_USED) // Since we do not know if the user callbacks have used or not FreeRTOS APIs, let's // consider that exiting from the USB interrupt will require a context switch. return pdTRUE; #else return; #endif }
static void udd_ctrl_out_received(void) { irqflags_t flags; uint8_t i; uint16_t nb_data; if (UDD_EPCTRL_DATA_OUT != udd_ep_control_state) { if ((UDD_EPCTRL_DATA_IN == udd_ep_control_state) || (UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP == udd_ep_control_state)) { // End of SETUP request: // - Data IN Phase aborted, // - or last Data IN Phase hidden by ZLP OUT sending quickly, // - or ZLP OUT received normally. udd_ctrl_endofrequest(); } else { // Protocol error during SETUP request udd_ctrl_stall_data(); } // Reinitializes control endpoint management udd_ctrl_init(); return; } // Read data received during OUT phase nb_data = udd_byte_count(0); if (udd_g_ctrlreq.payload_size < (udd_ctrl_payload_nb_trans + nb_data)) { // Payload buffer too small nb_data = udd_g_ctrlreq.payload_size - udd_ctrl_payload_nb_trans; } uint8_t *ptr_src = (uint8_t *) & udd_get_endpoint_fifo_access(0, 8); uint8_t *ptr_dest = udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans; for (i = 0; i < nb_data; i++) { *ptr_dest++ = *ptr_src++; } udd_ctrl_payload_nb_trans += nb_data; if ((USB_DEVICE_EP_CTRL_SIZE != nb_data) || (udd_g_ctrlreq.req.wLength <= (udd_ctrl_prev_payload_nb_trans + udd_ctrl_payload_nb_trans))) { // End of reception because it is a short packet // Before send ZLP, call intermediate callback // in case of data receive generate a stall udd_g_ctrlreq.payload_size = udd_ctrl_payload_nb_trans; if (NULL != udd_g_ctrlreq.over_under_run) { if (!udd_g_ctrlreq.over_under_run()) { // Stall ZLP udd_ctrl_stall_data(); // Ack reception of OUT to replace NAK by a STALL udd_ack_out_received(0); return; } } // Send IN ZLP to ACK setup request udd_ack_out_received(0); udd_ctrl_send_zlp_in(); return; } if (udd_g_ctrlreq.payload_size == udd_ctrl_payload_nb_trans) { // Overrun then request a new payload buffer if (!udd_g_ctrlreq.over_under_run) { // No callback available to request a new payload buffer udd_ctrl_stall_data(); // Ack reception of OUT to replace NAK by a STALL udd_ack_out_received(0); return; } if (!udd_g_ctrlreq.over_under_run()) { // No new payload buffer delivered udd_ctrl_stall_data(); // Ack reception of OUT to replace NAK by a STALL udd_ack_out_received(0); return; } // New payload buffer available // Update number of total data received udd_ctrl_prev_payload_nb_trans += udd_ctrl_payload_nb_trans; // Reinit reception on payload buffer udd_ctrl_payload_nb_trans = 0; } // Free buffer of control endpoint to authorize next reception udd_ack_out_received(0); // To detect a protocol error, enable nak interrupt on data IN phase udd_ack_nak_in(0); flags = cpu_irq_save(); udd_enable_nak_in_interrupt(0); cpu_irq_restore(flags); }
static void udd_ctrl_in_sent(void) { static bool b_shortpacket = false; uint16_t nb_remain; uint8_t i; uint8_t *ptr_dest, *ptr_src; irqflags_t flags; flags = cpu_irq_save(); udd_disable_in_send_interrupt(0); cpu_irq_restore(flags); if (UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) { // 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(); 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_dest = (uint8_t *) & udd_get_endpoint_fifo_access(0, 8); 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_out_received(0)) { // IN DATA phase aborted by OUT ZLP cpu_irq_restore(flags); udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP; return; // Exit of IN DATA phase } // Write quickly the IN data for (i = 0; i < nb_remain; i++) { *ptr_dest++ = *ptr_src++; } udd_ctrl_payload_nb_trans += nb_remain; // Validate and send the data available in the control endpoint buffer udd_ack_in_send(0); udd_enable_in_send_interrupt(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); }
ISR(udd_interrupt, AVR32_USBB_IRQ_GROUP, UDD_USB_INT_LEVEL) #endif { #ifdef UDC_SOF_EVENT if (Is_udd_sof()) { udd_ack_sof(); UDC_SOF_EVENT(); goto udd_interrupt_end; } #endif if (udd_ctrl_interrupt()) goto udd_interrupt_end; // Interrupt acked by control endpoint managed #if (0!=USB_DEVICE_MAX_EP) if (udd_ep_interrupt()) goto udd_interrupt_end; // Interrupt acked by bulk/interrupt/isochronous endpoint managed #endif // USB bus reset detection if (Is_udd_reset()) { udd_ack_reset(); // Abort all jobs on-going #if (0!=USB_DEVICE_MAX_EP) udd_ep_job_table_kill(); #endif // Reset USB Device Stack Core udc_reset(); // Reset endpoint control udd_reset_ep_ctrl(); // Reset endpoint control management udd_ctrl_init(); goto udd_interrupt_end; } if (Is_udd_suspend_interrupt_enabled() && Is_udd_suspend()) { otg_unfreeze_clock(); // The suspend interrupt is automatic acked when a wakeup occur udd_disable_suspend_interrupt(); udd_enable_wake_up_interrupt(); otg_freeze_clock(); // Mandatory to exit of sleep mode after a wakeup event udd_sleep_mode(false); // Enter in SUSPEND mode #ifdef UDC_SUSPEND_EVENT UDC_SUSPEND_EVENT(); #endif goto udd_interrupt_end; } if (Is_udd_wake_up_interrupt_enabled() && Is_udd_wake_up()) { // Ack wakeup interrupt and enable suspend interrupt otg_unfreeze_clock(); // Check USB clock ready after suspend and eventually sleep USB clock while( !Is_clock_usable() ) { if(Is_udd_suspend()) break; // In case of USB state change in HS }; // The wakeup interrupt is automatic acked when a suspend occur udd_disable_wake_up_interrupt(); udd_enable_suspend_interrupt(); udd_sleep_mode(true); // Enter in IDLE mode #ifdef UDC_RESUME_EVENT UDC_RESUME_EVENT(); #endif goto udd_interrupt_end; } if (Is_udd_vbus_transition()) { // Ack VBus transition and send status to high level otg_unfreeze_clock(); udd_ack_vbus_transition(); otg_freeze_clock(); #ifdef UDC_VBUS_EVENT UDC_VBUS_EVENT(Is_udd_vbus_high()); #endif goto udd_interrupt_end; } udd_interrupt_end: otg_data_memory_barrier(); return; }
static void udd_ctrl_setup_received(void) { irqflags_t flags; uint8_t i; if (UDD_EPCTRL_SETUP != udd_ep_control_state) { // May be a hidden DATA or ZLP phase // or protocol abort udd_ctrl_endofrequest(); // Reinitializes control endpoint management udd_ctrl_init(); } // Fill setup request structure if (8 != udd_byte_count(0)) { udd_ctrl_stall_data(); udd_ack_setup_received(0); return; // Error data number doesn't correspond to SETUP packet } uint32_t *ptr = (uint32_t *) & udd_get_endpoint_fifo_access(0, 32); for (i = 0; i < 8 / 4; i++) { ((uint32_t *) & udd_g_ctrlreq.req)[i] = *ptr++; } // Manage LSB/MSB to fit with CPU usage udd_g_ctrlreq.req.wValue = le16_to_cpu(udd_g_ctrlreq.req.wValue); udd_g_ctrlreq.req.wIndex = le16_to_cpu(udd_g_ctrlreq.req.wIndex); udd_g_ctrlreq.req.wLength = le16_to_cpu(udd_g_ctrlreq.req.wLength); // Decode setup request if (udc_process_setup() == false) { // Setup request unknow then stall it udd_ctrl_stall_data(); udd_ack_setup_received(0); return; } udd_ack_setup_received(0); if (Udd_setup_is_in()) { // Compute if an IN ZLP must be send after IN data udd_ctrl_payload_need_in_zlp = ((udd_g_ctrlreq.payload_size % USB_DEVICE_EP_CTRL_SIZE) == 0); // IN data phase requested udd_ctrl_prev_payload_nb_trans = 0; udd_ctrl_payload_nb_trans = 0; udd_ep_control_state = UDD_EPCTRL_DATA_IN; udd_ctrl_in_sent(); // Send first data transfer } else { if (0 == udd_g_ctrlreq.req.wLength) { // No data phase requested // Send IN ZLP to ACK setup request udd_ctrl_send_zlp_in(); return; } // OUT data phase requested udd_ctrl_prev_payload_nb_trans = 0; udd_ctrl_payload_nb_trans = 0; udd_ep_control_state = UDD_EPCTRL_DATA_OUT; // To detect a protocol error, enable nak interrupt on data IN phase udd_ack_nak_in(0); flags = cpu_irq_save(); udd_enable_nak_in_interrupt(0); cpu_irq_restore(flags); } }
static void udd_ctrl_out_received(void) { uint16_t nb_data; if (UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP == udd_ep_control_state) { // Valid end of setup request udd_ctrl_endofrequest(); // Reinitializes control endpoint management udd_ctrl_init(); return; } Assert(udd_ep_control_state == UDD_EPCTRL_DATA_OUT); // Read data received during OUT phase nb_data = udd_control_out_get_bytecnt(); if (udd_g_ctrlreq.payload_size < (udd_ctrl_payload_nb_trans + nb_data)) { // Payload buffer too small, ignore data remaining nb_data = udd_g_ctrlreq.payload_size - udd_ctrl_payload_nb_trans; } memcpy((uint8_t *) (udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans), udd_ctrl_buffer, nb_data); udd_ctrl_payload_nb_trans += nb_data; if ((USB_DEVICE_EP_CTRL_SIZE != nb_data) || (udd_g_ctrlreq.req.wLength <= (udd_ctrl_prev_payload_nb_trans + udd_ctrl_payload_nb_trans))) { // End of reception because it is a short packet // or all data are transfered // Before send ZLP, call intermediate callback // in case of data receive generate a stall udd_g_ctrlreq.payload_size = udd_ctrl_payload_nb_trans; if (NULL != udd_g_ctrlreq.over_under_run) { if (!udd_g_ctrlreq.over_under_run()) { // Stall ZLP udd_ctrl_stall_data(); return; } } // Send IN ZLP to ACK setup request udd_ctrl_send_zlp_in(); return; } if (udd_g_ctrlreq.payload_size == udd_ctrl_payload_nb_trans) { // Overrun then request a new payload buffer if (!udd_g_ctrlreq.over_under_run) { // No callback available to request a new payload buffer udd_ctrl_stall_data(); return; } if (!udd_g_ctrlreq.over_under_run()) { // No new payload buffer delivered udd_ctrl_stall_data(); return; } // New payload buffer available // Update number of total data received udd_ctrl_prev_payload_nb_trans += udd_ctrl_payload_nb_trans; // Reinit reception on payload buffer udd_ctrl_payload_nb_trans = 0; } // Free buffer of OUT control endpoint to authorize next reception udd_control_out_clear_NACK0(); }
static void udd_ctrl_in_sent(void) { uint16_t nb_remain; irqflags_t flags; flags = cpu_irq_save(); udd_disable_in_send_interrupt(0); cpu_irq_restore(flags); if (UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) { // 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 if (!udd_ctrl_payload_need_in_zlp) { // It is the end of data phase, because the last data packet is a short packet // then generate an OUT ZLP for handshake phase. udd_ctrl_send_zlp_out(); return; } if ((udd_g_ctrlreq.req.wLength > (udd_ctrl_prev_payload_nb_trans + udd_g_ctrlreq. payload_size)) || (!udd_g_ctrlreq.over_under_run) || (!udd_g_ctrlreq.over_under_run())) { // Underrun or data packet complette than send zlp on IN (note don't change DataToggle) udd_ctrl_payload_need_in_zlp = false; // nb_remain==0 allows to send a IN ZLP } else { // A new payload buffer is given // Update number of total data sending by previous playlaod buffer udd_ctrl_prev_payload_nb_trans += udd_ctrl_payload_nb_trans; // Update maangement of current playoad transfer udd_ctrl_payload_nb_trans = 0; nb_remain = udd_g_ctrlreq.payload_size; // Compute if an IN ZLP must be send after IN data udd_ctrl_payload_need_in_zlp = ((udd_g_ctrlreq.payload_size % USB_DEVICE_EP_CTRL_SIZE) == 0); } } // Continue transfer and send next data if (nb_remain > USB_DEVICE_EP_CTRL_SIZE) { nb_remain = USB_DEVICE_EP_CTRL_SIZE; } //** Critical section // Only in case of DATA IN phase abort without USB Reset signal after. // The IN data don't must be writed 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 recevied the data must be written quickly (800us) // before an eventually ZLP OUT and SETUP reception flags = cpu_irq_save(); if (Is_udd_out_received(0)) { // IN DATA phase aborted by OUT ZLP cpu_irq_restore(flags); udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP; return; // Exit of IN DATA phase } // Write quickly the IN data memcpy(udd_ctrl_buffer, udd_g_ctrlreq.payload + udd_ctrl_payload_nb_trans, nb_remain); udd_ctrl_payload_nb_trans += nb_remain; udd_udesc_set_buf0_ctn(0, nb_remain); // Validate and send the data available in the control endpoint buffer udd_ack_in_send(0); udd_enable_in_send_interrupt(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); }