Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 8 Nov 2009 20:54:03 +0000 (UTC)
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r199059 - in head/sys/dev/usb: . controller
Message-ID:  <200911082054.nA8Ks30X097596@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: thompsa
Date: Sun Nov  8 20:54:03 2009
New Revision: 199059
URL: http://svn.freebsd.org/changeset/base/199059

Log:
  improve support for high speed isochronous endpoints which does not run 1:1,
  but needs intervalling 1:2, 1:4 or 1:8
  
  Submitted by:	Hans Petter Selasky

Modified:
  head/sys/dev/usb/controller/ehci.c
  head/sys/dev/usb/usb_core.h
  head/sys/dev/usb/usb_transfer.c
  head/sys/dev/usb/usbdi.h

Modified: head/sys/dev/usb/controller/ehci.c
==============================================================================
--- head/sys/dev/usb/controller/ehci.c	Sun Nov  8 20:51:15 2009	(r199058)
+++ head/sys/dev/usb/controller/ehci.c	Sun Nov  8 20:54:03 2009	(r199059)
@@ -2140,7 +2140,7 @@ ehci_isoc_hs_done(ehci_softc_t *sc, stru
 	DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n",
 	    xfer, xfer->endpoint);
 
-	while (nframes--) {
+	while (nframes) {
 		if (td == NULL) {
 			panic("%s:%d: out of TD's\n",
 			    __FUNCTION__, __LINE__);
@@ -2162,21 +2162,26 @@ ehci_isoc_hs_done(ehci_softc_t *sc, stru
 
 		DPRINTFN(2, "status=0x%08x, len=%u\n", status, len);
 
-		if (*plen >= len) {
-			/*
-			 * The length is valid. NOTE: The complete
-			 * length is written back into the status
-			 * field, and not the remainder like with
-			 * other transfer descriptor types.
-			 */
-		} else {
-			/* Invalid length - truncate */
-			len = 0;
-		}
+		if (xfer->usb_smask & (1 << td_no)) {
 
-		*plen = len;
+			if (*plen >= len) {
+				/*
+				 * The length is valid. NOTE: The
+				 * complete length is written back
+				 * into the status field, and not the
+				 * remainder like with other transfer
+				 * descriptor types.
+				 */
+			} else {
+				/* Invalid length - truncate */
+				len = 0;
+			}
+
+			*plen = len;
+			plen++;
+			nframes--;
+		}
 
-		plen++;
 		td_no++;
 
 		if ((td_no == 8) || (nframes == 0)) {
@@ -2393,10 +2398,9 @@ static void
 ehci_device_intr_close(struct usb_xfer *xfer)
 {
 	ehci_softc_t *sc = EHCI_BUS2SC(xfer->xroot->bus);
-	uint8_t slot;
 
-	slot = usb_intr_schedule_adjust
-	    (xfer->xroot->udev, -(xfer->max_frame_size), xfer->usb_uframe);
+	usb_intr_schedule_adjust(xfer->xroot->udev,
+	    -(xfer->max_frame_size), xfer->usb_uframe);
 
 	sc->sc_intr_stat[xfer->qh_pos]--;
 
@@ -2722,6 +2726,28 @@ ehci_device_isoc_hs_open(struct usb_xfer
 	ehci_itd_t *td;
 	uint32_t temp;
 	uint8_t ds;
+	uint8_t slot;
+
+	slot = usb_intr_schedule_adjust(xfer->xroot->udev, xfer->max_frame_size,
+	    USB_HS_MICRO_FRAMES_MAX);
+
+	xfer->usb_uframe = slot;
+	xfer->usb_cmask = 0;
+
+	switch (usbd_xfer_get_fps_shift(xfer)) {
+	case 0:
+		xfer->usb_smask = 0xFF;
+		break;
+	case 1:
+		xfer->usb_smask = 0x55 << (slot & 1);
+		break;
+	case 2:
+		xfer->usb_smask = 0x11 << (slot & 3);
+		break;
+	default:
+		xfer->usb_smask = 0x01 << (slot & 7);
+		break;
+	}
 
 	/* initialize all TD's */
 
@@ -2765,6 +2791,10 @@ ehci_device_isoc_hs_open(struct usb_xfer
 static void
 ehci_device_isoc_hs_close(struct usb_xfer *xfer)
 {
+
+	usb_intr_schedule_adjust(xfer->xroot->udev,
+	    -(xfer->max_frame_size), xfer->usb_uframe);
+
 	ehci_device_done(xfer, USB_ERR_CANCELLED);
 }
 
@@ -2854,7 +2884,7 @@ ehci_device_isoc_hs_enter(struct usb_xfe
 
 	xfer->qh_pos = xfer->endpoint->isoc_next;
 
-	while (nframes--) {
+	while (nframes) {
 		if (td == NULL) {
 			panic("%s:%d: out of TD's\n",
 			    __FUNCTION__, __LINE__);
@@ -2874,13 +2904,21 @@ ehci_device_isoc_hs_enter(struct usb_xfe
 #endif
 			*plen = xfer->max_frame_size;
 		}
-		status = (EHCI_ITD_SET_LEN(*plen) |
-		    EHCI_ITD_ACTIVE |
-		    EHCI_ITD_SET_PG(0));
-		td->itd_status[td_no] = htohc32(sc, status);
-		itd_offset[td_no] = buf_offset;
-		buf_offset += *plen;
-		plen++;
+
+		if (xfer->usb_smask & (1 << td_no)) {
+			status = (EHCI_ITD_SET_LEN(*plen) |
+			    EHCI_ITD_ACTIVE |
+			    EHCI_ITD_SET_PG(0));
+			td->itd_status[td_no] = htohc32(sc, status);
+			itd_offset[td_no] = buf_offset;
+			buf_offset += *plen;
+			plen++;
+			nframes --;
+		} else {
+			td->itd_status[td_no] = 0;	/* not active */
+			itd_offset[td_no] = buf_offset;
+		}
+
 		td_no++;
 
 		if ((td_no == 8) || (nframes == 0)) {
@@ -2937,7 +2975,7 @@ ehci_device_isoc_hs_enter(struct usb_xfe
 			}
 			/* set IOC bit if we are complete */
 			if (nframes == 0) {
-				td->itd_status[7] |= htohc32(sc, EHCI_ITD_IOC);
+				td->itd_status[td_no - 1] |= htohc32(sc, EHCI_ITD_IOC);
 			}
 			usb_pc_cpu_flush(td->page_cache);
 #if USB_DEBUG
@@ -3583,7 +3621,8 @@ ehci_xfer_setup(struct usb_setup_params 
 
 		usbd_transfer_setup_sub(parm);
 
-		nitd = (xfer->nframes + 7) / 8;
+		nitd = ((xfer->nframes + 7) / 8) <<
+		    usbd_xfer_get_fps_shift(xfer);
 
 	} else {
 

Modified: head/sys/dev/usb/usb_core.h
==============================================================================
--- head/sys/dev/usb/usb_core.h	Sun Nov  8 20:51:15 2009	(r199058)
+++ head/sys/dev/usb/usb_core.h	Sun Nov  8 20:54:03 2009	(r199059)
@@ -165,6 +165,7 @@ struct usb_xfer {
 	uint8_t	usb_cmask;
 	uint8_t	usb_uframe;
 	uint8_t	usb_state;
+	uint8_t fps_shift;		/* down shift of FPS, 0..3 */
 
 	usb_error_t error;
 

Modified: head/sys/dev/usb/usb_transfer.c
==============================================================================
--- head/sys/dev/usb/usb_transfer.c	Sun Nov  8 20:51:15 2009	(r199058)
+++ head/sys/dev/usb/usb_transfer.c	Sun Nov  8 20:54:03 2009	(r199059)
@@ -416,9 +416,15 @@ usbd_transfer_setup_sub(struct usb_setup
 		case USB_SPEED_LOW:
 		case USB_SPEED_FULL:
 			frame_limit = USB_MAX_FS_ISOC_FRAMES_PER_XFER;
+			xfer->fps_shift = 0;
 			break;
 		default:
 			frame_limit = USB_MAX_HS_ISOC_FRAMES_PER_XFER;
+			xfer->fps_shift = edesc->bInterval;
+			if (xfer->fps_shift > 0)
+				xfer->fps_shift--;
+			if (xfer->fps_shift > 3)
+				xfer->fps_shift = 3;
 			break;
 		}
 
@@ -1826,6 +1832,23 @@ usbd_xfer_get_frame(struct usb_xfer *xfe
 	return (&xfer->frbuffers[frindex]);
 }
 
+/*------------------------------------------------------------------------*
+ *	usbd_xfer_get_fps_shift
+ *
+ * The following function is only useful for isochronous transfers. It
+ * returns how many times the frame execution rate has been shifted
+ * down.
+ *
+ * Return value:
+ * Success: 0..3
+ * Failure: 0
+ *------------------------------------------------------------------------*/
+uint8_t
+usbd_xfer_get_fps_shift(struct usb_xfer *xfer)
+{
+	return (xfer->fps_shift);
+}
+
 usb_frlength_t
 usbd_xfer_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex)
 {

Modified: head/sys/dev/usb/usbdi.h
==============================================================================
--- head/sys/dev/usb/usbdi.h	Sun Nov  8 20:51:15 2009	(r199058)
+++ head/sys/dev/usb/usbdi.h	Sun Nov  8 20:54:03 2009	(r199059)
@@ -478,6 +478,7 @@ void	usbd_xfer_set_frame_offset(struct u
 usb_frlength_t usbd_xfer_max_len(struct usb_xfer *xfer);
 usb_frlength_t usbd_xfer_max_framelen(struct usb_xfer *xfer);
 usb_frcount_t usbd_xfer_max_frames(struct usb_xfer *xfer);
+uint8_t	usbd_xfer_get_fps_shift(struct usb_xfer *xfer);
 usb_frlength_t usbd_xfer_frame_len(struct usb_xfer *xfer,
 	    usb_frcount_t frindex);
 void	usbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200911082054.nA8Ks30X097596>