|  | @@ -1220,6 +1220,30 @@ static int ehci_endpoint_message ( struct usb_endpoint *ep,
 | 
		
	
		
			
			| 1220 | 1220 |  	return 0;
 | 
		
	
		
			
			| 1221 | 1221 |  }
 | 
		
	
		
			
			| 1222 | 1222 |  
 | 
		
	
		
			
			|  | 1223 | +/**
 | 
		
	
		
			
			|  | 1224 | + * Calculate number of transfer descriptors
 | 
		
	
		
			
			|  | 1225 | + *
 | 
		
	
		
			
			|  | 1226 | + * @v len		Length of data
 | 
		
	
		
			
			|  | 1227 | + * @v zlp		Append a zero-length packet
 | 
		
	
		
			
			|  | 1228 | + * @ret count		Number of transfer descriptors
 | 
		
	
		
			
			|  | 1229 | + */
 | 
		
	
		
			
			|  | 1230 | +static unsigned int ehci_endpoint_count ( size_t len, int zlp ) {
 | 
		
	
		
			
			|  | 1231 | +	unsigned int count;
 | 
		
	
		
			
			|  | 1232 | +
 | 
		
	
		
			
			|  | 1233 | +	/* Split into 16kB transfers.  A single transfer can handle up
 | 
		
	
		
			
			|  | 1234 | +	 * to 20kB if it happens to be page-aligned, or up to 16kB
 | 
		
	
		
			
			|  | 1235 | +	 * with arbitrary alignment.  We simplify the code by assuming
 | 
		
	
		
			
			|  | 1236 | +	 * that we can fit only 16kB into each transfer.
 | 
		
	
		
			
			|  | 1237 | +	 */
 | 
		
	
		
			
			|  | 1238 | +	count = ( ( len + EHCI_MTU - 1 ) / EHCI_MTU );
 | 
		
	
		
			
			|  | 1239 | +
 | 
		
	
		
			
			|  | 1240 | +	/* Append a zero-length transfer if applicable */
 | 
		
	
		
			
			|  | 1241 | +	if ( zlp || ( count == 0 ) )
 | 
		
	
		
			
			|  | 1242 | +		count++;
 | 
		
	
		
			
			|  | 1243 | +
 | 
		
	
		
			
			|  | 1244 | +	return count;
 | 
		
	
		
			
			|  | 1245 | +}
 | 
		
	
		
			
			|  | 1246 | +
 | 
		
	
		
			
			| 1223 | 1247 |  /**
 | 
		
	
		
			
			| 1224 | 1248 |   * Enqueue stream transfer
 | 
		
	
		
			
			| 1225 | 1249 |   *
 | 
		
	
	
		
			
			|  | @@ -1232,29 +1256,40 @@ static int ehci_endpoint_stream ( struct usb_endpoint *ep,
 | 
		
	
		
			
			| 1232 | 1256 |  				  struct io_buffer *iobuf, int zlp ) {
 | 
		
	
		
			
			| 1233 | 1257 |  	struct ehci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep );
 | 
		
	
		
			
			| 1234 | 1258 |  	struct ehci_device *ehci = endpoint->ehci;
 | 
		
	
		
			
			|  | 1259 | +	void *data = iobuf->data;
 | 
		
	
		
			
			|  | 1260 | +	size_t len = iob_len ( iobuf );
 | 
		
	
		
			
			|  | 1261 | +	unsigned int count = ehci_endpoint_count ( len, zlp );
 | 
		
	
		
			
			| 1235 | 1262 |  	unsigned int input = ( ep->address & USB_DIR_IN );
 | 
		
	
		
			
			| 1236 |  | -	struct ehci_transfer xfers[2];
 | 
		
	
		
			
			|  | 1263 | +	unsigned int flags = ( input ? EHCI_FL_PID_IN : EHCI_FL_PID_OUT );
 | 
		
	
		
			
			|  | 1264 | +	struct ehci_transfer xfers[count];
 | 
		
	
		
			
			| 1237 | 1265 |  	struct ehci_transfer *xfer = xfers;
 | 
		
	
		
			
			| 1238 |  | -	size_t len = iob_len ( iobuf );
 | 
		
	
		
			
			|  | 1266 | +	size_t xfer_len;
 | 
		
	
		
			
			|  | 1267 | +	unsigned int i;
 | 
		
	
		
			
			| 1239 | 1268 |  	int rc;
 | 
		
	
		
			
			| 1240 | 1269 |  
 | 
		
	
		
			
			| 1241 |  | -	/* Create transfer */
 | 
		
	
		
			
			| 1242 |  | -	xfer->data = iobuf->data;
 | 
		
	
		
			
			| 1243 |  | -	xfer->len = len;
 | 
		
	
		
			
			| 1244 |  | -	xfer->flags = ( EHCI_FL_IOC |
 | 
		
	
		
			
			| 1245 |  | -			( input ? EHCI_FL_PID_IN : EHCI_FL_PID_OUT ) );
 | 
		
	
		
			
			| 1246 |  | -	xfer++;
 | 
		
	
		
			
			| 1247 |  | -	if ( zlp ) {
 | 
		
	
		
			
			| 1248 |  | -		xfer->data = NULL;
 | 
		
	
		
			
			| 1249 |  | -		xfer->len = 0;
 | 
		
	
		
			
			| 1250 |  | -		assert ( ! input );
 | 
		
	
		
			
			| 1251 |  | -		xfer->flags = ( EHCI_FL_IOC | EHCI_FL_PID_OUT );
 | 
		
	
		
			
			|  | 1270 | +	/* Create transfers */
 | 
		
	
		
			
			|  | 1271 | +	for ( i = 0 ; i < count ; i++ ) {
 | 
		
	
		
			
			|  | 1272 | +
 | 
		
	
		
			
			|  | 1273 | +		/* Calculate transfer length */
 | 
		
	
		
			
			|  | 1274 | +		xfer_len = EHCI_MTU;
 | 
		
	
		
			
			|  | 1275 | +		if ( xfer_len > len )
 | 
		
	
		
			
			|  | 1276 | +			xfer_len = len;
 | 
		
	
		
			
			|  | 1277 | +
 | 
		
	
		
			
			|  | 1278 | +		/* Create transfer */
 | 
		
	
		
			
			|  | 1279 | +		xfer->data = data;
 | 
		
	
		
			
			|  | 1280 | +		xfer->len = xfer_len;
 | 
		
	
		
			
			|  | 1281 | +		xfer->flags = flags;
 | 
		
	
		
			
			|  | 1282 | +
 | 
		
	
		
			
			|  | 1283 | +		/* Move to next transfer */
 | 
		
	
		
			
			|  | 1284 | +		data += xfer_len;
 | 
		
	
		
			
			|  | 1285 | +		len -= xfer_len;
 | 
		
	
		
			
			| 1252 | 1286 |  		xfer++;
 | 
		
	
		
			
			| 1253 | 1287 |  	}
 | 
		
	
		
			
			|  | 1288 | +	xfer[-1].flags |= EHCI_FL_IOC;
 | 
		
	
		
			
			| 1254 | 1289 |  
 | 
		
	
		
			
			| 1255 | 1290 |  	/* Enqueue transfer */
 | 
		
	
		
			
			| 1256 | 1291 |  	if ( ( rc = ehci_enqueue ( ehci, &endpoint->ring, iobuf, xfers,
 | 
		
	
		
			
			| 1257 |  | -				   ( xfer - xfers ) ) ) != 0 )
 | 
		
	
		
			
			|  | 1292 | +				   count ) ) != 0 )
 | 
		
	
		
			
			| 1258 | 1293 |  		return rc;
 | 
		
	
		
			
			| 1259 | 1294 |  
 | 
		
	
		
			
			| 1260 | 1295 |  	return 0;
 |