Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 23 Sep 2007 12:34:31 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 126720 for review
Message-ID:  <200709231234.l8NCYVwK067871@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=126720

Change 126720 by hselasky@hselasky_laptop001 on 2007/09/23 12:34:22

	
	FYI; The comments follow the P4 diff from top to bottom.
	
	- the maximum frame size must be read from the USB transfer
	
	- convert kernel USB flags (USBD_XXX) into a bitmap (scripted)
	
	- computing correct buffer sizes have been factored out into
	  the USB kernel by setting the "proxy_buffer" flag.
	
	- "xfer->actlen < xfer->sumlen" is the new way to check if a
	  USB transfer is short.
	
	- remove redundant setting of "xfer->length" for ISOC USB transfers.
	
	- proxy buffer data size is now stored in "xfer->max_data_length".
	
	- new mechanism to proxy USB control transfers

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb/usb_compat_linux.c#7 edit

Differences ...

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

@@ -753,7 +753,6 @@
 usb_setup_endpoint(struct usb_device *dev, struct usb_host_endpoint *uhe, uint32_t bufsize)
 {
 	struct usbd_config cfg[2];
-	uint16_t mfs = usbd_get_max_frame_size((usb_endpoint_descriptor_t *)&(uhe->desc));
 	uint8_t type = uhe->desc.bmAttributes & UE_XFERTYPE;
 	uint8_t addr = uhe->desc.bEndpointAddress;
 
@@ -784,7 +783,8 @@
 	    cfg[0].callback = &usb_linux_isoc_callback;
 	    cfg[0].bufsize = 0; /* use wMaxPacketSize */
 	    cfg[0].frames = usb_max_isoc_frames(dev);
-	    cfg[0].flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK);
+	    cfg[0].flags.proxy_buffer = 1;
+	    cfg[0].flags.short_xfer_ok = 1;
 
 	    bcopy(cfg + 0, cfg + 1, sizeof(*cfg));
 
@@ -802,16 +802,6 @@
 		bufsize = (1 << 22);
 	    }
 
-	    /* we need enough room for the control header */
-	    if (bufsize < sizeof(usb_device_request_t)) {
-		bufsize = sizeof(usb_device_request_t);
-	    }
-
-	    if (bufsize < mfs) {
-		/* we need to be able to hold at least one frame! */
-		bufsize = mfs;
-	    }
-
 	    /* Allocate and setup one generic FreeBSD USB transfer */
 
 	    cfg[0].type = type;
@@ -819,7 +809,8 @@
 	    cfg[0].direction = addr & (UE_DIR_OUT|UE_DIR_IN);
 	    cfg[0].callback = &usb_linux_non_isoc_callback;
 	    cfg[0].bufsize = bufsize;
-	    cfg[0].flags = (USBD_USE_DMA|USBD_SHORT_XFER_OK);
+	    cfg[0].flags.proxy_buffer = 1;
+	    cfg[0].flags.short_xfer_ok = 1;
 
 	    if (usbd_transfer_setup(dev->bsd_udev, uhe->bsd_iface_index,
 				    uhe->bsd_xfer, cfg, 1, uhe, 
@@ -1359,7 +1350,7 @@
 	urb->actual_length = xfer->actlen;
 
 	/* check for short transfer */
-	if (xfer->actlen < xfer->length) {
+	if (xfer->actlen < xfer->sumlen) {
 	    /* short transfer */
 	    if (urb->transfer_flags & URB_SHORT_NOT_OK) {
 		urb->status = -EPIPE; /* XXX should be EREMOTEIO */
@@ -1431,10 +1422,9 @@
 	}
 
 	xfer->priv_fifo = urb;
-	xfer->flags &= ~USBD_FORCE_SHORT_XFER;
+	xfer->flags.force_short_xfer = 0;
 	xfer->timeout = urb->timeout;
 	xfer->nframes = urb->number_of_packets;
-	xfer->length = offset; /* not really used */
 	usbd_start_hardware(xfer);
 	return;
 }
@@ -1448,10 +1438,13 @@
 static void
 usb_linux_non_isoc_callback(struct usbd_xfer *xfer)
 {
+	enum {
+	    REQ_SIZE = sizeof(usb_device_request_t)
+	};
 	struct urb *urb = xfer->priv_fifo;
 	struct usb_host_endpoint *uhe = xfer->priv_sc;
-	uint32_t max_bulk = (uhe->fbsd_buf_size - 
-			     (uhe->fbsd_buf_size % xfer->max_packet_size));
+	uint32_t max_bulk = xfer->max_data_length;
+	uint8_t data_frame = xfer->flags_int.control_xfr ? 1 : 0;
 
 	USBD_CHECK_STATUS(xfer);
 
@@ -1476,18 +1469,31 @@
 
  tr_transferred:
 
+	if (xfer->flags_int.control_xfr) {
+
+	    /* sanity check - should not happen */
+
+	    if (xfer->aframes < xfer->nframes) {
+		goto tr_error;
+	    }
+
+	    /* don't transfer the setup packet again: */
+
+	    xfer->frlengths[0] = 0;
+	}
+
 	if (urb->bsd_isread) {
 	    /* copy in data with regard to the URB */
-	    usbd_copy_out(&(xfer->buf_data), 0,
-			  urb->bsd_data_ptr, xfer->actlen);
+	    usbd_copy_out(xfer->frbuffers + data_frame, 0,
+			  urb->bsd_data_ptr, xfer->frlengths[data_frame]);
 	}
 
-	urb->bsd_length_rem -= xfer->actlen;
-	urb->bsd_data_ptr += xfer->actlen;
-	urb->actual_length += xfer->actlen;
+	urb->bsd_length_rem -= xfer->frlengths[data_frame];
+	urb->bsd_data_ptr += xfer->frlengths[data_frame];
+	urb->actual_length += xfer->frlengths[data_frame];
 
-	/* check for short packet */
-	if (xfer->actlen < xfer->length) {
+	/* check for short transfer */
+	if (xfer->actlen < xfer->sumlen) {
 	    urb->bsd_length_rem = 0;
 
 	    /* short transfer */
@@ -1499,7 +1505,7 @@
 	} else {
 
 	    /* check remainder */
-	    if (urb->bsd_length_rem) {
+	    if (urb->bsd_length_rem > 0) {
 		goto setup_bulk;
 	    }
 
@@ -1507,12 +1513,6 @@
 	    urb->status = 0;
 	}
 
-	/* check actual length */
-	if (urb->actual_length > urb->transfer_buffer_length) {
-	    /* premature end of a control transfer */
-	    urb->actual_length = 0;
-	}
-
 	/* call callback */
 	usb_linux_complete(xfer);
 
@@ -1529,49 +1529,58 @@
 	urb->bsd_urb_list.tqe_prev = NULL;
 
 	xfer->priv_fifo = urb;
-	xfer->flags &= ~USBD_FORCE_SHORT_XFER;
+	xfer->flags.force_short_xfer = 0;
 	xfer->timeout = urb->timeout;
 
-	if ((uhe->desc.bmAttributes & UE_XFERTYPE) == UE_CONTROL) {
-	    /* transfer the control header first and then the data,
-	     * if any, to a control endpoint:
+	if (xfer->flags_int.control_xfr) {
+
+	    /*
+	     * USB control transfers need special handling.
+	     * First copy in the header, then copy in data!
 	     */
-	    usbd_copy_in(&(xfer->buf_data), 0, 
-			 urb->setup_packet, sizeof(usb_device_request_t));
-	    xfer->length = sizeof(usb_device_request_t);
+	    usbd_copy_in(xfer->frbuffers + 0, 0, 
+			 urb->setup_packet, REQ_SIZE);
+
+	    xfer->frlengths[0] = REQ_SIZE;
+
+	    /* setup data transfer direction */
 
-	    urb->bsd_length_rem = xfer->length + urb->transfer_buffer_length;
-	    urb->bsd_data_ptr = ((uint8_t *)(urb->transfer_buffer)) - xfer->length;
-	    urb->actual_length = -xfer->length;
 	    urb->bsd_isread = (((uint8_t *)(urb->setup_packet))[0] & UT_READ) ? 1 : 0;
 
-	    usbd_start_hardware(xfer);
-	    return;
+	} else {
+
+	    /* setup data transfer direction */
+
+	    urb->bsd_isread = (uhe->desc.bEndpointAddress & UE_DIR_IN) ? 1 : 0;
 	}
 
 	urb->bsd_length_rem = urb->transfer_buffer_length;
 	urb->bsd_data_ptr = urb->transfer_buffer;
 	urb->actual_length = 0;
-	urb->bsd_isread = (uhe->desc.bEndpointAddress & UE_DIR_IN) ? 1 : 0;
 
  setup_bulk:
 	if (max_bulk > urb->bsd_length_rem) {
 	    max_bulk = urb->bsd_length_rem;
 	}
 
-	if (max_bulk == urb->bsd_length_rem) {
-	    if (urb->transfer_flags & URB_ZERO_PACKET) {
-		xfer->flags |= USBD_FORCE_SHORT_XFER;
-	    }
+	/* check if we need to force a short transfer */
+
+	if ((max_bulk == urb->bsd_length_rem) &&
+	    (urb->transfer_flags & URB_ZERO_PACKET) &&
+	    (!xfer->flags_int.control_xfr)) {
+	    xfer->flags.force_short_xfer = 1;
 	}
 
+	/* check if we need to copy in data */
+
 	if (!(urb->bsd_isread)) {
 	    /* copy out data with regard to the URB */
-	    usbd_copy_in(&(xfer->buf_data), 0,
+	    usbd_copy_in(xfer->frbuffers + data_frame, 0,
 			 urb->bsd_data_ptr, max_bulk);
 	}
 
-	xfer->length = max_bulk;
+	xfer->frlengths[data_frame] = max_bulk;
+	xfer->nframes = data_frame + 1;
 	usbd_start_hardware(xfer);
 	return;
 }



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