Пример #1
0
static void S3C24X0_udc_ep0(void)
{
	u_int8_t ep0csr;
	struct usb_endpoint_instance *ep0 = udc_device->bus->endpoint_array;

	S3C24X0_UDC_SETIX(0);
	ep0csr = inl(S3C24X0_UDC_IN_CSR1_REG);

	/* clear stall status */
	if (ep0csr & S3C24X0_UDC_EP0_CSR_SENTSTL) {
	    	/* serial_printf("Clearing SENT_STALL\n"); */
		clear_ep0_sst();
		if (ep0csr & S3C24X0_UDC_EP0_CSR_SOPKTRDY)
			clear_ep0_opr();
		ep0->state = EP0_IDLE;
		return;
	}

	/* clear setup end */
	if (ep0csr & S3C24X0_UDC_EP0_CSR_SE
	    /* && ep0->state != EP0_IDLE */) {
	    	/* serial_printf("Clearing SETUP_END\n"); */
		clear_ep0_se();
#if 1
		if (ep0csr & S3C24X0_UDC_EP0_CSR_SOPKTRDY) {
			/* Flush FIFO */
			while (inl(S3C24X0_UDC_OUT_FIFO_CNT1_REG))
				inl(S3C24X0_UDC_EP0_FIFO_REG);
			clear_ep0_opr();
		}
#endif
		ep0->state = EP0_IDLE;
		return;
	}

	/* Don't ever put [serial] debugging in non-error codepaths here, it
	 * will violate the tight timing constraints of this USB Device
	 * controller (and lead to bus enumeration failures) */

	switch (ep0->state) {
		int i, fifo_count;
		unsigned char *datap;
	case EP0_IDLE:
		if (!(ep0csr & S3C24X0_UDC_EP0_CSR_OPKRDY))
			break;

		datap = (unsigned char *) &ep0_urb->device_request;
		/* host->device packet has been received */

		/* pull it out of the fifo */
		fifo_count = fifo_count_out();
		for (i = 0; i < fifo_count; i++) {
			*datap = (unsigned char)inl(S3C24X0_UDC_EP0_FIFO_REG);
			datap++;
		}
		if (fifo_count != 8) {
			debug("STRANGE FIFO COUNT: %u bytes\n", fifo_count);
			set_ep0_ss();
			return;
		}

		if (ep0_urb->device_request.wLength == 0) {
			if (ep0_recv_setup(ep0_urb)) {
				/* Not a setup packet, stall next EP0 transaction */
				debug("can't parse setup packet1\n");
				set_ep0_ss();
				set_ep0_de_out();
				ep0->state = EP0_IDLE;
				return;
			}
			/* There are some requests with which we need to deal
			 * manually here */
			switch (ep0_urb->device_request.bRequest) {
			case USB_REQ_SET_CONFIGURATION:
				if (!ep0_urb->device_request.wValue)
					usbd_device_event_irq(udc_device,
							DEVICE_DE_CONFIGURED, 0);
				else
					usbd_device_event_irq(udc_device,
							DEVICE_CONFIGURED, 0);
				break;
			case USB_REQ_SET_ADDRESS:
				udc_set_address(udc_device->address);
				usbd_device_event_irq(udc_device,
						DEVICE_ADDRESS_ASSIGNED, 0);
				break;
			default:
				break;
			}
			set_ep0_de_out();
			ep0->state = EP0_IDLE;
		} else {
			if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
				clear_ep0_opr();
				ep0->state = EP0_OUT_DATA_PHASE;
				ep0_urb->buffer = ep0_urb->buffer_data;
				ep0_urb->buffer_length = sizeof(ep0_urb->buffer_data);
				ep0_urb->actual_length = 0;
			} else {
				ep0->state = EP0_IN_DATA_PHASE;

				if (ep0_recv_setup(ep0_urb)) {
					/* Not a setup packet, stall next EP0 transaction */
					debug("can't parse setup packet2\n");
					set_ep0_ss();
					//set_ep0_de_out();
					ep0->state = EP0_IDLE;
					return;
				}
				clear_ep0_opr();
				ep0->tx_urb = ep0_urb;
				ep0->sent = ep0->last = 0;

				if (S3C24X0_write_noniso_tx_fifo(ep0)) {
					ep0->state = EP0_IDLE;
					set_ep0_de_in();
				} else
					set_ep0_ipr();
			}
		}
		break;
	case EP0_IN_DATA_PHASE:
		if (!(ep0csr & S3C24X0_UDC_EP0_CSR_IPKRDY)) {
			ep0->sent += ep0->last;

			if (S3C24X0_write_noniso_tx_fifo(ep0)) {
				ep0->state = EP0_IDLE;
				set_ep0_de_in();
			} else
				set_ep0_ipr();
		}
		break;
	case EP0_OUT_DATA_PHASE:
		if (ep0csr & S3C24X0_UDC_EP0_CSR_OPKRDY) {
			u32 urb_avail = ep0_urb->buffer_length - ep0_urb->actual_length;
			u_int8_t *cp = ep0_urb->buffer + ep0_urb->actual_length;
			int i, fifo_count;

			fifo_count = fifo_count_out();
			if (fifo_count < urb_avail)
				urb_avail = fifo_count;

			for (i = 0; i < urb_avail; i++)
				*cp++ = inl(S3C24X0_UDC_EP0_FIFO_REG);

			ep0_urb->actual_length += urb_avail;

			if (fifo_count < ep0->rcv_packetSize ||
			    ep0_urb->actual_length >= ep0_urb->device_request.wLength) {
				ep0->state = EP0_IDLE;
				if (ep0_recv_setup(ep0_urb)) {
					/* Not a setup packet, stall next EP0 transaction */
					debug("can't parse setup packet3\n");
					set_ep0_ss();
					//set_ep0_de_out();
					return;
				}
				set_ep0_de_out();
			} else
				clear_ep0_opr();
		}
		break;
	case EP0_END_XFER:
		ep0->state = EP0_IDLE;
		break;
	case EP0_STALL:
		//set_ep0_ss;
		ep0->state = EP0_IDLE;
		break;
	}
}
Пример #2
0
static void S3C24X0_udc_epn(int ep)
{
	struct usb_endpoint_instance *endpoint;
	struct urb *urb;
	u32 ep_csr1;

	if (ep >= S3C24X0_UDC_NUM_ENDPOINTS)
		return;

	endpoint = &udc_device->bus->endpoint_array[ep];

	S3C24X0_UDC_SETIX(ep);

	if (endpoint->endpoint_address & USB_DIR_IN) {
		/* IN transfer (device to host) */
		ep_csr1 = inl(S3C24X0_UDC_IN_CSR1_REG);
		debug("for ep=%u, CSR1=0x%x ", ep, ep_csr1);

		urb = endpoint->tx_urb;
		if (ep_csr1 & S3C24X0_UDC_ICSR1_SENTSTL) {
			/* Stall handshake */
			debug("stall\n");
			outl(0x00, S3C24X0_UDC_IN_CSR1_REG);
			return;
		}
		if (!(ep_csr1 & S3C24X0_UDC_ICSR1_PKTRDY) && urb &&
		      urb->actual_length) {

			debug("completing previously send data ");
			usbd_tx_complete(endpoint);

			/* push pending data into FIFO */
			if ((endpoint->last == endpoint->tx_packetSize) &&
			    (urb->actual_length - endpoint->sent - endpoint->last == 0)) {
				endpoint->sent += endpoint->last;
				/* Write 0 bytes of data (ZLP) */
				debug("ZLP ");
				outl(ep_csr1|S3C24X0_UDC_ICSR1_PKTRDY, S3C24X0_UDC_IN_CSR1_REG);
			} else {
				/* write actual data to fifo */
				debug_urb_buffer("TX_DATA", endpoint);
				S3C24X0_write_noniso_tx_fifo(endpoint);
				outl(ep_csr1|S3C24X0_UDC_ICSR1_PKTRDY, S3C24X0_UDC_IN_CSR1_REG);
			}
		}
		debug("\n");
	} else {
		/* OUT transfer (host to device) */
		ep_csr1 = inl(S3C24X0_UDC_OUT_CSR1_REG);
		debug("for ep=%u, CSR1=0x%x ", ep, ep_csr1);

		urb = endpoint->rcv_urb;
		if (ep_csr1 & S3C24X0_UDC_OCSR1_SENTSTL) {
			/* Stall handshake */
			outl(0x00, S3C24X0_UDC_IN_CSR1_REG);
			return;
		}
		if ((ep_csr1 & S3C24X0_UDC_OCSR1_PKTRDY) && urb) {
			/* Read pending data from fifo */
			u32 fifo_count = fifo_count_out();
			int is_last = 0;
			u32 i, urb_avail = urb->buffer_length - urb->actual_length;
			u8 *cp = urb->buffer + urb->actual_length;

			if (fifo_count < endpoint->rcv_packetSize)
				is_last = 1;

			debug("fifo_count=%u is_last=%, urb_avail=%u)\n",
				fifo_count, is_last, urb_avail);

			if (fifo_count < urb_avail)
				urb_avail = fifo_count;

			for (i = 0; i < urb_avail; i++)
				*cp++ = inb(ep_fifo_reg[ep]);

			if (is_last)
				outl(ep_csr1 & ~S3C24X0_UDC_OCSR1_PKTRDY,
				     S3C24X0_UDC_OUT_CSR1_REG);

			usbd_rcv_complete(endpoint, urb_avail, 0);
		}
	}

	urb = endpoint->rcv_urb;
}
Пример #3
0
static void s3c2410_udc_epn(int ep)
{
	struct usb_endpoint_instance *endpoint;
	struct urb *urb;
	u32 ep_csr1;

	if (ep >= S3C2410_UDC_NUM_ENDPOINTS)
		return;

	endpoint = &udc_device->bus->endpoint_array[ep];

	S3C2410_UDC_SETIX(ep);

	if (endpoint->endpoint_address & USB_DIR_IN) {
		/* IN transfer (device to host) */
		ep_csr1 = inl(S3C2410_UDC_IN_CSR1_REG);
		debug("for ep=%u, IN_CSR1=0x%x ", ep, ep_csr1);

		urb = endpoint->tx_urb;
		if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) {
			/* Stall handshake */
			debug("stall\n");
			outl(0x00, S3C2410_UDC_IN_CSR1_REG);
			return;
		}
		if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && urb &&
		      urb->actual_length) {

			debug("completing previously send data ");
			usbd_tx_complete(endpoint);

			/* push pending data into FIFO */
			if ((endpoint->last == endpoint->tx_packetSize) &&
			    (urb->actual_length - endpoint->sent - endpoint->last == 0)) {
				endpoint->sent += endpoint->last;
				/* Write 0 bytes of data (ZLP) */
				debug("ZLP ");
				outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG);
			} else {
				/* write actual data to fifo */
				debug_urb_buffer("TX_DATA", endpoint);
				s3c2410_write_noniso_tx_fifo(endpoint);
				outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG);
			}
		}
		debug("\n");
	} else {
		/* OUT transfer (host to device) */
		ep_csr1 = inl(S3C2410_UDC_OUT_CSR1_REG);
		debug("for ep=%u, OUT_CSR1=0x%x ", ep, ep_csr1);

		urb = endpoint->rcv_urb;
		if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) {
			/* Stall handshake */
			debugX("SENT STALL\n");
			outl(0x00, S3C2410_UDC_IN_CSR1_REG);
			return;
		}
		if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && urb) {
			/* Read pending data from fifo */
			u32 fifo_count = fifo_count_out();
			int is_last = 0;
			u32 i, urb_avail = urb->buffer_length - urb->actual_length;
			u8 *cp = urb->buffer + urb->actual_length;

			if (fifo_count < endpoint->rcv_packetSize)
				is_last = 1;

			debug("fifo_count=%u is_last=%d, urb_avail=%u\n",
				fifo_count, is_last, urb_avail);

			if (fifo_count < urb_avail)
				urb_avail = fifo_count;

			for (i = 0; i < urb_avail; i++)
				*cp++ = inb(ep_fifo_reg[ep]);

			/* if (is_last) */
			/*
			 * Once the MCU reads the packet from FIFO,
			 * this bit should be cleared
			 */
#ifndef AUTO_CLEAR 
			outl(ep_csr1 & ~S3C2410_UDC_OCSR1_PKTRDY,
				     S3C2410_UDC_OUT_CSR1_REG);
#endif

			usbd_rcv_complete(endpoint, urb_avail, 0);
			/* FIXME is there a better way to notify that,
			 * we have got data */
			usbd_device_event_irq(udc_device,
						DEVICE_FUNCTION_PRIVATE, 0);
		}
	}

	urb = endpoint->rcv_urb;
}