[usb] Handle Setup and in packets from host.

Change-Id: I9ffc2705af3c30389b30fdcac34e9e3a1a97a3d7
This commit is contained in:
Léa Saviot
2018-02-06 18:08:55 +01:00
parent 46eaac5054
commit 1a8062e365
3 changed files with 759 additions and 35 deletions

View File

@@ -20,6 +20,9 @@ public:
class GRSTCTL : public Register32 {
public:
REGS_BOOL_FIELD(CSRST, 0);
REGS_BOOL_FIELD(RXFFLSH, 4);
REGS_BOOL_FIELD(TXFFLSH, 5);
REGS_FIELD(TXFNUM, uint8_t, 10, 6);
REGS_BOOL_FIELD(AHBIDL, 31);
};
@@ -32,6 +35,7 @@ public:
REGS_BOOL_FIELD(USBSUSP, 11);
REGS_BOOL_FIELD(USBRST, 12);
REGS_BOOL_FIELD(ENUMDNE, 13);
REGS_BOOL_FIELD(IEPINT, 18);
REGS_BOOL_FIELD(WKUPINT, 31);
};
@@ -46,6 +50,21 @@ public:
REGS_BOOL_FIELD(WUIM, 31);
};
class GRXSTSP : public Register32 {
public:
using Register32::Register32;
enum class PKTSTS {
GlobalOutNAK = 1,
OutReceived = 2,
OutCompleted = 3,
SetupCompleted = 4,
SetupReceived = 6
};
REGS_FIELD(EPNUM, uint8_t, 3, 0);
REGS_FIELD(BCNT, uint16_t, 14, 4);
PKTSTS getPKTSTS() volatile { return (PKTSTS)getBitRange(20, 17); }
};
class GRXFSIZ : public Register32 {
public:
REGS_FIELD(RXFD, uint16_t, 15, 0);
@@ -96,6 +115,9 @@ public:
Size8 = 3
};
void setMPSIZ(MPSIZ s) volatile { setBitRange(1, 0, (uint8_t)s); }
REGS_BOOL_FIELD(STALL, 21);
REGS_FIELD(TXFNUM, uint8_t, 25, 22);
REGS_BOOL_FIELD(CNAK, 26);
REGS_BOOL_FIELD(SNAK, 27);
REGS_BOOL_FIELD(EPENA, 31);
};
@@ -103,6 +125,14 @@ public:
class DIEPTSIZ0 : public Register32 {
public:
REGS_FIELD(XFRSIZ, uint8_t, 6, 0);
REGS_FIELD(PKTCNT, uint8_t, 20, 19);
};
class DOEPCTL0 : public Register32 {
public:
REGS_BOOL_FIELD(CNAK, 26);
REGS_BOOL_FIELD(SNAK, 27);
REGS_BOOL_FIELD(EPENA, 31);
};
class DOEPTSIZ0 : public Register32 {
@@ -116,6 +146,7 @@ public:
class DIEPINT : public Register32 {
public:
REGS_BOOL_FIELD(XFRC, 0);
REGS_BOOL_FIELD(INEPNE, 6);
};
class PCGCCTL : public Register32 {
@@ -124,12 +155,16 @@ public:
REGS_BOOL_FIELD(STPPCLK, 1);
};
class DFIFO0 : public Register32 {
};
constexpr OTG() {};
REGS_REGISTER_AT(GAHBCFG, 0x008);
REGS_REGISTER_AT(GUSBCFG, 0x00C);
REGS_REGISTER_AT(GRSTCTL, 0x010);
REGS_REGISTER_AT(GINTSTS, 0x014);
REGS_REGISTER_AT(GINTMSK, 0x018);
REGS_REGISTER_AT(GRXSTSP, 0x020);
REGS_REGISTER_AT(GRXFSIZ, 0x024);
REGS_REGISTER_AT(DIEPTXF0, 0x28);
REGS_REGISTER_AT(GCCFG, 0x038);
@@ -139,8 +174,10 @@ public:
REGS_REGISTER_AT(DAINTMSK, 0x81C);
REGS_REGISTER_AT(DIEPCTL0, 0x900);
REGS_REGISTER_AT(DIEPTSIZ0, 0x910);
REGS_REGISTER_AT(DOEPCTL0, 0xB00);
REGS_REGISTER_AT(DOEPTSIZ0, 0xB10);
REGS_REGISTER_AT(PCGCCTL, 0xE00);
REGS_REGISTER_AT(DFIFO0, 0x1000);
constexpr volatile DIEPINT * DIEPINT(int i) const {
return (class DIEPINT *)(Base() + 0xB08 + i*0x20);
}

View File

@@ -18,29 +18,96 @@ namespace Device {
#include <stdlib.h>
static const struct DeviceDescriptor deviceDescriptor = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = 0,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = USB_MAX_PACKET_SIZE,
.idVendor = 0xcafe, //TODO Buy one!
.idProduct = 0xcafe, //TODO Create one!
.bcdDevice = 0x0001,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1
};
static const struct ConfigDescriptor configDescriptor = {
.bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = USB_DT_CONFIGURATION_SIZE+USB_DT_INTERFACE_SIZE, //TODO The example puts 0 here.
.bNumInterfaces = 1,
.bConfigurationValue = USB_DFU_CONFIGURATION_VALUE,
.iConfiguration = 0,
.bmAttributes = 0x80,
.bMaxPower = 0x32
};
static const struct InterfaceDescriptor interfaceDescriptor = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0, /* Alternate settings can be used by an application to access additional memory segments */
.bNumEndpoints = 0,
.bInterfaceClass = USB_CLASS_APPLICATION_SPECIFIC,
.bInterfaceSubClass = USB_SUBCLASS_DFU,
.bInterfaceProtocol = USB_PROTOCOL_DFU,
.iInterface = 0
};
SetupData sSetupData;
uint16_t sRxPacketSize;
// TODO Explain those two buffers
/* Buffer used for control requests. */
static uint8_t sControlBufferInit[5*64]; // TODO why 5*64? (from libopencm3/tests/gadget-zero/usb-gadget0.c)
static uint16_t sControlBufferInitLength = sizeof(sControlBufferInit);
uint8_t * sControlBuffer;
uint16_t sControlBufferLength;
bool sZLPNeeded; /* True if the device needs to send a Zero-Length Packet */
bool sForceNAK = false;
ControlState sControlState;
void usb_endpoint_setup() {
// Configure IN
// To configure depending on the endpoint
/* Set the maximum packet size */
OTG.DIEPCTL0()->setMPSIZ(OTG::DIEPCTL0::MPSIZ::Size64);
// Set depending on size
/* Transfer size */
OTG.DIEPTSIZ0()->setXFRSIZ(64);
OTG.DIEPCTL0()->setEPENA(true);
/* Set the NAK bit */
OTG.DIEPCTL0()->setSNAK(true);
/* Enable the endpoint */
OTG.DIEPCTL0()->setEPENA(true);
// Configure OUT
class OTG::DOEPTSIZ0 doeptsiz0(0);
doeptsiz0.setSTUPCNT(1);
/* Max number of back-to-back setup packets that can be received */
doeptsiz0.setSTUPCNT(1); //TODO 3 in the spec
doeptsiz0.setPKTCNT(true);
/* Transfer size */
doeptsiz0.setXFRSIZ(64);
OTG.DOEPTSIZ0()->set(doeptsiz0);
/* Set the NAK bit */
OTG.DOEPCTL0()->setSNAK(true);
/* Enable the endpoint */
OTG.DOEPCTL0()->setEPENA(true);
/* Endpoint0 Tx FIFO depth */
OTG.DIEPTXF0()->setTX0FD(64/4);
//OTG.DIEPTXF0().setTX0FSA(fifo/4);
OTG.DIEPTXF0()->setTX0FSA(128 + 64/4); // TODO ?
}
void usb_endpoints_reset() {
/* There are no additional endpoints to reset */
/* Flush tx/rx fifo */
flushTxFifo();
flushRxFifo();
}
void usb_set_address(uint8_t address) {
@@ -50,42 +117,512 @@ void usb_set_address(uint8_t address) {
void poll() {
class OTG::GINTSTS intsts(OTG.GINTSTS()->get());
if (intsts.getENUMDNE()) {
abort();
// **SPEED** enumeration done
/* Handle USB RESET condition. */
OTG.GINTSTS()->setENUMDNE(true); //Clear the ENUMDNE bit.
usb_endpoint_setup();
usb_set_address(0);
return;
}
// There is no global interrupt flag for transmit complete.
// The XFRC bit must be checked in each OTG_DIEPINT(x).
for (int i=0; i<4; i++) { // Iterate over endpoints
if (OTG.DIEPINT(i)->getXFRC()) {
/* Transfer complete. */
// USB transaction in
abort();
}
/* TODO There is no global interrupt flag for transmit complete.
* The XFRC bit must be checked in each OTG_DIEPINT(x). */
if (OTG.DIEPINT(0)->getXFRC()) {//intsts.getIEPINT()) {
controlIn();
OTG.DIEPINT(0)->setXFRC(true); // This bit is cleared by writing 1 to it.
}
if (intsts.getRXFLVL()) {
abort();
}
/* Receive FIFO non-empty. */
class OTG::GRXSTSP grxstsp(OTG.GRXSTSP()->get());
OTG::GRXSTSP::PKTSTS pktsts = grxstsp.getPKTSTS();
uint8_t ep = grxstsp.getEPNUM();
if (pktsts == OTG::GRXSTSP::PKTSTS::OutCompleted
|| pktsts == OTG::GRXSTSP::PKTSTS::SetupCompleted)
{
if (ep == 0) {
class OTG::DOEPTSIZ0 doeptsiz0(0);
/* Max number of back-to-back setup packets that can be received */
doeptsiz0.setSTUPCNT(1); //TODO 3 in the spec
doeptsiz0.setPKTCNT(true);
/* Transfer size */
doeptsiz0.setXFRSIZ(64);
OTG.DOEPTSIZ0()->set(doeptsiz0);
/* Enable the endpoint */
OTG.DOEPCTL0()->setEPENA(true);
/* Set the NAK bit */
if (sForceNAK) {
OTG.DOEPCTL0()->setSNAK(true);
} else {
OTG.DOEPCTL0()->setCNAK(true);
}
}
return;
}
if (pktsts != OTG::GRXSTSP::PKTSTS::OutReceived
&& pktsts != OTG::GRXSTSP::PKTSTS::SetupReceived)
{
return;
}
USBTransaction type = USBTransaction::Setup;
if (pktsts == OTG::GRXSTSP::PKTSTS::OutReceived) {
type = USBTransaction::Out;
}
if (type == USBTransaction::Setup && OTG.DIEPTSIZ0()->getPKTCNT()) {
/* SETUP received but there is still something stuck in the transmit fifo.
* Flush it. */
flushTxFifo();
}
/* Save packet size */
sRxPacketSize = grxstsp.getBCNT();
if (type == USBTransaction::Setup) {
controlSetup();
} else {
assert(type == USBTransaction::Out);
controlOut();
}
/* Discard unread packet data. */
for (int i = 0; i < sRxPacketSize; i += 4) {
/* There is only one receive FIFO */
OTG.DFIFO0()->get();
}
sRxPacketSize = 0;
}
if (intsts.getUSBSUSP()) {
// Suspend was detected on the USB bus
//abort();
OTG.GINTSTS()->setUSBSUSP(true); // Clear the interrupt
}
if (intsts.getWKUPINT()) {
abort();
OTG.GINTSTS()->setWKUPINT(true); // Clear the interrupt
}
if (intsts.getSOF()) {
abort();
OTG.GINTSTS()->setSOF(true); // Clear the interrupt
}
}
void controlSetup() {
endpoint0SetNak(true);
// Read the 8-bytes Setup packet
if (endpoint0ReadPacket(&sSetupData, 8) != 8) {
endpoint0StallTransaction();
return;
};
if (sSetupData.wLength == 0) {
controlSetupIn();
} else if (bmRequestTypeDirection(sSetupData.bmRequestType) == DataDirection::In) {
controlSetupIn();
} else {
assert(bmRequestTypeDirection(sSetupData.bmRequestType) == DataDirection::Out);
controlSetupOut();
}
}
void controlIn() {
switch (sControlState) {
case ControlState::DATA_IN:
controlSendChunk();
break;
case ControlState::LAST_DATA_IN:
sControlState = ControlState::STATUS_OUT;
endpoint0SetNak(false);
break;
case ControlState::STATUS_IN:
/*if (usbd_dev->control_state.complete) {
usbd_dev->control_state.complete(usbd_dev,
&(usbd_dev->control_state.req));
}*/
/* Exception: Handle SET ADDRESS function here... */
if ((sSetupData.bmRequestType == 0) && (sSetupData.bRequest == USB_REQ_SET_ADDRESS)) {
usb_set_address(sSetupData.wValue);
}
sControlState = ControlState::IDLE;
break;
default:
endpoint0StallTransaction();
}
}
DataDirection bmRequestTypeDirection(uint8_t bmRequestType) {
if (bmRequestType & 0x80) {
return DataDirection::In;
}
return DataDirection::Out;
}
int descriptorIndexFromWValue(uint16_t wValue) {
return wValue & 0xFF;
}
int descriptorTypeFromWValue(uint16_t wValue) {
return wValue >> 8;
}
void controlSetupIn() {
sControlBuffer = sControlBufferInit;
sControlBufferLength = sSetupData.wLength;
if (controlRequestDispatch()) {
if (sSetupData.wLength) {
// The host is waiting for device data. Check if we need to send a Zero
// Length Packet to explicit a short transaction.
sZLPNeeded = zlpIsNeeded(sControlBufferLength, sSetupData.wLength, deviceDescriptor.bMaxPacketSize0);
// Send the data.
controlSendChunk();
} else {
/* If no data is expected, send a zero length packet. */
endpoint0WritePacket(NULL, 0);
sControlState = ControlState::STATUS_IN;
}
} else {
/* Stall endpoint on failure. */
endpoint0StallTransaction();
}
}
void controlSendChunk() {
if (deviceDescriptor.bMaxPacketSize0 < sControlBufferLength) {
/* Data stage, normal transmission */
endpoint0WritePacket(sControlBuffer, deviceDescriptor.bMaxPacketSize0);
sControlState = ControlState::DATA_IN;
sControlBuffer += deviceDescriptor.bMaxPacketSize0;
sControlBufferLength -= deviceDescriptor.bMaxPacketSize0;
} else {
/* Data stage, end of transmission */
endpoint0WritePacket(sControlBuffer, deviceDescriptor.bMaxPacketSize0);
sControlState = sZLPNeeded ? ControlState::DATA_IN : ControlState::LAST_DATA_IN;
sZLPNeeded = false;
sControlBufferLength = 0;
sControlBuffer = NULL;
}
}
uint16_t endpoint0WritePacket(const void *buffer, uint16_t length) {
const uint32_t * buf32 = (uint32_t *) buffer;
/* Return if endpoint is already enabled. */ //TODO Why?
if (OTG.DIEPTSIZ0()->getPKTCNT()) {
return 0;
}
/* Enable endpoint for transmission. */
OTG.DIEPTSIZ0()->setPKTCNT(length);
OTG.DIEPCTL0()->setEPENA(true);
OTG.DIEPCTL0()->setCNAK(true);
/* Copy buffer to endpoint FIFO, note - memcpy does not work */
for (int i = length; i > 0; i -= 4) {
OTG.DFIFO0()->set(*buf32++);
}
return length;
}
void endpoint0StallTransaction() {
// Set endpoint stall
OTG.DIEPCTL0()->setSTALL(true);
// Set the control state to IDLE
sControlState = ControlState::IDLE;
}
void endpoint0SetNak(bool nak) {
sForceNAK = nak;
if (nak) {
OTG.DOEPCTL0()->setSNAK(true);
return;
}
OTG.DOEPCTL0()->setCNAK(true);
}
int controlRequestDispatch() {
switch (sSetupData.bRequest) {
case USB_REQ_GET_STATUS:
//TODO Not needed for enumeration?
break;
case USB_REQ_CLEAR_FEATURE:
case USB_REQ_SET_FEATURE:
//TODO Not needed for enumeration?
break;
case USB_REQ_SET_ADDRESS:
if ((sSetupData.bmRequestType != 0) || (sSetupData.wValue >= 128)) {
return 0;
}
/* The address should be set after the Status stage of the current
* transaction. This way, the device can reveice the IN ADDR 0 EP 0 packet
* that begins the status phase. */
return 1;
break;
case USB_REQ_GET_DESCRIPTOR:
return controlSetupGetDescriptor();
break;
case USB_REQ_SET_DESCRIPTOR:
//TODO Not needed for enumeration?
break;
case USB_REQ_SET_CONFIGURATION:
return controlSetupSetConfiguration();
case USB_REQ_GET_CONFIGURATION:
//TODO Not needed for enumeration?
break;
default:
break;
}
return 0;
}
int controlSetupGetDescriptor() {
int descriptorIndex = descriptorIndexFromWValue(sSetupData.wValue);
switch (descriptorTypeFromWValue(sSetupData.wValue)) {
case USB_DT_DEVICE:
sControlBuffer = (uint8_t *)(&deviceDescriptor);
sControlBufferLength = MIN(sControlBufferLength, deviceDescriptor.bLength);
return (int) RequestReturnCodes::USBD_REQ_HANDLED;
case USB_DT_CONFIGURATION:
sControlBuffer = sControlBufferInit;
sControlBufferLength = buildConfigDescriptor(descriptorIndex);
return (int) RequestReturnCodes::USBD_REQ_HANDLED;
case USB_DT_STRING:
struct StringDescriptor * stringDescriptor = (struct StringDescriptor *)sControlBufferInit;
if (descriptorIndex == 0) {
/* Send sane Language ID descriptor. */
stringDescriptor->wData[0] = USB_LANGID_ENGLISH_US;
stringDescriptor->bLength = sizeof(stringDescriptor->bLength) +
sizeof(stringDescriptor->bDescriptorType) +
sizeof(stringDescriptor->wData[0]);
sControlBufferLength = MIN(sControlBufferLength, stringDescriptor->bLength);
} else {
int arrayIndex = descriptorIndex - 1;
/* Check that string index is in range. */
if (arrayIndex >= sNumberOfStrings) {
return (int) RequestReturnCodes::USBD_REQ_NOTSUPP;
}
/* Strings with Language ID different from USB_LANGID_ENGLISH_US are not
* supported */
if (sSetupData.wIndex != USB_LANGID_ENGLISH_US) {
return (int) RequestReturnCodes::USBD_REQ_NOTSUPP;
}
/* This string is returned as UTF16, hence the multiplication */
stringDescriptor->bLength = strlen(sStrings[arrayIndex]) * 2 +
sizeof(stringDescriptor->bLength) +
sizeof(stringDescriptor->bDescriptorType);
sControlBufferLength = MIN(sControlBufferLength, stringDescriptor->bLength);
for (int i = 0; i < (sControlBufferLength / 2) - 1; i++) {
stringDescriptor->wData[i] = sStrings[arrayIndex][i];
}
}
stringDescriptor->bDescriptorType = USB_DT_STRING;
sControlBuffer = (uint8_t *)stringDescriptor;
return (int) RequestReturnCodes::USBD_REQ_HANDLED;
}
return (int) RequestReturnCodes::USBD_REQ_NOTSUPP;
}
uint16_t buildConfigDescriptor(uint8_t index) {
uint8_t *tmpbuf = sControlBuffer;
uint16_t count = MIN(sControlBufferLength, configDescriptor.bLength);
memcpy(sControlBuffer, &configDescriptor, count);
sControlBuffer += count;
sControlBufferLength -= count;
uint16_t total = count;
uint16_t totalLength = configDescriptor.bLength;
/* For now, we have one interface only */
assert(configDescriptor.bNumInterfaces == 1);
/* The interface has no Interface Association Descriptor and one setting only */
/* Copy interface descriptor. */
count = MIN(sControlBufferLength, interfaceDescriptor.bLength);
memcpy(sControlBuffer, &interfaceDescriptor, count);
sControlBuffer += count;
sControlBufferLength -= count;
total += count;
totalLength += interfaceDescriptor.bLength;
/* We have no additional endpoints for this interface */
/* Fill in wTotalLength. */
*(uint16_t *)(tmpbuf + 2) = totalLength;
return total;
}
/* If the device needs to reply data, but less than what the host expects and a
* multiple of the endpoint max packet size, the device needs to explicit the
* end of the transfer by sending a Zero Length Data Packet. */
bool zlpIsNeeded(uint16_t dataLength, uint16_t dataExpectedLength, uint8_t endpointMaxPacketSize) {
if (dataLength < dataExpectedLength) {
if (/* TODO I do not think this condition is needed: dataLength && */dataLength % endpointMaxPacketSize == 0) {
return true;
}
}
return false;
}
void controlSetupOut() {
if (sSetupData.wLength > sControlBufferInitLength) {
endpoint0StallTransaction();
return;
}
/* Buffer into which to write received data. */
sControlBuffer = sControlBufferInit;
sControlBufferLength = 0;
/* Wait for DATA OUT stage. */
if (sSetupData.wLength > deviceDescriptor.bMaxPacketSize0) {
sControlState = ControlState::DATA_OUT;
} else {
sControlState = ControlState::LAST_DATA_OUT;
}
endpoint0SetNak(false);
}
int controlSetupSetConfiguration() {
/* We support one configuration only */
if (sSetupData.wValue != 0 || sSetupData.wValue != USB_DFU_CONFIGURATION_VALUE) {
return (int) RequestReturnCodes::USBD_REQ_NOTSUPP;
}
/* Because there is one configuration only, no need to set it again. */
/* Reset all endpoints. */
usb_endpoints_reset();
return (int) RequestReturnCodes::USBD_REQ_HANDLED;
}
void controlOut() {
switch (sControlState) {
case ControlState::DATA_OUT:
if (controlReceiveChunk() < 0) {
break;
}
if ((sSetupData.wLength - sControlBufferLength) <= deviceDescriptor.bMaxPacketSize0) {
sControlState = ControlState::LAST_DATA_OUT;
}
break;
case ControlState::LAST_DATA_OUT:
if (controlReceiveChunk() < 0) {
break;
}
/*
* We have now received the full data payload.
* Invoke callback to process.
*/
if (controlRequestDispatch()) {
/* Go to status stage on success. */
endpoint0WritePacket(NULL, 0); //TODO Why?
sControlState = ControlState::STATUS_IN;
} else {
endpoint0StallTransaction();
}
break;
case ControlState::STATUS_OUT:
endpoint0ReadPacket(NULL, 0); //TODO Why?
sControlState = ControlState::IDLE;
break;
default:
endpoint0StallTransaction();
}
}
int controlReceiveChunk() {
uint16_t packetsize = MIN(deviceDescriptor.bMaxPacketSize0, sSetupData.wLength - sControlBufferLength);
uint16_t size = endpoint0ReadPacket(sControlBuffer + sControlBufferLength, packetsize); //TODO Pourquoi avance-t'on avant de lire?
if (size != packetsize) {
endpoint0StallTransaction();
return -1;
}
sControlBufferLength += size;
return packetsize;
}
uint16_t endpoint0ReadPacket(void * buffer, uint16_t length) {
uint32_t * buf = (uint32_t *) buffer;
uint16_t len = MIN(length, sRxPacketSize);
int i;
for (i = len; i >= 4; i -= 4) {
*buf++ = OTG.DFIFO0()->get(); //TODO: Why would this work?
sRxPacketSize -= 4;
}
if (i) {
uint32_t extra = OTG.DFIFO0()->get();
/* We read 4 bytes from the fifo, so update sRxPacketSize. Be careful not to
* underflow (rxbcnt is unsigned) */
if (sRxPacketSize < 4) {
sRxPacketSize = 0;
} else {
sRxPacketSize -= 4;
}
memcpy(buf, &extra, i);
}
return len;
}
void flushTxFifo() {
/* Set IN endpoint NAK */
OTG.DIEPCTL0()->setSNAK(true);
/* Wait for core to respond */
while (!OTG.DIEPINT(0)->getINEPNE()) {
}
/* Get the Tx FIFO number for endpoint 0 */
uint32_t fifo = OTG.DIEPCTL0()->getTXFNUM();
/* Wait for AHB idle */
while (!OTG.GRSTCTL()->getAHBIDL()) {
}
/* Flush Tx FIFO */
OTG.GRSTCTL()->setTXFNUM(fifo);
OTG.GRSTCTL()->setTXFFLSH(true);
/* Reset packet counter */
OTG.DIEPTSIZ0()->setPKTCNT(0);
/* Wait for the flush */
while (OTG.GRSTCTL()->getTXFFLSH()) {
}
}
void flushRxFifo() {
/* Set OUT endpoint NAK */
OTG.DOEPCTL0()->setSNAK(true);
/* Wait for AHB idle */
while (!OTG.GRSTCTL()->getAHBIDL()) {
}
/* Flush Tx FIFO */
OTG.GRSTCTL()->setTXFFLSH(true);
/* Reset packet counter */
OTG.DOEPTSIZ0()->setPKTCNT(0);
/* Wait for the flush */
while (OTG.GRSTCTL()->getRXFFLSH()) {
}
}
@@ -102,8 +639,6 @@ void init() {
while (OTG.GRSTCTL()->getCSRST()) {
}
// TODO: Check BCUSBSEN / VBDEN
// Enable the USB transceiver
OTG.GCCFG()->setPWRDWN(true);
// FIXME: Understand why VBDEN is required
@@ -127,12 +662,6 @@ void init() {
/* Full speed device. */
OTG.DCFG()->setDSPD(OTG::DCFG::DSPD::FullSpeed);
/* Restart the PHY clock. */
//OTG::PCGCCTL pcgcctl;// = OTG.PCGCCTL();
// This is already zero...
//OTG.PCGCCTL()->setGATEHCLK(0);
//OTG.PCGCCTL()->setSTPPCLK(0);
// FIFO-size = 128 * 32bits.
// FIXME: Explain :-)
OTG.GRXFSIZ()->setRXFD(128);
@@ -162,8 +691,6 @@ void init() {
while (!OTG.GINTSTS()->getENUMDNE()) {
}
abort();
while (true) {
poll();
}

View File

@@ -2,6 +2,7 @@
#define ION_DEVICE_USB_H
#include "regs/regs.h"
#include "ion.h"
namespace Ion {
namespace USB {
@@ -9,15 +10,174 @@ namespace Device {
/* Pin | Role | Mode | Function
* -----+-------------------+-----------------------+----------
* PA9 | VBUS | Input, pulled down | Low = unplugged, high = plugged
* PA9 | VBUS | Input, pulled down//TODO | Low = unplugged, high = plugged
* PA11 | USB D- | Alternate Function 10 |
* PA12 | USB D+ | Alternate Function 10 |
*/
#define MIN(a, b) ((a) < (b) ? (a) : (b))
enum class USBTransaction {
In,
Out,
Setup
};
/* USB Setup Transaction Data structure */
struct SetupData {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} __attribute__((packed));
enum class DataDirection {
In,
Out
};
/* USB Standard Request Codes */
#define USB_REQ_GET_STATUS 0
#define USB_REQ_CLEAR_FEATURE 1
#define USB_REQ_SET_FEATURE 3
#define USB_REQ_SET_ADDRESS 5
#define USB_REQ_GET_DESCRIPTOR 6
#define USB_REQ_SET_DESCRIPTOR 7
#define USB_REQ_GET_CONFIGURATION 8
#define USB_REQ_SET_CONFIGURATION 9
#define USB_REQ_GET_INTERFACE 10
#define USB_REQ_SET_INTERFACE 11
#define USB_REQ_SET_SYNCH_FRAME 12
/* USB Descriptor Types */
#define USB_DT_DEVICE 1
#define USB_DT_CONFIGURATION 2
#define USB_DT_STRING 3
#define USB_DT_INTERFACE 4
#define USB_DT_ENDPOINT 5
#define USB_DT_DEVICE_QUALIFIER 6
#define USB_DT_OTHER_SPEED_CONFIGURATION 7
#define USB_DT_INTERFACE_POWER 8
enum class RequestReturnCodes {
USBD_REQ_NOTSUPP = 0,
USBD_REQ_HANDLED = 1,
USBD_REQ_NEXT_CALLBACK = 2
};
struct DeviceDescriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} __attribute__((packed));
#define USB_DT_DEVICE_SIZE sizeof(struct DeviceDescriptor)
#define USB_MAX_PACKET_SIZE 64
struct StringDescriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wData[];
} __attribute__((packed));
#define USB_LANGID_ENGLISH_US 0x409
/* USB Standard Configuration Descriptor */
struct ConfigDescriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
} __attribute__((packed));
#define USB_DT_CONFIGURATION_SIZE 9
/* USB Standard Interface Descriptor - Table 9-12 */
struct InterfaceDescriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} __attribute__((packed));
#define USB_DT_INTERFACE_SIZE 9
/* Class Definition */
#define USB_CLASS_APPLICATION_SPECIFIC 0xFE
/* Class Definition */
#define USB_SUBCLASS_DFU 0x01
/* Class Definition */
#define USB_PROTOCOL_DFU 0x01
#define USB_DFU_CONFIGURATION_VALUE 1
enum class ControlState {
IDLE,
STALLED,
DATA_IN,
LAST_DATA_IN,
STATUS_IN,
DATA_OUT,
LAST_DATA_OUT,
STATUS_OUT,
};
void init();
void initGPIO();
void shutdown();
void flushTxFifo();
void flushRxFifo();
void controlSetup();
void controlSetupIn();
void controlSetupOut();
int controlSetupGetDescriptor();
int controlSetupSetConfiguration();
void controlSendChunk();
int controlReceiveChunk();
int controlRequestDispatch();
void controlOut();
void controlIn();
uint16_t endpoint0ReadPacket(void * buffer, uint16_t length);
uint16_t endpoint0WritePacket(const void *buffer, uint16_t length);
void endpoint0StallTransaction();
void endpoint0SetNak(bool nak);
DataDirection bmRequestTypeDirection(uint8_t bmRequestType);
int descriptorIndexFromWValue(uint16_t wValue);
int descriptorTypeFromWValue(uint16_t wValue);
uint16_t buildConfigDescriptor(uint8_t index);
bool zlpIsNeeded(uint16_t dataLength, uint16_t dataExpectedLength, uint8_t endpointMaxPacketSize);
constexpr static const char *sStrings[] = {
"Numworks",
"Calculatrice USB",
"111111111" //TODO
};
constexpr static uint16_t sNumberOfStrings = 4; //TODO set value
constexpr static GPIOPin VbusPin = GPIOPin(GPIOA, 9);
constexpr static GPIOPin DmPin = GPIOPin(GPIOA, 11);
constexpr static GPIOPin DpPin = GPIOPin(GPIOA, 12);