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: f6c7474
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: 6e8c7b1
Choose a head ref
  • 11 commits
  • 1 file changed
  • 2 contributors

Commits on Nov 19, 2011

  1. softusb: 4 kB hack

    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011

    Unverified

    The signing certificate or its chain could not be verified.
    Copy the full SHA
    f1c0fe7 View commit details
  2. softusb: use OE# of port A for trigger

    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
    c8111e5 View commit details
  3. softusb: send SETUP and DATA0 back-to-back

    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
    edf599e View commit details
  4. 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.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    4e255d0 View commit details
  5. softusb: in SETUP, only use IN data with the right sequence bit

    This also removes the functional regression of the previous commit.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    f246bcf View commit details
  6. softusb: use toggle() also for bulk/interrupt

    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    7c9748b View commit details
  7. softusb: swap in_reply and out_reply

    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    9a26965 View commit details
  8. 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.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    d5ae456 View commit details
  9. 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.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    0ff5764 View commit details
  10. suftusb: remove one now unused debug message

    wpwrak authored and Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    309d30d View commit details
  11. Revert 4KB hack

    Sebastien Bourdeauducq committed Nov 19, 2011
    Copy the full SHA
    6e8c7b1 View commit details
Showing with 119 additions and 108 deletions.
  1. +119 −108 softusb-input/main.c
227 changes: 119 additions & 108 deletions softusb-input/main.c
Original file line number Diff line number Diff line change
@@ -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,57 +262,36 @@ 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)
break;
}
} 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);