void udd_ep_abort(udd_ep_id_t ep)
{
	bool b_dir_in = ep & USB_EP_DIR_IN;
	irqflags_t flags;

	ep &= USB_EP_ADDR_MASK;
	if (USB_DEVICE_MAX_EP < ep)
		return;

	// Disable interrupts
	flags = cpu_irq_save();
	udd_disable_endpoint_interrupt(ep);
	cpu_irq_restore(flags);
	// Clear pending statuses
	if (b_dir_in) {
		// Kill banks
		if (Is_udd_transmit_ready(ep)) {
			udd_kill_data_in_fifo(ep,
					udd_get_endpoint_bank_max_nbr(ep)>1);
		}
		udd_ack_in_sent(ep);
		// Reset number of buffered banks
		udd_ep_job[ep - 1].bank = 0;
	} else {
		// Clear all pending banks statuses
		while(Is_udd_any_bank_received(ep)) {
			udd_ep_ack_out_received(ep);
		}
	}
	// Reset FIFO and data toggle
	udd_reset_endpoint(ep);
	// Abort job
	udd_ep_abort_job(ep);
}
static bool udd_ep_in_sent(udd_ep_id_t ep, bool b_tx)
{
	bool b_shortpacket;
	udd_ep_job_t *ptr_job = &udd_ep_job[ep - 1];

	// All banks are full
	if (ptr_job->bank >= udd_get_endpoint_bank_max_nbr(ep)) {
		return true; // Data pending
	}

	// No more data in buffer
	if (ptr_job->buf_cnt >= ptr_job->buf_size && !ptr_job->b_shortpacket) {
		return false;
	}

	// Fill FIFO
	b_shortpacket = udd_ep_write_fifo(ep);

	// Data is ready to send
	if (b_tx) {
		udd_set_transmit_ready(ep);
	}
	// Short PKT? no need to send it again.
	if (b_shortpacket) {
		ptr_job->b_shortpacket = false;
	}
	// All transfer done, including ZLP, Finish Job
	if ((ptr_job->buf_cnt >= ptr_job->buf_size)
			&& (!ptr_job->b_shortpacket)) {
		ptr_job->b_buf_end = true;
		return false;
	}
	return true; // Pending
}
Пример #3
0
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 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;
}