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: 02c81d5
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: 0b2d12a
Choose a head ref
  • 8 commits
  • 1 file changed
  • 1 contributor

Commits on Nov 13, 2011

  1. softusb-input: also accept 3 byte reports, e.g., from wheelless mice

    wpwrak authored and Sebastien Bourdeauducq committed Nov 13, 2011
    Copy the full SHA
    6b83fa4 View commit details
  2. softusb-input: use symbolic constants for packet ID values

    wpwrak authored and Sebastien Bourdeauducq committed Nov 13, 2011
    Copy the full SHA
    85b2d1c View commit details
  3. softusb: use macro to construct (address, EP) value

    0x81 meaning "address 1, endpoint 1" looks like the ubiquitous 0x81
    meaning "direction IN, endpoint 1". This patch makes things a little
    less misleading.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 13, 2011
    Copy the full SHA
    bd7d5e1 View commit details
  4. softusb: don't interrupt the host if we're ignoring the packet anyway

    wpwrak authored and Sebastien Bourdeauducq committed Nov 13, 2011
    Copy the full SHA
    40404f9 View commit details
  5. softusb: renamed "fs" to "full_speed"

    No need to be *that* tight-lipped ...
    wpwrak authored and Sebastien Bourdeauducq committed Nov 13, 2011
    Copy the full SHA
    169c6a6 View commit details
  6. softusb: separate EP-specific state from port-specific state

    This is made a little easier by the rest of the code ignoring the
    data toggle in SETUP requests. Otherwise, EP0 would need some state
    as well.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 13, 2011
    Copy the full SHA
    a2656a5 View commit details
  7. softusb: support composite USB devices

    For this, we parse the entire configuration descriptor and look at
    all interface descriptors. Furthermore, we set the endpoint number
    according to the endpoint descriptor(s) following the interface
    descriptor, instead of hard-coding it.
    
    Here is a brief description of how composite devices are structured:
    http://atmel.com/dyn/resources/prod_documents/doc7805.pdf
    
    Note that this doesn't help with combi-devices that present
    themselves as independent devices plus a hub.
    
    We still bail out at the first interface descriptor we don't
    understand, to avoid wandering into crazy things that may be lurking
    at tne end of the configuration descriptor. (I did this on a whim.
    Maybe we don't need that extra dose of paranoia.)
    wpwrak authored and Sebastien Bourdeauducq committed Nov 13, 2011
    Copy the full SHA
    a26dc51 View commit details
  8. softusb: added hack for Rii RF mini-keyboard

    Unlike the ACME rodent, the mouse pad of the Rii RF mini-keyboard
    sends reports with report ID and 16 bit resolution. This patch just
    identifies these reports by their sheer size and then rearranges the
    packet content before further processing.
    wpwrak authored and Sebastien Bourdeauducq committed Nov 13, 2011
    Copy the full SHA
    0b2d12a View commit details
Showing with 111 additions and 60 deletions.
  1. +111 −60 softusb-input/main.c
171 changes: 111 additions & 60 deletions softusb-input/main.c
Original file line number Diff line number Diff line change
@@ -26,6 +26,16 @@
#include "host.h"
#include "crc.h"

enum {
USB_PID_OUT = 0xe1,
USB_PID_IN = 0x69,
USB_PID_SETUP = 0x2d,
USB_PID_DATA0 = 0xc3,
USB_PID_DATA1 = 0x4b,
USB_PID_ACK = 0xd2,
USB_PID_NAK = 0x5a,
};

enum {
PORT_STATE_DISCONNECTED = 0,
PORT_STATE_BUS_RESET,
@@ -38,21 +48,27 @@ enum {
PORT_STATE_UNSUPPORTED
};

struct ep_status {
char ep;
unsigned char expected_data;
};

struct port_status {
char state;
char fs;
char keyboard;
char full_speed;
char retry_count;
unsigned int unreset_frame;

unsigned char expected_data;
struct ep_status keyboard;
struct ep_status mouse;
};

static struct port_status port_a;
static struct port_status port_b;

static unsigned int frame_nr;

#define ADDR_EP(addr, ep) ((addr) | (ep) << 7)

static void make_usb_token(unsigned char pid, unsigned int elevenbits, unsigned char *out)
{
out[0] = pid;
@@ -131,9 +147,9 @@ static inline unsigned char get_data_token(char *toggle)
{
*toggle = !(*toggle);
if(*toggle)
return 0xc3;
return USB_PID_DATA0;
else
return 0x4b;
return USB_PID_DATA1;
}

static const char control_failed[] PROGMEM = "Control transfer failed:\n";
@@ -153,7 +169,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
toggle = 0;

/* send SETUP token */
make_usb_token(0x2d, addr, usb_buffer);
make_usb_token(USB_PID_SETUP, addr, usb_buffer);
usb_tx(usb_buffer, 3);
/* send setup packet */
usb_buffer[0] = get_data_token(&toggle);
@@ -162,7 +178,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
usb_tx(usb_buffer, 11);
/* get ACK token from device */
rxlen = usb_rx(usb_buffer, 11);
if((rxlen != 1) || (usb_buffer[0] != 0xd2)) {
if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
print_string(control_failed);
print_string(setup_reply);
dump_hex(usb_buffer, rxlen);
@@ -180,7 +196,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
chunklen = 8;

/* send OUT token */
make_usb_token(0xe1, addr, usb_buffer);
make_usb_token(USB_PID_OUT, addr, usb_buffer);
usb_tx(usb_buffer, 3);
/* send DATAx packet */
usb_buffer[0] = get_data_token(&toggle);
@@ -189,8 +205,9 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
usb_tx(usb_buffer, chunklen+3);
/* get ACK from device */
rxlen = usb_rx(usb_buffer, 11);
if((rxlen != 1) || (usb_buffer[0] != 0xd2)) {
if((rxlen > 0) && (usb_buffer[0] == 0x5a))
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);
@@ -206,12 +223,14 @@ 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(0x69, addr, usb_buffer);
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] != 0xc3) && (usb_buffer[0] != 0x4b))) {
if((rxlen > 0) && (usb_buffer[0] == 0x5a))
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);
@@ -224,7 +243,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
memcpy(payload, &usb_buffer[1], chunklen);

/* send ACK token */
usb_buffer[0] = 0xd2;
usb_buffer[0] = USB_PID_ACK;
usb_tx(usb_buffer, 1);

transferred += chunklen;
@@ -236,13 +255,14 @@ 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 ? 0x69 : 0xe1, addr, usb_buffer);
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] != 0xc3) && (usb_buffer[0] != 0x4b))) {
if((rxlen > 0) && (usb_buffer[0] == 0x5a))
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);
@@ -251,7 +271,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
return -1;
}
/* send ACK token */
usb_buffer[0] = 0xd2;
usb_buffer[0] = USB_PID_ACK;
usb_tx(usb_buffer, 1);
} else {
/* send DATAx packet */
@@ -260,8 +280,8 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
usb_tx(usb_buffer, 3);
/* get ACK token from device */
rxlen = usb_rx(usb_buffer, 11);
if((rxlen != 1) || (usb_buffer[0] != 0xd2)) {
if((rxlen > 0) && (usb_buffer[0] == 0x5a))
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);
@@ -275,51 +295,68 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
}

static const char datax_mismatch[] PROGMEM = "DATAx mismatch\n";
static void poll(struct port_status *p)
static void poll(struct ep_status *ep, char keyboard)
{
unsigned char usb_buffer[11];
unsigned char len;
unsigned char m;
char i;

/* IN */
make_usb_token(0x69, 0x081, usb_buffer);
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 < 7)
if(len < 6)
return;
if(usb_buffer[0] != p->expected_data) {
if((usb_buffer[0] == 0xc3) || (usb_buffer[0] == 0x4b)) {
if(usb_buffer[0] != ep->expected_data) {
if((usb_buffer[0] == USB_PID_DATA0) ||
(usb_buffer[0] == USB_PID_DATA1)) {
/* ACK */
usb_buffer[0] = 0xd2;
usb_buffer[0] = USB_PID_ACK;
usb_tx(usb_buffer, 1);
print_string(datax_mismatch);
}
return; /* drop */
}
/* ACK */
usb_buffer[0] = 0xd2;
usb_buffer[0] = USB_PID_ACK;
usb_tx(usb_buffer, 1);
if(p->expected_data == 0xc3)
p->expected_data = 0x4b;
if(ep->expected_data == USB_PID_DATA0)
ep->expected_data = USB_PID_DATA1;
else
p->expected_data = 0xc3;
ep->expected_data = USB_PID_DATA0;
/* send to host */
if(p->keyboard) {
if(len >= 9) {
m = COMLOC_KEVT_PRODUCE;
for(i=0;i<8;i++)
COMLOC_KEVT(8*m+i) = usb_buffer[i+1];
COMLOC_KEVT_PRODUCE = (m + 1) & 0x07;
}
if(keyboard) {
if(len < 9)
return;
m = COMLOC_KEVT_PRODUCE;
for(i=0;i<8;i++)
COMLOC_KEVT(8*m+i) = usb_buffer[i+1];
COMLOC_KEVT_PRODUCE = (m + 1) & 0x07;
} else {
if(len >= 7) {
m = COMLOC_MEVT_PRODUCE;
for(i=0;i<4;i++)
COMLOC_MEVT(4*m+i) = usb_buffer[i+1];
COMLOC_MEVT_PRODUCE = (m + 1) & 0x0f;
if(len < 6)
return;
/*
* HACK: The Rii RF mini-keyboard sends ten byte messages with
* a report ID and 16 bit coordinates. We're too lazy to parse
* report descriptors, so we just hard-code that report layout.
*/
if(len == 10) {
usb_buffer[1] = usb_buffer[2]; /* buttons */
usb_buffer[2] = usb_buffer[3]; /* X LSB */
usb_buffer[3] = usb_buffer[5]; /* Y LSB */
}
if(len > 7)
len = 7;
m = COMLOC_MEVT_PRODUCE;
for(i=0;i<len-3;i++)
COMLOC_MEVT(4*m+i) = usb_buffer[i+1];
while(i < 4) {
COMLOC_MEVT(4*m+i) = 0;
i++;
}
COMLOC_MEVT_PRODUCE = (m + 1) & 0x0f;
}
/* trigger host IRQ */
wio8(HOST_IRQ, 1);
@@ -343,8 +380,10 @@ static void check_discon(struct port_status *p, char name)
}
}

static char validate_configuration_descriptor(unsigned char *descriptor, char len, char *keyboard)
static char validate_configuration_descriptor(unsigned char *descriptor,
char len, struct port_status *p)
{
struct ep_status *ep = NULL;
char offset;

offset = 0;
@@ -353,24 +392,30 @@ static char validate_configuration_descriptor(unsigned char *descriptor, char le
/* got an interface descriptor */
/* check for bInterfaceClass=3 and bInterfaceSubClass=1 (HID) */
if((descriptor[offset+5] != 0x03) || (descriptor[offset+6] != 0x01))
return 0;
break;
/* check bInterfaceProtocol */
switch(descriptor[offset+7]) {
case 0x01:
*keyboard = 1;
return 1;
ep = &p->keyboard;
break;
case 0x02:
*keyboard = 0;
return 1;
ep = &p->mouse;
break;
default:
/* unknown protocol, fail */
return 0;
ep = NULL;
break;
}
} else if(descriptor[offset+1] == 0x05 &&
(descriptor[offset+2] & 0x80) && ep) {
ep->ep = descriptor[offset+2] & 0x7f;
ep->expected_data = USB_PID_DATA0;
/* start with DATA0 */
ep = NULL;
}
offset += descriptor[offset+0];
}
/* no interface descriptor found, fail */
return 0;
return p->keyboard.ep || p->mouse.ep;
}

static const char retry_exceed[] PROGMEM = "Retry count exceeded, disabling device.\n";
@@ -406,12 +451,12 @@ static void port_service(struct port_status *p, char name)
linestat = rio8(SIE_LINE_STATUS_B);
if(linestat == 0x01) {
print_string(connect_fs); print_char(name); print_char('\n');
p->fs = 1;
p->full_speed = 1;
p->state = PORT_STATE_UNSUPPORTED;
}
if(linestat == 0x02) {
print_string(connect_ls); print_char(name); print_char('\n');
p->fs = 0;
p->full_speed = 0;
if(name == 'A')
wio8(SIE_TX_BUSRESET, rio8(SIE_TX_BUSRESET) | 0x01);
else
@@ -506,15 +551,19 @@ static void port_service(struct port_status *p, char name)
len = control_transfer(0x01, &packet, 0, configuration_descriptor, 127);
if(len >= 0) {
p->retry_count = 0;
if(!validate_configuration_descriptor(configuration_descriptor, len, &p->keyboard)) {
if(!validate_configuration_descriptor(
configuration_descriptor, len, p)) {
print_string(found); print_string(unsupported_device);
p->state = PORT_STATE_UNSUPPORTED;
} else {
print_string(found);
if(p->keyboard)
if(p->keyboard.ep) {
print_string(found);
print_string(keyboard);
else
}
if(p->mouse.ep) {
print_string(found);
print_string(mouse);
}
p->state = PORT_STATE_SET_CONFIGURATION;
}
}
@@ -535,14 +584,16 @@ static void port_service(struct port_status *p, char name)

if(control_transfer(0x01, &packet, 1, NULL, 0) == 0) {
p->retry_count = 0;
p->expected_data = 0xc3; /* start with DATA0 */
p->state = PORT_STATE_RUNNING;
}
check_retry(p);
break;
}
case PORT_STATE_RUNNING:
poll(p);
if(p->keyboard.ep)
poll(&p->keyboard, 1);
if(p->mouse.ep)
poll(&p->mouse, 0);
break;
case PORT_STATE_UNSUPPORTED:
break;