summaryrefslogtreecommitdiff
path: root/usb
diff options
context:
space:
mode:
authorVegard Storheil Eriksen <zyp@jvnv.net>2012-09-20 21:19:29 +0200
committerVegard Storheil Eriksen <zyp@jvnv.net>2012-09-20 21:43:44 +0200
commitd2e7c6170752b085bbfed155308511790984ccab (patch)
tree8e340f63c3d0e9c6db4f990a0283c7a7286f46bd /usb
parent9bf644e65d5bb51a161b22da94f9718af29d02f1 (diff)
Improved USB driver.
Diffstat (limited to 'usb')
-rw-r--r--usb/dwc_otg.h97
-rw-r--r--usb/dwc_otg_def.h4
-rw-r--r--usb/generic.h23
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);
}