示例#1
0
int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
{
	int ret = 0;

	/* Transmit only if the hardware is available */
	if (endpoint->tx_urb && endpoint->state == 0) {
		unsigned int ep = endpoint->endpoint_address &
			USB_ENDPOINT_NUMBER_MASK;

		u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);

		/* Error conditions */
		if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) {
			peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN;
			writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
		}

		if (debug_level > 1)
			musb_print_txcsr(peri_txcsr);

		/* Check if a packet is waiting to be sent */
		if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) {
			u32 length;
			u8 *data;
			struct urb *urb = endpoint->tx_urb;
			unsigned int remaining_packet = urb->actual_length -
				endpoint->sent;

			if (endpoint->tx_packetSize < remaining_packet)
				length = endpoint->tx_packetSize;
			else
				length = remaining_packet;

			data = (u8 *) urb->buffer;
			data += endpoint->sent;

			/* common musb fifo function */
			write_fifo(ep, length, data);

			musb_peri_tx_ready(ep);

			endpoint->last = length;
			/* usbd_tx_complete will take care of updating 'sent' */
			usbd_tx_complete(endpoint);
		}
	
		musb_peri_wait_tx_done(ep);
	} else {
		if (debug_level > 0)
			serial_printf("ERROR : %s Problem with urb %p "
				      "or ep state %d\n",
				      __PRETTY_FUNCTION__,
				      endpoint->tx_urb, endpoint->state);
	}

	return ret;
}
示例#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
/*
 * If the endpoint has an active tx_urb, then the next packet of data from the
 * URB is written to the tx FIFO.
 * The total amount of data in the urb is given by urb->actual_length.
 * The maximum amount of data that can be sent in any one packet is given by
 * endpoint->tx_packetSize.
 * The number of data bytes from this URB that have already been transmitted
 * is given by endpoint->sent.
 * endpoint->last is updated by this routine with the number of data bytes
 * transmitted in this packet.
 */
static int udc_write_urb(struct usb_endpoint_instance *endpoint)
{
	struct urb *urb = endpoint->tx_urb;
	int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
	u32 *data32 = (u32 *) urb->buffer;
	u8  *data8 = (u8 *) urb->buffer;
	unsigned int i, n, w, b, is_short;
	int timeout = 2000;	/* 2ms */

	if (!urb || !urb->actual_length)
		return -1;

	n = MIN(urb->actual_length - endpoint->sent, endpoint->tx_packetSize);
	if (n <= 0)
		return -1;

	usbdbg("write 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: sent %d, tx_packetSize %d, last %d",
		endpoint->sent, endpoint->tx_packetSize, endpoint->last);
#endif

	is_short = n != endpoint->tx_packetSize;
	w = n / 4;
	b = n % 4;
	usbdbg("n %d%s w %d b %d", n, is_short ? "-s" : "", w, b);
	udc_dump_buffer("urb write", data8 + endpoint->sent, n);

	/* Prepare for data send */
	if (ep_num)
		writel(UDCCSR_PC ,UDCCSN(ep_num));

	for (i = 0; i < w; i++)
		  writel(data32[endpoint->sent / 4 + i], UDCDN(ep_num));

	for (i = 0; i < b; i++)
		  writeb(data8[endpoint->sent + w * 4 + i], UDCDN(ep_num));

	/* Set "Packet Complete" if less data then tx_packetSize */
	if (is_short)
		writel(ep_num ? UDCCSR_SP : UDCCSR0_IPR, UDCCSN(ep_num));

	/* Wait for data sent */
	if (ep_num) {
		while (!(readl(UDCCSN(ep_num)) & UDCCSR_PC)) {
			if (timeout-- == 0)
				return -1;
			else
				udelay(1);
		}
	}

	endpoint->last = n;

	if (ep_num) {
		usbd_tx_complete(endpoint);
	} else {
		endpoint->sent += n;
		endpoint->last -= n;
	}

	if (endpoint->sent >= urb->actual_length) {
		urb->actual_length = 0;
		endpoint->sent = 0;
		endpoint->last = 0;
	}

	if ((endpoint->sent >= urb->actual_length) && (!ep_num)) {
		usbdbg("ep0 IN stage done");
		if (is_short)
			ep0state = EP0_IDLE;
		else
			ep0state = EP0_XFER_COMPLETE;
	}

	return 0;
}
示例#4
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;
}