static bool udd_ctrl_interrupt(void)
{
	if (!Is_udd_endpoint_interrupt(0))
		return false; // No interrupt events on control endpoint

	// Search event on control endpoint
	if (Is_udd_setup_received(0)) {
		// SETUP packet received
		udd_ctrl_setup_received();
		return true;
	}
	if (Is_udd_in_sent(0)) {
		// IN packet sent
		udd_ctrl_in_sent();
		return true;
	}
	if (Is_udd_bank0_received(0)) {
		// OUT packet received
		udd_ctrl_out_received();
		return true;
	}
	if (Is_udd_stall(0)) {
		// STALLed
		udd_ack_stall(0);
		return true;
	}
	return false;
}
示例#2
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 void udd_ctrl_in_sent(void)
{
	static bool b_shortpacket = false;
	uint16_t nb_remain;
	uint8_t i;
	uint8_t *ptr_src;
	irqflags_t flags;

	if (UDD_EPCTRL_HANDSHAKE_WAIT_IN_ZLP == udd_ep_control_state) {
		// Ack
		udd_ack_in_sent(0);
		// 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();
			udd_ack_in_sent(0);
			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_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_bank0_received(0)) {
		// IN DATA phase aborted by OUT ZLP
		cpu_irq_restore(flags);
		udd_ep_control_state = UDD_EPCTRL_HANDSHAKE_WAIT_OUT_ZLP;
		udd_ack_in_sent(0);
		return; // Exit of IN DATA phase
	}
	// Write quickly the IN data
	for (i = 0; i < nb_remain; i++) {
		udd_endpoint_fifo_write(0, *ptr_src++);
	}
	udd_ctrl_payload_nb_trans += nb_remain;
	// Validate and send the data available in the control endpoint buffer
	udd_set_transmit_ready(0);
	udd_ack_in_sent(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);
}