PERFORCE change 123022 for review

Hans Petter Selasky hselasky at FreeBSD.org
Fri Jul 6 16:04:05 UTC 2007


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

Change 123022 by hselasky at hselasky_mini_itx on 2007/07/06 16:04:03

	       Hi,
	
	       My main hacking location did not have internet access, so here
	       is a multiple changes submit again. Summed up:
	
	       1) Added a completely new FULL speed over HIGH speed USB HUB
	       bandwidth allocator. See the "usbd_fs_isoc_xxx()" functions in
	       "usb_subr.c". Finally it should be possible to connect several
	       FULL speed isochronous devices to a HIGH speed USB HUB at the
	       same time, without problems. NOTE: The sum of the isochronous
	       bandwidth must not exceed 6.0Mbit/s per HS USB HUB!  This is
	       because I have made a simple hack and reserved 3.0 Mbit/s for
	       interrupt endpoints so that the scheduling becomes extremely
	       fast and simple. The bandwidth distribution is tunable through
	the "USB_FS_ISOC_UFRAME_MAX" definition in "usb.h".
	
	       2) Fixed a data-toggle error in the EHCI driver. Now the
	       hardware/DMA data toggle value is used as reference for the next
	       transfer.
	
	       3) Fixed a possible control transfer problem when using the
	       Linux emulation layer with the UHCI driver. Part of this fix
	       is to always use a fixup buffer independent of transfer type.
	       This way it will also be easier to make virtual kernel
	       mappings from the allocated memory pages.
	
	       4) Instead of comparing memory pointers with "less than",
	       compute the end-pointer and use the "not equal to" comparison
	       instead. This is safer and faster.
	
	       5) Removed interrupt counting in the interrupt handlers.
	
	       6) ISOCHRONOUS transfers will always have a timeout. If the
	       driver does not specify a timeout, 250ms will be used.
	
	       7) Make sure that LOW speed devices cannot specify FULL speed
	       ISOCHRONOUS transfers. The check is done in the host
	       controller "pipe_init" callbacks.
	
	       8) EHCI-driver: Lower EHCI NAK-reload count to 1 for
	       non-HIGH-speed devices.
	
	       9) New mechanism: If the "pipe_init" callback wants to say
	       that it does not support a certain transfer type, it can do so
	       by not setting "pipe->methods".
	
	       10) Added maximum string length arguments to
	       "usbd_devinfo_vp()" and "usbd_printBCD()", instead of
	       depending on some old assumptions.
	
	       11) Replaced the remaining "strcpy()" with "strlcpy()". This
	       does not fix anything.
	
	       12) "usbd_page_fit_obj()" does no longer clobber the
	       "page->length" variable, which turned out to not be
	       a good idea.
	
	       13) Fixed a bug in the UHCI driver, where the wrong page was
	       exited/entered from/to DMA.
	
	       14) Some optimizations and nits.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/README#15 edit
.. //depot/projects/usb/src/sys/dev/usb/ehci.c#35 edit
.. //depot/projects/usb/src/sys/dev/usb/ehci.h#13 edit
.. //depot/projects/usb/src/sys/dev/usb/ohci.c#29 edit
.. //depot/projects/usb/src/sys/dev/usb/ugen.c#19 edit
.. //depot/projects/usb/src/sys/dev/usb/uhci.c#29 edit
.. //depot/projects/usb/src/sys/dev/usb/uhub.c#14 edit
.. //depot/projects/usb/src/sys/dev/usb/umass.c#19 edit
.. //depot/projects/usb/src/sys/dev/usb/usb.c#15 edit
.. //depot/projects/usb/src/sys/dev/usb/usb.h#12 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_subr.c#40 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_subr.h#43 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#28 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb/README#15 (text+ko) ====

@@ -215,8 +215,9 @@
 	NOTE: The transfer timeout, if any, is started after that
 	the pre-delay has elapsed! 
 
-- The "timeout" field, if non-zero, will set the transfer timeout, in
-  milliseconds.
+- The "timeout" field, if non-zero, will set the transfer timeout in
+  milliseconds. If the "timeout" field is zero and the transfer type
+  is ISOCHRONOUS a timeout of 250ms will be used.
 
 - The "frames" field sets the number of isochronous frames, for 
   "type" = UE_ISOCHRONOUS.

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

@@ -1108,7 +1108,7 @@
 		}
 
 		/* Make a copy of the data toggle */
-		last_toggle = td->toggle_curr;
+		last_toggle = (status & EHCI_QTD_TOGGLE_MASK) ? 1 : 0;
 
 		/* Check if this is the last transfer */
 		if (((void *)td) == xfer->td_transfer_last) {
@@ -1125,12 +1125,6 @@
 
 	/* update data toggle */
 
-	if ((last_len == 0) ||
-	    (((last_len + xfer->max_packet_size - 1) /
-	      xfer->max_packet_size) & 1)) {
-	    last_toggle = !last_toggle;
-	}
-
 	xfer->pipe->toggle_next = last_toggle;
 
 	DPRINTFN(10, ("actlen=%d\n", actlen));
@@ -1362,8 +1356,6 @@
 
 	td = curthread; /* NULL is not a valid thread */
 
-	sc->sc_bus.no_intrs++;
-
 	DPRINTFN(15,("%s: real interrupt\n",
 		     device_get_nameunit(sc->sc_bus.bdev)));
 
@@ -1570,18 +1562,19 @@
 	u_int32_t buf_offset;
 	u_int32_t len;
 	u_int32_t c_error = 
-	  (xfer->udev->speed == USB_SPEED_HIGH) ? 0 : 
+	  (usbd_get_speed(xfer->udev) == USB_SPEED_HIGH) ? 0 : 
 	  htole32(EHCI_QTD_SET_CERR(3));
 	u_int8_t isread;
 	u_int8_t shortpkt = 0;
 	u_int8_t force_short;
+	struct usbd_pipe_methods *methods = xfer->pipe->methods;
 	ehci_qtd_t *td;
 	ehci_qtd_t *td_last = NULL;
 	ehci_qh_t *qh;
 
 	DPRINTFN(8, ("addr=%d endpt=%d len=%d speed=%d\n", 
 		     xfer->address, UE_GET_ADDR(xfer->endpoint),
-		     xfer->length, xfer->udev->speed));
+		     xfer->length, usbd_get_speed(xfer->udev)));
 
 	td = (xfer->td_transfer_first = 
 	      xfer->td_transfer_cache = xfer->td_start);
@@ -1593,7 +1586,7 @@
 
 	len = xfer->length;
 
-	if(xfer->pipe->methods == &ehci_device_ctrl_methods)
+	if(methods == &ehci_device_ctrl_methods)
 	{
 	    isread = xfer->control_isread;
 
@@ -1620,7 +1613,6 @@
 		td->qtd_buffer[1] = 
 		  htole32(buf_res.physaddr & (~0xFFF));
 		td->qtd_buffer_hi[1] = 0;
-		td->toggle_curr = 0;
 
 		td->len = sizeof(usb_device_request_t);
 		len -= sizeof(usb_device_request_t);
@@ -1726,7 +1718,6 @@
 		  htole32(buf_res.physaddr & (~0xFFF));
 		td->qtd_buffer_hi[1] = 0;
 
-		td->toggle_curr = xfer->pipe->toggle_next;
 		td->len = average;
 
 		/* adjust the toggle based on the 
@@ -1756,7 +1747,7 @@
 		usbd_page_dma_enter(td_last->page);
 	}
 
-	if(xfer->pipe->methods == &ehci_device_ctrl_methods)
+	if(methods == &ehci_device_ctrl_methods)
 	{
 	    if (xfer->control_remainder == 0) {
 
@@ -1820,38 +1811,37 @@
 	qh_endp =
 	  (EHCI_QH_SET_ADDR(xfer->address) |
 	   EHCI_QH_SET_ENDPT(UE_GET_ADDR(xfer->endpoint)) |
-	   EHCI_QH_DTC |
-	   EHCI_QH_SET_MPL(xfer->max_packet_size) |
-	   EHCI_QH_SET_NRL(8) /* XXX */ 
-	   );
+	   EHCI_QH_SET_MPL(xfer->max_packet_size));
+
+	if (usbd_get_speed(xfer->udev) == USB_SPEED_HIGH) {
+	    qh_endp |= (EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | 
+			EHCI_QH_DTC | EHCI_QH_SET_NRL(8));
+	} else {
+
+	    if (usbd_get_speed(xfer->udev) == USB_SPEED_FULL) {
+	      qh_endp |= (EHCI_QH_SET_EPS(EHCI_QH_SPEED_FULL) |
+			  EHCI_QH_DTC);
+	    } else {
+	      qh_endp |= (EHCI_QH_SET_EPS(EHCI_QH_SPEED_LOW) |
+			  EHCI_QH_DTC);
+	    }
 
-	switch (xfer->udev->speed) {
-	case USB_SPEED_LOW:  
-	  qh_endp |= (EHCI_QH_SET_EPS(EHCI_QH_SPEED_LOW)|
-		      EHCI_QH_CTL);  
-	  break;
-	case USB_SPEED_FULL: 
-	  qh_endp |= (EHCI_QH_SET_EPS(EHCI_QH_SPEED_FULL)|
-		      EHCI_QH_CTL);
-	  break;
-	case USB_SPEED_HIGH: 
-	  qh_endp |= (EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH)); 
-	  break;
-	default:
-	  panic("%s: bad device speed %d!", __FUNCTION__, xfer->udev->speed);
-	  break;
-	}
+	    if (methods == &ehci_device_ctrl_methods) {
+	        qh_endp |= EHCI_QH_CTL;
+	    }
 
-	if(xfer->pipe->methods != &ehci_device_ctrl_methods)
-	{
-		qh_endp &= ~EHCI_QH_CTL;
+	    if (methods != &ehci_device_intr_methods) {
+		/* Only try one time per microframe! */
+	        qh_endp |= EHCI_QH_SET_NRL(1);
+	    }
 	}
 
 	qh->qh_endp = htole32(qh_endp);
 
 	qh_endphub =
 	  (EHCI_QH_SET_MULT(xfer->max_packet_count & 3)|
-	   EHCI_QH_SET_CMASK(0xf0));
+	   EHCI_QH_SET_CMASK(xfer->usb_cmask)|
+	   EHCI_QH_SET_SMASK(xfer->usb_smask));
 
 	if(xfer->udev->myhsport)
 	{
@@ -1860,12 +1850,6 @@
 		   EHCI_QH_SET_PORT(xfer->udev->myhsport->portno));
 	}
 
-	if(xfer->pipe->methods == &ehci_device_intr_methods)
-	{
-		/* execute the transfer one time per 1ms */
-		qh_endphub |= EHCI_QH_SET_SMASK(0x04);
-	}
-
 	qh->qh_endphub = htole32(qh_endphub);
 	qh->qh_curqtd = htole32(0);
 
@@ -2354,7 +2338,27 @@
 	u_int16_t best;
 	u_int16_t bit;
 	u_int16_t x;
+	uint8_t slot;
+
+	/* Allocate a microframe slot first: */
+
+	slot = usbd_intr_schedule_adjust
+	  (xfer->udev, xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX);
+
+	if (usbd_get_speed(xfer->udev) == USB_SPEED_HIGH) {
+	    xfer->usb_uframe = slot;
+	    xfer->usb_smask = (1 << slot) & 0xFF;
+	    xfer->usb_cmask = 0;
+	} else {
+	    xfer->usb_uframe = slot;
+	    xfer->usb_smask = (1 << slot) & 0x3F;
+	    xfer->usb_cmask = (-(4 << slot)) & 0xFE;
+	}
 
+	/* Find the best QH position corresponding 
+	 * to the given interval:
+	 */
+
 	best = 0;
 	bit = EHCI_VIRTUAL_FRAMELIST_COUNT/2;
 	while(bit)
@@ -2389,6 +2393,10 @@
 ehci_device_intr_close(struct usbd_xfer *xfer)
 {
 	ehci_softc_t *sc = xfer->usb_sc;
+	uint8_t slot;
+
+	slot = usbd_intr_schedule_adjust
+	  (xfer->udev, -(xfer->max_frame_size), xfer->usb_uframe);
 
 	sc->sc_intr_stat[xfer->qh_pos]--;
 
@@ -2447,20 +2455,15 @@
 
 	sitd_portaddr = 
 	  EHCI_SITD_SET_ADDR(xfer->address)|
-	  EHCI_SITD_SET_ENDPT(UE_GET_ADDR(xfer->endpoint));
+	  EHCI_SITD_SET_ENDPT(UE_GET_ADDR(xfer->endpoint))|
+	  EHCI_SITD_SET_HUBA(xfer->udev->myhsport->parent->address)|
+	  EHCI_SITD_SET_PORT(xfer->udev->myhsport->portno);
 
 	if(UE_GET_DIR(xfer->endpoint) == UE_DIR_IN)
 	{
 		sitd_portaddr |= EHCI_SITD_SET_DIR_IN;
 	}
 
-	if(xfer->udev->myhsport)
-	{
-		sitd_portaddr |= 
-			EHCI_SITD_SET_HUBA(xfer->udev->myhsport->parent->address)|
-			EHCI_SITD_SET_PORT(xfer->udev->myhsport->portno);
-	}
-
 	sitd_portaddr = htole32(sitd_portaddr);
 
 	/* initialize all TD's */
@@ -2476,24 +2479,7 @@
 		 *
 		 * micro-frame usage 
 		 * (8 microframes per 1ms)
-		 *
-		 * 0: isoc-IN
-		 * 1: isoc-OUT
-		 * 2: interrupt transfers
-		 * .
-		 * .
-		 * 7:
 		 */
-		if(UE_GET_DIR(xfer->endpoint) == UE_DIR_IN)
-		{
-			td->sitd_mask = htole32(EHCI_SITD_SET_SMASK(0x01)|
-						EHCI_SITD_SET_CMASK(0xFC));
-		}
-		else
-		{
-			td->sitd_mask = htole32(EHCI_SITD_SET_SMASK(0x02)|
-						EHCI_SITD_SET_CMASK(0xF8));
-		}
 		td->sitd_back = htole32(EHCI_LINK_TERMINATE);
 
 		usbd_page_dma_enter(td->page);
@@ -2513,13 +2499,20 @@
 {
 	struct usbd_page_search buf_res;
 	ehci_softc_t *sc = xfer->usb_sc;
+	struct usbd_fs_isoc_schedule *fss_start;
+	struct usbd_fs_isoc_schedule *fss_end;
+	struct usbd_fs_isoc_schedule *fss;
 	u_int32_t buf_offset;
 	u_int32_t nframes;
 	uint32_t temp;
+	uint32_t sitd_mask;
 	u_int16_t *plen;
+	uint16_t tlen;
 #ifdef USB_DEBUG
 	u_int8_t once = 1;
 #endif
+	uint8_t sa;
+	uint8_t sb;
 	ehci_sitd_t *td;
 	ehci_sitd_t *td_last = NULL;
 	ehci_sitd_t **pp_last;
@@ -2562,7 +2555,8 @@
 	 * will be finished:
 	 */
 	xfer->isoc_time_complete = 
-	  usbd_isoc_time_expand(&(sc->sc_bus), nframes) + buf_offset + 
+	  usbd_fs_isoc_schedule_isoc_time_expand
+	  (xfer->udev, &fss_start, &fss_end, nframes) + buf_offset + 
 	  xfer->nframes;
 
 	/* get the real number of frames */
@@ -2593,6 +2587,8 @@
 
 	xfer->qh_pos = xfer->pipe->isoc_next;
 
+	fss = fss_start + (xfer->qh_pos % USB_ISOC_TIME_MAX);
+
 	while(nframes--)
 	{
 		if(td == NULL)
@@ -2606,9 +2602,12 @@
 			pp_last = &sc->sc_isoc_fs_p_last[0];
 		}
 
+		if (fss >= fss_end) {
+		    fss = fss_start;
+		}
+
 		/* reuse sitd_portaddr and sitd_back from last transfer */
 
-		/* TODO: implement support for multiple transactions */
 		if(*plen > xfer->max_frame_size)
 		{
 #ifdef USB_DEBUG
@@ -2624,6 +2623,11 @@
 			*plen = xfer->max_frame_size;
 		}
 
+		/* We currently don't care if the
+		 * ISOCHRONOUS schedule is full!
+		 */
+		sa = usbd_fs_isoc_schedule_alloc(fss, *plen);
+
 		usbd_page_dma_exit(td->page);
 
 		td->sitd_bp[0] = htole32(buf_res.physaddr);
@@ -2633,13 +2637,41 @@
 
 		temp = buf_res.physaddr & (~0xFFF);
 
-		if(UE_GET_DIR(xfer->endpoint) == UE_DIR_OUT)
-		{
-			temp |= 1; /* T-count == 1*/
+		if (UE_GET_DIR(xfer->endpoint) == UE_DIR_OUT) {
+		  tlen = *plen;
+		  if (tlen <= 188) {
+		    temp |= 1; /* T-count = 1, TP = ALL*/
+		    tlen = 1;
+		  } else {
+		    tlen += 187;
+		    tlen /= 188;
+		    temp |= tlen; /* T-count = [1..6] */
+		    temp |= 8; /* TP = Begin */
+		  }
+
+		  tlen += sa;
+
+		  if (tlen >= 8) {
+		    sb = 0;
+		  } else {
+		    sb = (1 << tlen);
+		  }
+
+		  sa = (1 << sa);
+		  sa = (sb - sa) & 0x3F;
+		  sb = 0;
+		} else {
+		  sb = (-(4 << sa)) & 0xFE;
+		  sa = (1 << sa) & 0x3F;
 		}
 
+		sitd_mask = (EHCI_SITD_SET_SMASK(sa)|
+			     EHCI_SITD_SET_CMASK(sb));
+
 		td->sitd_bp[1] = htole32(temp);
 
+		td->sitd_mask = htole32(sitd_mask);
+
 		if(nframes == 0)
 		{
 			td->sitd_status = htole32
@@ -2667,6 +2699,7 @@
 		pp_last++;
 
 		plen++;
+		fss++;
 		td_last = td;
 		td = td->obj_next;
 	}
@@ -3838,11 +3871,23 @@
 		   (xfer->pipe->methods == &ehci_device_bulk_methods) ||
 		   (xfer->pipe->methods == &ehci_device_intr_methods))
 		{
-			if ((xfer->pipe->methods == &ehci_device_intr_methods) &&
-			    (udev->speed == USB_SPEED_HIGH))
-			    usbd_std_transfer_setup(udev, xfer, setup, 0x400, 0xC00, 3);
-			else
-			    usbd_std_transfer_setup(udev, xfer, setup, 0x400, 0x400, 1);
+			if (xfer->pipe->methods == &ehci_device_intr_methods) {
+			    if (udev->speed == USB_SPEED_HIGH) {
+			        usbd_std_transfer_setup(udev, xfer, setup, 
+							0x400, 0xC00, 3);
+			    } else if (udev->speed == USB_SPEED_FULL) {
+			        usbd_std_transfer_setup(udev, xfer, setup, 
+							USB_FS_BYTES_PER_HS_UFRAME, 
+							USB_FS_BYTES_PER_HS_UFRAME, 1);
+			    } else {
+			        usbd_std_transfer_setup(udev, xfer, setup, 
+							USB_FS_BYTES_PER_HS_UFRAME / 8, 
+							USB_FS_BYTES_PER_HS_UFRAME / 8, 1);
+			    }
+			} else {
+			    usbd_std_transfer_setup(udev, xfer, setup, 
+						    0x400, 0x400, 1);
+			}
 			nqh = 1;
 			nqtd = (1+ /* SETUP */ 1+ /* STATUS */
 			       1  /* SHORTPKT */) +
@@ -3850,7 +3895,7 @@
 		}
 		else if(xfer->pipe->methods == &ehci_device_isoc_fs_methods)
 		{
-			usbd_std_transfer_setup(udev, xfer, setup, 188, 188, 1);
+			usbd_std_transfer_setup(udev, xfer, setup, 0x3FF, 0x3FF, 1);
 
 			if(xfer->nframes == 0)
 			{
@@ -3967,8 +4012,8 @@
 	      n < nitd;
 	      n++)
 	  {
-	    size[1] += usbd_page_fit_obj(page_ptr, size[1], 
-					 sizeof(ehci_itd_t));
+	    size[1] += usbd_page_fit_obj(size[1], sizeof(ehci_itd_t));
+
 	    if(buf)
 	    {
 		register ehci_itd_t *td;
@@ -3995,8 +4040,8 @@
 	      n < nsitd;
 	      n++)
 	  {
-	    size[1] += usbd_page_fit_obj(page_ptr, size[1], 
-					 sizeof(ehci_sitd_t));
+	    size[1] += usbd_page_fit_obj(size[1], sizeof(ehci_sitd_t));
+
 	    if(buf)
 	    {
 	        register ehci_sitd_t *td;
@@ -4023,8 +4068,8 @@
 	      n < nqtd;
 	      n++)
 	  {
-	    size[1] += usbd_page_fit_obj(page_ptr, size[1], 
-					 sizeof(ehci_qtd_t));
+	    size[1] += usbd_page_fit_obj(size[1], sizeof(ehci_qtd_t));
+
 	    if(buf)
 	    {
 		register ehci_qtd_t *qtd;
@@ -4061,8 +4106,8 @@
 	      n < nqh;
 	      n++)
 	  {
-	    size[1] += usbd_page_fit_obj(page_ptr, size[1],
-					 sizeof(ehci_qh_t));
+	    size[1] += usbd_page_fit_obj(size[1], sizeof(ehci_qh_t));
+
 	    if(buf)
 	    {
 		register ehci_qh_t *qh;
@@ -4154,13 +4199,18 @@
 			pipe->methods = &ehci_root_intr_methods;
 			break;
 		default:
-			panic("invalid endpoint address: 0x%02x",
-			      edesc->bEndpointAddress);
+			/* do nothing */
 			break;
 		}
 	}
 	else
         {
+		if ((udev->speed != USB_SPEED_HIGH) &&
+		    (udev->myhsport == NULL)) {
+		    /* We need a transaction translator */
+		    goto done;
+		}
+
 		switch (edesc->bmAttributes & UE_XFERTYPE)
 		{
 		case UE_CONTROL:
@@ -4174,7 +4224,7 @@
 			{
 				pipe->methods = &ehci_device_isoc_hs_methods;
 			}
-			else
+			else if (udev->speed == USB_SPEED_FULL)
 			{
 				pipe->methods = &ehci_device_isoc_fs_methods;
 			}
@@ -4182,8 +4232,12 @@
 		case UE_BULK:
 			pipe->methods = &ehci_device_bulk_methods;
 			break;
+		default:
+			/* do nothing */
+			break;
 		}
 	}
+ done:
 	return;
 }
 

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

@@ -319,8 +319,6 @@
 	struct usbd_page 	*page;
 	uint32_t		qtd_self;
 	uint16_t		len;
-	uint8_t			toggle_curr;
-	uint8_t			unused;
 } __aligned(EHCI_QTD_ALIGN) ehci_qtd_t;
 
 /* Queue Head */

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

@@ -1052,7 +1052,6 @@
 
 	td = curthread; /* NULL is not a valid thread */
 
-	sc->sc_bus.no_intrs++;
 	hw_ptr = sc->sc_hw_ptr;
 
 	DPRINTFN(15,("%s: real interrupt\n",
@@ -2114,12 +2113,6 @@
 	/**/
 	ohci_add_interrupt_info(sc, xfer);
 
-	if(!xfer->timeout)
-	{
-		/* in case the frame start number is wrong */
-		xfer->timeout = 1000/4;
-	}
-
 	/* enqueue transfer 
 	 * (so that it can be aborted through pipe abort)
 	 */
@@ -2948,8 +2941,8 @@
 	      n < ntd;
 	      n++)
 	  {
-	    size[1] += usbd_page_fit_obj(page_ptr, size[1], 
-					 sizeof(ohci_td_t));
+	    size[1] += usbd_page_fit_obj(size[1], sizeof(ohci_td_t));
+
 	    if(buf)
 	    {
 		register ohci_td_t *td;
@@ -2976,8 +2969,8 @@
 	      n < nitd;
 	      n++)
 	  {
-	    size[1] += usbd_page_fit_obj(page_ptr, size[1], 
-					 sizeof(ohci_itd_t));
+	    size[1] += usbd_page_fit_obj(size[1], sizeof(ohci_itd_t));
+
 	    if(buf)
 	    {
 		register ohci_itd_t *itd;
@@ -3011,8 +3004,8 @@
 	      n < nqh;
 	      n++)
 	  {
-	    size[1] += usbd_page_fit_obj(page_ptr, size[1],
-					 sizeof(ohci_ed_t));
+	    size[1] += usbd_page_fit_obj(size[1], sizeof(ohci_ed_t));
+
 	    if(buf)
 	    {
 		register ohci_ed_t *ed;
@@ -3104,8 +3097,7 @@
 			pipe->methods = &ohci_root_intr_methods;
 			break;
 		default:
-			panic("invalid endpoint address: 0x%02x",
-			      edesc->bEndpointAddress);
+			/* do nothing */
 			break;
 		}
 	}
@@ -3120,11 +3112,16 @@
 			pipe->methods = &ohci_device_intr_methods;
 			break;
 		case UE_ISOCHRONOUS:
-			pipe->methods = &ohci_device_isoc_methods;
+			if (udev->speed == USB_SPEED_FULL) {
+			    pipe->methods = &ohci_device_isoc_methods;
+			}
 			break;
 		case UE_BULK:
 			pipe->methods = &ohci_device_bulk_methods;
 			break;
+		default:
+			/* do nothing */
+			break;
 		}
 	}
 	return;

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

@@ -1092,7 +1092,8 @@
 			/* start transfer */
 			usbd_transfer_start(xfer);
 
-			while (xfer->flags & USBD_DEV_TRANSFERRING) {
+			while ((xfer->flags & USBD_DEV_TRANSFERRING) ||
+			       (sce->xfer_in[1]->flags & USBD_DEV_TRANSFERRING)) {
 
 			    /* wait for data */
 
@@ -1104,6 +1105,7 @@
 			    sce->state &= ~(UGEN_RD_SLP|UGEN_RD_WUP);
 
 			    if (error) {
+			        usbd_transfer_stop(sce->xfer_in[1]);
 			        usbd_transfer_stop(xfer);
 				break;
 			    }
@@ -1217,7 +1219,8 @@
 			/* start transfer */
 			usbd_transfer_start(xfer);
 
-			while (xfer->flags & USBD_DEV_TRANSFERRING) {
+			while ((xfer->flags & USBD_DEV_TRANSFERRING) ||
+			       (sce->xfer_out[1]->flags & USBD_DEV_TRANSFERRING)) {
 
 			    /* wait for data */
 
@@ -1229,6 +1232,7 @@
 			    sce->state &= ~(UGEN_WR_SLP|UGEN_WR_WUP);
 
 			    if (error) {
+			        usbd_transfer_stop(sce->xfer_out[1]);
 			        usbd_transfer_stop(xfer);
 				break;
 			    }
@@ -1489,7 +1493,7 @@
 
 	if (usbd_clear_stall_callback(xfer, xfer_other)) {
 	    PRINTFN(4, ("sce=%p: stall cleared\n", sce));
-	    sce->write_stall = 1;
+	    sce->write_stall = 0;
 	    usbd_transfer_start(xfer_other);
 	}
 	return;

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

@@ -128,6 +128,19 @@
   ((sc)->sc_hw_page.physaddr + \
    POINTER_TO_UNSIGNED(&(((struct uhci_hw_softc *)0)->what)))
 
+struct uhci_mem_layout {
+
+	struct usbd_page_search buf_res;
+	struct usbd_page_search fix_res;
+
+	struct usbd_xfer *xfer;
+
+	uint32_t buf_offset;
+	uint32_t fix_offset;
+
+	uint8_t isread;
+};
+
 extern struct usbd_bus_methods uhci_bus_methods;
 extern struct usbd_pipe_methods uhci_device_bulk_methods;
 extern struct usbd_pipe_methods uhci_device_ctrl_methods;
@@ -140,6 +153,146 @@
 static void uhci_root_ctrl_task_td(struct uhci_softc *sc, struct thread *ctd);
 static void uhci_do_poll(struct usbd_bus *bus);
 
+static void
+uhci_mem_layout_init(struct uhci_mem_layout *ml, struct usbd_xfer *xfer)
+{
+	ml->buf_offset = 0;
+	usbd_get_page(&(xfer->buf_data), ml->buf_offset, &(ml->buf_res));
+
+	ml->fix_offset = 0;
+	usbd_get_page(&(xfer->buf_fixup), ml->fix_offset, &(ml->fix_res));
+
+	ml->isread = 0; /* write */
+
+	ml->xfer = xfer; /* save a push */
+	return;
+}
+
+static void
+uhci_mem_layout_fit(struct uhci_mem_layout *ml, struct uhci_td *td, uint16_t len)
+{
+	struct usbd_page_search tmp_res;
+	struct usbd_xfer *xfer = ml->xfer;
+
+	if (ml->buf_res.length < len) {
+
+	    /* need to do a fixup */
+
+	    if (ml->fix_res.length < len) {
+
+		/* need to do a sub-fixup */
+
+		ml->fix_offset += ml->fix_res.length;
+		usbd_get_page(&(xfer->buf_fixup), ml->fix_offset, &(ml->fix_res));
+	    }
+
+	    td->td_buffer = htole32(ml->fix_res.physaddr);
+
+	    if (!ml->isread) {
+
+		/*
+		 * The UHCI driver cannot handle
+		 * page crossings, so a fixup is
+		 * needed:
+		 *
+		 *  +----+----+ - - -
+		 *  | YYY|Y   |
+		 *  +----+----+ - - -
+		 *     \	     \
+		 *	\			\
+		 *	 +----+
+		 *	 |YYYY|	 (fixup)
+		 *	 +----+
+		 */
+
+		/* no copy back needed: */
+
+		td->fixup_dst_offset = 0xffffffff;
+		td->fixup_src_offset = 0xffffffff;
+
+		usbd_get_page(&(xfer->buf_data), ml->buf_offset + 
+			      ml->buf_res.length, &tmp_res);
+
+		/* copy first data part to fixup location */
+
+		usbd_page_dma_exit(ml->fix_res.page);
+
+		usbd_page_dma_exit(ml->buf_res.page);
+		bcopy(ml->buf_res.buffer, ml->fix_res.buffer, ml->buf_res.length);
+		usbd_page_dma_enter(ml->buf_res.page);
+
+		/* copy second data part to fixup location */
+
+		usbd_page_dma_exit(tmp_res.page);
+		bcopy(tmp_res.buffer, ADD_BYTES(ml->fix_res.buffer, 
+						ml->buf_res.length),
+		      len - ml->buf_res.length);
+		usbd_page_dma_enter(tmp_res.page);
+
+		usbd_page_dma_enter(ml->fix_res.page);
+
+	    } else {
+		td->fixup_dst_offset = ml->buf_offset;
+		td->fixup_src_offset = ml->fix_offset;
+	    }
+
+	    /* prepare next fixup */
+	    ml->fix_offset += xfer->max_frame_size;
+	    usbd_get_page(&(xfer->buf_fixup), ml->fix_offset, &(ml->fix_res));
+
+	} else {
+	    td->td_buffer = htole32(ml->buf_res.physaddr);
+	    td->fixup_dst_offset = 0xffffffff;
+	    td->fixup_src_offset = 0xffffffff;
+	}
+
+	/* prepare next data location */
+	ml->buf_offset += len;
+	usbd_get_page(&(xfer->buf_data), ml->buf_offset, &(ml->buf_res));
+
+	return;
+}
+
+static void
+uhci_mem_layout_do_fixup(struct usbd_xfer *xfer, struct uhci_td *td, uint16_t len)
+{
+	struct usbd_page_search buf_res;
+	struct usbd_page_search fix_res;
+	u_int16_t temp;
+
+	usbd_get_page(&(xfer->buf_data), td->fixup_dst_offset, &buf_res);
+	usbd_get_page(&(xfer->buf_fixup), td->fixup_src_offset, &fix_res);
+ 
+	temp = min(buf_res.length, len);
+
+	usbd_page_dma_exit(fix_res.page);
+
+	usbd_page_dma_exit(buf_res.page);
+	bcopy(fix_res.buffer, buf_res.buffer, temp);
+	usbd_page_dma_enter(buf_res.page);
+
+	len -= temp;
+
+	if (len) {
+		usbd_get_page(&(xfer->buf_data), 
+			      td->fixup_dst_offset + temp, &buf_res);
+
+		if (len > buf_res.length) {
+		    /* overflow protection - should not happen */
+		    len = buf_res.length;
+		}
+
+		usbd_page_dma_exit(buf_res.page);
+		bcopy(ADD_BYTES(fix_res.buffer, temp), 
+		      buf_res.buffer, len);
+		usbd_page_dma_enter(buf_res.page);
+	}
+
+	usbd_page_dma_enter(fix_res.page);
+
+	return;
+}
+
 void
 uhci_reset(uhci_softc_t *sc)
 {
@@ -618,7 +771,6 @@
 	struct uhci_hw_softc *hw_ptr = sc->sc_hw_ptr;
 
 	uhci_dumpregs(sc);
-	printf("intrs=%d\n", sc->sc_bus.no_intrs);
 	uhci_dump_qh(&(hw_ptr->ls_ctl_start));
 	uhci_dump_qh(&(hw_ptr->hs_ctl_start));
 	uhci_dump_qh(&(hw_ptr->bulk_start));
@@ -886,14 +1038,11 @@
 static u_int8_t
 uhci_isoc_done(uhci_softc_t *sc, struct usbd_xfer *xfer)
 {
-	struct usbd_page_search buf_res;
-	struct usbd_page_search fix_res;
 	u_int32_t nframes = xfer->nframes;
 	u_int32_t actlen = 0;
 	uint32_t status;
 	u_int16_t *plen = xfer->frlengths;
 	u_int16_t len = 0;
-	u_int16_t temp;
 	u_int8_t need_delay = 0;
 	uhci_td_t *td = xfer->td_transfer_first;
 	uhci_td_t **pp_last = &sc->sc_isoc_p_last[xfer->qh_pos];
@@ -941,32 +1090,7 @@
 	  actlen += len;
 
 	  if (td->fixup_src_offset != 0xffffffff) {
-
-	      usbd_get_page(&(xfer->buf_data), td->fixup_dst_offset, &buf_res);
-	      usbd_get_page(&(xfer->buf_fixup), td->fixup_src_offset, &fix_res);
- 
-	      temp = min(buf_res.length, len);
-
-	      usbd_page_dma_exit(fix_res.page);
-
-	      usbd_page_dma_exit(buf_res.page);
-	      bcopy(fix_res.buffer, buf_res.buffer, temp);
-	      usbd_page_dma_enter(buf_res.page);
-
-	      len -= temp;
-
-	      if (len) {
-
-		  usbd_get_page(&(xfer->buf_data), 
-				td->fixup_dst_offset + temp, &buf_res);
-
-		  usbd_page_dma_exit(buf_res.page);
-		  bcopy(ADD_BYTES(fix_res.buffer, temp), 
-			buf_res.buffer, len);
-		  usbd_page_dma_enter(buf_res.page);
-	      }
-
-	      usbd_page_dma_enter(fix_res.page);
+		uhci_mem_layout_do_fixup(xfer, td, len);
 	  }
 
 	  /* remove TD from schedule */
@@ -986,7 +1110,8 @@
 {
 	uint32_t status = 0;
 	uint32_t token = 0;
-	u_int32_t actlen = 0;
+	uint32_t actlen = 0;
+	uint16_t len;
 	uhci_td_t *td = xfer->td_transfer_first;
 
 	DPRINTFN(12, ("xfer=%p pipe=%p transfer done\n",
@@ -1013,7 +1138,12 @@
 			break;
 		}
 
-		actlen += UHCI_TD_GET_ACTLEN(status);
+		len = UHCI_TD_GET_ACTLEN(status);
+		actlen += len;
+
+		if (td->fixup_src_offset != 0xffffffff) {
+			uhci_mem_layout_do_fixup(xfer, td, len);
+		}
 
 		if (((void *)td) == xfer->td_transfer_last) {
 			td = NULL;
@@ -1202,8 +1332,6 @@
 
 	td = curthread; /* NULL is not a valid thread */
 
-	sc->sc_bus.no_intrs++;
-
 	DPRINTFN(15,("%s: real interrupt\n",
 		     device_get_nameunit(sc->sc_bus.bdev)));
 
@@ -1384,11 +1512,10 @@
 static uhci_td_t *

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


More information about the p4-projects mailing list