| #ifndef LAKS_USB_USB_NRF_H
#define LAKS_USB_USB_NRF_H
#include "generic.h"
#include "usb_nrf_def.h"
#include <string.h>
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
|