diff options
-rw-r--r-- | boards.txt | 80 | ||||
-rw-r--r-- | cores/arduino/CDC.cpp | 277 | ||||
-rw-r--r-- | cores/arduino/USBAPI.h | 66 | ||||
-rw-r--r-- | cores/arduino/USBCore.cpp | 128 | ||||
-rw-r--r-- | cores/arduino/USBCore.h | 107 | ||||
-rw-r--r-- | cores/arduino/USBDesc.h | 19 | ||||
-rw-r--r-- | cores/arduino/xinput/USB_XInput_API.cpp | 57 | ||||
-rw-r--r-- | cores/arduino/xinput/USB_XInput_API.h | 51 | ||||
-rw-r--r-- | cores/arduino/xinput/USB_XInput_Descriptors.cpp | 210 | ||||
-rw-r--r-- | cores/arduino/xinput/USB_XInput_Descriptors.h | 53 | ||||
-rw-r--r-- | libraries/HID/keywords.txt | 21 | ||||
-rw-r--r-- | libraries/HID/library.properties | 9 | ||||
-rw-r--r-- | libraries/HID/src/HID.cpp | 162 | ||||
-rw-r--r-- | libraries/HID/src/HID.h | 125 | ||||
-rw-r--r-- | platform.txt | 2 |
15 files changed, 485 insertions, 882 deletions
@@ -4,7 +4,7 @@ menu.cpu=Processor ############################################################## -yun.name=Arduino Yún +yun.name=Arduino Yún w/ XInput yun.upload.via_ssh=true yun.vid.0=0x2341 @@ -36,8 +36,8 @@ yun.bootloader.lock_bits=0x2F yun.build.mcu=atmega32u4 yun.build.f_cpu=16000000L -yun.build.vid=0x2341 -yun.build.pid=0x8041 +yun.build.vid=0x045E +yun.build.pid=0x028E yun.build.usb_product="Arduino Yun" yun.build.board=AVR_YUN yun.build.core=arduino @@ -46,7 +46,7 @@ yun.build.extra_flags={build.usb_flags} ############################################################## -leonardo.name=Arduino Leonardo +leonardo.name=Arduino Leonardo w/ XInput leonardo.vid.0=0x2341 leonardo.pid.0=0x0036 leonardo.vid.1=0x2341 @@ -75,8 +75,8 @@ leonardo.bootloader.lock_bits=0x2F leonardo.build.mcu=atmega32u4 leonardo.build.f_cpu=16000000L -leonardo.build.vid=0x2341 -leonardo.build.pid=0x8036 +leonardo.build.vid=0x045E +leonardo.build.pid=0x028E leonardo.build.usb_product="Arduino Leonardo" leonardo.build.board=AVR_LEONARDO leonardo.build.core=arduino @@ -85,7 +85,7 @@ leonardo.build.extra_flags={build.usb_flags} ############################################################## -leonardoeth.name=Arduino Leonardo ETH +leonardoeth.name=Arduino Leonardo ETH w/ XInput leonardoeth.vid.0=0x2a03 leonardoeth.pid.0=0x0040 leonardoeth.vid.1=0x2a03 @@ -110,8 +110,8 @@ leonardoeth.bootloader.lock_bits=0x2F leonardoeth.build.mcu=atmega32u4 leonardoeth.build.f_cpu=16000000L -leonardoeth.build.vid=0x2a03 -leonardoeth.build.pid=0x8040 +leonardoeth.build.vid=0x045E +leonardoeth.build.pid=0x028E leonardoeth.build.usb_product="Arduino Leonardo ETH" leonardoeth.build.board=AVR_LEONARDO_ETH leonardoeth.build.core=arduino @@ -120,7 +120,7 @@ leonardoeth.build.extra_flags={build.usb_flags} ############################################################## -micro.name=Arduino/Genuino Micro +micro.name=Arduino/Genuino Micro w/ XInput micro.vid.0=0x2341 micro.pid.0=0x0037 @@ -135,8 +135,8 @@ micro.vid.4=0x2341 micro.pid.4=0x0237 # If the board is a 2341:0237 use 2341:8237 for build and set # other parameters as well -micro.vid.4.build.vid=0x2341 -micro.vid.4.build.pid=0x8237 +micro.vid.4.build.vid=0x045E +micro.vid.4.build.pid=0x028E micro.vid.4.build.usb_product="Genuino Micro" micro.vid.4.bootloader.file=caterina/Caterina-Genuino-Micro.hex @@ -144,8 +144,8 @@ micro.vid.5=0x2341 micro.pid.5=0x8237 # If the board is a 2341:8237 use 2341:8237 for build and set # other paramters as well -micro.vid.5.build.vid=0x2341 -micro.vid.5.build.pid=0x8237 +micro.vid.5.build.vid=0x045E +micro.vid.5.build.pid=0x028E micro.vid.5.build.usb_product="Genuino Micro" micro.vid.5.bootloader.file=caterina/Caterina-Genuino-Micro.hex @@ -168,8 +168,8 @@ micro.bootloader.lock_bits=0x2F micro.build.mcu=atmega32u4 micro.build.f_cpu=16000000L -micro.build.vid=0x2341 -micro.build.pid=0x8037 +micro.build.vid=0x045E +micro.build.pid=0x028E micro.build.usb_product="Arduino Micro" micro.build.board=AVR_MICRO micro.build.core=arduino @@ -178,7 +178,7 @@ micro.build.extra_flags={build.usb_flags} ############################################################## -esplora.name=Arduino Esplora +esplora.name=Arduino Esplora w/ XInput esplora.vid.0=0x2341 esplora.pid.0=0x003C esplora.vid.1=0x2341 @@ -207,8 +207,8 @@ esplora.bootloader.lock_bits=0x2F esplora.build.mcu=atmega32u4 esplora.build.f_cpu=16000000L -esplora.build.vid=0x2341 -esplora.build.pid=0x803c +esplora.build.vid=0x045E +esplora.build.pid=0x028E esplora.build.usb_product="Arduino Esplora" esplora.build.board=AVR_ESPLORA esplora.build.core=arduino @@ -217,7 +217,7 @@ esplora.build.extra_flags={build.usb_flags} ############################################################## -LilyPadUSB.name=LilyPad Arduino USB +LilyPadUSB.name=LilyPad Arduino USB w/ XInput LilyPadUSB.vid.0=0x1B4F LilyPadUSB.pid.0=0x9207 LilyPadUSB.vid.1=0x1B4F @@ -242,8 +242,8 @@ LilyPadUSB.bootloader.lock_bits=0x2F LilyPadUSB.build.mcu=atmega32u4 LilyPadUSB.build.f_cpu=8000000L -LilyPadUSB.build.vid=0x1B4F -LilyPadUSB.build.pid=0x9208 +LilyPadUSB.build.vid=0x045E +LilyPadUSB.build.pid=0x028E LilyPadUSB.build.usb_product="LilyPad USB" LilyPadUSB.build.board=AVR_LILYPAD_USB LilyPadUSB.build.core=arduino @@ -252,7 +252,7 @@ LilyPadUSB.build.extra_flags={build.usb_flags} ############################################################## -robotControl.name=Arduino Robot Control +robotControl.name=Arduino Robot Control w/ XInput robotControl.vid.0=0x2341 robotControl.pid.0=0x0038 robotControl.vid.1=0x2341 @@ -281,8 +281,8 @@ robotControl.bootloader.lock_bits=0x2F robotControl.build.mcu=atmega32u4 robotControl.build.f_cpu=16000000L -robotControl.build.vid=0x2341 -robotControl.build.pid=0x8038 +robotControl.build.vid=0x045E +robotControl.build.pid=0x028E robotControl.build.usb_product="Robot Control" robotControl.build.board=AVR_ROBOT_CONTROL robotControl.build.core=arduino @@ -291,7 +291,7 @@ robotControl.build.extra_flags={build.usb_flags} ############################################################## -robotMotor.name=Arduino Robot Motor +robotMotor.name=Arduino Robot Motor w/ XInput robotMotor.vid.0=0x2341 robotMotor.pid.0=0x0039 robotMotor.vid.1=0x2341 @@ -320,8 +320,8 @@ robotMotor.bootloader.lock_bits=0x2F robotMotor.build.mcu=atmega32u4 robotMotor.build.f_cpu=16000000L -robotMotor.build.vid=0x2341 -robotMotor.build.pid=0x8039 +robotMotor.build.vid=0x045E +robotMotor.build.pid=0x028E robotMotor.build.usb_product="Robot Motor" robotMotor.build.board=AVR_ROBOT_MOTOR robotMotor.build.core=arduino @@ -330,7 +330,7 @@ robotMotor.build.extra_flags={build.usb_flags} ############################################################## -# Adafruit Circuit Playground 32u4 w/Caterina Configuration +# Adafruit Circuit Playground 32u4 w/Caterina Configuration w/ XInput circuitplay32u4cat.name=Adafruit Circuit Playground circuitplay32u4cat.bootloader.low_fuses=0xff circuitplay32u4cat.bootloader.high_fuses=0xd8 @@ -341,8 +341,8 @@ circuitplay32u4cat.bootloader.lock_bits=0x2F circuitplay32u4cat.bootloader.tool=avrdude circuitplay32u4cat.build.mcu=atmega32u4 circuitplay32u4cat.build.f_cpu=8000000L -circuitplay32u4cat.build.vid=0x239A -circuitplay32u4cat.build.pid=0x8011 +circuitplay32u4cat.build.vid=0x045E +circuitplay32u4cat.build.pid=0x028E circuitplay32u4cat.build.core=arduino circuitplay32u4cat.build.variant=circuitplay32u4 circuitplay32u4cat.build.board=AVR_CIRCUITPLAY @@ -361,7 +361,7 @@ circuitplay32u4cat.pid.0=0x8011 ############################################################## -yunmini.name=Arduino Yún Mini +yunmini.name=Arduino Yún Mini w/ XInput yunmini.upload.via_ssh=true yunmini.vid.0=0x2a03 @@ -388,8 +388,8 @@ yunmini.bootloader.lock_bits=0x2F yunmini.build.mcu=atmega32u4 yunmini.build.f_cpu=16000000L -yunmini.build.vid=0x2a03 -yunmini.build.pid=0x8050 +yunmini.build.vid=0x045E +yunmini.build.pid=0x028E yunmini.build.usb_product="Arduino Yún Mini" yunmini.build.board=AVR_YUNMINI yunmini.build.core=arduino @@ -398,7 +398,7 @@ yunmini.build.extra_flags={build.usb_flags} ############################################################## -chiwawa.name=Arduino Industrial 101 +chiwawa.name=Arduino Industrial 101 w/ XInput chiwawa.upload.via_ssh=true chiwawa.vid.0=0x2a03 @@ -425,8 +425,8 @@ chiwawa.bootloader.lock_bits=0x2F chiwawa.build.mcu=atmega32u4 chiwawa.build.f_cpu=16000000L -chiwawa.build.vid=0x2a03 -chiwawa.build.pid=0x8056 +chiwawa.build.vid=0x045E +chiwawa.build.pid=0x028E chiwawa.build.usb_product="Arduino Industrial 101" chiwawa.build.board=AVR_INDUSTRIAL101 chiwawa.build.core=arduino @@ -435,7 +435,7 @@ chiwawa.build.extra_flags={build.usb_flags} ############################################################## -one.name=Linino One +one.name=Linino One w/ XInput one.upload.via_ssh=true one.vid.0=0x2a03 @@ -462,8 +462,8 @@ one.bootloader.lock_bits=0x2F one.build.mcu=atmega32u4 one.build.f_cpu=16000000L -one.build.vid=0x2a03 -one.build.pid=0x8001 +one.build.vid=0x045E +one.build.pid=0x028E one.build.usb_product="Linino One" one.build.board=AVR_LININO_ONE one.build.core=arduino diff --git a/cores/arduino/CDC.cpp b/cores/arduino/CDC.cpp index 142f8f6..a6bce17 100644 --- a/cores/arduino/CDC.cpp +++ b/cores/arduino/CDC.cpp @@ -17,286 +17,9 @@ */ #include "USBAPI.h" -#include <avr/wdt.h> -#include <util/atomic.h> #if defined(USBCON) -typedef struct -{ - u32 dwDTERate; - u8 bCharFormat; - u8 bParityType; - u8 bDataBits; - u8 lineState; -} LineInfo; - -static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 }; -static volatile int32_t breakValue = -1; - -static u8 wdtcsr_save; - -#define WEAK __attribute__ ((weak)) - -extern const CDCDescriptor _cdcInterface PROGMEM; -const CDCDescriptor _cdcInterface = -{ - D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1), - - // CDC communication interface - D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), - D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd) - D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not) - D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported - D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0 - D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40), - - // CDC data interface - D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0), - D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0), - D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0) -}; - -bool isLUFAbootloader() -{ - return pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE; -} - -int CDC_GetInterface(u8* interfaceNum) -{ - interfaceNum[0] += 2; // uses 2 - return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface)); -} - -bool CDC_Setup(USBSetup& setup) -{ - u8 r = setup.bRequest; - u8 requestType = setup.bmRequestType; - - if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType) - { - if (CDC_GET_LINE_CODING == r) - { - USB_SendControl(0,(void*)&_usbLineInfo,7); - return true; - } - } - - if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType) - { - if (CDC_SEND_BREAK == r) - { - breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL; - } - - if (CDC_SET_LINE_CODING == r) - { - USB_RecvControl((void*)&_usbLineInfo,7); - } - - if (CDC_SET_CONTROL_LINE_STATE == r) - { - _usbLineInfo.lineState = setup.wValueL; - - // auto-reset into the bootloader is triggered when the port, already - // open at 1200 bps, is closed. this is the signal to start the watchdog - // with a relatively long period so it can finish housekeeping tasks - // like servicing endpoints before the sketch ends - - uint16_t magic_key_pos = MAGIC_KEY_POS; - -// If we don't use the new RAMEND directly, check manually if we have a newer bootloader. -// This is used to keep compatible with the old leonardo bootloaders. -// You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check. -#if MAGIC_KEY_POS != (RAMEND-1) - // For future boards save the key in the inproblematic RAMEND - // Which is reserved for the main() return value (which will never return) - if (isLUFAbootloader()) { - // horray, we got a new bootloader! - magic_key_pos = (RAMEND-1); - } -#endif - - // We check DTR state to determine if host port is open (bit 0 of lineState). - if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0) - { -#if MAGIC_KEY_POS != (RAMEND-1) - // Backup ram value if its not a newer bootloader and it hasn't already been saved. - // This should avoid memory corruption at least a bit, not fully - if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) { - *(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos; - } -#endif - // Store boot key - *(uint16_t *)magic_key_pos = MAGIC_KEY; - // Save the watchdog state in case the reset is aborted. - wdtcsr_save = WDTCSR; - wdt_enable(WDTO_120MS); - } - else if (*(uint16_t *)magic_key_pos == MAGIC_KEY) - { - // Most OSs do some intermediate steps when configuring ports and DTR can - // twiggle more than once before stabilizing. - // To avoid spurious resets we set the watchdog to 120ms and eventually - // cancel if DTR goes back high. - // Cancellation is only done if an auto-reset was started, which is - // indicated by the magic key having been set. - - wdt_reset(); - // Restore the watchdog state in case the sketch was using it. - WDTCSR |= (1<<WDCE) | (1<<WDE); - WDTCSR = wdtcsr_save; -#if MAGIC_KEY_POS != (RAMEND-1) - // Restore backed up (old bootloader) magic key data - if (magic_key_pos != (RAMEND-1)) { - *(uint16_t *)magic_key_pos = *(uint16_t *)(RAMEND-1); - } else -#endif - { - // Clean up RAMEND key - *(uint16_t *)magic_key_pos = 0x0000; - } - } - } - return true; - } - return false; -} - - -void Serial_::begin(unsigned long /* baud_count */) -{ - peek_buffer = -1; -} - -void Serial_::begin(unsigned long /* baud_count */, byte /* config */) -{ - peek_buffer = -1; -} - -void Serial_::end(void) -{ -} - -int Serial_::available(void) -{ - if (peek_buffer >= 0) { - return 1 + USB_Available(CDC_RX); - } - return USB_Available(CDC_RX); -} - -int Serial_::peek(void) -{ - if (peek_buffer < 0) - peek_buffer = USB_Recv(CDC_RX); - return peek_buffer; -} - -int Serial_::read(void) -{ - if (peek_buffer >= 0) { - int c = peek_buffer; - peek_buffer = -1; - return c; - } - return USB_Recv(CDC_RX); -} - -int Serial_::availableForWrite(void) -{ - return USB_SendSpace(CDC_TX); -} - -void Serial_::flush(void) -{ - USB_Flush(CDC_TX); -} - -size_t Serial_::write(uint8_t c) -{ - return write(&c, 1); -} - -size_t Serial_::write(const uint8_t *buffer, size_t size) -{ - /* only try to send bytes if the high-level CDC connection itself - is open (not just the pipe) - the OS should set lineState when the port - is opened and clear lineState when the port is closed. - bytes sent before the user opens the connection or after - the connection is closed are lost - just like with a UART. */ - - // TODO - ZE - check behavior on different OSes and test what happens if an - // open connection isn't broken cleanly (cable is yanked out, host dies - // or locks up, or host virtual serial port hangs) - if (_usbLineInfo.lineState > 0) { - int r = USB_Send(CDC_TX,buffer,size); - if (r > 0) { - return r; - } else { - setWriteError(); - return 0; - } - } - setWriteError(); - return 0; -} - -// This operator is a convenient way for a sketch to check whether the -// port has actually been configured and opened by the host (as opposed -// to just being connected to the host). It can be used, for example, in -// setup() before printing to ensure that an application on the host is -// actually ready to receive and display the data. -// We add a short delay before returning to fix a bug observed by Federico -// where the port is configured (lineState != 0) but not quite opened. -Serial_::operator bool() { - bool result = false; - if (_usbLineInfo.lineState > 0) - result = true; - delay(10); - return result; -} - -unsigned long Serial_::baud() { - // Disable interrupts while reading a multi-byte value - uint32_t baudrate; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - baudrate = _usbLineInfo.dwDTERate; - } - return baudrate; -} - -uint8_t Serial_::stopbits() { - return _usbLineInfo.bCharFormat; -} - -uint8_t Serial_::paritytype() { - return _usbLineInfo.bParityType; -} - -uint8_t Serial_::numbits() { - return _usbLineInfo.bDataBits; -} - -bool Serial_::dtr() { - return _usbLineInfo.lineState & 0x1; -} - -bool Serial_::rts() { - return _usbLineInfo.lineState & 0x2; -} - -int32_t Serial_::readBreak() { - int32_t ret; - // Disable IRQs while reading and clearing breakValue to make - // sure we don't overwrite a value just set by the ISR. - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - ret = breakValue; - breakValue = -1; - } - return ret; -} - Serial_ Serial; #endif /* if defined(USBCON) */ diff --git a/cores/arduino/USBAPI.h b/cores/arduino/USBAPI.h index 479ced9..0f7d171 100644 --- a/cores/arduino/USBAPI.h +++ b/cores/arduino/USBAPI.h @@ -42,6 +42,7 @@ typedef unsigned long u32; #include "USBDesc.h" #include "USBCore.h" +#include "xinput/USB_XInput_Descriptors.h" //================================================================================ //================================================================================ @@ -87,27 +88,21 @@ struct ring_buffer; class Serial_ : public Stream { -private: - int peek_buffer; public: - Serial_() { peek_buffer = -1; }; - void begin(unsigned long); - void begin(unsigned long, uint8_t); - void end(void); - - virtual int available(void); - virtual int peek(void); - virtual int read(void); - virtual int availableForWrite(void); - virtual void flush(void); - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t*, size_t); + Serial_() {}; + void begin(unsigned long) {} + void begin(unsigned long, uint8_t) {} + void end(void) {} + + virtual int available(void) { return -1; } + virtual int peek(void) { return -1; } + virtual int read(void) { return -1; } + virtual int availableForWrite(void) { return 0; } + virtual void flush(void) {} + virtual size_t write(uint8_t) { return 1; } + virtual size_t write(const uint8_t*, size_t n) { return n; } using Print::write; // pull in write(str) and write(buf, size) from Print - operator bool(); - - volatile uint8_t _rx_buffer_head; - volatile uint8_t _rx_buffer_tail; - unsigned char _rx_buffer[SERIAL_BUFFER_SIZE]; + operator bool() { return true; } // This method allows processing "SEND_BREAK" requests sent by // the USB host. Those requests indicate that the host wants to @@ -124,17 +119,17 @@ public: // first request is lost. // Note that the value returned is a long, so it can return // 0-0xffff as well as -1. - int32_t readBreak(); + int32_t readBreak() { return -1; }; // These return the settings specified by the USB host for the // serial port. These aren't really used, but are offered here // in case a sketch wants to act on these settings. - uint32_t baud(); - uint8_t stopbits(); - uint8_t paritytype(); - uint8_t numbits(); - bool dtr(); - bool rts(); + uint32_t baud() { return 0; } + uint8_t stopbits() { return 1; } + uint8_t paritytype() { return 0; } + uint8_t numbits() { return 8; } + bool dtr() { return true; } + bool rts() { return true; } enum { ONE_STOP_BIT = 0, ONE_AND_HALF_STOP_BIT = 1, @@ -169,23 +164,6 @@ typedef struct //================================================================================ //================================================================================ -// MSC 'Driver' - -int MSC_GetInterface(uint8_t* interfaceNum); -int MSC_GetDescriptor(int i); -bool MSC_Setup(USBSetup& setup); -bool MSC_Data(uint8_t rx,uint8_t tx); - -//================================================================================ -//================================================================================ -// CSC 'Driver' - -int CDC_GetInterface(uint8_t* interfaceNum); -int CDC_GetDescriptor(int i); -bool CDC_Setup(USBSetup& setup); - -//================================================================================ -//================================================================================ #define TRANSFER_PGM 0x80 #define TRANSFER_RELEASE 0x40 @@ -202,6 +180,8 @@ int USB_Recv(uint8_t ep, void* data, int len); // non-blocking int USB_Recv(uint8_t ep); // non-blocking void USB_Flush(uint8_t ep); +#include "xinput/USB_XInput_API.h" + #endif #endif /* if defined(USBCON) */ diff --git a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp index 81f689d..6e820a1 100644 --- a/cores/arduino/USBCore.cpp +++ b/cores/arduino/USBCore.cpp @@ -34,7 +34,6 @@ volatile u8 RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */ extern const u16 STRING_LANGUAGE[] PROGMEM; extern const u8 STRING_PRODUCT[] PROGMEM; extern const u8 STRING_MANUFACTURER[] PROGMEM; -extern const DeviceDescriptor USB_DeviceDescriptorIAD PROGMEM; const u16 STRING_LANGUAGE[2] = { (3<<8) | (2+2), @@ -65,13 +64,6 @@ const u8 STRING_PRODUCT[] PROGMEM = USB_PRODUCT; const u8 STRING_MANUFACTURER[] PROGMEM = USB_MANUFACTURER; - -#define DEVICE_CLASS 0x02 - -// DEVICE DESCRIPTOR -const DeviceDescriptor USB_DeviceDescriptorIAD = - D_DEVICE(0xEF,0x02,0x01,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,ISERIAL,1); - //================================================================== //================================================================== @@ -325,63 +317,52 @@ int USB_Send(u8 ep, const void* d, int len) return r; } -u8 _initEndpoints[USB_ENDPOINTS] = -{ - 0, // Control Endpoint - - EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM - EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT - EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN - - // Following endpoints are automatically initialized to 0 -}; - #define EP_SINGLE_64 0x32 // EP0 #define EP_DOUBLE_64 0x36 // Other endpoints #define EP_SINGLE_16 0x12 -static +static inline +u8 BankSizeMask(const uint8_t nbytes) +{ + uint8_t mask = 0; + for (uint8_t size = 8; size < 64; size <<= 1) { + if (nbytes <= size) break; + mask++; + } + + return (mask << EPSIZE0); +} + +static inline void InitEP(u8 index, u8 type, u8 size) { - UENUM = index; - UECONX = (1<<EPEN); - UECFG0X = type; - UECFG1X = size; + UENUM = index; // Select endpoint + UECONX = (1<<EPEN); // Enable endpoint + UECFG0X = type; // Direction and transmission type + UECFG1X = size; // Memory allocation, # of data banks, and bank size } -static -void InitEndpoints() +static inline +bool InitEPSize(const u8 index, const u8 type, const u8 nbanks, const u8 banksize) { - for (u8 i = 1; i < sizeof(_initEndpoints) && _initEndpoints[i] != 0; i++) - { - UENUM = i; - UECONX = (1<<EPEN); - UECFG0X = _initEndpoints[i]; -#if USB_EP_SIZE == 16 - UECFG1X = EP_SINGLE_16; -#elif USB_EP_SIZE == 64 - UECFG1X = EP_DOUBLE_64; -#else -#error Unsupported value for USB_EP_SIZE -#endif - } - UERST = 0x7E; // And reset them - UERST = 0; + if (index >= USB_ENDPOINTS) return false; + uint8_t size = ((1 << ALLOC) | ((nbanks > 1) ? (1 << EPBK0) : 0) | BankSizeMask(banksize)); + InitEP(index, type, size); + return UESTA0X & (1 << CFGOK); // Success } -// Handle CLASS_INTERFACE requests static -bool ClassInterfaceRequest(USBSetup& setup) +void InitEndpoints() { - u8 i = setup.wIndex; + InitEPSize(XINPUT_TX_ENDPOINT, EP_TYPE_INTERRUPT_IN, 1, 32); // Control Data Send + InitEPSize(XINPUT_RX_ENDPOINT, EP_TYPE_INTERRUPT_OUT, 2, 32); // Control Data Receive + InitEPSize(5, EP_TYPE_INTERRUPT_IN, 1, 32); // Expansion Interface NACK (avoid config reset) - if (CDC_ACM_INTERFACE == i) - return CDC_Setup(setup); + UERST = 0x7E; // Reset endpoints + UERST = 0; // End reset -#ifdef PLUGGABLE_USB_ENABLED - return PluggableUSB().setup(setup); -#endif - return false; + SetEP(XINPUT_RX_ENDPOINT); // Select XInput RX endpoint (OUT) + UEIENX |= (1 << RXOUTE); // Enable received "OUT" interrupt } static int _cmark; @@ -462,48 +443,27 @@ int USB_RecvControl(void* d, int len) return len; } -static u8 SendInterfaces() -{ - u8 interfaces = 0; - - CDC_GetInterface(&interfaces); - -#ifdef PLUGGABLE_USB_ENABLED - PluggableUSB().getInterface(&interfaces); -#endif - - return interfaces; -} - // Construct a dynamic configuration descriptor // This really needs dynamic endpoint allocation etc // TODO static bool SendConfiguration(int maxlen) { - // Count and measure interfaces - InitControl(0); - u8 interfaces = SendInterfaces(); - ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces); - - // Now send them InitControl(maxlen); - USB_SendControl(0,&config,sizeof(ConfigDescriptor)); - SendInterfaces(); + USB_SendControl(TRANSFER_PGM, &USB_ConfigDescriptor, USB_ConfigDescriptorSize); return true; } static bool SendDescriptor(USBSetup& setup) { - int ret; u8 t = setup.wValueH; if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t) return SendConfiguration(setup.wLength); InitControl(setup.wLength); #ifdef PLUGGABLE_USB_ENABLED - ret = PluggableUSB().getDescriptor(setup); + int ret = PluggableUSB().getDescriptor(setup); if (ret != 0) { return (ret > 0 ? true : false); } @@ -512,7 +472,7 @@ bool SendDescriptor(USBSetup& setup) const u8* desc_addr = 0; if (USB_DEVICE_DESCRIPTOR_TYPE == t) { - desc_addr = (const u8*)&USB_DeviceDescriptorIAD; + desc_addr = (const u8*) &USB_DeviceDescriptor; } else if (USB_STRING_DESCRIPTOR_TYPE == t) { @@ -530,8 +490,13 @@ bool SendDescriptor(USBSetup& setup) char name[ISERIAL_MAX_LEN]; PluggableUSB().getShortName(name); return USB_SendStringDescriptor((uint8_t*)name, strlen(name), 0); +#else + return USB_SendStringDescriptor(STRING_SERIAL, strlen((char*)STRING_SERIAL), TRANSFER_PGM); #endif } + else if (setup.wValueL == ISECURITY) { + return USB_SendStringDescriptor(STRING_SECURITY, strlen((char*)STRING_SECURITY), TRANSFER_PGM); + } else return false; } @@ -544,9 +509,17 @@ bool SendDescriptor(USBSetup& setup) return true; } -// Endpoint 0 interrupt +// Endpoint interrupt ISR(USB_COM_vect) { + SetEP(XINPUT_RX_ENDPOINT); // Select XInput RX endpoint (OUT) + if (UEINTX & (1 << RXOUTI)) { // If data received... + UEINTX &= ~(1 << RXOUTI); // Clear interrupt flag + if (XInputUSB::RecvCallback != nullptr) { + XInputUSB::RecvCallback(); // Call callback function if it exists + } + } + SetEP(0); if (!ReceivedSetupInt()) return; @@ -633,8 +606,7 @@ ISR(USB_COM_vect) } else { - InitControl(setup.wLength); // Max length of transfer - ok = ClassInterfaceRequest(setup); + ok = true; } if (ok) @@ -755,8 +727,6 @@ ISR(USB_GEN_vect) // Start of Frame - happens every millisecond so we use it for TX and RX LED one-shot timing, too if (udint & (1<<SOFI)) { - USB_Flush(CDC_TX); // Send a tx frame if found - // check whether the one-shot period has elapsed. if so, turn off the LED if (TxLEDPulse && !(--TxLEDPulse)) TXLED0; diff --git a/cores/arduino/USBCore.h b/cores/arduino/USBCore.h index 4210ced..eafdbe5 100644 --- a/cores/arduino/USBCore.h +++ b/cores/arduino/USBCore.h @@ -53,16 +53,6 @@ #define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE) #define REQUEST_DEVICETOHOST_STANDARD_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE) -// Class requests - -#define CDC_SET_LINE_CODING 0x20 -#define CDC_GET_LINE_CODING 0x21 -#define CDC_SET_CONTROL_LINE_STATE 0x22 -#define CDC_SEND_BREAK 0x23 - -#define MSC_RESET 0xFF -#define MSC_GET_MAX_LUN 0xFE - // Descriptors #define USB_DEVICE_DESC_SIZE 18 @@ -111,21 +101,6 @@ #define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF) -#define CDC_V1_10 0x0110 -#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02 - -#define CDC_CALL_MANAGEMENT 0x01 -#define CDC_ABSTRACT_CONTROL_MODEL 0x02 -#define CDC_HEADER 0x00 -#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02 -#define CDC_UNION 0x06 -#define CDC_CS_INTERFACE 0x24 -#define CDC_CS_ENDPOINT 0x25 -#define CDC_DATA_INTERFACE_CLASS 0x0A - -#define MSC_SUBCLASS_SCSI 0x06 -#define MSC_PROTOCOL_BULK_ONLY 0x50 - #ifndef USB_VERSION #define USB_VERSION 0x200 #endif @@ -187,82 +162,6 @@ typedef struct u8 interval; } EndpointDescriptor; -// Interface Association Descriptor -// Used to bind 2 interfaces together in CDC compostite device -typedef struct -{ - u8 len; // 8 - u8 dtype; // 11 - u8 firstInterface; - u8 interfaceCount; - u8 functionClass; - u8 funtionSubClass; - u8 functionProtocol; - u8 iInterface; -} IADDescriptor; - -// CDC CS interface descriptor -typedef struct -{ - u8 len; // 5 - u8 dtype; // 0x24 - u8 subtype; - u8 d0; - u8 d1; -} CDCCSInterfaceDescriptor; - -typedef struct -{ - u8 len; // 4 - u8 dtype; // 0x24 - u8 subtype; - u8 d0; -} CDCCSInterfaceDescriptor4; - -typedef struct -{ - u8 len; - u8 dtype; // 0x24 - u8 subtype; // 1 - u8 bmCapabilities; - u8 bDataInterface; -} CMFunctionalDescriptor; - -typedef struct -{ - u8 len; - u8 dtype; // 0x24 - u8 subtype; // 1 - u8 bmCapabilities; -} ACMFunctionalDescriptor; - -typedef struct -{ - // IAD - IADDescriptor iad; // Only needed on compound device - - // Control - InterfaceDescriptor cif; // - CDCCSInterfaceDescriptor header; - CMFunctionalDescriptor callManagement; // Call Management - ACMFunctionalDescriptor controlManagement; // ACM - CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION - EndpointDescriptor cifin; - - // Data - InterfaceDescriptor dif; - EndpointDescriptor in; - EndpointDescriptor out; -} CDCDescriptor; - -typedef struct -{ - InterfaceDescriptor msc; - EndpointDescriptor in; - EndpointDescriptor out; -} MSCDescriptor; - - #define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \ { 18, 1, USB_VERSION, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs } @@ -275,12 +174,6 @@ typedef struct #define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \ { 7, 5, _addr,_attr,_packetSize, _interval } -#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \ - { 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 } - -#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 } -#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 } - // Bootloader related fields // Old Caterina bootloader places the MAGIC key into unsafe RAM locations (it can be rewritten // by the running sketch before to actual reboot). diff --git a/cores/arduino/USBDesc.h b/cores/arduino/USBDesc.h index c0dce07..fe1af92 100644 --- a/cores/arduino/USBDesc.h +++ b/cores/arduino/USBDesc.h @@ -16,7 +16,7 @@ SOFTWARE. */ -#define PLUGGABLE_USB_ENABLED +// #define PLUGGABLE_USB_ENABLED // Not compatible with XInput #if defined(EPRST6) #define USB_ENDPOINTS 7 // AtMegaxxU4 @@ -24,23 +24,6 @@ #define USB_ENDPOINTS 5 // AtMegaxxU2 #endif -#define ISERIAL_MAX_LEN 20 - -#define CDC_INTERFACE_COUNT 2 -#define CDC_ENPOINT_COUNT 3 - -#define CDC_ACM_INTERFACE 0 // CDC ACM -#define CDC_DATA_INTERFACE 1 // CDC Data -#define CDC_FIRST_ENDPOINT 1 -#define CDC_ENDPOINT_ACM (CDC_FIRST_ENDPOINT) // CDC First -#define CDC_ENDPOINT_OUT (CDC_FIRST_ENDPOINT+1) -#define CDC_ENDPOINT_IN (CDC_FIRST_ENDPOINT+2) - -#define INTERFACE_COUNT (MSC_INTERFACE + MSC_INTERFACE_COUNT) - -#define CDC_RX CDC_ENDPOINT_OUT -#define CDC_TX CDC_ENDPOINT_IN - #define IMANUFACTURER 1 #define IPRODUCT 2 #define ISERIAL 3
\ No newline at end of file diff --git a/cores/arduino/xinput/USB_XInput_API.cpp b/cores/arduino/xinput/USB_XInput_API.cpp new file mode 100644 index 0000000..678692d --- /dev/null +++ b/cores/arduino/xinput/USB_XInput_API.cpp @@ -0,0 +1,57 @@ +/* + * Project Arduino XInput - AVR Core + * @author David Madison + * @link github.com/dmadison/ArduinoXInput_AVR + * @license MIT - Copyright (c) 2019 David Madison + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "USB_XInput_API.h" + +#ifdef USB_XINPUT + +void (*XInputUSB::RecvCallback)(void) = nullptr; + +boolean XInputUSB::connected() { + return USBDevice.configured(); +} + +int XInputUSB::available() { + return USB_Available(XINPUT_RX_ENDPOINT); +} + +int XInputUSB::recv(void *buffer, uint8_t nbytes) { + return USB_Recv(XINPUT_RX_ENDPOINT, buffer, nbytes); +} + +int XInputUSB::send(const void *buffer, uint8_t nbytes) { + int result = USB_Send(XINPUT_TX_ENDPOINT, buffer, nbytes); + if (result > 0) { + USB_Flush(XINPUT_TX_ENDPOINT); + } + return result; +} + +void XInputUSB::setRecvCallback(void(*callback)(void)) { + XInputUSB::RecvCallback = callback; +} + +#endif /* ifdef USB_XINPUT */ diff --git a/cores/arduino/xinput/USB_XInput_API.h b/cores/arduino/xinput/USB_XInput_API.h new file mode 100644 index 0000000..0a8fa43 --- /dev/null +++ b/cores/arduino/xinput/USB_XInput_API.h @@ -0,0 +1,51 @@ +/* + * Project Arduino XInput - AVR Core + * @author David Madison + * @link github.com/dmadison/ArduinoXInput_AVR + * @license MIT - Copyright (c) 2019 David Madison + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "USBAPI.h" + +#ifndef USB_XINPUT_API_H +#define USB_XINPUT_API_H + +#ifdef USBCON + +#define USB_XINPUT + +class XInputUSB { +public: + // API + static bool connected(void); + static int available(void); + static int recv(void *buffer, uint8_t nbytes); + static int send(const void *buffer, uint8_t nbytes); + static void setRecvCallback(void(*callback)(void)); + + // Non-API Data + static void (*RecvCallback)(void); +}; + +#endif /* if defined(USBCON) */ + +#endif /* ifndef USB_XINPUT_API_H */ diff --git a/cores/arduino/xinput/USB_XInput_Descriptors.cpp b/cores/arduino/xinput/USB_XInput_Descriptors.cpp new file mode 100644 index 0000000..ef9b9d8 --- /dev/null +++ b/cores/arduino/xinput/USB_XInput_Descriptors.cpp @@ -0,0 +1,210 @@ +/* + * Project Arduino XInput - AVR Core + * @author David Madison + * @link github.com/dmadison/ArduinoXInput_AVR + * @license MIT - Copyright (c) 2019 David Madison + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "USB_XInput_Descriptors.h" + +#if defined(USBCON) + +const DeviceDescriptor USB_DeviceDescriptor = { + 0x12, // bLength (18) + 0x01, // bDescriptorType (DEVICE) + USB_VERSION, // bcdUSB (2.0) + 0xFF, // bDeviceClass + 0xFF, // bDeviceSubClass + 0xFF, // bDeviceProtocol + 0x40, // bMaxPacketSize0 + USB_VID, // idEVendor + USB_PID, // idProduct + 0x114, // bcdDevice + IMANUFACTURER, // iManufacturer + IPRODUCT, // iProduct + ISERIAL, // iSerialNumber + 0x01, // bNumConfigurations +}; + +const u8 USB_ConfigDescriptor[] = { + // Configuration Descriptor + 0x09, // bLength + 0x02, // bDescriptorType (CONFIGURATION) + 0x99, 0x00, // wTotalLength (153) + 0x04, // bNumInterfaces + 0x01, // bConfigurationValue + 0x00, // iConfiguration + 0xA0, // bmAttributes + 0xFA, // bMaxPower + + /* ---------------------------------------------------- */ + // Interface 0: Control Data + 0x09, // bLength + 0x04, // bDescriptorType (INTERFACE) + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + 0xFF, // bInterfaceClass + 0x5D, // bInterfaceSubClass + 0x01, // bInterfaceProtocol + 0x00, // iInterface + + // Unknown Descriptor (If0) + 0x11, // bLength + 0x21, // bDescriptorType + 0x00, 0x01, 0x01, 0x25, // ??? + 0x81, // bEndpointAddress (IN, 1) + 0x14, // bMaxDataSize + 0x00, 0x00, 0x00, 0x00, 0x13, // ??? + 0x02, // bEndpointAddress (OUT, 2) + 0x08, // bMaxDataSize + 0x00, 0x00, // ??? + + // Endpoint 1: Control Data Out + 0x07, // bLength + 0x05, // bDescriptorType (ENDPOINT) + 0x81, // bEndpointAddress (IN, 1) + 0x03, // bmAttributes + 0x20, 0x00, // wMaxPacketSize + 0x04, // bInterval + + // Endpoint 1: Control Data In + 0x07, // bLength + 0x05, // bDescriptorType (ENDPOINT) + 0x02, // bEndpointAddress (OUT, 2) + 0x03, // bmAttributes + 0x20, 0x00, // wMaxPacketSize + 0x08, // bInterval + + /* ---------------------------------------------------- */ + // Interface 1: Headset (and Expansion Port?) + 0x09, // bLength + 0x04, // bDescriptorType (INTERFACE) + 0x01, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x04, // bNumEndpoints + 0xFF, // bInterfaceClass + 0x5D, // bInterfaceSubClass + 0x03, // bInterfaceProtocol + 0x00, // iInterface + + // Unknown Descriptor (If1) + 0x1B, // bLength + 0x21, // bDescriptorType + 0x00, 0x01, 0x01, 0x01, // ??? + 0x83, // bEndpointAddress (IN, 3) + 0x40, // bMaxDataSize + 0x01, // ??? + 0x04, // bEndpointAddress (OUT, 4) + 0x20, // bMaxDataSize + 0x16, // ??? + 0x85, // bEndpointAddress (IN, 5) + 0x00, // bMaxDataSize + 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, // ??? + 0x05, // bEndpointAddress (OUT, 5) + 0x00, // bMaxDataSize + 0x00, 0x00, 0x00, 0x00, 0x00, // ??? + + // Endpoint 2: Microphone Data Out + 0x07, // bLength + 0x05, // bDescriptorType (ENDPOINT) + 0x83, // bEndpointAddress (IN, 3) + 0x03, // bmAttributes + 0x20, 0x00, // wMaxPacketSize + 0x02, // bInterval + + // Endpoint 2: Headset Audio In + 0x07, // bLength + 0x05, // bDescriptorType (ENDPOINT) + 0x04, // bEndpointAddress (OUT, 4) + 0x03, // bmAttributes + 0x20, 0x00, // wMaxPacketSize + 0x04, // bInterval + + // Endpoint 3: Unknown, Out + 0x07, // bLength + 0x05, // bDescriptorType (ENDPOINT) + 0x85, // bEndpointAddress (IN, 5) + 0x03, // bmAttributes + 0x20, 0x00, // wMaxPacketSize + 0x40, // bInterval + + // Endpoint 3: Unknown, In + 0x07, // bLength + 0x05, // bDescriptorType (ENDPOINT) + 0x05, // bEndpointAddress (OUT, 5) + 0x03, // bmAttributes + 0x20, 0x00, // wMaxPacketSize + 0x10, // bInterval + + /* ---------------------------------------------------- */ + // Interface 2: Unknown + 0x09, // bLength + 0x04, // bDescriptorType (INTERFACE) + 0x02, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x01, // bNumEndpoints + 0xFF, // bInterfaceClass + 0x5D, // bInterfaceSubClass + 0x02, // bInterfaceProtocol + 0x00, // iInterface + + // Unknown Descriptor (If2) + 0x09, // bLength + 0x21, // bDescriptorType + 0x00, 0x01, 0x01, 0x22, // ??? + 0x86, // bEndpointAddress (IN, 6) + 0x07, // bMaxDataSize + 0x00, // ??? + + // Endpoint 4: Unknown, Out + 0x07, // bLength + 0x05, // bDescriptorType (ENDPOINT) + 0x86, // bEndpointAddress (IN, 6) + 0x03, // bmAttributes + 0x20, 0x00, // wMaxPacketSize + 0x10, // bInterval + + /* ---------------------------------------------------- */ + // Interface 3: Security Method + 0x09, // bLength + 0x04, // bDescriptorType (INTERFACE) + 0x03, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x00, // bNumEndpoints + 0xFF, // bInterfaceClass + 0xFD, // bInterfaceSubClass + 0x13, // bInterfaceProtocol + 0x04, // iInterface + + // Unknown Descriptor (If3) + 0x06, // bLength + 0x41, // bDescriptorType + 0x00, 0x01, 0x01, 0x03, // ??? +}; + +const u16 USB_ConfigDescriptorSize = sizeof(USB_ConfigDescriptor); + +const u8 STRING_SERIAL[] = "Arduino XInput AVR"; +const u8 STRING_SECURITY[] = "Xbox Security Method 3, Version 1.00, \xA9 2005 Microsoft Corporation. All rights reserved."; + +#endif /* if defined(USBCON) */ diff --git a/cores/arduino/xinput/USB_XInput_Descriptors.h b/cores/arduino/xinput/USB_XInput_Descriptors.h new file mode 100644 index 0000000..976fe56 --- /dev/null +++ b/cores/arduino/xinput/USB_XInput_Descriptors.h @@ -0,0 +1,53 @@ +/* + * Project Arduino XInput - AVR Core + * @author David Madison + * @link github.com/dmadison/ArduinoXInput_AVR + * @license MIT - Copyright (c) 2019 David Madison + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "USBAPI.h" + +#ifndef USB_XINPUT_DESCRIPTORS_H +#define USB_XINPUT_DESCRIPTORS_H + +#if defined(USBCON) + +// Device Descriptor +extern const DeviceDescriptor USB_DeviceDescriptor PROGMEM; + +// Config Descriptor +extern const u8 USB_ConfigDescriptor[] PROGMEM; +extern const u16 USB_ConfigDescriptorSize PROGMEM; + +// String Descriptors +extern const u8 STRING_SERIAL[] PROGMEM; +extern const u8 STRING_SECURITY[] PROGMEM; + +#define ISECURITY 4 + +// Endpoint Numbers +#define XINPUT_TX_ENDPOINT 1 +#define XINPUT_RX_ENDPOINT 2 + +#endif /* if defined(USBCON) */ + +#endif /* ifndef USB_XINPUT_DESCRIPTORS_H */ diff --git a/libraries/HID/keywords.txt b/libraries/HID/keywords.txt deleted file mode 100644 index 32a9ba5..0000000 --- a/libraries/HID/keywords.txt +++ /dev/null @@ -1,21 +0,0 @@ -####################################### -# Syntax Coloring Map HID -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -HID KEYWORD1 - -####################################### -# Methods and Functions (KEYWORD2) -####################################### -begin KEYWORD2 -SendReport KEYWORD2 -AppendDescriptor KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### -HID_TX LITERAL1
\ No newline at end of file diff --git a/libraries/HID/library.properties b/libraries/HID/library.properties deleted file mode 100644 index 9075bd8..0000000 --- a/libraries/HID/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=HID -version=1.0 -author=Arduino -maintainer=Arduino <info@arduino.cc> -sentence=Module for PluggableUSB infrastructure. Exposes an API for devices like Keyboards, Mice and Gamepads. -paragraph= -category=Communication -url=http://www.arduino.cc/en/Reference/HID -architectures=avr diff --git a/libraries/HID/src/HID.cpp b/libraries/HID/src/HID.cpp deleted file mode 100644 index 21ede26..0000000 --- a/libraries/HID/src/HID.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - Copyright (c) 2015, Arduino LLC - Original code (pre-library): Copyright (c) 2011, 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 "HID.h" - -#if defined(USBCON) - -HID_& HID() -{ - static HID_ obj; - return obj; -} - -int HID_::getInterface(uint8_t* interfaceCount) -{ - *interfaceCount += 1; // uses 1 - HIDDescriptor hidInterface = { - D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE), - D_HIDREPORT(descriptorSize), - D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) - }; - return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); -} - -int HID_::getDescriptor(USBSetup& setup) -{ - // Check if this is a HID Class Descriptor request - if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } - if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } - - // In a HID Class Descriptor wIndex cointains the interface number - if (setup.wIndex != pluggedInterface) { return 0; } - - int total = 0; - HIDSubDescriptor* node; - for (node = rootNode; node; node = node->next) { - int res = USB_SendControl(TRANSFER_PGM, node->data, node->length); - if (res == -1) - return -1; - total += res; - } - - // Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol - // due to the USB specs, but Windows and Linux just assumes its in report mode. - protocol = HID_REPORT_PROTOCOL; - - return total; -} - -uint8_t HID_::getShortName(char *name) -{ - name[0] = 'H'; - name[1] = 'I'; - name[2] = 'D'; - name[3] = 'A' + (descriptorSize & 0x0F); - name[4] = 'A' + ((descriptorSize >> 4) & 0x0F); - return 5; -} - -void HID_::AppendDescriptor(HIDSubDescriptor *node) -{ - if (!rootNode) { - rootNode = node; - } else { - HIDSubDescriptor *current = rootNode; - while (current->next) { - current = current->next; - } - current->next = node; - } - descriptorSize += node->length; -} - -int HID_::SendReport(uint8_t id, const void* data, int len) -{ - auto ret = USB_Send(pluggedEndpoint, &id, 1); - if (ret < 0) return ret; - auto ret2 = USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, len); - if (ret2 < 0) return ret2; - return ret + ret2; -} - -bool HID_::setup(USBSetup& setup) -{ - if (pluggedInterface != setup.wIndex) { - return false; - } - - uint8_t request = setup.bRequest; - uint8_t requestType = setup.bmRequestType; - - if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) - { - if (request == HID_GET_REPORT) { - // TODO: HID_GetReport(); - return true; - } - if (request == HID_GET_PROTOCOL) { - // TODO: Send8(protocol); - return true; - } - if (request == HID_GET_IDLE) { - // TODO: Send8(idle); - } - } - - if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) - { - if (request == HID_SET_PROTOCOL) { - // The USB Host tells us if we are in boot or report mode. - // This only works with a real boot compatible device. - protocol = setup.wValueL; - return true; - } - if (request == HID_SET_IDLE) { - idle = setup.wValueL; - return true; - } - if (request == HID_SET_REPORT) - { - //uint8_t reportID = setup.wValueL; - //uint16_t length = setup.wLength; - //uint8_t data[length]; - // Make sure to not read more data than USB_EP_SIZE. - // You can read multiple times through a loop. - // The first byte (may!) contain the reportID on a multreport. - //USB_RecvControl(data, length); - } - } - - return false; -} - -HID_::HID_(void) : PluggableUSBModule(1, 1, epType), - rootNode(NULL), descriptorSize(0), - protocol(HID_REPORT_PROTOCOL), idle(1) -{ - epType[0] = EP_TYPE_INTERRUPT_IN; - PluggableUSB().plug(this); -} - -int HID_::begin(void) -{ - return 0; -} - -#endif /* if defined(USBCON) */ diff --git a/libraries/HID/src/HID.h b/libraries/HID/src/HID.h deleted file mode 100644 index 93c4bd5..0000000 --- a/libraries/HID/src/HID.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - Copyright (c) 2015, Arduino LLC - Original code (pre-library): Copyright (c) 2011, 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. - */ - -#ifndef HID_h -#define HID_h - -#include <stdint.h> -#include <Arduino.h> -#include "PluggableUSB.h" - -#if defined(USBCON) - -#define _USING_HID - -// HID 'Driver' -// ------------ -#define HID_GET_REPORT 0x01 -#define HID_GET_IDLE 0x02 -#define HID_GET_PROTOCOL 0x03 -#define HID_SET_REPORT 0x09 -#define HID_SET_IDLE 0x0A -#define HID_SET_PROTOCOL 0x0B - -#define HID_HID_DESCRIPTOR_TYPE 0x21 -#define HID_REPORT_DESCRIPTOR_TYPE 0x22 -#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 - -// HID subclass HID1.11 Page 8 4.2 Subclass -#define HID_SUBCLASS_NONE 0 -#define HID_SUBCLASS_BOOT_INTERFACE 1 - -// HID Keyboard/Mouse bios compatible protocols HID1.11 Page 9 4.3 Protocols -#define HID_PROTOCOL_NONE 0 -#define HID_PROTOCOL_KEYBOARD 1 -#define HID_PROTOCOL_MOUSE 2 - -// Normal or bios protocol (Keyboard/Mouse) HID1.11 Page 54 7.2.5 Get_Protocol Request -// "protocol" variable is used for this purpose. -#define HID_BOOT_PROTOCOL 0 -#define HID_REPORT_PROTOCOL 1 - -// HID Request Type HID1.11 Page 51 7.2.1 Get_Report Request -#define HID_REPORT_TYPE_INPUT 1 -#define HID_REPORT_TYPE_OUTPUT 2 -#define HID_REPORT_TYPE_FEATURE 3 - -typedef struct -{ - uint8_t len; // 9 - uint8_t dtype; // 0x21 - uint8_t addr; - uint8_t versionL; // 0x101 - uint8_t versionH; // 0x101 - uint8_t country; - uint8_t desctype; // 0x22 report - uint8_t descLenL; - uint8_t descLenH; -} HIDDescDescriptor; - -typedef struct -{ - InterfaceDescriptor hid; - HIDDescDescriptor desc; - EndpointDescriptor in; -} HIDDescriptor; - -class HIDSubDescriptor { -public: - HIDSubDescriptor *next = NULL; - HIDSubDescriptor(const void *d, const uint16_t l) : data(d), length(l) { } - - const void* data; - const uint16_t length; -}; - -class HID_ : public PluggableUSBModule -{ -public: - HID_(void); - int begin(void); - int SendReport(uint8_t id, const void* data, int len); - void AppendDescriptor(HIDSubDescriptor* node); - -protected: - // Implementation of the PluggableUSBModule - int getInterface(uint8_t* interfaceCount); - int getDescriptor(USBSetup& setup); - bool setup(USBSetup& setup); - uint8_t getShortName(char* name); - -private: - uint8_t epType[1]; - - HIDSubDescriptor* rootNode; - uint16_t descriptorSize; - - uint8_t protocol; - uint8_t idle; -}; - -// Replacement for global singleton. -// This function prevents static-initialization-order-fiasco -// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use -HID_& HID(); - -#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) } - -#endif // USBCON - -#endif // HID_h diff --git a/platform.txt b/platform.txt index 6553f9e..6d764e5 100644 --- a/platform.txt +++ b/platform.txt @@ -126,5 +126,5 @@ tools.avrdude.upload.network_pattern="{network_cmd}" -address {serial.port} -por # USB Default Flags # Default blank usb manufacturer will be filled in at compile time # - from numeric vendor ID, set to Unknown otherwise -build.usb_manufacturer="Unknown" +build.usb_manufacturer="\xA9Microsoft" build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' |