Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 6 commits
  • 1 file changed
  • 0 commit comments
  • 2 contributors
Commits on Nov 19, 2011
Werner Almesberger wpwrak 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 wpwrak 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 wpwrak 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 wpwrak 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 wpwrak 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 sbourdeauducq softusb: update copyright notice 3a7e212
Showing with 124 additions and 69 deletions.
  1. +124 −69 softusb-input/main.c
193 softusb-input/main.c
View
@@ -1,6 +1,7 @@
/*
* Milkymist SoC (USB firmware)
- * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
+ * Copyright (C) 2011 Werner Almesberger
*
* This program is free software: you can redistribute it and/or modify
* 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)
while(rio8(SIE_TX_BUSY));
}
-static const char transfer_start[] PROGMEM = "Transfer start: ";
+static inline void usb_ack(void)
+{
+ wio8(SIE_TX_DATA, 0x80); /* send SYNC */
+ while(rio8(SIE_TX_PENDING));
+ wio8(SIE_TX_DATA, USB_PID_ACK); /* send SYNC */
+ while(rio8(SIE_TX_PENDING));
+ wio8(SIE_TX_VALID, 0);
+ while(rio8(SIE_TX_BUSY));
+}
+
+static const char ack_error[] PROGMEM = "ACK: ";
static const char timeout_error[] PROGMEM = "RX timeout error\n";
static const char bitstuff_error[] PROGMEM = "RX bitstuff error\n";
-static unsigned char usb_rx(unsigned char *buf, unsigned char maxlen)
+#define WAIT_RX(first, end) \
+ do { \
+ unsigned timeout = 0x200; \
+ while(!rio8(SIE_RX_PENDING)) { \
+ if(!--timeout) \
+ goto timeout; \
+ if(rio8(SIE_RX_ERROR)) \
+ goto error; \
+ if(!first && !rio8(SIE_RX_ACTIVE)) \
+ goto end; \
+ } \
+ } while (0)
+
+
+static char usb_rx_ack(void)
{
- unsigned int timeout;
+ unsigned char pid;
unsigned char i;
- i = 0;
- timeout = 0x1ff;
- while(!rio8(SIE_RX_PENDING)) {
- if(timeout-- == 0) {
- print_string(transfer_start);
- print_string(timeout_error);
- return 0;
- }
- if(rio8(SIE_RX_ERROR)) {
- print_string(transfer_start);
- print_string(bitstuff_error);
- return 0;
- }
- }
- while(1) {
- timeout = 0x1ff;
- while(!rio8(SIE_RX_PENDING)) {
- if(rio8(SIE_RX_ERROR)) {
- print_string(bitstuff_error);
- return 0;
- }
- if(!rio8(SIE_RX_ACTIVE))
- return i;
- if(timeout-- == 0) {
- print_string(timeout_error);
- return 0;
- }
- }
- if(i == maxlen)
- return 0;
- buf[i] = rio8(SIE_RX_DATA);
- i++;
- }
+ /* SYNC */
+ WAIT_RX(1, nothing);
+
+ /* PID */
+ WAIT_RX(0, nothing);
+ pid = rio8(SIE_RX_DATA);
+
+ /* wait for idle, or simply time out and fall foward */
+ for(i = 200; i; i--)
+ if(!rio8(SIE_RX_ACTIVE))
+ break;
+
+ if(pid == USB_PID_ACK)
+ return 1;
+ if(pid == USB_PID_NAK)
+ return 0;
+
+ for(i = 200; i; i--)
+ WAIT_RX(0,out);
+out:
+ print_string(ack_error);
+ print_hex(pid);
+ print_char('\n');
+ return -1;
+
+timeout:
+ print_string(timeout_error);
+nothing:
+ return 0;
+error:
+ print_string(bitstuff_error);
+ return 0;
}
static const char in_reply[] PROGMEM = "IN reply:\n";
@@ -147,32 +171,76 @@ static int usb_in(unsigned addr, unsigned char expected_data,
unsigned char *buf, unsigned char maxlen)
{
unsigned char in[3];
- unsigned char ack[1] = { USB_PID_ACK };
- unsigned char len;
+ unsigned char len = 1;
+ unsigned char i;
/* send IN */
make_usb_token(USB_PID_IN, addr, in);
usb_tx(in, 3);
- /* receive DATAx */
- len = usb_rx(buf, maxlen);
- if(!len) /* timeout or massive confusion */
- return 0;
+ /* SYNC */
+ WAIT_RX(1, nothing);
+
+ /* PID */
+ WAIT_RX(0, nothing);
+ buf[0] = rio8(SIE_RX_DATA);
+
+ if(buf[0] == expected_data)
+ goto receive;
+ if(buf[0] == USB_PID_DATA0 || buf[0] == USB_PID_DATA1)
+ goto ignore;
if(buf[0] == USB_PID_NAK)
return 0;
- if(buf[0] != USB_PID_DATA0 && buf[0] != USB_PID_DATA1) {
- print_string(in_reply);
- dump_hex(buf, len);
- return -1;
+
+ /* unknown packet: try to receive for debug purposes, then dump */
+
+ while(len != maxlen) {
+ WAIT_RX(0, fail);
+ buf[len++] = rio8(SIE_RX_DATA);
}
+fail:
+ print_string(in_reply);
+ dump_hex(buf, len);
+ return -1;
- /* send ACK */
- usb_tx(ack, 1);
- if(buf[0] == expected_data)
- return len;
+ /* bad sequence bit: wait until packet has arrived, then ack */
+ignore:
+ for(i = 200; i; i--)
+ WAIT_RX(0, ignore_eop);
+ goto complain; /* this doesn't stop - just quit silently */
+ignore_eop:
+ usb_ack();
+complain:
print_string(datax_mismatch);
return 0;
+
+ /* receive the rest of the (good) packet */
+
+receive:
+ while(1) {
+ WAIT_RX(0, eop);
+ if(len == maxlen)
+ goto discard;
+ buf[len++] = rio8(SIE_RX_DATA);
+ }
+eop:
+ usb_ack();
+ return len;
+
+discard:
+ for(i = 200; i; i--)
+ WAIT_RX(0, nothing);
+nothing:
+ return 0;
+
+timeout:
+ print_string(timeout_error);
+ return 0;
+
+error:
+ print_string(bitstuff_error);
+ return 0;
}
static const char out_reply[] PROGMEM = "OUT/DATA reply:\n";
@@ -180,8 +248,6 @@ static const char out_reply[] PROGMEM = "OUT/DATA reply:\n";
static char usb_out(unsigned addr, const unsigned char *buf, unsigned char len)
{
unsigned char out[3];
- unsigned char ack[11];
- unsigned char got;
/* send OUT */
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)
usb_tx(buf, len);
/* receive ACK */
- got = usb_rx(ack, 11);
- if(got == 1 && ack[0] == USB_PID_ACK)
- return 1;
- if (!got || ack[0] == USB_PID_NAK) /* timeout or NAK */
- return 0;
-
- print_string(out_reply);
- dump_hex(ack, got);
- return -1;
+ return usb_rx_ack();
}
struct setup_packet {
@@ -215,8 +273,7 @@ static inline unsigned char toggle(unsigned char old)
return old ^ USB_PID_DATA0 ^ USB_PID_DATA1;
}
-static const char control_failed[] PROGMEM = "Control transfer failed:\n";
-static const char setup_reply[] PROGMEM = "SETUP reply:\n";
+static const char setup_ack[] PROGMEM = "SETUP not ACKed\n";
static int control_transfer(unsigned char addr, struct setup_packet *p,
char out, unsigned char *payload, int maxlen)
@@ -244,11 +301,8 @@ wio8(SIE_SEL_TX, 3);
wio8(SIE_SEL_TX, 2);
#endif
/* get ACK token from device */
- rxlen = usb_rx(usb_buffer, 11);
- if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
- print_string(control_failed);
- print_string(setup_reply);
- dump_hex(usb_buffer, rxlen);
+ if(usb_rx_ack() != 1) {
+ print_string(setup_ack);
return -1;
}
@@ -385,6 +439,7 @@ static void check_discon(struct port_status *p, char name)
if(discon) {
print_string(disconnect); print_char(name); print_char('\n');
p->state = PORT_STATE_DISCONNECTED;
+ p->keyboard.ep = p->mouse.ep = 0;
}
}

No commit comments for this range

Something went wrong with that request. Please try again.