|
@@ -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
|