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;
}
Beispiel #2
0
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;
}
Beispiel #3
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;
			}
		}
	}
Beispiel #4
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 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;
}
Beispiel #6
0
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);
	}
}
Beispiel #7
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);
	}
}
Beispiel #8
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;
}
Beispiel #9
0
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);
}
Beispiel #10
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;
}