class USBHost; | class USBHost; | ||||
class USBDriver; | class USBDriver; | ||||
typedef struct Device_struct Device_t; | |||||
typedef struct Pipe_struct Pipe_t; | |||||
typedef struct Transfer_struct Transfer_t; | |||||
class USBDriverTimer; | |||||
typedef struct Device_struct Device_t; | |||||
typedef struct Pipe_struct Pipe_t; | |||||
typedef struct Transfer_struct Transfer_t; | |||||
//typedef struct DriverTimer_struct DriverTimer_t; | |||||
// setup_t holds the 8 byte USB SETUP packet data. | // setup_t holds the 8 byte USB SETUP packet data. | ||||
// These unions & structs allow convenient access to | // These unions & structs allow convenient access to | ||||
uint32_t unused; | uint32_t unused; | ||||
}; | }; | ||||
/************************************************/ | /************************************************/ | ||||
/* Main USB EHCI Controller */ | /* Main USB EHCI Controller */ | ||||
/************************************************/ | /************************************************/ | ||||
// All USB device drivers inherit from this base class. | // All USB device drivers inherit from this base class. | ||||
class USBDriver : public USBHost { | class USBDriver : public USBHost { | ||||
public: | |||||
// TODO: user-level functions | |||||
// check if device is bound/active/online | |||||
// query vid, pid | |||||
// query string: manufacturer, product, serial number | |||||
protected: | protected: | ||||
USBDriver() : next(NULL), device(NULL) {} | USBDriver() : next(NULL), device(NULL) {} | ||||
// Check if a driver wishes to claim a device or interface or group | // Check if a driver wishes to claim a device or interface or group | ||||
// transfers and wishes to be notified when they complete. | // transfers and wishes to be notified when they complete. | ||||
virtual void control(const Transfer_t *transfer) { } | virtual void control(const Transfer_t *transfer) { } | ||||
// When any of the USBDriverTimer objects a driver creates generates | |||||
// a timer event, this function is called. | |||||
virtual void timer(USBDriverTimer &whichTimer) { } | |||||
// When a device disconnects from the USB, this function is called. | // When a device disconnects from the USB, this function is called. | ||||
// The driver must free all resources it allocated and update any | // The driver must free all resources it allocated and update any | ||||
// internal state necessary to deal with the possibility of user | // internal state necessary to deal with the possibility of user | ||||
Device_t *device; | Device_t *device; | ||||
friend class USBHost; | friend class USBHost; | ||||
public: | |||||
// TODO: user-level functions | |||||
// check if device is bound/active/online | |||||
// query vid, pid | |||||
// query string: manufacturer, product, serial number | |||||
}; | }; | ||||
// Device drivers may create these timer objects to schedule a timer call | |||||
class USBDriverTimer { | |||||
public: | |||||
USBDriverTimer() { } | |||||
USBDriverTimer(USBDriver *d) : driver(d) { } | |||||
void init(USBDriver *d) { driver = d; }; | |||||
void start(uint32_t microseconds); | |||||
void *pointer; | |||||
uint32_t integer; | |||||
private: | |||||
USBDriver *driver; | |||||
uint32_t usec; | |||||
USBDriverTimer *next; | |||||
USBDriverTimer *prev; | |||||
friend class USBHost; | |||||
}; | |||||
/************************************************/ | /************************************************/ | ||||
/* USB Device Drivers */ | /* USB Device Drivers */ | ||||
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 update_status(); | void update_status(); | ||||
USBDriverTimer mytimer; | |||||
USBDriverTimer othertimer; | |||||
setup_t setup; | setup_t setup; | ||||
uint8_t hub_desc[16]; | uint8_t hub_desc[16]; | ||||
uint8_t endpoint; | uint8_t endpoint; |
static Transfer_t *async_followup_last=NULL; | static Transfer_t *async_followup_last=NULL; | ||||
static Transfer_t *periodic_followup_first=NULL; | static Transfer_t *periodic_followup_first=NULL; | ||||
static Transfer_t *periodic_followup_last=NULL; | static Transfer_t *periodic_followup_last=NULL; | ||||
static USBDriverTimer *active_timers=NULL; | |||||
static void init_qTD(volatile Transfer_t *t, void *buf, uint32_t len, | static void init_qTD(volatile Transfer_t *t, void *buf, uint32_t len, | ||||
// enable interrupts, after this point interruts to all the work | // enable interrupts, after this point interruts to all the work | ||||
attachInterruptVector(IRQ_USBHS, isr); | attachInterruptVector(IRQ_USBHS, isr); | ||||
NVIC_ENABLE_IRQ(IRQ_USBHS); | NVIC_ENABLE_IRQ(IRQ_USBHS); | ||||
USBHS_USBINTR = USBHS_USBINTR_PCE | USBHS_USBINTR_TIE0; | |||||
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_AAE; | ||||
USBHS_USBINTR |= USBHS_USBINTR_UPIE | USBHS_USBINTR_UAIE; | USBHS_USBINTR |= USBHS_USBINTR_UPIE | USBHS_USBINTR_UAIE; | ||||
} | } | ||||
} | } | ||||
if (stat & USBHS_USBSTS_TI0) { // timer 0 | |||||
println("timer"); | |||||
if (stat & USBHS_USBSTS_TI0) { // timer 0 - used for built-in port events | |||||
println("timer0"); | |||||
if (port_state == PORT_STATE_DEBOUNCE) { | if (port_state == PORT_STATE_DEBOUNCE) { | ||||
port_state = PORT_STATE_RESET; | port_state = PORT_STATE_RESET; | ||||
USBHS_PORTSC1 |= USBHS_PORTSC_PR; // begin reset sequence | USBHS_PORTSC1 |= USBHS_PORTSC_PR; // begin reset sequence | ||||
rootdev = new_Device(speed, 0, 0); | rootdev = new_Device(speed, 0, 0); | ||||
} | } | ||||
} | } | ||||
if (stat & USBHS_USBSTS_TI1) { // timer 1 - used for USBDriverTimer | |||||
println("timer1"); | |||||
} | |||||
} | |||||
void USBDriverTimer::start(uint32_t microseconds) | |||||
{ | |||||
Serial.print("start_timer, usec = "); | |||||
Serial.print(usec); | |||||
Serial.print(", driver = "); | |||||
Serial.print((uint32_t)driver, HEX); | |||||
Serial.print(", this = "); | |||||
Serial.println((uint32_t)this, HEX); | |||||
#if 1 | |||||
if (!driver) return; | |||||
if (microseconds < 100) return; // minimum timer duration | |||||
if (active_timers == NULL) { | |||||
usec = microseconds; | |||||
next = NULL; | |||||
prev = NULL; | |||||
active_timers = this; | |||||
USBHS_GPTIMER1LD = microseconds - 1; | |||||
USBHS_GPTIMER1CTL = USBHS_GPTIMERCTL_RST | USBHS_GPTIMERCTL_RUN; | |||||
return; | |||||
} | |||||
#endif | |||||
// TODO, add to active_timers list | |||||
//uint32_t remain = USBHS_GPTIMER1CTL & 0xFFFFFF; | |||||
} | } | ||||
// bulk | // bulk | ||||
} else if (type == 3) { | } else if (type == 3) { | ||||
// interrupt | // interrupt | ||||
//pipe->qh.token = 0x80000000; // TODO: OUT starts with DATA0 or DATA1? | |||||
} | } | ||||
pipe->qh.capabilities[0] = QH_capabilities1(15, c, maxlen, 0, | pipe->qh.capabilities[0] = QH_capabilities1(15, c, maxlen, 0, | ||||
dtc, dev->speed, endpoint, 0, dev->address); | dtc, dev->speed, endpoint, 0, dev->address); |
#include <Arduino.h> | #include <Arduino.h> | ||||
#include "USBHost.h" | #include "USBHost.h" | ||||
USBHub::USBHub() | |||||
USBHub::USBHub() : /* mytimer(this), */ othertimer(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 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.start(99129); | |||||
othertimer.start(12345); | |||||
// check for HUB type | // check for HUB type | ||||
if (dev->bDeviceClass != 9 || dev->bDeviceSubClass != 0) return false; | if (dev->bDeviceClass != 9 || dev->bDeviceSubClass != 0) return false; | ||||
// protocol must be 0=FS, 1=HS Single-TT, or 2=HS Multi-TT | // protocol must be 0=FS, 1=HS Single-TT, or 2=HS Multi-TT |