PERFORCE change 132640 for review

Hans Petter Selasky hselasky at FreeBSD.org
Sun Jan 6 13:44:13 PST 2008


http://perforce.freebsd.org/chv.cgi?CH=132640

Change 132640 by hselasky at hselasky_laptop001 on 2008/01/06 21:43:50

	
	AT91 UDP bugfixes:
	
	o Remove "did_multi_buffer" flag. Multi bufring works
	  regardless of this.
	
	o Create new routine, at9100_dci_reset_ep, that handles
	  all endpoint reset. The reason for this is that the
	  FIFO reset command does not release all the FIFO
	  banks, so if we do not clear these ourselves we
	  end up receiving ZLP's which can confuse the USB
	  device drivers.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/at9100_dci.c#12 edit
.. //depot/projects/usb/src/sys/dev/usb/at9100_dci.h#4 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/at9100_dci.c#12 (text+ko) ====

@@ -561,23 +561,13 @@
 	temp &= AT91_UDP_CSR_STALLSENT;
 
 	if (csr & AT91_UDP_CSR_TXPKTRDY) {
-		/* check for double buffering */
-		if (td->support_multi_buffer &&
-		    (!td->did_multi_buffer)) {
-			td->did_multi_buffer = 1;
-
-			/* only set TXPKTRDY next time  */
-			temp |= AT91_UDP_CSR_TXPKTRDY;
-
-		} else if (temp) {
+		if (temp) {
 			/* write command */
 			AT91_CSR_ACK(csr, temp);
 			bus_space_write_4(td->io_tag, td->io_hdl,
 			    td->status_reg, csr);
-			return (1);	/* not complete */
-		} else {
-			return (1);	/* not complete */
 		}
+		return (1);		/* not complete */
 	} else {
 		/* clear TXCOMP and set TXPKTRDY */
 		temp |= (AT91_UDP_CSR_TXCOMP |
@@ -673,19 +663,6 @@
 	bus_space_write_4(td->io_tag, td->io_hdl,
 	    td->status_reg, csr);
 
-#if 0
-	/*
-	 * XXX The AT91 USB chip does not generate a second interrupt
-	 * when we do double bufring, so there is no way of telling
-	 * when the peer has actually received the data. Usually this
-	 * is not a big problem. XXX
-	 */
-	if (td->did_multi_buffer) {
-		/* wait for the second and final interrupt */
-		td->did_multi_buffer = 0;
-		goto repeat;
-	}
-#endif
 	return (0);			/* complete */
 
 not_complete:
@@ -734,14 +711,10 @@
 		temp = 0;
 		if (td->fifo_bank)
 			temp |= 1;
-		if (td->did_multi_buffer)
-			temp |= 2;
 		td = td->obj_next;
 		xfer->td_transfer_cache = td;
 		if (temp & 1)
 			td->fifo_bank = 1;
-		if (temp & 2)
-			td->did_multi_buffer = 1;
 	}
 	return (1);			/* not complete */
 
@@ -756,13 +729,6 @@
 		sc->sc_ep_flags[temp].fifo_bank = 0;
 	}
 
-	/* update multi buffer flag */
-	if (td->did_multi_buffer) {
-		sc->sc_ep_flags[temp].did_multi_buffer = 1;
-	} else {
-		sc->sc_ep_flags[temp].did_multi_buffer = 0;
-	}
-
 	/* compute all actual lengths */
 
 	at9100_dci_standard_done(xfer);
@@ -927,7 +893,6 @@
 	td->remainder = temp->len;
 	td->fifo_bank = 0;
 	td->error = 0;
-	td->did_multi_buffer = 0;
 	td->did_stall = 0;
 	td->short_pkt = temp->short_pkt;
 	td->alt_next = temp->setup_alt_next;
@@ -1081,11 +1046,6 @@
 		td = xfer->td_transfer_first;
 		td->fifo_bank = 1;
 	}
-	/* setup the correct multi buffer flag */
-	if (sc->sc_ep_flags[ep_no].did_multi_buffer) {
-		td = xfer->td_transfer_first;
-		td->did_multi_buffer = 1;
-	}
 	return;
 }
 
@@ -1342,28 +1302,77 @@
 }
 
 static void
-at9100_dci_clear_stall(struct usbd_device *udev, struct usbd_pipe *pipe)
+at9100_dci_reset_ep(struct usbd_device *udev, uint8_t ep_no)
 {
 	struct at9100_dci_softc *sc;
-	uint32_t rst_val;
+	const struct usbd_hw_ep_profile *pf;
+	uint32_t csr_val;
+	uint32_t temp;
+	uint8_t csr_reg;
+	uint8_t to;
+
+	/* get softc */
+	sc = AT9100_DCI_BUS2SC(udev->bus);
+
+	/* get endpoint profile */
+	at9100_dci_get_hw_ep_profile(udev, &pf, ep_no);
+
+	/* reset FIFO */
+	AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(ep_no));
+	AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0);
+
+	/*
+	 * NOTE: One would assume that a FIFO reset would release the
+	 * FIFO banks aswell, but it doesn't! We have to do this
+	 * manually!
+	 */
+	csr_reg = AT91_UDP_CSR(ep_no);
+
+	/* release FIFO banks, if any */
+	for (to = 0; to != 2; to++) {
+
+		/* get csr value */
+		csr_val = AT91_UDP_READ_4(sc, csr_reg);
+
+		if (csr_val & (AT91_UDP_CSR_RX_DATA_BK0 |
+		    AT91_UDP_CSR_RX_DATA_BK1)) {
+			/* clear status bits */
+			if (pf->support_multi_buffer) {
+				if (sc->sc_ep_flags[ep_no].fifo_bank) {
+					sc->sc_ep_flags[ep_no].fifo_bank = 0;
+					temp = AT91_UDP_CSR_RX_DATA_BK1;
+				} else {
+					sc->sc_ep_flags[ep_no].fifo_bank = 1;
+					temp = AT91_UDP_CSR_RX_DATA_BK0;
+				}
+			} else {
+				temp = (AT91_UDP_CSR_RX_DATA_BK0 |
+				    AT91_UDP_CSR_RX_DATA_BK1);
+			}
+		} else {
+			temp = 0;
+		}
+
+		/* clear FORCESTALL */
+		temp |= AT91_UDP_CSR_STALLSENT;
 
-	mtx_assert(&(udev->bus->mtx), MA_OWNED);
+		AT91_CSR_ACK(csr_val, temp);
+		AT91_UDP_WRITE_4(sc, csr_reg, csr_val);
+	}
+	return;
+}
 
+static void
+at9100_dci_clear_stall(struct usbd_device *udev, struct usbd_pipe *pipe)
+{
 	DPRINTFN(4, "pipe=%p\n", pipe);
 
-	/* reset pipe state */
+	mtx_assert(&(udev->bus->mtx), MA_OWNED);
 
-	sc = AT9100_DCI_BUS2SC(udev->bus);
-	rst_val = (pipe->edesc->bEndpointAddress & UE_ADDR);
-	sc->sc_ep_flags[rst_val].did_multi_buffer = 0;
-	rst_val = AT91_UDP_RST_EP(rst_val);
+	/* reset endpoint */
+	at9100_dci_reset_ep(udev,
+	    (pipe->edesc->bEndpointAddress & UE_ADDR));
 
-	/*
-	 * XXX Do we need some delay between setting and clearing
-	 * reset ?
-	 */
-	AT91_UDP_WRITE_4(sc, AT91_UDP_RST, rst_val);
-	AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0);
 	return;
 }
 
@@ -1401,11 +1410,7 @@
 		AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(n), csr_val);
 
 		/* reset endpoint */
-		AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(n));
-		AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0);
-
-		/* reset "did_multi_buffer" */
-		sc->sc_ep_flags[n].did_multi_buffer = 0;
+		at9100_dci_reset_ep(udev, n);
 	}
 
 	if (cd == NULL) {
@@ -1486,10 +1491,6 @@
 
 		/* disable endpoint */
 		AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(n), csr_val);
-
-		/* reset endpoint */
-		AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(n));
-		AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0);
 	}
 
 	/* enable the interrupts we want */
@@ -1860,13 +1861,13 @@
 	.DeviceRemovable = {0},		/* port is removable */
 };
 
-#define STRING_LANG \
+#define	STRING_LANG \
   0x09, 0x04,				/* American English */
 
-#define STRING_VENDOR \
+#define	STRING_VENDOR \
   'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0
 
-#define STRING_PRODUCT \
+#define	STRING_PRODUCT \
   'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \
   'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \
   'U', 0, 'B', 0,

==== //depot/projects/usb/src/sys/dev/usb/at9100_dci.h#4 (text+ko) ====

@@ -149,7 +149,6 @@
 	uint8_t	alt_next:1;
 	uint8_t	short_pkt:1;
 	uint8_t	support_multi_buffer:1;
-	uint8_t	did_multi_buffer:1;
 	uint8_t	did_stall:1;
 };
 
@@ -182,7 +181,6 @@
 
 struct at9100_ep_flags {
 	uint8_t	fifo_bank:1;		/* hardware specific */
-	uint8_t	did_multi_buffer:1;	/* hardware specific */
 };
 
 struct at9100_flags {


More information about the p4-projects mailing list