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 } uint8_t *ptr = (uint8_t *) & udd_get_endpoint_fifo_access(0,8); for (i = 0; i < 8; i++) { ((uint8_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 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_buf_cnt = 0; udd_ctrl_payload_buf_cnt = 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_buf_cnt = 0; udd_ctrl_payload_buf_cnt = 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); } }
//! \brief Waits a SETUP packet and load data in main_setup_packet[] static void main_usb_wait_setup_packet(void) { while (!Is_udd_setup_received(0)); // SETUP packet received Assert(8 == udd_byte_count(0)); uint8_t *ptr = (uint8_t *) & udd_get_endpoint_fifo_access(0,8); for (uint8_t i = 0; i < 8; i++) { ((uint8_t*) &main_setup_packet)[i] = *ptr++; } udd_ack_setup_received(0); }
void udd_test_mode_packet(void) { uint8_t i; uint8_t *ptr_dest; const uint8_t *ptr_src; irqflags_t flags; const uint8_t test_packet[] = { // 00000000 * 9 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 01010101 * 8 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, // 01110111 * 8 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, // 0, {111111S * 15}, 111111 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // S, 111111S, {0111111S * 7} 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, // 00111111, {S0111111 * 9}, S0 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E }; // Reconfigure control endpoint to bulk IN endpoint udd_disable_endpoint(0); udd_configure_endpoint(0, USB_EP_TYPE_BULK, 1, 64, AVR32_USBB_UECFG0_EPBK_SINGLE); udd_allocate_memory(0); udd_enable_endpoint(0); udd_enable_hs_test_mode(); udd_enable_hs_test_mode_packet(); // Send packet on endpoint 0 ptr_dest = (uint8_t *) & udd_get_endpoint_fifo_access(0, 8); ptr_src = test_packet; for (i = 0; i < sizeof(test_packet); i++) { *ptr_dest++ = *ptr_src++; } flags = cpu_irq_save(); udd_enable_in_send_interrupt(0); cpu_irq_restore(flags); udd_ack_in_send(0); }
/** * \brief Sends a DATA OUT packets on control endpoint * * \param payload Data buffer to send * \param size Size of buffer */ static void main_usb_wait_out(uint8_t *payload, uint8_t size) { uint8_t nb_data; do { while (!Is_udd_out_received(0)); // Read data received during OUT phase nb_data = udd_byte_count(0); uint8_t *ptr_src = (uint8_t *) & udd_get_endpoint_fifo_access(0, 8); for (uint8_t i = 0; (i < nb_data) && size; i++) { *payload++ = *ptr_src++; size--; } // Send IN ZLP to ACK setup request udd_ack_out_received(0); } while(size); }
/** * \brief Waits a DATA IN packets on control endpoint * * \param payload RAM buffer to store data received * \param size Size of RAM buffer waiting */ static void main_usb_send_in(uint8_t *payload, uint8_t size) { uint8_t *ptr_dest; do { while (!Is_udd_in_send(0)); // Fill buffer of endpoint control ptr_dest = (uint8_t *) & udd_get_endpoint_fifo_access(0, 8); // Write quickly the IN data for (uint8_t i = 0; (i<udd_get_endpoint_size(0)) && size; i++) { *ptr_dest++ = *payload++; size--; } // Validate and send the data available in the control endpoint buffer udd_ack_in_send(0); } while (size); while (!Is_udd_in_send(0)); }
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); }