PERFORCE change 131636 for review

Hans Petter Selasky hselasky at FreeBSD.org
Tue Dec 25 15:48:54 PST 2007


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

Change 131636 by hselasky at hselasky_laptop001 on 2007/12/25 23:48:19

	
	This commit is device side related.
	
	Fix the AT91 series full speed USB Device Controller driver so
	that it works !
	
	Some more testing remains. At least the Control Endpoint is
	working excellent.
	
	o Reading string descriptor test yielded:
	  5000 bytes per second at 154 transactions per second.

Affected files ...

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

Differences ...

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

@@ -38,8 +38,11 @@
  */
 
 /*
- * NOTE: the "fifo_bank" is not reset in hardware when the endpoint is
+ * NOTE: The "fifo_bank" is not reset in hardware when the endpoint is
  * reset !
+ *
+ * NOTE: When the chip detects BUS-reset it will also reset the
+ * endpoints, Function-address and more.
  */
 
 #include <sys/param.h>
@@ -109,7 +112,8 @@
  */
 #define	AT91_CSR_ACK(csr, what) do {		\
   (csr) &= ~((AT91_UDP_CSR_FORCESTALL|		\
-	      AT91_UDP_CSR_TXPKTRDY) ^ (what));	\
+	      AT91_UDP_CSR_TXPKTRDY|		\
+	      AT91_UDP_CSR_RXBYTECNT) ^ (what));\
   (csr) |= ((AT91_UDP_CSR_RX_DATA_BK0|		\
 	     AT91_UDP_CSR_RX_DATA_BK1|		\
 	     AT91_UDP_CSR_TXCOMP|		\
@@ -197,6 +201,8 @@
 	if (sc->sc_flags.clocks_off &&
 	    sc->sc_flags.port_powered) {
 
+		DPRINTFN(4, "\n");
+
 		if (sc->sc_clocks_on) {
 			(sc->sc_clocks_on) (sc->sc_clocks_arg);
 		}
@@ -213,6 +219,8 @@
 {
 	if (!sc->sc_flags.clocks_off) {
 
+		DPRINTFN(4, "\n");
+
 		/* disable Transceiver */
 		AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS);
 
@@ -227,6 +235,8 @@
 static void
 at9100_dci_pull_up(struct at9100_dci_softc *sc)
 {
+	/* pullup D+, if possible */
+
 	if (!sc->sc_flags.d_pulled_up &&
 	    sc->sc_flags.port_powered) {
 		sc->sc_flags.d_pulled_up = 1;
@@ -238,6 +248,8 @@
 static void
 at9100_dci_pull_down(struct at9100_dci_softc *sc)
 {
+	/* pulldown D+, if possible */
+
 	if (sc->sc_flags.d_pulled_up) {
 		sc->sc_flags.d_pulled_up = 0;
 		(sc->sc_pull_down) (sc->sc_pull_arg);
@@ -265,66 +277,106 @@
 	return;
 }
 
+static void
+at9100_dci_set_address(struct at9100_dci_softc *sc, uint8_t addr)
+{
+	DPRINTFN(4, "addr=%d\n", addr);
+
+	AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, addr |
+	    AT91_UDP_FADDR_EN);
+
+	return;
+}
+
 static uint8_t
 at9100_dci_setup_rx(struct at9100_dci_td *td)
 {
-	struct usbd_page_search buf_res;
+	struct at9100_dci_softc *sc;
+	usb_device_request_t req;
 	uint32_t csr;
+	uint32_t temp;
 	uint16_t count;
 
 	/* read out FIFO status */
 	csr = bus_space_read_4(td->io_tag, td->io_hdl,
 	    td->status_reg);
 
-	DPRINTFN(4, "csr=0x%08x\n", csr);
+	DPRINTFN(4, "csr=0x%08x rem=%d\n", csr, td->remainder);
+
+	temp = csr;
+	temp &= (AT91_UDP_CSR_RX_DATA_BK0 |
+	    AT91_UDP_CSR_RX_DATA_BK1 |
+	    AT91_UDP_CSR_STALLSENT |
+	    AT91_UDP_CSR_RXSETUP |
+	    AT91_UDP_CSR_TXCOMP);
 
-	/* check status */
 	if (!(csr & AT91_UDP_CSR_RXSETUP)) {
-		return (1);		/* not complete */
+		/* abort any ongoing transfer */
+		if (!td->did_stall) {
+			DPRINTFN(4, "stalling\n");
+			temp |= AT91_UDP_CSR_FORCESTALL;
+			td->did_stall = 1;
+		}
+		goto not_complete;
 	}
 	/* get the packet byte count */
 	count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16;
 
 	/* verify data length */
 	if (count != td->remainder) {
-		DPRINTFN(0, "Invalid SETUP packet "
+		DPRINTFN(-1, "Invalid SETUP packet "
+		    "length, %d bytes\n", count);
+		goto not_complete;
+	}
+	if (count != sizeof(req)) {
+		DPRINTFN(-1, "Unsupported SETUP packet "
 		    "length, %d bytes\n", count);
-		td->error = 1;
-		return (0);		/* we are complete */
+		goto not_complete;
 	}
-	while (count > 0) {
-		usbd_get_page(td->pc, td->offset, &buf_res);
+	/* receive data */
+	bus_space_read_multi_1(td->io_tag, td->io_hdl,
+	    td->fifo_reg, (void *)&req, sizeof(req));
+
+	/* copy data into real buffer */
+	usbd_copy_in(td->pc, 0, &req, sizeof(req));
+
+	td->offset = sizeof(req);
+	td->remainder = 0;
 
-		/* get correct length */
-		if (buf_res.length > count) {
-			buf_res.length = count;
-		}
-		/* receive data */
-		bus_space_read_multi_1(td->io_tag, td->io_hdl,
-		    td->fifo_reg, buf_res.buffer, buf_res.length);
+	/* get pointer to softc */
+	sc = td->pc->xfer->usb_sc;
 
-		if (td->offset == 0) {
-			/* sneak peek the endpoint direction */
-			if ((*(uint8_t *)(buf_res.buffer)) & UE_DIR_IN) {
-				csr |= AT91_UDP_CSR_DIR;
-			} else {
-				csr &= ~AT91_UDP_CSR_DIR;
-			}
-		}
-		/* update counters */
-		count -= buf_res.length;
-		td->offset += buf_res.length;
-		td->remainder -= buf_res.length;
+	/* sneak peek the set address */
+	if ((req.bmRequestType == UT_WRITE_DEVICE) &&
+	    (req.bRequest == UR_SET_ADDRESS)) {
+		sc->sc_dv_addr = req.wValue[0] & 0x7F;
+	} else {
+		sc->sc_dv_addr = 0xFF;
 	}
 
-	/* clear RXSETUP */
-	AT91_CSR_ACK(csr, AT91_UDP_CSR_RXSETUP);
+	/* sneak peek the endpoint direction */
+	if (req.bmRequestType & UE_DIR_IN) {
+		csr |= AT91_UDP_CSR_DIR;
+	} else {
+		csr &= ~AT91_UDP_CSR_DIR;
+	}
 
-	/* write command */
+	/* write the direction of the control transfer */
+	AT91_CSR_ACK(csr, temp);
 	bus_space_write_4(td->io_tag, td->io_hdl,
 	    td->status_reg, csr);
+	return (0);			/* complete */
+
+not_complete:
+	/* clear interrupts, if any */
+	if (temp) {
+		DPRINTFN(4, "clearing 0x%08x\n", temp);
+		AT91_CSR_ACK(csr, temp);
+		bus_space_write_4(td->io_tag, td->io_hdl,
+		    td->status_reg, csr);
+	}
+	return (1);			/* not complete */
 
-	return (0);			/* complete */
 }
 
 static uint8_t
@@ -332,93 +384,122 @@
 {
 	struct usbd_page_search buf_res;
 	uint32_t csr;
+	uint32_t temp;
 	uint16_t count;
 	uint8_t to;
 
 	to = 2;				/* don't loop forever! */
 
 	/* check if any of the FIFO banks have data */
-	do {
-		/* read out FIFO status */
-		csr = bus_space_read_4(td->io_tag, td->io_hdl,
-		    td->status_reg);
+repeat:
+	/* read out FIFO status */
+	csr = bus_space_read_4(td->io_tag, td->io_hdl,
+	    td->status_reg);
 
-		DPRINTFN(4, "csr=0x%08x\n", csr);
+	DPRINTFN(4, "csr=0x%08x\n", csr);
 
-		/* check status */
-		if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 |
-		    AT91_UDP_CSR_RX_DATA_BK1))) {
-			break;
+	if (csr & AT91_UDP_CSR_RXSETUP) {
+		if (td->remainder == 0) {
+			/*
+			 * We are actually complete and have
+			 * received the next SETUP
+			 */
+			DPRINTFN(4, "faking complete\n");
+			return (0);	/* complete */
 		}
-		/* get the packet byte count */
-		count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16;
+		/*
+	         * USB Host Aborted the transfer.
+	         */
+		td->error = 1;
+		return (0);		/* complete */
+	}
+	/* Make sure that "STALLSENT" gets cleared */
+	temp = csr;
+	temp &= AT91_UDP_CSR_STALLSENT;
 
-		/* verify the packet byte count */
-		if (count != td->max_packet_size) {
-			if (count < td->max_packet_size) {
-				/* we have a short packet */
-				td->short_pkt = 1;
-			} else {
-				/* invalid USB packet */
-				td->error = 1;
-				return (0);	/* we are complete */
-			}
+	/* check status */
+	if (!(csr & (AT91_UDP_CSR_RX_DATA_BK0 |
+	    AT91_UDP_CSR_RX_DATA_BK1))) {
+		if (temp) {
+			/* write command */
+			AT91_CSR_ACK(csr, temp);
+			bus_space_write_4(td->io_tag, td->io_hdl,
+			    td->status_reg, csr);
 		}
-		/* verify the packet byte count */
-		if (count > td->remainder) {
+		return (1);		/* not complete */
+	}
+	/* get the packet byte count */
+	count = (csr & AT91_UDP_CSR_RXBYTECNT) >> 16;
+
+	/* verify the packet byte count */
+	if (count != td->max_packet_size) {
+		if (count < td->max_packet_size) {
+			/* we have a short packet */
+			td->short_pkt = 1;
+		} else {
 			/* invalid USB packet */
 			td->error = 1;
 			return (0);	/* we are complete */
 		}
-		while (count > 0) {
-			usbd_get_page(td->pc, td->offset, &buf_res);
+	}
+	/* verify the packet byte count */
+	if (count > td->remainder) {
+		/* invalid USB packet */
+		td->error = 1;
+		return (0);		/* we are complete */
+	}
+	while (count > 0) {
+		usbd_get_page(td->pc, td->offset, &buf_res);
 
-			/* get correct length */
-			if (buf_res.length > count) {
-				buf_res.length = count;
-			}
-			/* receive data */
-			bus_space_read_multi_1(td->io_tag, td->io_hdl,
-			    td->fifo_reg, buf_res.buffer, buf_res.length);
+		/* get correct length */
+		if (buf_res.length > count) {
+			buf_res.length = count;
+		}
+		/* receive data */
+		bus_space_read_multi_1(td->io_tag, td->io_hdl,
+		    td->fifo_reg, buf_res.buffer, buf_res.length);
 
-			/* update counters */
-			count -= buf_res.length;
-			td->offset += buf_res.length;
-			td->remainder -= buf_res.length;
-		}
+		/* update counters */
+		count -= buf_res.length;
+		td->offset += buf_res.length;
+		td->remainder -= buf_res.length;
+	}
 
-		/* clear status bits */
-		if (td->support_multi_buffer) {
-			if (td->fifo_bank) {
-				td->fifo_bank = 0;
-				AT91_CSR_ACK(csr, AT91_UDP_CSR_RX_DATA_BK1);
-			} else {
-				td->fifo_bank = 1;
-				AT91_CSR_ACK(csr, AT91_UDP_CSR_RX_DATA_BK0);
-			}
+	/* clear status bits */
+	if (td->support_multi_buffer) {
+		if (td->fifo_bank) {
+			td->fifo_bank = 0;
+			temp |= AT91_UDP_CSR_RX_DATA_BK1;
 		} else {
-			AT91_CSR_ACK(csr, AT91_UDP_CSR_RX_DATA_BK0 |
-			    AT91_UDP_CSR_RX_DATA_BK1);
+			td->fifo_bank = 1;
+			temp |= AT91_UDP_CSR_RX_DATA_BK0;
 		}
+	} else {
+		temp |= (AT91_UDP_CSR_RX_DATA_BK0 |
+		    AT91_UDP_CSR_RX_DATA_BK1);
+	}
 
-		/* write command */
-		bus_space_write_4(td->io_tag, td->io_hdl,
-		    td->status_reg, csr);
+	/* write command */
+	AT91_CSR_ACK(csr, temp);
+	bus_space_write_4(td->io_tag, td->io_hdl,
+	    td->status_reg, csr);
 
-		/*
-		 * NOTE: We may have to delay a little bit before
-		 * proceeding after clearing the DATA_BK bits.
-		 */
+	/*
+	 * NOTE: We may have to delay a little bit before
+	 * proceeding after clearing the DATA_BK bits.
+	 */
 
-		/* check if we are complete */
-		if (td->remainder == 0) {
-			if (td->short_pkt) {
-				/* we are complete */
-				return (0);
-			}
-			/* else need to receive a zero length packet */
+	/* check if we are complete */
+	if (td->remainder == 0) {
+		if (td->short_pkt) {
+			/* we are complete */
+			return (0);
 		}
-	} while (--to);
+		/* else need to receive a zero length packet */
+	}
+	if (--to) {
+		goto repeat;
+	}
 	return (1);			/* not complete */
 }
 
@@ -427,70 +508,94 @@
 {
 	struct usbd_page_search buf_res;
 	uint32_t csr;
+	uint32_t temp;
 	uint16_t count;
+	uint8_t to;
+
+	to = 2;				/* don't loop forever! */
+
+repeat:
 
 	/* read out FIFO status */
 	csr = bus_space_read_4(td->io_tag, td->io_hdl,
 	    td->status_reg);
 
-	DPRINTFN(4, "csr=0x%08x\n", csr);
+	DPRINTFN(4, "csr=0x%08x rem=%d\n", csr, td->remainder);
+
+	if (csr & AT91_UDP_CSR_RXSETUP) {
+		/*
+	         * The current transfer was aborted
+	         * by the USB Host
+	         */
+		td->error = 1;
+		return (0);		/* complete */
+	}
+	/* Make sure that "STALLSENT" gets cleared */
+	temp = csr;
+	temp &= AT91_UDP_CSR_STALLSENT;
 
-	/* check status */
 	if (csr & AT91_UDP_CSR_TXPKTRDY) {
-		return (1);		/* not complete - wait for interrupt */
-	}
-	/* clear TXCOMP and set TXPKTRDY */
-	AT91_CSR_ACK(csr, AT91_UDP_CSR_TXCOMP |
-	    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;
 
-	while (1) {
-		count = td->max_packet_size;
-		if (td->remainder < count) {
-			/* we have a short packet */
-			td->short_pkt = 1;
-			count = td->remainder;
+		} else 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 */
 		}
-		while (count > 0) {
+	} else {
+		/* clear TXCOMP and set TXPKTRDY */
+		temp |= (AT91_UDP_CSR_TXCOMP |
+		    AT91_UDP_CSR_TXPKTRDY);
+	}
 
-			usbd_get_page(td->pc, td->offset, &buf_res);
+	count = td->max_packet_size;
+	if (td->remainder < count) {
+		/* we have a short packet */
+		td->short_pkt = 1;
+		count = td->remainder;
+	}
+	while (count > 0) {
 
-			/* get correct length */
-			if (buf_res.length > count) {
-				buf_res.length = count;
-			}
-			/* transmit data */
-			bus_space_write_multi_1(td->io_tag, td->io_hdl,
-			    td->fifo_reg, buf_res.buffer, buf_res.length);
+		usbd_get_page(td->pc, td->offset, &buf_res);
 
-			/* update counters */
-			count -= buf_res.length;
-			td->offset += buf_res.length;
-			td->remainder -= buf_res.length;
+		/* get correct length */
+		if (buf_res.length > count) {
+			buf_res.length = count;
 		}
+		/* transmit data */
+		bus_space_write_multi_1(td->io_tag, td->io_hdl,
+		    td->fifo_reg, buf_res.buffer, buf_res.length);
+
+		/* update counters */
+		count -= buf_res.length;
+		td->offset += buf_res.length;
+		td->remainder -= buf_res.length;
+	}
 
-		/* write command */
-		bus_space_write_4(td->io_tag, td->io_hdl,
-		    td->status_reg, csr);
+	/* write command */
+	AT91_CSR_ACK(csr, temp);
+	bus_space_write_4(td->io_tag, td->io_hdl,
+	    td->status_reg, csr);
 
-		/* check remainder */
-		if (td->remainder == 0) {
-			if (td->short_pkt) {
-				return (0);	/* complete */
-			}
-			/* else we need to transmit a short packet */
+	/* check remainder */
+	if (td->remainder == 0) {
+		if (td->short_pkt) {
+			return (0);	/* complete */
 		}
-		/* check for double buffering */
-		if (!td->support_multi_buffer) {
-			break;
-		}
-		/* check if we can do a multi buffer */
-		if (td->did_multi_buffer) {
-			break;
-		}
-		td->did_multi_buffer = 1;
-
-		/* only set TXPKTRDY next time  */
-		AT91_CSR_ACK(csr, AT91_UDP_CSR_TXPKTRDY);
+		/* else we need to transmit a short packet */
+	}
+	if (--to) {
+		goto repeat;
 	}
 	return (1);			/* not complete */
 }
@@ -498,8 +603,11 @@
 static uint8_t
 at9100_dci_data_tx_sync(struct at9100_dci_td *td)
 {
-	struct usbd_xfer *xfer;
+	struct at9100_dci_softc *sc;
 	uint32_t csr;
+	uint32_t temp;
+
+repeat:
 
 	/* read out FIFO status */
 	csr = bus_space_read_4(td->io_tag, td->io_hdl,
@@ -507,26 +615,49 @@
 
 	DPRINTFN(4, "csr=0x%08x\n", csr);
 
+	if (csr & AT91_UDP_CSR_RXSETUP) {
+		DPRINTFN(4, "faking complete\n");
+		/* Race condition */
+		return (0);		/* complete */
+	}
+	temp = csr;
+	temp &= (AT91_UDP_CSR_STALLSENT |
+	    AT91_UDP_CSR_TXCOMP);
+
 	/* check status */
 	if (csr & AT91_UDP_CSR_TXPKTRDY) {
-		return (1);		/* not complete - wait for interrupt */
+		goto not_complete;
+	}
+	if (!(csr & AT91_UDP_CSR_TXCOMP)) {
+		goto not_complete;
+	}
+	sc = td->pc->xfer->usb_sc;
+	if (sc->sc_dv_addr != 0xFF) {
+		/*
+		 * The AT91 has a special requirement with regard to
+		 * setting the address and that is to write the new
+		 * address before clearing TXCOMP:
+		 */
+		at9100_dci_set_address(sc, sc->sc_dv_addr);
 	}
-	if (csr & AT91_UDP_CSR_TXCOMP) {
+	/* write command */
+	AT91_CSR_ACK(csr, temp);
+	bus_space_write_4(td->io_tag, td->io_hdl,
+	    td->status_reg, csr);
 
-		/* clear TXCOMP */
-		AT91_CSR_ACK(csr, AT91_UDP_CSR_TXCOMP);
+	if (td->did_multi_buffer) {
+		/* wait for the second and final interrupt */
+		td->did_multi_buffer = 0;
+		goto repeat;
+	}
+	return (0);			/* complete */
 
+not_complete:
+	if (temp) {
 		/* write command */
+		AT91_CSR_ACK(csr, temp);
 		bus_space_write_4(td->io_tag, td->io_hdl,
 		    td->status_reg, csr);
-
-		if (!td->did_multi_buffer) {
-			/* restore double buffer flag */
-			xfer = td->pc->xfer;
-			return (0);	/* complete */
-		}
-		/* wait for the second and final interrupt */
-		td->did_multi_buffer = 0;
 	}
 	return (1);			/* not complete */
 }
@@ -538,6 +669,8 @@
 	struct at9100_dci_td *td;
 	uint8_t temp;
 
+	DPRINTFN(8, "\n");
+
 	td = xfer->td_transfer_cache;
 	while (1) {
 		if ((td->func) (td)) {
@@ -578,7 +711,7 @@
 
 done:
 	sc = xfer->usb_sc;
-	temp = (xfer->pipe->edesc->bEndpointAddress & UE_ADDR);
+	temp = (xfer->endpoint & UE_ADDR);
 
 	/* update FIFO bank flag and multi buffer */
 	if (td->fifo_bank) {
@@ -661,17 +794,22 @@
 	mtx_lock(&(sc->sc_bus.mtx));
 
 	status = AT91_UDP_READ_4(sc, AT91_UDP_ISR);
+	status &= AT91_UDP_INT_DEFAULT;
+
+	if (!status) {
+		mtx_unlock(&(sc->sc_bus.mtx));
+		return;
+	}
+	/* acknowledge interrupts */
 
+	AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status);
+
 	/* check for any bus state change interrupts */
 
 	if (status & AT91_UDP_INT_BUS) {
 
 		DPRINTFN(4, "real bus interrupt 0x%08x\n", status);
 
-		/* acknowledge interrupts */
-
-		AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, status & AT91_UDP_INT_BUS);
-
 		if (status & AT91_UDP_INT_END_BR) {
 			sc->sc_flags.status_bus_reset = 1;
 			sc->sc_flags.status_suspend = 0;
@@ -732,6 +870,7 @@
 	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;
 	return;
@@ -753,8 +892,9 @@
 
 	temp.max_frame_size = xfer->max_frame_size;
 
-	xfer->td_transfer_first = xfer->td_start;
-	xfer->td_transfer_cache = xfer->td_start;
+	td = xfer->td_start[0];
+	xfer->td_transfer_first = td;
+	xfer->td_transfer_cache = td;
 
 	/* setup temp */
 
@@ -762,9 +902,9 @@
 	temp.td_next = xfer->td_start[0];
 	temp.setup_alt_next = xfer->flags_int.short_frames_ok;
 	temp.offset = 0;
-	temp.pc = NULL;
 
-	need_sync = 0;
+	sc = xfer->usb_sc;
+	ep_no = (xfer->endpoint & UE_ADDR);
 
 	/* check if we should prepend a setup message */
 
@@ -789,10 +929,14 @@
 			need_sync = 1;
 		} else {
 			temp.func = &at9100_dci_data_rx;
+			need_sync = 0;
 		}
+
+		/* setup "pc" pointer */
+		temp.pc = xfer->frbuffers + x;
+	} else {
+		need_sync = 0;
 	}
-	/* always setup a valid "pc" pointer */
-	temp.pc = xfer->frbuffers + x;
 
 	while (x != xfer->nframes) {
 
@@ -828,6 +972,19 @@
 		}
 	}
 
+	/* always setup a valid "pc" pointer for status and sync */
+	temp.pc = xfer->frbuffers + 0;
+
+	/* check if we need to sync */
+	if (need_sync && !xfer->flags_int.isochronous_xfr) {
+
+		/* we need a SYNC point after TX */
+		temp.func = &at9100_dci_data_tx_sync;
+		temp.len = 0;
+		temp.short_pkt = 0;
+
+		at9100_dci_setup_standard_chain_sub(&temp);
+	}
 	/* check if we should append a status stage */
 
 	if (xfer->flags_int.control_xfr &&
@@ -839,6 +996,7 @@
 		 */
 		if (xfer->endpoint & UE_DIR_IN) {
 			temp.func = &at9100_dci_data_rx;
+			need_sync = 0;
 		} else {
 			temp.func = &at9100_dci_data_tx;
 			need_sync = 1;
@@ -847,27 +1005,19 @@
 		temp.short_pkt = 0;
 
 		at9100_dci_setup_standard_chain_sub(&temp);
-	}
-	if (need_sync && !xfer->flags_int.isochronous_xfr) {
+		if (need_sync) {
+			/* we need a SYNC point after TX */
+			temp.func = &at9100_dci_data_tx_sync;
+			temp.len = 0;
+			temp.short_pkt = 0;
 
-		/* we need a SYNC point */
-		temp.func = &at9100_dci_data_tx_sync;
-		temp.len = 0;
-		temp.short_pkt = 0;
-
-		at9100_dci_setup_standard_chain_sub(&temp);
-
-		td = temp.td;
-	} else {
-		td = temp.td;
+			at9100_dci_setup_standard_chain_sub(&temp);
+		}
 	}
-
 	/* must have at least one frame! */
+	td = temp.td;
 	xfer->td_transfer_last = td;
 
-	sc = xfer->usb_sc;
-	ep_no = (xfer->pipe->edesc->bEndpointAddress & UE_ADDR);
-
 	/* setup the correct fifo bank */
 	if (sc->sc_ep_flags[ep_no].fifo_bank) {
 		td = xfer->td_transfer_first;
@@ -904,8 +1054,23 @@
 static void
 at9100_dci_start_standard_chain(struct usbd_xfer *xfer)
 {
+	DPRINTFN(8, "\n");
+
 	/* poll one time */
 	if (at9100_dci_xfer_do_fifo(xfer)) {
+
+		struct at9100_dci_softc *sc = xfer->usb_sc;
+		uint8_t ep_no = xfer->endpoint & UE_ADDR;
+
+		/*
+		 * Only enable the endpoint interrupt when we are actually
+		 * waiting for data, hence we are dealing with level
+		 * triggered interrupts !
+		 */
+		AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_EP(ep_no));
+
+		DPRINTFN(14, "enable interrupts on endpoint %d\n", ep_no);
+
 		/* queue up transfer on interrupt list */
 		usbd_transfer_intr_enqueue(xfer);
 
@@ -916,7 +1081,10 @@
 			    (void *)&at9100_dci_timeout, xfer);
 		}
 	} else {
-		/* queue callback for execution */
+		/*
+		 * The USB transfer is complete. Queue callback for
+		 * execution:
+		 */
 		usbd_callback_wrapper(xfer, NULL,
 		    USBD_CONTEXT_CALLBACK);
 	}
@@ -929,6 +1097,8 @@
 {
 	struct at9100_dci_softc *sc = xfer->usb_sc;
 
+	DPRINTFN(8, "\n");
+
 	mtx_assert(&sc->sc_bus.mtx, MA_OWNED);
 
 	if (std->state != USBD_STD_ROOT_TR_PRE_DATA) {
@@ -956,6 +1126,8 @@
 	uint32_t len;
 	uint8_t error;
 
+	DPRINTFN(8, "\n");
+
 	td = xfer->td_transfer_cache;
 
 	do {
@@ -1064,11 +1236,22 @@
 static void
 at9100_dci_device_done(struct usbd_xfer *xfer, usbd_status_t error)
 {
+	struct at9100_dci_softc *sc = xfer->usb_sc;
+	uint8_t ep_no;
+
 	mtx_assert(&sc->sc_bus.mtx, MA_OWNED);
 
 	DPRINTFN(1, "xfer=%p, pipe=%p, error=%d\n",
 	    xfer, xfer->pipe, error);
 
+	if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
+		ep_no = (xfer->endpoint & UE_ADDR);
+
+		/* disable endpoint interrupt */
+		AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, AT91_UDP_INT_EP(ep_no));
+
+		DPRINTFN(14, "disable interrupts on endpoint %d\n", ep_no);
+	}
 	/* dequeue transfer and start next transfer */
 	usbd_transfer_dequeue(xfer, error);
 	return;
@@ -1082,6 +1265,10 @@
 	uint32_t csr_val;
 	uint8_t csr_reg;
 
+	mtx_assert(&(udev->bus->mtx), MA_OWNED);
+
+	DPRINTFN(4, "\n");
+
 	if (xfer) {
 		/* cancel any ongoing transfers */
 		at9100_dci_device_done(xfer, USBD_STALLED);
@@ -1102,6 +1289,10 @@
 	struct at9100_dci_softc *sc;
 	uint32_t rst_val;
 
+	mtx_assert(&(udev->bus->mtx), MA_OWNED);
+
+	DPRINTFN(4, "\n");
+
 	/* reset pipe state */
 
 	sc = AT9100_DCI_BUS2SC(udev->bus);
@@ -1135,6 +1326,12 @@
 	uint8_t ep_type;
 	uint8_t ep_dir;
 
+	mtx_assert(&(udev->bus->mtx), MA_OWNED);
+
+	if (udev->flags.usb_mode == USB_MODE_HOST) {
+		/* this is the Root HUB */
+		return;
+	}
 	sc = AT9100_DCI_BUS2SC(udev->bus);
 	AT91_CSR_ACK(csr_val, 0);
 
@@ -1196,19 +1393,6 @@
 	return;
 }
 
-static void
-at9100_dci_set_address(struct usbd_device *udev, uint8_t addr)
-{
-	struct at9100_dci_softc *sc;
-
-	sc = AT9100_DCI_BUS2SC(udev->bus);
-
-	AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, (addr & 0x7F) |
-	    AT91_UDP_FADDR_EN);
-
-	return;
-}
-
 usbd_status_t
 at9100_dci_init(struct at9100_dci_softc *sc)
 {
@@ -1223,14 +1407,25 @@
 
 	mtx_lock(&(sc->sc_bus.mtx));
 
+	/* turn on clocks */
+
+	if (sc->sc_clocks_on) {
+		(sc->sc_clocks_on) (sc->sc_clocks_arg);
+	}
+	/* wait a little for things to stabilise */
+	DELAY(1000);
+
+	/* enable Transceiver */
+	AT91_UDP_WRITE_4(sc, AT91_UDP_TXVC, 0);
+
+	/* disable and clear all interrupts */
+	AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF);
+	AT91_UDP_WRITE_4(sc, AT91_UDP_ICR, 0xFFFFFFFF);
+
 	csr_val = 0;
 	AT91_CSR_ACK(csr_val, 0);
 
-	/* reset device address */
-
-	AT91_UDP_WRITE_4(sc, AT91_UDP_FADDR, 0);
-
-	/* disable everything */
+	/* disable and reset all endpoints */
 
 	for (n = 0; n != AT91_UDP_EP_MAX; n++) {
 
@@ -1242,25 +1437,18 @@
 		AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0);
 	}
 
-	/* enable control endpoint */
+	/* enable the interrupts we want */
 
-	csr_val |= (AT91_UDP_CSR_ET_CTRL | AT91_UDP_CSR_EPEDS);
+	AT91_UDP_WRITE_4(sc, AT91_UDP_IER, AT91_UDP_INT_BUS);
 
-	AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(0), csr_val);
-
-	/* disable all interrupts */
-
-	AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, 0xFFFFFFFF);
+	/* turn off clocks */
 
-	/* enable the interrupts we want */
-
-	AT91_UDP_WRITE_4(sc, AT91_UDP_IDR, AT91_UDP_INT_DEFAULT);
-
 	at9100_dci_clocks_off(sc);
 
 	mtx_unlock(&(sc->sc_bus.mtx));
 
 	/* catch any lost interrupts */
+
 	at9100_dci_do_poll(&(sc->sc_bus));
 
 	return (0);			/* success */
@@ -1604,13 +1792,12 @@
   0x09, 0x04,				/* American English */
 
 #define STRING_VENDOR \
-  'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L'
+  'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0
 
 #define STRING_PRODUCT \
-  'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0, \
-  ' ', 0, 'D', 0, 'e', 0, 'v', 0, 'i', 0, \
-  'c', 0, 'e', 0, 'R', 0, 'o', 0, 'o', 0, \
-  't', 0, ' ', 0, 'H', 0, 'U', 0, 'B', 0,
+  'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \
+  'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \
+  'U', 0, 'B', 0,
 
 USB_MAKE_STRING_DESC(STRING_LANG, at9100_dci_langtab);
 USB_MAKE_STRING_DESC(STRING_VENDOR, at9100_dci_vendor);
@@ -1885,7 +2072,7 @@
 	if (value & 0xFF00) {
 		goto tr_stalled;
 	}
-	sc->sc_addr = value;
+	sc->sc_rt_addr = value;
 	goto tr_valid;

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list