Exemple #1
0
bool udd_ep_clear_halt(udd_ep_id_t ep)
{
	bool b_stall_cleared = false;
	udd_ep_job_t *ptr_job;

	ep &= USB_EP_ADDR_MASK;
	if (USB_DEVICE_MAX_EP < ep)
		return false;
	ptr_job = &udd_ep_job[ep - 1];

	if (ptr_job->stall_requested) {
		// Endpoint stall has been requested but not done
		// Remove stall request
		ptr_job->stall_requested = false;
		udd_disable_bank_interrupt(ep);
		udd_disable_endpoint_interrupt(ep);
		b_stall_cleared = true;
	}
	if (Is_udd_endpoint_stall_requested(ep)) { 
		if (Is_udd_stall(ep)) {
			udd_ack_stall(ep);
			// A packet has been stalled
			// then reset datatoggle
			udd_reset_data_toggle(ep);
		}
		// Disable stall
		udd_disable_stall_handshake(ep);
		udd_enable_endpoint_bank_autoswitch(ep);
		b_stall_cleared = true;
	}
	if (b_stall_cleared) {
		// If a job is register on clear halt action
		// then execute callback
		if (ptr_job->busy == true) {
			ptr_job->busy = false;
			ptr_job->call_nohalt();
		}
	}
	return true;
}
Exemple #2
0
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)
{
	bool b_dir_in;
	uint32_t udd_dma_ctrl = 0;
	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)
			|| ptr_job->stall_requested)
		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);

	// The USBB supports a maximum transfer size of 64KB
	if (0x10000 <= buf_size) {
		// Transfer size = 64KB
		ptr_job->buf_size = 0x10000;
		buf_size = 0;
	} else {
		ptr_job->buf_size = buf_size;
		if (b_dir_in && (0 != buf_size % udd_get_endpoint_size(ep))) {
			// Force short packet option to send a shortpacket on IN,
			// else the DMA transfer is accepted and interrupt DMA valid but nothing is sent.
			b_shortpacket = true;
		}
	}
	ptr_job->buf = buf;
	ptr_job->call_trans = callback;

	// Start USB DMA to fill or read fifo of the selected endpoint
	udd_endpoint_dma_set_addr(ep, (U32) buf);
	if (b_shortpacket) {
		if (b_dir_in) {
			udd_dma_ctrl = AVR32_USBB_UDDMA1_CONTROL_DMAEND_EN_MASK;
		} else {
			udd_dma_ctrl = AVR32_USBB_UDDMA1_CONTROL_EOT_IRQ_EN_MASK
					|
					AVR32_USBB_UDDMA1_CONTROL_BUFF_CLOSE_IN_EN_MASK;
		}
	}
	udd_dma_ctrl |= (buf_size <<
			AVR32_USBB_UDDMA1_CONTROL_CH_BYTE_LENGTH_OFFSET)
			& AVR32_USBB_UDDMA1_CONTROL_CH_BYTE_LENGTH_MASK;
	udd_dma_ctrl |= AVR32_USBB_UDDMA1_CONTROL_EOBUFF_IRQ_EN_MASK |
			AVR32_USBB_UDDMA1_CONTROL_CH_EN_MASK;
	udd_enable_endpoint_bank_autoswitch(ep);
	udd_endpoint_dma_set_control(ep, udd_dma_ctrl);
	flags = cpu_irq_save();
	udd_enable_endpoint_dma_interrupt(ep);
	cpu_irq_restore(flags);

	return true;
}
Exemple #3
0
bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes,
		uint16_t MaxEndpointSize)
{
	bool b_dir_in;
	uint16_t ep_allocated;
	uint8_t bank, i;

	b_dir_in = ep & USB_EP_DIR_IN;
	ep = ep & USB_EP_ADDR_MASK;

	if (ep > USB_DEVICE_MAX_EP) {
		return false;
	}
	if (Is_udd_endpoint_enabled(ep)) {
		return false;
	}

	// Bank choice
	switch(bmAttributes&USB_EP_TYPE_MASK) {
	case USB_EP_TYPE_ISOCHRONOUS:
		bank = UDD_ISOCHRONOUS_NB_BANK(ep);
		break;
	case USB_EP_TYPE_INTERRUPT:
		bank = UDD_INTERRUPT_NB_BANK(ep);
		break;
	case USB_EP_TYPE_BULK:
		bank = UDD_BULK_NB_BANK(ep);
		break;
	default:
		Assert(false);
		return false;
	}
	switch(bank) {
	case 1:
		bank = AVR32_USBB_UECFG0_EPBK_SINGLE;
		break;
	case 2:
		bank = AVR32_USBB_UECFG0_EPBK_DOUBLE;
		break;
	case 3:
		bank = AVR32_USBB_UECFG0_EPBK_TRIPLE;
		break;
	default:
		Assert(false);
		return false;
	}

	// Check if endpoint size is 8,16,32,64,128,256,512 or 1023
	Assert(MaxEndpointSize < 1024);
	Assert((MaxEndpointSize == 1023) || !(MaxEndpointSize & (MaxEndpointSize - 1)));
	Assert(MaxEndpointSize >= 8);

	// Set configuration of new endpoint
	udd_configure_endpoint(ep, bmAttributes, (b_dir_in ? 1 : 0),
			MaxEndpointSize, bank);
	ep_allocated = 1 << ep;

	// Unalloc endpoints superior
	for (i = USB_DEVICE_MAX_EP; i > ep; i--) {
		if (Is_udd_endpoint_enabled(i)) {
			ep_allocated |= 1 << i;
			udd_disable_endpoint(i);
			udd_unallocate_memory(i);
		}
	}

	// Realloc/Enable endpoints
	for (i = ep; i <= USB_DEVICE_MAX_EP; i++) {
		if (ep_allocated & (1 << i)) {
			udd_ep_job_t *ptr_job = &udd_ep_job[i - 1];
			bool b_restart = ptr_job->busy;
			ptr_job->busy = false;

			udd_allocate_memory(i);
			udd_enable_endpoint(i);
			if (!Is_udd_endpoint_configured(i)) {
				if (NULL == ptr_job->call_trans) {
					return false;
				}
				if (Is_udd_endpoint_in(i)) {
					i |= USB_EP_DIR_IN;
				}				
				ptr_job->call_trans(UDD_EP_TRANSFER_ABORT,
						ptr_job->buf_size, i);
				return false;
			}
			udd_enable_endpoint_bank_autoswitch(i);
			if (b_restart) {
				// Re-run the job
				udd_ep_run(i, ptr_job->b_shortpacket,
						ptr_job->buf,
						ptr_job->buf_size,
						ptr_job->call_trans);
			}
		}
	}
	return true;
}
Exemple #4
0
bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes,
		uint16_t MaxEndpointSize)
{
	bool b_dir_in;
	uint16_t ep_allocated;
	uint8_t nb_bank, bank, i;

	b_dir_in = ep & USB_EP_DIR_IN;
	ep = ep & USB_EP_ADDR_MASK;

	if (ep > USB_DEVICE_MAX_EP) {
		return false;
	}
	if (Is_udd_endpoint_enabled(ep)) {
		return false;
	}
	dbg_print("alloc(%x, %d) ", ep, MaxEndpointSize);

	// Bank choice
	switch (bmAttributes & USB_EP_TYPE_MASK) {
	case USB_EP_TYPE_ISOCHRONOUS:
		nb_bank = UDD_ISOCHRONOUS_NB_BANK(ep);
		break;
	case USB_EP_TYPE_INTERRUPT:
		nb_bank = UDD_INTERRUPT_NB_BANK(ep);
		break;
	case USB_EP_TYPE_BULK:
		nb_bank = UDD_BULK_NB_BANK(ep);
		break;
	default:
		Assert(false);
		return false;
	}
	switch (nb_bank) {
	case 1:
		bank = UOTGHS_DEVEPTCFG_EPBK_1_BANK >>
				UOTGHS_DEVEPTCFG_EPBK_Pos;
		break;
	case 2:
		bank = UOTGHS_DEVEPTCFG_EPBK_2_BANK >>
				UOTGHS_DEVEPTCFG_EPBK_Pos;
		break;
	case 3:
		bank = UOTGHS_DEVEPTCFG_EPBK_3_BANK >>
				UOTGHS_DEVEPTCFG_EPBK_Pos;
		break;
	default:
		Assert(false);
		return false;
	}

	// Check if endpoint size is 8,16,32,64,128,256,512 or 1023
	Assert(MaxEndpointSize < 1024);
	Assert((MaxEndpointSize == 1023)
		|| !(MaxEndpointSize & (MaxEndpointSize - 1)));
	Assert(MaxEndpointSize >= 8);

	// Set configuration of new endpoint
	udd_configure_endpoint(ep, bmAttributes, (b_dir_in ? 1 : 0),
			MaxEndpointSize, bank);
	ep_allocated = 1 << ep;

	// Unalloc endpoints superior
	for (i = USB_DEVICE_MAX_EP; i > ep; i--) {
		if (Is_udd_endpoint_enabled(i)) {
			ep_allocated |= 1 << i;
			udd_disable_endpoint(i);
			udd_unallocate_memory(i);
		}
	}

	// Realloc/Enable endpoints
	for (i = ep; i <= USB_DEVICE_MAX_EP; i++) {
		if (ep_allocated & (1 << i)) {
			udd_ep_job_t *ptr_job = &udd_ep_job[i - 1];
			bool b_restart = ptr_job->busy;
			// Restart running job because
			// memory window slides up and its data is lost
			ptr_job->busy = false;
			// Re-allocate memory
			udd_allocate_memory(i);
			udd_enable_endpoint(i);
			if (!Is_udd_endpoint_configured(i)) {
				dbg_print("ErrRealloc%d ", i);
				if (NULL == ptr_job->call_trans) {
					return false;
				}
				if (Is_udd_endpoint_in(i)) {
					i |= USB_EP_DIR_IN;
				}
				ptr_job->call_trans(UDD_EP_TRANSFER_ABORT,
						ptr_job->buf_cnt, i);
				return false;
			}
			udd_enable_endpoint_bank_autoswitch(i);
			if (b_restart) {
				// Re-run the job remaining part
				ptr_job->buf_cnt -= ptr_job->buf_load;
				b_restart = udd_ep_run(Is_udd_endpoint_in(i) ?
							(i | USB_EP_DIR_IN) : i,
						ptr_job->b_shortpacket,
						&ptr_job->buf[ptr_job->buf_cnt],
						ptr_job->buf_size
							- ptr_job->buf_cnt,
						ptr_job->call_trans);
				if (!b_restart) {
					dbg_print("ErrReRun%d ", i);
					return false;
				}
			}
		}
	}
	return true;
}