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