// TITLE: Enumeration code to handle all endpoint zero traffic
#include "usbd.h"
#include <sysctl.h>
#include <usb.h>
namespace usb{
bool tDevice::Init() {
config = 0;
devstat = 0;
USBDevMode(USB_BASE); // Force device mode
USBIntStatusControl(USB_BASE);
USBIntStatusEndpoint(USB_BASE);
USBIntEnableControl(USB_BASE,
USB_INTCTRL_RESET
| USB_INTCTRL_DISCONNECT
| USB_INTCTRL_RESUME
| USB_INTCTRL_SUSPEND
| USB_INTCTRL_SOF);
USBIntEnableEndpoint(USB_BASE, USB_INTEP_ALL);
USBDevConnect(USB_BASE);
return true;
}
void tDevice::Term() {
USBIntDisableControl(USB_BASE, USB_INTCTRL_ALL);
USBIntDisableEndpoint(USB_BASE, USB_INTEP_ALL);
USBDevDisconnect(USB_BASE);
USBIntStatusControl(USB_BASE);
USBIntStatusEndpoint(USB_BASE);
}
void tDevice::SendDataEP0(const uint8_t *data, unsigned size) {
while (size) {
unsigned sz=size>64?64:size;
if (USBEndpointDataPut(USB_BASE, 0, const_cast<uint8_t*>(data), sz)) {
idle();
if (USBIntStatusControl(USB_BASE)&USB_INTCTRL_RESET) return;
}
USBEndpointDataSend(USB_BASE, 0, sz==64 ? USB_TRANS_IN : USB_TRANS_IN_LAST);
data+=sz;
size-=sz;
}
}
void tDevice::SendDataEP0(const uint8_t *data, unsigned size, const tRequest&rq) {
rq.limitLength(size);
SendDataEP0(data, size);
}
void tDevice::pollEP0() {
tRequest rq;
uint32_t ui32Size = sizeof rq;
// Get the data from the USB controller end point 0.
USBEndpointDataGet(USB_BASE, 0, rq,&ui32Size);
// If there was a null setup packet then just return.
if (!ui32Size) return;
USBDevEndpointDataAck(USB_BASE, 0, !(rq.bmRequestType&0x80));
uint8_t answer[2]={0,0};
switch (rq.wRequest()) {
case 0x0080: { // GetStatus-Device
answer[0]=devstat;
SendDataEP0(answer,2);
}return;
case 0x0081: { // GetStatus-Interface(wIndexL)
SendDataEP0(answer,2);
}return;
case 0x0082: { // GetStatus-Endpoint(wIndexL)
if (rq.wIndexL != 0x81) goto stall;
//TODO: Stall-Zustand von EP1IN abfragen
SendDataEP0(answer,2);
}return;
case 0x0100: { // ClearFeature-Device
if (rq.wValueL != 1) goto stall;
devstat &= ~2; // Clear the remote wake up state.
}return;
case 0x0102: { // ClearFeature-Endpoint(wIndexL)
if (rq.wIndexL != 0x81) goto stall; // Nur EP1IN
if (rq.wValueL != 0) goto stall; // nur HALT
USBDevEndpointStallClear(USB_BASE,1<<4,USB_EP_DEV_IN);
USBEndpointDataToggleClear(USB_BASE,1<<4,USB_EP_DEV_IN);
}return;
case 0x0300: { // SetFeature-Device
if (rq.wValueL != 1) goto stall;
devstat |= 2; // Set the remote wake up state
}return;
case 0x0302: { // SetFeature-Endpoint(wIndexL)
if (rq.wIndexL != 0x81) goto stall; // Nur EP1IN
if (rq.wValueL != 0) goto stall; // nur HALT
USBDevEndpointStall(USB_BASE,1<<4,USB_EP_DEV_IN);
}return;
case 0x0500: { // SetAddress-Device
while (!(USBIntStatusEndpoint(USB_BASE)&USB_INTEP_0)) {
idle();
if (USBIntStatusControl(USB_BASE)&USB_INTCTRL_RESET) return;
};
USBDevAddrSet(USB_BASE,rq.wValueL);
}return;
case 0x0680: // GetDescriptor-Device (für HID-Deskriptor aus UsbTreeView)
case 0x0681: { // GetDescriptor-Interface (für HID-Deskriptor aus Windows)
// Need to ACK the data on end point 0 without setting last data as there will be a data phase.
if (cbGetDescriptor(rq)) return;
}goto stall;
case 0x0700: goto stall; // SetDescriptor-Device
case 0x0880: { // GetConfig-Device
answer[0] = config;
SendDataEP0(answer,1);
}return;
case 0x0900: { // SetConfig-Device
if (rq.wValueL>1) goto stall; // nur 0 oder 1 erlaubt
if ((config = rq.wValueL)) {
// Konfiguriere EP1IN
USBDevEndpointConfigSet(USB_BASE,1<<4,64,USB_EP_MODE_INT/*|USB_EP_AUTO_SET*/);
// EP0 verwendet die ersten 64 Bytes, EP1 kommt danach:
USBFIFOConfigSet(USB_BASE,1<<4,64,64,USB_EP_DEV_IN);
}
}return;
case 0x0A81: { // GetInterface-Interface(wIndexL)
if (rq.wIndexL) goto stall;
SendDataEP0(answer,1); // Einfaches Beispiel hat nur eine Alternate Setting
}return;
case 0x0B01: { // SetInterface-Interface(wIndexL)
// bmRequestType=0x01, wIndexL=Interface, wValueL=AltSetting, wLength=0
if (rq.wIndexL) goto stall;
if (rq.wValueL) goto stall;
}return;
case 0x0C82: goto stall; // SyncFrame-Endpoint(wIndexL)
// bmRequestType=0x82, wIndexL=Endpoint, wLength=2: Antwort = FrameNumber
default: if (cbRequestHandler(rq)) return;
}
stall:
USBDevEndpointStall(USB_BASE, 0, USB_EP_DEV_OUT);
}
void tDevice::poll() {
if (!this) {
USBDevDisconnect(USB_BASE);
return;
}
uint32_t IntStatusEP,sta = USBIntStatus(USB_BASE,&IntStatusEP);
if (sta & USB_INTCTRL_RESET) onReset();
if (sta & USB_INTCTRL_DISCONNECT) onDisconnect();
if (sta & USB_INTCTRL_SOF) onSOF();
if (IntStatusEP & USB_INTEP_0) {
uint32_t sta = USBEndpointStatus(USB_BASE, 0);
if (sta & USB_DEV_EP0_OUT_PKTRDY) pollEP0();
// USBDevEndpointDataAck(USB_BASE, USB_EP_0, true);
if (sta & USB_DEV_EP0_SENT_STALL)
USBDevEndpointStatusClear(USB_BASE, USB_EP_0, USB_DEV_EP0_SENT_STALL);
}
}
}
Detected encoding: UTF-8 | 0
|