]> git.donarmstrong.com Git - qmk_firmware.git/blobdiff - tmk_core/protocol/chibios/usb_main.c
Adds support for Planck Rev 6 (#2666)
[qmk_firmware.git] / tmk_core / protocol / chibios / usb_main.c
index 9bfdf572a10f82b319bc44723df89dd4ae94ad80..e79ff15e8909307a118c9dc319001a4f696eb4dd 100644 (file)
@@ -28,6 +28,8 @@
 #include "led.h"
 #endif
 #include "wait.h"
+#include "usb_descriptor.h"
+#include "usb_driver.h"
 
 #ifdef NKRO_ENABLE
   #include "keycode_config.h"
@@ -63,24 +65,12 @@ report_mouse_t mouse_report_blank = {0};
 uint8_t extra_report_blank[3] = {0};
 #endif /* EXTRAKEY_ENABLE */
 
-#ifdef CONSOLE_ENABLE
-/* The emission buffers queue */
-output_buffers_queue_t console_buf_queue;
-static uint8_t console_queue_buffer[BQ_BUFFER_SIZE(CONSOLE_QUEUE_CAPACITY, CONSOLE_EPSIZE)];
-
-static virtual_timer_t console_flush_timer;
-void console_queue_onotify(io_buffers_queue_t *bqp);
-static void console_flush_cb(void *arg);
-#endif /* CONSOLE_ENABLE */
-
 /* ---------------------------------------------------------
  *            Descriptors and USB driver objects
  * ---------------------------------------------------------
  */
 
 /* HID specific constants */
-#define USB_DESCRIPTOR_HID 0x21
-#define USB_DESCRIPTOR_HID_REPORT 0x22
 #define HID_GET_REPORT 0x01
 #define HID_GET_IDLE 0x02
 #define HID_GET_PROTOCOL 0x03
@@ -88,593 +78,21 @@ static void console_flush_cb(void *arg);
 #define HID_SET_IDLE 0x0A
 #define HID_SET_PROTOCOL 0x0B
 
-/* USB Device Descriptor */
-static const uint8_t usb_device_descriptor_data[] = {
-  USB_DESC_DEVICE(0x0200,      // bcdUSB (1.1)
-                  0,           // bDeviceClass (defined in later in interface)
-                  0,           // bDeviceSubClass
-                  0,           // bDeviceProtocol
-                  64,          // bMaxPacketSize (64 bytes) (the driver didn't work with 32)
-                  VENDOR_ID,   // idVendor
-                  PRODUCT_ID,  // idProduct
-                  DEVICE_VER,      // bcdDevice
-                  1,           // iManufacturer
-                  2,           // iProduct
-                  3,           // iSerialNumber
-                  1)           // bNumConfigurations
-};
-
-/* Device Descriptor wrapper */
-static const USBDescriptor usb_device_descriptor = {
-  sizeof usb_device_descriptor_data,
-  usb_device_descriptor_data
-};
-
-/*
- * HID Report Descriptor
- *
- * See "Device Class Definition for Human Interface Devices (HID)"
- * (http://www.usb.org/developers/hidpage/HID1_11.pdf) for the
- * detailed descrition of all the fields
- */
-
-/* Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 */
-static const uint8_t keyboard_hid_report_desc_data[] = {
-  0x05, 0x01,                // Usage Page (Generic Desktop),
-  0x09, 0x06,                // Usage (Keyboard),
-  0xA1, 0x01,                // Collection (Application),
-  0x75, 0x01,                //   Report Size (1),
-  0x95, 0x08,                //   Report Count (8),
-  0x05, 0x07,                //   Usage Page (Key Codes),
-  0x19, 0xE0,                //   Usage Minimum (224),
-  0x29, 0xE7,                //   Usage Maximum (231),
-  0x15, 0x00,                //   Logical Minimum (0),
-  0x25, 0x01,                //   Logical Maximum (1),
-  0x81, 0x02,                //   Input (Data, Variable, Absolute), ;Modifier byte
-  0x95, 0x01,                //   Report Count (1),
-  0x75, 0x08,                //   Report Size (8),
-  0x81, 0x03,                //   Input (Constant),                 ;Reserved byte
-  0x95, 0x05,                //   Report Count (5),
-  0x75, 0x01,                //   Report Size (1),
-  0x05, 0x08,                //   Usage Page (LEDs),
-  0x19, 0x01,                //   Usage Minimum (1),
-  0x29, 0x05,                //   Usage Maximum (5),
-  0x91, 0x02,                //   Output (Data, Variable, Absolute), ;LED report
-  0x95, 0x01,                //   Report Count (1),
-  0x75, 0x03,                //   Report Size (3),
-  0x91, 0x03,                //   Output (Constant),                 ;LED report padding
-  0x95, KBD_REPORT_KEYS,          //   Report Count (),
-  0x75, 0x08,                //   Report Size (8),
-  0x15, 0x00,                //   Logical Minimum (0),
-  0x26, 0xFF, 0x00,          //   Logical Maximum(255),
-  0x05, 0x07,                //   Usage Page (Key Codes),
-  0x19, 0x00,                //   Usage Minimum (0),
-  0x29, 0xFF,                //   Usage Maximum (255),
-  0x81, 0x00,                //   Input (Data, Array),
-  0xc0                       // End Collection
-};
-/* wrapper */
-static const USBDescriptor keyboard_hid_report_descriptor = {
-  sizeof keyboard_hid_report_desc_data,
-  keyboard_hid_report_desc_data
-};
-
-#ifdef NKRO_ENABLE
-static const uint8_t nkro_hid_report_desc_data[] = {
-  0x05, 0x01,                           // Usage Page (Generic Desktop),
-  0x09, 0x06,                           // Usage (Keyboard),
-  0xA1, 0x01,                           // Collection (Application),
-  // bitmap of modifiers
-  0x75, 0x01,                           //   Report Size (1),
-  0x95, 0x08,                           //   Report Count (8),
-  0x05, 0x07,                           //   Usage Page (Key Codes),
-  0x19, 0xE0,                           //   Usage Minimum (224),
-  0x29, 0xE7,                           //   Usage Maximum (231),
-  0x15, 0x00,                           //   Logical Minimum (0),
-  0x25, 0x01,                           //   Logical Maximum (1),
-  0x81, 0x02,                           //   Input (Data, Variable, Absolute), ;Modifier byte
-  // LED output report
-  0x95, 0x05,                           //   Report Count (5),
-  0x75, 0x01,                           //   Report Size (1),
-  0x05, 0x08,                           //   Usage Page (LEDs),
-  0x19, 0x01,                           //   Usage Minimum (1),
-  0x29, 0x05,                           //   Usage Maximum (5),
-  0x91, 0x02,                           //   Output (Data, Variable, Absolute),
-  0x95, 0x01,                           //   Report Count (1),
-  0x75, 0x03,                           //   Report Size (3),
-  0x91, 0x03,                           //   Output (Constant),
-  // bitmap of keys
-  0x95, NKRO_REPORT_KEYS * 8,           //   Report Count (),
-  0x75, 0x01,                           //   Report Size (1),
-  0x15, 0x00,                           //   Logical Minimum (0),
-  0x25, 0x01,                           //   Logical Maximum(1),
-  0x05, 0x07,                           //   Usage Page (Key Codes),
-  0x19, 0x00,                           //   Usage Minimum (0),
-  0x29, NKRO_REPORT_KEYS * 8 - 1,       //   Usage Maximum (),
-  0x81, 0x02,                           //   Input (Data, Variable, Absolute),
-  0xc0                                  // End Collection
-};
-/* wrapper */
-static const USBDescriptor nkro_hid_report_descriptor = {
-  sizeof nkro_hid_report_desc_data,
-  nkro_hid_report_desc_data
-};
-#endif /* NKRO_ENABLE */
-
-#ifdef MOUSE_ENABLE
-/* Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
- * http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
- * http://www.keil.com/forum/15671/
- * http://www.microsoft.com/whdc/device/input/wheel.mspx */
-static const uint8_t mouse_hid_report_desc_data[] = {
-  /* mouse */
-  0x05, 0x01,                      // USAGE_PAGE (Generic Desktop)
-  0x09, 0x02,                      // USAGE (Mouse)
-  0xa1, 0x01,                      // COLLECTION (Application)
-  //0x85, REPORT_ID_MOUSE,         //   REPORT_ID (1)
-  0x09, 0x01,                      //   USAGE (Pointer)
-  0xa1, 0x00,                      //   COLLECTION (Physical)
-                                   // ----------------------------  Buttons
-  0x05, 0x09,                      //     USAGE_PAGE (Button)
-  0x19, 0x01,                      //     USAGE_MINIMUM (Button 1)
-  0x29, 0x05,                      //     USAGE_MAXIMUM (Button 5)
-  0x15, 0x00,                      //     LOGICAL_MINIMUM (0)
-  0x25, 0x01,                      //     LOGICAL_MAXIMUM (1)
-  0x75, 0x01,                      //     REPORT_SIZE (1)
-  0x95, 0x05,                      //     REPORT_COUNT (5)
-  0x81, 0x02,                      //     INPUT (Data,Var,Abs)
-  0x75, 0x03,                      //     REPORT_SIZE (3)
-  0x95, 0x01,                      //     REPORT_COUNT (1)
-  0x81, 0x03,                      //     INPUT (Cnst,Var,Abs)
-                                   // ----------------------------  X,Y position
-  0x05, 0x01,                      //     USAGE_PAGE (Generic Desktop)
-  0x09, 0x30,                      //     USAGE (X)
-  0x09, 0x31,                      //     USAGE (Y)
-  0x15, 0x81,                      //     LOGICAL_MINIMUM (-127)
-  0x25, 0x7f,                      //     LOGICAL_MAXIMUM (127)
-  0x75, 0x08,                      //     REPORT_SIZE (8)
-  0x95, 0x02,                      //     REPORT_COUNT (2)
-  0x81, 0x06,                      //     INPUT (Data,Var,Rel)
-                                   // ----------------------------  Vertical wheel
-  0x09, 0x38,                      //     USAGE (Wheel)
-  0x15, 0x81,                      //     LOGICAL_MINIMUM (-127)
-  0x25, 0x7f,                      //     LOGICAL_MAXIMUM (127)
-  0x35, 0x00,                      //     PHYSICAL_MINIMUM (0)        - reset physical
-  0x45, 0x00,                      //     PHYSICAL_MAXIMUM (0)
-  0x75, 0x08,                      //     REPORT_SIZE (8)
-  0x95, 0x01,                      //     REPORT_COUNT (1)
-  0x81, 0x06,                      //     INPUT (Data,Var,Rel)
-                                   // ----------------------------  Horizontal wheel
-  0x05, 0x0c,                      //     USAGE_PAGE (Consumer Devices)
-  0x0a, 0x38, 0x02,                //     USAGE (AC Pan)
-  0x15, 0x81,                      //     LOGICAL_MINIMUM (-127)
-  0x25, 0x7f,                      //     LOGICAL_MAXIMUM (127)
-  0x75, 0x08,                      //     REPORT_SIZE (8)
-  0x95, 0x01,                      //     REPORT_COUNT (1)
-  0x81, 0x06,                      //     INPUT (Data,Var,Rel)
-  0xc0,                            //   END_COLLECTION
-  0xc0,                            // END_COLLECTION
-};
-/* wrapper */
-static const USBDescriptor mouse_hid_report_descriptor = {
-  sizeof mouse_hid_report_desc_data,
-  mouse_hid_report_desc_data
-};
-#endif /* MOUSE_ENABLE */
-
-#ifdef CONSOLE_ENABLE
-static const uint8_t console_hid_report_desc_data[] = {
-  0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined)
-  0x09, 0x74,       // Usage 0x74
-  0xA1, 0x53,       // Collection 0x53
-  0x75, 0x08,       // report size = 8 bits
-  0x15, 0x00,       // logical minimum = 0
-  0x26, 0xFF, 0x00, // logical maximum = 255
-  0x95, CONSOLE_EPSIZE, // report count
-  0x09, 0x75,       // usage
-  0x81, 0x02,       // Input (array)
-  0xC0              // end collection
-};
-/* wrapper */
-static const USBDescriptor console_hid_report_descriptor = {
-  sizeof console_hid_report_desc_data,
-  console_hid_report_desc_data
-};
-#endif /* CONSOLE_ENABLE */
-
-#ifdef EXTRAKEY_ENABLE
-/* audio controls & system controls
- * http://www.microsoft.com/whdc/archive/w2kbd.mspx */
-static const uint8_t extra_hid_report_desc_data[] = {
-  /* system control */
-  0x05, 0x01,                      // USAGE_PAGE (Generic Desktop)
-  0x09, 0x80,                      // USAGE (System Control)
-  0xa1, 0x01,                      // COLLECTION (Application)
-  0x85, REPORT_ID_SYSTEM,          //   REPORT_ID (2)
-  0x15, 0x01,                      //   LOGICAL_MINIMUM (0x1)
-  0x25, 0xb7,                      //   LOGICAL_MAXIMUM (0xb7)
-  0x19, 0x01,                      //   USAGE_MINIMUM (0x1)
-  0x29, 0xb7,                      //   USAGE_MAXIMUM (0xb7)
-  0x75, 0x10,                      //   REPORT_SIZE (16)
-  0x95, 0x01,                      //   REPORT_COUNT (1)
-  0x81, 0x00,                      //   INPUT (Data,Array,Abs)
-  0xc0,                            // END_COLLECTION
-  /* consumer */
-  0x05, 0x0c,                      // USAGE_PAGE (Consumer Devices)
-  0x09, 0x01,                      // USAGE (Consumer Control)
-  0xa1, 0x01,                      // COLLECTION (Application)
-  0x85, REPORT_ID_CONSUMER,        //   REPORT_ID (3)
-  0x15, 0x01,                      //   LOGICAL_MINIMUM (0x1)
-  0x26, 0x9c, 0x02,                //   LOGICAL_MAXIMUM (0x29c)
-  0x19, 0x01,                      //   USAGE_MINIMUM (0x1)
-  0x2a, 0x9c, 0x02,                //   USAGE_MAXIMUM (0x29c)
-  0x75, 0x10,                      //   REPORT_SIZE (16)
-  0x95, 0x01,                      //   REPORT_COUNT (1)
-  0x81, 0x00,                      //   INPUT (Data,Array,Abs)
-  0xc0,                            // END_COLLECTION
-};
-/* wrapper */
-static const USBDescriptor extra_hid_report_descriptor = {
-  sizeof extra_hid_report_desc_data,
-  extra_hid_report_desc_data
-};
-#endif /* EXTRAKEY_ENABLE */
-
-
-/*
- * Configuration Descriptor tree for a HID device
- *
- * The HID Specifications version 1.11 require the following order:
- * - Configuration Descriptor
- * - Interface Descriptor
- * - HID Descriptor
- * - Endpoints Descriptors
- */
-#define KBD_HID_DESC_NUM                0
-#define KBD_HID_DESC_OFFSET             (9 + (9 + 9 + 7) * KBD_HID_DESC_NUM + 9)
-
-#ifdef MOUSE_ENABLE
-#   define MOUSE_HID_DESC_NUM           (KBD_HID_DESC_NUM + 1)
-#   define MOUSE_HID_DESC_OFFSET        (9 + (9 + 9 + 7) * MOUSE_HID_DESC_NUM + 9)
-#else /* MOUSE_ENABLE */
-#   define MOUSE_HID_DESC_NUM           (KBD_HID_DESC_NUM + 0)
-#endif /* MOUSE_ENABLE */
-
-#ifdef CONSOLE_ENABLE
-#define CONSOLE_HID_DESC_NUM            (MOUSE_HID_DESC_NUM + 1)
-#define CONSOLE_HID_DESC_OFFSET         (9 + (9 + 9 + 7) * CONSOLE_HID_DESC_NUM + 9)
-#else /* CONSOLE_ENABLE */
-#   define CONSOLE_HID_DESC_NUM         (MOUSE_HID_DESC_NUM + 0)
-#endif /* CONSOLE_ENABLE */
-
-#ifdef EXTRAKEY_ENABLE
-#   define EXTRA_HID_DESC_NUM           (CONSOLE_HID_DESC_NUM + 1)
-#   define EXTRA_HID_DESC_OFFSET        (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
-#else /* EXTRAKEY_ENABLE */
-#   define EXTRA_HID_DESC_NUM           (CONSOLE_HID_DESC_NUM + 0)
-#endif /* EXTRAKEY_ENABLE */
-
-#ifdef NKRO_ENABLE
-#   define NKRO_HID_DESC_NUM            (EXTRA_HID_DESC_NUM + 1)
-#   define NKRO_HID_DESC_OFFSET         (9 + (9 + 9 + 7) * EXTRA_HID_DESC_NUM + 9)
-#else /* NKRO_ENABLE */
-#   define NKRO_HID_DESC_NUM            (EXTRA_HID_DESC_NUM + 0)
-#endif /* NKRO_ENABLE */
-
-#define NUM_INTERFACES                  (NKRO_HID_DESC_NUM + 1)
-#define CONFIG1_DESC_SIZE               (9 + (9 + 9 + 7) * NUM_INTERFACES)
-
-static const uint8_t hid_configuration_descriptor_data[] = {
-  /* Configuration Descriptor (9 bytes) USB spec 9.6.3, page 264-266, Table 9-10 */
-  USB_DESC_CONFIGURATION(CONFIG1_DESC_SIZE, // wTotalLength
-                         NUM_INTERFACES,    // bNumInterfaces
-                         1,    // bConfigurationValue
-                         0,    // iConfiguration
-                         0xA0, // bmAttributes (RESERVED|REMOTEWAKEUP)
-                         50),  // bMaxPower (50mA)
-
-  /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
-  USB_DESC_INTERFACE(KBD_INTERFACE,        // bInterfaceNumber
-                     0,        // bAlternateSetting
-                     1,        // bNumEndpoints
-                     0x03,     // bInterfaceClass: HID
-                     0x01,     // bInterfaceSubClass: Boot
-                     0x01,     // bInterfaceProtocol: Keyboard
-                     0),       // iInterface
-
-  /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
-  USB_DESC_BYTE(9),            // bLength
-  USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
-  USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
-  USB_DESC_BYTE(0),            // bCountryCode
-  USB_DESC_BYTE(1),            // bNumDescriptors
-  USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
-  USB_DESC_WORD(sizeof(keyboard_hid_report_desc_data)), // wDescriptorLength
-
-  /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
-  USB_DESC_ENDPOINT(KBD_ENDPOINT | 0x80,  // bEndpointAddress
-                    0x03,      // bmAttributes (Interrupt)
-                    KBD_EPSIZE,// wMaxPacketSize
-                    10),       // bInterval
-
-  #ifdef MOUSE_ENABLE
-  /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
-  USB_DESC_INTERFACE(MOUSE_INTERFACE,   // bInterfaceNumber
-                     0,        // bAlternateSetting
-                     1,        // bNumEndpoints
-                     0x03,     // bInterfaceClass (0x03 = HID)
-                     // ThinkPad T23 BIOS doesn't work with boot mouse.
-                     0x00,     // bInterfaceSubClass (0x01 = Boot)
-                     0x00,     // bInterfaceProtocol (0x02 = Mouse)
-                     /*
-                        0x01,      // bInterfaceSubClass (0x01 = Boot)
-                        0x02,      // bInterfaceProtocol (0x02 = Mouse)
-                      */
-                     0),        // iInterface
-
-  /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
-  USB_DESC_BYTE(9),            // bLength
-  USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
-  USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
-  USB_DESC_BYTE(0),            // bCountryCode
-  USB_DESC_BYTE(1),            // bNumDescriptors
-  USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
-  USB_DESC_WORD(sizeof(mouse_hid_report_desc_data)), // wDescriptorLength
-
-  /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
-  USB_DESC_ENDPOINT(MOUSE_ENDPOINT | 0x80,  // bEndpointAddress
-                    0x03,      // bmAttributes (Interrupt)
-                    MOUSE_EPSIZE,  // wMaxPacketSize
-                    1),        // bInterval
-  #endif /* MOUSE_ENABLE */
-
-  #ifdef CONSOLE_ENABLE
-  /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
-  USB_DESC_INTERFACE(CONSOLE_INTERFACE, // bInterfaceNumber
-                     0,        // bAlternateSetting
-                     1,        // bNumEndpoints
-                     0x03,     // bInterfaceClass: HID
-                     0x00,     // bInterfaceSubClass: None
-                     0x00,     // bInterfaceProtocol: None
-                     0),       // iInterface
-
-  /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
-  USB_DESC_BYTE(9),            // bLength
-  USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
-  USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
-  USB_DESC_BYTE(0),            // bCountryCode
-  USB_DESC_BYTE(1),            // bNumDescriptors
-  USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
-  USB_DESC_WORD(sizeof(console_hid_report_desc_data)), // wDescriptorLength
-
-  /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
-  USB_DESC_ENDPOINT(CONSOLE_ENDPOINT | 0x80,  // bEndpointAddress
-                    0x03,      // bmAttributes (Interrupt)
-                    CONSOLE_EPSIZE, // wMaxPacketSize
-                    1),        // bInterval
-  #endif /* CONSOLE_ENABLE */
-
-  #ifdef EXTRAKEY_ENABLE
-  /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
-  USB_DESC_INTERFACE(EXTRA_INTERFACE, // bInterfaceNumber
-                     0,        // bAlternateSetting
-                     1,        // bNumEndpoints
-                     0x03,     // bInterfaceClass: HID
-                     0x00,     // bInterfaceSubClass: None
-                     0x00,     // bInterfaceProtocol: None
-                     0),       // iInterface
-
-  /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
-  USB_DESC_BYTE(9),            // bLength
-  USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
-  USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
-  USB_DESC_BYTE(0),            // bCountryCode
-  USB_DESC_BYTE(1),            // bNumDescriptors
-  USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
-  USB_DESC_WORD(sizeof(extra_hid_report_desc_data)), // wDescriptorLength
-
-  /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
-  USB_DESC_ENDPOINT(EXTRA_ENDPOINT | 0x80,  // bEndpointAddress
-                    0x03,      // bmAttributes (Interrupt)
-                    EXTRA_EPSIZE, // wMaxPacketSize
-                    10),       // bInterval
-  #endif /* EXTRAKEY_ENABLE */
-
-  #ifdef NKRO_ENABLE
-  /* Interface Descriptor (9 bytes) USB spec 9.6.5, page 267-269, Table 9-12 */
-  USB_DESC_INTERFACE(NKRO_INTERFACE, // bInterfaceNumber
-                     0,        // bAlternateSetting
-                     1,        // bNumEndpoints
-                     0x03,     // bInterfaceClass: HID
-                     0x00,     // bInterfaceSubClass: None
-                     0x00,     // bInterfaceProtocol: None
-                     0),       // iInterface
-
-  /* HID descriptor (9 bytes) HID 1.11 spec, section 6.2.1 */
-  USB_DESC_BYTE(9),            // bLength
-  USB_DESC_BYTE(0x21),         // bDescriptorType (HID class)
-  USB_DESC_BCD(0x0111),        // bcdHID: HID version 1.11
-  USB_DESC_BYTE(0),            // bCountryCode
-  USB_DESC_BYTE(1),            // bNumDescriptors
-  USB_DESC_BYTE(0x22),         // bDescriptorType (report desc)
-  USB_DESC_WORD(sizeof(nkro_hid_report_desc_data)), // wDescriptorLength
-
-  /* Endpoint Descriptor (7 bytes) USB spec 9.6.6, page 269-271, Table 9-13 */
-  USB_DESC_ENDPOINT(NKRO_ENDPOINT | 0x80,  // bEndpointAddress
-                    0x03,      // bmAttributes (Interrupt)
-                    NKRO_EPSIZE, // wMaxPacketSize
-                    1),       // bInterval
-  #endif /* NKRO_ENABLE */
-};
-
-/* Configuration Descriptor wrapper */
-static const USBDescriptor hid_configuration_descriptor = {
-  sizeof hid_configuration_descriptor_data,
-  hid_configuration_descriptor_data
-};
-
-/* wrappers */
-#define HID_DESCRIPTOR_SIZE 9
-static const USBDescriptor keyboard_hid_descriptor = {
-  HID_DESCRIPTOR_SIZE,
-  &hid_configuration_descriptor_data[KBD_HID_DESC_OFFSET]
-};
-#ifdef MOUSE_ENABLE
-static const USBDescriptor mouse_hid_descriptor = {
-  HID_DESCRIPTOR_SIZE,
-  &hid_configuration_descriptor_data[MOUSE_HID_DESC_OFFSET]
-};
-#endif /* MOUSE_ENABLE */
-#ifdef CONSOLE_ENABLE
-static const USBDescriptor console_hid_descriptor = {
-  HID_DESCRIPTOR_SIZE,
-  &hid_configuration_descriptor_data[CONSOLE_HID_DESC_OFFSET]
-};
-#endif /* CONSOLE_ENABLE */
-#ifdef EXTRAKEY_ENABLE
-static const USBDescriptor extra_hid_descriptor = {
-  HID_DESCRIPTOR_SIZE,
-  &hid_configuration_descriptor_data[EXTRA_HID_DESC_OFFSET]
-};
-#endif /* EXTRAKEY_ENABLE */
-#ifdef NKRO_ENABLE
-static const USBDescriptor nkro_hid_descriptor = {
-  HID_DESCRIPTOR_SIZE,
-  &hid_configuration_descriptor_data[NKRO_HID_DESC_OFFSET]
-};
-#endif /* NKRO_ENABLE */
-
-
-/* U.S. English language identifier */
-static const uint8_t usb_string_langid[] = {
-  USB_DESC_BYTE(4),                        // bLength
-  USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
-  USB_DESC_WORD(0x0409)                    // wLANGID (U.S. English)
-};
-
-/* ugly ugly hack */
-#define PP_NARG(...) \
-         PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
-#define PP_NARG_(...) \
-         PP_ARG_N(__VA_ARGS__)
-#define PP_ARG_N( \
-          _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
-         _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
-         _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
-         _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
-         _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
-         _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
-         _61,_62,_63,N,...) N
-#define PP_RSEQ_N() \
-         63,62,61,60,                   \
-         59,58,57,56,55,54,53,52,51,50, \
-         49,48,47,46,45,44,43,42,41,40, \
-         39,38,37,36,35,34,33,32,31,30, \
-         29,28,27,26,25,24,23,22,21,20, \
-         19,18,17,16,15,14,13,12,11,10, \
-         9,8,7,6,5,4,3,2,1,0
-
-/* Vendor string = manufacturer */
-static const uint8_t usb_string_vendor[] = {
-  USB_DESC_BYTE(PP_NARG(USBSTR_MANUFACTURER)+2),                       // bLength
-  USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
-  USBSTR_MANUFACTURER
-};
-
-/* Device Description string = product */
-static const uint8_t usb_string_description[] = {
-  USB_DESC_BYTE(PP_NARG(USBSTR_PRODUCT)+2),           // bLength
-  USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
-  USBSTR_PRODUCT
-};
-
-/* Serial Number string (will be filled by the function init_usb_serial_string) */
-static uint8_t usb_string_serial[] = {
-  USB_DESC_BYTE(22),                       // bLength
-  USB_DESC_BYTE(USB_DESCRIPTOR_STRING),    // bDescriptorType
-  '0', 0, 'x', 0, 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'B', 0, 'E', 0, 'E', 0, 'F', 0
-};
-
-/* Strings wrappers array */
-static const USBDescriptor usb_strings[] = {
-  { sizeof usb_string_langid, usb_string_langid }
-  ,
-  { sizeof usb_string_vendor, usb_string_vendor }
-  ,
-  { sizeof usb_string_description, usb_string_description }
-  ,
-  { sizeof usb_string_serial, usb_string_serial }
-};
-
 /*
  * Handles the GET_DESCRIPTOR callback
  *
  * Returns the proper descriptor
  */
-static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang) {
+static const USBDescriptor *usb_get_descriptor_cb(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t wIndex) {
   (void)usbp;
-  (void)lang;
-  switch(dtype) {
-  /* Generic descriptors */
-  case USB_DESCRIPTOR_DEVICE:   /* Device Descriptor */
-    return &usb_device_descriptor;
-
-  case USB_DESCRIPTOR_CONFIGURATION:    /* Configuration Descriptor */
-    return &hid_configuration_descriptor;
-
-  case USB_DESCRIPTOR_STRING:   /* Strings */
-    if(dindex < 4)
-      return &usb_strings[dindex];
-    break;
-
-  /* HID specific descriptors */
-  case USB_DESCRIPTOR_HID:      /* HID Descriptors */
-    switch(lang) {    /* yea, poor label, it's actually wIndex from the setup packet */
-    case KBD_INTERFACE:
-      return &keyboard_hid_descriptor;
-
-#ifdef MOUSE_ENABLE
-    case MOUSE_INTERFACE:
-      return &mouse_hid_descriptor;
-#endif /* MOUSE_ENABLE */
-#ifdef CONSOLE_ENABLE
-    case CONSOLE_INTERFACE:
-      return &console_hid_descriptor;
-#endif /* CONSOLE_ENABLE */
-#ifdef EXTRAKEY_ENABLE
-    case EXTRA_INTERFACE:
-      return &extra_hid_descriptor;
-#endif /* EXTRAKEY_ENABLE */
-#ifdef NKRO_ENABLE
-    case NKRO_INTERFACE:
-      return &nkro_hid_descriptor;
-#endif /* NKRO_ENABLE */
-    }
-
-  case USB_DESCRIPTOR_HID_REPORT:       /* HID Report Descriptor */
-    switch(lang) {
-    case KBD_INTERFACE:
-      return &keyboard_hid_report_descriptor;
-
-#ifdef MOUSE_ENABLE
-    case MOUSE_INTERFACE:
-      return &mouse_hid_report_descriptor;
-#endif /* MOUSE_ENABLE */
-#ifdef CONSOLE_ENABLE
-    case CONSOLE_INTERFACE:
-      return &console_hid_report_descriptor;
-#endif /* CONSOLE_ENABLE */
-#ifdef EXTRAKEY_ENABLE
-    case EXTRA_INTERFACE:
-      return &extra_hid_report_descriptor;
-#endif /* EXTRAKEY_ENABLE */
-#ifdef NKRO_ENABLE
-    case NKRO_INTERFACE:
-      return &nkro_hid_report_descriptor;
-#endif /* NKRO_ENABLE */
-    }
-  }
-  return NULL;
+  static USBDescriptor desc;
+  uint16_t wValue = ((uint16_t)dtype << 8) | dindex;
+  desc.ud_string = NULL;
+  desc.ud_size = get_usb_descriptor(wValue, wIndex, (const void** const)&desc.ud_string);
+  if (desc.ud_string == NULL)
+    return NULL;
+  else
+    return &desc;
 }
 
 /* keyboard endpoint state structure */
@@ -685,7 +103,7 @@ static const USBEndpointConfig kbd_ep_config = {
   NULL,                         /* SETUP packet notification callback */
   kbd_in_cb,                    /* IN notification callback */
   NULL,                         /* OUT notification callback */
-  KBD_EPSIZE,                   /* IN maximum packet size */
+  KEYBOARD_EPSIZE,              /* IN maximum packet size */
   0,                            /* OUT maximum packet size */
   &kbd_ep_state,                /* IN Endpoint state */
   NULL,                         /* OUT endpoint state */
@@ -712,25 +130,6 @@ static const USBEndpointConfig mouse_ep_config = {
 };
 #endif /* MOUSE_ENABLE */
 
-#ifdef CONSOLE_ENABLE
-/* console endpoint state structure */
-static USBInEndpointState console_ep_state;
-
-/* console endpoint initialization structure (IN) */
-static const USBEndpointConfig console_ep_config = {
-  USB_EP_MODE_TYPE_INTR,        /* Interrupt EP */
-  NULL,                         /* SETUP packet notification callback */
-  console_in_cb,                /* IN notification callback */
-  NULL,                         /* OUT notification callback */
-  CONSOLE_EPSIZE,               /* IN maximum packet size */
-  0,                            /* OUT maximum packet size */
-  &console_ep_state,            /* IN Endpoint state */
-  NULL,                         /* OUT endpoint state */
-  2,                            /* IN multiplier */
-  NULL                          /* SETUP buffer (not a SETUP endpoint) */
-};
-#endif /* CONSOLE_ENABLE */
-
 #ifdef EXTRAKEY_ENABLE
 /* extrakey endpoint state structure */
 static USBInEndpointState extra_ep_state;
@@ -741,7 +140,7 @@ static const USBEndpointConfig extra_ep_config = {
   NULL,                         /* SETUP packet notification callback */
   extra_in_cb,                  /* IN notification callback */
   NULL,                         /* OUT notification callback */
-  EXTRA_EPSIZE,                 /* IN maximum packet size */
+  EXTRAKEY_EPSIZE,              /* IN maximum packet size */
   0,                            /* OUT maximum packet size */
   &extra_ep_state,              /* IN Endpoint state */
   NULL,                         /* OUT endpoint state */
@@ -769,6 +168,132 @@ static const USBEndpointConfig nkro_ep_config = {
 };
 #endif /* NKRO_ENABLE */
 
+typedef struct {
+  size_t queue_capacity_in;
+  size_t queue_capacity_out;
+  USBInEndpointState in_ep_state;
+  USBOutEndpointState out_ep_state;
+  USBInEndpointState int_ep_state;
+  USBEndpointConfig in_ep_config;
+  USBEndpointConfig out_ep_config;
+  USBEndpointConfig int_ep_config;
+  const QMKUSBConfig config;
+  QMKUSBDriver driver;
+} usb_driver_config_t;
+
+#define QMK_USB_DRIVER_CONFIG(stream, notification, fixedsize) { \
+  .queue_capacity_in = stream##_IN_CAPACITY, \
+  .queue_capacity_out = stream##_OUT_CAPACITY, \
+  .in_ep_config = { \
+    .ep_mode = stream##_IN_MODE, \
+    .setup_cb = NULL, \
+    .in_cb = qmkusbDataTransmitted, \
+    .out_cb = NULL, \
+    .in_maxsize = stream##_EPSIZE, \
+    .out_maxsize = 0, \
+    /* The pointer to the states will be filled during initialization */ \
+    .in_state = NULL, \
+    .out_state = NULL, \
+    .ep_buffers = 2, \
+    .setup_buf = NULL \
+  }, \
+  .out_ep_config = { \
+    .ep_mode = stream##_OUT_MODE, \
+    .setup_cb = NULL, \
+    .in_cb = NULL, \
+    .out_cb = qmkusbDataReceived, \
+    .in_maxsize = 0, \
+    .out_maxsize = stream##_EPSIZE, \
+    /* The pointer to the states will be filled during initialization */ \
+    .in_state = NULL, \
+    .out_state = NULL, \
+    .ep_buffers = 2, \
+    .setup_buf = NULL, \
+  }, \
+  .int_ep_config = { \
+    .ep_mode = USB_EP_MODE_TYPE_INTR, \
+    .setup_cb = NULL, \
+    .in_cb = qmkusbInterruptTransmitted, \
+    .out_cb = NULL, \
+    .in_maxsize = CDC_NOTIFICATION_EPSIZE, \
+    .out_maxsize = 0, \
+    /* The pointer to the states will be filled during initialization */ \
+    .in_state = NULL, \
+    .out_state = NULL, \
+    .ep_buffers = 2, \
+    .setup_buf = NULL, \
+  }, \
+  .config = { \
+    .usbp = &USB_DRIVER, \
+    .bulk_in = stream##_IN_EPNUM, \
+    .bulk_out = stream##_OUT_EPNUM, \
+    .int_in = notification, \
+    .in_buffers = stream##_IN_CAPACITY, \
+    .out_buffers = stream##_OUT_CAPACITY, \
+    .in_size = stream##_EPSIZE, \
+    .out_size = stream##_EPSIZE, \
+    .fixed_size = fixedsize, \
+    .ib = (uint8_t[BQ_BUFFER_SIZE(stream##_IN_CAPACITY, stream##_EPSIZE)]) {}, \
+    .ob = (uint8_t[BQ_BUFFER_SIZE(stream##_OUT_CAPACITY,stream##_EPSIZE)]) {}, \
+  } \
+}
+
+typedef struct {
+  union {
+    struct {
+#ifdef CONSOLE_ENABLE
+      usb_driver_config_t console_driver;
+#endif
+#ifdef RAW_ENABLE
+      usb_driver_config_t raw_driver;
+#endif
+#ifdef MIDI_ENABLE
+      usb_driver_config_t midi_driver;
+#endif
+#ifdef VIRTSER_ENABLE
+      usb_driver_config_t serial_driver;
+#endif
+    };
+    usb_driver_config_t array[0];
+  };
+} usb_driver_configs_t;
+
+static usb_driver_configs_t drivers = {
+#ifdef CONSOLE_ENABLE
+  #define CONSOLE_IN_CAPACITY 4
+  #define CONSOLE_OUT_CAPACITY 4
+  #define CONSOLE_IN_MODE USB_EP_MODE_TYPE_INTR
+  #define CONSOLE_OUT_MODE USB_EP_MODE_TYPE_INTR
+  .console_driver = QMK_USB_DRIVER_CONFIG(CONSOLE, 0, true),
+#endif
+#ifdef RAW_ENABLE
+  #define RAW_IN_CAPACITY 4
+  #define RAW_OUT_CAPACITY 4
+  #define RAW_IN_MODE USB_EP_MODE_TYPE_INTR
+  #define RAW_OUT_MODE USB_EP_MODE_TYPE_INTR
+  .raw_driver = QMK_USB_DRIVER_CONFIG(RAW, 0, false),
+#endif
+
+#ifdef MIDI_ENABLE
+  #define MIDI_STREAM_IN_CAPACITY 4
+  #define MIDI_STREAM_OUT_CAPACITY 4
+  #define MIDI_STREAM_IN_MODE USB_EP_MODE_TYPE_BULK
+  #define MIDI_STREAM_OUT_MODE USB_EP_MODE_TYPE_BULK
+  .midi_driver = QMK_USB_DRIVER_CONFIG(MIDI_STREAM, 0, false),
+#endif
+
+#ifdef VIRTSER_ENABLE
+  #define CDC_IN_CAPACITY 4
+  #define CDC_OUT_CAPACITY 4
+  #define CDC_IN_MODE USB_EP_MODE_TYPE_BULK
+  #define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK
+  .serial_driver = QMK_USB_DRIVER_CONFIG(CDC, CDC_NOTIFICATION_EPNUM, false),
+#endif
+};
+
+#define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t))
+
+
 /* ---------------------------------------------------------
  *                  USB driver functions
  * ---------------------------------------------------------
@@ -778,42 +303,56 @@ static const USBEndpointConfig nkro_ep_config = {
  * TODO: maybe disable some things when connection is lost? */
 static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
   switch(event) {
-  case USB_EVENT_RESET:
-    //TODO: from ISR! print("[R]");
-    return;
-
   case USB_EVENT_ADDRESS:
     return;
 
   case USB_EVENT_CONFIGURED:
     osalSysLockFromISR();
     /* Enable the endpoints specified into the configuration. */
-    usbInitEndpointI(usbp, KBD_ENDPOINT, &kbd_ep_config);
+    usbInitEndpointI(usbp, KEYBOARD_IN_EPNUM, &kbd_ep_config);
 #ifdef MOUSE_ENABLE
-    usbInitEndpointI(usbp, MOUSE_ENDPOINT, &mouse_ep_config);
+    usbInitEndpointI(usbp, MOUSE_IN_EPNUM, &mouse_ep_config);
 #endif /* MOUSE_ENABLE */
-#ifdef CONSOLE_ENABLE
-    usbInitEndpointI(usbp, CONSOLE_ENDPOINT, &console_ep_config);
-    /* don't need to start the flush timer, it starts from console_in_cb automatically */
-#endif /* CONSOLE_ENABLE */
 #ifdef EXTRAKEY_ENABLE
-    usbInitEndpointI(usbp, EXTRA_ENDPOINT, &extra_ep_config);
+    usbInitEndpointI(usbp, EXTRAKEY_IN_EPNUM, &extra_ep_config);
 #endif /* EXTRAKEY_ENABLE */
 #ifdef NKRO_ENABLE
-    usbInitEndpointI(usbp, NKRO_ENDPOINT, &nkro_ep_config);
+    usbInitEndpointI(usbp, NKRO_IN_EPNUM, &nkro_ep_config);
 #endif /* NKRO_ENABLE */
+    for (int i=0;i<NUM_USB_DRIVERS;i++) {
+      usbInitEndpointI(usbp, drivers.array[i].config.bulk_in, &drivers.array[i].in_ep_config);
+      usbInitEndpointI(usbp, drivers.array[i].config.bulk_out, &drivers.array[i].out_ep_config);
+      if (drivers.array[i].config.int_in) {
+        usbInitEndpointI(usbp, drivers.array[i].config.int_in, &drivers.array[i].int_ep_config);
+      }
+      qmkusbConfigureHookI(&drivers.array[i].driver);
+    }
     osalSysUnlockFromISR();
     return;
-
   case USB_EVENT_SUSPEND:
-    //TODO: from ISR! print("[S]");
 #ifdef SLEEP_LED_ENABLE
     sleep_led_enable();
 #endif /* SLEEP_LED_ENABLE */
+    /* Falls into.*/
+  case USB_EVENT_UNCONFIGURED:
+    /* Falls into.*/
+  case USB_EVENT_RESET:
+      for (int i=0;i<NUM_USB_DRIVERS;i++) {
+        chSysLockFromISR();
+        /* Disconnection event on suspend.*/
+        qmkusbSuspendHookI(&drivers.array[i].driver);
+        chSysUnlockFromISR();
+      }
     return;
 
   case USB_EVENT_WAKEUP:
     //TODO: from ISR! print("[W]");
+      for (int i=0;i<NUM_USB_DRIVERS;i++) {
+        chSysLockFromISR();
+        /* Disconnection event on suspend.*/
+        qmkusbWakeupHookI(&drivers.array[i].driver);
+        chSysUnlockFromISR();
+      }
     suspend_wakeup_init();
 #ifdef SLEEP_LED_ENABLE
     sleep_led_disable();
@@ -869,7 +408,7 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
       switch(usbp->setup[1]) {   /* bRequest */
       case HID_GET_REPORT:
         switch(usbp->setup[4]) {     /* LSB(wIndex) (check MSB==0?) */
-        case KBD_INTERFACE:
+        case KEYBOARD_INTERFACE:
 #ifdef NKRO_ENABLE
         case NKRO_INTERFACE:
 #endif /* NKRO_ENABLE */
@@ -884,15 +423,8 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
           break;
 #endif /* MOUSE_ENABLE */
 
-#ifdef CONSOLE_ENABLE
-        case CONSOLE_INTERFACE:
-          usbSetupTransfer(usbp, console_queue_buffer, CONSOLE_EPSIZE, NULL);
-          return TRUE;
-          break;
-#endif /* CONSOLE_ENABLE */
-
 #ifdef EXTRAKEY_ENABLE
-        case EXTRA_INTERFACE:
+        case EXTRAKEY_INTERFACE:
           if(usbp->setup[3] == 1) { /* MSB(wValue) [Report Type] == 1 [Input Report] */
             switch(usbp->setup[2]) { /* LSB(wValue) [Report ID] */
               case REPORT_ID_SYSTEM:
@@ -922,7 +454,7 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
         break;
 
       case HID_GET_PROTOCOL:
-        if((usbp->setup[4] == KBD_INTERFACE) && (usbp->setup[5] == 0)) {   /* wIndex */
+        if((usbp->setup[4] == KEYBOARD_INTERFACE) && (usbp->setup[5] == 0)) {   /* wIndex */
           usbSetupTransfer(usbp, &keyboard_protocol, 1, NULL);
           return TRUE;
         }
@@ -939,7 +471,7 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
       switch(usbp->setup[1]) {   /* bRequest */
       case HID_SET_REPORT:
         switch(usbp->setup[4]) {       /* LSB(wIndex) (check MSB==0 and wLength==1?) */
-        case KBD_INTERFACE:
+        case KEYBOARD_INTERFACE:
 #ifdef NKRO_ENABLE
         case NKRO_INTERFACE:
 #endif  /* NKRO_ENABLE */
@@ -952,7 +484,7 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
         break;
 
       case HID_SET_PROTOCOL:
-        if((usbp->setup[4] == KBD_INTERFACE) && (usbp->setup[5] == 0)) {   /* wIndex */
+        if((usbp->setup[4] == KEYBOARD_INTERFACE) && (usbp->setup[5] == 0)) {   /* wIndex */
           keyboard_protocol = ((usbp->setup[2]) != 0x00);   /* LSB(wValue) */
 #ifdef NKRO_ENABLE
           keymap_config.nkro = !!keyboard_protocol;
@@ -999,12 +531,24 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
     return TRUE;
   }
 
+  for (int i=0;i<NUM_USB_DRIVERS;i++) {
+    if (drivers.array[i].config.int_in) {
+      // NOTE: Assumes that we only have one serial driver
+      return qmkusbRequestsHook(usbp);
+    }
+  }
+
   return FALSE;
 }
 
 /* Start-of-frame callback */
 static void usb_sof_cb(USBDriver *usbp) {
   kbd_sof_cb(usbp);
+  osalSysLockFromISR();
+  for (int i=0; i<NUM_USB_DRIVERS;i++) {
+    qmkusbSOFHookI(&drivers.array[i].driver);
+  }
+  osalSysUnlockFromISR();
 }
 
 
@@ -1020,6 +564,15 @@ static const USBConfig usbcfg = {
  * Initialize the USB driver
  */
 void init_usb_driver(USBDriver *usbp) {
+  for (int i=0; i<NUM_USB_DRIVERS;i++) {
+    QMKUSBDriver* driver = &drivers.array[i].driver;
+    drivers.array[i].in_ep_config.in_state = &drivers.array[i].in_ep_state;
+    drivers.array[i].out_ep_config.out_state = &drivers.array[i].out_ep_state;
+    drivers.array[i].int_ep_config.in_state = &drivers.array[i].int_ep_state;
+    qmkusbObjectInit(driver, &drivers.array[i].config);
+    qmkusbStart(driver, &drivers.array[i].config);
+  }
+
   /*
    * Activates the USB driver and then the USB bus pull-up on D+.
    * Note, a delay is inserted in order to not have to disconnect the cable
@@ -1031,38 +584,12 @@ void init_usb_driver(USBDriver *usbp) {
   usbConnectBus(usbp);
 
   chVTObjectInit(&keyboard_idle_timer);
-#ifdef CONSOLE_ENABLE
-  obqObjectInit(&console_buf_queue, console_queue_buffer, CONSOLE_EPSIZE, CONSOLE_QUEUE_CAPACITY, console_queue_onotify, (void*)usbp);
-  chVTObjectInit(&console_flush_timer);
-#endif
-}
-
-/*
- * Send remote wakeup packet
- * Note: should not be called from ISR
- */
-void send_remote_wakeup(USBDriver *usbp) {
-  (void)usbp;
-#if defined(K20x) || defined(KL2x)
-#if KINETIS_USB_USE_USB0
-  USB0->CTL |= USBx_CTL_RESUME;
-  wait_ms(15);
-  USB0->CTL &= ~USBx_CTL_RESUME;
-#endif /* KINETIS_USB_USE_USB0 */
-#elif defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) /* End K20x || KL2x */
-  STM32_USB->CNTR |= CNTR_RESUME;
-  wait_ms(15);
-  STM32_USB->CNTR &= ~CNTR_RESUME;
-#else /* End STM32F0XX || STM32F1XX || STM32F3XX */
-#warning Sending remote wakeup packet not implemented for your platform.
-#endif
 }
 
 /* ---------------------------------------------------------
  *                  Keyboard functions
  * ---------------------------------------------------------
  */
-
 /* keyboard IN callback hander (a kbd report has made it IN) */
 void kbd_in_cb(USBDriver *usbp, usbep_t ep) {
   /* STUB */
@@ -1106,8 +633,8 @@ static void keyboard_idle_timer_cb(void *arg) {
   if(keyboard_idle) {
 #endif /* NKRO_ENABLE */
     /* TODO: are we sure we want the KBD_ENDPOINT? */
-    if(!usbGetTransmitStatusI(usbp, KBD_ENDPOINT)) {
-      usbStartTransmitI(usbp, KBD_ENDPOINT, (uint8_t *)&keyboard_report_sent, KBD_EPSIZE);
+    if(!usbGetTransmitStatusI(usbp, KEYBOARD_IN_EPNUM)) {
+      usbStartTransmitI(usbp, KEYBOARD_IN_EPNUM, (uint8_t *)&keyboard_report_sent, KEYBOARD_EPSIZE);
     }
     /* rearm the timer */
     chVTSetI(&keyboard_idle_timer, 4*MS2ST(keyboard_idle), keyboard_idle_timer_cb, (void *)usbp);
@@ -1141,14 +668,14 @@ void send_keyboard(report_keyboard_t *report) {
      * this is more efficient */
     /* busy wait, should be short and not very common */
     osalSysLock();
-    if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_ENDPOINT)) {
+    if(usbGetTransmitStatusI(&USB_DRIVER, NKRO_IN_EPNUM)) {
       /* Need to either suspend, or loop and call unlock/lock during
        * every iteration - otherwise the system will remain locked,
        * no interrupts served, so USB not going through as well.
        * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
-      osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_ENDPOINT]->in_state->thread);
+      osalThreadSuspendS(&(&USB_DRIVER)->epc[NKRO_IN_EPNUM]->in_state->thread);
     }
-    usbStartTransmitI(&USB_DRIVER, NKRO_ENDPOINT, (uint8_t *)report, sizeof(report_keyboard_t));
+    usbStartTransmitI(&USB_DRIVER, NKRO_IN_EPNUM, (uint8_t *)report, sizeof(report_keyboard_t));
     osalSysUnlock();
   } else
 #endif /* NKRO_ENABLE */
@@ -1156,14 +683,14 @@ void send_keyboard(report_keyboard_t *report) {
     /* need to wait until the previous packet has made it through */
     /* busy wait, should be short and not very common */
     osalSysLock();
-    if(usbGetTransmitStatusI(&USB_DRIVER, KBD_ENDPOINT)) {
+    if(usbGetTransmitStatusI(&USB_DRIVER, KEYBOARD_IN_EPNUM)) {
       /* Need to either suspend, or loop and call unlock/lock during
        * every iteration - otherwise the system will remain locked,
        * no interrupts served, so USB not going through as well.
        * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
-      osalThreadSuspendS(&(&USB_DRIVER)->epc[KBD_ENDPOINT]->in_state->thread);
+      osalThreadSuspendS(&(&USB_DRIVER)->epc[KEYBOARD_IN_EPNUM]->in_state->thread);
     }
-    usbStartTransmitI(&USB_DRIVER, KBD_ENDPOINT, (uint8_t *)report, KBD_EPSIZE);
+    usbStartTransmitI(&USB_DRIVER, KEYBOARD_IN_EPNUM, (uint8_t *)report, KEYBOARD_EPSIZE);
     osalSysUnlock();
   }
   keyboard_report_sent = *report;
@@ -1190,13 +717,15 @@ void send_mouse(report_mouse_t *report) {
   }
   osalSysUnlock();
 
-  /* TODO: LUFA manually waits for the endpoint to become ready
-   * for about 10ms for mouse, kbd, system; 1ms for nkro
-   * is this really needed?
-   */
-
   osalSysLock();
-  usbStartTransmitI(&USB_DRIVER, MOUSE_ENDPOINT, (uint8_t *)report, sizeof(report_mouse_t));
+  if(usbGetTransmitStatusI(&USB_DRIVER, MOUSE_IN_EPNUM)) {
+    /* Need to either suspend, or loop and call unlock/lock during
+     * every iteration - otherwise the system will remain locked,
+     * no interrupts served, so USB not going through as well.
+     * Note: for suspend, need USB_USE_WAIT == TRUE in halconf.h */
+    osalThreadSuspendS(&(&USB_DRIVER)->epc[MOUSE_IN_EPNUM]->in_state->thread);
+  }
+  usbStartTransmitI(&USB_DRIVER, MOUSE_IN_EPNUM, (uint8_t *)report, sizeof(report_mouse_t));
   osalSysUnlock();
 }
 
@@ -1232,7 +761,7 @@ static void send_extra_report(uint8_t report_id, uint16_t data) {
     .usage = data
   };
 
-  usbStartTransmitI(&USB_DRIVER, EXTRA_ENDPOINT, (uint8_t *)&report, sizeof(report_extra_t));
+  usbStartTransmitI(&USB_DRIVER, EXTRAKEY_IN_EPNUM, (uint8_t *)&report, sizeof(report_extra_t));
   osalSysUnlock();
 }
 
@@ -1260,125 +789,107 @@ void send_consumer(uint16_t data) {
 
 #ifdef CONSOLE_ENABLE
 
-/* console IN callback hander */
-void console_in_cb(USBDriver *usbp, usbep_t ep) {
-  (void)ep; /* should have ep == CONSOLE_ENDPOINT, so use that to save time/space */
-  uint8_t *buf;
-  size_t n;
+int8_t sendchar(uint8_t c) {
+  // The previous implmentation had timeouts, but I think it's better to just slow down
+  // and make sure that everything is transferred, rather than dropping stuff
+  return chnWrite(&drivers.console_driver.driver, &c, 1);
+}
 
-  osalSysLockFromISR();
+// Just a dummy function for now, this could be exposed as a weak function
+// Or connected to the actual QMK console
+static void console_receive( uint8_t *data, uint8_t length ) {
+  (void)data;
+  (void)length;
+}
 
-  /* rearm the timer */
-  chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
+void console_task(void) {
+  uint8_t buffer[CONSOLE_EPSIZE];
+  size_t size = 0;
+  do {
+    size_t size = chnReadTimeout(&drivers.console_driver.driver, buffer, sizeof(buffer), TIME_IMMEDIATE);
+    if (size > 0) {
+        console_receive(buffer, size);
+    }
+  } while(size > 0);
+}
 
-  /* Freeing the buffer just transmitted, if it was not a zero size packet.*/
-  if (usbp->epc[CONSOLE_ENDPOINT]->in_state->txsize > 0U) {
-    obqReleaseEmptyBufferI(&console_buf_queue);
-  }
+#else /* CONSOLE_ENABLE */
+int8_t sendchar(uint8_t c) {
+  (void)c;
+  return 0;
+}
+#endif /* CONSOLE_ENABLE */
 
-  /* Checking if there is a buffer ready for transmission.*/
-  buf = obqGetFullBufferI(&console_buf_queue, &n);
+void sendchar_pf(void *p, char c) {
+  (void)p;
+  sendchar((uint8_t)c);
+}
 
-  if (buf != NULL) {
-    /* The endpoint cannot be busy, we are in the context of the callback,
-       so it is safe to transmit without a check.*/
-    /* Should have n == CONSOLE_EPSIZE; check it? */
-    usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE);
-  } else {
-    /* Nothing to transmit.*/
-  }
+#ifdef RAW_ENABLE
+void raw_hid_send( uint8_t *data, uint8_t length ) {
+       // TODO: implement variable size packet
+       if ( length != RAW_EPSIZE )
+       {
+               return;
 
-  osalSysUnlockFromISR();
+       }
+  chnWrite(&drivers.raw_driver.driver, data, length);
 }
 
-/* Callback when data is inserted into the output queue
- * Called from a locked state */
-void console_queue_onotify(io_buffers_queue_t *bqp) {
-  size_t n;
-  USBDriver *usbp = bqGetLinkX(bqp);
-
-  if(usbGetDriverStateI(usbp) != USB_ACTIVE)
-    return;
+__attribute__ ((weak))
+void raw_hid_receive( uint8_t *data, uint8_t length ) {
+       // Users should #include "raw_hid.h" in their own code
+       // and implement this function there. Leave this as weak linkage
+       // so users can opt to not handle data coming in.
+}
 
-  /* Checking if there is already a transaction ongoing on the endpoint.*/
-  if (!usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT)) {
-    /* Trying to get a full buffer.*/
-    uint8_t *buf = obqGetFullBufferI(&console_buf_queue, &n);
-    if (buf != NULL) {
-      /* Buffer found, starting a new transaction.*/
-      /* Should have n == CONSOLE_EPSIZE; check this? */
-      usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE);
+void raw_hid_task(void) {
+  uint8_t buffer[RAW_EPSIZE];
+  size_t size = 0;
+  do {
+    size_t size = chnReadTimeout(&drivers.raw_driver.driver, buffer, sizeof(buffer), TIME_IMMEDIATE);
+    if (size > 0) {
+        raw_hid_receive(buffer, size);
     }
-  }
+  } while(size > 0);
 }
 
-/* Flush timer code
- * callback (called from ISR, unlocked state) */
-static void console_flush_cb(void *arg) {
-  USBDriver *usbp = (USBDriver *)arg;
-  osalSysLockFromISR();
+#endif
 
-  /* check that the states of things are as they're supposed to */
-  if(usbGetDriverStateI(usbp) != USB_ACTIVE) {
-    /* rearm the timer */
-    chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
-    osalSysUnlockFromISR();
-    return;
-  }
+#ifdef MIDI_ENABLE
 
-  /* If there is already a transaction ongoing then another one cannot be
-     started.*/
-  if (usbGetTransmitStatusI(usbp, CONSOLE_ENDPOINT)) {
-    /* rearm the timer */
-    chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
-    osalSysUnlockFromISR();
-    return;
-  }
+void send_midi_packet(MIDI_EventPacket_t* event) {
+  chnWrite(&drivers.midi_driver.driver, (uint8_t*)event, sizeof(MIDI_EventPacket_t));
+}
 
-  /* Checking if there only a buffer partially filled, if so then it is
-     enforced in the queue and transmitted.*/
-  if(obqTryFlushI(&console_buf_queue)) {
-    size_t n,i;
-    uint8_t *buf = obqGetFullBufferI(&console_buf_queue, &n);
+bool recv_midi_packet(MIDI_EventPacket_t* const event) {
+  size_t size = chnReadTimeout(&drivers.midi_driver.driver, (uint8_t*)event, sizeof(MIDI_EventPacket_t), TIME_IMMEDIATE);
+  return size == sizeof(MIDI_EventPacket_t);
+}
 
-    osalDbgAssert(buf != NULL, "queue is empty");
+#endif
 
-    /* zero the rest of the buffer (buf should point to allocated space) */
-    for(i=n; i<CONSOLE_EPSIZE; i++)
-      buf[i]=0;
-    usbStartTransmitI(usbp, CONSOLE_ENDPOINT, buf, CONSOLE_EPSIZE);
-  }
+#ifdef VIRTSER_ENABLE
 
-  /* rearm the timer */
-  chVTSetI(&console_flush_timer, MS2ST(CONSOLE_FLUSH_MS), console_flush_cb, (void *)usbp);
-  osalSysUnlockFromISR();
+void virtser_send(const uint8_t byte) {
+  chnWrite(&drivers.serial_driver.driver, &byte, 1);
 }
 
-
-int8_t sendchar(uint8_t c) {
-  osalSysLock();
-  if(usbGetDriverStateI(&USB_DRIVER) != USB_ACTIVE) {
-    osalSysUnlock();
-    return 0;
-  }
-  osalSysUnlock();
-  /* Timeout after 100us if the queue is full.
-   * Increase this timeout if too much stuff is getting
-   * dropped (i.e. the buffer is getting full too fast
-   * for USB/HIDRAW to dequeue). Another possibility
-   * for fixing this kind of thing is to increase
-   * CONSOLE_QUEUE_CAPACITY. */
-  return(obqPutTimeout(&console_buf_queue, c, US2ST(100)));
+__attribute__ ((weak))
+void virtser_recv(uint8_t c)
+{
+  // Ignore by default
 }
 
-#else /* CONSOLE_ENABLE */
-int8_t sendchar(uint8_t c) {
-  (void)c;
-  return 0;
+void virtser_task(void) {
+  uint8_t numBytesReceived = 0;
+  uint8_t buffer[16];
+  do {
+    numBytesReceived = chnReadTimeout(&drivers.serial_driver.driver, buffer, sizeof(buffer), TIME_IMMEDIATE);
+    for (int i=0;i<numBytesReceived;i++) {
+      virtser_recv(buffer[i]);
+    }
+  } while (numBytesReceived > 0);
 }
-#endif /* CONSOLE_ENABLE */
 
-void sendchar_pf(void *p, char c) {
-  (void)p;
-  sendchar((uint8_t)c);
-}
+#endif