@@ -161,6 +161,7 @@ protected: | |||
static void disconnect_Device(Device_t *dev); | |||
static void enumeration(const Transfer_t *transfer); | |||
static void driver_ready_for_device(USBDriver *driver); | |||
static volatile bool enumeration_busy; | |||
private: | |||
static void isr(); | |||
static void claim_drivers(Device_t *dev); | |||
@@ -326,7 +327,6 @@ protected: | |||
virtual void timer_event(USBDriverTimer *whichTimer); | |||
virtual void disconnect(); | |||
bool can_send_control_now(); | |||
void send_poweron(uint32_t port); | |||
void send_getstatus(uint32_t port); | |||
void send_clearstatus_connect(uint32_t port); | |||
@@ -335,15 +335,14 @@ protected: | |||
void send_clearstatus_overcurrent(uint32_t port); | |||
void send_clearstatus_reset(uint32_t port); | |||
void send_setreset(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 start_debounce_timer(uint32_t port); | |||
void stop_debounce_timer(uint32_t port); | |||
static volatile bool reset_busy; | |||
USBDriverTimer debouncetimer; | |||
//USBDriverTimer mytimer; | |||
USBDriverTimer resettimer; | |||
setup_t setup; | |||
Pipe_t *changepipe; |
@@ -175,7 +175,6 @@ void USBHost::begin() | |||
NVIC_ENABLE_IRQ(IRQ_USBHS); | |||
USBHS_USBINTR = USBHS_USBINTR_PCE | USBHS_USBINTR_TIE0 | USBHS_USBINTR_TIE1; | |||
USBHS_USBINTR |= USBHS_USBINTR_UEE | USBHS_USBINTR_SEE; | |||
USBHS_USBINTR |= USBHS_USBINTR_AAE; | |||
USBHS_USBINTR |= USBHS_USBINTR_UPIE | USBHS_USBINTR_UAIE; | |||
} | |||
@@ -313,12 +312,16 @@ void USBHost::isr() | |||
//println("timer0"); | |||
if (port_state == PORT_STATE_DEBOUNCE) { | |||
port_state = PORT_STATE_RESET; | |||
// Since we have only 1 port, no other device can | |||
// be in reset or enumeration. If multiple ports | |||
// are ever supported, we would need to remain in | |||
// debounce if any other port was resetting or | |||
// enumerating a device. | |||
USBHS_PORTSC1 |= USBHS_PORTSC_PR; // begin reset sequence | |||
println(" begin reset"); | |||
} else if (port_state == PORT_STATE_RECOVERY) { | |||
port_state = PORT_STATE_ACTIVE; | |||
println(" end recovery"); | |||
// HCSPARAMS TTCTRL page 1671 | |||
uint32_t speed = (USBHS_PORTSC1 >> 26) & 3; | |||
rootdev = new_Device(speed, 0, 0); |
@@ -31,6 +31,10 @@ static setup_t enumsetup __attribute__ ((aligned(16))); | |||
static uint16_t enumlen; | |||
static Device_t *devlist=NULL; | |||
// True while any device is present but not yet fully configured. | |||
// Only one USB device may be in this state at a time (responding | |||
// to address zero) and using the enumeration static buffer. | |||
volatile bool USBHost::enumeration_busy = false; | |||
static void pipe_set_maxlen(Pipe_t *pipe, uint32_t maxlen); | |||
static void pipe_set_addr(Pipe_t *pipe, uint32_t addr); | |||
@@ -79,9 +83,9 @@ Device_t * USBHost::new_Device(uint32_t speed, uint32_t hub_addr, uint32_t hub_p | |||
} | |||
dev->control_pipe->callback_function = &enumeration; | |||
dev->control_pipe->direction = 1; // 1=IN | |||
// TODO: exclusive access to enumeration process | |||
// any new devices detected while enumerating would | |||
// go onto a waiting list | |||
// Here is where the enumeration process officially begins. | |||
// Only a single device can enumerate at a time. | |||
USBHost::enumeration_busy = true; | |||
mk_setup(enumsetup, 0x80, 6, 0x0100, 0, 8); // 6=GET_DESCRIPTOR | |||
queue_Control_Transfer(dev, &enumsetup, enumbuf, NULL); | |||
if (devlist == NULL) { | |||
@@ -227,8 +231,11 @@ void USBHost::enumeration(const Transfer_t *transfer) | |||
case 14: // device is now configured | |||
claim_drivers(dev); | |||
dev->enum_state = 15; | |||
// TODO: unlock exclusive access to enumeration process | |||
// if any detected devices are waiting, start the first | |||
// unlock exclusive access to enumeration process. If any | |||
// more devices are waiting, the hub driver is responsible | |||
// for resetting their ports and starting their enumeration | |||
// when the port enables. | |||
USBHost::enumeration_busy = false; | |||
return; | |||
case 15: // control transfers for other stuff? | |||
// TODO: handle other standard control: set/clear feature, etc |
@@ -24,7 +24,12 @@ | |||
#include <Arduino.h> | |||
#include "USBHost.h" | |||
USBHub::USBHub() : debouncetimer(this), /* mytimer(this), */ resettimer(this) | |||
// True when any hub port is in the reset or reset recovery phase. | |||
// Only one USB device may be reset at a time, because it will | |||
// begin responding to address zero. | |||
volatile bool USBHub::reset_busy = false; | |||
USBHub::USBHub() : debouncetimer(this), resettimer(this) | |||
{ | |||
// TODO: free Device_t, Pipe_t & Transfer_t we will need | |||
driver_ready_for_device(this); | |||
@@ -38,12 +43,7 @@ bool USBHub::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t | |||
println("USBHub memory usage = ", sizeof(USBHub)); | |||
println("USBHub claim_device this=", (uint32_t)this, HEX); | |||
// timer testing TODO: remove this later | |||
//mytimer.init(this); | |||
//mytimer.pointer = (void *)"This is mytimer"; | |||
//mytimer.start(99129); | |||
resettimer.pointer = (void *)"Hello, I'm resettimer"; | |||
//resettimer.start(12345); | |||
debouncetimer.pointer = (void *)"Debounce Timer"; | |||
// check for HUB type | |||
@@ -347,9 +347,13 @@ void USBHub::new_port_status(uint32_t port, uint32_t status) | |||
case PORT_DEBOUNCE5: | |||
if (status & 0x0001) { | |||
if (++state > PORT_DEBOUNCE5) { | |||
// TODO: check for exclusive access to | |||
// enumeration process... stay in debounce | |||
// and add to wait list if enumeration busy | |||
if (USBHub::reset_busy || USBHost::enumeration_busy) { | |||
// wait in debounce state if another port is | |||
// resetting or a device is busy enumerating | |||
state = PORT_DEBOUNCE5; | |||
break; | |||
} | |||
USBHub::reset_busy = true; | |||
stop_debounce_timer(port); | |||
state = PORT_RESET; | |||
println("sending reset"); | |||
@@ -409,10 +413,21 @@ void USBHub::timer_event(USBDriverTimer *timer) | |||
// begin enumeration process | |||
uint8_t speed = port_doing_reset_speed; | |||
devicelist[port-1] = new_Device(speed, device->address, port); | |||
// TODO: if return is NULL, what to do? Panic? | |||
// Can we disable the port? Will this device | |||
// play havoc if it sits unconfigured responding | |||
// to address zero? Does that even matter? Maybe | |||
// we have far worse issues when memory isn't | |||
// available?! | |||
USBHub::reset_busy = false; | |||
state = PORT_ACTIVE; | |||
} | |||
} | |||
} | |||
// TODO: testing only!!! | |||
static uint32_t count=0; | |||
if (++count > 36) while (1) ; // stop here | |||
} | |||
void USBHub::start_debounce_timer(uint32_t port) |
@@ -27,7 +27,7 @@ | |||
// Memory allocation | |||
static Device_t memory_Device[3]; | |||
static Device_t memory_Device[4]; | |||
static Pipe_t memory_Pipe[8] __attribute__ ((aligned(32))); | |||
static Transfer_t memory_Transfer[34] __attribute__ ((aligned(32))); | |||