static void disconnect_Device(Device_t *dev); | static void disconnect_Device(Device_t *dev); | ||||
static void enumeration(const Transfer_t *transfer); | static void enumeration(const Transfer_t *transfer); | ||||
static void driver_ready_for_device(USBDriver *driver); | static void driver_ready_for_device(USBDriver *driver); | ||||
static volatile bool enumeration_busy; | |||||
private: | private: | ||||
static void isr(); | static void isr(); | ||||
static void claim_drivers(Device_t *dev); | static void claim_drivers(Device_t *dev); | ||||
virtual void timer_event(USBDriverTimer *whichTimer); | virtual void timer_event(USBDriverTimer *whichTimer); | ||||
virtual void disconnect(); | virtual void disconnect(); | ||||
bool can_send_control_now(); | bool can_send_control_now(); | ||||
void send_poweron(uint32_t port); | void send_poweron(uint32_t port); | ||||
void send_getstatus(uint32_t port); | void send_getstatus(uint32_t port); | ||||
void send_clearstatus_connect(uint32_t port); | void send_clearstatus_connect(uint32_t port); | ||||
void send_clearstatus_overcurrent(uint32_t port); | void send_clearstatus_overcurrent(uint32_t port); | ||||
void send_clearstatus_reset(uint32_t port); | void send_clearstatus_reset(uint32_t port); | ||||
void send_setreset(uint32_t port); | void send_setreset(uint32_t port); | ||||
static void callback(const Transfer_t *transfer); | static void callback(const Transfer_t *transfer); | ||||
void status_change(const Transfer_t *transfer); | void status_change(const Transfer_t *transfer); | ||||
void new_port_status(uint32_t port, uint32_t status); | void new_port_status(uint32_t port, uint32_t status); | ||||
void start_debounce_timer(uint32_t port); | void start_debounce_timer(uint32_t port); | ||||
void stop_debounce_timer(uint32_t port); | void stop_debounce_timer(uint32_t port); | ||||
static volatile bool reset_busy; | |||||
USBDriverTimer debouncetimer; | USBDriverTimer debouncetimer; | ||||
//USBDriverTimer mytimer; | |||||
USBDriverTimer resettimer; | USBDriverTimer resettimer; | ||||
setup_t setup; | setup_t setup; | ||||
Pipe_t *changepipe; | Pipe_t *changepipe; |
NVIC_ENABLE_IRQ(IRQ_USBHS); | NVIC_ENABLE_IRQ(IRQ_USBHS); | ||||
USBHS_USBINTR = USBHS_USBINTR_PCE | USBHS_USBINTR_TIE0 | USBHS_USBINTR_TIE1; | USBHS_USBINTR = USBHS_USBINTR_PCE | USBHS_USBINTR_TIE0 | USBHS_USBINTR_TIE1; | ||||
USBHS_USBINTR |= USBHS_USBINTR_UEE | USBHS_USBINTR_SEE; | USBHS_USBINTR |= USBHS_USBINTR_UEE | USBHS_USBINTR_SEE; | ||||
USBHS_USBINTR |= USBHS_USBINTR_AAE; | |||||
USBHS_USBINTR |= USBHS_USBINTR_UPIE | USBHS_USBINTR_UAIE; | USBHS_USBINTR |= USBHS_USBINTR_UPIE | USBHS_USBINTR_UAIE; | ||||
} | } | ||||
//println("timer0"); | //println("timer0"); | ||||
if (port_state == PORT_STATE_DEBOUNCE) { | if (port_state == PORT_STATE_DEBOUNCE) { | ||||
port_state = PORT_STATE_RESET; | 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 | USBHS_PORTSC1 |= USBHS_PORTSC_PR; // begin reset sequence | ||||
println(" begin reset"); | println(" begin reset"); | ||||
} else if (port_state == PORT_STATE_RECOVERY) { | } else if (port_state == PORT_STATE_RECOVERY) { | ||||
port_state = PORT_STATE_ACTIVE; | port_state = PORT_STATE_ACTIVE; | ||||
println(" end recovery"); | println(" end recovery"); | ||||
// HCSPARAMS TTCTRL page 1671 | // HCSPARAMS TTCTRL page 1671 | ||||
uint32_t speed = (USBHS_PORTSC1 >> 26) & 3; | uint32_t speed = (USBHS_PORTSC1 >> 26) & 3; | ||||
rootdev = new_Device(speed, 0, 0); | rootdev = new_Device(speed, 0, 0); |
static uint16_t enumlen; | static uint16_t enumlen; | ||||
static Device_t *devlist=NULL; | 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_maxlen(Pipe_t *pipe, uint32_t maxlen); | ||||
static void pipe_set_addr(Pipe_t *pipe, uint32_t addr); | static void pipe_set_addr(Pipe_t *pipe, uint32_t addr); | ||||
} | } | ||||
dev->control_pipe->callback_function = &enumeration; | dev->control_pipe->callback_function = &enumeration; | ||||
dev->control_pipe->direction = 1; // 1=IN | 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 | mk_setup(enumsetup, 0x80, 6, 0x0100, 0, 8); // 6=GET_DESCRIPTOR | ||||
queue_Control_Transfer(dev, &enumsetup, enumbuf, NULL); | queue_Control_Transfer(dev, &enumsetup, enumbuf, NULL); | ||||
if (devlist == NULL) { | if (devlist == NULL) { | ||||
case 14: // device is now configured | case 14: // device is now configured | ||||
claim_drivers(dev); | claim_drivers(dev); | ||||
dev->enum_state = 15; | 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; | return; | ||||
case 15: // control transfers for other stuff? | case 15: // control transfers for other stuff? | ||||
// TODO: handle other standard control: set/clear feature, etc | // TODO: handle other standard control: set/clear feature, etc |
#include <Arduino.h> | #include <Arduino.h> | ||||
#include "USBHost.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 | // TODO: free Device_t, Pipe_t & Transfer_t we will need | ||||
driver_ready_for_device(this); | driver_ready_for_device(this); | ||||
println("USBHub memory usage = ", sizeof(USBHub)); | println("USBHub memory usage = ", sizeof(USBHub)); | ||||
println("USBHub claim_device this=", (uint32_t)this, HEX); | 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.pointer = (void *)"Hello, I'm resettimer"; | ||||
//resettimer.start(12345); | |||||
debouncetimer.pointer = (void *)"Debounce Timer"; | debouncetimer.pointer = (void *)"Debounce Timer"; | ||||
// check for HUB type | // check for HUB type | ||||
case PORT_DEBOUNCE5: | case PORT_DEBOUNCE5: | ||||
if (status & 0x0001) { | if (status & 0x0001) { | ||||
if (++state > PORT_DEBOUNCE5) { | 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); | stop_debounce_timer(port); | ||||
state = PORT_RESET; | state = PORT_RESET; | ||||
println("sending reset"); | println("sending reset"); | ||||
// begin enumeration process | // begin enumeration process | ||||
uint8_t speed = port_doing_reset_speed; | uint8_t speed = port_doing_reset_speed; | ||||
devicelist[port-1] = new_Device(speed, device->address, port); | 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; | 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) | void USBHub::start_debounce_timer(uint32_t port) |
// Memory allocation | // Memory allocation | ||||
static Device_t memory_Device[3]; | |||||
static Device_t memory_Device[4]; | |||||
static Pipe_t memory_Pipe[8] __attribute__ ((aligned(32))); | static Pipe_t memory_Pipe[8] __attribute__ ((aligned(32))); | ||||
static Transfer_t memory_Transfer[34] __attribute__ ((aligned(32))); | static Transfer_t memory_Transfer[34] __attribute__ ((aligned(32))); | ||||