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.
  • 8 commits
  • 1 file changed
  • 0 commit comments
  • 1 contributor
Commits on Nov 13, 2011
@wpwrak wpwrak softusb-input: also accept 3 byte reports, e.g., from wheelless mice 6b83fa4
@wpwrak wpwrak softusb-input: use symbolic constants for packet ID values 85b2d1c
@wpwrak wpwrak 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.
bd7d5e1
@wpwrak wpwrak softusb: don't interrupt the host if we're ignoring the packet anyway 40404f9
@wpwrak wpwrak softusb: renamed "fs" to "full_speed"
No need to be *that* tight-lipped ...
169c6a6
@wpwrak wpwrak 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.
a2656a5
@wpwrak wpwrak 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.)
a26dc51
@wpwrak wpwrak 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.
0b2d12a
Showing with 111 additions and 60 deletions.
  1. +111 −60 softusb-input/main.c
View
171 softusb-input/main.c
@@ -27,6 +27,16 @@
#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,
PORT_STATE_WARMUP,
@@ -38,14 +48,18 @@ 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;
@@ -53,6 +67,8 @@ 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,7 +295,7 @@ 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;
@@ -283,43 +303,60 @@ static void poll(struct port_status *p)
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;

No commit comments for this range

Something went wrong with that request. Please try again.