diff options
-rw-r--r-- | usb/dwc_otg.h | 141 | ||||
-rw-r--r-- | usb/dwc_otg_def.h | 87 | ||||
-rw-r--r-- | usb/generic.h | 155 | ||||
-rw-r--r-- | usb/usb.h | 324 |
4 files changed, 387 insertions, 320 deletions
diff --git a/usb/dwc_otg.h b/usb/dwc_otg.h new file mode 100644 index 0000000..b68ca0e --- /dev/null +++ b/usb/dwc_otg.h @@ -0,0 +1,141 @@ +#ifndef DWC_OTG_H +#define DWC_OTG_H + +#include "generic.h" +#include "dwc_otg_def.h" + +class USB_otg : public USB_generic { + private: + DWC_OTG_t& otg; + + uint32_t rxfifo_bytes; + uint8_t rxfifo_ep; + + uint32_t setup_buf[16]; + + void handle_rxfifo() { + uint32_t status = otg.reg.GRXSTSP; + + uint8_t ep = status & 0x4; + uint32_t len = (status & 0x7ff0) >> 4; + uint32_t type = status & (0xf << 17); + + rxfifo_bytes = len; + + // OUT packet. + if(type == (0x2 << 17)) { + // TODO: Call endpoint callback. + (void)ep; + } + + // SETUP packet. + if(type == (0x6 << 17)) { + for(uint32_t i = 0; i < len; i += 4) { + setup_buf[i >> 2] = otg.fifo[0].reg; + } + + rxfifo_bytes = 0; + + handle_setup(setup_buf); + otg.dev_oep_reg[0].DOEPCTL |= (1 << 26); // CNAK + } + + // Discard remaining bytes from FIFO. + for(uint32_t i = 0; i < rxfifo_bytes; i += 4) { + (void)otg.fifo[0].reg; + } + + rxfifo_bytes = 0; + } + + protected: + virtual void hw_set_address(uint8_t addr) { + otg.dev_reg.DCFG |= addr << 4; + } + + virtual void hw_conf_ep(uint8_t ep, uint32_t conf) { + otg.dev_iep_reg[ep].DIEPCTL = conf; + } + + virtual void hw_set_stall(uint8_t ep) { + otg.dev_iep_reg[ep].DIEPCTL |= (1 << 21); + } + + public: + USB_otg(DWC_OTG_t& otg_periph, desc_t dev, desc_t conf) : USB_generic(dev, conf), otg(otg_periph) {} + + void init() { + // Set PHYSEL. + otg.reg.GUSBCFG |= (1 << 6); + + Time::sleep(10); + + while(!(otg.reg.GRSTCTL & (1 << 31))); + otg.reg.GRSTCTL |= 1; + while(otg.reg.GRSTCTL & 1); + + otg.reg.GAHBCFG = 0; + + // USB configuration + otg.reg.GUSBCFG = (1 << 30) | (0xf << 10) | (0 << 9) | (0 << 8) | (1 << 6); + // FDMOD TRDT HNPCAP SRPCAP PHYSEL + + // interrupt mask + otg.reg.GINTMSK = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 4); + // ENUMDNEM USBRST USBSUSPM ESUSPM SOFM OTGINT MMISM + + // device configuration + otg.dev_reg.DCFG = (1 << 2) | 3; + // NZLSOHSK DSPD + + // core configuration + otg.reg.GCCFG = (1 << 19) | (1 << 16); + // VBUSBSEN PWRDWN + + } + + void process() { + // USB reset. + if(otg.reg.GINTSTS & (1 << 12)) { + otg.dev_oep_reg[0].DOEPCTL = (1 << 27); + otg.dev_reg.DAINTMSK = (1 << 16) | 1; + otg.dev_reg.DOEPMSK = (1 << 3) | 1; + otg.dev_reg.DIEPEMPMSK = (1 << 3) | 1; + otg.reg.GRXFSIZ = 256; + otg.reg.DIEPTXF0 = (64 << 16) | 256; + otg.reg.DIEPTXF1 = (64 << 16) | 320; + otg.dev_oep_reg[0].DOEPTSIZ = (3 << 29); + } + + // OTG interrupt. + if(otg.reg.GINTSTS & (1 << 2)) { + otg.reg.GOTGINT = (1 << 2); // SEDET + } + + // RxFIFO non-empty. + if(otg.reg.GINTSTS & (1 << 4)) { + handle_rxfifo(); + } + + otg.reg.GINTSTS = 0xffffffff; + } + + virtual bool ep_ready(uint32_t ep) { + return (otg.dev_iep_reg[ep].DIEPCTL & 0x80008000) == 0x8000; + } + + virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) { + otg.dev_iep_reg[ep].DIEPTSIZ = (1 << 19) | len; + // PKTCNT + otg.dev_iep_reg[ep].DIEPCTL |= (1 << 31) | (1 << 26); + // EPENA CNAK + + len = (len + 3) >> 2; + + while(len--) { + otg.fifo[ep].reg = *bufp++; + } + } +}; + +#endif diff --git a/usb/dwc_otg_def.h b/usb/dwc_otg_def.h new file mode 100644 index 0000000..2f19116 --- /dev/null +++ b/usb/dwc_otg_def.h @@ -0,0 +1,87 @@ +#ifndef DWC_OTG_DEF_H +#define DWC_OTG_DEF_H + +#include <stdint.h> + +class DWC_OTG_t { + private: + struct DWC_OTG_reg_t { + volatile uint32_t GOTGCTL; + volatile uint32_t GOTGINT; + volatile uint32_t GAHBCFG; + volatile uint32_t GUSBCFG; + volatile uint32_t GRSTCTL; + volatile uint32_t GINTSTS; + volatile uint32_t GINTMSK; + volatile uint32_t GRXSTSR; + volatile uint32_t GRXSTSP; + volatile uint32_t GRXFSIZ; + volatile uint32_t DIEPTXF0; + volatile uint32_t HNPTXSTS; + uint32_t _reserved[2]; + volatile uint32_t GCCFG; + volatile uint32_t CID; + uint32_t _reserved1[48]; + volatile uint32_t HPTXFSIZ; + volatile uint32_t DIEPTXF1; + volatile uint32_t DIEPTXF2; + volatile uint32_t DIEPTXF3; + }; + + struct DWC_OTG_dev_reg_t { + volatile uint32_t DCFG; + volatile uint32_t DCTL; + volatile uint32_t DSTS; + uint32_t _reserved; + volatile uint32_t DIEPMSK; + volatile uint32_t DOEPMSK; + volatile uint32_t DAINT; + volatile uint32_t DAINTMSK; + uint32_t _reserved1[2]; + volatile uint32_t DVBUSDIS; + volatile uint32_t DVBUSPULSE; + uint32_t _reserved2; + volatile uint32_t DIEPEMPMSK; + }; + + struct DWC_OTG_dev_iep_reg_t { + volatile uint32_t DIEPCTL; + uint32_t _reserved; + volatile uint32_t DIEPINT; + uint32_t _reserved1; + volatile uint32_t DIEPTSIZ; + uint32_t _reserved2; + volatile uint32_t DTXFSTS; + uint32_t _reserved3; + }; + + struct DWC_OTG_dev_oep_reg_t { + volatile uint32_t DOEPCTL; + uint32_t _reserved; + volatile uint32_t DOEPINT; + uint32_t _reserved1; + volatile uint32_t DOEPTSIZ; + uint32_t _reserved2[3]; + }; + + union DWC_OTG_fifo_reg_t { + volatile uint32_t reg; + volatile uint32_t buf[1024]; + }; + + public: + DWC_OTG_reg_t& reg; + DWC_OTG_dev_reg_t& dev_reg; + DWC_OTG_dev_iep_reg_t* const dev_iep_reg; + DWC_OTG_dev_oep_reg_t* const dev_oep_reg; + DWC_OTG_fifo_reg_t* const fifo; + + DWC_OTG_t(uint32_t reg_addr) : + reg(*(DWC_OTG_reg_t*)reg_addr), + dev_reg(*(DWC_OTG_dev_reg_t*)(reg_addr + 0x800)), + dev_iep_reg((DWC_OTG_dev_iep_reg_t*)(reg_addr + 0x900)), + dev_oep_reg((DWC_OTG_dev_oep_reg_t*)(reg_addr + 0xb00)), + fifo((DWC_OTG_fifo_reg_t*)(reg_addr + 0x1000)) {} +}; + +#endif diff --git a/usb/generic.h b/usb/generic.h new file mode 100644 index 0000000..915b25a --- /dev/null +++ b/usb/generic.h @@ -0,0 +1,155 @@ +#ifndef GENERIC_H +#define GENERIC_H + +#include <stdint.h> + +struct desc_t { + uint32_t size; + void* data; +}; + +enum SetupStatus {Unhandled, Ok, Stall}; + +class USB_class_driver { + friend class USB_generic; + + protected: + virtual SetupStatus handle_setup(uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength) { + return SetupStatus::Unhandled; + } +}; + +class USB_generic { + private: + desc_t dev_desc; + desc_t conf_desc; + + USB_class_driver* control_handlers[4]; + + public: + USB_generic(desc_t dev, desc_t conf) : dev_desc(dev), conf_desc(conf) {} + + virtual bool ep_ready(uint32_t ep) = 0; + virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) = 0; + virtual void hw_set_address(uint8_t addr) = 0; + virtual void hw_conf_ep(uint8_t ep, uint32_t conf) = 0; + virtual void hw_set_stall(uint8_t ep) = 0; + + bool register_control_handler(USB_class_driver* control_handler) { + for(USB_class_driver*& handler : control_handlers) { + if(!handler || handler == control_handler) { + handler = control_handler; + return true; + } + } + + // Handler table is full. + return false; + } + + protected: + bool get_descriptor(uint16_t wValue, uint16_t wIndex, uint16_t wLength) { + desc_t* descp; + + switch(wValue) { + case 0x100: + descp = &dev_desc; + break; + case 0x200: + descp = &conf_desc; + break; + default: + return false; + } + + uint32_t* dp = (uint32_t*)descp->data; + uint32_t length = wLength > descp->size ? descp->size : wLength; + + while(length > 64) { + write(0, dp, 64); + dp += 16; + length -= 64; + + while(!ep_ready(0)); + } + + write(0, dp, length); + + return true; + } + + bool set_address(uint16_t wValue, uint16_t wIndex, uint16_t wLength) { + hw_set_address(wValue); + write(0, 0, 0); + return true; + } + + bool set_configuration(uint16_t wValue, uint16_t wIndex, uint16_t wLength) { + switch(wValue) { + case 0: + hw_conf_ep(1, 0); + break; + + case 1: + hw_conf_ep(1, (1 << 22) | (2 << 18) | (1 << 15) | 64); + break; + + default: + return false; + } + + write(0, 0, 0); + return true; + } + + + void handle_setup(const uint32_t* bufp) { + uint8_t bmRequestType = bufp[0] & 0xff; + uint8_t bRequest = (bufp[0] >> 8) & 0xff; + uint16_t wValue = (bufp[0] >> 16) & 0xffff; + uint16_t wIndex = bufp[1] & 0xffff; + uint16_t wLength = (bufp[1] >> 16) & 0xffff; + + // GET_DESCRIPTOR + if(bmRequestType == 0x80 && bRequest == 0x06) { + if(get_descriptor(wValue, wIndex, wLength)) { + return; + } + } + + // SET_ADDRESS + if(bmRequestType == 0x00 && bRequest == 0x05) { + if(set_address(wValue, wIndex, wLength)) { + return; + } + } + + // SET_CONFIGURATION + if(bmRequestType == 0x00 && bRequest == 0x09) { + if(set_configuration(wValue, wIndex, wLength)) { + return; + } + } + + SetupStatus res = SetupStatus::Unhandled; + + for(USB_class_driver*& handler : control_handlers) { + if(handler) { + res = handler->handle_setup(bmRequestType, bRequest, wValue, wIndex, wLength); + + if(res != SetupStatus::Unhandled) { + break; + } + } + } + + if(res == SetupStatus::Ok) { + return; + } + + hw_set_stall(0); + } + +}; + +#endif @@ -1,327 +1,11 @@ #ifndef USB_H #define USB_H -#include <stdint.h> +#if defined(STM32F4) +#include "dwc_otg.h" -struct USB_reg_t { - volatile uint32_t GOTGCTL; - volatile uint32_t GOTGINT; - volatile uint32_t GAHBCFG; - volatile uint32_t GUSBCFG; - volatile uint32_t GRSTCTL; - volatile uint32_t GINTSTS; - volatile uint32_t GINTMSK; - volatile uint32_t GRXSTSR; - volatile uint32_t GRXSTSP; - volatile uint32_t GRXFSIZ; - volatile uint32_t DIEPTXF0; - volatile uint32_t HNPTXSTS; - uint32_t _reserved[2]; - volatile uint32_t GCCFG; - volatile uint32_t CID; - uint32_t _reserved1[48]; - volatile uint32_t HPTXFSIZ; - volatile uint32_t DIEPTXF1; - volatile uint32_t DIEPTXF2; - volatile uint32_t DIEPTXF3; -}; - -struct USB_dev_reg_t { - volatile uint32_t DCFG; - volatile uint32_t DCTL; - volatile uint32_t DSTS; - uint32_t _reserved; - volatile uint32_t DIEPMSK; - volatile uint32_t DOEPMSK; - volatile uint32_t DAINT; - volatile uint32_t DAINTMSK; - uint32_t _reserved1[2]; - volatile uint32_t DVBUSDIS; - volatile uint32_t DVBUSPULSE; - uint32_t _reserved2; - volatile uint32_t DIEPEMPMSK; -}; - -struct USB_dev_iep_reg_t { - volatile uint32_t DIEPCTL; - uint32_t _reserved; - volatile uint32_t DIEPINT; - uint32_t _reserved1; - volatile uint32_t DIEPTSIZ; - uint32_t _reserved2; - volatile uint32_t DTXFSTS; - uint32_t _reserved3; -}; - -struct USB_dev_oep_reg_t { - volatile uint32_t DOEPCTL; - uint32_t _reserved; - volatile uint32_t DOEPINT; - uint32_t _reserved1; - volatile uint32_t DOEPTSIZ; - uint32_t _reserved2[3]; -}; - -union USB_fifo_reg_t { - volatile uint32_t reg; - volatile uint32_t buf[1024]; -}; - -class USB_t { - public: - USB_reg_t& reg; - USB_dev_reg_t& dev_reg; - USB_dev_iep_reg_t* const dev_iep_reg; - USB_dev_oep_reg_t* const dev_oep_reg; - USB_fifo_reg_t* const fifo; - - USB_t(uint32_t reg_addr) : - reg(*(USB_reg_t*)reg_addr), - dev_reg(*(USB_dev_reg_t*)(reg_addr + 0x800)), - dev_iep_reg((USB_dev_iep_reg_t*)(reg_addr + 0x900)), - dev_oep_reg((USB_dev_oep_reg_t*)(reg_addr + 0xb00)), - fifo((USB_fifo_reg_t*)(reg_addr + 0x1000)) {} -}; - -#if defined(STM32F1) - -#elif defined(STM32F4) -static USB_t OTG_FS(0x50000000); -static USB_t OTG_HS(0x40040000); +static DWC_OTG_t OTG_FS(0x50000000); +static DWC_OTG_t OTG_HS(0x40040000); #endif -static uint32_t buf[16]; - -struct desc_t { - uint32_t size; - void* data; -}; - -class USB_generic { - private: - desc_t dev_desc; - desc_t conf_desc; - - public: - USB_generic(desc_t dev, desc_t conf) : dev_desc(dev), conf_desc(conf) {} - - virtual bool ep_ready(uint32_t ep) = 0; - virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) = 0; - virtual void hw_set_address(uint8_t addr) = 0; - virtual void hw_conf_ep(uint8_t ep, uint32_t conf) = 0; - virtual void hw_set_stall(uint8_t ep) = 0; - - protected: - bool get_descriptor(uint16_t wValue, uint16_t wIndex, uint16_t wLength) { - desc_t* descp; - - switch(wValue) { - case 0x100: - descp = &dev_desc; - break; - case 0x200: - descp = &conf_desc; - break; - default: - return false; - } - - uint32_t* dp = (uint32_t*)descp->data; - uint32_t length = wLength > descp->size ? descp->size : wLength; - - while(length > 64) { - write(0, dp, 64); - dp += 16; - length -= 64; - - while(!ep_ready(0)); - } - - write(0, dp, length); - - return true; - } - - bool set_address(uint16_t wValue, uint16_t wIndex, uint16_t wLength) { - hw_set_address(wValue); - write(0, 0, 0); - return true; - } - - bool set_configuration(uint16_t wValue, uint16_t wIndex, uint16_t wLength) { - switch(wValue) { - case 0: - hw_conf_ep(1, 0); - break; - - case 1: - hw_conf_ep(1, (1 << 22) | (2 << 18) | (1 << 15) | 64); - break; - - default: - return false; - } - - write(0, 0, 0); - return true; - } - - - void handle_setup(const uint32_t* bufp) { - uint8_t bmRequestType = bufp[0] & 0xff; - uint8_t bRequest = (bufp[0] >> 8) & 0xff; - uint16_t wValue = (bufp[0] >> 16) & 0xffff; - uint16_t wIndex = bufp[1] & 0xffff; - uint16_t wLength = (bufp[1] >> 16) & 0xffff; - - // GET_DESCRIPTOR - if(bmRequestType == 0x80 && bRequest == 0x06) { - if(get_descriptor(wValue, wIndex, wLength)) { - return; - } - } - - // SET_ADDRESS - if(bmRequestType == 0x00 && bRequest == 0x05) { - if(set_address(wValue, wIndex, wLength)) { - return; - } - } - - // SET_CONFIGURATION - if(bmRequestType == 0x00 && bRequest == 0x09) { - if(set_configuration(wValue, wIndex, wLength)) { - return; - } - } - - // I2C_READ - //if(bmRequestType == 0xc0 && bRequest == 0xf0) { - // if(i2c_read(wValue, wIndex, wLength)) { - // return; - // } - //} - - // JTAG_SHIFT - //if(bmRequestType == 0xc0 && bRequest == 0xff) { - // if(jtag_shift(wValue, wIndex, wLength)) { - // return; - // } - //} - - hw_set_stall(0); - } - -}; - -class USB_otg : public USB_generic { - private: - USB_t& otg; - - protected: - virtual void hw_set_address(uint8_t addr) { - otg.dev_reg.DCFG |= addr << 4; - } - - virtual void hw_conf_ep(uint8_t ep, uint32_t conf) { - otg.dev_iep_reg[ep].DIEPCTL = conf; - } - - virtual void hw_set_stall(uint8_t ep) { - otg.dev_iep_reg[ep].DIEPCTL |= (1 << 21); - } - - public: - USB_otg(USB_t& otg_periph, desc_t dev, desc_t conf) : USB_generic(dev, conf), otg(otg_periph) {} - - void init() { - // Set PHYSEL. - otg.reg.GUSBCFG |= (1 << 6); - - Time::sleep(10); - - while(!(otg.reg.GRSTCTL & (1 << 31))); - otg.reg.GRSTCTL |= 1; - while(otg.reg.GRSTCTL & 1); - - otg.reg.GAHBCFG = 0; - - // USB configuration - otg.reg.GUSBCFG = (1 << 30) | (0xf << 10) | (0 << 9) | (0 << 8) | (1 << 6); - // FDMOD TRDT HNPCAP SRPCAP PHYSEL - - // interrupt mask - otg.reg.GINTMSK = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 4); - // ENUMDNEM USBRST USBSUSPM ESUSPM SOFM OTGINT MMISM - - // device configuration - otg.dev_reg.DCFG = (1 << 2) | 3; - // NZLSOHSK DSPD - - // core configuration - otg.reg.GCCFG = (1 << 19) | (1 << 16); - // VBUSBSEN PWRDWN - - } - - void process() { - // USB reset. - if(otg.reg.GINTSTS & (1 << 12)) { - otg.dev_oep_reg[0].DOEPCTL = (1 << 27); - otg.dev_reg.DAINTMSK = (1 << 16) | 1; - otg.dev_reg.DOEPMSK = (1 << 3) | 1; - otg.dev_reg.DIEPEMPMSK = (1 << 3) | 1; - otg.reg.GRXFSIZ = 256; - otg.reg.DIEPTXF0 = (64 << 16) | 256; - otg.reg.DIEPTXF1 = (64 << 16) | 320; - otg.dev_oep_reg[0].DOEPTSIZ = (3 << 29); - } - - // OTG interrupt. - if(otg.reg.GINTSTS & (1 << 2)) { - otg.reg.GOTGINT = (1 << 2); // SEDET - } - - // RxFIFO non-empty. - if(otg.reg.GINTSTS & (1 << 4)) { - handle_rxfifo(); - } - - otg.reg.GINTSTS = 0xffffffff; - } - - virtual bool ep_ready(uint32_t ep) { - return (otg.dev_iep_reg[ep].DIEPCTL & 0x80008000) == 0x8000; - } - - virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) { - otg.dev_iep_reg[ep].DIEPTSIZ = (1 << 19) | len; - // PKTCNT - otg.dev_iep_reg[ep].DIEPCTL |= (1 << 31) | (1 << 26); - // EPENA CNAK - - len = (len + 3) >> 2; - - while(len--) { - otg.fifo[ep].reg = *bufp++; - } - } - - void handle_rxfifo() { - uint32_t status = otg.reg.GRXSTSP; - - uint32_t len = (status & 0x7ff0) >> 6; - - for(uint32_t i = 0; i < len; i++) { - buf[i] = otg.fifo[0].reg; - } - - //if(status == 0x000c0080) { - if((status & (0xf << 17)) == (0x4 << 17)) { - handle_setup(buf); - otg.dev_oep_reg[0].DOEPCTL |= (1 << 26); - } - } -}; - #endif |