Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 6 commits
  • 1 file changed
  • 0 comments
  • 2 contributors
Nov 19, 2011
Werner Almesberger softusb: partially unroll usb_in
This patch partially unrolls usb_in and takes decisions on the further
disposition of a packet at early as possible. The objective is to
minimize the processing needed between EOP of the DATAx packet and the
sending of an ACK.

The patch also changes error handling in two ways:

1) when deciding to discard a packet, always wait until the device
   really stops sending

2) packets with a garbled PID are treated as non-fatal errors
016e556
Werner Almesberger softusb: send ACKs from dedicated inline function
To accelerate sending ACKs, this patch avoids the call setup overhead
of usb_tx and introduces a dedicated inline function. In experiments,
this reduced EOP-to-ACK time by about 10 full-speed bit times.
f3023cf
Werner Almesberger softusb: fail garbled packets fatally again
As the result of more testing that showed no degradation in performance,
this reverts to the original logic of failing garbled packets harder.
f995f37
Werner Almesberger softusb: convert last remaining use of usb_rx to usb_rx_ack
Since usb_rx is now only used to receive ACK/NAK, we can replace it
with a more streamlined version. This should also marginally improve
error handling.
8fcbc21
Werner Almesberger softusb: clear EPs on disconnect
Along with the logic to handle multiple interfaces, commit
a26dc51 also introduced the following
bug:

When a keyboard or composite device with keyboard was replaced by a
mouse after enumeration, the stack would still poll the "keyboard",
which most likely resulted in the mouse data to be b drained and
discarded.

This patch clears the EP roles on disconnect.
5695188
Sébastien Bourdeauducq softusb: update copyright notice 3a7e212

Showing 1 changed file with 124 additions and 69 deletions. Show diff stats Hide diff stats

  1. 193  softusb-input/main.c
193  softusb-input/main.c
... ...
@@ -1,6 +1,7 @@
1 1
 /*
2 2
  * Milkymist SoC (USB firmware)
3  
- * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
  3
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
  4
+ * Copyright (C) 2011 Werner Almesberger
4 5
  *
5 6
  * This program is free software: you can redistribute it and/or modify
6 7
  * it under the terms of the GNU General Public License as published by
@@ -96,48 +97,71 @@ static void usb_tx(const unsigned char *buf, unsigned char len)
96 97
 	while(rio8(SIE_TX_BUSY));
97 98
 }
98 99
 
99  
-static const char transfer_start[] PROGMEM = "Transfer start: ";
  100
+static inline void usb_ack(void)
  101
+{
  102
+	wio8(SIE_TX_DATA, 0x80); /* send SYNC */
  103
+	while(rio8(SIE_TX_PENDING));
  104
+	wio8(SIE_TX_DATA, USB_PID_ACK); /* send SYNC */
  105
+	while(rio8(SIE_TX_PENDING));
  106
+	wio8(SIE_TX_VALID, 0);
  107
+	while(rio8(SIE_TX_BUSY));
  108
+}
  109
+
  110
+static const char ack_error[] PROGMEM = "ACK: ";
100 111
 static const char timeout_error[] PROGMEM = "RX timeout error\n";
101 112
 static const char bitstuff_error[] PROGMEM = "RX bitstuff error\n";
102 113
 
103  
-static unsigned char usb_rx(unsigned char *buf, unsigned char maxlen)
  114
+#define	WAIT_RX(first, end)					\
  115
+	do {							\
  116
+		unsigned timeout = 0x200;			\
  117
+		while(!rio8(SIE_RX_PENDING)) {			\
  118
+			if(!--timeout)				\
  119
+				goto timeout;			\
  120
+			if(rio8(SIE_RX_ERROR))			\
  121
+				goto error;			\
  122
+			if(!first && !rio8(SIE_RX_ACTIVE))	\
  123
+				goto end;			\
  124
+		}						\
  125
+	} while (0)
  126
+
  127
+
  128
+static char usb_rx_ack(void)
104 129
 {
105  
-	unsigned int timeout;
  130
+	unsigned char pid;
106 131
 	unsigned char i;
107 132
 
108  
-	i = 0;
109  
-	timeout = 0x1ff;
110  
-	while(!rio8(SIE_RX_PENDING)) {
111  
-		if(timeout-- == 0) {
112  
-			print_string(transfer_start);
113  
-			print_string(timeout_error);
114  
-			return 0;
115  
-		}
116  
-		if(rio8(SIE_RX_ERROR)) {
117  
-			print_string(transfer_start);
118  
-			print_string(bitstuff_error);
119  
-			return 0;
120  
-		}
121  
-	}
122  
-	while(1) {
123  
-		timeout = 0x1ff;
124  
-		while(!rio8(SIE_RX_PENDING)) {
125  
-			if(rio8(SIE_RX_ERROR)) {
126  
-				print_string(bitstuff_error);
127  
-				return 0;
128  
-			}
129  
-			if(!rio8(SIE_RX_ACTIVE))
130  
-				return i;
131  
-			if(timeout-- == 0) {
132  
-				print_string(timeout_error);
133  
-				return 0;
134  
-			}
135  
-		}
136  
-		if(i == maxlen)
137  
-			return 0;
138  
-		buf[i] = rio8(SIE_RX_DATA);
139  
-		i++;
140  
-	}
  133
+	/* SYNC */
  134
+	WAIT_RX(1, nothing);
  135
+
  136
+	/* PID */
  137
+	WAIT_RX(0, nothing);
  138
+	pid = rio8(SIE_RX_DATA);
  139
+
  140
+	/* wait for idle, or simply time out and fall foward */
  141
+	for(i = 200; i; i--)
  142
+		if(!rio8(SIE_RX_ACTIVE))
  143
+			break;
  144
+
  145
+	if(pid == USB_PID_ACK)
  146
+		return 1;
  147
+	if(pid == USB_PID_NAK)
  148
+		return 0;
  149
+
  150
+	for(i = 200; i; i--)
  151
+		WAIT_RX(0,out);
  152
+out:
  153
+	print_string(ack_error);
  154
+	print_hex(pid);
  155
+	print_char('\n');
  156
+	return -1;
  157
+
  158
+timeout:
  159
+	print_string(timeout_error);
  160
+nothing:
  161
+	return 0;
  162
+error:
  163
+	print_string(bitstuff_error);
  164
+	return 0;
141 165
 }
142 166
 
143 167
 static const char in_reply[] PROGMEM = "IN reply:\n";
@@ -147,32 +171,76 @@ static int usb_in(unsigned addr, unsigned char expected_data,
147 171
     unsigned char *buf, unsigned char maxlen)
148 172
 {
149 173
 	unsigned char in[3];
150  
-	unsigned char ack[1] = { USB_PID_ACK };
151  
-	unsigned char len;
  174
+	unsigned char len = 1;
  175
+	unsigned char i;
152 176
 
153 177
 	/* send IN */
154 178
 	make_usb_token(USB_PID_IN, addr, in);
155 179
 	usb_tx(in, 3);
156 180
 
157  
-	/* receive DATAx */
158  
-	len = usb_rx(buf, maxlen);
159  
-	if(!len) /* timeout or massive confusion */
160  
-		return 0;
  181
+	/* SYNC */
  182
+	WAIT_RX(1, nothing);
  183
+
  184
+	/* PID */
  185
+	WAIT_RX(0, nothing);
  186
+	buf[0] = rio8(SIE_RX_DATA);
  187
+
  188
+	if(buf[0] == expected_data)
  189
+		goto receive;
  190
+	if(buf[0] == USB_PID_DATA0 || buf[0] == USB_PID_DATA1)
  191
+		goto ignore;
161 192
 	if(buf[0] == USB_PID_NAK)
162 193
 		return 0;
163  
-	if(buf[0] != USB_PID_DATA0 && buf[0] != USB_PID_DATA1) {
164  
-		print_string(in_reply);
165  
-		dump_hex(buf, len);
166  
-		return -1;
  194
+
  195
+	/* unknown packet: try to receive for debug purposes, then dump */
  196
+
  197
+	while(len != maxlen) {
  198
+		WAIT_RX(0, fail);
  199
+		buf[len++] = rio8(SIE_RX_DATA);
167 200
 	}
  201
+fail:
  202
+	print_string(in_reply);
  203
+	dump_hex(buf, len);
  204
+	return -1;
168 205
 
169  
-	/* send ACK */
170  
-	usb_tx(ack, 1);
171  
-	if(buf[0] == expected_data)
172  
-		return len;
  206
+	/* bad sequence bit: wait until packet has arrived, then ack */
173 207
 
  208
+ignore:
  209
+	for(i = 200; i; i--)
  210
+		WAIT_RX(0, ignore_eop);
  211
+	goto complain; /* this doesn't stop - just quit silently */
  212
+ignore_eop:
  213
+	usb_ack();
  214
+complain:
174 215
 	print_string(datax_mismatch);
175 216
 	return 0;
  217
+
  218
+	/* receive the rest of the (good) packet */
  219
+
  220
+receive:
  221
+	while(1) {
  222
+		WAIT_RX(0, eop);
  223
+		if(len == maxlen)
  224
+			goto discard;
  225
+		buf[len++] = rio8(SIE_RX_DATA);
  226
+	}
  227
+eop:
  228
+	usb_ack();
  229
+	return len;
  230
+
  231
+discard:
  232
+	for(i = 200; i; i--)
  233
+		WAIT_RX(0, nothing);
  234
+nothing:
  235
+	return 0;
  236
+
  237
+timeout:
  238
+	print_string(timeout_error);
  239
+	return 0;
  240
+
  241
+error:
  242
+	print_string(bitstuff_error);
  243
+	return 0;
176 244
 }
177 245
 
178 246
 static const char out_reply[] PROGMEM = "OUT/DATA reply:\n";
@@ -180,8 +248,6 @@ static const char out_reply[] PROGMEM = "OUT/DATA reply:\n";
180 248
 static char usb_out(unsigned addr, const unsigned char *buf, unsigned char len)
181 249
 {
182 250
 	unsigned char out[3];
183  
-	unsigned char ack[11];
184  
-	unsigned char got;
185 251
 
186 252
 	/* send OUT */
187 253
 	make_usb_token(USB_PID_OUT, addr, out);
@@ -191,15 +257,7 @@ static char usb_out(unsigned addr, const unsigned char *buf, unsigned char len)
191 257
 	usb_tx(buf, len);
192 258
 
193 259
 	/* receive ACK */
194  
-	got = usb_rx(ack, 11);
195  
-	if(got == 1 && ack[0] == USB_PID_ACK)
196  
-		return 1;
197  
-	if (!got || ack[0] == USB_PID_NAK) /* timeout or NAK */
198  
-		return 0;
199  
-
200  
-	print_string(out_reply);
201  
-	dump_hex(ack, got);
202  
-	return -1;
  260
+	return usb_rx_ack();
203 261
 }
204 262
 
205 263
 struct setup_packet {
@@ -215,8 +273,7 @@ static inline unsigned char toggle(unsigned char old)
215 273
 	return old ^ USB_PID_DATA0 ^ USB_PID_DATA1;
216 274
 }
217 275
 
218  
-static const char control_failed[] PROGMEM = "Control transfer failed:\n";
219  
-static const char setup_reply[] PROGMEM = "SETUP reply:\n";
  276
+static const char setup_ack[] PROGMEM = "SETUP not ACKed\n";
220 277
 
221 278
 static int control_transfer(unsigned char addr, struct setup_packet *p,
222 279
     char out, unsigned char *payload, int maxlen)
@@ -244,11 +301,8 @@ wio8(SIE_SEL_TX, 3);
244 301
 wio8(SIE_SEL_TX, 2);
245 302
 #endif
246 303
 	/* get ACK token from device */
247  
-	rxlen = usb_rx(usb_buffer, 11);
248  
-	if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
249  
-		print_string(control_failed);
250  
-		print_string(setup_reply);
251  
-		dump_hex(usb_buffer, rxlen);
  304
+	if(usb_rx_ack() != 1) {
  305
+		print_string(setup_ack);
252 306
 		return -1;
253 307
 	}
254 308
 
@@ -385,6 +439,7 @@ static void check_discon(struct port_status *p, char name)
385 439
 	if(discon) {
386 440
 		print_string(disconnect); print_char(name); print_char('\n');
387 441
 		p->state = PORT_STATE_DISCONNECTED;
  442
+		p->keyboard.ep = p->mouse.ep = 0;
388 443
 	}
389 444
 }
390 445
 

No commit comments for this range

Something went wrong with that request. Please try again.