diff --git a/tmk_core/protocol/vusb/main.c b/tmk_core/protocol/vusb/main.c
index 219989876cc0..1ab765343b7b 100644
--- a/tmk_core/protocol/vusb/main.c
+++ b/tmk_core/protocol/vusb/main.c
@@ -108,6 +108,13 @@ int main(void) {
keyboard_task();
}
vusb_transfer_keyboard();
+#ifdef RAW_ENABLE
+ usbPoll();
+
+ if (usbConfiguration && usbInterruptIsReady3()) {
+ raw_hid_task();
+ }
+#endif
}
}
}
diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c
index 19df35805d7e..47dc1245d068 100644
--- a/tmk_core/protocol/vusb/vusb.c
+++ b/tmk_core/protocol/vusb/vusb.c
@@ -28,6 +28,14 @@ along with this program. If not, see .
#include "vusb.h"
#include
+#if defined(RAW_ENABLE)
+# include "raw_hid.h"
+#endif
+
+#if (defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)) && defined(RAW_ENABLE)
+# error "Enabling Mousekeys/Extrakeys and Raw HID at the same time is not currently supported on V-USB."
+#endif
+
static uint8_t vusb_keyboard_leds = 0;
static uint8_t vusb_idle_rate = 0;
@@ -71,6 +79,52 @@ void vusb_transfer_keyboard(void) {
}
}
+/*------------------------------------------------------------------*
+ * RAW HID
+ *------------------------------------------------------------------*/
+#ifdef RAW_ENABLE
+# define RAW_BUFFER_SIZE 32
+# define RAW_EPSIZE 8
+
+static uint8_t raw_output_buffer[RAW_BUFFER_SIZE];
+static uint8_t raw_output_received_bytes = 0;
+
+void raw_hid_send(uint8_t *data, uint8_t length) {
+ if (length != RAW_BUFFER_SIZE) {
+ return;
+ }
+
+ uint8_t *temp = data;
+ for (uint8_t i = 0; i < 4; i++) {
+ while (!usbInterruptIsReady3()) {
+ usbPoll();
+ }
+ usbSetInterrupt3(temp, 8);
+ temp += 8;
+ }
+ while (!usbInterruptIsReady3()) {
+ usbPoll();
+ }
+ usbSetInterrupt3(0, 0);
+ usbPoll();
+ _delay_ms(1);
+}
+
+__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.
+}
+
+void raw_hid_task(void) {
+ if (raw_output_received_bytes == RAW_BUFFER_SIZE) {
+ raw_hid_receive(raw_output_buffer, RAW_BUFFER_SIZE);
+ raw_output_received_bytes = 0;
+ }
+}
+
+#endif
+
/*------------------------------------------------------------------*
* Host driver
*------------------------------------------------------------------*/
@@ -206,6 +260,27 @@ uchar usbFunctionWrite(uchar *data, uchar len) {
return 1;
}
+void usbFunctionWriteOut(uchar *data, uchar len) {
+#ifdef RAW_ENABLE
+ // Data from host must be divided every 8bytes
+ if (len != 8) {
+ debug("RAW: invalid length");
+ raw_output_received_bytes = 0;
+ return;
+ }
+
+ if (raw_output_received_bytes + len > RAW_BUFFER_SIZE) {
+ debug("RAW: buffer full");
+ raw_output_received_bytes = 0;
+ } else {
+ for (uint8_t i = 0; i < 8; i++) {
+ raw_output_buffer[raw_output_received_bytes + i] = data[i];
+ }
+ raw_output_received_bytes += len;
+ }
+#endif
+}
+
/*------------------------------------------------------------------*
* Descriptors *
*------------------------------------------------------------------*/
@@ -335,6 +410,29 @@ const PROGMEM uchar mouse_extra_hid_report[] = {
};
#endif
+#if defined(RAW_ENABLE)
+const PROGMEM uchar raw_hid_report[] = {
+ 0x06, 0x60, 0xFF, // Usage Page (Vendor Defined)
+ 0x09, 0x61, // Usage (Vendor Defined)
+ 0xA1, 0x01, // Collection (Application)
+ // Data to host
+ 0x09, 0x62, // Usage (Vendor Defined)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x95, RAW_BUFFER_SIZE, // Report Count
+ 0x75, 0x08, // Report Size (8)
+ 0x81, 0x02, // Input (Data, Variable, Absolute)
+ // Data from host
+ 0x09, 0x63, // Usage (Vendor Defined)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ 0x95, RAW_BUFFER_SIZE, // Report Count
+ 0x75, 0x08, // Report Size (8)
+ 0x91, 0x02, // Output (Data, Variable, Absolute)
+ 0xC0, // End Collection
+};
+#endif
+
#ifndef SERIAL_NUMBER
# define SERIAL_NUMBER 0
#endif
@@ -416,7 +514,7 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
.bDescriptorType = USBDESCR_CONFIG
},
.wTotalLength = sizeof(usbConfigurationDescriptor_t),
-# if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
+# if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE) || defined(RAW_ENABLE)
.bNumInterfaces = 2,
# else
.bNumInterfaces = 1,
@@ -511,6 +609,53 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
.bInterval = USB_POLLING_INTERVAL_MS
}
# endif
+# elif defined(RAW_ENABLE)
+ .rawInterface = {
+ .header = {
+ .bLength = sizeof(usbInterfaceDescriptor_t),
+ .bDescriptorType = USBDESCR_INTERFACE
+ },
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = 0x03,
+ .bInterfaceSubClass = 0x00,
+ .bInterfaceProtocol = 0x00,
+ .iInterface = 0x00
+ },
+ .rawHID = {
+ .header = {
+ .bLength = sizeof(usbHIDDescriptor_t),
+ .bDescriptorType = USBDESCR_HID
+ },
+ .bcdHID = 0x0101,
+ .bCountryCode = 0x00,
+ .bNumDescriptors = 2,
+ .bDescriptorType = USBDESCR_HID_REPORT,
+ .wDescriptorLength = sizeof(raw_hid_report)
+ },
+# if USB_CFG_HAVE_INTRIN_ENDPOINT3
+ .rawINEndpoint = {
+ .header = {
+ .bLength = sizeof(usbEndpointDescriptor_t),
+ .bDescriptorType = USBDESCR_ENDPOINT
+ },
+ .bEndpointAddress = (USBRQ_DIR_DEVICE_TO_HOST | USB_CFG_EP3_NUMBER),
+ .bmAttributes = 0x03,
+ .wMaxPacketSize = RAW_EPSIZE,
+ .bInterval = USB_POLLING_INTERVAL_MS
+ },
+ .rawOUTEndpoint = {
+ .header = {
+ .bLength = sizeof(usbEndpointDescriptor_t),
+ .bDescriptorType = USBDESCR_ENDPOINT
+ },
+ .bEndpointAddress = (USBRQ_DIR_HOST_TO_DEVICE | USB_CFG_EP3_NUMBER),
+ .bmAttributes = 0x03,
+ .wMaxPacketSize = RAW_EPSIZE,
+ .bInterval = USB_POLLING_INTERVAL_MS
+ }
+# endif
# endif
};
#endif
@@ -572,6 +717,11 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.mouseExtraHID;
len = sizeof(usbHIDDescriptor_t);
break;
+#elif defined(RAW_ENABLE)
+ case 1:
+ usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.rawHID;
+ len = sizeof(usbHIDDescriptor_t);
+ break;
#endif
}
break;
@@ -587,6 +737,11 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
usbMsgPtr = (unsigned char *)mouse_extra_hid_report;
len = sizeof(mouse_extra_hid_report);
break;
+#elif defined(RAW_ENABLE)
+ case 1:
+ usbMsgPtr = (unsigned char *)raw_hid_report;
+ len = sizeof(raw_hid_report);
+ break;
#endif
}
break;
diff --git a/tmk_core/protocol/vusb/vusb.h b/tmk_core/protocol/vusb/vusb.h
index debac67d24d3..6d491266db28 100644
--- a/tmk_core/protocol/vusb/vusb.h
+++ b/tmk_core/protocol/vusb/vusb.h
@@ -97,6 +97,13 @@ typedef struct usbConfigurationDescriptor {
# ifdef USB_CFG_HAVE_INTRIN_ENDPOINT3
usbEndpointDescriptor_t mouseExtraINEndpoint;
# endif
+#elif defined(RAW_ENABLE)
+ usbInterfaceDescriptor_t rawInterface;
+ usbHIDDescriptor_t rawHID;
+# ifdef USB_CFG_HAVE_INTRIN_ENDPOINT3
+ usbEndpointDescriptor_t rawINEndpoint;
+ usbEndpointDescriptor_t rawOUTEndpoint;
+# endif
#endif
} __attribute__((packed)) usbConfigurationDescriptor_t;
@@ -104,3 +111,7 @@ typedef struct usbConfigurationDescriptor {
host_driver_t *vusb_driver(void);
void vusb_transfer_keyboard(void);
+
+#if defined(RAW_ENABLE)
+void raw_hid_task(void);
+#endif