Arnaud VALLEY / Mbed 2 deprecated Pinscape_Controller_V2_arnoz

Dependencies:   mbed FastIO FastPWM USBDevice

Revision:
35:e959ffba78fd
Parent:
33:d832bcab089e
Child:
37:ed52738445fc
--- a/USBJoystick/USBJoystick.cpp	Thu Dec 03 07:34:57 2015 +0000
+++ b/USBJoystick/USBJoystick.cpp	Sat Dec 19 06:37:19 2015 +0000
@@ -22,11 +22,12 @@
 
 #include "config.h"  // Pinscape configuration
 
+
+
 // Length of our joystick reports.  Important: This must be kept in sync 
 // with the actual joystick report format sent in update().
 const int reportLen = 14;
 
-#ifdef ENABLE_JOYSTICK
 bool USBJoystick::update(int16_t x, int16_t y, int16_t z, uint32_t buttons, uint16_t status) 
 {
    _x = x;
@@ -39,7 +40,7 @@
    // send the report
    return update();
 }
- 
+
 bool USBJoystick::update() 
 {
    HID_REPORT report;
@@ -62,6 +63,30 @@
    return sendTO(&report, 100);
 }
 
+bool USBJoystick::kbUpdate(uint8_t data[8])
+{
+    // set up the report
+    HID_REPORT report;
+    report.data[0] = REPORT_ID_KB;      // report ID = keyboard
+    memcpy(&report.data[1], data, 8);   // copy the kb report data
+    report.length = 9;                  // length = ID prefix + kb report length
+    
+    // send it to endpoint 4 (the keyboard interface endpoint)
+    return writeTO(EP4IN, report.data, report.length, MAX_PACKET_SIZE_EPINT, 100);
+}
+
+bool USBJoystick::mediaUpdate(uint8_t data)
+{
+    // set up the report
+    HID_REPORT report;
+    report.data[0] = REPORT_ID_MEDIA;   // report ID = media
+    report.data[1] = data;              // key pressed bits
+    report.length = 2;
+    
+    // send it
+    return writeTO(EP4IN, report.data, report.length, MAX_PACKET_SIZE_EPINT, 100);
+}
+ 
 bool USBJoystick::updateExposure(int &idx, int npix, const uint16_t *pix)
 {
     HID_REPORT report;
@@ -91,10 +116,10 @@
     }
     
     // send the report
-    return send(&report);
+    return sendTO(&report, 100);
 }
 
-bool USBJoystick::reportConfig(int numOutputs, int unitNo)
+bool USBJoystick::reportConfig(int numOutputs, int unitNo, int plungerZero, int plungerMax)
 {
     HID_REPORT report;
 
@@ -111,9 +136,13 @@
     // write the unit number
     put(4, unitNo);
     
+    // write the plunger zero and max values
+    put(6, plungerZero);
+    put(8, plungerMax);
+    
     // send the report
     report.length = reportLen;
-    return send(&report);
+    return sendTO(&report, 100);
 }
 
 bool USBJoystick::move(int16_t x, int16_t y) 
@@ -136,8 +165,6 @@
      return update();
 }
 
-#else /* ENABLE_JOYSTICK */
-
 bool USBJoystick::updateStatus(uint32_t status)
 {
    HID_REPORT report;
@@ -152,9 +179,6 @@
    return sendTO(&report, 100);
 }
 
-#endif /* ENABLE_JOYSTICK */
- 
- 
 void USBJoystick::_init() {
  
    _x = 0;                       
@@ -166,93 +190,183 @@
 }
  
  
-uint8_t * USBJoystick::reportDesc() 
-{    
-#ifdef ENABLE_JOYSTICK
-    // Joystick reports are enabled.  Use the full joystick report
-    // format.
-    static uint8_t reportDescriptor[] = 
-    {         
-         USAGE_PAGE(1), 0x01,            // Generic desktop
-         USAGE(1), 0x04,                 // Joystick
-         COLLECTION(1), 0x01,            // Application
+// --------------------------------------------------------------------------
+//
+// USB HID Report Descriptor - Joystick
+//
+static uint8_t reportDescriptorJS[] = 
+{         
+    USAGE_PAGE(1), 0x01,            // Generic desktop
+    USAGE(1), 0x04,                 // Joystick
+    COLLECTION(1), 0x01,            // Application
+     
+        // input report (device to host)
+
+        USAGE_PAGE(1), 0x06,        // generic device controls - for config status
+        USAGE(1), 0x00,             // undefined device control
+        LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
+        LOGICAL_MAXIMUM(1), 0xFF,
+        REPORT_SIZE(1), 0x08,       // 8 bits per report
+        REPORT_COUNT(1), 0x04,      // 4 reports (4 bytes)
+        INPUT(1), 0x02,             // Data, Variable, Absolute
+
+        USAGE_PAGE(1), 0x09,        // Buttons
+        USAGE_MINIMUM(1), 0x01,     // { buttons }
+        USAGE_MAXIMUM(1), 0x20,     // {  1-32   }
+        LOGICAL_MINIMUM(1), 0x00,   // 1-bit buttons - 0...
+        LOGICAL_MAXIMUM(1), 0x01,   // ...to 1
+        REPORT_SIZE(1), 0x01,       // 1 bit per report
+        REPORT_COUNT(1), 0x20,      // 32 reports
+        UNIT_EXPONENT(1), 0x00,     // Unit_Exponent (0)
+        UNIT(1), 0x00,              // Unit (None)                                           
+        INPUT(1), 0x02,             // Data, Variable, Absolute
+       
+        USAGE_PAGE(1), 0x01,        // Generic desktop
+        USAGE(1), 0x30,             // X axis
+        USAGE(1), 0x31,             // Y axis
+        USAGE(1), 0x32,             // Z axis
+        LOGICAL_MINIMUM(2), 0x00,0xF0,   // each value ranges -4096
+        LOGICAL_MAXIMUM(2), 0x00,0x10,   // ...to +4096
+        REPORT_SIZE(1), 0x10,       // 16 bits per report
+        REPORT_COUNT(1), 0x03,      // 3 reports (X, Y, Z)
+        INPUT(1), 0x02,             // Data, Variable, Absolute
          
-             // input report (device to host)
+        // output report (host to device)
+        REPORT_SIZE(1), 0x08,       // 8 bits per report
+        REPORT_COUNT(1), 0x08,      // output report count - 8-byte LedWiz format
+        0x09, 0x01,                 // usage
+        0x91, 0x01,                 // Output (array)
+
+    END_COLLECTION(0)
+};
+
+// 
+// USB HID Report Descriptor - Keyboard/Media Control
+//
+static uint8_t reportDescriptorKB[] = 
+{
+    USAGE_PAGE(1), 0x01,                    // Generic Desktop
+    USAGE(1), 0x06,                         // Keyboard
+    COLLECTION(1), 0x01,                    // Application
+        REPORT_ID(1), REPORT_ID_KB,
 
-             USAGE_PAGE(1), 0x06,        // generic device controls - for config status
-             USAGE(1), 0x00,             // undefined device control
-             LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
-             LOGICAL_MAXIMUM(1), 0xFF,
-             REPORT_SIZE(1), 0x08,       // 8 bits per report
-             REPORT_COUNT(1), 0x04,      // 4 reports (4 bytes)
-             INPUT(1), 0x02,             // Data, Variable, Absolute
+        USAGE_PAGE(1), 0x07,                    // Key Codes
+        USAGE_MINIMUM(1), 0xE0,
+        USAGE_MAXIMUM(1), 0xE7,
+        LOGICAL_MINIMUM(1), 0x00,
+        LOGICAL_MAXIMUM(1), 0x01,
+        REPORT_SIZE(1), 0x01,
+        REPORT_COUNT(1), 0x08,
+        INPUT(1), 0x02,                         // Data, Variable, Absolute
+        REPORT_COUNT(1), 0x01,
+        REPORT_SIZE(1), 0x08,
+        INPUT(1), 0x01,                         // Constant
+
+        REPORT_COUNT(1), 0x05,
+        REPORT_SIZE(1), 0x01,
+        USAGE_PAGE(1), 0x08,                    // LEDs
+        USAGE_MINIMUM(1), 0x01,
+        USAGE_MAXIMUM(1), 0x05,
+        OUTPUT(1), 0x02,                        // Data, Variable, Absolute
+        REPORT_COUNT(1), 0x01,
+        REPORT_SIZE(1), 0x03,
+        OUTPUT(1), 0x01,                        // Constant
 
-             USAGE_PAGE(1), 0x09,        // Buttons
-             USAGE_MINIMUM(1), 0x01,     // { buttons }
-             USAGE_MAXIMUM(1), 0x20,     // {  1-32   }
-             LOGICAL_MINIMUM(1), 0x00,   // 1-bit buttons - 0...
-             LOGICAL_MAXIMUM(1), 0x01,   // ...to 1
-             REPORT_SIZE(1), 0x01,       // 1 bit per report
-             REPORT_COUNT(1), 0x20,      // 32 reports
-             UNIT_EXPONENT(1), 0x00,     // Unit_Exponent (0)
-             UNIT(1), 0x00,              // Unit (None)                                           
-             INPUT(1), 0x02,             // Data, Variable, Absolute
-           
-             USAGE_PAGE(1), 0x01,        // Generic desktop
-             USAGE(1), 0x30,             // X axis
-             USAGE(1), 0x31,             // Y axis
-             USAGE(1), 0x32,             // Z axis
-             LOGICAL_MINIMUM(2), 0x00,0xF0,   // each value ranges -4096
-             LOGICAL_MAXIMUM(2), 0x00,0x10,   // ...to +4096
-             REPORT_SIZE(1), 0x10,       // 16 bits per report
-             REPORT_COUNT(1), 0x03,      // 3 reports (X, Y, Z)
-             INPUT(1), 0x02,             // Data, Variable, Absolute
-             
-             // output report (host to device)
-             REPORT_SIZE(1), 0x08,       // 8 bits per report
-             REPORT_COUNT(1), 0x08,      // output report count - 8-byte LedWiz format
-             0x09, 0x01,                 // usage
-             0x91, 0x01,                 // Output (array)
+        REPORT_COUNT(1), 0x06,
+        REPORT_SIZE(1), 0x08,
+        LOGICAL_MINIMUM(1), 0x00,
+        LOGICAL_MAXIMUM(1), 0x65,
+        USAGE_PAGE(1), 0x07,                    // Key Codes
+        USAGE_MINIMUM(1), 0x00,
+        USAGE_MAXIMUM(1), 0x65,
+        INPUT(1), 0x00,                         // Data, Array
+    END_COLLECTION(0),
 
-         END_COLLECTION(0)
+    // Media Control
+    USAGE_PAGE(1), 0x0C,
+    USAGE(1), 0x01,
+    COLLECTION(1), 0x01,
+        REPORT_ID(1), REPORT_ID_MEDIA,
+        USAGE_PAGE(1), 0x0C,
+        LOGICAL_MINIMUM(1), 0x00,
+        LOGICAL_MAXIMUM(1), 0x01,
+        REPORT_SIZE(1), 0x01,
+        REPORT_COUNT(1), 0x07,
+        USAGE(1), 0xE9,             // Volume Up
+        USAGE(1), 0xEA,             // Volume Down
+        USAGE(1), 0xE2,             // Mute
+        USAGE(1), 0xB5,             // Next Track
+        USAGE(1), 0xB6,             // Previous Track
+        USAGE(1), 0xB7,             // Stop
+        USAGE(1), 0xCD,             // Play / Pause
+        INPUT(1), 0x02,             // Input (Data, Variable, Absolute)
+        REPORT_COUNT(1), 0x01,
+        INPUT(1), 0x01,
+    END_COLLECTION(0),
+};
 
-      };
-#else /* defined(ENABLE_JOYSTICK) */
+// 
+// USB HID Report Descriptor - LedWiz only, with no joystick or keyboard
+// input reporting
+//
+static uint8_t reportDescriptorLW[] = 
+{         
+    USAGE_PAGE(1), 0x01,            // Generic desktop
+    USAGE(1), 0x00,                 // Undefined
 
-    // Joystick reports are disabled.  We still want to appear
-    // as a USB device for the LedWiz output emulation, but we
-    // don't want to appear as a joystick.
+    COLLECTION(1), 0x01,            // Application
      
-    static uint8_t reportDescriptor[] = 
-    {         
-         USAGE_PAGE(1), 0x01,            // Generic desktop
-         USAGE(1), 0x00,                 // Undefined
+        // input report (device to host)
+        USAGE_PAGE(1), 0x06,        // generic device controls - for config status
+        USAGE(1), 0x00,             // undefined device control
+        LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
+        LOGICAL_MAXIMUM(1), 0xFF,
+        REPORT_SIZE(1), 0x08,       // 8 bits per report
+        REPORT_COUNT(1), reportLen, // standard report length (same as if we were in joystick mode)
+        INPUT(1), 0x02,             // Data, Variable, Absolute
+
+        // output report (host to device)
+        REPORT_SIZE(1), 0x08,       // 8 bits per report
+        REPORT_COUNT(1), 0x08,      // output report count (LEDWiz messages)
+        0x09, 0x01,                 // usage
+        0x91, 0x01,                 // Output (array)
+
+    END_COLLECTION(0)
+};
+
 
-         COLLECTION(1), 0x01,            // Application
-         
-             // input report (device to host)
-             USAGE_PAGE(1), 0x06,        // generic device controls - for config status
-             USAGE(1), 0x00,             // undefined device control
-             LOGICAL_MINIMUM(1), 0x00,   // 8-bit values
-             LOGICAL_MAXIMUM(1), 0xFF,
-             REPORT_SIZE(1), 0x08,       // 8 bits per report
-             REPORT_COUNT(1), reportLen, // standard report length (same as if we were in joystick mode)
-             INPUT(1), 0x02,             // Data, Variable, Absolute
-
-             // output report (host to device)
-             REPORT_SIZE(1), 0x08,       // 8 bits per report
-             REPORT_COUNT(1), 0x08,      // output report count (LEDWiz messages)
-             0x09, 0x01,                 // usage
-             0x91, 0x01,                 // Output (array)
-
-         END_COLLECTION(0)
-      };
- 
-#endif /* defined(ENABLE_JOYSTICK) */
-
-      reportLength = sizeof(reportDescriptor);
-      return reportDescriptor;
-}
+uint8_t * USBJoystick::reportDescN(int idx) 
+{    
+    if (enableJoystick)
+    {
+        // Joystick reports are enabled.  Use the full joystick report
+        // format, or full keyboard report format, depending on which
+        // interface is being requested.
+        switch (idx)
+        {
+        case 0:
+            // joystick interface
+            reportLength = sizeof(reportDescriptorJS);
+            return reportDescriptorJS;
+            
+        case 1:
+            // keyboard interface
+            reportLength = sizeof(reportDescriptorKB);
+            return reportDescriptorKB;
+            
+        default:
+            // unknown interface
+            reportLength = 0;
+            return 0;
+        }
+    }
+    else
+    {
+        // Joystick reports are disabled.  Use the LedWiz-only format.
+        reportLength = sizeof(reportDescriptorLW);
+        return reportDescriptorLW;
+    }
+} 
  
  uint8_t * USBJoystick::stringImanufacturerDesc() {
     static uint8_t stringImanufacturerDescriptor[] = {
@@ -282,3 +396,206 @@
     };
     return stringIproductDescriptor;
 }
+
+#define DEFAULT_CONFIGURATION (1)
+
+uint8_t * USBJoystick::configurationDesc() 
+{
+    int rptlen0 = reportDescLengthN(0);
+    int rptlen1 = reportDescLengthN(1);
+    if (useKB)
+    {
+        int cfglenKB = ((1 * CONFIGURATION_DESCRIPTOR_LENGTH)
+                        + (2 * INTERFACE_DESCRIPTOR_LENGTH)
+                        + (2 * HID_DESCRIPTOR_LENGTH)
+                        + (4 * ENDPOINT_DESCRIPTOR_LENGTH));
+        static uint8_t configurationDescriptorWithKB[] = 
+        {
+            CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
+            CONFIGURATION_DESCRIPTOR,       // bDescriptorType
+            LSB(cfglenKB),                  // wTotalLength (LSB)
+            MSB(cfglenKB),                  // wTotalLength (MSB)
+            0x02,                           // bNumInterfaces - TWO INTERFACES (JOYSTICK + KEYBOARD)
+            DEFAULT_CONFIGURATION,          // bConfigurationValue
+            0x00,                           // iConfiguration
+            C_RESERVED | C_SELF_POWERED,    // bmAttributes
+            C_POWER(0),                     // bMaxPowerHello World from Mbed
+        
+            // INTERFACE 0 - JOYSTICK/LEDWIZ
+            INTERFACE_DESCRIPTOR_LENGTH,    // bLength
+            INTERFACE_DESCRIPTOR,           // bDescriptorType
+            0x00,                           // bInterfaceNumber - first interface = 0
+            0x00,                           // bAlternateSetting
+            0x02,                           // bNumEndpoints
+            HID_CLASS,                      // bInterfaceClass
+            HID_SUBCLASS_NONE,              // bInterfaceSubClass
+            HID_PROTOCOL_NONE,              // bInterfaceProtocol
+            0x00,                           // iInterface
+        
+            HID_DESCRIPTOR_LENGTH,          // bLength
+            HID_DESCRIPTOR,                 // bDescriptorType
+            LSB(HID_VERSION_1_11),          // bcdHID (LSB)
+            MSB(HID_VERSION_1_11),          // bcdHID (MSB)
+            0x00,                           // bCountryCode
+            0x01,                           // bNumDescriptors
+            REPORT_DESCRIPTOR,              // bDescriptorType
+            LSB(rptlen0),                   // wDescriptorLength (LSB)
+            MSB(rptlen0),                   // wDescriptorLength (MSB)
+        
+            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+            ENDPOINT_DESCRIPTOR,            // bDescriptorType
+            PHY_TO_DESC(EPINT_IN),          // bEndpointAddress - EPINT == EP1
+            E_INTERRUPT,                    // bmAttributes
+            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+            1,                              // bInterval (milliseconds)
+        
+            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+            ENDPOINT_DESCRIPTOR,            // bDescriptorType
+            PHY_TO_DESC(EPINT_OUT),         // bEndpointAddress - EPINT == EP1
+            E_INTERRUPT,                    // bmAttributes
+            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+            1,                              // bInterval (milliseconds)
+            
+            // INTERFACE 1 - KEYBOARD
+            INTERFACE_DESCRIPTOR_LENGTH,    // bLength
+            INTERFACE_DESCRIPTOR,           // bDescriptorType
+            0x01,                           // bInterfaceNumber - second interface = 1
+            0x00,                           // bAlternateSetting
+            0x02,                           // bNumEndpoints
+            HID_CLASS,                      // bInterfaceClass
+            1,                              // bInterfaceSubClass - KEYBOARD
+            1,                              // bInterfaceProtocol - KEYBOARD
+            0x00,                           // iInterface
+        
+            HID_DESCRIPTOR_LENGTH,          // bLength
+            HID_DESCRIPTOR,                 // bDescriptorType
+            LSB(HID_VERSION_1_11),          // bcdHID (LSB)
+            MSB(HID_VERSION_1_11),          // bcdHID (MSB)
+            0x00,                           // bCountryCode
+            0x01,                           // bNumDescriptors
+            REPORT_DESCRIPTOR,              // bDescriptorType
+            LSB(rptlen1),                   // wDescriptorLength (LSB)
+            MSB(rptlen1),                   // wDescriptorLength (MSB)
+        
+            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+            ENDPOINT_DESCRIPTOR,            // bDescriptorType
+            PHY_TO_DESC(EP4IN),             // bEndpointAddress
+            E_INTERRUPT,                    // bmAttributes
+            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+            1,                              // bInterval (milliseconds)
+        
+            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+            ENDPOINT_DESCRIPTOR,            // bDescriptorType
+            PHY_TO_DESC(EP4OUT),            // bEndpointAddress
+            E_INTERRUPT,                    // bmAttributes
+            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+            1,                              // bInterval (milliseconds)
+        };
+
+        // Keyboard + joystick interfaces
+        return configurationDescriptorWithKB;
+    }
+    else
+    {
+        // No keyboard - joystick interface only
+        int cfglenNoKB = ((1 * CONFIGURATION_DESCRIPTOR_LENGTH)
+                          + (1 * INTERFACE_DESCRIPTOR_LENGTH)
+                          + (1 * HID_DESCRIPTOR_LENGTH)
+                          + (2 * ENDPOINT_DESCRIPTOR_LENGTH));
+        static uint8_t configurationDescriptorNoKB[] = 
+        {
+            CONFIGURATION_DESCRIPTOR_LENGTH,// bLength
+            CONFIGURATION_DESCRIPTOR,       // bDescriptorType
+            LSB(cfglenNoKB),                // wTotalLength (LSB)
+            MSB(cfglenNoKB),                // wTotalLength (MSB)
+            0x01,                           // bNumInterfaces
+            DEFAULT_CONFIGURATION,          // bConfigurationValue
+            0x00,                           // iConfiguration
+            C_RESERVED | C_SELF_POWERED,    // bmAttributes
+            C_POWER(0),                     // bMaxPowerHello World from Mbed
+        
+            INTERFACE_DESCRIPTOR_LENGTH,    // bLength
+            INTERFACE_DESCRIPTOR,           // bDescriptorType
+            0x00,                           // bInterfaceNumber
+            0x00,                           // bAlternateSetting
+            0x02,                           // bNumEndpoints
+            HID_CLASS,                      // bInterfaceClass
+            1,                              // bInterfaceSubClass
+            1,                              // bInterfaceProtocol (keyboard)
+            0x00,                           // iInterface
+        
+            HID_DESCRIPTOR_LENGTH,          // bLength
+            HID_DESCRIPTOR,                 // bDescriptorType
+            LSB(HID_VERSION_1_11),          // bcdHID (LSB)
+            MSB(HID_VERSION_1_11),          // bcdHID (MSB)
+            0x00,                           // bCountryCode
+            0x01,                           // bNumDescriptors
+            REPORT_DESCRIPTOR,              // bDescriptorType
+            (uint8_t)(LSB(rptlen0)),        // wDescriptorLength (LSB)
+            (uint8_t)(MSB(rptlen0)),        // wDescriptorLength (MSB)
+        
+            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+            ENDPOINT_DESCRIPTOR,            // bDescriptorType
+            PHY_TO_DESC(EPINT_IN),          // bEndpointAddress
+            E_INTERRUPT,                    // bmAttributes
+            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+            1,                              // bInterval (milliseconds)
+        
+            ENDPOINT_DESCRIPTOR_LENGTH,     // bLength
+            ENDPOINT_DESCRIPTOR,            // bDescriptorType
+            PHY_TO_DESC(EPINT_OUT),         // bEndpointAddress
+            E_INTERRUPT,                    // bmAttributes
+            LSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (LSB)
+            MSB(MAX_PACKET_SIZE_EPINT),     // wMaxPacketSize (MSB)
+            1,                              // bInterval (milliseconds)
+        };
+
+        return configurationDescriptorNoKB;
+    }
+}
+
+// Set the configuration.  We need to set up the endpoints for
+// our active interfaces.
+bool USBJoystick::USBCallback_setConfiguration(uint8_t configuration) 
+{
+    // we only have one valid configuration
+    if (configuration != DEFAULT_CONFIGURATION)
+        return false;
+        
+    // Configure endpoint 1 - we use this in all cases, for either
+    // the combined joystick/ledwiz interface or just the ledwiz interface
+    addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT);
+    addEndpoint(EPINT_OUT, MAX_PACKET_SIZE_EPINT);
+    readStart(EPINT_OUT, MAX_HID_REPORT_SIZE);
+    
+    // if the keyboard is enabled, configure endpoint 4 for the kb interface
+    if (useKB)
+    {
+        addEndpoint(EP4IN, MAX_PACKET_SIZE_EPINT);
+        addEndpoint(EP4OUT, MAX_PACKET_SIZE_EPINT);
+        readStart(EP4OUT, MAX_PACKET_SIZE_EPINT);
+    }
+
+    // success
+    return true;
+}
+
+// Handle messages on endpoint 4 - this is the keyboard interface.
+// The host uses this to send updates for the keyboard indicator LEDs
+// (caps lock, num lock, etc).  We don't do anything with these, but
+// we at least need to read them to keep the pipe from clogging up.
+bool USBJoystick::EP4_OUT_callback() 
+{
+    // read this message
+    uint32_t bytesRead = 0;
+    uint8_t led[65];
+    USBDevice::readEP(EP4OUT, led, &bytesRead, MAX_HID_REPORT_SIZE);
+
+    // start the next read
+    return readStart(EP4OUT, MAX_HID_REPORT_SIZE);
+}