diff options
Diffstat (limited to 'bootloaders/caterina/src/USBCore.cpp')
-rw-r--r-- | bootloaders/caterina/src/USBCore.cpp | 512 |
1 files changed, 0 insertions, 512 deletions
diff --git a/bootloaders/caterina/src/USBCore.cpp b/bootloaders/caterina/src/USBCore.cpp deleted file mode 100644 index 0eecacc..0000000 --- a/bootloaders/caterina/src/USBCore.cpp +++ /dev/null @@ -1,512 +0,0 @@ - - -/* Copyright (c) 2010, Peter Barrett -** -** Permission to use, copy, modify, and/or distribute this software for -** any purpose with or without fee is hereby granted, provided that the -** above copyright notice and this permission notice appear in all copies. -** -** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR -** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES -** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -** SOFTWARE. -*/ - -#include "Platform.h" - -#define CDC_TX CDC_ENDPOINT_IN -#define CDC_RX CDC_ENDPOINT_OUT - -#define EP_TYPE_CONTROL 0x00 -#define EP_TYPE_BULK_IN 0x81 -#define EP_TYPE_BULK_OUT 0x80 -#define EP_TYPE_INTERRUPT_IN 0xC1 -#define EP_TYPE_INTERRUPT_OUT 0xC0 -#define EP_TYPE_ISOCHRONOUS_IN 0x41 -#define EP_TYPE_ISOCHRONOUS_OUT 0x40 - -/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */ -#define TX_RX_LED_PULSE_MS 100 -uint8_t TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */ -uint8_t RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */ - -void Reset(); - -//================================================================== -//================================================================== - -typedef struct -{ - uint32_t dwDTERate; - uint8_t bCharFormat; - uint8_t bParityType; - uint8_t bDataBits; - uint8_t lineState; -} LineInfo; - -static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; - -//================================================================== -//================================================================== - -// 4 bytes of RAM -volatile uint8_t _usbConfiguration; -volatile uint8_t _ejected; -volatile uint16_t _timeout; - -static inline void WaitIN(void) -{ - while (!(UEINTX & (1<<TXINI))); -} - -static inline void ClearIN(void) -{ - UEINTX = ~(1<<TXINI); -} - -static inline void WaitOUT(void) -{ - while (!(UEINTX & (1<<RXOUTI))) - ; -} - -static inline uint8_t WaitForINOrOUT() -{ - while (!(UEINTX & ((1<<TXINI)|(1<<RXOUTI)))) - ; - return (UEINTX & (1<<RXOUTI)) == 0; -} - -static inline void ClearOUT(void) -{ - UEINTX = ~(1<<RXOUTI); -} - -static -void Send(volatile const uint8_t* data, uint8_t count) -{ - TX_LED_ON(); // light the TX LED - TxLEDPulse = TX_RX_LED_PULSE_MS; - while (count--) - UEDATX = *data++; -} - -void Recv(volatile uint8_t* data, uint8_t count) -{ - RX_LED_ON(); // light the RX LED - RxLEDPulse = TX_RX_LED_PULSE_MS; - while (count--) - *data++ = UEDATX; -} - -static inline uint8_t Recv8() -{ - RX_LED_ON(); // light the RX LED - RxLEDPulse = TX_RX_LED_PULSE_MS; - return UEDATX; -} - -static inline void Send8(uint8_t d) -{ - TX_LED_ON(); // light the TX LED - TxLEDPulse = TX_RX_LED_PULSE_MS; - UEDATX = d; -} - -static inline void SetEP(uint8_t ep) -{ - UENUM = ep; -} - -static inline uint8_t FifoByteCount() -{ - return UEBCLX; -} - -static inline uint8_t ReceivedSetupInt() -{ - return UEINTX & (1<<RXSTPI); -} - -static inline void ClearSetupInt() -{ - UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI)); -} - -static inline void Stall() -{ - UECONX = (1<<STALLRQ) | (1<<EPEN); -} - -static inline uint8_t ReadWriteAllowed() -{ - return UEINTX & (1<<RWAL); -} - -static inline uint8_t Stalled() -{ - return UEINTX & (1<<STALLEDI); -} - -static inline uint8_t FifoFree() -{ - return UEINTX & (1<<FIFOCON); -} - -static inline void ReleaseRX() -{ - UEINTX = 0x6B; // FIFOCON=0 NAKINI=1 RWAL=1 NAKOUTI=0 RXSTPI=1 RXOUTI=0 STALLEDI=1 TXINI=1 -} - -static inline void ReleaseTX() -{ - UEINTX = 0x3A; // FIFOCON=0 NAKINI=0 RWAL=1 NAKOUTI=1 RXSTPI=1 RXOUTI=0 STALLEDI=1 TXINI=0 -} - -static inline uint8_t FrameNumber() -{ - return UDFNUML; -} - -//================================================================== -//================================================================== - -#define EP_SINGLE_64 0x32 // EP0 -#define EP_DOUBLE_64 0x36 // Other endpoints - -static void InitEP(uint8_t index, uint8_t type, uint8_t size) -{ - UENUM = index; - UECONX = 1; - UECFG0X = type; - UECFG1X = size; -} - -// API -void USBInit(void) -{ - _timeout = 0; - _usbConfiguration = 0; - _ejected = 0; - - UHWCON = 0x01; // power internal reg (don't need this?) - USBCON = (1<<USBE)|(1<<FRZCLK); // clock frozen, usb enabled - PLLCSR = 0x12; // Need 16 MHz xtal - while (!(PLLCSR & (1<<PLOCK))) // wait for lock pll - ; - USBCON = ((1<<USBE)|(1<<OTGPADE)); // start USB clock - UDCON = 0; // enable attach resistor -} - -uint8_t USBGetConfiguration(void) -{ - return _usbConfiguration; -} - -uint8_t HasData(uint8_t ep) -{ - SetEP(ep); - return ReadWriteAllowed(); // count in fifo -} - -int USBGetChar(); -void Recv(uint8_t ep, uint8_t* dst, uint8_t len) -{ - SetEP(ep); - while (len--) - { - while (!ReadWriteAllowed()) - ; - *dst++ = Recv8(); - if (!ReadWriteAllowed()) // release empty buffer - ReleaseRX(); - } -} - -// Transmit a packet to endpoint -void Transfer(uint8_t ep, const uint8_t* data, int len) -{ - uint8_t zero = ep & TRANSFER_ZERO; - SetEP(ep & 7); - while (len--) - { - while (!ReadWriteAllowed()) - ; // TODO Check for STALL etc - - uint8_t d = (ep & TRANSFER_PGM) ? pgm_read_byte(data) : data[0]; - data++; - if (zero) - d = 0; - Send8(d); - - if (!ReadWriteAllowed()) - ReleaseTX(); - } - if (ep & TRANSFER_RELEASE) - ReleaseTX(); -} - -extern const uint8_t _initEndpoints[] PROGMEM; -const uint8_t _initEndpoints[] = -{ - 0, - - EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM - EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT - EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN - -#ifdef HID_ENABLED - EP_TYPE_INTERRUPT_IN, // HID_ENDPOINT_INT -#endif -}; - -static void InitEndpoints() -{ - for (uint8_t i = 1; i < sizeof(_initEndpoints); i++) - { - UENUM = i; - UECONX = 1; - UECFG0X = pgm_read_byte(_initEndpoints+i); - UECFG1X = EP_DOUBLE_64; - } - UERST = 0x7E; // And reset them - UERST = 0; -} - -typedef struct -{ - uint8_t bmRequestType; - uint8_t bRequest; - uint8_t wValueL; - uint8_t wValueH; - uint16_t wIndex; - uint16_t wLength; -} Setup; -Setup _setup; - -//bool USBHook(Setup& setup) -bool USBHook() -{ - Setup& setup = _setup; - uint8_t r = setup.bRequest; - - // CDC Requests - if (CDC_GET_LINE_CODING == r) - { - Send((const volatile uint8_t*)&_usbLineInfo,7); - } - - else if (CDC_SET_LINE_CODING == r) - { - WaitOUT(); - Recv((volatile uint8_t*)&_usbLineInfo,7); - ClearOUT(); - } - - else if (CDC_SET_CONTROL_LINE_STATE == r) - { - _usbLineInfo.lineState = setup.wValueL; - } - - return true; -} - -extern const uint8_t _rawHID[] PROGMEM; -#define LSB(_x) ((_x) & 0xFF) -#define MSB(_x) ((_x) >> 8) - -#define RAWHID_USAGE_PAGE 0xFFC0 -#define RAWHID_USAGE 0x0C00 -#define RAWHID_TX_SIZE 64 -#define RAWHID_RX_SIZE 64 - -const uint8_t _rawHID[] = -{ - // RAW HID - 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), // 30 - 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), - - 0xA1, 0x01, // Collection 0x01 - 0x85, 0x03, // REPORT_ID (3) - 0x75, 0x08, // report size = 8 bits - 0x15, 0x00, // logical minimum = 0 - 0x26, 0xFF, 0x00, // logical maximum = 255 - - 0x95, 64, // report count TX - 0x09, 0x01, // usage - 0x81, 0x02, // Input (array) - - 0x95, 64, // report count RX - 0x09, 0x02, // usage - 0x91, 0x02, // Output (array) - 0xC0 // end collection -}; - -uint8_t _cdcComposite = 0; - -bool SendDescriptor() -{ - Setup& setup = _setup; - uint16_t desc_length = 0; - const uint8_t* desc_addr = 0; - - uint8_t t = setup.wValueH; - if (0x22 == t) - { -#ifdef HID_ENABLED - desc_addr = _rawHID; - desc_length = sizeof(desc_length); -#endif - } else if (USB_DEVICE_DESCRIPTOR_TYPE == t) - { - if (setup.wLength == 8) - _cdcComposite = 1; - desc_addr = _cdcComposite ? (const uint8_t*)&USB_DeviceDescriptorA : (const uint8_t*)&USB_DeviceDescriptor; - } - else if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) - { - desc_addr = (const uint8_t*)&USB_ConfigDescriptor; - desc_length = sizeof(USB_ConfigDescriptor); - } - else if (USB_STRING_DESCRIPTOR_TYPE == t) - { - if (setup.wValueL == 0) - desc_addr = (const uint8_t*)&STRING_LANGUAGE; - else if (setup.wValueL == IPRODUCT) - desc_addr = (const uint8_t*)&STRING_IPRODUCT; - else if (setup.wValueL == ISERIAL) - desc_addr = (const uint8_t*)&STRING_SERIAL; - else if (setup.wValueL == IMANUFACTURER) - desc_addr = (const uint8_t*)&STRING_IMANUFACTURER; - else - return false; - } else - return false; - - if (desc_length == 0) - desc_length = pgm_read_byte(desc_addr); - if (setup.wLength < desc_length) - desc_length = setup.wLength; - - // Send descriptor - // EP0 is 64 bytes long - // RWAL and FIFOCON don't work on EP0 - uint16_t n = 0; - do - { - if (!WaitForINOrOUT()) - return false; - Send8(pgm_read_byte(&desc_addr[n++])); - uint8_t clr = n & 0x3F; - if (!clr) - ClearIN(); // Fifo is full, release this packet - } while (n < desc_length); - return true; -} - -void USBSetupInterrupt() -{ - SetEP(0); - if (!ReceivedSetupInt()) - return; - - Setup& setup = _setup; // global saves ~30 bytes - Recv((uint8_t*)&setup,8); - ClearSetupInt(); - - if (setup.bmRequestType & DEVICETOHOST) - WaitIN(); - else - ClearIN(); - - bool ok = true; - uint8_t r = setup.bRequest; - if (SET_ADDRESS == r) - { - WaitIN(); - UDADDR = setup.wValueL | (1<<ADDEN); - } - else if (SET_CONFIGURATION == r) - { - _usbConfiguration = setup.wValueL; - InitEndpoints(); - } - else if (GET_CONFIGURATION == r) - { - Send8(_usbConfiguration); - } - else if (GET_STATUS == r) - { - Send8(0); // All good as far as I know - } - else if (GET_DESCRIPTOR == r) - { - ok = SendDescriptor(); - } - else - { - ok = USBHook(); - } - - if (ok) - ClearIN(); - else - Stall(); -} - -void USBGeneralInterrupt() -{ - uint8_t udint = UDINT; - UDINT = 0; - - // End of Reset - if (udint & (1<<EORSTI)) - { - InitEP(0,EP_TYPE_CONTROL,EP_SINGLE_64); // init ep0 - _usbConfiguration = 0; // not configured yet - } - - // Start of Frame - happens every millisecond so we use it for TX and RX LED one-shot timing, too - if (udint & (1<<SOFI)) - { - // check whether the one-shot period has elapsed. if so, turn off the LED - if (TxLEDPulse && !(--TxLEDPulse)) - TX_LED_OFF(); - if (RxLEDPulse && !(--RxLEDPulse)) - RX_LED_OFF(); - - if (!_ejected) - _timeout = 0; - } -} - -void LEDPulse(); -int USBGetChar() -{ - for(;;) - { - USBSetupInterrupt(); - USBGeneralInterrupt(); - - // Read a char - if (HasData(CDC_RX)) - { - uint8_t c = Recv8(); - if (!ReadWriteAllowed()) - ReleaseRX(); - return c; - } - - if (!--_timeout) { - Reset(); - } - - _delay_us(100); // stretch out the bootloader period to about 5 seconds after enumeration - LEDPulse(); - } - return -1; -} |