Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 11 commits
  • 1 file changed
  • 0 comments
  • 2 contributors
Nov 19, 2011
Werner Almesberger softusb: 4 kB hack f1c0fe7
Werner Almesberger softusb: use OE# of port A for trigger c8111e5
Werner Almesberger softusb: send SETUP and DATA0 back-to-back edf599e
Werner Almesberger softusb: simplify and correct data toggle in control transactions
This patch does three things:

1) it replaces get_data_token with a simpler and more efficient
   version that doesn't unconditionally toggle

2) it only toggles the transmitter-side sequence if the DATAx
   packet is acknowledged (USB 1.1 sec 8.6 pg 168 and USB 2.0
   sec 8.6 pg 232)

3) it always sends DATA1 in the status stage, in accordance with
   USB 1.1 sec 8.5.2 pg 165 and USB 2.0 sec 8.5.3 pg 226.

In testing, this patch reduced the probability of the low-speed device
used (the Rii RF keyboard) registering. This seems to simply be the
effect of bugs eliminated in later patches having a greater effect,
and does not constitute a regression of code correctness.
4e255d0
Werner Almesberger softusb: in SETUP, only use IN data with the right sequence bit
This also removes the functional regression of the previous commit.
f246bcf
Werner Almesberger softusb: use toggle() also for bulk/interrupt 7c9748b
Werner Almesberger softusb: swap in_reply and out_reply 9a26965
Werner Almesberger softusb: move all IN transfers to function usb_in
Besides reducing some redundancy, this patch also makes the following
changes:

- retry on timeout (e.g., if the DATAx packet was garbled) in the data
  stage of control transfers instead of failing the entire transfer

- retry IN tranfers in the status stage

- reject IN transfers in the status stage if they have the wrong
  sequence bit (more USB 1.1 sec 8.5.2 and USB 2.0 sec 8.5.3)

- slightly reduce the information in debugging output since control
  and bulk/interrupt now use the same code path for IN transfers

The streamlined code path also makes full-speed work occasionally.
d5ae456
Werner Almesberger softusb: move all OUT transfers to function usb_out
This is mainly cosmetic, to reduce the amount of code. It adds
retry on timeout, though.

Again, as a side-effect, debug messages become a bit less detailed.
0ff5764
Werner Almesberger suftusb: remove one now unused debug message 309d30d
Sébastien Bourdeauducq Revert 4KB hack 6e8c7b1

Showing 1 changed file with 119 additions and 108 deletions. Show diff stats Hide diff stats

  1. 227  softusb-input/main.c
227  softusb-input/main.c
@@ -26,6 +26,8 @@
26 26
 #include "host.h"
27 27
 #include "crc.h"
28 28
 
  29
+//#define	TRIGGER
  30
+
29 31
 enum {
30 32
 	USB_PID_OUT	= 0xe1,
31 33
 	USB_PID_IN	= 0x69,
@@ -80,7 +82,7 @@ static void make_usb_token(unsigned char pid, unsigned int elevenbits, unsigned
80 82
 	out[2] |= usb_crc5(out[1], out[2]) << 3;
81 83
 }
82 84
 
83  
-static void usb_tx(unsigned char *buf, unsigned char len)
  85
+static void usb_tx(const unsigned char *buf, unsigned char len)
84 86
 {
85 87
 	unsigned char i;
86 88
 
@@ -138,6 +140,68 @@ static unsigned char usb_rx(unsigned char *buf, unsigned char maxlen)
138 140
 	}
139 141
 }
140 142
 
  143
+static const char in_reply[] PROGMEM = "IN reply:\n";
  144
+static const char datax_mismatch[] PROGMEM = "DATAx mismatch\n";
  145
+
  146
+static int usb_in(unsigned addr, unsigned char expected_data,
  147
+    unsigned char *buf, unsigned char maxlen)
  148
+{
  149
+	unsigned char in[3];
  150
+	unsigned char ack[1] = { USB_PID_ACK };
  151
+	unsigned char len;
  152
+
  153
+	/* send IN */
  154
+	make_usb_token(USB_PID_IN, addr, in);
  155
+	usb_tx(in, 3);
  156
+
  157
+	/* receive DATAx */
  158
+	len = usb_rx(buf, maxlen);
  159
+	if(!len) /* timeout or massive confusion */
  160
+		return 0;
  161
+	if(buf[0] == USB_PID_NAK)
  162
+		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;
  167
+	}
  168
+
  169
+	/* send ACK */
  170
+	usb_tx(ack, 1);
  171
+	if(buf[0] == expected_data)
  172
+		return len;
  173
+
  174
+	print_string(datax_mismatch);
  175
+	return 0;
  176
+}
  177
+
  178
+static const char out_reply[] PROGMEM = "OUT/DATA reply:\n";
  179
+
  180
+static char usb_out(unsigned addr, const unsigned char *buf, unsigned char len)
  181
+{
  182
+	unsigned char out[3];
  183
+	unsigned char ack[11];
  184
+	unsigned char got;
  185
+
  186
+	/* send OUT */
  187
+	make_usb_token(USB_PID_OUT, addr, out);
  188
+	usb_tx(out, 3);
  189
+
  190
+	/* send DATAx */
  191
+	usb_tx(buf, len);
  192
+
  193
+	/* 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;
  203
+}
  204
+
141 205
 struct setup_packet {
142 206
 	unsigned char bmRequestType;
143 207
 	unsigned char bRequest;
@@ -146,39 +210,39 @@ struct setup_packet {
146 210
 	unsigned char wLength[2];
147 211
 } __attribute__((packed));
148 212
 
149  
-static inline unsigned char get_data_token(char *toggle)
  213
+static inline unsigned char toggle(unsigned char old)
150 214
 {
151  
-	*toggle = !(*toggle);
152  
-	if(*toggle)
153  
-		return USB_PID_DATA0;
154  
-	else
155  
-		return USB_PID_DATA1;
  215
+	return old ^ USB_PID_DATA0 ^ USB_PID_DATA1;
156 216
 }
157 217
 
158 218
 static const char control_failed[] PROGMEM = "Control transfer failed:\n";
159  
-static const char termination[] PROGMEM = "(termination)\n";
160 219
 static const char setup_reply[] PROGMEM = "SETUP reply:\n";
161  
-static const char in_reply[] PROGMEM = "OUT/DATA reply:\n";
162  
-static const char out_reply[] PROGMEM = "IN reply:\n";
163 220
 
164  
-static char control_transfer(unsigned char addr, struct setup_packet *p, char out, unsigned char *payload, int maxlen)
  221
+static int control_transfer(unsigned char addr, struct setup_packet *p,
  222
+    char out, unsigned char *payload, int maxlen)
165 223
 {
  224
+	unsigned char setup[11];
166 225
 	unsigned char usb_buffer[11];
167  
-	char toggle;
  226
+	unsigned char expected_data = USB_PID_DATA1;
168 227
 	char rxlen;
169 228
 	char transferred;
170 229
 	char chunklen;
171 230
 
172  
-	toggle = 0;
173  
-
174  
-	/* send SETUP token */
175  
-	make_usb_token(USB_PID_SETUP, addr, usb_buffer);
176  
-	usb_tx(usb_buffer, 3);
177  
-	/* send setup packet */
178  
-	usb_buffer[0] = get_data_token(&toggle);
  231
+	/* generate SETUP token */
  232
+	make_usb_token(USB_PID_SETUP, addr, setup);
  233
+	/* generate setup packet */
  234
+	usb_buffer[0] = USB_PID_DATA0;
179 235
 	memcpy(&usb_buffer[1], p, 8);
180 236
 	usb_crc16(&usb_buffer[1], 8, &usb_buffer[9]);
  237
+#ifdef TRIGGER
  238
+wio8(SIE_SEL_TX, 3);
  239
+#endif
  240
+	/* send them back-to-back */
  241
+	usb_tx(setup, 3);
181 242
 	usb_tx(usb_buffer, 11);
  243
+#ifdef TRIGGER
  244
+wio8(SIE_SEL_TX, 2);
  245
+#endif
182 246
 	/* get ACK token from device */
183 247
 	rxlen = usb_rx(usb_buffer, 11);
184 248
 	if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
@@ -198,26 +262,17 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
198 262
 			if(chunklen > 8)
199 263
 				chunklen = 8;
200 264
 
201  
-			/* send OUT token */
202  
-			make_usb_token(USB_PID_OUT, addr, usb_buffer);
203  
-			usb_tx(usb_buffer, 3);
204  
-			/* send DATAx packet */
205  
-			usb_buffer[0] = get_data_token(&toggle);
  265
+			/* make DATAx packet */
  266
+			usb_buffer[0] = expected_data;
206 267
 			memcpy(&usb_buffer[1], payload, chunklen);
207 268
 			usb_crc16(&usb_buffer[1], chunklen, &usb_buffer[chunklen+1]);
208  
-			usb_tx(usb_buffer, chunklen+3);
209  
-			/* get ACK from device */
210  
-			rxlen = usb_rx(usb_buffer, 11);
211  
-			if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
212  
-				if((rxlen > 0) &&
213  
-				    (usb_buffer[0] == USB_PID_NAK))
214  
-					continue; /* NAK: retry */
215  
-				print_string(control_failed);
216  
-				print_string(out_reply);
217  
-				dump_hex(usb_buffer, rxlen);
  269
+			rxlen = usb_out(addr, usb_buffer, chunklen+3);
  270
+			if(!rxlen)
  271
+				continue;
  272
+			if(rxlen < 0)
218 273
 				return -1;
219  
-			}
220 274
 
  275
+			expected_data = toggle(expected_data);
221 276
 			transferred += chunklen;
222 277
 			payload += chunklen;
223 278
 			if(chunklen < 8)
@@ -225,30 +280,18 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
225 280
 		}
226 281
 	} else if(maxlen != 0) {
227 282
 		while(1) {
228  
-			/* send IN token */
229  
-			make_usb_token(USB_PID_IN, addr, usb_buffer);
230  
-			usb_tx(usb_buffer, 3);
231  
-			/* get DATAx packet */
232  
-			rxlen = usb_rx(usb_buffer, 11);
233  
-			if((rxlen < 3) || ((usb_buffer[0] != USB_PID_DATA0) &&
234  
-			    (usb_buffer[0] != USB_PID_DATA1))) {
235  
-				if((rxlen > 0) &&
236  
-				    (usb_buffer[0] == USB_PID_NAK))
237  
-					continue; /* NAK: retry */
238  
-				print_string(control_failed);
239  
-				print_string(in_reply);
240  
-				dump_hex(usb_buffer, rxlen);
241  
-				return -1;
242  
-			}
  283
+			rxlen = usb_in(addr, expected_data, usb_buffer, 11);
  284
+			if(!rxlen)
  285
+				continue;
  286
+			if(rxlen <0)
  287
+				return rxlen;
  288
+
  289
+			expected_data = toggle(expected_data);
243 290
 			chunklen = rxlen - 3; /* strip token and CRC */
244 291
 			if(chunklen > (maxlen - transferred))
245 292
 				chunklen = maxlen - transferred;
246 293
 			memcpy(payload, &usb_buffer[1], chunklen);
247 294
 
248  
-			/* send ACK token */
249  
-			usb_buffer[0] = USB_PID_ACK;
250  
-			usb_tx(usb_buffer, 1);
251  
-
252 295
 			transferred += chunklen;
253 296
 			payload += chunklen;
254 297
 			if(chunklen < 8)
@@ -258,77 +301,39 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
258 301
 
259 302
 	/* send IN/OUT token in the opposite direction to end transfer */
260 303
 retry:
261  
-	make_usb_token(out ? USB_PID_IN : USB_PID_OUT, addr, usb_buffer);
262  
-	usb_tx(usb_buffer, 3);
263 304
 	if(out) {
264  
-		/* get DATAx packet */
265  
-		rxlen = usb_rx(usb_buffer, 11);
266  
-		if((rxlen != 3) || ((usb_buffer[0] != USB_PID_DATA0) &&
267  
-		    (usb_buffer[0] != USB_PID_DATA1))) {
268  
-			if((rxlen > 0) && (usb_buffer[0] == USB_PID_NAK))
269  
-				goto retry; /* NAK: retry */
270  
-			print_string(control_failed);
271  
-			print_string(termination);
272  
-			print_string(in_reply);
273  
-			dump_hex(usb_buffer, rxlen);
  305
+		rxlen = usb_in(addr, USB_PID_DATA1, usb_buffer, 11);
  306
+		if(!rxlen)
  307
+			goto retry;
  308
+		if(rxlen < 0)
274 309
 			return -1;
275  
-		}
276  
-		/* send ACK token */
277  
-		usb_buffer[0] = USB_PID_ACK;
278  
-		usb_tx(usb_buffer, 1);
279 310
 	} else {
280  
-		/* send DATAx packet */
281  
-		usb_buffer[0] = get_data_token(&toggle);
  311
+		/* make DATA1 packet */
  312
+		usb_buffer[0] = USB_PID_DATA1;
282 313
 		usb_buffer[1] = usb_buffer[2] = 0x00; /* CRC is 0x0000 without data */
283  
-		usb_tx(usb_buffer, 3);
284  
-		/* get ACK token from device */
285  
-		rxlen = usb_rx(usb_buffer, 11);
286  
-		if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
287  
-			if((rxlen > 0) && (usb_buffer[0] == USB_PID_NAK))
288  
-				goto retry; /* NAK: retry */
289  
-			print_string(control_failed);
290  
-			print_string(termination);
291  
-			print_string(out_reply);
292  
-			dump_hex(usb_buffer, rxlen);
  314
+
  315
+		rxlen = usb_out(addr, usb_buffer, 3);
  316
+		if(!rxlen)
  317
+			goto retry;
  318
+		if(!rxlen < 0)
293 319
 			return -1;
294  
-		}
295 320
 	}
296 321
 
297 322
 	return transferred;
298 323
 }
299 324
 
300  
-static const char datax_mismatch[] PROGMEM = "DATAx mismatch\n";
301 325
 static void poll(struct ep_status *ep, char keyboard)
302 326
 {
303 327
 	unsigned char usb_buffer[11];
304  
-	unsigned char len;
  328
+	int len;
305 329
 	unsigned char m;
306 330
 	char i;
307 331
 
308  
-	/* IN */
309  
-	make_usb_token(USB_PID_IN, ADDR_EP(1, ep->ep), usb_buffer);
310  
-	usb_tx(usb_buffer, 3);
311  
-	/* DATAx */
312  
-	len = usb_rx(usb_buffer, 11);
313  
-	if(len < 6)
  332
+	len = usb_in(ADDR_EP(1, ep->ep), ep->expected_data, usb_buffer, 11);
  333
+	if(len <= 0)
314 334
 		return;
315  
-	if(usb_buffer[0] != ep->expected_data) {
316  
-		if((usb_buffer[0] == USB_PID_DATA0) ||
317  
-		    (usb_buffer[0] == USB_PID_DATA1)) {
318  
-			/* ACK */
319  
-			usb_buffer[0] = USB_PID_ACK;
320  
-			usb_tx(usb_buffer, 1);
321  
-			print_string(datax_mismatch);
322  
-		}
323  
-		return; /* drop */
324  
-	}
325  
-	/* ACK */
326  
-	usb_buffer[0] = USB_PID_ACK;
327  
-	usb_tx(usb_buffer, 1);
328  
-	if(ep->expected_data == USB_PID_DATA0)
329  
-		ep->expected_data = USB_PID_DATA1;
330  
-	else
331  
-		ep->expected_data = USB_PID_DATA0;
  335
+	ep->expected_data = toggle(ep->expected_data);
  336
+
332 337
 	/* send to host */
333 338
 	if(keyboard) {
334 339
 		if(len < 9)
@@ -619,8 +624,10 @@ static void sof()
619 624
 	unsigned char usb_buffer[3];
620 625
 	
621 626
 	mask = 0;
  627
+#ifndef TRIGGER
622 628
 	if(port_a.full_speed && (port_a.state > PORT_STATE_BUS_RESET))
623 629
 		mask |= 0x01;
  630
+#endif
624 631
 	if(port_b.full_speed && (port_b.state > PORT_STATE_BUS_RESET))
625 632
 		mask |= 0x02;
626 633
 	if(mask != 0) {
@@ -636,8 +643,10 @@ static void keepalive()
636 643
 	unsigned char mask;
637 644
 	
638 645
 	mask = 0;
  646
+#ifndef TRIGGER
639 647
 	if(!port_a.full_speed && (port_a.state == PORT_STATE_RESET_WAIT))
640 648
 		mask |= 0x01;
  649
+#endif
641 650
 	if(!port_b.full_speed && (port_b.state == PORT_STATE_RESET_WAIT))
642 651
 		mask |= 0x02;
643 652
 	if(mask != 0) {
@@ -681,9 +690,11 @@ int main()
681 690
 		for(i=0;i<128;i++)
682 691
 			asm("nop");
683 692
 		
  693
+#ifndef TRIGGER
684 694
 		wio8(SIE_SEL_RX, 0);
685 695
 		wio8(SIE_SEL_TX, 0x01);
686 696
 		port_service(&port_a, 'A');
  697
+#endif
687 698
 
688 699
 		wio8(SIE_SEL_RX, 1);
689 700
 		wio8(SIE_SEL_TX, 0x02);

No commit comments for this range

Something went wrong with that request. Please try again.