Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 9 commits
  • 2 files changed
  • 0 commit comments
  • 1 contributor
Commits on Nov 30, 2011
Werner Almesberger wpwrak softusb: use symbolic names for various USB constants 4923a9d
Werner Almesberger wpwrak softusb: move protocol identification (interface descriptor) to separ…
…ate function
4d9920b
Werner Almesberger wpwrak softusb: remove trailing whitespace
Some lines had trailing tabs. Those can sometimes trip patch.
dae5ff5
Werner Almesberger wpwrak softusb: minimize time between SETUP/OUT and DATAx
By not waiting until the transmitter is idle, we can reduce the
time between the end of the SE0 indicating EOP of SETUP or OUT
and the first transition of the following DATAx to a mere two
bit times (as oppose to ~6 bit times before).

While I haven't been able to find anything in the USB standard
that would require such tight timing, AVR USB chips (i.e., the
ATmega32U2 of atusb and the AT90USB162 of the Faderfox LV3)
flat out ignore any transfers with longer delays.
6ca46c2
Werner Almesberger wpwrak softusb: clean up device reporting
Moved reporting of the device(s) detected out of port_service, making
it a bit less cluttered and providing a more comfortable basis for
future additions.
b553999
Werner Almesberger wpwrak softusb: added detection of MIDI devices (WIP) 0294551
Werner Almesberger wpwrak softusb: move protocol-specfic data processing to separate functions
This will prevent "poll" from getting too cluttered when MIDI is added.
98be89d
Werner Almesberger wpwrak softusb: protect macro arguments in comloc.h
This change is purely cosmetic.
b452f54
Werner Almesberger wpwrak softusb: poll MIDI EPs and pass control changes to the LM32
Adding other events should be easy, but one step at a time.
9e05e46
Showing with 175 additions and 99 deletions.
  1. +5 −3 softusb-input/comloc.h
  2. +170 −96 softusb-input/main.c
8 softusb-input/comloc.h
View
@@ -22,10 +22,12 @@
#define COMLOCV(x) (*(volatile unsigned char *)(x))
#define COMLOC_DEBUG_PRODUCE COMLOC(0x1000)
-#define COMLOC_DEBUG(offset) COMLOC(0x1001+offset)
+#define COMLOC_DEBUG(offset) COMLOC(0x1001+(offset))
#define COMLOC_MEVT_PRODUCE COMLOC(0x1101)
-#define COMLOC_MEVT(offset) COMLOC(0x1102+offset)
+#define COMLOC_MEVT(offset) COMLOC(0x1102+(offset))
#define COMLOC_KEVT_PRODUCE COMLOC(0x1142)
-#define COMLOC_KEVT(offset) COMLOC(0x1143+offset)
+#define COMLOC_KEVT(offset) COMLOC(0x1143+(offset))
+#define COMLOC_MIDI_PRODUCE COMLOC(0x1183)
+#define COMLOC_MIDI(offset) COMLOC(0x1184+(offset))
#endif /* __COMLOC_H */
266 softusb-input/main.c
View
@@ -53,6 +53,31 @@ enum {
};
enum {
+ USB_DT_DEVICE = 1,
+ USB_DT_CONFIG = 2,
+ USB_DT_INTERFACE = 4,
+ USB_DT_ENDPOINT = 5,
+};
+
+enum {
+ USB_CLASS_AUDIO = 1,
+ USB_CLASS_HID = 3,
+};
+
+enum {
+ USB_SUBCLASS_BOOT = 1, /* HID */
+};
+
+enum {
+ USB_SUBCLASS_MIDISTREAMING = 3, /* AUDIO */
+};
+
+enum {
+ USB_PROTO_KEYBOARD = 1, /* HID */
+ USB_PROTO_MOUSE = 2,
+};
+
+enum {
PORT_STATE_DISCONNECTED = 0,
PORT_STATE_BUS_RESET,
PORT_STATE_RESET_WAIT,
@@ -80,6 +105,7 @@ struct port_status {
unsigned char ep0_size;
struct ep_status keyboard;
struct ep_status mouse;
+ struct ep_status midi;
};
static struct port_status port_a;
@@ -99,7 +125,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(const unsigned char *buf, unsigned char len)
+static void usb_tx_nowait(const unsigned char *buf, unsigned char len)
{
unsigned char i;
@@ -110,9 +136,15 @@ static void usb_tx(const unsigned char *buf, unsigned char len)
}
while(rio8(SIE_TX_PENDING));
wio8(SIE_TX_VALID, 0);
+}
+
+static void usb_tx(const unsigned char *buf, unsigned char len)
+{
+ usb_tx_nowait(buf, len);
while(rio8(SIE_TX_BUSY));
}
+
static inline void usb_ack(void)
{
wio8(SIE_TX_DATA, 0x80); /* send SYNC */
@@ -282,7 +314,7 @@ static char usb_out(unsigned addr, const unsigned char *buf, unsigned char len)
/* send OUT */
make_usb_token(USB_PID_OUT, addr, out);
- usb_tx(out, 3);
+ usb_tx_nowait(out, 3);
/* send DATAx */
usb_tx(buf, len);
@@ -326,7 +358,7 @@ static int control_transfer(unsigned char addr, struct setup_packet *p,
TRIGGER_ON();
/* send them back-to-back */
- usb_tx(setup, 3);
+ usb_tx_nowait(setup, 3);
usb_tx(usb_buffer, 11);
TRIGGER_OFF();
@@ -407,52 +439,79 @@ static int control_transfer(unsigned char addr, struct setup_packet *p,
return transferred;
}
-static void poll(struct ep_status *ep, char keyboard)
+static char process_keyboard(unsigned char *buf, unsigned char len)
+{
+ unsigned char m, i;
+
+ if(len < 6)
+ return 0;
+ m = COMLOC_KEVT_PRODUCE;
+ for(i = 0; i < 8; i++)
+ COMLOC_KEVT(8*m+i) = buf[i];
+ COMLOC_KEVT_PRODUCE = (m + 1) & 0x07;
+ return 1;
+}
+
+static char process_mouse(unsigned char *buf, unsigned char len)
+{
+ unsigned char m, i;
+
+ if(len < 3)
+ return 0;
+ /*
+ * 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 == 7) {
+ buf[0] = buf[1]; /* buttons */
+ buf[1] = buf[2]; /* X LSB */
+ buf[2] = buf[4]; /* Y LSB */
+ }
+ if(len > 4)
+ len = 4;
+ m = COMLOC_MEVT_PRODUCE;
+ for(i = 0; i < len; i++)
+ COMLOC_MEVT(4*m+i) = buf[i];
+ while(i < 4) {
+ COMLOC_MEVT(4*m+i) = 0;
+ i++;
+ }
+ COMLOC_MEVT_PRODUCE = (m + 1) & 0x0f;
+ return 1;
+}
+
+static char process_midi(unsigned char *buf, unsigned char len)
+{
+ unsigned char end = len & ~3;
+ unsigned char i, m, j;
+
+ for(i = 0; i != end; i += 4) {
+ if((buf[i] & 0xf) != 0xb) /* not a control change */
+ continue;
+ m = COMLOC_MIDI_PRODUCE;
+ for(j = 0; j != 4; j++)
+ COMLOC_MIDI(4*m+j) = buf[i+j];
+ COMLOC_MIDI_PRODUCE = (m + 1) & 15;
+ }
+ return 0;
+}
+
+static void poll(struct ep_status *ep,
+ char (*process)(unsigned char *buf, unsigned char len))
{
- unsigned char usb_buffer[11];
+ unsigned char usb_buffer[1+64+2]; /* DATAx + payload + CRC */
int len;
- unsigned char m;
- char i;
len = usb_in(ADDR_EP(ADDR, ep->ep), ep->expected_data, usb_buffer, 11);
if(len <= 0)
return;
ep->expected_data = toggle(ep->expected_data);
- /* send to host */
- 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 < 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);
+ if(len <= 3)
+ return;
+ if(process(usb_buffer+1, len-3)) /* send to host */
+ wio8(HOST_IRQ, 1); /* trigger host IRQ */
}
static const char connect_fs[] PROGMEM = "Full speed device on port ";
@@ -470,11 +529,37 @@ 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;
+ p->keyboard.ep = p->mouse.ep = p->midi.ep = 0;
}
}
-static char validate_configuration_descriptor(unsigned char *descriptor,
+static struct ep_status *identify_protocol(const unsigned char *itf,
+ struct port_status *p)
+{
+ /* check for bInterfaceClass=3 and bInterfaceSubClass=1 (HID) */
+ if (itf[5] == USB_CLASS_HID && itf[6] == USB_SUBCLASS_BOOT)
+ switch(itf[7]) { /* check bInterfaceProtocol */
+ case USB_PROTO_KEYBOARD:
+ return &p->keyboard;
+ case USB_PROTO_MOUSE:
+ return &p->mouse;
+ default:
+ /* unknown protocol, fail */
+ return NULL;
+ }
+ if (itf[5] == USB_CLASS_AUDIO && itf[6] == USB_SUBCLASS_MIDISTREAMING)
+ return &p->midi;
+
+ return NULL;
+}
+
+static const char found[] PROGMEM = "Found ";
+static const char unsupported_device[] PROGMEM = "unsupported device\n";
+static const char mouse[] PROGMEM = "mouse\n";
+static const char keyboard[] PROGMEM = "keyboard\n";
+static const char midi[] PROGMEM = "MIDI\n";
+
+static char validate_configuration_descriptor(const unsigned char *descriptor,
char len, struct port_status *p)
{
struct ep_status *ep = NULL;
@@ -482,25 +567,9 @@ static char validate_configuration_descriptor(unsigned char *descriptor,
offset = 0;
while(offset < len) {
- if(descriptor[offset+1] == 0x04) {
- /* got an interface descriptor */
- /* check for bInterfaceClass=3 and bInterfaceSubClass=1 (HID) */
- if((descriptor[offset+5] != 0x03) || (descriptor[offset+6] != 0x01))
- break;
- /* check bInterfaceProtocol */
- switch(descriptor[offset+7]) {
- case 0x01:
- ep = &p->keyboard;
- break;
- case 0x02:
- ep = &p->mouse;
- break;
- default:
- /* unknown protocol, fail */
- ep = NULL;
- break;
- }
- } else if(descriptor[offset+1] == 0x05 &&
+ if(descriptor[offset+1] == USB_DT_INTERFACE) {
+ ep = identify_protocol(descriptor+offset, p);
+ } else if(descriptor[offset+1] == USB_DT_ENDPOINT &&
(descriptor[offset+2] & 0x80) && ep) {
ep->ep = descriptor[offset+2] & 0x7f;
ep->expected_data = USB_PID_DATA0;
@@ -509,7 +578,26 @@ static char validate_configuration_descriptor(unsigned char *descriptor,
}
offset += descriptor[offset+0];
}
- return p->keyboard.ep || p->mouse.ep;
+ if(p->keyboard.ep) {
+ print_string(found);
+ print_string(keyboard);
+ }
+ if(p->mouse.ep) {
+ print_string(found);
+ print_string(mouse);
+ }
+ if(p->midi.ep) {
+ print_string(found);
+ print_string(midi);
+ }
+ return p->keyboard.ep || p->mouse.ep || p->midi.ep;
+}
+
+static void unsupported(struct port_status *p)
+{
+ print_string(found);
+ print_string(unsupported_device);
+ p->state = PORT_STATE_UNSUPPORTED;
}
static const char retry_exceed[] PROGMEM = "Retry count exceeded, disabling device.\n";
@@ -524,20 +612,15 @@ static void check_retry(struct port_status *p)
static const char vid[] PROGMEM = "VID: ";
static const char pid[] PROGMEM = ", PID: ";
-static const char found[] PROGMEM = "Found ";
-static const char unsupported_device[] PROGMEM = "unsupported device\n";
-static const char mouse[] PROGMEM = "mouse\n";
-static const char keyboard[] PROGMEM = "keyboard\n";
-
static int get_device_descriptor(unsigned char *buf, int size,
unsigned char ep0_size)
{
struct setup_packet packet;
-
+
packet.bmRequestType = 0x80;
packet.bRequest = 0x06;
packet.wValue[0] = 0x00;
- packet.wValue[1] = 0x01;
+ packet.wValue[1] = USB_DT_DEVICE;
packet.wIndex[0] = 0x00;
packet.wIndex[1] = 0x00;
packet.wLength[0] = size;
@@ -646,7 +729,7 @@ static void port_service(struct port_status *p, char name)
break;
case PORT_STATE_GET_DEVICE_DESCRIPTOR: {
unsigned char device_descriptor[18];
-
+
if(get_device_descriptor(device_descriptor, 18,
p->ep0_size) >= 0) {
p->retry_count = 0;
@@ -660,10 +743,9 @@ static void port_service(struct port_status *p, char name)
/* check for bDeviceClass=0 and bDeviceSubClass=0.
* HID devices have those.
*/
- if((device_descriptor[4] != 0) || (device_descriptor[5] != 0)) {
- print_string(found); print_string(unsupported_device);
- p->state = PORT_STATE_UNSUPPORTED;
- } else
+ if((device_descriptor[4] != 0) || (device_descriptor[5] != 0))
+ unsupported(p);
+ else
p->state = PORT_STATE_GET_CONFIGURATION_DESCRIPTOR;
}
check_retry(p);
@@ -677,7 +759,7 @@ static void port_service(struct port_status *p, char name)
packet.bmRequestType = 0x80;
packet.bRequest = 0x06;
packet.wValue[0] = 0x00;
- packet.wValue[1] = 0x02;
+ packet.wValue[1] = USB_DT_CONFIG;
packet.wIndex[0] = 0x00;
packet.wIndex[1] = 0x00;
packet.wLength[0] = 127;
@@ -688,20 +770,10 @@ static void port_service(struct port_status *p, char name)
if(len >= 0) {
p->retry_count = 0;
if(!validate_configuration_descriptor(
- configuration_descriptor, len, p)) {
- print_string(found); print_string(unsupported_device);
- p->state = PORT_STATE_UNSUPPORTED;
- } else {
- if(p->keyboard.ep) {
- print_string(found);
- print_string(keyboard);
- }
- if(p->mouse.ep) {
- print_string(found);
- print_string(mouse);
- }
+ configuration_descriptor, len, p))
+ unsupported(p);
+ else
p->state = PORT_STATE_SET_CONFIGURATION;
- }
}
check_retry(p);
break;
@@ -728,9 +800,11 @@ static void port_service(struct port_status *p, char name)
}
case PORT_STATE_RUNNING:
if(p->keyboard.ep)
- poll(&p->keyboard, 1);
+ poll(&p->keyboard, process_keyboard);
if(p->mouse.ep)
- poll(&p->mouse, 0);
+ poll(&p->mouse, process_mouse);
+ if(p->midi.ep)
+ poll(&p->midi, process_midi);
break;
case PORT_STATE_UNSUPPORTED:
break;
@@ -744,7 +818,7 @@ static void sof()
{
unsigned char mask;
unsigned char usb_buffer[3];
-
+
mask = 0;
#ifndef TRIGGER
if(port_a.full_speed && (port_a.state > PORT_STATE_BUS_RESET))
@@ -763,7 +837,7 @@ static void sof()
static void keepalive()
{
unsigned char mask;
-
+
mask = 0;
#ifndef TRIGGER
if(!port_a.full_speed && (port_a.state == PORT_STATE_RESET_WAIT))
@@ -782,7 +856,7 @@ static void keepalive()
static void set_rx_speed()
{
unsigned char mask;
-
+
mask = 0;
if(!port_a.full_speed) mask |= 0x01;
if(!port_b.full_speed) mask |= 0x02;
@@ -811,7 +885,7 @@ int main()
*/
for(i=0;i<128;i++)
asm("nop");
-
+
#ifndef TRIGGER
wio8(SIE_SEL_RX, 0);
wio8(SIE_SEL_TX, 0x01);
@@ -821,7 +895,7 @@ int main()
wio8(SIE_SEL_RX, 1);
wio8(SIE_SEL_TX, 0x02);
port_service(&port_b, 'B');
-
+
/* set RX speed for new detected devices */
set_rx_speed();

No commit comments for this range

Something went wrong with that request. Please try again.