Пример #1
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)
{
	udd_ep_job_t *ptr_job;
	irqflags_t flags;
	UDD_EP_t *ep_ctrl;

	Assert(udd_ep_is_valid(ep));

	// Get control & job about this endpoint
	ptr_job = udd_ep_get_job(ep);
	ep_ctrl = udd_ep_get_ctrl(ep);

	if (!udd_endpoint_is_enable(ep_ctrl)) {
		return false; // Endpoint not allocated
	}
	if (udd_endpoint_get_type(ep_ctrl)!=USB_EP_TYPE_ISOCHRONOUS_gc
		&& udd_endpoint_is_stall(ep_ctrl)) {
		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);


	// Update Job information
	ptr_job->buf = buf;
	ptr_job->buf_size = buf_size;
	ptr_job->nb_trans = 0;
	ptr_job->call_trans = callback;
	// Need to enable shortpacket to send a ZLP (buf_size==0)
	ptr_job->b_shortpacket = b_shortpacket || (buf_size==0);
	ptr_job->b_use_out_cache_buffer = false;

	// Initialize value to simulate a empty transfer
	if (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)) {
		udd_endpoint_in_reset_nb_sent(ep_ctrl);
	}
	else
	{
		if ((USB_EP_TYPE_ISOCHRONOUS_gc == udd_endpoint_get_type(ep_ctrl))
		&& (0 != (buf_size % udd_ep_get_size(ep_ctrl)))) {
			// The user must use a buffer size modulo endpoint size
			ptr_job->busy = false;
			return false;
		}
		udd_endpoint_out_reset_nb_received(ep_ctrl);
		udd_endpoint_out_set_nbbyte(ep_ctrl, 0);
	}
	// Request next transfer
	udd_ep_trans_complet(ep);
	return true;
}
Пример #2
0
void udd_ep_free(udd_ep_id_t ep)
{
	UDD_EP_t *ep_ctrl;
	Assert(udd_ep_is_valid(ep));

	udd_ep_abort(ep);
	ep_ctrl = udd_ep_get_ctrl(ep);
	udd_endpoint_disable(ep_ctrl);
}
bool udd_ep_set_halt(udd_ep_id_t ep)
{
	UDD_EP_t *ep_ctrl;
	Assert(udd_ep_is_valid(ep));

	ep_ctrl = udd_ep_get_ctrl(ep);
	udd_endpoint_enable_stall(ep_ctrl);

	udd_ep_abort(ep);
	return true;
}
Пример #4
0
bool udd_ep_clear_halt(udd_ep_id_t ep)
{
	udd_ep_job_t *ptr_job;
	UDD_EP_t *ep_ctrl;
	Assert(udd_ep_is_valid(ep));

	ep_ctrl = udd_ep_get_ctrl(ep);
	if (!udd_endpoint_is_stall(ep_ctrl)) {
		return true; // No stall on going
	}
	udd_endpoint_disable_stall(ep_ctrl);

	// If a job is register on clear halt action
	// then execute callback
	ptr_job = udd_ep_get_job(ep);
	if (ptr_job->busy == true) {
		ptr_job->busy = false;
		ptr_job->call_nohalt();
	}
	return true;
}
Пример #5
0
bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes,
		uint16_t MaxEndpointSize)
{
	UDD_EP_t *ep_ctrl;
	Assert(udd_ep_is_valid(ep));

	ep_ctrl = udd_ep_get_ctrl(ep);
	if (udd_endpoint_is_enable(ep_ctrl)) {
		return false; // Already allocated
	}
	udd_ep_init(ep, bmAttributes, MaxEndpointSize);

	// Do not use multipacket mode with isochronous 1023 bytes endpoint
	if (udd_endpoint_get_type(ep_ctrl)==USB_EP_TYPE_ISOCHRONOUS_gc
			&& (udd_endpoint_get_size_field(ep_ctrl)
			==USB_EP_BUFSIZE_1023_gc)) {
		return true;
	}

	udd_endpoint_set_multipacket(ep_ctrl);
	return true;
}
Пример #6
0
bool udd_ep_wait_stall_clear(udd_ep_id_t ep,
		udd_callback_halt_cleared_t callback)
{
	udd_ep_job_t *ptr_job;
	UDD_EP_t *ep_ctrl;
	Assert(udd_ep_is_valid(ep));

	ep_ctrl = udd_ep_get_ctrl(ep);
	ptr_job = udd_ep_get_job(ep);

	if (udd_endpoint_is_stall(ep_ctrl)) {
		// Wait clear halt endpoint
		if (ptr_job->busy == true) {
			return false; // Job already on going
		}
		ptr_job->busy = true;
		ptr_job->call_nohalt = callback;
	} else {
		// endpoint not halted then call directly callback
		callback();
	}
	return true;
}
Пример #7
0
void udd_ep_abort(udd_ep_id_t ep)
{
	UDD_EP_t *ep_ctrl;
	udd_ep_job_t *ptr_job;
	Assert(udd_ep_is_valid(ep));

	ep_ctrl = udd_ep_get_ctrl(ep);
	ptr_job = udd_ep_get_job(ep);

	// Stop transfer
	udd_endpoint_set_NACK0(ep_ctrl);
	if (ptr_job->busy == false) {
		return; // No job on going
	}
	ptr_job->busy = false;
	if (NULL != ptr_job->call_trans) {
		ptr_job->call_trans(UDD_EP_TRANSFER_ABORT,
				(ep & USB_EP_DIR_IN) ?
				udd_endpoint_in_nb_sent(ep_ctrl)
				: udd_endpoint_out_nb_receiv(ep_ctrl),
				ep);
	}
}
Пример #8
0
static void udd_ep_init(udd_ep_id_t ep, uint8_t bmAttributes,
		uint16_t MaxEndpointSize)
{
	USB_EP_TYPE_t type;
	USB_EP_BUFSIZE_t size;
	UDD_EP_t *ep_ctrl;

#if (0!=USB_DEVICE_MAX_EP)
	// Translate USB attribute to hardware defines
	switch (bmAttributes & USB_EP_TYPE_MASK) {
	case USB_EP_TYPE_CONTROL:
		type = USB_EP_TYPE_CONTROL_gc;
		break;
	case USB_EP_TYPE_ISOCHRONOUS:
		type = USB_EP_TYPE_ISOCHRONOUS_gc;
		break;
	case USB_EP_TYPE_BULK:
	case USB_EP_TYPE_INTERRUPT: //interrupt behaves as bulk
		type = USB_EP_TYPE_BULK_gc;
		break;
	default:
		Assert(false); // Wrong value
		return;
	}
#else
	type = USB_EP_TYPE_CONTROL_gc;
#endif

	// Translate USB endpoint size to hardware defines
	switch (MaxEndpointSize) {
	default:
		Assert(false); // Wrong value
	case 8:
		size = USB_EP_BUFSIZE_8_gc;
		break;
	case 16:
		size = USB_EP_BUFSIZE_16_gc;
		break;
	case 32:
		size = USB_EP_BUFSIZE_32_gc;
		break;
	case 64:
		size = USB_EP_BUFSIZE_64_gc;
		break;
#if (0!=USB_DEVICE_MAX_EP)
	case 128:
		size = USB_EP_BUFSIZE_128_gc;
		break;
	case 256:
		size = USB_EP_BUFSIZE_256_gc;
		break;
	case 512:
		size = USB_EP_BUFSIZE_512_gc;
		break;
	case 1023:
		size =USB_EP_BUFSIZE_1023_gc;
		break;
#endif
	}

	// Enable endpoint
	ep_ctrl = udd_ep_get_ctrl(ep);
	udd_endpoint_disable(ep_ctrl);
	udd_endpoint_clear_status(ep_ctrl);
	udd_endpoint_set_control(ep_ctrl, (uint8_t) type | (uint8_t) size);
}
Пример #9
0
static void udd_ep_trans_complet(udd_ep_id_t ep)
{
	UDD_EP_t *ep_ctrl;
	udd_ep_job_t *ptr_job;
	uint16_t ep_size, nb_trans;
	iram_size_t next_trans;

	ptr_job = udd_ep_get_job(ep);
	ep_ctrl = udd_ep_get_ctrl(ep);
	ep_size = udd_ep_get_size(ep_ctrl);

	if (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)) {
		// Transfer complete on IN
		nb_trans = udd_endpoint_in_nb_sent(ep_ctrl);

		// 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) {
			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);
			}
			// Need ZLP, if requested and last packet is not a short packet
			ptr_job->b_shortpacket = ptr_job->b_shortpacket
				&& (0==(next_trans % ep_size));
			udd_endpoint_in_reset_nb_sent(ep_ctrl);
			udd_endpoint_in_set_bytecnt(ep_ctrl, next_trans);
			// Link the user buffer directly on USB hardware DMA
			udd_endpoint_set_buf(ep_ctrl, &ptr_job->buf[ptr_job->nb_trans]);
			udd_endpoint_clear_NACK0(ep_ctrl);
			return;
		}

		// Need to send a ZLP after all data transfer
		if (ptr_job->b_shortpacket) {
			ptr_job->b_shortpacket = false;
			udd_endpoint_in_reset_nb_sent(ep_ctrl);
			udd_endpoint_in_set_bytecnt(ep_ctrl, 0);
			udd_endpoint_clear_NACK0(ep_ctrl);
			return;
		}
	}
	else
	{
		// Transfer complete on OUT
		nb_trans = udd_endpoint_out_nb_receiv(ep_ctrl);

		// 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 - 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_endpoint_out_get_nbbyte_requested(ep_ctrl))
			&& (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_endpoint_out_reset_nb_received(ep_ctrl);
			if (next_trans < ep_size) {
				// Use the cache buffer for Bulk or Interrupt size endpoint
				ptr_job->b_use_out_cache_buffer = true;
				udd_endpoint_set_buf( ep_ctrl,
					udd_ep_out_cache_buffer[ep - 1]);
				udd_endpoint_out_set_nbbyte(ep_ctrl, ep_size);
			} else {
				// Link the user buffer directly on USB hardware DMA
				udd_endpoint_set_buf(ep_ctrl, &ptr_job->buf[ptr_job->nb_trans]);
				udd_endpoint_out_set_nbbyte(ep_ctrl, next_trans);
			}
			// Start transfer
			udd_endpoint_clear_NACK0(ep_ctrl);
			return;
		}
	}

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