diff options
author | Vegard Storheil Eriksen <zyp@jvnv.net> | 2012-09-20 21:19:29 +0200 |
---|---|---|
committer | Vegard Storheil Eriksen <zyp@jvnv.net> | 2012-09-20 21:43:44 +0200 |
commit | d2e7c6170752b085bbfed155308511790984ccab (patch) | |
tree | 8e340f63c3d0e9c6db4f990a0283c7a7286f46bd | |
parent | 9bf644e65d5bb51a161b22da94f9718af29d02f1 (diff) |
Improved USB driver.
-rw-r--r-- | usb/dwc_otg.h | 97 | ||||
-rw-r--r-- | usb/dwc_otg_def.h | 4 | ||||
-rw-r--r-- | usb/generic.h | 23 |
3 files changed, 102 insertions, 22 deletions
diff --git a/usb/dwc_otg.h b/usb/dwc_otg.h index f206a44..5ad253f 100644 --- a/usb/dwc_otg.h +++ b/usb/dwc_otg.h @@ -13,13 +13,18 @@ class USB_otg : public USB_generic { uint32_t setup_buf[16]; + uint32_t buf_end; + void handle_rxfifo() { uint32_t status = otg.reg.GRXSTSP; - uint8_t ep = status & 0x4; + usb_rblog.log("RXFIFO status: %08x", status); + + uint8_t ep = status & 0xf; uint32_t len = (status & 0x7ff0) >> 4; uint32_t type = status & (0xf << 17); + rxfifo_ep = ep; rxfifo_bytes = len; // OUT packet. @@ -34,9 +39,11 @@ class USB_otg : public USB_generic { } rxfifo_bytes = 0; - + } + + if(type == (0x4 << 17)) { handle_setup(setup_buf); - otg.dev_oep_reg[0].DOEPCTL |= (1 << 26); // CNAK + otg.dev_oep_reg[0].DOEPCTL |= (1 << 31) | (1 << 26); // CNAK } // Discard remaining bytes from FIFO. @@ -44,16 +51,56 @@ class USB_otg : public USB_generic { (void)otg.fifo[0].reg; } + if(type == (0x2 << 17) && ep != 0) { + otg.dev_oep_reg[ep].DOEPCTL |= (1 << 31) | (1 << 26); // CNAK + } + rxfifo_bytes = 0; } protected: virtual void hw_set_address(uint8_t addr) { + usb_rblog.log("SetAddress: %d", 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_conf_ep(uint8_t ep, EPType type, uint32_t size) { + usb_rblog.log("Configuring EP%02x: size=%d", ep, size); + + uint8_t in = ep & 0x80; + ep &= 0x7f; + + uint32_t epctl = ((type == Control ? 0 : type == Isochronous ? 1 : type == Bulk ? 2 : 3) << 18); + epctl |= (1 << 31) | (1 << 28) | (1 << 15) | (ep == 0 ? 64 : size); // EPENA, USBAEP, SD0PID + + if(ep == 0) { + otg.reg.GRXFSIZ = 64; + buf_end = 64; + + otg.reg.DIEPTXF0 = (buf_end << 16) | (64 >> 2); + buf_end += (64 >> 2); + + otg.dev_iep_reg[ep].DIEPTSIZ = size; + otg.dev_oep_reg[ep].DOEPTSIZ = (1 << 29) | (1 << 19) | size; + + otg.dev_iep_reg[ep].DIEPCTL = epctl | (1 << 27); // SNAK + otg.dev_oep_reg[ep].DOEPCTL = epctl | (1 << 26); // CNAK + + return; + } + + if(in) { + otg.dev_iep_reg[ep].DIEPTSIZ = size; + otg.dev_iep_reg[ep].DIEPCTL = epctl | (1 << 27) | (ep << 22); // SNAK + + } else { + otg.reg.DIEPTXF[ep - 1] = (buf_end << 16) | (size >> 2); + buf_end += (size >> 2); + + otg.dev_oep_reg[ep].DOEPTSIZ = (1 << 19) | size; + otg.dev_oep_reg[ep].DOEPCTL = epctl | (1 << 26); // CNAK + } } virtual void hw_set_stall(uint8_t ep) { @@ -94,31 +141,45 @@ class USB_otg : public USB_generic { } void process() { + uint32_t gintsts = otg.reg.GINTSTS; + // USB reset. - if(otg.reg.GINTSTS & (1 << 12)) { - handle_reset(); + if(gintsts & (1 << 12)) { + usb_rblog.log("USB Reset"); + otg.dev_reg.DCFG = (1 << 2) | 3; otg.dev_oep_reg[0].DOEPCTL = (1 << 27); + otg.dev_oep_reg[1].DOEPCTL = (1 << 27); + otg.dev_oep_reg[2].DOEPCTL = (1 << 27); + otg.dev_oep_reg[3].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); + + buf_end = 0; + + handle_reset(); + + otg.reg.GINTSTS = 1 << 12; + } + + // Enumeration done. + if(gintsts & (1 << 13)) { + usb_rblog.log("Enumeration done"); + + otg.reg.GINTSTS = 1 << 13; + otg.dev_iep_reg[0].DIEPCTL = 0; // MPSIZ = 64 bytes. } // OTG interrupt. - if(otg.reg.GINTSTS & (1 << 2)) { + if(gintsts & (1 << 2)) { otg.reg.GOTGINT = (1 << 2); // SEDET } // RxFIFO non-empty. - if(otg.reg.GINTSTS & (1 << 4)) { + if(gintsts & (1 << 4)) { handle_rxfifo(); } - - otg.reg.GINTSTS = 0xffffffff; } virtual bool ep_ready(uint32_t ep) { @@ -126,6 +187,8 @@ class USB_otg : public USB_generic { } virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) { + usb_rblog.log("Writing, ep=%d, len=%d", ep, len); + otg.dev_iep_reg[ep].DIEPTSIZ = (1 << 19) | len; // PKTCNT otg.dev_iep_reg[ep].DIEPCTL |= (1 << 31) | (1 << 26); @@ -139,6 +202,8 @@ class USB_otg : public USB_generic { } virtual uint32_t read(uint32_t ep, uint32_t* bufp, uint32_t len) { + usb_rblog.log("Reading, ep=%d, len=%d", ep, len); + if(ep != rxfifo_ep) { return 0; } @@ -155,6 +220,8 @@ class USB_otg : public USB_generic { rxfifo_bytes -= len; + usb_rblog.log("Read %d bytes.", len); + return len; } }; diff --git a/usb/dwc_otg_def.h b/usb/dwc_otg_def.h index 2f19116..6ed6ba8 100644 --- a/usb/dwc_otg_def.h +++ b/usb/dwc_otg_def.h @@ -23,9 +23,7 @@ class DWC_OTG_t { volatile uint32_t CID; uint32_t _reserved1[48]; volatile uint32_t HPTXFSIZ; - volatile uint32_t DIEPTXF1; - volatile uint32_t DIEPTXF2; - volatile uint32_t DIEPTXF3; + volatile uint32_t DIEPTXF[5]; }; struct DWC_OTG_dev_reg_t { diff --git a/usb/generic.h b/usb/generic.h index 60c89c4..d5c12ff 100644 --- a/usb/generic.h +++ b/usb/generic.h @@ -3,12 +3,17 @@ #include <stdint.h> +#include <util/rblog.h> + +RBLog<256, 2> usb_rblog; + struct desc_t { uint32_t size; void* data; }; enum SetupStatus {Unhandled, Ok, Stall}; +enum EPType {Control, Bulk, Interrupt, Isochronous}; class USB_class_driver { friend class USB_generic; @@ -36,7 +41,7 @@ class USB_generic { virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) = 0; virtual uint32_t read(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_conf_ep(uint8_t ep, EPType type, uint32_t size) = 0; virtual void hw_set_stall(uint8_t ep) = 0; bool register_control_handler(USB_class_driver* control_handler) { @@ -101,11 +106,11 @@ class USB_generic { 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); + hw_conf_ep(0x01, Bulk, 64); + hw_conf_ep(0x81, Bulk, 64); break; default: @@ -117,7 +122,7 @@ class USB_generic { } void handle_reset() { - + hw_conf_ep(0, Control, 64); } void handle_setup(const uint32_t* bufp) { @@ -127,6 +132,10 @@ class USB_generic { uint16_t wIndex = bufp[1] & 0xffff; uint16_t wLength = (bufp[1] >> 16) & 0xffff; + usb_rblog.log("handle_setup, bmRequestType=%02x, bRequest=%02x", bmRequestType, bRequest); + + out_handlers[0] = nullptr; + // GET_DESCRIPTOR if(bmRequestType == 0x80 && bRequest == 0x06) { if(get_descriptor(wValue, wIndex, wLength)) { @@ -154,6 +163,10 @@ class USB_generic { if(handler) { res = handler->handle_setup(bmRequestType, bRequest, wValue, wIndex, wLength); + if(res == SetupStatus::Ok) { + out_handlers[0] = handler; + } + if(res != SetupStatus::Unhandled) { break; } @@ -168,6 +181,8 @@ class USB_generic { } void handle_out(uint8_t ep, uint32_t len) { + usb_rblog.log("handle_out, ep=%02x, len=%d", ep, len); + if(out_handlers[ep]) { out_handlers[ep]->handle_out(ep, len); } |