#ifndef LAKS_USB_USB_NRF_H #define LAKS_USB_USB_NRF_H #include "generic.h" #include "usb_nrf_def.h" #include class USB_NRF : public USB_generic { private: USB_NRF_t& usb; uint32_t ep_in_busy; uint8_t buf_in[8][64]; uint8_t buf_out[8][64]; protected: virtual void hw_set_address(uint8_t addr) { usb_rblog.log("SetAddress: %d", addr); // Do nothing, handled in hardware. } 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; if(in || ep == 0) { usb.reg_in[ep].PTR = (uint32_t)&buf_in[ep]; usb.reg.EPINEN |= 1 << ep; } if(!in) { usb.reg_out[ep].PTR = (uint32_t)&buf_out[ep]; usb.reg.SIZE_EPOUT[ep] = 0; usb.reg.EPOUTEN |= 1 << ep; } } virtual void hw_set_stall(uint8_t ep) { if(ep == 0) { usb.tasks.EP0STALL = 1; } } public: USB_NRF(USB_NRF_t& usb_periph, desc_t dev, desc_t conf) : USB_generic(dev, conf), usb(usb_periph) {} void init() { *(volatile uint32_t*)0x4006ec00 = 0x00009375; *(volatile uint32_t*)0x4006ed14 = 0x00000003; *(volatile uint32_t*)0x4006ec00 = 0x00009375; usb.reg.ENABLE = 1; while(!(usb.reg.EVENTCAUSE & (1 << 11))); usb.reg.EVENTCAUSE = 1 << 11; *(volatile uint32_t*)0x4006ec00 = 0x00009375; *(volatile uint32_t*)0x4006ed14 = 0x00000000; *(volatile uint32_t*)0x4006ec00 = 0x00009375; usb.reg.USBPULLUP = 1; } void process() { if(usb.events.USBRESET) { usb.events.USBRESET = 0; usb_rblog.log("USB Reset"); handle_reset(); return; } if(usb.events.EP0SETUP) { usb.events.EP0SETUP = 0; uint8_t setupbuf[8] = { (uint8_t)usb.reg.BMREQUESTTYPE, (uint8_t)usb.reg.BREQUEST, (uint8_t)usb.reg.WVALUEL, (uint8_t)usb.reg.WVALUEH, (uint8_t)usb.reg.WINDEXL, (uint8_t)usb.reg.WINDEXH, (uint8_t)usb.reg.WLENGTHL, (uint8_t)usb.reg.WLENGTHH, }; handle_setup((uint32_t*)&setupbuf); } if(usb.events.EP0DATADONE) { // TODO: Support multi-packet data stages. usb.events.EP0DATADONE = 0; usb_rblog.log("Control data IN done, ACKing status stage."); usb.tasks.EP0STATUS = 1; } /* for(uint32_t ep = 0; ep <= 7; ep++) { if(usb.events.ENDEPIN[ep]) { usb.events.ENDEPIN[ep] = 0; ep_in_busy &= ~(1 << ep); } } */ if(usb.reg.EPDATASTATUS) { for(uint32_t ep = 1; ep <= 7; ep++) { if((usb.reg.EPDATASTATUS & ((1 << 16) << ep)) == 0) { continue; } usb_rblog.log("EPDATA, starting DMA on ep %d", ep); usb.reg.EPDATASTATUS = (1 << 16) << ep; usb.reg_out[ep].MAXCNT = usb.reg.SIZE_EPOUT[ep]; usb.tasks.STARTEPOUT[ep] = 1; } } for(uint32_t ep = 0; ep <= 7; ep++) { if(usb.events.ENDEPOUT[ep]) { usb.events.ENDEPOUT[ep] = 0; handle_out(ep, usb.reg_out[ep].AMOUNT); } } } virtual bool ep_ready(uint32_t ep) { //if(usb.events.ENDEPIN[ep]) { // usb.events.ENDEPIN[ep] = 0; // ep_in_busy &= ~(1 << ep); //} if(usb.reg.EPDATASTATUS & (1 << ep)) { usb.reg.EPDATASTATUS = 1 << ep; ep_in_busy &= ~(1 << ep); } return (ep_in_busy & (1 << ep)) == 0; } virtual void write(uint32_t ep, uint32_t* bufp, uint32_t len) { usb_rblog.log("Writing, ep=%d, len=%d", ep, len); if(ep == 0 && len == 0 && (usb.reg.BMREQUESTTYPE & 0x80) == 0) { usb_rblog.log("EP0 status ACK"); usb.tasks.EP0STATUS = 1; return; } memcpy(&buf_in[ep], bufp, len); usb.reg_in[ep].MAXCNT = len; usb.tasks.STARTEPIN[ep] = 1; ep_in_busy |= 1 << ep; } virtual uint32_t read(uint32_t ep, uint32_t* bufp, uint32_t len) { usb_rblog.log("Reading, ep=%d, len=%d", ep, len); if(len > usb.reg_out[ep].AMOUNT) { len = usb.reg_out[ep].AMOUNT; } memcpy(bufp, &buf_out[ep], len); return len; } }; #endif