Index: firmware/usb/LICENSE
===================================================================
--- firmware/usb/LICENSE	(nonexistent)
+++ firmware/usb/LICENSE	(revision 269)
@@ -0,0 +1 @@
+This part is GPL - in fact this whole firmware should be - just need to check a few things...
Index: firmware/usb/debug.h
===================================================================
--- firmware/usb/debug.h	(nonexistent)
+++ firmware/usb/debug.h	(revision 269)
@@ -0,0 +1,3 @@
+#define hid_debugf(IN, ...) {};
+#define hidp_debugf(IN, ...) {};
+#define iprintf(IN, ...) {};
Index: firmware/usb/events.h
===================================================================
--- firmware/usb/events.h	(nonexistent)
+++ firmware/usb/events.h	(revision 269)
@@ -0,0 +1,33 @@
+void event_keyboard(uint8_t i, uint8_t buf[])
+{
+	int j;
+	printf("Event keyboard:%d\n", i);
+        for (j=0;j!=6;++j)
+	{
+		printf("Event keyboard:%d = %x\n", j, buf[j]);
+	}
+}
+void event_mouse(uint8_t a, uint8_t b, uint8_t c)
+{
+	printf("Event mouse:%d %d %d\n",a,b,c);
+}
+void event_digital_joystick(uint8_t idx, uint8_t jmap)
+{
+	printf("Event joystick:%d %x\n", idx,jmap);
+}
+void event_analog_joystick(uint8_t idx, int8_t x, int8_t y)
+{
+	printf("Event analog joystick:%d %d %d\n", idx,x,y);
+}
+
+#define JOY_RIGHT       0x01
+#define JOY_LEFT        0x02
+#define JOY_DOWN        0x04
+#define JOY_UP          0x08
+#define JOY_BTN1        0x10
+#define JOY_BTN2        0x20
+#define JOY_BTN3        0x40
+#define JOY_BTN4        0x80
+#define JOY_MOVE        (JOY_RIGHT|JOY_LEFT|JOY_UP|JOY_DOWN)
+
+
Index: firmware/usb/hid.c
===================================================================
--- firmware/usb/hid.c	(nonexistent)
+++ firmware/usb/hid.c	(revision 269)
@@ -0,0 +1,565 @@
+#include <stdio.h>
+
+#include "usb.h"
+#include "timer.h"
+#include "hidparser.h"
+#include "events.h"
+#include "debug.h"
+#include "usbhostslave.h"
+
+static unsigned char kbd_led_state = 0;  // default: all leds off
+static unsigned char joysticks = 0;      // number of detected usb joysticks
+
+uint8_t hid_get_joysticks(void) {
+  return joysticks;
+}
+
+//get HID report descriptor 
+static uint8_t hid_get_report_descr(usb_device_t *dev, uint8_t i, uint16_t size)  {
+  //  hid_debugf("%s(%x, if=%d, size=%d)", __FUNCTION__, dev->bAddress, iface, size);
+
+  uint8_t buf[size];
+  usb_hid_info_t *info = &(dev->hid_info);
+  uint8_t rcode = usb_ctrl_req( dev, HID_REQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, 
+			      HID_DESCRIPTOR_REPORT, info->iface[i].iface_idx, size, buf);
+ 
+  if(!rcode) {
+    hid_debugf("HID report descriptor:");
+    //MWW hexdump(buf, size, 0);
+
+    // we got a report descriptor. Try to parse it
+    if(parse_report_descriptor(buf, size, &(info->iface[i].conf))) {
+      if(info->iface[i].conf.type == CONFIG_TYPE_JOYSTICK) {
+	hid_debugf("Detected USB joystick #%d", joysticks);
+
+	info->iface[i].device_type = HID_DEVICE_JOYSTICK;
+	info->iface[i].jindex = joysticks++;
+      }
+    }
+  }
+    
+  return rcode;
+}
+
+static uint8_t hid_set_idle(usb_device_t *dev, uint8_t iface, uint8_t reportID, uint8_t duration ) {
+  //  hid_debugf("%s(%x, if=%d id=%d, dur=%d)", __FUNCTION__, dev->bAddress, iface, reportID, duration);
+
+  return( usb_ctrl_req( dev, HID_REQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, 
+		       duration, iface, 0x0000, NULL));
+}
+
+static uint8_t hid_set_protocol(usb_device_t *dev, uint8_t iface, uint8_t protocol) {
+  //  hid_debugf("%s(%x, if=%d proto=%d)", __FUNCTION__, dev->bAddress, iface, protocol);
+
+  return( usb_ctrl_req( dev, HID_REQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 
+		       0x00, iface, 0x0000, NULL));
+}
+
+static uint8_t hid_set_report(usb_device_t *dev, uint8_t iface, uint8_t report_type, uint8_t report_id, 
+			      uint16_t nbytes, uint8_t* dataptr ) {
+  //  hid_debugf("%s(%x, if=%d data=%x)", __FUNCTION__, dev->bAddress, iface, dataptr[0]);
+
+  return( usb_ctrl_req(dev, HID_REQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, 
+		       report_type, iface, nbytes, dataptr));
+}
+
+/* todo: handle parsing in chunks */
+static uint8_t usb_hid_parse_conf(usb_device_t *dev, uint8_t conf, uint16_t len) {
+  usb_hid_info_t *info = &(dev->hid_info);
+  uint8_t rcode;
+  bool isGoodInterface = false;
+
+  union buf_u {
+    usb_configuration_descriptor_t conf_desc;
+    usb_interface_descriptor_t iface_desc;
+    usb_endpoint_descriptor_t ep_desc;
+    usb_hid_descriptor_t hid_desc;
+    uint8_t raw[len];
+  } buf, *p;
+
+  // usb_interface_descriptor
+
+  if(rcode = usb_get_conf_descr(dev, len, conf, &buf.conf_desc)) 
+    return rcode;
+
+  /* scan through all descriptors */
+  p = &buf;
+  while(len > 0) {
+    switch(p->conf_desc.bDescriptorType) {
+    case USB_DESCRIPTOR_CONFIGURATION:
+      // hid_debugf("conf descriptor size %d", p->conf_desc.bLength);
+      // we already had this, so we simply ignore it
+      break;
+
+    case USB_DESCRIPTOR_INTERFACE:
+      isGoodInterface = false;
+      // hid_debugf("iface descriptor size %d", p->iface_desc.bLength);
+
+      /* check the interface descriptors for supported class */
+
+      // only HID interfaces are supported
+      if(p->iface_desc.bInterfaceClass == USB_CLASS_HID) {
+	//	puts("iface is HID");
+
+	if(info->bNumIfaces < MAX_IFACES) {
+	  // ok, let's use this interface
+	  isGoodInterface = true;
+
+	  info->iface[info->bNumIfaces].iface_idx = p->iface_desc.bInterfaceNumber;
+	  info->iface[info->bNumIfaces].has_boot_mode = false;
+	  info->iface[info->bNumIfaces].is_5200daptor = false;
+	  info->iface[info->bNumIfaces].key_state = 0;
+	  info->iface[info->bNumIfaces].device_type = HID_DEVICE_UNKNOWN;
+	  info->iface[info->bNumIfaces].conf.type = CONFIG_TYPE_NONE;
+
+	  if(p->iface_desc.bInterfaceSubClass == HID_BOOT_INTF_SUBCLASS) {
+	    // hid_debugf("Iface %d is Boot sub class", info->bNumIfaces);
+	    info->iface[info->bNumIfaces].has_boot_mode = true;
+	  }
+	  
+	  switch(p->iface_desc.bInterfaceProtocol) {
+	  case HID_PROTOCOL_NONE:
+	    hid_debugf("HID protocol is NONE");
+	    break;
+	    
+	  case HID_PROTOCOL_KEYBOARD:
+	    hid_debugf("HID protocol is KEYBOARD");
+	    info->iface[info->bNumIfaces].device_type = HID_DEVICE_KEYBOARD;
+	    break;
+	    
+	  case HID_PROTOCOL_MOUSE:
+	    hid_debugf("HID protocol is MOUSE");
+	    info->iface[info->bNumIfaces].device_type = HID_DEVICE_MOUSE;
+	    break;
+	    
+	  default:
+	    hid_debugf("HID protocol is %d", p->iface_desc.bInterfaceProtocol);
+	    break;
+	  }
+	}
+      }
+      break;
+
+    case USB_DESCRIPTOR_ENDPOINT:
+      //      hid_debugf("endpoint descriptor size %d", p->ep_desc.bLength);
+
+      if(isGoodInterface) {
+
+	// only interrupt in endpoints are supported
+	if ((p->ep_desc.bmAttributes & 0x03) == 3 && (p->ep_desc.bEndpointAddress & 0x80) == 0x80) {
+	  hid_debugf("endpoint %d, interval = %dms", 
+		  p->ep_desc.bEndpointAddress & 0x0F, p->ep_desc.bInterval);
+
+	  // Fill in the endpoint info structure
+	  uint8_t epidx = info->bNumIfaces;
+	  info->iface[epidx].interval = p->ep_desc.bInterval;
+	  info->iface[epidx].ep.epAddr	 = (p->ep_desc.bEndpointAddress & 0x0F);
+	  info->iface[epidx].ep.maxPktSize = p->ep_desc.wMaxPacketSize[0];
+	  info->iface[epidx].ep.epAttribs	 = 0;
+	  info->iface[epidx].ep.bmNakPower = USB_NAK_NOWAIT;
+	  info->bNumIfaces++;
+	}
+      }
+      break;
+
+    case HID_DESCRIPTOR_HID:
+      hid_debugf("hid descriptor size %d", p->ep_desc.bLength);
+
+      if(isGoodInterface) {
+	// we need a report descriptor
+	if(p->hid_desc.bDescrType == HID_DESCRIPTOR_REPORT) {
+	  uint16_t len = p->hid_desc.wDescriptorLength[0] + 
+	    256 * p->hid_desc.wDescriptorLength[1];
+	  hid_debugf(" -> report descriptor size = %d", len);
+	  
+	  info->iface[info->bNumIfaces].report_desc_size = len;
+	}
+      }
+      break;
+
+    default:
+      hid_debugf("unsupported descriptor type %d size %d", p->raw[1], p->raw[0]);
+    }
+
+    // advance to next descriptor
+    len -= p->conf_desc.bLength;
+    p = (union buf_u*)(p->raw + p->conf_desc.bLength);
+  }
+  
+  if(len != 0) {
+    hid_debugf("Config underrun: %d", len);
+    return USB_ERROR_CONFIGURAION_SIZE_MISMATCH;
+  }
+
+  return 0;
+}
+
+static uint8_t usb_hid_init(usb_device_t *dev) {
+  hid_debugf("%s(%x)", __FUNCTION__, dev->bAddress);
+
+  uint8_t rcode;
+  uint8_t i;
+  uint16_t vid, pid;
+
+  usb_hid_info_t *info = &(dev->hid_info);
+  
+  union {
+    usb_device_descriptor_t dev_desc;
+    usb_configuration_descriptor_t conf_desc;
+  } buf;
+
+  // reset status
+  info->bPollEnable = false;
+  info->bNumIfaces = 0;
+
+  for(i=0;i<MAX_IFACES;i++) {
+    info->iface[i].qNextPollTime = 0;
+    info->iface[i].ep.epAddr	 = i;
+    info->iface[i].ep.maxPktSize = 8;
+    info->iface[i].ep.epAttribs	 = 0;
+    info->iface[i].ep.bmNakPower = USB_NAK_MAX_POWER;
+  }
+
+  // try to re-read full device descriptor from newly assigned address
+  if(rcode = usb_get_dev_descr( dev, sizeof(usb_device_descriptor_t), &buf.dev_desc ))
+    return rcode;
+
+  // save vid/pid for automatic hack later
+  vid = buf.dev_desc.idVendor;
+  pid = buf.dev_desc.idProduct;
+
+  uint8_t num_of_conf = buf.dev_desc.bNumConfigurations;
+  //  hid_debugf("number of configurations: %d", num_of_conf);
+
+  for(i=0; i<num_of_conf; i++) {
+    if(rcode = usb_get_conf_descr(dev, sizeof(usb_configuration_descriptor_t), i, &buf.conf_desc)) 
+      return rcode;
+    
+    //    hid_debugf("conf descriptor %d has total size %d", i, buf.conf_desc.wTotalLength);
+
+    // parse directly if it already fitted completely into the buffer
+    usb_hid_parse_conf(dev, i, buf.conf_desc.wTotalLength);
+  }
+
+  // check if we found valid hid interfaces
+  if(!info->bNumIfaces) {
+    hid_debugf("no hid interfaces found");
+    return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
+  }
+
+  // Set Configuration Value
+  rcode = usb_set_conf(dev, buf.conf_desc.bConfigurationValue);
+
+  // process all supported interfaces
+  for(i=0; i<info->bNumIfaces; i++) {
+    // no boot mode, try to parse HID report descriptor
+    if(!info->iface[i].has_boot_mode) {
+      rcode = hid_get_report_descr(dev, i, info->iface[i].report_desc_size);
+      if(rcode) return rcode;
+
+      if(info->iface[i].device_type == CONFIG_TYPE_JOYSTICK) {
+	char k;
+        
+	iprintf("Report: type = %d, id = %d, size = %d\n", 
+		info->iface[i].conf.type,
+		info->iface[i].conf.report_id,
+		info->iface[i].conf.report_size);
+	
+	for(k=0;k<2;k++)
+	  iprintf("Axis%d: %d@%d %d->%d\n", k, 
+		  info->iface[i].conf.joystick.axis[k].size,
+		  info->iface[i].conf.joystick.axis[k].byte_offset,
+		  info->iface[i].conf.joystick.axis[k].logical.min,
+		  info->iface[i].conf.joystick.axis[k].logical.max);
+	
+	for(k=0;k<4;k++)
+	  iprintf("Button%d: @%d/%d\n", k,
+		  info->iface[i].conf.joystick.button[k].byte_offset,
+		  info->iface[i].conf.joystick.button[k].bitmask);
+      }
+      
+      
+      // use fixed setup for known interfaces 
+      if((vid == 0x0079) && (pid == 0x0011) && (i==0)) {
+	iprintf("hacking cheap NES pad\n");
+        
+        // fixed setup for nes gamepad
+        info->iface[0].conf.joystick.button[0].byte_offset = 5;
+        info->iface[0].conf.joystick.button[0].bitmask = 32;
+        info->iface[0].conf.joystick.button[1].byte_offset = 5;
+        info->iface[0].conf.joystick.button[1].bitmask = 64;
+        info->iface[0].conf.joystick.button[2].byte_offset = 6;
+        info->iface[0].conf.joystick.button[2].bitmask = 16;
+        info->iface[0].conf.joystick.button[3].byte_offset = 6;
+        info->iface[0].conf.joystick.button[3].bitmask = 32;
+      }
+
+      if((vid == 0x04d8) && (pid == 0xf6ec) && (i==0)) {
+	iprintf("hacking 5200daptor\n");
+        
+	info->iface[0].conf.joystick.button[2].byte_offset = 4;
+	info->iface[0].conf.joystick.button[2].bitmask = 0x40;    // "Reset"
+	info->iface[0].conf.joystick.button[3].byte_offset = 4;
+	info->iface[0].conf.joystick.button[3].bitmask = 0x10;    // "Start"
+
+	info->iface[0].is_5200daptor = true;
+      }
+    }
+
+    rcode = hid_set_idle(dev, info->iface[i].iface_idx, 0, 0);
+    // MWW if (rcode && rcode != hrSTALL)
+    if (rcode && rcode != OHS900_STATMASK_STALL_RXED)
+      return rcode;
+
+    // enable boot mode
+    if(info->iface[i].has_boot_mode)
+      hid_set_protocol(dev, info->iface[i].iface_idx, HID_BOOT_PROTOCOL);
+  }
+  
+  puts("HID configured");
+
+  // update leds
+  for(i=0;i<MAX_IFACES;i++)
+    if(dev->hid_info.iface[i].device_type == HID_DEVICE_KEYBOARD)
+      hid_set_report(dev, dev->hid_info.iface[i].iface_idx, 2, 0, 1, &kbd_led_state);
+
+  info->bPollEnable = true;
+  return 0;
+}
+
+static uint8_t usb_hid_release(usb_device_t *dev) {
+  usb_hid_info_t *info = &(dev->hid_info);
+
+  puts(__FUNCTION__);
+
+  uint8_t i;
+  // check if a joystick is released
+  for(i=0;i<info->bNumIfaces;i++) {
+    if(info->iface[i].device_type == HID_DEVICE_JOYSTICK) {
+      uint8_t c_jindex = info->iface[i].jindex;
+      hid_debugf("releasing joystick #%d, renumbering", c_jindex);
+
+      // walk through all devices and search for sticks with a higher id
+
+      // search for all joystick interfaces on all hid devices
+      usb_device_t *dev = usb_get_devices();
+      uint8_t j;
+      for(j=0;j<USB_NUMDEVICES;j++) {
+	if(dev[j].bAddress && (dev[j].class == &usb_hid_class)) {
+	  // search for joystick interfaces
+	  uint8_t k;
+	  for(k=0;k<MAX_IFACES;k++) {
+	    if(dev[j].hid_info.iface[k].device_type == HID_DEVICE_JOYSTICK) {
+	      if(dev[j].hid_info.iface[k].jindex > c_jindex) {
+		hid_debugf("decreasing jindex of dev #%d from %d to %d", j, 
+			dev[j].hid_info.iface[k].jindex, dev[j].hid_info.iface[k].jindex-1);
+		dev[j].hid_info.iface[k].jindex--;
+	      }
+	    }
+	  }
+	}
+      }
+      // one less joystick in the system ...
+      joysticks--;
+    }
+  }
+
+  return 0;
+}
+
+// special 5200daptor button processing
+static void handle_5200daptor(usb_hid_iface_info_t *iface, uint8_t *buf) {
+
+  // list of buttons that are reported as keys
+  static const struct {
+    uint8_t byte_offset;   // offset of the byte within the report which the button bit is in
+    uint8_t mask;          // bitmask of the button bit
+    uint8_t key_code[2];   // usb keycodes to be sent for joystick 0 and joystick 1
+  } button_map[] = {
+    { 4, 0x10, 0x3a, 0x3d }, /* START -> f1/f4 */
+    { 4, 0x20, 0x3b, 0x3e }, /* PAUSE -> f2/f5 */
+    { 4, 0x40, 0x3c, 0x3f }, /* RESET -> f3/f6 */
+    { 5, 0x01, 0x1e, 0x21 }, /*     1 ->  1/4  */
+    { 5, 0x02, 0x1f, 0x22 }, /*     2 ->  2/5  */
+    { 5, 0x04, 0x20, 0x23 }, /*     3 ->  3/6  */
+    { 5, 0x08, 0x14, 0x15 }, /*     4 ->  q/r  */
+    { 5, 0x10, 0x1a, 0x17 }, /*     5 ->  w/t  */
+    { 5, 0x20, 0x08, 0x1c }, /*     6 ->  e/y  */
+    { 5, 0x40, 0x04, 0x09 }, /*     7 ->  a/f  */
+    { 5, 0x80, 0x16, 0x0a }, /*     8 ->  s/g  */
+    { 6, 0x01, 0x07, 0x0b }, /*     9 ->  d/h  */
+    { 6, 0x02, 0x1d, 0x19 }, /*     * ->  z/v  */
+    { 6, 0x04, 0x1b, 0x05 }, /*     0 ->  x/b  */
+    { 6, 0x08, 0x06, 0x11 }, /*     # ->  c/n  */
+    { 0, 0x00, 0x00, 0x00 }  /* ----  end ---- */
+  };
+
+  // keyboard events are only generated for the first
+  // two joysticks in the system
+  if(iface->jindex > 1) return;
+
+  // build map of pressed keys
+  uint8_t i;
+  uint16_t keys = 0;
+  for(i=0;button_map[i].mask;i++) 
+    if(buf[button_map[i].byte_offset] & button_map[i].mask)
+      keys |= (1<<i);
+
+  // check if keys have changed
+  if(iface->key_state != keys) {
+    uint8_t buf[6] = { 0,0,0,0,0,0 };
+    uint8_t p = 0;
+
+    // report up to 6 pressed keys
+    for(i=0;(i<16)&&(p<6);i++) 
+      if(keys & (1<<i))
+	buf[p++] = button_map[i].key_code[iface->jindex];
+
+    //    iprintf("5200: %d %d %d %d %d %d\n", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]);
+
+    // generate key events
+    event_keyboard(0x00, buf);
+
+    // save current state of keys
+    iface->key_state = keys;
+  }
+}
+
+static uint8_t usb_hid_poll(usb_device_t *dev) {
+  usb_hid_info_t *info = &(dev->hid_info);
+  int8_t i;
+
+  if (!info->bPollEnable)
+    return 0;
+  
+  for(i=0;i<info->bNumIfaces;i++) {
+    usb_hid_iface_info_t *iface = info->iface+i;
+    
+    if(iface->device_type != HID_DEVICE_UNKNOWN) {
+
+      if (iface->qNextPollTime <= timer_get_msec()) {
+	//      hid_debugf("poll %d...", iface->ep.epAddr);
+      
+	uint16_t read = iface->ep.maxPktSize;
+	uint8_t buf[iface->ep.maxPktSize];
+	uint8_t rcode = 
+	  usb_in_transfer(dev, &(iface->ep), &read, buf);
+	
+	if (rcode) {
+	  // MWW if (rcode != hrNAK)
+	  if (rcode != OHS900_STATMASK_NAK_RXED)
+	    hid_debugf("%s() error: %d", __FUNCTION__, rcode);
+	} else {
+	  
+	  // successfully received some bytes
+	  if(iface->has_boot_mode) {
+	    if(iface->device_type == HID_DEVICE_MOUSE) {
+	      // boot mouse needs at least three bytes
+	      if(read >= 3) {
+		// forward all three bytes to the user_io layer
+		event_mouse(buf[0], buf[1], buf[2]);
+	      }
+	    }
+	    
+	    if(iface->device_type == HID_DEVICE_KEYBOARD) {
+	      // boot kbd needs at least eight bytes
+	      if(read >= 8) {
+		event_keyboard(buf[0], buf+2);
+	      }
+	    }
+	  }
+	  
+	  if(iface->device_type == HID_DEVICE_JOYSTICK) {
+	    hid_config_t *conf = &iface->conf;
+	    if(read >= conf->report_size) {
+	      uint8_t jmap = 0;
+	      uint16_t a[2];
+	      uint8_t idx, i;
+	      
+	      // hid_debugf("Joystick data:"); hexdump(buf, read, 0);
+
+	      // two axes ...
+	      for(i=0;i<2;i++) {
+		a[i] = buf[conf->joystick.axis[i].byte_offset];
+		if(conf->joystick.axis[i].size == 16)
+		  a[i] += (buf[conf->joystick.axis[i].byte_offset+1])<<8;
+
+		// scale to 0 -> 255 range. 99% of the joysticks already deliver that
+		if((conf->joystick.axis[i].logical.min != 0) ||
+		   (conf->joystick.axis[i].logical.max != 255)) {
+		  a[i] = ((a[i] - conf->joystick.axis[i].logical.min) * 255)/
+		    (conf->joystick.axis[i].logical.max - 
+		     conf->joystick.axis[i].logical.min);
+		}
+	      }
+
+	      if(a[0] <  64) jmap |= JOY_LEFT;
+	      if(a[0] > 192) jmap |= JOY_RIGHT;
+	      if(a[1] <  64) jmap |= JOY_UP;
+	      if(a[1] > 192) jmap |= JOY_DOWN;
+	      
+	      //	      iprintf("JOY X:%d Y:%d\n", a[0], a[1]);
+	      
+	      // ... and four buttons
+	      for(i=0;i<4;i++)
+		if(buf[conf->joystick.button[i].byte_offset] & 
+		   conf->joystick.button[i].bitmask) jmap |= (JOY_BTN1<<i);
+	      
+	      //	      iprintf("JOY D:%d\n", jmap);
+
+	      // swap joystick 0 and 1 since 1 is the one 
+	      // used primarily on most systems
+	      idx = iface->jindex;
+	      if(idx == 0)      idx = 1;
+	      else if(idx == 1) idx = 0;
+	      
+	      // check if joystick state has changed
+	      if(jmap != iface->jmap) {
+		//	      iprintf("jmap %d changed to %x\n", idx, jmap);
+		
+		// and feed into joystick input system
+		event_digital_joystick(idx, jmap);
+		iface->jmap = jmap;
+	      }
+	      
+	      // also send analog values
+	      event_analog_joystick(idx, a[0]-128, a[1]-128);
+
+	      // do special 5200daptor treatment
+	      if(iface->is_5200daptor)
+		handle_5200daptor(iface, buf);
+	    }
+	  }
+	}
+	iface->qNextPollTime += iface->interval;   // poll at requested rate
+      }
+    }
+  }
+
+  return 0;
+}
+
+void hid_set_kbd_led(unsigned char led, bool on) {
+  // check if led state has changed
+  if( (on && !(kbd_led_state&led)) || (!on && (kbd_led_state&led))) {
+    if(on) kbd_led_state |=  led;
+    else   kbd_led_state &= ~led;
+
+    // search for all keyboard interfaces on all hid devices
+    usb_device_t *dev = usb_get_devices();
+    int i;
+    for(i=0;i<USB_NUMDEVICES;i++) {
+      if(dev[i].bAddress && (dev[i].class == &usb_hid_class)) {
+	// search for keyboard interfaces
+	int j;
+	for(j=0;j<MAX_IFACES;j++)
+	  if(dev[i].hid_info.iface[j].device_type == HID_DEVICE_KEYBOARD)
+	    hid_set_report(dev+i, dev[i].hid_info.iface[j].iface_idx, 2, 0, 1, &kbd_led_state);
+      }
+    }
+  }
+}
+
+const usb_device_class_config_t usb_hid_class = {
+  usb_hid_init, usb_hid_release, usb_hid_poll };  
+
Index: firmware/usb/hid.h
===================================================================
--- firmware/usb/hid.h	(nonexistent)
+++ firmware/usb/hid.h	(revision 269)
@@ -0,0 +1,92 @@
+#ifndef HID_H
+#define HID_H
+
+#include <stdbool.h>
+#include <inttypes.h>
+#include "hidparser.h"
+
+#define HID_LED_NUM_LOCK    0x01
+#define HID_LED_CAPS_LOCK   0x02
+#define HID_LED_SCROLL_LOCK 0x04
+
+/* HID constants. Not part of chapter 9 */
+/* Class-Specific Requests */
+#define HID_REQUEST_GET_REPORT      0x01
+#define HID_REQUEST_GET_IDLE        0x02
+#define HID_REQUEST_GET_PROTOCOL    0x03
+#define HID_REQUEST_SET_REPORT      0x09
+#define HID_REQUEST_SET_IDLE        0x0A
+#define HID_REQUEST_SET_PROTOCOL    0x0B
+
+#define HID_DESCRIPTOR_HID		0x21
+#define HID_DESCRIPTOR_REPORT		0x22
+#define HID_DESRIPTOR_PHY		0x23
+
+/* Protocol Selection */
+#define HID_BOOT_PROTOCOL                       0x00
+#define HID_RPT_PROTOCOL                        0x01
+
+/* HID Interface Class SubClass Codes */
+#define HID_BOOT_INTF_SUBCLASS          0x01
+
+#define HID_PROTOCOL_NONE           0x00
+#define HID_PROTOCOL_KEYBOARD       0x01
+#define HID_PROTOCOL_MOUSE          0x02
+
+#define HID_REQ_HIDREPORT     USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
+#define HID_REQ_HIDOUT        USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
+
+#define MAX_IFACES  2  // max supported interfaces per device. 2 to support kbd/mouse combos
+
+#define HID_DEVICE_UNKNOWN  0
+#define HID_DEVICE_MOUSE    1
+#define HID_DEVICE_KEYBOARD 2
+#define HID_DEVICE_JOYSTICK 3
+
+typedef struct {
+  ep_t ep;    // interrupt endpoint info structure
+
+  uint8_t iface_idx;
+  uint16_t report_desc_size;
+
+  uint8_t device_type;
+  bool has_boot_mode: 1;     // device supports boot mode
+  bool is_5200daptor: 1;     // device is a 5200daptor with special key handling
+  uint16_t key_state;        // needed to detect key state changes in 5200daptor
+  
+  // additional info extracted from the report descriptor
+  // (currently only used for joysticks) 
+  uint8_t jmap;           // last reported joystick state
+  uint8_t jindex;         // joystick index
+  hid_config_t conf;
+
+  uint8_t interval;
+  uint32_t qNextPollTime;     // next poll time
+
+} usb_hid_iface_info_t;
+
+typedef struct {
+  bool	   bPollEnable;	      // poll enable flag
+  uint8_t  bNumIfaces;
+
+  usb_hid_iface_info_t iface[MAX_IFACES];
+} usb_hid_info_t;
+
+/* HID descriptor */
+typedef struct  {
+  uint8_t         bLength;
+  uint8_t         bDescriptorType;
+  uint16_t        bcdHID;                         // HID class specification release
+  uint8_t         bCountryCode;
+  uint8_t         bNumDescriptors;                // Number of additional class specific descriptors
+  uint8_t         bDescrType;                     // Type of class descriptor
+  uint8_t         wDescriptorLength[2];           // Total size of the Report descriptor
+} __attribute__((packed)) usb_hid_descriptor_t;
+
+// interface to usb core
+extern const usb_device_class_config_t usb_hid_class;
+
+void hid_set_kbd_led(unsigned char led, bool on);
+uint8_t hid_get_joysticks(void);
+
+#endif // HID_H
Index: firmware/usb/hidparser.c
===================================================================
--- firmware/usb/hidparser.c	(nonexistent)
+++ firmware/usb/hidparser.c	(revision 269)
@@ -0,0 +1,421 @@
+// http://www.frank-zhao.com/cache/hid_tutorial_1.php
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "hidparser.h"
+#include "debug.h"
+
+#if 1
+#define hidp_extreme_debugf(...) hidp_debugf(__VA_ARGS__)
+#else
+#define hidp_extreme_debugf(...)
+#endif
+
+typedef struct {
+  uint8_t bSize: 2;
+  uint8_t bType: 2;
+  uint8_t bTag: 4;
+} __attribute__((packed)) item_t;
+
+// flags for joystick components required
+#define JOYSTICK_REQ_AXIS_X  0x01
+#define JOYSTICK_REQ_AXIS_Y  0x02
+#define JOYSTICK_REQ_BTN_0   0x04
+#define JOYSTICK_COMPLETE    (JOYSTICK_REQ_AXIS_X | JOYSTICK_REQ_AXIS_Y | JOYSTICK_REQ_BTN_0)
+
+#define USAGE_PAGE_GENERIC_DESKTOP  1
+#define USAGE_PAGE_SIMULATION       2
+#define USAGE_PAGE_VR               3
+#define USAGE_PAGE_SPORT            4
+#define USAGE_PAGE_GAMING           5
+#define USAGE_PAGE_GENERIC_DEVICE   6
+#define USAGE_PAGE_KEYBOARD         7
+#define USAGE_PAGE_LEDS             8
+#define USAGE_PAGE_BUTTON           9
+#define USAGE_PAGE_ORDINAL         10
+#define USAGE_PAGE_TELEPHONY       11
+#define USAGE_PAGE_CONSUMER        12
+
+
+#define USAGE_POINTER   1
+#define USAGE_MOUSE     2
+#define USAGE_JOYSTICK  4
+#define USAGE_GAMEPAD   5
+#define USAGE_KEYBOARD  6
+#define USAGE_KEYPAD    7
+#define USAGE_MULTIAXIS 8
+
+#define USAGE_X       48
+#define USAGE_Y       49
+#define USAGE_Z       50
+#define USAGE_WHEEL   56
+
+bool parse_report_descriptor(uint8_t *rep, uint16_t rep_size, hid_config_t *conf) {
+  int8_t app_collection = 0;
+  int8_t phys_log_collection = 0;
+  uint8_t skip_collection = 0;
+  int8_t generic_desktop = -1;   // depth at which first gen_desk was found
+  uint8_t collection_depth = 0;
+
+  uint8_t i;
+
+  // 
+  uint8_t report_size, report_count;
+  uint16_t bit_count = 0, usage_count = 0;
+  uint16_t logical_minimum=0, logical_maximum=0;
+
+  // mask used to check of all required components have been found, so
+  // that e.g. both axes and the button of a joystick are ready to be used
+  uint8_t setup_complete = 0;
+
+  // joystick/mouse components
+  int8_t axis[2] = { -1, -1};
+  uint8_t btns = 0;
+
+  conf->type = CONFIG_TYPE_NONE;
+
+  while(rep_size) {
+    // extract short item
+    uint8_t tag = ((item_t*)rep)->bTag;
+    uint8_t type = ((item_t*)rep)->bType;
+    uint8_t size = ((item_t*)rep)->bSize;
+
+    rep++;
+    rep_size--;   // one byte consumed
+    
+    uint32_t value = 0;
+    if(size) {      // size 1/2/3
+      value = *rep++;
+      rep_size--;
+    }
+
+    if(size > 1) {  // size 2/3
+      value = (value & 0xff) + ((uint32_t)(*rep++)<<8);
+      rep_size--;
+    }
+
+    if(size > 2) {  // size 3
+      value &= 0xffff;
+      value |= ((uint32_t)(*rep++)<<16);
+      value |= ((uint32_t)(*rep++)<<24);
+      rep_size-=2;
+    }
+
+    //    hidp_extreme_debugf("Value = %d (%u)\n", value, value);
+    
+    // we are currently skipping an unknown/unsupported collection) 
+    if(skip_collection) {
+      if(!type) {  // main item
+	// any new collection increases the depth of collections to skip
+	if(tag == 10) {
+	  skip_collection++;
+	  collection_depth++;
+	}
+
+	// any end collection decreases it
+	if(tag == 12) {
+	  skip_collection--;
+	  collection_depth--;
+
+	  // leaving the depth the generic desktop was valid for
+	  if(generic_desktop > collection_depth)
+	    generic_desktop = -1;
+	}
+      }
+
+      
+    } else {
+      //      hidp_extreme_debugf("-> Item tag=%d type=%d size=%d\n", tag, type, size);
+
+      switch(type) {
+      case 0:
+	// main item
+	
+	switch(tag) {
+	case 8:
+	  // 
+	  if(btns) {
+	    if(conf->type == CONFIG_TYPE_JOYSTICK) {
+	      // scan for up to four buttons
+	      char b;
+	      for(b=0;b<4;b++) {
+		if(report_count > b) {
+		  uint16_t this_bit = bit_count+b;
+
+		  hidp_debugf("BUTTON%d @ %d (byte %d, mask %d)\n", b, 
+			      this_bit, this_bit/8, 1 << (this_bit%8));
+
+		  conf->joystick.button[b].byte_offset = this_bit/8;
+		  conf->joystick.button[b].bitmask = 1 << (this_bit%8);
+		}
+	      }
+
+	      // we found at least one button which is all we want to accept this as a valid 
+	      // joystick
+	      setup_complete |= JOYSTICK_REQ_BTN_0;
+	    }
+	  }
+
+	  // 
+	  char c;
+	  for(c=0;c<2;c++) {
+	    if(axis[c] >= 0) {
+	      uint16_t cnt = bit_count + report_size * axis[c];
+	      hidp_debugf("  (%c-AXIS @ %d (byte %d))\n", 'X'+c,
+		     cnt, cnt/8);
+
+	      // only 8/16 bit axes at byte boundaries are supported for
+	      // joysticks
+	      if((conf->type == CONFIG_TYPE_JOYSTICK) &&
+		 ((report_size == 8) || (report_size == 16)) && ((cnt&7) == 0)) {
+		// save in joystick config
+		conf->joystick.axis[c].byte_offset = cnt/8;
+		conf->joystick.axis[c].size = report_size;
+		conf->joystick.axis[c].logical.min = logical_minimum;
+		conf->joystick.axis[c].logical.max = logical_maximum;
+		conf->joystick.axis[c].size = report_size;
+		if(c==0) setup_complete |= JOYSTICK_REQ_AXIS_X;
+		if(c==1) setup_complete |= JOYSTICK_REQ_AXIS_Y;
+	      }
+
+	      if((report_size != 8) && (report_size != 16))
+		hidp_debugf("Unsupported report size %d\n", report_size);
+
+	      if((cnt&7) != 0) 
+		hidp_debugf("Unsupported bit offset %d\n", cnt&7);
+	    }
+	  }
+	  
+	  hidp_extreme_debugf("INPUT(%d)\n", value);
+
+	  // reset for next inputs
+	  bit_count += report_count * report_size;
+	  usage_count = 0;
+	  btns = 0;
+	  axis[0] = axis[1] = -1;
+	  break;
+
+	case 9:
+	  hidp_extreme_debugf("OUTPUT(%d)\n", value);
+	  break;
+
+	case 11:
+	  hidp_extreme_debugf("FEATURE(%d)\n", value);
+	  break;
+
+	case 10:
+	  hidp_extreme_debugf("COLLECTION(%d)\n", value);
+	  collection_depth++;
+	  usage_count = 0;
+
+	  if(value == 1) {	   // app collection
+	    hidp_extreme_debugf("  -> application\n");
+	    app_collection++;
+	  } else if(value == 0) {  // physical collection
+	    hidp_extreme_debugf("  -> physical\n");
+	    phys_log_collection++;
+	  } else if(value == 2) {  // logical collection
+	    hidp_extreme_debugf("  -> logical\n");
+	    phys_log_collection++;
+	  } else {
+	    hidp_extreme_debugf("skipping unsupported collection\n");
+	    skip_collection++;
+	  }
+	  break;
+	  
+	case 12:
+	  hidp_extreme_debugf("END_COLLECTION(%d)\n", value);
+	  collection_depth--;
+
+	  // leaving the depth the generic desktop was valid for
+	  if(generic_desktop > collection_depth)
+	    generic_desktop = -1;
+
+	  if(phys_log_collection) {
+	    hidp_extreme_debugf("  -> phys/log end\n");
+	    phys_log_collection--;
+	  } else if(app_collection) {
+	    hidp_extreme_debugf("  -> app end\n");
+	    app_collection--;
+	  } else {
+	    hidp_debugf(" -> unexpected\n");
+	    return false;
+	  }
+	  break;
+
+	default:
+	  hidp_debugf("unexpected main item %d\n", tag);
+	  return false;
+	  break;
+	}
+	break;
+	
+      case 1:
+	// global item
+	switch(tag) {
+	case 0:
+	  hidp_extreme_debugf("USAGE_PAGE(%d/0x%x)\n", value, value);
+
+	  if(value == USAGE_PAGE_KEYBOARD) {
+	    hidp_extreme_debugf(" -> Keyboard\n");
+	  } else if(value == USAGE_PAGE_GAMING) {
+	    hidp_extreme_debugf(" -> Game device\n");
+	  } else if(value == USAGE_PAGE_LEDS) {
+	    hidp_extreme_debugf(" -> LEDs\n");
+	  } else if(value == USAGE_PAGE_CONSUMER) {
+	    hidp_extreme_debugf(" -> Consumer\n");
+	  } else if(value == USAGE_PAGE_BUTTON) {
+	    hidp_extreme_debugf(" -> Buttons\n");
+	    btns = 1;
+	  } else if(value == USAGE_PAGE_GENERIC_DESKTOP) {
+	    hidp_extreme_debugf(" -> Generic Desktop\n");
+
+	    if(generic_desktop < 0)
+	      generic_desktop = collection_depth;
+	  } else
+	    hidp_extreme_debugf(" -> UNSUPPORTED USAGE_PAGE\n");
+
+	  break;
+	  
+	case 1:
+	  hidp_extreme_debugf("LOGICAL_MINIMUM(%d/%d)\n", value, (int8_t)value);
+	  logical_minimum = value;
+	  break;
+	  
+	case 2:
+	  hidp_extreme_debugf("LOGICAL_MAXIMUM(%d)\n", value);
+	  logical_maximum = value;
+	  break;
+
+	case 3:
+	  hidp_extreme_debugf("PHYSICAL_MINIMUM(%d/%d)\n", value, (int8_t)value);
+	  break;
+	  
+	case 4:
+	  hidp_extreme_debugf("PHYSICAL_MAXIMUM(%d)\n", value);
+	  break;
+
+	case 5:
+	  hidp_extreme_debugf("UNIT_EXPONENT(%d)\n", value);
+	  break;
+
+	case 6:
+	  hidp_extreme_debugf("UNIT(%d)\n", value);
+	  break;
+
+	case 7:
+	  hidp_extreme_debugf("REPORT_SIZE(%d)\n", value);
+	  report_size = value;
+	  break;
+
+	case 8:
+	  hidp_extreme_debugf("REPORT_ID(%d)\n", value);
+	  conf->report_id = value;
+	  break;
+
+	case 9:
+	  hidp_extreme_debugf("REPORT_COUNT(%d)\n", value);
+	  report_count = value;
+	  break;
+	  
+	default:
+	  hidp_debugf("unexpected global item %d\n", tag);
+	  return false;
+	  break;
+	}
+	break;
+	
+      case 2:
+	// local item
+	switch(tag) {
+	case 0:
+	  // we only support mice, keyboards and joysticks
+	  hidp_extreme_debugf("USAGE(%d/0x%x)\n", value, value);
+
+	  if( !collection_depth && (value == USAGE_KEYBOARD)) {
+	    // usage(keyboard) is always allowed
+	    hidp_debugf(" -> Keyboard\n");
+	    conf->type = CONFIG_TYPE_KEYBOARD;
+	  } else if(!collection_depth && (value == USAGE_MOUSE)) {
+	    // usage(mouse) is always allowed
+	    hidp_debugf(" -> Mouse\n");
+	    conf->type = CONFIG_TYPE_MOUSE;
+	  } else if(!collection_depth && 
+		    ((value == USAGE_GAMEPAD) || (value == USAGE_JOYSTICK))) {
+	    hidp_extreme_debugf(" -> Gamepad/Joystick\n");
+	    hidp_debugf("Gamepad/Joystick usage found\n");
+	    conf->type = CONFIG_TYPE_JOYSTICK;
+	  } else if(value == USAGE_POINTER && app_collection) {
+	    // usage(pointer) is allowed within the application collection
+
+	    hidp_debugf(" -> Pointer\n");
+
+	  } else if((value == USAGE_X || value == USAGE_Y) && app_collection) {
+	    // usage(x) and usage(y) are allowed within the app collection
+	    hidp_extreme_debugf(" -> axis usage\n");
+
+	    // we support x and y axis on joysticks
+	    if(conf->type == CONFIG_TYPE_JOYSTICK) {
+	      if(value == USAGE_X) {
+		hidp_extreme_debugf("JOYSTICK: found x axis @ %d\n", usage_count);
+		axis[0] = usage_count;
+	      }
+	      if(value == USAGE_Y) {
+		hidp_extreme_debugf("JOYSTICK: found y axis @ %d\n", usage_count);
+		axis[1] = usage_count;
+	      }
+	    }
+	  } else {
+	    hidp_extreme_debugf(" -> UNSUPPORTED USAGE\n");
+	    //	    return false;
+	  }
+
+	  usage_count++;
+	  break;
+	  
+	case 1:
+	  hidp_extreme_debugf("USAGE_MINIMUM(%d)\n", value);
+	  usage_count -= (value-1);
+	  break;
+	  
+	case 2:
+	  hidp_extreme_debugf("USAGE_MAXIMUM(%d)\n", value);
+	  usage_count += value;
+	  break;
+	  
+	default:
+	  hidp_extreme_debugf("unexpected local item %d\n", tag);
+	  //	  return false;
+	  break;
+	}
+	break;
+	
+      default:
+	// reserved
+	hidp_extreme_debugf("unexpected resreved item %d\n", tag);
+	//	return false;
+	break;
+      }
+    }
+  }
+
+  hidp_debugf("total bit count: %d (%d bytes, %d bits)\n", 
+	 bit_count, bit_count/8, bit_count%8);
+
+  conf->report_size = bit_count/8;
+
+  // check if something useful was detected
+  if(conf->type == CONFIG_TYPE_JOYSTICK) {
+    if(setup_complete == JOYSTICK_COMPLETE) {
+      hidp_debugf("Joystick ok\n");
+      return true;
+    }
+
+    hidp_debugf("Ignoring incomplete joystick %x\n", setup_complete);
+  } else
+    hidp_debugf("No joystick\n");
+
+  return false;
+}
Index: firmware/usb/hidparser.h
===================================================================
--- firmware/usb/hidparser.h	(nonexistent)
+++ firmware/usb/hidparser.h	(revision 269)
@@ -0,0 +1,36 @@
+#ifndef HIDPARSER_H
+#define HIDPARSER_H
+
+#define CONFIG_TYPE_NONE     0
+#define CONFIG_TYPE_MOUSE    1
+#define CONFIG_TYPE_KEYBOARD 2
+#define CONFIG_TYPE_JOYSTICK 3
+
+// currently only joysticks are supported
+typedef struct {
+  uint8_t type: 2;             // CONFIG_TYPE_...
+  uint8_t report_id;
+  uint8_t report_size;
+
+  union {
+    struct {
+      struct {
+	uint8_t byte_offset;
+	uint8_t size;          // 8 or 16 bits supported
+	struct {
+	  uint16_t min;
+	  uint16_t max;
+	} logical;
+      } axis[2];               // x and y axis
+
+      struct {
+	uint8_t byte_offset;
+	uint8_t bitmask;
+      } button[4];             // 4 buttons
+    } joystick;
+  };
+} hid_config_t;
+
+bool parse_report_descriptor(uint8_t *rep, uint16_t rep_size, hid_config_t *conf);
+
+#endif // HIDPARSER_H
Index: firmware/usb/hub.c
===================================================================
--- firmware/usb/hub.c	(nonexistent)
+++ firmware/usb/hub.c	(revision 269)
@@ -0,0 +1,280 @@
+#include <stdio.h>
+
+#include "usb.h"
+#include "timer.h"
+#include "debug.h"
+
+static uint8_t usb_hub_clear_hub_feature(usb_device_t *dev, uint8_t fid )  {
+  return( usb_ctrl_req( dev, USB_HUB_REQ_CLEAR_HUB_FEATURE, 
+       USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, NULL));
+}
+
+// Clear Port Feature
+static uint8_t usb_hub_clear_port_feature(usb_device_t *dev, uint8_t fid, uint8_t port, uint8_t sel )  {
+  return( usb_ctrl_req( dev , USB_HUB_REQ_CLEAR_PORT_FEATURE, 
+       USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000|port)|(sel<<8)), 0, NULL));
+}
+// Get Hub Descriptor
+static uint8_t usb_hub_get_hub_descriptor(usb_device_t *dev, uint8_t index, 
+					  uint16_t nbytes, usb_hub_descriptor_t *dataptr )  {
+  return( usb_ctrl_req( dev, USB_HUB_REQ_GET_HUB_DESCRIPTOR, 
+			USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, (uint8_t*)dataptr));
+}
+
+// Set Port Feature
+static uint8_t usb_hub_set_port_feature(usb_device_t *dev, uint8_t fid, uint8_t port, uint8_t sel ) {
+  return( usb_ctrl_req( dev, USB_HUB_REQ_SET_PORT_FEATURE, 
+       USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000|sel)<<8)|port), 0, NULL));
+}
+
+// Get Port Status
+static uint8_t usb_hub_get_port_status(usb_device_t *dev, uint8_t port, uint16_t nbytes, uint8_t* dataptr )  {
+  return( usb_ctrl_req( dev, USB_HUB_REQ_GET_PORT_STATUS, 
+       USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, dataptr));
+}
+
+static uint8_t usb_hub_init(usb_device_t *dev) {
+  iprintf("%s()\n", __FUNCTION__);
+
+  uint8_t rcode;
+  uint8_t i;
+
+  usb_hub_info_t *info = &(dev->hub_info);
+
+  union {
+    usb_device_descriptor_t dev_desc;
+    usb_configuration_descriptor_t conf_desc;
+    usb_hub_descriptor_t hub_desc;
+  } buf;
+
+  // reset status
+  info->bNbrPorts = 0; 
+  info->qNextPollTime = 0;
+  info->bPollEnable = false;
+
+  info->ep.epAddr	= 1;
+  info->ep.maxPktSize	= 8;  //kludge
+  info->ep.epAttribs     = 0;
+  info->ep.bmNakPower	= USB_NAK_NOWAIT;
+
+  rcode = usb_get_dev_descr( dev, 8, &buf.dev_desc );
+  if( rcode ) {
+    puts("failed to get device descriptor 1");
+    return rcode;
+  }
+  
+  // Extract device class from device descriptor
+  // If device class is not a hub return
+  if (buf.dev_desc.bDeviceClass != USB_CLASS_HUB) {
+    puts("not a hub!");    
+    return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
+  }
+
+  // try to re-read full device descriptor from newly assigned address
+  if(rcode = usb_get_dev_descr( dev, sizeof(usb_device_descriptor_t), &buf.dev_desc )) {
+    puts("failed to get device descriptor 2");
+    return rcode;
+  }
+ 
+  // Get hub descriptor
+  rcode = usb_hub_get_hub_descriptor(dev, 0, 8, &buf.hub_desc);
+    
+  if (rcode) {
+    puts("failed to get hub descriptor");
+    return rcode;
+  }
+  
+  // Save number of ports for future use
+  info->bNbrPorts = buf.hub_desc.bNbrPorts;
+    
+  // Read configuration Descriptor in Order To Obtain Proper Configuration Value
+  rcode = usb_get_conf_descr(dev, sizeof(usb_configuration_descriptor_t), 0, &buf.conf_desc);
+  if (rcode) {
+    puts("failed to read configuration descriptor");
+    return rcode;
+  }
+
+  // Set Configuration Value
+  rcode = usb_set_conf(dev, buf.conf_desc.bConfigurationValue);
+  if (rcode) {
+    iprintf("failed to set configuration to %d\n", buf.conf_desc.bConfigurationValue);
+    return rcode;
+  }
+    
+  // Power on all ports
+  for (i=1; i<=info->bNbrPorts; i++)
+    usb_hub_set_port_feature(dev, HUB_FEATURE_PORT_POWER, i, 0);	// HubPortPowerOn(i);
+    
+  if(!dev->parent)
+    usb_SetHubPreMask();
+
+  info->bPollEnable = true;
+
+  return 0;
+}
+
+static uint8_t usb_hub_release(usb_device_t *dev) {
+  puts(__FUNCTION__);
+
+  // root hub unplugged
+  if(!dev->parent)
+    usb_ResetHubPreMask();
+
+  return 0;
+}
+
+static void usb_hub_show_port_status(uint8_t port, uint16_t status, uint16_t changed) {
+  iprintf("Status of port %d:\n", port);
+
+  if(status & USB_HUB_PORT_STATUS_PORT_CONNECTION)    puts(" connected");
+  if(status & USB_HUB_PORT_STATUS_PORT_ENABLE)        puts(" enabled");
+  if(status & USB_HUB_PORT_STATUS_PORT_SUSPEND)       puts(" suspended");
+  if(status & USB_HUB_PORT_STATUS_PORT_OVER_CURRENT)  puts(" over current");
+  if(status & USB_HUB_PORT_STATUS_PORT_RESET)         puts(" reset");
+  if(status & USB_HUB_PORT_STATUS_PORT_POWER)         puts(" powered");
+  if(status & USB_HUB_PORT_STATUS_PORT_LOW_SPEED)     puts(" low speed");
+  if(status & USB_HUB_PORT_STATUS_PORT_HIGH_SPEED)    puts(" high speed");
+  if(status & USB_HUB_PORT_STATUS_PORT_TEST)          puts(" test");
+  if(status & USB_HUB_PORT_STATUS_PORT_INDICATOR)     puts(" indicator");
+
+  iprintf("Changes on port %d:\n", port);
+  if(changed & USB_HUB_PORT_STATUS_PORT_CONNECTION)   puts(" connected");
+  if(changed & USB_HUB_PORT_STATUS_PORT_ENABLE)       puts(" enabled");
+  if(changed & USB_HUB_PORT_STATUS_PORT_SUSPEND)      puts(" suspended");
+  if(changed & USB_HUB_PORT_STATUS_PORT_OVER_CURRENT) puts(" over current");
+  if(changed & USB_HUB_PORT_STATUS_PORT_RESET)        puts(" reset");
+}
+
+static uint8_t usb_hub_port_status_change(usb_device_t *dev, uint8_t port, hub_event_t evt) {
+  usb_hub_info_t *info = &(dev->hub_info);
+
+  iprintf("status change on port %d, 0x%x\n", port, evt.bmEvent);
+  usb_hub_show_port_status(port, evt.bmStatus, evt.bmChange);
+
+  static bool bResetInitiated = false;
+
+  switch (evt.bmEvent) {
+    // Device connected event
+  case USB_HUB_PORT_EVENT_CONNECT:
+  case USB_HUB_PORT_EVENT_LS_CONNECT:
+    iprintf(" dev %x: port %d connect!\n", dev->bAddress, port);
+
+    if (bResetInitiated) {
+      iprintf("reset already in progress\n");
+      return 0;
+    }
+
+    //    timer_delay_msec(100);
+
+    iprintf("resetting port %d\n", port);
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_ENABLE, port, 0);
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
+    usb_hub_set_port_feature(dev, HUB_FEATURE_PORT_RESET, port, 0);	
+    bResetInitiated = true;
+    return HUB_ERROR_PORT_HAS_BEEN_RESET;
+    
+    // Device disconnected event
+  case USB_HUB_PORT_EVENT_DISCONNECT:
+    iprintf(" port %d disconnect!\n", port);
+
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_ENABLE, port, 0);
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
+    bResetInitiated = false;
+
+    usb_release_device(dev->bAddress, port);
+
+    return 0;
+    
+    // Reset complete event
+  case USB_HUB_PORT_EVENT_RESET_COMPLETE:
+  case USB_HUB_PORT_EVENT_LS_RESET_COMPLETE:
+    iprintf(" port %d reset complete!\n", port);
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_RESET, port, 0);
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
+    
+    usb_configure(dev->bAddress, port, 
+	  (evt.bmStatus & USB_HUB_PORT_STATUS_PORT_LOW_SPEED)!=0 );
+
+    bResetInitiated = false;
+    break;
+  }
+
+  return 0;
+}
+
+static uint8_t usb_hub_check_hub_status(usb_device_t *dev, uint8_t ports) {
+  usb_hub_info_t *info = &(dev->hub_info);
+
+  uint8_t	rcode;
+  uint8_t	buf[8];
+  uint16_t	read = 1;
+
+  //   iprintf("%s(addr=%x)\n", __FUNCTION__, dev->bAddress);
+
+  rcode = usb_in_transfer(dev, &(info->ep), &read, buf);
+  if(rcode)
+    return rcode;
+
+  uint8_t port, mask;
+  for(port=1,mask=0x02; port<8; mask<<=1, port++) {
+    if (buf[0] & mask) {
+      hub_event_t evt;
+      evt.bmEvent = 0;
+
+      rcode = usb_hub_get_port_status(dev, port, sizeof(evt.evtBuff), evt.evtBuff);
+      if (rcode)
+	continue;
+
+      rcode = usb_hub_port_status_change(dev, port, evt);
+      
+      if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
+	return 0;
+      
+      if (rcode)
+	return rcode;
+    }
+  } // for
+  
+  for (port=1; port<=ports; port++) {
+    hub_event_t	evt;
+    evt.bmEvent = 0;
+    
+    rcode = usb_hub_get_port_status(dev, port, 4, evt.evtBuff);
+    if (rcode)
+      continue;
+    
+    if ((evt.bmStatus & USB_HUB_PORT_STATE_CHECK_DISABLED) != USB_HUB_PORT_STATE_DISABLED)
+      continue;
+    
+    // Emulate connection event for the port
+    evt.bmChange |= USB_HUB_PORT_STATUS_PORT_CONNECTION;
+    
+    rcode = usb_hub_port_status_change(dev, port, evt);
+    if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
+      return 0;
+    
+    if (rcode)
+      return rcode;
+  }
+  return 0;
+}
+
+static uint8_t usb_hub_poll(usb_device_t *dev) {
+  usb_hub_info_t *info = &(dev->hub_info);
+
+  uint8_t rcode = 0;
+
+  if (!info->bPollEnable)
+    return 0;
+  
+  if (info->qNextPollTime <= timer_get_msec()) {
+    rcode = usb_hub_check_hub_status(dev, info->bNbrPorts);
+    info->qNextPollTime = timer_get_msec() + 100;   // poll 10 times a second
+  }
+
+  return rcode;
+}
+
+const usb_device_class_config_t usb_hub_class = {
+  usb_hub_init, usb_hub_release, usb_hub_poll };  
+
Index: firmware/usb/hub.h
===================================================================
--- firmware/usb/hub.h	(nonexistent)
+++ firmware/usb/hub.h	(revision 269)
@@ -0,0 +1,109 @@
+#ifndef HUB_H
+#define HUB_H
+
+#include <stdbool.h>
+#include <inttypes.h>
+
+typedef struct {
+  uint8_t  bNbrPorts;	    // number of ports
+  uint32_t qNextPollTime;   // next poll time
+  bool	   bPollEnable;	    // poll enable flag
+  ep_t ep;	            // interrupt endpoint info structure
+} usb_hub_info_t;
+
+// Hub Requests
+#define USB_HUB_REQ_CLEAR_HUB_FEATURE		USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
+#define USB_HUB_REQ_CLEAR_PORT_FEATURE	USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_CLEAR_TT_BUFFER		USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_GET_HUB_DESCRIPTOR	USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
+#define USB_HUB_REQ_GET_HUB_STATUS		USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
+#define USB_HUB_REQ_GET_PORT_STATUS		USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_RESET_TT			USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_SET_HUB_DESCRIPTOR	USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
+#define USB_HUB_REQ_SET_HUB_FEATURE		USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
+#define USB_HUB_REQ_SET_PORT_FEATURE		USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_GET_TT_STATE		USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_STOP_TT			USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+
+// Hub Features
+#define HUB_FEATURE_C_HUB_LOCAL_POWER	0
+#define HUB_FEATURE_C_HUB_OVER_CURRENT	1
+
+#define HUB_FEATURE_PORT_CONNECTION	0
+#define HUB_FEATURE_PORT_ENABLE		1
+#define HUB_FEATURE_PORT_SUSPEND	2
+#define HUB_FEATURE_PORT_OVER_CURRENT	3
+#define HUB_FEATURE_PORT_RESET		4
+#define HUB_FEATURE_PORT_POWER		8
+#define HUB_FEATURE_PORT_LOW_SPEED	9
+#define HUB_FEATURE_C_PORT_CONNECTION	16
+#define HUB_FEATURE_C_PORT_ENABLE	17
+#define HUB_FEATURE_C_PORT_SUSPEND	18
+#define HUB_FEATURE_C_PORT_OVER_CURRENT	19
+#define HUB_FEATURE_C_PORT_RESET	20
+#define HUB_FEATURE_PORT_TEST		21
+#define HUB_FEATURE_PORT_INDICATOR	22
+
+// Additional Error Codes
+#define HUB_ERROR_PORT_HAS_BEEN_RESET			0xb1
+
+// Hub Port Status Bitmasks 
+#define USB_HUB_PORT_STATUS_PORT_CONNECTION		0x0001
+#define USB_HUB_PORT_STATUS_PORT_ENABLE			0x0002
+#define USB_HUB_PORT_STATUS_PORT_SUSPEND			0x0004
+#define USB_HUB_PORT_STATUS_PORT_OVER_CURRENT		0x0008
+#define USB_HUB_PORT_STATUS_PORT_RESET			0x0010
+#define USB_HUB_PORT_STATUS_PORT_POWER			0x0100
+#define USB_HUB_PORT_STATUS_PORT_LOW_SPEED		0x0200
+#define USB_HUB_PORT_STATUS_PORT_HIGH_SPEED		0x0400
+#define USB_HUB_PORT_STATUS_PORT_TEST			0x0800
+#define USB_HUB_PORT_STATUS_PORT_INDICATOR		0x1000
+
+// Bit mask to check for DISABLED state in HubEvent::bmStatus field 
+#define USB_HUB_PORT_STATE_CHECK_DISABLED	(USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_SUSPEND)
+
+// Hub Port States
+#define USB_HUB_PORT_STATE_DISABLED		(USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION)
+
+// Hub Port Events
+#define USB_HUB_PORT_EVENT_CONNECT		(((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION)	<< 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION)
+#define USB_HUB_PORT_EVENT_DISCONNECT		(((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION)	<< 16) | USB_HUB_PORT_STATUS_PORT_POWER)
+#define USB_HUB_PORT_EVENT_RESET_COMPLETE	(((0UL | USB_HUB_PORT_STATUS_PORT_RESET) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION)
+
+#define USB_HUB_PORT_EVENT_LS_CONNECT		(((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION)	<< 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
+#define USB_HUB_PORT_EVENT_LS_RESET_COMPLETE	(((0UL | USB_HUB_PORT_STATUS_PORT_RESET)		<< 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
+#define USB_HUB_PORT_EVENT_LS_PORT_ENABLED	(((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_ENABLE) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
+
+typedef struct {
+  uint8_t bDescLength;		// descriptor length
+  uint8_t bDescriptorType;	// descriptor type
+  uint8_t bNbrPorts;		// number of ports a hub equiped with
+  
+  struct {
+    uint16_t LogPwrSwitchMode	     : 2;
+    uint16_t CompoundDevice	     : 1;
+    uint16_t OverCurrentProtectMode  : 2;
+    uint16_t TTThinkTime	     : 2;
+    uint16_t PortIndicatorsSupported : 1;
+    uint16_t Reserved		     : 8;
+  } __attribute__((packed));
+  
+  uint8_t bPwrOn2PwrGood;
+  uint8_t bHubContrCurrent;
+} __attribute__((packed)) usb_hub_descriptor_t;
+
+typedef struct {
+  union {
+    struct {
+      uint16_t bmStatus;	// port status bits
+      uint16_t bmChange;	// port status change bits
+    } __attribute__((packed));
+    uint32_t bmEvent;
+    uint8_t  evtBuff[4];
+  } __attribute__((packed));
+}__attribute__((packed)) hub_event_t;
+
+// interface to usb core
+extern const usb_device_class_config_t usb_hub_class;
+
+#endif // HUB_H
Index: firmware/usb/mii.h
===================================================================
--- firmware/usb/mii.h	(nonexistent)
+++ firmware/usb/mii.h	(revision 269)
@@ -0,0 +1,65 @@
+#ifndef MII_H
+#define MII_H
+
+/* Generic MII registers. */
+#define MII_BMCR                0x00    /* Basic mode control register */
+#define MII_BMSR                0x01    /* Basic mode status register  */
+#define MII_PHYSID1             0x02    /* PHYS ID 1                   */
+#define MII_PHYSID2             0x03    /* PHYS ID 2                   */
+#define MII_ADVERTISE           0x04    /* Advertisement control reg   */
+
+/* Basic mode control register. */
+#define BMCR_RESV               0x003f  /* Unused...                   */
+#define BMCR_SPEED1000          0x0040  /* MSB of Speed (1000)         */
+#define BMCR_CTST               0x0080  /* Collision test              */
+#define BMCR_FULLDPLX           0x0100  /* Full duplex                 */
+#define BMCR_ANRESTART          0x0200  /* Auto negotiation restart    */
+#define BMCR_ISOLATE            0x0400  /* Disconnect DP83840 from MII */
+#define BMCR_PDOWN              0x0800  /* Powerdown the DP83840       */
+#define BMCR_ANENABLE           0x1000  /* Enable auto negotiation     */
+#define BMCR_SPEED100           0x2000  /* Select 100Mbps              */
+#define BMCR_LOOPBACK           0x4000  /* TXD loopback bits           */
+#define BMCR_RESET              0x8000  /* Reset the DP83840           */
+
+/* Basic mode status register. */
+#define BMSR_ERCAP              0x0001  /* Ext-reg capability          */
+#define BMSR_JCD                0x0002  /* Jabber detected             */
+#define BMSR_LSTATUS            0x0004  /* Link status                 */
+#define BMSR_ANEGCAPABLE        0x0008  /* Able to do auto-negotiation */
+#define BMSR_RFAULT             0x0010  /* Remote fault detected       */
+#define BMSR_ANEGCOMPLETE       0x0020  /* Auto-negotiation complete   */
+#define BMSR_RESV               0x00c0  /* Unused...                   */
+#define BMSR_ESTATEN            0x0100  /* Extended Status in R15 */
+#define BMSR_100HALF2           0x0200  /* Can do 100BASE-T2 HDX */
+#define BMSR_100FULL2           0x0400  /* Can do 100BASE-T2 FDX */
+#define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
+#define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
+#define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL            0x4000  /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4           0x8000  /* Can do 100mbps, 4k packets  */
+
+/* Advertisement control register. */
+#define ADVERTISE_SLCT          0x001f  /* Selector bits               */
+#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_1000XFULL     0x0020  /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_1000XHALF     0x0040  /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE    0x0080  /* Try for 1000BASE-X pause    */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100  /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */
+#define ADVERTISE_PAUSE_CAP     0x0400  /* Try for pause               */
+#define ADVERTISE_PAUSE_ASYM    0x0800  /* Try for asymetric pause     */
+#define ADVERTISE_RESV          0x1000  /* Unused...                   */
+#define ADVERTISE_RFAULT        0x2000  /* Say we can detect faults    */
+#define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
+#define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
+
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+                        ADVERTISE_CSMA)
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+                       ADVERTISE_100HALF | ADVERTISE_100FULL)
+
+#endif // MII_H
Index: firmware/usb/timer.c
===================================================================
--- firmware/usb/timer.c	(nonexistent)
+++ firmware/usb/timer.c	(revision 269)
@@ -0,0 +1,19 @@
+#include "timer.h"
+
+// this is a 32 bit counter which overflows after 2^32 milliseconds
+// -> after 46 days
+
+void wait_us(int unsigned num);
+
+void timer_init() {
+	// TODO - set zpu to 0...
+}
+
+msec_t timer_get_msec() {
+	return 0; // TODO - read from ZPU
+}
+
+void timer_delay_msec(msec_t t) {
+	int y = t;
+	wait_us(y*1000);
+}
Index: firmware/usb/timer.h
===================================================================
--- firmware/usb/timer.h	(nonexistent)
+++ firmware/usb/timer.h	(revision 269)
@@ -0,0 +1,13 @@
+// interface between USB timer and minimig timer
+
+#ifndef TIMER_H
+#define TIMER_H
+
+#include <inttypes.h>
+typedef uint32_t msec_t;
+
+void timer_init();
+msec_t timer_get_msec();
+void timer_delay_msec(msec_t t);
+
+#endif // TIMER_H
Index: firmware/usb/usb.c
===================================================================
--- firmware/usb/usb.c	(nonexistent)
+++ firmware/usb/usb.c	(revision 269)
@@ -0,0 +1,718 @@
+#include <stdio.h>
+
+#include "timer.h"
+#include "usb.h"
+#include "usbhostslave.h"
+#include "debug.h"
+
+static uint8_t usb_task_state;
+static uint8_t bmHubPre;
+
+#define tokSETUP  0x10  // HS=0, ISO=0, OUTNIN=0, SETUP=1
+#define tokIN     0x00  // HS=0, ISO=0, OUTNIN=0, SETUP=0
+#define tokOUT    0x20  // HS=0, ISO=0, OUTNIN=1, SETUP=0
+#define tokINHS   0x80  // HS=1, ISO=0, OUTNIN=0, SETUP=0
+#define tokOUTHS  0xA0  // HS=1, ISO=0, OUTNIN=1, SETUP=0 
+#define tokISOIN  0x40  // HS=0, ISO=1, OUTNIN=0, SETUP=0
+#define tokISOOUT 0x60  // HS=0, ISO=1, OUTNIN=1, SETUP=0
+
+static uint8_t outType;
+static uint8_t controlAdj;
+
+static usb_device_t dev[USB_NUMDEVICES];
+
+void usb_reset_state() {
+  puts(__FUNCTION__);
+  bmHubPre	 = 0;
+}
+
+usb_device_t *usb_get_devices() {
+  return dev;
+}
+
+void usb_init() {
+  puts(__FUNCTION__);
+
+  // MWW max3421e_init();   // init underlaying hardware layer
+  usbhostslave[OHS900_HOSTSLAVECTLREG] = OHS900_HSCTLREG_RESET_CORE;
+  timer_delay_msec(1);
+  usbhostslave[OHS900_TXLINECTLREG] = 0;
+  usbhostslave[OHS900_HOSTSLAVECTLREG] = OHS900_HS_CTL_INIT;
+  usbhostslave[OHS900_SOFENREG] = 0;
+  usbhostslave[OHS900_IRQ_ENABLE] = 0;
+
+  usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; 
+
+  outType = 0;
+  controlAdj = 0;
+
+  uint8_t i;
+  for(i=0;i<USB_NUMDEVICES;i++)
+    dev[i].bAddress = 0;
+
+  usb_reset_state();
+}
+
+uint8_t usb_set_address(usb_device_t *dev, ep_t *ep, 
+			uint16_t *nak_limit) {
+  //  iprintf("  %s(addr=%x, ep=%d)\n", __FUNCTION__, addr, ep);
+  *nak_limit = (1UL << ( ( ep->bmNakPower > USB_NAK_MAX_POWER ) ? 
+			 USB_NAK_MAX_POWER : ep->bmNakPower) ) - 1;
+  
+  /*
+    iprintf("\nAddress: %x\n", addr);
+    iprintf(" EP: %d\n", ep);
+    iprintf(" NAK Power: %d\n",(*ppep)->bmNakPower);
+    iprintf(" NAK Limit: %d\n", nak_limit);
+  */
+  
+  usbhostslave[OHS900_TXADDRREG] = dev->bAddress;
+
+  controlAdj = 0;
+  if (bmHubPre)
+  {
+    controlAdj = OHS900_HCTLMASK_PREAMBLE_EN;
+  }
+  
+  /* MWW (sets address and messes with mode - I plan to change mode on connect only...)
+  max3421e_write_u08( MAX3421E_PERADDR, dev->bAddress); // set peripheral address
+  uint8_t mode = max3421e_read_u08( MAX3421E_MODE );
+  
+  // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, 
+  // reset them otherwise
+  max3421e_write_u08( MAX3421E_MODE, 
+		      (dev->lowspeed) ? mode |   MAX3421E_LOWSPEED | bmHubPre : 
+		                      mode & ~(MAX3421E_HUBPRE | MAX3421E_LOWSPEED)); 
+  */
+  
+  return 0;
+}
+
+/* dispatch usb packet. Assumes peripheral address is set and relevant */
+/* buffer is loaded/empty */
+/* If NAK, tries to re-send up to nak_limit times  */
+/* If nak_limit == 0, do not count NAKs, exit after timeout */
+/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
+/* return codes 0x00-0x0f are HRSLT (0x00 being success), 0xff means timeout */
+uint8_t usb_dispatchPktWithData( uint8_t token, uint8_t ep, uint16_t nak_limit, uint8_t * data, uint16_t bytes_tosend, uint8_t * sndToggle) {
+  //  iprintf("  %s(token=%x, ep=%d, nak_limit=%d)\n", 
+  //	  __FUNCTION__, token, ep, nak_limit);
+  unsigned long timeout = timer_get_msec() + USB_XFER_TIMEOUT;
+  uint8_t tmpdata;   
+  uint8_t rcode = 0x00;
+  uint8_t retry_count = 0;
+  uint16_t nak_count = 0;
+	
+  while( timeout > timer_get_msec() )  {
+    //MWW max3421e_write_u08( MAX3421E_HXFR, ( token|ep )); //launch the transfer
+    usbhostslave[OHS900_TXENDPREG] = ep;
+    uint8_t control = OHS900_HCTLMASK_TRANS_REQ|OHS900_HCTLMASK_SOF_SYNC|controlAdj;
+    uint8_t line_control = 0;
+    uint8_t out = 0;
+    switch (token)
+    {
+    case tokSETUP:
+        usbhostslave[OHS900_TXTRANSTYPEREG] = OHS900_SETUP;
+        break;
+    case tokIN:
+        usbhostslave[OHS900_TXTRANSTYPEREG] = OHS900_IN;
+        break;
+    case tokOUT:
+        usbhostslave[OHS900_TXTRANSTYPEREG] = *sndToggle ? OHS900_OUT_DATA1 : OHS900_OUT_DATA0;
+        out = 1;
+        break;
+    case tokINHS:
+        usbhostslave[OHS900_TXTRANSTYPEREG] = OHS900_IN;
+	line_control = OHS900_TXLCTL_MASK_FSPD;
+        break;
+    case tokOUTHS:
+        usbhostslave[OHS900_TXTRANSTYPEREG] = *sndToggle ? OHS900_OUT_DATA1 : OHS900_OUT_DATA0;
+        out = 1;
+	line_control = OHS900_TXLCTL_MASK_FSPD;
+        break;
+    case tokISOIN:
+        usbhostslave[OHS900_TXTRANSTYPEREG] = OHS900_IN;
+        control |= OHS900_HCTLMASK_ISO_EN;
+        break;
+    case tokISOOUT:
+        usbhostslave[OHS900_TXTRANSTYPEREG] = *sndToggle ? OHS900_OUT_DATA1 : OHS900_OUT_DATA0;
+        out = 1;
+        control |= OHS900_HCTLMASK_ISO_EN;
+        break;
+    default:
+        return 0xff;
+        break;
+    }
+
+    if (out)
+    {
+      //set toggle value
+      // MWW: max3421e_write_u08(MAX3421E_HCTL, 
+      //    (pep->bmSndToggle) ? MAX3421E_SNDTOG1 : MAX3421E_SNDTOG0 );
+      *sndToggle = !*sndToggle; // Correct place to flip Original code did this outside loop but that looks wrong - we should send 0/1/0/1 etc.
+  
+      //filling output FIFO
+      //MWW max3421e_write( MAX3421E_SNDFIFO, bytes_tosend, data );
+      uint16_t toSend = bytes_tosend;
+      uint8_t * dataToSend = data;
+      while (--toSend)
+      {
+        usbhostslave[OHS900_HOST_TXFIFO_DATA] = *dataToSend++;
+      }
+      
+      //set number of bytes
+      //MWW max3421e_write_u08( MAX3421E_SNDBC, bytes_tosend );
+    }
+
+    usbhostslave[OHS900_TXLINECTLREG] = line_control;
+    usbhostslave[OHS900_HOST_TX_CTLREG] = control;
+
+    rcode = USB_ERROR_TRANSFER_TIMEOUT;   
+    
+    // wait for transfer completion
+    while( timer_get_msec() < timeout )	{
+      //tmpdata = max3421e_read_u08( MAX3421E_HIRQ );
+      // MWW
+      tmpdata = usbhostslave[OHS900_IRQ_STATUS];
+
+      if( tmpdata & OHS900_INTMASK_TRANS_DONE ) {
+	//clear the interrupt
+	//max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ );
+	// MWW
+	usbhostslave[OHS900_IRQ_STATUS] = OHS900_INTMASK_TRANS_DONE;
+	rcode = 0x00;
+	break;
+      }
+    }
+
+    if( rcode != 0x00 )                 //exit if timeout
+      return( rcode );
+
+    //analyze transfer result
+    //rcode = ( max3421e_read_u08( MAX3421E_HRSL ) & 0x0f );
+    rcode = usbhostslave[OHS900_HRXSTATREG];
+
+    if (rcode&OHS900_STATMASK_NAK_RXED)
+    {
+      nak_count++;
+      if( nak_limit && ( nak_count == nak_limit ))
+	return( rcode );
+    }
+    else if (rcode&OHS900_STATMASK_RX_TMOUT)
+    {
+      retry_count++;
+      if( retry_count == USB_RETRY_LIMIT )
+	return( rcode );
+    }
+    else if (rcode&(OHS900_STATMASK_CRC_ERROR|OHS900_STATMASK_BS_ERROR|OHS900_STATMASK_STALL_RXED))
+    {
+      return( rcode );
+    }
+  }
+
+  return( rcode&~(OHS900_STATMASK_ACK_RXED|OHS900_STATMASK_DATA_SEQ));
+}
+
+uint8_t usb_dispatchPkt( uint8_t token, uint8_t ep, uint16_t nak_limit)
+{
+  uint8_t dummy = 0;
+  return usb_dispatchPktWithData(token,ep,nak_limit,0,0,&dummy);
+}
+
+uint8_t usb_InTransfer(ep_t *pep, uint16_t nak_limit, 
+		       uint16_t *nbytesptr, uint8_t* data) {
+  uint8_t rcode = 0;
+  uint8_t pktsize;
+  uint8_t stat;
+  
+  uint16_t	nbytes		= *nbytesptr;
+  uint8_t	maxpktsize	= pep->maxPktSize; 
+
+  *nbytesptr = 0;
+  // set toggle value
+  // MWW max3421e_write_u08( MAX3421E_HCTL, 
+  //	      (pep->bmRcvToggle) ? MAX3421E_RCVTOG1 : MAX3421E_RCVTOG0 );
+  // MWW: TODO on receipt looks like hardware takes cart of DATA0/DATA1? Perhaps I'm meant to check DATA_SEQUENCE_BIT...
+  
+  // use a 'return' to exit this loop
+  while( 1 ) { 
+    //IN packet to EP-'endpoint'. Function takes care of NAKS.
+    rcode = usb_dispatchPkt( tokIN, pep->epAddr, nak_limit );
+      
+    //should be 0, indicating ACK. Else return error code.
+    if( rcode )
+      return( rcode );
+    
+    /* check for RCVDAVIRQ and generate error if not present */ 
+    /* the only case when absense of RCVDAVIRQ makes sense is when */
+    /* toggle error occured. Need to add handling for that */
+  // MWW if(( max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_RCVDAVIRQ ) == 0 ) 
+  //    return ( 0xf0 );                            //receive error
+    stat = usbhostslave[OHS900_HRXSTATREG];
+    if (pep->bmRcvToggle != (!!(stat&OHS900_STATMASK_DATA_SEQ))) // Check data0/data1
+        return (0xf0);
+    
+    // MWW pktsize = max3421e_read_u08( MAX3421E_RCVBC ); // number of received bytes
+    pktsize = usbhostslave[OHS900_RXFIFOCNTLSBREG];
+        
+    int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
+
+    if (mem_left < 0)
+      mem_left = 0;
+
+    //MWW data = max3421e_read(MAX3421E_RCVFIFO, 
+    //		 ((pktsize > mem_left) ? mem_left : pktsize), data );
+    int16_t toRead = (pktsize > mem_left) ? mem_left : pktsize;
+    while (--toRead)
+    {
+      *data++ = usbhostslave[OHS900_HOST_RXFIFO_DATA];
+    }
+    
+    // Clear the IRQ & free the buffer
+    //MWW - already done? max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_RCVDAVIRQ );
+    *nbytesptr += pktsize;							
+    // add this packet's byte count to total transfer length
+    /* The transfer is complete under two conditions:           */
+    /* 1. The device sent a short packet (L.T. maxPacketSize)   */
+    /* 2. 'nbytes' have been transferred.                       */
+
+    // have we transferred 'nbytes' bytes?
+    if (( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) {     
+      // Save toggle value
+      //MWW pep->bmRcvToggle = (( max3421e_read_u08( MAX3421E_HRSL ) & 
+	//		    MAX3421E_RCVTOGRD )) ? 1 : 0;
+
+      pep->bmRcvToggle = (!(stat&OHS900_STATMASK_DATA_SEQ)); // expect other way next time
+      
+      return 0;
+    }
+  }
+}
+
+/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets */
+/* if necessary. Transfers 'nbytes' bytes. Keep sending INs and writes data to memory area */
+/* pointed by 'data' */
+/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, */
+/* fe USB xfer timeout */
+uint8_t usb_in_transfer( usb_device_t *dev, ep_t *ep, uint16_t *nbytesptr, uint8_t* data) {
+  uint16_t nak_limit = 0;
+
+  uint8_t rcode = usb_set_address(dev, ep, &nak_limit);
+  if (rcode) return rcode;
+
+  return usb_InTransfer(ep, nak_limit, nbytesptr, data);
+}
+
+uint8_t usb_OutTransfer(ep_t *pep, uint16_t nak_limit, 
+			uint16_t nbytes, uint8_t *data) {
+  //  iprintf("%s(%d)\n", __FUNCTION__, nbytes);
+
+  uint8_t rcode = 0;
+  uint16_t bytes_tosend;
+  uint16_t bytes_left = nbytes;
+  
+  uint8_t maxpktsize = pep->maxPktSize; 
+ 
+  if (maxpktsize < 1 || maxpktsize > 64)
+    return USB_ERROR_INVALID_MAX_PKT_SIZE;
+ 
+  //unsigned long timeout = timer_get_msec() + USB_XFER_TIMEOUT;
+  
+  while( bytes_left ) {
+    bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
+
+    uint8_t sndToggle = pep->bmSndToggle;
+    rcode = usb_dispatchPktWithData( tokOUT, pep->epAddr, nak_limit, data, bytes_tosend, &sndToggle );
+    pep->bmSndToggle = sndToggle!=0;
+    if (rcode)
+    {
+       return(rcode);
+    }
+
+/*    MWW (this was custom due to bug in chip I think) // dispatch packet
+    max3421e_write_u08( MAX3421E_HXFR, ( tokOUT | pep->epAddr ));
+
+    //wait for the completion IRQ
+    while(!(max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_HXFRDNIRQ ));
+    max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ );    //clear IRQ
+    rcode = max3421e_read_u08( MAX3421E_HRSL ) & 0x0f;
+    
+    while( rcode && ( timeout > timer_get_msec())) {
+      switch( rcode ) {
+      case hrNAK:
+	nak_count ++;
+	if( nak_limit && ( nak_count == nak_limit )) 
+	  return( rcode );
+	break;
+      case hrTIMEOUT:
+	retry_count ++;
+	if( retry_count == USB_RETRY_LIMIT ) 
+	  return( rcode );
+	break;
+      default:
+	return( rcode );
+      }
+      
+      // process NAK according to Host out NAK bug 
+      max3421e_write_u08( MAX3421E_SNDBC, 0 );
+      max3421e_write_u08( MAX3421E_SNDFIFO, *data );
+      max3421e_write_u08( MAX3421E_SNDBC, bytes_tosend );
+
+      // dispatch packet
+      max3421e_write_u08( MAX3421E_HXFR, ( tokOUT | pep->epAddr ));
+
+      // wait for the completion IRQ
+      while(!(max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_HXFRDNIRQ ));
+      max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ );      // clear IRQ
+      rcode = ( max3421e_read_u08( MAX3421E_HRSL ) & 0x0f );
+    }//while( rcode && .... */
+    bytes_left -= bytes_tosend;
+    data += bytes_tosend;
+  }//while( bytes_left...
+
+  //update toggle
+  // MWW: pep->bmSndToggle = ( max3421e_read_u08( MAX3421E_HRSL ) & MAX3421E_SNDTOGRD ) ? 1 : 0;
+
+  return (rcode);    //should be 0 in all cases
+}
+
+/* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
+/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer   */
+/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL                       */
+uint8_t usb_out_transfer(usb_device_t *dev, ep_t *ep, uint16_t nbytes, uint8_t* data ) {
+  uint16_t nak_limit = 0;
+
+  uint8_t rcode = usb_set_address(dev, ep, &nak_limit);
+  if (rcode) return rcode;
+
+  return usb_OutTransfer(ep, nak_limit, nbytes, data);
+}
+
+/* Control transfer. Sets address, endpoint, fills control packet */
+/* with necessary data, dispatches control packet, and initiates */
+/* bulk IN transfer, depending on request. Actual requests are defined */
+/* as inlines                   */
+/* return codes:                */
+/* 00       =   success         */
+/* 01-0f    =   non-zero HRSLT  */
+
+uint8_t usb_ctrl_req(usb_device_t *dev, uint8_t bmReqType, 
+		    uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, 
+		    uint16_t wInd, uint16_t nbytes, uint8_t* dataptr) {
+  //  iprintf("%s(addr=%x, len=%d, ptr=%p)\n", __FUNCTION__,
+  //	  dev->bAddress, nbytes, dataptr);
+  bool direction = false;     //request direction, IN or OUT
+  uint8_t rcode;   
+  setup_pkt_t setup_pkt;
+  uint16_t	nak_limit;
+  
+  rcode = usb_set_address(dev, &(dev->ep0), &nak_limit);
+  if (rcode)
+    return rcode;
+  
+  direction = (( bmReqType & 0x80 ) > 0);
+
+  /* fill in setup packet */
+  setup_pkt.ReqType_u.bmRequestType	= bmReqType;
+  setup_pkt.bRequest			= bRequest;
+  setup_pkt.wVal_u.wValueLo		= wValLo;
+  setup_pkt.wVal_u.wValueHi		= wValHi;
+  setup_pkt.wIndex			= wInd;
+  setup_pkt.wLength			= nbytes;
+  
+  // transfer to setup packet FIFO
+  /* MWW max3421e_write(MAX3421E_SUDFIFO, sizeof(setup_pkt_t), (uint8_t*)&setup_pkt );
+  
+  rcode = usb_dispatchPkt( tokSETUP, 0, nak_limit );     //dispatch packet
+  */
+  uint8_t dummy = 0;
+  rcode = usb_dispatchPktWithData( tokSETUP, 0, nak_limit, (uint8_t*)&setup_pkt,  sizeof(setup_pkt_t), &dummy);
+  if( rcode )		//return HRSLT if not zero
+    return( rcode );
+  
+  // data stage, if present
+  if( dataptr != NULL )	{
+    if( direction ) { //IN transfer
+      dev->ep0.bmRcvToggle = 1;
+      rcode = usb_InTransfer( &(dev->ep0), nak_limit, &nbytes, dataptr );
+    } else { //OUT transfer
+      dev->ep0.bmSndToggle = 1;
+      rcode = usb_OutTransfer( &(dev->ep0), nak_limit, nbytes, dataptr );
+    }    
+
+    //return error
+    if( rcode )	return( rcode );
+  }
+
+  // Status stage
+  // GET if direction
+  return usb_dispatchPkt( (direction) ? tokOUTHS : tokINHS, 0, nak_limit );
+}
+
+// list of supported device classes
+static const usb_device_class_config_t *class_list[] = {
+  &usb_hub_class,
+  &usb_hid_class,
+  NULL
+};
+
+uint8_t usb_configure(uint8_t parent, uint8_t port, bool lowspeed) {
+  uint8_t rcode = 0;
+  iprintf("%s(parent=%x port=%d lowspeed=%d)\n", __FUNCTION__, parent, port, lowspeed);
+
+  // find an empty device entry
+  uint8_t i;
+  for(i=0; i<USB_NUMDEVICES && dev[i].bAddress; i++);
+
+  if(i < USB_NUMDEVICES) {
+    iprintf("using free entry at %d\n", i);
+
+    usb_device_t *d = dev+i;
+
+    // setup generic info
+    d->bAddress = 0;
+    d->parent = parent;
+    d->lowspeed = lowspeed;
+    d->port = port;
+    d->class = NULL;
+
+    // setup endpoint 0
+    d->ep0.epAddr	= 0;
+    d->ep0.maxPktSize	= 8;
+    d->ep0.epAttribs	= 0;
+    d->ep0.bmNakPower	= USB_NAK_MAX_POWER;
+
+    // --- enumerate device ---
+
+    // Assign new address to the device
+    // (address is simply the number of the free slot + 1)
+    iprintf("Setting addr %x\n", i+1);
+    rcode = usb_set_addr(d, i+1);
+    if(rcode) {
+      puts("failed to assign address");
+      return rcode;
+    }
+
+    // try to connect device to one of the supported classes
+    uint8_t c;
+    for(c=0;class_list[c];c++) {
+      iprintf("trying to init class %d\n", c);
+      rcode = class_list[c]->init(d);
+
+      if (!rcode) {
+	d->class = class_list[c];
+
+	puts(" -> accepted :-)");
+	// ok, device accepted by class
+
+	return 0;
+      }
+  
+      puts(" -> not accepted :-(");
+    }
+  } else
+    iprintf("no more free entries\n");
+
+  iprintf("unsupported device\n");
+  return 0;
+}
+
+void usb_poll() {
+  static msec_t delay = 0;
+  bool lowspeed = false;
+
+  // poll underlaying hardware layer
+  //MWW tmpdata = max3421e_poll();
+  uint8_t conState = usbhostslave[OHS900_RXCONNSTATEREG];
+  switch(conState)
+  {
+  case OHS900_DISCONNECT_STATE:
+    if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) 
+      usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
+    break;
+  case OHS900_LS_CONN_STATE:
+    lowspeed = true;
+    // intentional fall-through ...
+  case OHS900_FS_CONN_STATE:
+    if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
+      delay = timer_get_msec() + USB_SETTLE_DELAY;
+      usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
+    }
+    break;
+  }
+
+  /* modify USB task state if Vbus changed */
+/*  switch( tmpdata )  {
+
+    // illegal state
+  case MAX3421E_STATE_SE1:   
+    usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
+    lowspeed = false;
+    break;
+
+    // disconnected
+  case MAX3421E_STATE_SE0:
+    if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) 
+      usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
+    lowspeed = false;
+    break;
+
+    // attached
+  case MAX3421E_STATE_LSHOST:
+    lowspeed = true;
+    // intentional fall-through ...
+
+  case MAX3421E_STATE_FSHOST:
+    if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
+      delay = timer_get_msec() + USB_SETTLE_DELAY;
+      usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
+    }
+    break;
+  }*/
+
+  // max poll 1ms
+  static msec_t poll=0;
+  if(timer_get_msec() > poll) {
+    poll = timer_get_msec()+1;
+
+    // poll all configured devices
+    uint8_t i;
+    for (i=0; i<USB_NUMDEVICES; i++)
+      if(dev[i].bAddress && dev[i].class && dev[i].class->poll)
+	dev[i].class->poll(dev+i);
+	// MWW (rcode unused error) rcode = dev[i].class->poll(dev+i);
+    
+    switch( usb_task_state ) {
+    case USB_DETACHED_SUBSTATE_INITIALIZE:
+      usb_reset_state();
+      
+      // just remove everything ...
+      for (i=0; i<USB_NUMDEVICES; i++) {
+	if(dev[i].bAddress && dev[i].class) {
+	  dev[i].class->release(dev+i);
+	  // MWW (rcode unused error) rcode = dev[i].class->release(dev+i);
+	  dev[i].bAddress = 0;
+	}
+      }
+    
+      usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
+      break;
+      
+    case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE:
+    case USB_DETACHED_SUBSTATE_ILLEGAL:
+      break;
+      
+    case USB_ATTACHED_SUBSTATE_SETTLE:              //settle time for just attached device            
+      if( delay < timer_get_msec() ) 
+	usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
+      break;
+      
+    case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
+      // MWW max3421e_write_u08( MAX3421E_HCTL, MAX3421E_BUSRST );	             // issue bus reset
+      usbhostslave[OHS900_SOFENREG] = 0;
+      usbhostslave[OHS900_TXLINECTLREG] = OHS900_TXLCTL_MASK_SE0;
+      usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
+      delay = timer_get_msec() + 50; // send reset for 50msec
+      break;
+      
+    case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
+      if( delay < timer_get_msec() )
+      {
+        usbhostslave[OHS900_SOFENREG] = OHS900_MASK_SOF_ENA;
+        usbhostslave[OHS900_TXLINECTLREG] = OHS900_TXLCTL_MASK_NORMAL;
+        usbhostslave[OHS900_IRQ_STATUS] = OHS900_INTMASK_SOFINTR;
+  
+        /*if(( !max3421e_read_u08( MAX3421E_HCTL ) & MAX3421E_BUSRST ) ) {
+  	tmpdata = max3421e_read_u08( MAX3421E_MODE ) | MAX3421E_SOFKAENAB;   // start SOF generation
+  	max3421e_write_u08( MAX3421E_MODE, tmpdata );
+        }*/
+        delay = timer_get_msec() + 20;                           //20ms wait after reset per USB spec
+        usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
+      }
+      break;
+      
+    case USB_ATTACHED_SUBSTATE_WAIT_SOF:  //todo: change check order
+      // MWW if( max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_FRAMEIRQ ) { //when first SOF received we can continue
+      if (usbhostslave[OHS900_IRQ_STATUS]&OHS900_INTMASK_SOFINTR)
+      {
+        usbhostslave[OHS900_IRQ_STATUS] = OHS900_INTMASK_SOFINTR;
+	if( delay < timer_get_msec() ) //20ms passed
+	  usb_task_state = USB_STATE_CONFIGURING;
+      }
+      break;
+      
+    case USB_STATE_CONFIGURING:
+      // configure root device
+      usb_configure(0, 0, lowspeed);
+      usb_task_state = USB_STATE_RUNNING;
+    break;
+    
+    case USB_STATE_RUNNING:
+      break;
+    }
+  }
+}
+
+uint8_t usb_release_device(uint8_t parent, uint8_t port) {
+  iprintf("%s(parent=%x, port=%d\n", __FUNCTION__, parent, port);
+
+  uint8_t i;
+  for(i=0; i<USB_NUMDEVICES; i++) {
+    if(dev[i].bAddress && dev[i].parent == parent && dev[i].port == port) {
+      iprintf("  -> device with address %x\n", dev[i].bAddress);
+
+      // check if this is a hub (parent of some other device)
+      // and release its kids first
+      uint8_t j;
+      for(j=0; j<USB_NUMDEVICES; j++) {
+	if(dev[j].parent == dev[i].bAddress)
+	  usb_release_device(dev[i].bAddress, dev[j].port);
+      }
+      
+      uint8_t rcode = 0;
+      if(dev[i].class)
+	rcode = dev[i].class->release(dev+i);
+
+      dev[i].bAddress = 0;
+      return rcode;	
+    }
+  }
+
+  // this should never happen ...
+  return 0;
+}
+
+uint8_t usb_get_dev_descr( usb_device_t *dev, uint16_t nbytes, usb_device_descriptor_t* p )  {
+  return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 
+	       0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, (uint8_t*)p));
+}
+
+//get configuration descriptor  
+uint8_t usb_get_conf_descr( usb_device_t *dev, uint16_t nbytes, 
+			    uint8_t conf, usb_configuration_descriptor_t* p )  {
+  return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 
+	       conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, (uint8_t*)p));
+}
+
+uint8_t usb_set_addr( usb_device_t *dev, uint8_t newaddr )  {
+  iprintf("%s(new=%x)\n", __FUNCTION__, newaddr);
+  
+  uint8_t rcode = usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 
+				0x00, 0x0000, 0x0000, NULL);
+  if(!rcode) dev->bAddress = newaddr;
+  return rcode;
+}
+
+//set configuration
+uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value )  {
+  return( usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_CONFIGURATION,
+			conf_value, 0x00, 0x0000, 0x0000, NULL));
+}
+
+void usb_SetHubPreMask() { 
+  bmHubPre = 1; // MWW
+};
+
+void usb_ResetHubPreMask() { 
+  bmHubPre = 0; // MWW
+};
Index: firmware/usb/usb.h
===================================================================
--- firmware/usb/usb.h	(nonexistent)
+++ firmware/usb/usb.h	(revision 269)
@@ -0,0 +1,248 @@
+#ifndef USB_H
+#define USB_H
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+/* NAK powers. To save space in endpoint data structure, amount of retries */
+/* before giving up and returning 0x4 is stored in bmNakPower as a power of 2.*/
+/* The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
+#define USB_NAK_MAX_POWER 16	//NAK binary order maximum value
+#define USB_NAK_DEFAULT	  14	//default 16K-1 NAKs before giving up
+#define USB_NAK_NOWAIT	  1	//Single NAK stops transfer
+#define USB_NAK_NONAK	  0	//Do not count NAKs, stop retrying after USB Timeout
+
+typedef struct {
+  uint8_t epAddr;	// Endpoint address 
+  uint8_t maxPktSize;	// Maximum packet size
+  
+  union {
+    uint8_t epAttribs;
+    
+    struct {
+      // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
+      uint8_t bmSndToggle: 1;
+      // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
+      uint8_t bmRcvToggle: 1;
+      // Binary order for NAK_LIMIT value
+      uint8_t bmNakPower:  6;
+    };
+  };
+} ep_t;
+
+#define USB_NUMDEVICES 16      // number of supported USB devices
+
+/* Common setup data constant combinations  */
+#define USB_REQ_GET_DESCR     USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE     //get descriptor request type
+#define USB_REQ_SET           USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE     //set request type for all but 'set feature' and 'set interface'
+#define USB_REQ_CL_GET_INTF   USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE     //get interface request type
+
+#define USB_SETTLE_DELAY 200   // settle delay in milliseconds
+#define USB_XFER_TIMEOUT 5000  // USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
+#define USB_RETRY_LIMIT	3      // retry limit for a transfer
+
+/* USB state machine states */
+#define USB_STATE_MASK                                      0xf0
+
+#define USB_STATE_DETACHED                                  0x10
+#define USB_DETACHED_SUBSTATE_INITIALIZE                    0x11        
+#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE               0x12
+#define USB_DETACHED_SUBSTATE_ILLEGAL                       0x13
+#define USB_ATTACHED_SUBSTATE_SETTLE                        0x20
+#define USB_ATTACHED_SUBSTATE_RESET_DEVICE                  0x30    
+#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE           0x40
+#define USB_ATTACHED_SUBSTATE_WAIT_SOF                      0x50
+#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE    0x60
+#define USB_STATE_ADDRESSING                                0x70
+#define USB_STATE_CONFIGURING                               0x80
+#define USB_STATE_RUNNING                                   0x90
+
+/* USB Setup Packet Structure   */
+typedef struct {
+  union {                          // offset   description
+    uint8_t bmRequestType;         //   0      Bit-map of request type
+    struct {
+      uint8_t    recipient:  5;    //          Recipient of the request
+      uint8_t    type:       2;    //          Type of request
+      uint8_t    direction:  1;    //          Direction of data X-fer
+    } __attribute__((packed));
+  } __attribute__((packed)) ReqType_u;
+  uint8_t    bRequest;		   //   1      Request
+  union {
+    uint16_t    wValue;            //   2/3    Depends on bRequest
+    struct {
+      uint8_t    wValueLo;
+      uint8_t    wValueHi;
+    } __attribute__((packed));
+  }  __attribute__((packed)) wVal_u;
+  uint16_t    wIndex;              //   4      Depends on bRequest
+  uint16_t    wLength;             //   6      Depends on bRequest
+} __attribute__((packed)) setup_pkt_t;
+
+// Additional Error Codes
+#define USB_ERROR_INVALID_MAX_PKT_SIZE			    0xDA
+#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED           0xDB
+#define USB_ERROR_CONFIGURAION_SIZE_MISMATCH                0xDC
+#define USB_ERROR_TRANSFER_TIMEOUT			    0xFF
+
+struct usb_device_entry;
+
+typedef struct {
+  uint8_t (*init)(struct usb_device_entry *);
+  uint8_t (*release)(struct usb_device_entry *);
+  uint8_t (*poll)(struct usb_device_entry *);
+} usb_device_class_config_t;
+
+#include "hub.h"
+#include "hid.h"
+
+// entry used for list of connected devices
+typedef struct usb_device_entry {
+  const usb_device_class_config_t *class;  // pointer to class hadlers
+  ep_t ep0;                            // information about endpoint 0
+  uint8_t bAddress;	                   // device address
+  uint8_t parent;                          // parent device address
+  uint8_t port;
+  bool lowspeed;
+
+  union {
+    usb_hub_info_t hub_info;
+    usb_hid_info_t hid_info;
+  };
+} usb_device_t;
+
+#define USB_CLASS_USE_CLASS_INFO          0x00    // Use Class Info in the Interface Descriptors
+#define USB_CLASS_AUDIO                   0x01    // Audio
+#define USB_CLASS_COM_AND_CDC_CTRL        0x02    // Communications and CDC Control
+#define USB_CLASS_HID                     0x03    // HID
+#define USB_CLASS_PHYSICAL                0x05    // Physical
+#define USB_CLASS_IMAGE                   0x06    // Image
+#define USB_CLASS_PRINTER                 0x07    // Printer
+#define USB_CLASS_MASS_STORAGE            0x08    // Mass Storage
+#define USB_CLASS_HUB                     0x09    // Hub
+#define USB_CLASS_CDC_DATA                0x0a    // CDC-Data
+#define USB_CLASS_SMART_CARD              0x0b    // Smart-Card
+#define USB_CLASS_CONTENT_SECURITY        0x0d    // Content Security
+#define USB_CLASS_VIDEO                   0x0e    // Video
+#define USB_CLASS_PERSONAL_HEALTH         0x0f    // Personal Healthcare
+#define USB_CLASS_DIAGNOSTIC_DEVICE       0xdc    // Diagnostic Device
+#define USB_CLASS_WIRELESS_CTRL           0xe0    // Wireless Controller
+#define USB_CLASS_MISC                    0xef    // Miscellaneous
+#define USB_CLASS_APP_SPECIFIC            0xfe    // Application Specific
+#define USB_CLASS_VENDOR_SPECIFIC         0xff    // Vendor Specific
+
+/*******************************************************************************/
+/***                                                                         ***/
+/***                       USB chapter 9 structures                          ***/
+/***                                                                         ***/
+/*******************************************************************************/
+
+/* Device descriptor structure */
+typedef struct {
+  uint8_t  bLength;            // Length of this descriptor.
+  uint8_t  bDescriptorType;    // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
+  uint16_t bcdUSB;	       // USB Spec Release Number (BCD).
+  uint8_t  bDeviceClass;       // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
+  uint8_t  bDeviceSubClass;    // Subclass code (assigned by the USB-IF).
+  uint8_t  bDeviceProtocol;    // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
+  uint8_t  bMaxPacketSize0;    // Maximum packet size for endpoint 0.
+  uint16_t idVendor;	       // Vendor ID (assigned by the USB-IF).
+  uint16_t idProduct;	       // Product ID (assigned by the manufacturer).
+  uint16_t bcdDevice;	       // Device release number (BCD).
+  uint8_t  iManufacturer;      // Index of String Descriptor describing the manufacturer.
+  uint8_t  iProduct;           // Index of String Descriptor describing the product.
+  uint8_t  iSerialNumber;      // Index of String Descriptor with the device's serial number.
+  uint8_t  bNumConfigurations; // Number of possible configurations.
+} __attribute__((packed)) usb_device_descriptor_t;
+
+/* Configuration descriptor structure */
+typedef struct {
+  uint8_t bLength;             // Length of this descriptor.
+  uint8_t bDescriptorType;     // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
+  uint16_t wTotalLength;       // Total length of all descriptors for this configuration.
+  uint8_t bNumInterfaces;      // Number of interfaces in this configuration.
+  uint8_t bConfigurationValue; // Value of this configuration (1 based).
+  uint8_t iConfiguration;      // Index of String Descriptor describing the configuration.
+  uint8_t bmAttributes;        // Configuration characteristics.
+  uint8_t bMaxPower;           // Maximum power consumed by this configuration.
+} __attribute__((packed)) usb_configuration_descriptor_t;
+
+/* Interface descriptor structure */
+typedef struct {
+  uint8_t bLength;               // Length of this descriptor.
+  uint8_t bDescriptorType;       // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
+  uint8_t bInterfaceNumber;      // Number of this interface (0 based).
+  uint8_t bAlternateSetting;     // Value of this alternate interface setting.
+  uint8_t bNumEndpoints;         // Number of endpoints in this interface.
+  uint8_t bInterfaceClass;       // Class code (assigned by the USB-IF).  0xFF-Vendor specific.
+  uint8_t bInterfaceSubClass;    // Subclass code (assigned by the USB-IF).
+  uint8_t bInterfaceProtocol;    // Protocol code (assigned by the USB-IF).  0xFF-Vendor specific.
+  uint8_t iInterface;            // Index of String Descriptor describing the interface.
+} __attribute__((packed)) usb_interface_descriptor_t;
+
+/* Endpoint descriptor structure */
+typedef struct {
+  uint8_t bLength;               // Length of this descriptor.
+  uint8_t bDescriptorType;       // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
+  uint8_t bEndpointAddress;      // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
+  uint8_t bmAttributes;          // Endpoint transfer type.
+  uint8_t wMaxPacketSize[2];     // Maximum packet size.
+  uint8_t bInterval;             // Polling interval in frames.
+} __attribute__((packed)) usb_endpoint_descriptor_t;
+
+/* Standard Device Requests */
+#define USB_REQUEST_GET_STATUS                  0       // Standard Device Request - GET STATUS
+#define USB_REQUEST_CLEAR_FEATURE               1       // Standard Device Request - CLEAR FEATURE
+#define USB_REQUEST_SET_FEATURE                 3       // Standard Device Request - SET FEATURE
+#define USB_REQUEST_SET_ADDRESS                 5       // Standard Device Request - SET ADDRESS
+#define USB_REQUEST_GET_DESCRIPTOR              6       // Standard Device Request - GET DESCRIPTOR
+#define USB_REQUEST_SET_DESCRIPTOR              7       // Standard Device Request - SET DESCRIPTOR
+#define USB_REQUEST_GET_CONFIGURATION           8       // Standard Device Request - GET CONFIGURATION
+#define USB_REQUEST_SET_CONFIGURATION           9       // Standard Device Request - SET CONFIGURATION
+#define USB_REQUEST_GET_INTERFACE               10      // Standard Device Request - GET INTERFACE
+#define USB_REQUEST_SET_INTERFACE               11      // Standard Device Request - SET INTERFACE
+#define USB_REQUEST_SYNCH_FRAME                 12      // Standard Device Request - SYNCH FRAME
+
+#define USB_FEATURE_ENDPOINT_HALT               0       // CLEAR/SET FEATURE - Endpoint Halt
+#define USB_FEATURE_DEVICE_REMOTE_WAKEUP        1       // CLEAR/SET FEATURE - Device remote wake-up
+#define USB_FEATURE_TEST_MODE                   2       // CLEAR/SET FEATURE - Test mode
+
+/* Setup Data Constants */
+#define USB_SETUP_HOST_TO_DEVICE                0x00    // Device Request bmRequestType transfer direction - host to device transfer
+#define USB_SETUP_DEVICE_TO_HOST                0x80    // Device Request bmRequestType transfer direction - device to host transfer
+#define USB_SETUP_TYPE_STANDARD                 0x00    // Device Request bmRequestType type - standard
+#define USB_SETUP_TYPE_CLASS                    0x20    // Device Request bmRequestType type - class
+#define USB_SETUP_TYPE_VENDOR                   0x40    // Device Request bmRequestType type - vendor
+#define USB_SETUP_RECIPIENT_DEVICE              0x00    // Device Request bmRequestType recipient - device
+#define USB_SETUP_RECIPIENT_INTERFACE           0x01    // Device Request bmRequestType recipient - interface
+#define USB_SETUP_RECIPIENT_ENDPOINT            0x02    // Device Request bmRequestType recipient - endpoint
+#define USB_SETUP_RECIPIENT_OTHER               0x03    // Device Request bmRequestType recipient - other
+
+/* USB descriptors  */
+#define USB_DESCRIPTOR_DEVICE           0x01    // bDescriptorType for a Device Descriptor.
+#define USB_DESCRIPTOR_CONFIGURATION    0x02    // bDescriptorType for a Configuration Descriptor.
+#define USB_DESCRIPTOR_STRING           0x03    // bDescriptorType for a String Descriptor.
+#define USB_DESCRIPTOR_INTERFACE        0x04    // bDescriptorType for an Interface Descriptor.
+#define USB_DESCRIPTOR_ENDPOINT         0x05    // bDescriptorType for an Endpoint Descriptor.
+#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06    // bDescriptorType for a Device Qualifier.
+#define USB_DESCRIPTOR_OTHER_SPEED      0x07    // bDescriptorType for a Other Speed Configuration.
+#define USB_DESCRIPTOR_INTERFACE_POWER  0x08    // bDescriptorType for Interface Power.
+
+void usb_init();
+void usb_poll();
+void usb_SetHubPreMask(void);
+void usb_ResetHubPreMask(void);
+
+uint8_t usb_set_addr( usb_device_t *, uint8_t );
+uint8_t usb_ctrl_req( usb_device_t *, uint8_t bmReqType, 
+		      uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, 
+		      uint16_t wInd, uint16_t nbytes, uint8_t* dataptr);
+uint8_t usb_get_dev_descr( usb_device_t *, uint16_t nbytes, usb_device_descriptor_t* dataptr );
+uint8_t usb_get_conf_descr( usb_device_t *, uint16_t nbytes, uint8_t conf, usb_configuration_descriptor_t* dataptr );
+uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value );
+uint8_t usb_in_transfer( usb_device_t *, ep_t *ep, uint16_t *nbytesptr, uint8_t* data);
+uint8_t usb_out_transfer( usb_device_t *, ep_t *ep, uint16_t nbytes, uint8_t* data );
+uint8_t usb_release_device(uint8_t parent, uint8_t port);
+usb_device_t *usb_get_devices();
+
+#endif // USB_H
Index: firmware/usb/usbhostslave.h
===================================================================
--- firmware/usb/usbhostslave.h	(nonexistent)
+++ firmware/usb/usbhostslave.h	(revision 269)
@@ -0,0 +1,113 @@
+/*
+ * OHS900 register declarations and HCD data structures
+ *
+ * Copyright (C) 2005 Steve Fielding
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ */
+
+// ----------------------- FIXME using direct memory access
+// base address of OHS900 MWW TODO!!!
+//#define OHS900_BASE 0x80900c00
+
+char usbhostslave[0x100];
+
+/*
+ * OHS900 has transfer registers, and control registers.  In host/master
+ * mode one set of registers is used; in peripheral/slave mode, another.
+ */
+
+
+/* TRANSFER REGISTERS
+ */
+#define OHS900_HOST_TX_CTLREG	0x00 
+#	define OHS900_HCTLMASK_TRANS_REQ		0x01 
+#	define OHS900_HCTLMASK_SOF_SYNC		0x02 
+#	define OHS900_HCTLMASK_PREAMBLE_EN	0x04 
+#	define OHS900_HCTLMASK_ISO_EN		0x08 
+
+
+#define OHS900_HRXSTATREG	0x0a	/* read */ 
+#	define OHS900_STATMASK_CRC_ERROR		0x01 
+#	define OHS900_STATMASK_BS_ERROR		0x02 
+#	define OHS900_STATMASK_RX_OVF		0x04 
+#	define OHS900_STATMASK_RX_TMOUT		0x08 
+#	define OHS900_STATMASK_NAK_RXED		0x10 
+#	define OHS900_STATMASK_STALL_RXED	0x20 
+#	define OHS900_STATMASK_ACK_RXED		0x40 
+#	define OHS900_STATMASK_DATA_SEQ		0x80 
+
+#define OHS900_TXTRANSTYPEREG		0x01	/* write */ 
+#	define	OHS900_SETUP	0x00 
+#	define	OHS900_IN	0x01 
+#	define	OHS900_OUT_DATA0	0x02 
+#	define	OHS900_OUT_DATA1	0x03 
+
+#define OHS900_TXADDRREG	0x04	
+#define OHS900_TXENDPREG	0x05	
+
+/* CONTROL REGISTERS:  
+ */
+#define OHS900_SOFENREG		0x03 
+#	define OHS900_MASK_SOF_ENA	0x01 
+
+#define OHS900_TXLINECTLREG 0x02 
+#	define OHS900_TXLCTL_MASK_FORCE	0x4 
+#	define OHS900_TXLCTL_MASK_LINE_CTRL_BITS 0x7
+#		define OHS900_TXLCTL_MASK_NORMAL	0x00 
+#		define OHS900_TXLCTL_MASK_SE0	0x04	
+#		define OHS900_TXLCTL_MASK_FS_J	0x06    
+#		define OHS900_TXLCTL_MASK_FS_K	0x05	
+#	define OHS900_TXLCTL_MASK_LSPD	0x00 
+#	define OHS900_TXLCTL_MASK_FSPD	0x18 
+#	define OHS900_TXLCTL_MASK_FS_POL	0x08 
+#	define OHS900_TXLCTL_MASK_FS_RATE 0x10 
+
+
+#define OHS900_IRQ_ENABLE	0x09             
+#	define OHS900_INTMASK_TRANS_DONE	0x01   
+#	define OHS900_INTMASK_SOFINTR	0x08   
+#	define OHS900_INTMASK_INSRMV	0x04   	
+#	define OHS900_INTMASK_RESUME_DET	0x02   
+		  
+#define OHS900_RXCONNSTATEREG 0x0e
+#define   OHS900_DISCONNECT_STATE 0x00
+#define   OHS900_LS_CONN_STATE 0x01
+#define   OHS900_FS_CONN_STATE 0x02
+
+#define OHS900_SLAVE_ADDRESS		0x54 
+
+
+
+#define OHS900_IRQ_STATUS	0x08	/* write to ack */ 
+#define OHS900_HWREVREG		0xe1	/* read */ 
+
+#define OHS900_SOFTMRREG		0x0F 
+
+
+
+#define OHS900_HOSTSLAVECTLREG 			0xe0 
+#	define OHS900_HSCTLREG_HOST_EN_MASK	0x01 
+#	define OHS900_HSCTLREG_RESET_CORE	0x02 
+
+
+
+#define OHS900_HS_CTL_INIT OHS900_HSCTLREG_HOST_EN_MASK 
+
+/* 64-byte FIFO control and status
+ */
+#define H_MAXPACKET	64		/* bytes in fifos */
+
+#define OHS900_HOST_TXFIFO_DATA	0x30 
+#define OHS900_TXFIFOCNTMSBREG	0x32 
+#define OHS900_TXFIFOCNTLSBREG	0x33
+#define OHS900_TXFIFOCONTROLREG	0x34
+#define OHS900_HOST_RXFIFO_DATA	0x20 
+#define OHS900_RXFIFOCNTMSBREG	0x22 
+#define OHS900_RXFIFOCNTLSBREG	0x23
+#define OHS900_RXFIFOCONTROLREG	0x24
+#define		OHS900_FIFO_FORCE_EMPTY 0x01
+
+
+#define OHS900_IO_EXTENT 0x100
+
