|  | @@ -313,6 +313,8 @@ int usb_endpoint_open ( struct usb_endpoint *ep ) {
 | 
		
	
		
			
			| 313 | 313 |   err_open:
 | 
		
	
		
			
			| 314 | 314 |  	usb->ep[idx] = NULL;
 | 
		
	
		
			
			| 315 | 315 |   err_already:
 | 
		
	
		
			
			|  | 316 | +	if ( ep->max )
 | 
		
	
		
			
			|  | 317 | +		usb_flush ( ep );
 | 
		
	
		
			
			| 316 | 318 |  	return rc;
 | 
		
	
		
			
			| 317 | 319 |  }
 | 
		
	
		
			
			| 318 | 320 |  
 | 
		
	
	
		
			
			|  | @@ -331,9 +333,14 @@ void usb_endpoint_close ( struct usb_endpoint *ep ) {
 | 
		
	
		
			
			| 331 | 333 |  	/* Close endpoint */
 | 
		
	
		
			
			| 332 | 334 |  	ep->open = 0;
 | 
		
	
		
			
			| 333 | 335 |  	ep->host->close ( ep );
 | 
		
	
		
			
			|  | 336 | +	assert ( ep->fill == 0 );
 | 
		
	
		
			
			| 334 | 337 |  
 | 
		
	
		
			
			| 335 | 338 |  	/* Remove from endpoint list */
 | 
		
	
		
			
			| 336 | 339 |  	usb->ep[idx] = NULL;
 | 
		
	
		
			
			|  | 340 | +
 | 
		
	
		
			
			|  | 341 | +	/* Discard any recycled buffers, if applicable */
 | 
		
	
		
			
			|  | 342 | +	if ( ep->max )
 | 
		
	
		
			
			|  | 343 | +		usb_flush ( ep );
 | 
		
	
		
			
			| 337 | 344 |  }
 | 
		
	
		
			
			| 338 | 345 |  
 | 
		
	
		
			
			| 339 | 346 |  /**
 | 
		
	
	
		
			
			|  | @@ -443,6 +450,9 @@ int usb_message ( struct usb_endpoint *ep, unsigned int request,
 | 
		
	
		
			
			| 443 | 450 |  		return rc;
 | 
		
	
		
			
			| 444 | 451 |  	}
 | 
		
	
		
			
			| 445 | 452 |  
 | 
		
	
		
			
			|  | 453 | +	/* Increment fill level */
 | 
		
	
		
			
			|  | 454 | +	ep->fill++;
 | 
		
	
		
			
			|  | 455 | +
 | 
		
	
		
			
			| 446 | 456 |  	return 0;
 | 
		
	
		
			
			| 447 | 457 |  }
 | 
		
	
		
			
			| 448 | 458 |  
 | 
		
	
	
		
			
			|  | @@ -476,6 +486,9 @@ int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf,
 | 
		
	
		
			
			| 476 | 486 |  		return rc;
 | 
		
	
		
			
			| 477 | 487 |  	}
 | 
		
	
		
			
			| 478 | 488 |  
 | 
		
	
		
			
			|  | 489 | +	/* Increment fill level */
 | 
		
	
		
			
			|  | 490 | +	ep->fill++;
 | 
		
	
		
			
			|  | 491 | +
 | 
		
	
		
			
			| 479 | 492 |  	return 0;
 | 
		
	
		
			
			| 480 | 493 |  }
 | 
		
	
		
			
			| 481 | 494 |  
 | 
		
	
	
		
			
			|  | @@ -490,6 +503,10 @@ void usb_complete_err ( struct usb_endpoint *ep, struct io_buffer *iobuf,
 | 
		
	
		
			
			| 490 | 503 |  			int rc ) {
 | 
		
	
		
			
			| 491 | 504 |  	struct usb_device *usb = ep->usb;
 | 
		
	
		
			
			| 492 | 505 |  
 | 
		
	
		
			
			|  | 506 | +	/* Decrement fill level */
 | 
		
	
		
			
			|  | 507 | +	assert ( ep->fill > 0 );
 | 
		
	
		
			
			|  | 508 | +	ep->fill--;
 | 
		
	
		
			
			|  | 509 | +
 | 
		
	
		
			
			| 493 | 510 |  	/* Record error (if any) */
 | 
		
	
		
			
			| 494 | 511 |  	ep->rc = rc;
 | 
		
	
		
			
			| 495 | 512 |  	if ( ( rc != 0 ) && ep->open ) {
 | 
		
	
	
		
			
			|  | @@ -502,6 +519,117 @@ void usb_complete_err ( struct usb_endpoint *ep, struct io_buffer *iobuf,
 | 
		
	
		
			
			| 502 | 519 |  	ep->driver->complete ( ep, iobuf, rc );
 | 
		
	
		
			
			| 503 | 520 |  }
 | 
		
	
		
			
			| 504 | 521 |  
 | 
		
	
		
			
			|  | 522 | +/******************************************************************************
 | 
		
	
		
			
			|  | 523 | + *
 | 
		
	
		
			
			|  | 524 | + * Endpoint refilling
 | 
		
	
		
			
			|  | 525 | + *
 | 
		
	
		
			
			|  | 526 | + ******************************************************************************
 | 
		
	
		
			
			|  | 527 | + */
 | 
		
	
		
			
			|  | 528 | +
 | 
		
	
		
			
			|  | 529 | +/**
 | 
		
	
		
			
			|  | 530 | + * Prefill endpoint recycled buffer list
 | 
		
	
		
			
			|  | 531 | + *
 | 
		
	
		
			
			|  | 532 | + * @v ep		USB endpoint
 | 
		
	
		
			
			|  | 533 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 534 | + */
 | 
		
	
		
			
			|  | 535 | +int usb_prefill ( struct usb_endpoint *ep ) {
 | 
		
	
		
			
			|  | 536 | +	struct io_buffer *iobuf;
 | 
		
	
		
			
			|  | 537 | +	size_t len = ( ep->len ? ep->len : ep->mtu );
 | 
		
	
		
			
			|  | 538 | +	unsigned int fill;
 | 
		
	
		
			
			|  | 539 | +	int rc;
 | 
		
	
		
			
			|  | 540 | +
 | 
		
	
		
			
			|  | 541 | +	/* Sanity checks */
 | 
		
	
		
			
			|  | 542 | +	assert ( ep->fill == 0 );
 | 
		
	
		
			
			|  | 543 | +	assert ( ep->max > 0 );
 | 
		
	
		
			
			|  | 544 | +	assert ( list_empty ( &ep->recycled ) );
 | 
		
	
		
			
			|  | 545 | +
 | 
		
	
		
			
			|  | 546 | +	/* Fill recycled buffer list */
 | 
		
	
		
			
			|  | 547 | +	for ( fill = 0 ; fill < ep->max ; fill++ ) {
 | 
		
	
		
			
			|  | 548 | +
 | 
		
	
		
			
			|  | 549 | +		/* Allocate I/O buffer */
 | 
		
	
		
			
			|  | 550 | +		iobuf = alloc_iob ( len );
 | 
		
	
		
			
			|  | 551 | +		if ( ! iobuf ) {
 | 
		
	
		
			
			|  | 552 | +			rc = -ENOMEM;
 | 
		
	
		
			
			|  | 553 | +			goto err_alloc;
 | 
		
	
		
			
			|  | 554 | +		}
 | 
		
	
		
			
			|  | 555 | +
 | 
		
	
		
			
			|  | 556 | +		/* Add to recycled buffer list */
 | 
		
	
		
			
			|  | 557 | +		list_add_tail ( &iobuf->list, &ep->recycled );
 | 
		
	
		
			
			|  | 558 | +	}
 | 
		
	
		
			
			|  | 559 | +
 | 
		
	
		
			
			|  | 560 | +	return 0;
 | 
		
	
		
			
			|  | 561 | +
 | 
		
	
		
			
			|  | 562 | + err_alloc:
 | 
		
	
		
			
			|  | 563 | +	usb_flush ( ep );
 | 
		
	
		
			
			|  | 564 | +	return rc;
 | 
		
	
		
			
			|  | 565 | +}
 | 
		
	
		
			
			|  | 566 | +
 | 
		
	
		
			
			|  | 567 | +/**
 | 
		
	
		
			
			|  | 568 | + * Refill endpoint
 | 
		
	
		
			
			|  | 569 | + *
 | 
		
	
		
			
			|  | 570 | + * @v ep		USB endpoint
 | 
		
	
		
			
			|  | 571 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 572 | + */
 | 
		
	
		
			
			|  | 573 | +int usb_refill ( struct usb_endpoint *ep ) {
 | 
		
	
		
			
			|  | 574 | +	struct io_buffer *iobuf;
 | 
		
	
		
			
			|  | 575 | +	size_t len = ( ep->len ? ep->len : ep->mtu );
 | 
		
	
		
			
			|  | 576 | +	int rc;
 | 
		
	
		
			
			|  | 577 | +
 | 
		
	
		
			
			|  | 578 | +	/* Sanity checks */
 | 
		
	
		
			
			|  | 579 | +	assert ( ep->open );
 | 
		
	
		
			
			|  | 580 | +	assert ( ep->max > 0 );
 | 
		
	
		
			
			|  | 581 | +
 | 
		
	
		
			
			|  | 582 | +	/* Refill endpoint */
 | 
		
	
		
			
			|  | 583 | +	while ( ep->fill < ep->max ) {
 | 
		
	
		
			
			|  | 584 | +
 | 
		
	
		
			
			|  | 585 | +		/* Get or allocate buffer */
 | 
		
	
		
			
			|  | 586 | +		if ( list_empty ( &ep->recycled ) ) {
 | 
		
	
		
			
			|  | 587 | +			/* Recycled buffer list is empty; allocate new buffer */
 | 
		
	
		
			
			|  | 588 | +			iobuf = alloc_iob ( len );
 | 
		
	
		
			
			|  | 589 | +			if ( ! iobuf )
 | 
		
	
		
			
			|  | 590 | +				return -ENOMEM;
 | 
		
	
		
			
			|  | 591 | +		} else {
 | 
		
	
		
			
			|  | 592 | +			/* Get buffer from recycled buffer list */
 | 
		
	
		
			
			|  | 593 | +			iobuf = list_first_entry ( &ep->recycled,
 | 
		
	
		
			
			|  | 594 | +						   struct io_buffer, list );
 | 
		
	
		
			
			|  | 595 | +			assert ( iobuf != NULL );
 | 
		
	
		
			
			|  | 596 | +			list_del ( &iobuf->list );
 | 
		
	
		
			
			|  | 597 | +		}
 | 
		
	
		
			
			|  | 598 | +
 | 
		
	
		
			
			|  | 599 | +		/* Reset buffer to maximum size */
 | 
		
	
		
			
			|  | 600 | +		assert ( iob_len ( iobuf ) <= len );
 | 
		
	
		
			
			|  | 601 | +		iob_put ( iobuf, ( len - iob_len ( iobuf ) ) );
 | 
		
	
		
			
			|  | 602 | +
 | 
		
	
		
			
			|  | 603 | +		/* Enqueue buffer */
 | 
		
	
		
			
			|  | 604 | +		if ( ( rc = usb_stream ( ep, iobuf, 0 ) ) != 0 ) {
 | 
		
	
		
			
			|  | 605 | +			list_add ( &iobuf->list, &ep->recycled );
 | 
		
	
		
			
			|  | 606 | +			return rc;
 | 
		
	
		
			
			|  | 607 | +		}
 | 
		
	
		
			
			|  | 608 | +	}
 | 
		
	
		
			
			|  | 609 | +
 | 
		
	
		
			
			|  | 610 | +	return 0;
 | 
		
	
		
			
			|  | 611 | +}
 | 
		
	
		
			
			|  | 612 | +
 | 
		
	
		
			
			|  | 613 | +/**
 | 
		
	
		
			
			|  | 614 | + * Discard endpoint recycled buffer list
 | 
		
	
		
			
			|  | 615 | + *
 | 
		
	
		
			
			|  | 616 | + * @v ep		USB endpoint
 | 
		
	
		
			
			|  | 617 | + */
 | 
		
	
		
			
			|  | 618 | +void usb_flush ( struct usb_endpoint *ep ) {
 | 
		
	
		
			
			|  | 619 | +	struct io_buffer *iobuf;
 | 
		
	
		
			
			|  | 620 | +	struct io_buffer *tmp;
 | 
		
	
		
			
			|  | 621 | +
 | 
		
	
		
			
			|  | 622 | +	/* Sanity checks */
 | 
		
	
		
			
			|  | 623 | +	assert ( ! ep->open );
 | 
		
	
		
			
			|  | 624 | +	assert ( ep->max > 0 );
 | 
		
	
		
			
			|  | 625 | +
 | 
		
	
		
			
			|  | 626 | +	/* Free all I/O buffers */
 | 
		
	
		
			
			|  | 627 | +	list_for_each_entry_safe ( iobuf, tmp, &ep->recycled, list ) {
 | 
		
	
		
			
			|  | 628 | +		list_del ( &iobuf->list );
 | 
		
	
		
			
			|  | 629 | +		free_iob ( iobuf );
 | 
		
	
		
			
			|  | 630 | +	}
 | 
		
	
		
			
			|  | 631 | +}
 | 
		
	
		
			
			|  | 632 | +
 | 
		
	
		
			
			| 505 | 633 |  /******************************************************************************
 | 
		
	
		
			
			| 506 | 634 |   *
 | 
		
	
		
			
			| 507 | 635 |   * Control endpoint
 |