Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
  • 11 commits
  • 1 file changed
  • 0 commit comments
  • 2 contributors
Commits on Nov 19, 2011
@wpwrak wpwrak softusb: 4 kB hack
f1c0fe7
@wpwrak wpwrak softusb: use OE# of port A for trigger
c8111e5
@wpwrak wpwrak softusb: send SETUP and DATA0 back-to-back
edf599e
@wpwrak wpwrak 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
@wpwrak wpwrak softusb: in SETUP, only use IN data with the right sequence bit
This also removes the functional regression of the previous commit.
f246bcf
@wpwrak wpwrak softusb: use toggle() also for bulk/interrupt
7c9748b
@wpwrak wpwrak softusb: swap in_reply and out_reply
9a26965
@wpwrak wpwrak 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
@wpwrak wpwrak 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
@wpwrak wpwrak suftusb: remove one now unused debug message
309d30d
@sbourdeauducq sbourdeauducq Revert 4KB hack
6e8c7b1
Showing with 119 additions and 108 deletions.
  1. +119 −108 softusb-input/main.c
View
227 softusb-input/main.c
@@ -26,6 +26,8 @@
#include "host.h"
#include "crc.h"
+//#define TRIGGER
+
enum {
USB_PID_OUT = 0xe1,
USB_PID_IN = 0x69,
@@ -80,7 +82,7 @@ static void make_usb_token(unsigned char pid, unsigned int elevenbits, unsigned
out[2] |= usb_crc5(out[1], out[2]) << 3;
}
-static void usb_tx(unsigned char *buf, unsigned char len)
+static void usb_tx(const unsigned char *buf, unsigned char len)
{
unsigned char i;
@@ -138,6 +140,68 @@ static unsigned char usb_rx(unsigned char *buf, unsigned char maxlen)
}
}
+static const char in_reply[] PROGMEM = "IN reply:\n";
+static const char datax_mismatch[] PROGMEM = "DATAx mismatch\n";
+
+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;
+
+ /* 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;
+ 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;
+ }
+
+ /* send ACK */
+ usb_tx(ack, 1);
+ if(buf[0] == expected_data)
+ return len;
+
+ print_string(datax_mismatch);
+ return 0;
+}
+
+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);
+ usb_tx(out, 3);
+
+ /* send DATAx */
+ 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;
+}
+
struct setup_packet {
unsigned char bmRequestType;
unsigned char bRequest;
@@ -146,39 +210,39 @@ struct setup_packet {
unsigned char wLength[2];
} __attribute__((packed));
-static inline unsigned char get_data_token(char *toggle)
+static inline unsigned char toggle(unsigned char old)
{
- *toggle = !(*toggle);
- if(*toggle)
- return USB_PID_DATA0;
- else
- return USB_PID_DATA1;
+ return old ^ USB_PID_DATA0 ^ USB_PID_DATA1;
}
static const char control_failed[] PROGMEM = "Control transfer failed:\n";
-static const char termination[] PROGMEM = "(termination)\n";
static const char setup_reply[] PROGMEM = "SETUP reply:\n";
-static const char in_reply[] PROGMEM = "OUT/DATA reply:\n";
-static const char out_reply[] PROGMEM = "IN reply:\n";
-static char control_transfer(unsigned char addr, struct setup_packet *p, char out, unsigned char *payload, int maxlen)
+static int control_transfer(unsigned char addr, struct setup_packet *p,
+ char out, unsigned char *payload, int maxlen)
{
+ unsigned char setup[11];
unsigned char usb_buffer[11];
- char toggle;
+ unsigned char expected_data = USB_PID_DATA1;
char rxlen;
char transferred;
char chunklen;
- toggle = 0;
-
- /* send SETUP token */
- make_usb_token(USB_PID_SETUP, addr, usb_buffer);
- usb_tx(usb_buffer, 3);
- /* send setup packet */
- usb_buffer[0] = get_data_token(&toggle);
+ /* generate SETUP token */
+ make_usb_token(USB_PID_SETUP, addr, setup);
+ /* generate setup packet */
+ usb_buffer[0] = USB_PID_DATA0;
memcpy(&usb_buffer[1], p, 8);
usb_crc16(&usb_buffer[1], 8, &usb_buffer[9]);
+#ifdef TRIGGER
+wio8(SIE_SEL_TX, 3);
+#endif
+ /* send them back-to-back */
+ usb_tx(setup, 3);
usb_tx(usb_buffer, 11);
+#ifdef TRIGGER
+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)) {
@@ -198,26 +262,17 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
if(chunklen > 8)
chunklen = 8;
- /* send OUT token */
- make_usb_token(USB_PID_OUT, addr, usb_buffer);
- usb_tx(usb_buffer, 3);
- /* send DATAx packet */
- usb_buffer[0] = get_data_token(&toggle);
+ /* make DATAx packet */
+ usb_buffer[0] = expected_data;
memcpy(&usb_buffer[1], payload, chunklen);
usb_crc16(&usb_buffer[1], chunklen, &usb_buffer[chunklen+1]);
- usb_tx(usb_buffer, chunklen+3);
- /* get ACK from device */
- rxlen = usb_rx(usb_buffer, 11);
- if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
- if((rxlen > 0) &&
- (usb_buffer[0] == USB_PID_NAK))
- continue; /* NAK: retry */
- print_string(control_failed);
- print_string(out_reply);
- dump_hex(usb_buffer, rxlen);
+ rxlen = usb_out(addr, usb_buffer, chunklen+3);
+ if(!rxlen)
+ continue;
+ if(rxlen < 0)
return -1;
- }
+ expected_data = toggle(expected_data);
transferred += chunklen;
payload += chunklen;
if(chunklen < 8)
@@ -225,30 +280,18 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
}
} else if(maxlen != 0) {
while(1) {
- /* send IN token */
- make_usb_token(USB_PID_IN, addr, usb_buffer);
- usb_tx(usb_buffer, 3);
- /* get DATAx packet */
- rxlen = usb_rx(usb_buffer, 11);
- if((rxlen < 3) || ((usb_buffer[0] != USB_PID_DATA0) &&
- (usb_buffer[0] != USB_PID_DATA1))) {
- if((rxlen > 0) &&
- (usb_buffer[0] == USB_PID_NAK))
- continue; /* NAK: retry */
- print_string(control_failed);
- print_string(in_reply);
- dump_hex(usb_buffer, rxlen);
- return -1;
- }
+ rxlen = usb_in(addr, expected_data, usb_buffer, 11);
+ if(!rxlen)
+ continue;
+ if(rxlen <0)
+ return rxlen;
+
+ expected_data = toggle(expected_data);
chunklen = rxlen - 3; /* strip token and CRC */
if(chunklen > (maxlen - transferred))
chunklen = maxlen - transferred;
memcpy(payload, &usb_buffer[1], chunklen);
- /* send ACK token */
- usb_buffer[0] = USB_PID_ACK;
- usb_tx(usb_buffer, 1);
-
transferred += chunklen;
payload += chunklen;
if(chunklen < 8)
@@ -258,77 +301,39 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
/* send IN/OUT token in the opposite direction to end transfer */
retry:
- make_usb_token(out ? USB_PID_IN : USB_PID_OUT, addr, usb_buffer);
- usb_tx(usb_buffer, 3);
if(out) {
- /* get DATAx packet */
- rxlen = usb_rx(usb_buffer, 11);
- if((rxlen != 3) || ((usb_buffer[0] != USB_PID_DATA0) &&
- (usb_buffer[0] != USB_PID_DATA1))) {
- if((rxlen > 0) && (usb_buffer[0] == USB_PID_NAK))
- goto retry; /* NAK: retry */
- print_string(control_failed);
- print_string(termination);
- print_string(in_reply);
- dump_hex(usb_buffer, rxlen);
+ rxlen = usb_in(addr, USB_PID_DATA1, usb_buffer, 11);
+ if(!rxlen)
+ goto retry;
+ if(rxlen < 0)
return -1;
- }
- /* send ACK token */
- usb_buffer[0] = USB_PID_ACK;
- usb_tx(usb_buffer, 1);
} else {
- /* send DATAx packet */
- usb_buffer[0] = get_data_token(&toggle);
+ /* make DATA1 packet */
+ usb_buffer[0] = USB_PID_DATA1;
usb_buffer[1] = usb_buffer[2] = 0x00; /* CRC is 0x0000 without data */
- usb_tx(usb_buffer, 3);
- /* get ACK token from device */
- rxlen = usb_rx(usb_buffer, 11);
- if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
- if((rxlen > 0) && (usb_buffer[0] == USB_PID_NAK))
- goto retry; /* NAK: retry */
- print_string(control_failed);
- print_string(termination);
- print_string(out_reply);
- dump_hex(usb_buffer, rxlen);
+
+ rxlen = usb_out(addr, usb_buffer, 3);
+ if(!rxlen)
+ goto retry;
+ if(!rxlen < 0)
return -1;
- }
}
return transferred;
}
-static const char datax_mismatch[] PROGMEM = "DATAx mismatch\n";
static void poll(struct ep_status *ep, char keyboard)
{
unsigned char usb_buffer[11];
- unsigned char len;
+ int len;
unsigned char m;
char i;
- /* IN */
- make_usb_token(USB_PID_IN, ADDR_EP(1, ep->ep), usb_buffer);
- usb_tx(usb_buffer, 3);
- /* DATAx */
- len = usb_rx(usb_buffer, 11);
- if(len < 6)
+ len = usb_in(ADDR_EP(1, ep->ep), ep->expected_data, usb_buffer, 11);
+ if(len <= 0)
return;
- if(usb_buffer[0] != ep->expected_data) {
- if((usb_buffer[0] == USB_PID_DATA0) ||
- (usb_buffer[0] == USB_PID_DATA1)) {
- /* ACK */
- usb_buffer[0] = USB_PID_ACK;
- usb_tx(usb_buffer, 1);
- print_string(datax_mismatch);
- }
- return; /* drop */
- }
- /* ACK */
- usb_buffer[0] = USB_PID_ACK;
- usb_tx(usb_buffer, 1);
- if(ep->expected_data == USB_PID_DATA0)
- ep->expected_data = USB_PID_DATA1;
- else
- ep->expected_data = USB_PID_DATA0;
+ ep->expected_data = toggle(ep->expected_data);
+
/* send to host */
if(keyboard) {
if(len < 9)
@@ -619,8 +624,10 @@ static void sof()
unsigned char usb_buffer[3];
mask = 0;
+#ifndef TRIGGER
if(port_a.full_speed && (port_a.state > PORT_STATE_BUS_RESET))
mask |= 0x01;
+#endif
if(port_b.full_speed && (port_b.state > PORT_STATE_BUS_RESET))
mask |= 0x02;
if(mask != 0) {
@@ -636,8 +643,10 @@ static void keepalive()
unsigned char mask;
mask = 0;
+#ifndef TRIGGER
if(!port_a.full_speed && (port_a.state == PORT_STATE_RESET_WAIT))
mask |= 0x01;
+#endif
if(!port_b.full_speed && (port_b.state == PORT_STATE_RESET_WAIT))
mask |= 0x02;
if(mask != 0) {
@@ -681,9 +690,11 @@ int main()
for(i=0;i<128;i++)
asm("nop");
+#ifndef TRIGGER
wio8(SIE_SEL_RX, 0);
wio8(SIE_SEL_TX, 0x01);
port_service(&port_a, 'A');
+#endif
wio8(SIE_SEL_RX, 1);
wio8(SIE_SEL_TX, 0x02);

No commit comments for this range

Something went wrong with that request. Please try again.