diff --git a/USBHost.h b/USBHost.h index f082801..3f32ecd 100644 --- a/USBHost.h +++ b/USBHost.h @@ -239,8 +239,10 @@ protected: void poweron(uint32_t port); void getstatus(uint32_t port); void clearstatus(uint32_t port); + void reset(uint32_t port); static void callback(const Transfer_t *transfer); void status_change(const Transfer_t *transfer); + void new_port_status(uint32_t port, uint32_t status); void update_status(); setup_t setup; uint8_t hub_desc[16]; @@ -251,7 +253,9 @@ protected: uint8_t state; Pipe_t *changepipe; uint32_t changebits; - uint32_t status; + uint32_t statusbits; + uint16_t portstatus[7]; + uint8_t portstate[7]; }; diff --git a/ehci.cpp b/ehci.cpp index b6672b3..5f13d66 100644 --- a/ehci.cpp +++ b/ehci.cpp @@ -751,7 +751,7 @@ static bool allocate_interrupt_pipe_bandwidth(uint32_t speed, uint32_t maxlen, maxlen = (maxlen * 76459) >> 16; // worst case bit stuffing if (speed == 2) { // high speed 480 Mbit/sec - uint32_t stime = (55 + 32 + maxlen) >> 5; + uint32_t stime = (55 + 32 + maxlen) >> 5; // time units: 32 bytes or 533 ns uint32_t min_offset = 0xFFFFFFFF; uint32_t min_bw = 0xFFFFFFFF; for (uint32_t offset=0; offset < interval; offset++) { @@ -788,6 +788,8 @@ static bool allocate_interrupt_pipe_bandwidth(uint32_t speed, uint32_t maxlen, // full speed 12 Mbit/sec or low speed 1.5 Mbit/sec uint32_t stime, ctime; if (direction == 0) { + // TODO: how much time to SSPLIT & CSPLIT actually take? + // they're not documented in 5.7 or 5.11.3. stime = (100 + 32 + maxlen) >> 5; ctime = (55 + 32) >> 5; } else { @@ -795,6 +797,8 @@ static bool allocate_interrupt_pipe_bandwidth(uint32_t speed, uint32_t maxlen, ctime = (70 + 32 + maxlen) >> 5; } interval = interval >> 3; // can't be zero, earlier check for interval >= 8 + // TODO: should we take Single-TT hubs into account, avoid + // scheduling overlapping SSPLIT & CSPLIT to the same hub? uint32_t min_shift = 0; uint32_t min_offset = 0xFFFFFFFF; uint32_t min_bw = 0xFFFFFFFF; diff --git a/hub.cpp b/hub.cpp index 8d91ccc..08ba847 100644 --- a/hub.cpp +++ b/hub.cpp @@ -74,6 +74,8 @@ bool USBHub::claim(Device_t *dev, int type, const uint8_t *descriptors) changepipe = NULL; changebits = 0; state = 0; + memset(portstatus, 0, sizeof(portstatus)); + memset(portstate, 0, sizeof(portstate)); mk_setup(setup, 0xA0, 6, 0x2900, 0, sizeof(hub_desc)); queue_Control_Transfer(dev, &setup, hub_desc, this); @@ -94,7 +96,7 @@ void USBHub::getstatus(uint32_t port) } else { mk_setup(setup, 0xA3, 0, 0, port, 4); // get port status } - queue_Control_Transfer(device, &setup, &status, this); + queue_Control_Transfer(device, &setup, &statusbits, this); } void USBHub::clearstatus(uint32_t port) @@ -107,6 +109,13 @@ void USBHub::clearstatus(uint32_t port) queue_Control_Transfer(device, &setup, NULL, this); } +void USBHub::reset(uint32_t port) +{ + mk_setup(setup, 0x23, 3, 4, port, 0); // set feature PORT_RESET + queue_Control_Transfer(device, &setup, NULL, this); +} + + void USBHub::control(const Transfer_t *transfer) { Serial.println("USBHub control callback"); @@ -148,8 +157,7 @@ void USBHub::control(const Transfer_t *transfer) clearstatus(0); return; case 0x000000A3: // get port status - Serial.print("New Port Status, port="); - Serial.println(setup.wIndex); + new_port_status(setup.wIndex, statusbits); clearstatus(setup.wIndex); return; case 0x00100120: // clear hub status @@ -194,6 +202,55 @@ void USBHub::update_status() } } +void USBHub::new_port_status(uint32_t port, uint32_t status) +{ + if (port < 1 || port > 7) return; + uint32_t priorstatus = portstatus[port - 1]; + portstatus[port] = status; + + Serial.print("New Port Status, port="); + Serial.print(port); + Serial.print(", status="); + Serial.println(status, HEX); + + // status bits, USB 2.0: 11.24.2.7.1 page 427 + if (status & 0x0001) Serial.println(" Device is present: "); + if (status & 0x0002) { + Serial.println(" Enabled, speed = "); + if (status & 0x0200) { + Serial.print("1.5"); + } else { + if (status & 0x0400) { + Serial.print("480"); + } else { + Serial.print("12"); + } + } + Serial.println(" Mbit/sec"); + } + if (status & 0x0004) Serial.println(" Suspended"); + if (status & 0x0008) Serial.println(" Over-current"); + if (status & 0x0010) Serial.println(" Reset"); + if (status & 0x0100) Serial.println(" Has Power"); + if (status & 0x0800) Serial.println(" Test Mode"); + if (status & 0x1000) Serial.println(" Software Controls LEDs"); + + if ((status & 0x0001) && !(priorstatus & 0x0001)) { + Serial.println(" connect"); + // 100 ms debounce (USB 2.0: TATTDB, page 150 & 188) + delay(100); // TODO: horribly bad... need timing events + reset(port); + // TODO... reset timer? + + } else if (!(status & 0x0001) && (priorstatus & 0x0001)) { + Serial.println(" disconnect"); + + + } + +} + + void USBHub::disconnect() { // TODO: free resources