Exemplo n.º 1
0
void udd_test_mode_packet(void)
{
	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_USBC_UECFG0_EPBK_SINGLE);

	udd_enable_hs_test_mode();
	udd_enable_hs_test_mode_packet();

	// Send packet on endpoint 0
	udd_udesc_set_buf0_addr(0, (uint8_t *) test_packet);
	flags = cpu_irq_save();
	udd_enable_in_send_interrupt(0);
	cpu_irq_restore(flags);

	udd_ack_in_send(0);
}
Exemplo n.º 2
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++) {
		// 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;
			}
		}
	}
Exemplo n.º 3
0
static void udd_ctrl_send_zlp_in(void)
{
	irqflags_t flags;

	udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP;
	// Validate and send empty IN packet on control endpoint
	flags = cpu_irq_save();
	// Send ZLP on IN endpoint
	udd_ack_in_send(0);
	udd_enable_in_send_interrupt(0);
	// To detect a protocol error, enable nak interrupt on data OUT phase
	udd_ack_nak_out(0);
	udd_enable_nak_out_interrupt(0);
	cpu_irq_restore(flags);
}
Exemplo n.º 4
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);
}
Exemplo n.º 5
0
/**
 * \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));
}
Exemplo n.º 6
0
static void udd_ep_trans_done(udd_ep_id_t ep)
{
	uint32_t udd_dma_ctrl = 0;
	udd_ep_job_t *ptr_job;
	iram_size_t next_trans;
	irqflags_t flags;

	// Get job corresponding at endpoint
	ptr_job = &udd_ep_job[ep - 1];

	if (!ptr_job->busy) {
		return; // No job is running, then ignore it (system error)
	}

	if (ptr_job->nb_trans != ptr_job->buf_size) {
		// Need to send or receive other data
		next_trans = ptr_job->buf_size - ptr_job->nb_trans;

		if (UDD_ENDPOINT_MAX_TRANS < next_trans) {
			// The USB hardware support a maximum
			// transfer size of UDD_ENDPOINT_MAX_TRANS Bytes
			next_trans = UDD_ENDPOINT_MAX_TRANS;

			// Set 0 to transfer the maximum
			udd_dma_ctrl = (0 <<
					AVR32_USBB_UDDMA1_CONTROL_CH_BYTE_LENGTH_OFFSET)
					& AVR32_USBB_UDDMA1_CONTROL_CH_BYTE_LENGTH_MASK;
		} else {
			udd_dma_ctrl = (next_trans <<
					AVR32_USBB_UDDMA1_CONTROL_CH_BYTE_LENGTH_OFFSET)
					& AVR32_USBB_UDDMA1_CONTROL_CH_BYTE_LENGTH_MASK;
		}
		if (Is_udd_endpoint_in(ep)) {
			if (0 != next_trans % udd_get_endpoint_size(ep)) {
				// Enable short packet option
				// else the DMA transfer is accepted
				// and interrupt DMA valid but nothing is sent.
				udd_dma_ctrl |= AVR32_USBB_UDDMA1_CONTROL_DMAEND_EN_MASK;
				// No need to request another ZLP
				ptr_job->b_shortpacket = false;
			}
		} else {
			if ((USB_EP_TYPE_ISOCHRONOUS != udd_get_endpoint_type(ep))
					|| (next_trans <= udd_get_endpoint_size(ep))) {

				// Enable short packet reception
				udd_dma_ctrl |= AVR32_USBB_UDDMA1_CONTROL_EOT_IRQ_EN_MASK
						| AVR32_USBB_UDDMA1_CONTROL_BUFF_CLOSE_IN_EN_MASK;
			}
		}

		// Start USB DMA to fill or read fifo of the selected endpoint
		udd_endpoint_dma_set_addr(ep, (U32) &ptr_job->buf[ptr_job->nb_trans]);
		udd_dma_ctrl |= AVR32_USBB_UDDMA1_CONTROL_EOBUFF_IRQ_EN_MASK |
				AVR32_USBB_UDDMA1_CONTROL_CH_EN_MASK;

		// Disable IRQs to have a short sequence
		// between read of EOT_STA and DMA enable
		flags = cpu_irq_save();
		if ( !(udd_endpoint_dma_get_status(ep)
				& AVR32_USBB_UDDMA1_STATUS_EOT_STA_MASK)) {
			udd_endpoint_dma_set_control(ep, udd_dma_ctrl);
			ptr_job->nb_trans += next_trans;
			udd_enable_endpoint_dma_interrupt(ep);
			cpu_irq_restore(flags);
			return;
		}
		cpu_irq_restore(flags);

		// Here a ZLP has been received
		// and the DMA transfer must be not started.
		// It is the end of transfer
		ptr_job->buf_size = ptr_job->nb_trans;
	}
	if (Is_udd_endpoint_in(ep)) {
		if (ptr_job->b_shortpacket) {
			// Need to send a ZLP (No possible with USB DMA)
			// enable interrupt to wait a free bank to sent ZLP
			udd_ack_in_send(ep);
			if (Is_udd_write_enabled(ep)) {
				// Force interrupt in case of ep already free
				udd_raise_in_send(ep);
			}
			udd_enable_in_send_interrupt(ep);
			udd_enable_endpoint_interrupt(ep);
			return;
		}
	}
	// Call callback to signal end of transfer
	udd_ep_finish_job(ptr_job, false, ep);
}
Exemplo n.º 7
0
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);
}
Exemplo n.º 8
0
static void udd_ep_trans_done(udd_ep_id_t ep)
{
	udd_ep_job_t *ptr_job;
	uint16_t ep_size, nb_trans;
	uint16_t next_trans;
	udd_ep_id_t ep_num;
	irqflags_t flags;

	ep_num = ep & USB_EP_ADDR_MASK;
	ep_size = udd_get_endpoint_size(ep_num);

	// Get job corresponding at endpoint
	ptr_job = &udd_ep_job[ep_num - 1];

	// Disable interrupt of endpoint
	flags = cpu_irq_save();
	udd_disable_endpoint_interrupt(ep_num);
	cpu_irq_restore(flags);

	if (!ptr_job->busy) {
		return; // No job is running, then ignore it (system error)
	}

	if (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)) {
		// Transfer complete on IN
		nb_trans = udd_udesc_get_buf0_size(ep_num);

		// Lock emission of new IN packet
		udd_enable_busy_bank0(ep_num);

		// Ack interrupt
		udd_ack_in_send(ep_num);

		if (0 == nb_trans) {
			if (0 == udd_nb_busy_bank(ep_num)) {
				// All byte are transfered than take nb byte requested
				nb_trans = udd_udesc_get_buf0_ctn(ep_num);
			}
		}
		// Update number of data transfered
		ptr_job->nb_trans += nb_trans;

		// Need to send other data
		if ((ptr_job->nb_trans != ptr_job->buf_size)
				|| ptr_job->b_shortpacket) {
			next_trans = ptr_job->buf_size - ptr_job->nb_trans;
			if (UDD_ENDPOINT_MAX_TRANS < next_trans) {
				// The USB hardware support a maximum
				// transfer size of UDD_ENDPOINT_MAX_TRANS Bytes
				next_trans = UDD_ENDPOINT_MAX_TRANS -
						(UDD_ENDPOINT_MAX_TRANS % ep_size);
				udd_udesc_set_buf0_autozlp(ep_num, false);
			} else {
				// Need ZLP, if requested and last packet is not a short packet
				udd_udesc_set_buf0_autozlp(ep_num, ptr_job->b_shortpacket);
				ptr_job->b_shortpacket = false; // No need to request another ZLP
			}

			udd_udesc_set_buf0_ctn(ep_num, next_trans);
			udd_udesc_rst_buf0_size(ep_num);

			// Link the user buffer directly on USB hardware DMA
			udd_udesc_set_buf0_addr(ep_num,
					&ptr_job->buf[ptr_job->nb_trans]);

			// Start transfer
			udd_ack_fifocon(ep_num);
			udd_disable_busy_bank0(ep_num);

			// Enable interrupt
			flags = cpu_irq_save();
			udd_enable_in_send_interrupt(ep_num);
			udd_enable_endpoint_interrupt(ep_num);
			cpu_irq_restore(flags);
			return;
		}
	} else {
		// Transfer complete on OUT
		nb_trans = udd_udesc_get_buf0_ctn(ep_num);

		// Lock reception of new OUT packet
		udd_enable_busy_bank0(ep_num);

		// Ack interrupt
		udd_ack_out_received(ep_num);
		udd_ack_fifocon(ep_num);

		// Can be necessary to copy data receive from cache buffer to user buffer
		if (ptr_job->b_use_out_cache_buffer) {
			memcpy(&ptr_job->buf[ptr_job->nb_trans],
					udd_ep_out_cache_buffer[ep_num - 1],
					ptr_job->buf_size % ep_size);
		}

		// Update number of data transfered
		ptr_job->nb_trans += nb_trans;
		if (ptr_job->nb_trans > ptr_job->buf_size) {
			ptr_job->nb_trans = ptr_job->buf_size;
		}

		// If all previous data requested are received and user buffer not full
		// then need to receive other data
		if ((nb_trans == udd_udesc_get_buf0_size(ep_num))
			&& (ptr_job->nb_trans != ptr_job->buf_size)) {
			next_trans = ptr_job->buf_size - ptr_job->nb_trans;
			if (UDD_ENDPOINT_MAX_TRANS < next_trans) {
				// The USB hardware support a maximum transfer size
				// of UDD_ENDPOINT_MAX_TRANS Bytes
				next_trans = UDD_ENDPOINT_MAX_TRANS
						- (UDD_ENDPOINT_MAX_TRANS % ep_size);
			} else {
				next_trans -= next_trans % ep_size;
			}

			udd_udesc_rst_buf0_ctn(ep_num);
			if (next_trans < ep_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_num,
						udd_ep_out_cache_buffer[ep_num-1]);
				udd_udesc_set_buf0_size(ep_num, ep_size);
			} else {
				// Link the user buffer directly on USB hardware DMA
				udd_udesc_set_buf0_addr(ep_num, &ptr_job->buf[ptr_job->nb_trans]);
				udd_udesc_set_buf0_size(ep_num, next_trans);
			}
			// Start transfer
			udd_disable_busy_bank0(ep_num);

			// Enable interrupt
			flags = cpu_irq_save();
			udd_enable_out_received_interrupt(ep_num);
			udd_enable_endpoint_interrupt(ep_num);
			cpu_irq_restore(flags);
			return;
		}
	}

	// Job complete then call callback
	ptr_job->busy = false;
	if (NULL != ptr_job->call_trans) {
		ptr_job->call_trans(UDD_EP_TRANSFER_OK, ptr_job->nb_trans, ep);
	}
	return;
}
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;
}
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);
}