Exemplo n.º 1
0
static int udc_read_urb(struct usb_endpoint_instance *endpoint)
{
	struct urb *urb = endpoint->rcv_urb;
	int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
	u32 *data32 = (u32 *) urb->buffer;
	unsigned int i, n, is_short ;

	usbdbg("read urb on ep %d", ep_num);
#if defined(USBDDBG) && defined(USBDPARANOIA)
	usbdbg("urb: buf %p, buf_len %d, actual_len %d",
		urb->buffer, urb->buffer_length, urb->actual_length);
	usbdbg("endpoint: rcv_packetSize %d",
		endpoint->rcv_packetSize);
#endif

	if (readl(UDCCSN(ep_num)) & UDCCSR_BNE)
		n = readl(UDCBCN(ep_num)) & 0x3ff;
	else /* zlp */
		n = 0;
	is_short = n != endpoint->rcv_packetSize;

	usbdbg("n %d%s", n, is_short ? "-s" : "");
	for (i = 0; i < n; i += 4)
		data32[urb->actual_length / 4 + i / 4] = readl(UDCDN(ep_num));

	udc_dump_buffer("urb read", (u8 *) data32, urb->actual_length + n);
	usbd_rcv_complete(endpoint, n, 0);

	return 0;
}
Exemplo n.º 2
0
static void musb_peri_rx_ep(unsigned int ep)
{
	u16 peri_rxcount = readw(&musbr->ep[ep].epN.rxcount);

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

		endpoint = GET_ENDPOINT(udc_device, ep);
		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 (peri_rxcount > remaining_space)
					length = remaining_space;
				else
					length = peri_rxcount;

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

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

				musb_peri_rx_ack(ep);

				/*
				 * 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 %d no space "
						      "in rcv buffer\n",
						      __PRETTY_FUNCTION__, ep);
			}
		} else {
			if (debug_level > 0)
				serial_printf("ERROR : %s %d problem with "
					      "endpoint\n",
					      __PRETTY_FUNCTION__, ep);
		}

	} else {
		if (debug_level > 0)
			serial_printf("ERROR : %s %d with nothing to do\n",
				      __PRETTY_FUNCTION__, ep);
	}
}
Exemplo n.º 3
0
static void mxc_udc_ep_recv(u8 epnum)
{
	mxc_ep_t *ep = mxc_udc.mxc_ep + (epnum * 2 + USB_RECV);
	struct ep_queue_item *tqi;
	while (1) {
		u32 nbytes;
		tqi = ep->ep_dtd[ep->done];
		if (mxc_udc_tqi_empty(tqi))
			break;
		nbytes = _mxc_ep_recv_data(epnum, tqi);
		usbd_rcv_complete(ep->epi, nbytes, 0);
		inc_index(ep->done);
		if (ep->done == ep->index)
			break;
	}
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
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__);
	}
}
Exemplo n.º 6
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;
}