Browse Source

Send zero length packets when terminating a usb write aligned to maxpacketsize.

Con Kolivas 12 years ago
parent
commit
8e5dc21ea6
1 changed files with 14 additions and 2 deletions
  1. 14 2
      usbutils.c

+ 14 - 2
usbutils.c

@@ -2418,7 +2418,9 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
 	struct usb_epinfo *usb_epinfo;
 	struct usb_epinfo *usb_epinfo;
 	struct usb_transfer ut;
 	struct usb_transfer ut;
 	unsigned char endpoint;
 	unsigned char endpoint;
-	int err, errn;
+	int err, errn, dummy;
+	/* End of transfer and zero length packet required */
+	bool eot = false, zlp = false;
 #if DO_USB_STATS
 #if DO_USB_STATS
 	struct timeval tv_start, tv_finish;
 	struct timeval tv_start, tv_finish;
 #endif
 #endif
@@ -2438,14 +2440,22 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
 
 
 	if (length > usb_epinfo->wMaxPacketSize)
 	if (length > usb_epinfo->wMaxPacketSize)
 		length = usb_epinfo->wMaxPacketSize;
 		length = usb_epinfo->wMaxPacketSize;
+	else if (length == usb_epinfo->wMaxPacketSize)
+		eot = true;
 
 
 	/* Avoid any async transfers during shutdown to allow the polling
 	/* Avoid any async transfers during shutdown to allow the polling
 	 * thread to be shut down after all existing transfers are complete */
 	 * thread to be shut down after all existing transfers are complete */
 	if (unlikely(cgpu->shutdown))
 	if (unlikely(cgpu->shutdown))
 		return libusb_bulk_transfer(dev_handle, endpoint, data, length, transferred, timeout);
 		return libusb_bulk_transfer(dev_handle, endpoint, data, length, transferred, timeout);
 
 
-	if ((endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
+	if ((endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) {
 		memcpy(buf, data, length);
 		memcpy(buf, data, length);
+		/* If this is the last packet in a transfer and is the length
+		 * of the wMaxPacketSize then we need to send a zero length
+		 * packet to let the device know it's the end of the message.*/
+		if (eot)
+			zlp = true;
+	}
 
 
 	USBDEBUG("USB debug: @usb_bulk_transfer(%s (nodev=%s),intinfo=%d,epinfo=%d,data=%p,length=%d,timeout=%u,mode=%d,cmd=%s,seq=%d) endpoint=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), intinfo, epinfo, data, length, timeout, mode, usb_cmdname(cmd), seq, (int)endpoint);
 	USBDEBUG("USB debug: @usb_bulk_transfer(%s (nodev=%s),intinfo=%d,epinfo=%d,data=%p,length=%d,timeout=%u,mode=%d,cmd=%s,seq=%d) endpoint=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), intinfo, epinfo, data, length, timeout, mode, usb_cmdname(cmd), seq, (int)endpoint);
 
 
@@ -2488,6 +2498,8 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
 	}
 	}
 	if ((endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
 	if ((endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
 		memcpy(data, buf, *transferred);
 		memcpy(data, buf, *transferred);
+	else if (zlp) /* Send a zero length packet */
+		libusb_bulk_transfer(dev_handle, endpoint, NULL, 0, &dummy, 100);
 
 
 	return err;
 	return err;
 }
 }