| 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))); | ||||