Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/milkymist
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6e8c7b1
Choose a base ref
...
head repository: m-labs/milkymist
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3a7e212
Choose a head ref
  • 6 commits
  • 1 file changed
  • 2 contributors

Commits on Nov 19, 2011

  1. 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
    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011

    Unverified

    The signing certificate or its chain could not be verified.
    Copy the full SHA
    016e556 View commit details
  2. 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.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    f3023cf View commit details
  3. 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.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    f995f37 View commit details
  4. 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.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    8fcbc21 View commit details
  5. 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.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    5695188 View commit details
  6. softusb: update copyright notice

    Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    3a7e212 View commit details
Showing with 124 additions and 69 deletions.
  1. +124 −69 softusb-input/main.c
193 changes: 124 additions & 69 deletions softusb-input/main.c
Original file line number Diff line number Diff line change
@@ -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,41 +171,83 @@ 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";

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;
}
}