예제 #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 mxc_udc_recv_setup(void)
{
	setup_packet *s = &ep0_urb->device_request;

	mxc_udc_read_setup_pkt(s);
	if (s->wLength)	{
		mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ?
					USB_DIR_OUT : USB_DIR_IN;
		mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
	}
	if (ep0_recv_setup(ep0_urb)) {
		mxc_ep0_stall();
		return;
	}
	switch (s->bRequest) {
	case USB_REQ_GET_STATUS:
		if ((s->bmRequestType & (USB_DIR_IN | USB_TYPE_MASK)) !=
					 (USB_DIR_IN | USB_TYPE_STANDARD))
			break;
		ch9getstatus(s->bmRequestType, s->wValue,
				s->wIndex, s->wLength);
		return;
	case USB_REQ_SET_ADDRESS:
		if (s->bmRequestType != (USB_DIR_OUT |
			    USB_TYPE_STANDARD | USB_RECIP_DEVICE))
			break;
		mxc_udc.setaddr = 1;
		mxc_udc.ep0_dir = USB_DIR_IN;
		mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
		usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
		return;
	case USB_REQ_SET_CONFIGURATION:
		usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
	case USB_REQ_CLEAR_FEATURE:
	case USB_REQ_SET_FEATURE:
	{
		int rc = -1;
		if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) ==
				 (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD))
			rc = 0;
		else if ((s->bmRequestType &
			    (USB_RECIP_MASK | USB_TYPE_MASK)) ==
			     (USB_RECIP_DEVICE | USB_TYPE_STANDARD))
			rc = 0;
		else
			break;
		if (rc == 0) {
			mxc_udc.ep0_dir = USB_DIR_IN;
			mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
		}
		return;
	}
	default:
		break;
	}
	if (s->wLength) {
		mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ?
					USB_DIR_IN : USB_DIR_OUT;
		mxc_udc_queue_update(0, ep0_urb->buffer,
				ep0_urb->actual_length, 0xffffffff);
		ep0_urb->actual_length = 0;
	} else {
		mxc_udc.ep0_dir = USB_DIR_IN;
		mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
	}
}
예제 #3
0
static void mxc_udc_recv_setup(void)
{
	struct usb_device_request *s = &ep0_urb->device_request;

	mxc_udc_read_setup_pkt(s);
	if (s->wLength)	{
		/* If has a data phase,
		  * then prime a dtd for status stage which has zero length DATA0.
		  * The direction of status stage should oppsite to direction of data phase.
		  */
		mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ?
					USB_DIR_OUT : USB_DIR_IN;
		mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
	}
	if (ep0_recv_setup(ep0_urb)) {
		mxc_ep0_stall();
		return;
	}
	switch (s->bRequest) {
	case USB_REQ_GET_STATUS:
		if ((s->bmRequestType & (USB_DIR_IN | USB_TYPE_MASK)) !=
					 (USB_DIR_IN | USB_TYPE_STANDARD))
			break;
		ch9getstatus(s->bmRequestType, s->wValue,
				s->wIndex, s->wLength);

		DBG("[SETUP] REQ_GET_STATUS\n");
		return;
	case USB_REQ_SET_ADDRESS:
		if (s->bmRequestType != (USB_DIR_OUT |
			    USB_TYPE_STANDARD | USB_RECIP_DEVICE))
			break;
		mxc_udc.setaddr = 1;
		mxc_udc.ep0_dir = USB_DIR_IN;
		mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
		usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
		DBG("[SETUP] REQ_SET_ADDRESS\n");
		return;
	case USB_REQ_SET_CONFIGURATION:
		usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
		DBG("[SETUP] REQ_SET_CONFIGURATION\n");
	case USB_REQ_CLEAR_FEATURE:
	case USB_REQ_SET_FEATURE:
	{
		int rc = -1;
		if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) ==
				 (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD))
			rc = 0;
		else if ((s->bmRequestType &
			    (USB_RECIP_MASK | USB_TYPE_MASK)) ==
			     (USB_RECIP_DEVICE | USB_TYPE_STANDARD))
			rc = 0;
		else
			break;
		if (rc == 0) {
			mxc_udc.ep0_dir = USB_DIR_IN;
			mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
		}
		return;
	}
	default:
		break;
	}
	if (s->wLength) {
		mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ?
					USB_DIR_IN : USB_DIR_OUT;
		mxc_udc_queue_update(0, ep0_urb->buffer,
				ep0_urb->actual_length, 0xffffffff);
		ep0_urb->actual_length = 0;
	} else {
		mxc_udc.ep0_dir = USB_DIR_IN;
		mxc_udc_queue_update(0, NULL, 0, 0xffffffff);
	}
}
예제 #4
0
static void musb_peri_ep0_rx(void)
{
	/*
	 * This is the completion of the data OUT / RX
	 *
	 * Host is sending data to ep0 that is not
	 * part of setup.  This comes from the cdc_recv_setup
	 * op that is device specific.
	 *
	 * Pass the data back to driver ep0_recv_setup which
	 * should give the cdc_recv_setup the chance to handle
	 * the rx
	 */
	u16 csr0;
	u16 count0;

	if (debug_level > 3) {
		if (0 != ep0_urb->actual_length) {
			serial_printf("%s finished ? %d of %d\n",
				      __PRETTY_FUNCTION__,
				      ep0_urb->actual_length,
				      ep0_urb->device_request.wLength);
		}
	}

	if (ep0_urb->device_request.wLength == ep0_urb->actual_length) {
		musb_peri_ep0_last();
		SET_EP0_STATE(IDLE);
		ep0_recv_setup(ep0_urb);
		return;
	}

	csr0 = readw(&musbr->ep[0].ep0.csr0);
	if (!(MUSB_CSR0_RXPKTRDY & csr0))
		return;

	count0 = readw(&musbr->ep[0].ep0.count0);

	if (count0) {
		struct usb_endpoint_instance *endpoint;
		u32 length;
		u8 *data;

		endpoint = ep0_endpoint;
		if (endpoint && endpoint->rcv_urb) {
			struct urb *urb = endpoint->rcv_urb;
			unsigned int remaining_space = urb->buffer_length -
				urb->actual_length;

			if (remaining_space) {
				int urb_bad = 0; /* urb is good */

				if (count0 > remaining_space)
					length = remaining_space;
				else
					length = count0;

				data = (u8 *) urb->buffer_data;
				data += urb->actual_length;

				/* The common musb fifo reader */
				read_fifo(0, length, data);

				musb_peri_ep0_ack_req();

				/*
				 * urb's actual_length is updated in
				 * usbd_rcv_complete
				 */
				usbd_rcv_complete(endpoint, length, urb_bad);

			} else {
				if (debug_level > 0)
					serial_printf("ERROR : %s no space in "
						      "rcv buffer\n",
						      __PRETTY_FUNCTION__);
			}
		} else {
			if (debug_level > 0)
				serial_printf("ERROR : %s problem with "
					      "endpoint\n",
					      __PRETTY_FUNCTION__);
		}
	} else {
		if (debug_level > 0)
			serial_printf("ERROR : %s with nothing to do\n",
				      __PRETTY_FUNCTION__);
	}
}
예제 #5
0
static void musb_peri_ep0_idle(void)
{
	u16 count0;
	int err;
	u16 csr0;

	/*
	 * Verify addresses
	 * A lot of confusion can be caused if the address
	 * in software, udc layer, does not agree with the
	 * hardware.  Since the setting of the hardware address
	 * must be set after the set address request, the
	 * usb state machine is out of sync for a few frame.
	 * It is a good idea to run this check when changes
	 * are made to the state machine.
	 */
	if ((debug_level > 0) &&
	    (ep0_state != SET_ADDRESS)) {
		u8 faddr;

		faddr = readb(&musbr->faddr);
		if (udc_device->address != faddr) {
			serial_printf("ERROR : %s addresses do not"
				      "match sw %d vs hw %d\n",
				      __PRETTY_FUNCTION__,
				      udc_device->address, faddr);
			udelay(1000 * 1000);
			hang();
		}
	}

	csr0 = readw(&musbr->ep[0].ep0.csr0);

	if (!(MUSB_CSR0_RXPKTRDY & csr0))
		goto end;

	count0 = readw(&musbr->ep[0].ep0.count0);
	if (count0 == 0)
		goto end;

	if (count0 != 8) {
		if ((debug_setup) && (debug_level > 1))
			serial_printf("WARN : %s SETUP incorrect size %d\n",
				      __PRETTY_FUNCTION__, count0);
		musb_peri_ep0_stall();
		goto end;
	}

	read_fifo(0, count0, &ep0_urb->device_request);

	if (debug_level > 2)
		print_usb_device_request(&ep0_urb->device_request);

	if (ep0_urb->device_request.wLength == 0) {
		err = ep0_recv_setup(ep0_urb);

		/* Zero data request */
		musb_peri_ep0_zero_data_request(err);
	} else {
		/* Is data coming or going ? */
		u8 reqType = ep0_urb->device_request.bmRequestType;

		if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
			err = ep0_recv_setup(ep0_urb);
			/* Device to host */
			musb_peri_ep0_tx_data_request(err);
		} else {
			/*
			 * Host to device
			 *
			 * The RX routine will call ep0_recv_setup
			 * when the data packet has arrived.
			 */
			musb_peri_ep0_rx_data_request();
		}
	}

end:
	return;
}
예제 #6
0
파일: pxa27x_udc.c 프로젝트: cnauman/u-boot
static void udc_handle_ep0(struct usb_endpoint_instance *endpoint)
{
	u32 udccsr0 = readl(UDCCSR0);
	u32 *data = (u32 *) &ep0_urb->device_request;
	int i;

	usbdbg("udccsr0 %x", udccsr0);

	/* Clear stall status */
	if (udccsr0 & UDCCSR0_SST) {
		usberr("clear stall status");
		writel(UDCCSR0_SST, UDCCSR0);
		ep0state = EP0_IDLE;
	}

	/* previous request unfinished?  non-error iff back-to-back ... */
	if ((udccsr0 & UDCCSR0_SA) != 0 && ep0state != EP0_IDLE)
		ep0state = EP0_IDLE;

	switch (ep0state) {

	case EP0_IDLE:
		udccsr0 = readl(UDCCSR0);
		/* Start control request? */
		if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE))
			== (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) {

			/* Read SETUP packet.
			 * SETUP packet size is 8 bytes (aka 2 words)
			 */
			usbdbg("try reading SETUP packet");
			for (i = 0; i < 2; i++) {
				if ((readl(UDCCSR0) & UDCCSR0_RNE) == 0) {
					usberr("setup packet too short:%d", i);
					goto stall;
				}
				data[i] = readl(UDCDR0);
			}

			writel(readl(UDCCSR0) | UDCCSR0_OPC | UDCCSR0_SA, UDCCSR0);
			if ((readl(UDCCSR0) & UDCCSR0_RNE) != 0) {
				usberr("setup packet too long");
				goto stall;
			}

			udc_dump_buffer("ep0 setup read", (u8 *) data, 8);

			if (ep0_urb->device_request.wLength == 0) {
				usbdbg("Zero Data control Packet\n");
				if (ep0_recv_setup(ep0_urb)) {
					usberr("Invalid Setup Packet\n");
					udc_dump_buffer("ep0 setup read",
								(u8 *)data, 8);
					goto stall;
				}
				writel(UDCCSR0_IPR, UDCCSR0);
				ep0state = EP0_IDLE;
			} else {
				/* Check direction */
				if ((ep0_urb->device_request.bmRequestType &
						USB_REQ_DIRECTION_MASK)
						== USB_REQ_HOST2DEVICE) {
					ep0state = EP0_OUT_DATA;
					ep0_urb->buffer =
						(u8 *)ep0_urb->buffer_data;
					ep0_urb->buffer_length =
						sizeof(ep0_urb->buffer_data);
					ep0_urb->actual_length = 0;
					writel(UDCCSR0_IPR, UDCCSR0);
				} else {
					/* The ep0_recv_setup function has
					 * already placed our response packet
					 * data in ep0_urb->buffer and the
					 * packet length in
					 * ep0_urb->actual_length.
					 */
					if (ep0_recv_setup(ep0_urb)) {
stall:
						usberr("Invalid setup packet");
						udc_dump_buffer("ep0 setup read"
							, (u8 *) data, 8);
						ep0state = EP0_IDLE;

						writel(UDCCSR0_SA |
						UDCCSR0_OPC | UDCCSR0_FST |
						UDCCS0_FTF, UDCCSR0);

						return;
					}

					endpoint->tx_urb = ep0_urb;
					endpoint->sent = 0;
					usbdbg("EP0_IN_DATA");
					ep0state = EP0_IN_DATA;
					if (udc_write_urb(endpoint) < 0)
						goto stall;

				}
			}
			return;
		} else if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA))
			== (UDCCSR0_OPC|UDCCSR0_SA)) {
			usberr("Setup Active but no data. Stalling ....\n");
			goto stall;
		} else {
			usbdbg("random early IRQs");
			/* Some random early IRQs:
			 * - we acked FST
			 * - IPR cleared
			 * - OPC got set, without SA (likely status stage)
			 */
			writel(udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC), UDCCSR0);
		}
		break;

	case EP0_OUT_DATA:

		if ((udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_SA)) {
			if (udc_read_urb_ep0()) {
read_complete:
				ep0state = EP0_IDLE;
				if (ep0_recv_setup(ep0_urb)) {
					/* Not a setup packet, stall next
					 * EP0 transaction
					 */
					udc_dump_buffer("ep0 setup read",
							(u8 *) data, 8);
					usberr("can't parse setup packet\n");
					goto stall;
				}
			}
		} else if (!(udccsr0 & UDCCSR0_OPC) &&
				!(udccsr0 & UDCCSR0_IPR)) {
			if (ep0_urb->device_request.wLength ==
				ep0_urb->actual_length)
				goto read_complete;

			usberr("Premature Status\n");
			ep0state = EP0_IDLE;
		}
		break;

	case EP0_IN_DATA:
		/* GET_DESCRIPTOR etc */
		if (udccsr0 & UDCCSR0_OPC) {
			writel(UDCCSR0_OPC | UDCCSR0_FTF, UDCCSR0);
			usberr("ep0in premature status");
			ep0state = EP0_IDLE;
		} else {
			/* irq was IPR clearing */
			if (udc_write_urb(endpoint) < 0) {
				usberr("ep0_write_error\n");
				goto stall;
			}
		}
		break;

	case EP0_XFER_COMPLETE:
		writel(UDCCSR0_IPR, UDCCSR0);
		ep0state = EP0_IDLE;
		break;

	default:
		usbdbg("Default\n");
	}
	writel(USIR0_IR0, USIR0);
}