Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 3 commits
  • 1 file changed
  • 0 comments
  • 2 contributors
Nov 15, 2011
Werner Almesberger softusb: remove compiler warning about unused variable 0decd11
Werner Almesberger softusb: implement the reset recovery interval
Sections 7.1.7.5 and 9.2.6.2 of the USB 2.0 spec say the a host has
to wait for at least 10 ms (Trstrcy) after reset before it can expect
a device to be able to receive data.

In Linux drivers/usb/core/hub.c:hub_port_reset we find this:

	/* TRSTRCY = 10 ms; plus some extra */
	msleep(10 + 40);

So let's use 50 ms.
6c4bb3f
Sébastien Bourdeauducq USB: send SOFs and keepalives on both ports and immediately after reset f6c7474

Showing 1 changed file with 75 additions and 21 deletions. Show diff stats Hide diff stats

  1. 96  softusb-input/main.c
96  softusb-input/main.c
@@ -40,6 +40,7 @@ enum {
40 40
 enum {
41 41
 	PORT_STATE_DISCONNECTED = 0,
42 42
 	PORT_STATE_BUS_RESET,
  43
+	PORT_STATE_RESET_WAIT,
43 44
 	PORT_STATE_SET_ADDRESS,
44 45
 	PORT_STATE_GET_DEVICE_DESCRIPTOR,
45 46
 	PORT_STATE_GET_CONFIGURATION_DESCRIPTOR,
@@ -48,6 +49,8 @@ enum {
48 49
 	PORT_STATE_UNSUPPORTED
49 50
 };
50 51
 
  52
+#define	RESET_RECOVERY_MS	50	/* USB 2.0, 7.1.7.5: >= 10 ms */
  53
+
51 54
 struct ep_status {
52 55
 	char ep;
53 56
 	unsigned char expected_data;
@@ -446,12 +449,6 @@ static void port_service(struct port_status *p, char name)
446 449
 		wio8(SIE_TX_LOW_SPEED, 0);
447 450
 	else
448 451
 		wio8(SIE_TX_LOW_SPEED, 1);
449  
-	if((p->full_speed) && (p->state > PORT_STATE_BUS_RESET)) {
450  
-		/* send SOF */
451  
-		unsigned char usb_buffer[3];
452  
-		make_usb_token(USB_PID_SOF, frame_nr, usb_buffer);
453  
-		usb_tx(usb_buffer, 3);
454  
-	}
455 452
 	switch(p->state) {
456 453
 		case PORT_STATE_DISCONNECTED: {
457 454
 			char linestat;
@@ -478,14 +475,21 @@ static void port_service(struct port_status *p, char name)
478 475
 			break;
479 476
 		}
480 477
 		case PORT_STATE_BUS_RESET:
481  
-			if(frame_nr == p->unreset_frame) {
482  
-				if(name == 'A')
483  
-					wio8(SIE_TX_BUSRESET, rio8(SIE_TX_BUSRESET) & 0x02);
484  
-				else
485  
-					wio8(SIE_TX_BUSRESET, rio8(SIE_TX_BUSRESET) & 0x01);
486  
-				p->state = PORT_STATE_SET_ADDRESS;
487  
-				p->retry_count = 0;
488  
-			}
  478
+			if(frame_nr != p->unreset_frame)
  479
+				break;
  480
+			if(name == 'A')
  481
+				wio8(SIE_TX_BUSRESET, rio8(SIE_TX_BUSRESET) & 0x02);
  482
+			else
  483
+				wio8(SIE_TX_BUSRESET, rio8(SIE_TX_BUSRESET) & 0x01);
  484
+			p->state = PORT_STATE_RESET_WAIT;
  485
+			p->unreset_frame =
  486
+			    (frame_nr + RESET_RECOVERY_MS) & 0x7ff;
  487
+			break;
  488
+		case PORT_STATE_RESET_WAIT:
  489
+			if(frame_nr != p->unreset_frame)
  490
+				break;
  491
+			p->state = PORT_STATE_SET_ADDRESS;
  492
+			p->retry_count = 0;
489 493
 			break;
490 494
 		case PORT_STATE_SET_ADDRESS: {
491 495
 			struct setup_packet packet;
@@ -609,10 +613,54 @@ static void port_service(struct port_status *p, char name)
609 613
 
610 614
 static const char banner[] PROGMEM = "softusb-input v"VERSION"\n";
611 615
 
  616
+static void sof()
  617
+{
  618
+	unsigned char mask;
  619
+	unsigned char usb_buffer[3];
  620
+	
  621
+	mask = 0;
  622
+	if(port_a.full_speed && (port_a.state > PORT_STATE_BUS_RESET))
  623
+		mask |= 0x01;
  624
+	if(port_b.full_speed && (port_b.state > PORT_STATE_BUS_RESET))
  625
+		mask |= 0x02;
  626
+	if(mask != 0) {
  627
+		wio8(SIE_TX_LOW_SPEED, 0);
  628
+		wio8(SIE_SEL_TX, mask);
  629
+		make_usb_token(USB_PID_SOF, frame_nr, usb_buffer);
  630
+		usb_tx(usb_buffer, 3);
  631
+	}
  632
+}
  633
+
  634
+static void keepalive()
  635
+{
  636
+	unsigned char mask;
  637
+	
  638
+	mask = 0;
  639
+	if(!port_a.full_speed && (port_a.state == PORT_STATE_RESET_WAIT))
  640
+		mask |= 0x01;
  641
+	if(!port_b.full_speed && (port_b.state == PORT_STATE_RESET_WAIT))
  642
+		mask |= 0x02;
  643
+	if(mask != 0) {
  644
+		wio8(SIE_TX_LOW_SPEED, 1);
  645
+		wio8(SIE_SEL_TX, mask);
  646
+		wio8(SIE_GENERATE_EOP, 1);
  647
+		while(rio8(SIE_TX_BUSY));
  648
+	}
  649
+}
  650
+
  651
+static void set_rx_speed()
  652
+{
  653
+	unsigned char mask;
  654
+	
  655
+	mask = 0;
  656
+	if(!port_a.full_speed) mask |= 0x01;
  657
+	if(!port_b.full_speed) mask |= 0x02;
  658
+	wio8(SIE_LOW_SPEED, mask);
  659
+}
  660
+
612 661
 int main()
613 662
 {
614 663
 	unsigned char i;
615  
-	unsigned char mask;
616 664
 
617 665
 	print_string(banner);
618 666
 
@@ -622,14 +670,17 @@ int main()
622 670
 		while((rio8(TIMER1) < 0xbb) || (rio8(TIMER0) < 0x70));
623 671
 		wio8(TIMER0, 0);
624 672
 
  673
+		sof();
  674
+		keepalive();
  675
+
625 676
 		/*
626  
-		 * set RX speed bits
  677
+		 * wait extra time to allow the USB cable
  678
+		 * capacitance to discharge (otherwise some disconnects
  679
+		 * aren't properly detected)
627 680
 		 */
628  
-		mask = 0;
629  
-		if(!port_a.full_speed) mask |= 0x01;
630  
-		if(!port_b.full_speed) mask |= 0x02;
631  
-		wio8(SIE_LOW_SPEED, mask);
632  
-
  681
+		for(i=0;i<128;i++)
  682
+			asm("nop");
  683
+		
633 684
 		wio8(SIE_SEL_RX, 0);
634 685
 		wio8(SIE_SEL_TX, 0x01);
635 686
 		port_service(&port_a, 'A');
@@ -637,6 +688,9 @@ int main()
637 688
 		wio8(SIE_SEL_RX, 1);
638 689
 		wio8(SIE_SEL_TX, 0x02);
639 690
 		port_service(&port_b, 'B');
  691
+		
  692
+		/* set RX speed for new detected devices */
  693
+		set_rx_speed();
640 694
 
641 695
 		frame_nr = (frame_nr + 1) & 0x7ff;
642 696
 	}

No commit comments for this range

Something went wrong with that request. Please try again.