From ab91e07753720f8114d6c427139a1436e6efa3ce Mon Sep 17 00:00:00 2001
From: patrickmt <40182064+patrickmt@users.noreply.github.com>
Date: Tue, 9 Oct 2018 15:14:13 -0400
Subject: Massdrop keyboards console device support for hid_listen
Added hid_listen USB device for arm_atsam USB protocol.
Debug printing is now done through the console device (CONSOLE_ENABLE = yes) rather than the virtser device, for viewing in hid_listen.
Function dpf(...) renamed to CDC_printf(...) and should now be called directly if intending to print to the virtual serial device.
---
tmk_core/common.mk | 1 +
tmk_core/common/arm_atsam/printf.c | 66 ++++++++++
tmk_core/common/arm_atsam/printf.h | 7 +-
tmk_core/protocol/arm_atsam/main_arm_atsam.c | 12 +-
tmk_core/protocol/arm_atsam/usb/conf_usb.h | 5 +
tmk_core/protocol/arm_atsam/usb/main_usb.c | 14 ++
tmk_core/protocol/arm_atsam/usb/udi_cdc.c | 4 +-
tmk_core/protocol/arm_atsam/usb/udi_cdc.h | 1 +
tmk_core/protocol/arm_atsam/usb/udi_device_conf.h | 88 +++++++++++--
tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c | 146 +++++++++++++++++++++
tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h | 11 ++
tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c | 6 +
tmk_core/protocol/arm_atsam/usb/usb_main.h | 6 +
13 files changed, 347 insertions(+), 20 deletions(-)
create mode 100644 tmk_core/common/arm_atsam/printf.c
diff --git a/tmk_core/common.mk b/tmk_core/common.mk
index 319d196aec..4a0f7dcf9a 100644
--- a/tmk_core/common.mk
+++ b/tmk_core/common.mk
@@ -43,6 +43,7 @@ endif
endif
ifeq ($(PLATFORM),ARM_ATSAM)
+ TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
endif
diff --git a/tmk_core/common/arm_atsam/printf.c b/tmk_core/common/arm_atsam/printf.c
new file mode 100644
index 0000000000..d49d234de2
--- /dev/null
+++ b/tmk_core/common/arm_atsam/printf.c
@@ -0,0 +1,66 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#ifdef CONSOLE_PRINT
+
+#include "samd51j18a.h"
+#include "arm_atsam_protocol.h"
+#include "printf.h"
+#include
+#include
+
+void console_printf(char *fmt, ...) {
+ while (udi_hid_con_b_report_trans_ongoing) {} //Wait for any previous transfers to complete
+
+ static char console_printbuf[CONSOLE_PRINTBUF_SIZE]; //Print and send buffer
+ va_list va;
+ int result;
+
+ va_start(va, fmt);
+ result = vsnprintf(console_printbuf, CONSOLE_PRINTBUF_SIZE, fmt, va);
+ va_end(va);
+
+ uint32_t irqflags;
+ char *pconbuf = console_printbuf; //Pointer to start send from
+ int send_out = CONSOLE_EPSIZE; //Bytes to send per transfer
+
+ while (result > 0) { //While not error and bytes remain
+ while (udi_hid_con_b_report_trans_ongoing) {} //Wait for any previous transfers to complete
+
+ irqflags = __get_PRIMASK();
+ __disable_irq();
+ __DMB();
+
+ if (result < CONSOLE_EPSIZE) { //If remaining bytes are less than console epsize
+ memset(udi_hid_con_report, 0, CONSOLE_EPSIZE); //Clear the buffer
+ send_out = result; //Send remaining size
+ }
+
+ memcpy(udi_hid_con_report, pconbuf, send_out); //Copy data into the send buffer
+
+ udi_hid_con_b_report_valid = 1; //Set report valid
+ udi_hid_con_send_report(); //Send report
+
+ __DMB();
+ __set_PRIMASK(irqflags);
+
+ result -= send_out; //Decrement result by bytes sent
+ pconbuf += send_out; //Increment buffer point by bytes sent
+ }
+}
+
+#endif //CONSOLE_PRINT
diff --git a/tmk_core/common/arm_atsam/printf.h b/tmk_core/common/arm_atsam/printf.h
index 3206b40bdb..1f1c2280b5 100644
--- a/tmk_core/common/arm_atsam/printf.h
+++ b/tmk_core/common/arm_atsam/printf.h
@@ -1,8 +1,11 @@
#ifndef _PRINTF_H_
#define _PRINTF_H_
-int dpf(const char *_Format, ...);
-#define __xprintf dpf
+#define CONSOLE_PRINTBUF_SIZE 512
+
+void console_printf(char *fmt, ...);
+
+#define __xprintf console_printf
#endif //_PRINTF_H_
diff --git a/tmk_core/protocol/arm_atsam/main_arm_atsam.c b/tmk_core/protocol/arm_atsam/main_arm_atsam.c
index 676dac4ea3..54d056a14e 100644
--- a/tmk_core/protocol/arm_atsam/main_arm_atsam.c
+++ b/tmk_core/protocol/arm_atsam/main_arm_atsam.c
@@ -276,9 +276,9 @@ int main(void)
host_set_driver(&arm_atsam_driver);
-#ifdef VIRTSER_ENABLE
+#ifdef CONSOLE_ENABLE
uint64_t next_print = 0;
-#endif //VIRTSER_ENABLE
+#endif //CONSOLE_ENABLE
v_5v_avg = adc_get(ADC_5V);
@@ -290,15 +290,17 @@ int main(void)
main_subtasks(); //Note these tasks will also be run while waiting for USB keyboard polling intervals
-#ifdef VIRTSER_ENABLE
+#ifdef CONSOLE_ENABLE
if (CLK_get_ms() > next_print)
{
next_print = CLK_get_ms() + 250;
- dprintf("5v=%u 5vu=%u dlow=%u dhi=%u gca=%u gcd=%u\r\n",v_5v,v_5v_avg,v_5v_avg-V5_LOW,v_5v_avg-V5_HIGH,gcr_actual,gcr_desired);
+ //Add any debug information here that you want to see very often
+ //dprintf("5v=%u 5vu=%u dlow=%u dhi=%u gca=%u gcd=%u\r\n", v_5v, v_5v_avg, v_5v_avg - V5_LOW, v_5v_avg - V5_HIGH, gcr_actual, gcr_desired);
}
-#endif //VIRTSER_ENABLE
+#endif //CONSOLE_ENABLE
}
+
return 1;
}
diff --git a/tmk_core/protocol/arm_atsam/usb/conf_usb.h b/tmk_core/protocol/arm_atsam/usb/conf_usb.h
index 8f0f472687..c91caffe02 100644
--- a/tmk_core/protocol/arm_atsam/usb/conf_usb.h
+++ b/tmk_core/protocol/arm_atsam/usb/conf_usb.h
@@ -134,6 +134,11 @@
#define UDI_HID_EXK_DISABLE_EXT() main_exk_disable()
#endif
+#ifdef CON
+#define UDI_HID_CON_ENABLE_EXT() main_con_enable()
+#define UDI_HID_CON_DISABLE_EXT() main_con_disable()
+#endif
+
#ifdef MOU
#define UDI_HID_MOU_ENABLE_EXT() main_mou_enable()
#define UDI_HID_MOU_DISABLE_EXT() main_mou_disable()
diff --git a/tmk_core/protocol/arm_atsam/usb/main_usb.c b/tmk_core/protocol/arm_atsam/usb/main_usb.c
index e943cbcdcd..0f676ab639 100644
--- a/tmk_core/protocol/arm_atsam/usb/main_usb.c
+++ b/tmk_core/protocol/arm_atsam/usb/main_usb.c
@@ -88,6 +88,20 @@ void main_exk_disable(void)
}
#endif
+#ifdef CON
+volatile bool main_b_con_enable = false;
+bool main_con_enable(void)
+{
+ main_b_con_enable = true;
+ return true;
+}
+
+void main_con_disable(void)
+{
+ main_b_con_enable = false;
+}
+#endif
+
#ifdef MOU
volatile bool main_b_mou_enable = false;
bool main_mou_enable(void)
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_cdc.c b/tmk_core/protocol/arm_atsam/usb/udi_cdc.c
index 15f0f760cc..5f3c289e81 100644
--- a/tmk_core/protocol/arm_atsam/usb/udi_cdc.c
+++ b/tmk_core/protocol/arm_atsam/usb/udi_cdc.c
@@ -1260,7 +1260,7 @@ uint32_t CDC_print(char *printbuf)
char printbuf[CDC_PRINTBUF_SIZE];
-int dpf(const char *_Format, ...)
+int CDC_printf(const char *_Format, ...)
{
va_list va; //Variable argument list variable
int result;
@@ -1356,7 +1356,7 @@ uint32_t CDC_print(char *printbuf)
return 0;
}
-int dpf(const char *_Format, ...)
+int CDC_printf(const char *_Format, ...)
{
return 0;
}
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_cdc.h b/tmk_core/protocol/arm_atsam/usb/udi_cdc.h
index e134cf2360..86077ce53b 100644
--- a/tmk_core/protocol/arm_atsam/usb/udi_cdc.h
+++ b/tmk_core/protocol/arm_atsam/usb/udi_cdc.h
@@ -365,6 +365,7 @@ extern inbuf_t inbuf;
#endif //CDC
uint32_t CDC_print(char *printbuf);
+int CDC_printf(const char *_Format, ...);
uint32_t CDC_input(void);
void CDC_init(void);
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h b/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h
index c787262340..1e82b9eccb 100644
--- a/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h
+++ b/tmk_core/protocol/arm_atsam/usb/udi_device_conf.h
@@ -44,10 +44,10 @@ along with this program. If not, see .
#define RAW
#endif
-//#define CONSOLE_ENABLE //deferred implementation
-//#ifdef CONSOLE_ENABLE
-//#define CON
-//#endif
+//#define CONSOLE_ENABLE //rules.mk
+#ifdef CONSOLE_ENABLE
+#define CON
+#endif
//#define NKRO_ENABLE //rules.mk
#ifdef NKRO_ENABLE
@@ -110,8 +110,9 @@ along with this program. If not, see .
#endif
#ifdef CON
-#define CONSOLE_INTERFACE NEXT_INTERFACE_4
-#define NEXT_INTERFACE_5 (CONSOLE_INTERFACE + 1)
+#define CON_INTERFACE NEXT_INTERFACE_4
+#define NEXT_INTERFACE_5 (CON_INTERFACE + 1)
+#define UDI_HID_CON_IFACE_NUMBER CON_INTERFACE
#else
#define NEXT_INTERFACE_5 NEXT_INTERFACE_4
#endif
@@ -211,11 +212,16 @@ along with this program. If not, see .
#endif
#ifdef CON
-#define CONSOLE_IN_EPNUM NEXT_IN_EPNUM_4
-#define NEXT_IN_EPNUM_5 (CONSOLE_IN_EPNUM + 1)
-#define CONSOLE_OUT_EPNUM NEXT_OUT_EPNUM_1
-#define NEXT_OUT_EPNUM_2 (CONSOLE_OUT_EPNUM + 1)
-#define CONSOLE_POLLING_INTERVAL 1
+#define CON_IN_EPNUM NEXT_IN_EPNUM_4
+#define UDI_HID_CON_EP_IN CON_IN_EPNUM
+#define NEXT_IN_EPNUM_5 (CON_IN_EPNUM + 1)
+#define CON_OUT_EPNUM NEXT_OUT_EPNUM_1
+#define UDI_HID_CON_EP_OUT CON_OUT_EPNUM
+#define NEXT_OUT_EPNUM_2 (CON_OUT_EPNUM + 1)
+#define CON_POLLING_INTERVAL 1
+#ifndef UDI_HID_CON_STRING_ID
+#define UDI_HID_CON_STRING_ID 0
+#endif
#else
#define NEXT_IN_EPNUM_5 NEXT_IN_EPNUM_4
#define NEXT_OUT_EPNUM_2 NEXT_OUT_EPNUM_1
@@ -558,6 +564,66 @@ COMPILER_PACK_RESET()
#endif //RAW
+// **********************************************************************
+// CON Descriptor structure and content
+// **********************************************************************
+#ifdef CON
+
+COMPILER_PACK_SET(1)
+
+typedef struct {
+ usb_iface_desc_t iface;
+ usb_hid_descriptor_t hid;
+ usb_ep_desc_t ep_out;
+ usb_ep_desc_t ep_in;
+} udi_hid_con_desc_t;
+
+typedef struct {
+ uint8_t array[34];
+} udi_hid_con_report_desc_t;
+
+#define UDI_HID_CON_DESC {\
+ .iface.bLength = sizeof(usb_iface_desc_t),\
+ .iface.bDescriptorType = USB_DT_INTERFACE,\
+ .iface.bInterfaceNumber = UDI_HID_CON_IFACE_NUMBER,\
+ .iface.bAlternateSetting = 0,\
+ .iface.bNumEndpoints = 2,\
+ .iface.bInterfaceClass = HID_CLASS,\
+ .iface.bInterfaceSubClass = HID_SUB_CLASS_NOBOOT,\
+ .iface.bInterfaceProtocol = HID_SUB_CLASS_NOBOOT,\
+ .iface.iInterface = UDI_HID_CON_STRING_ID,\
+ .hid.bLength = sizeof(usb_hid_descriptor_t),\
+ .hid.bDescriptorType = USB_DT_HID,\
+ .hid.bcdHID = LE16(USB_HID_BDC_V1_11),\
+ .hid.bCountryCode = USB_HID_NO_COUNTRY_CODE,\
+ .hid.bNumDescriptors = USB_HID_NUM_DESC,\
+ .hid.bRDescriptorType = USB_DT_HID_REPORT,\
+ .hid.wDescriptorLength = LE16(sizeof(udi_hid_con_report_desc_t)),\
+ .ep_out.bLength = sizeof(usb_ep_desc_t),\
+ .ep_out.bDescriptorType = USB_DT_ENDPOINT,\
+ .ep_out.bEndpointAddress = UDI_HID_CON_EP_OUT | USB_EP_DIR_OUT,\
+ .ep_out.bmAttributes = USB_EP_TYPE_INTERRUPT,\
+ .ep_out.wMaxPacketSize = LE16(CONSOLE_EPSIZE),\
+ .ep_out.bInterval = CON_POLLING_INTERVAL,\
+ .ep_in.bLength = sizeof(usb_ep_desc_t),\
+ .ep_in.bDescriptorType = USB_DT_ENDPOINT,\
+ .ep_in.bEndpointAddress = UDI_HID_CON_EP_IN | USB_EP_DIR_IN,\
+ .ep_in.bmAttributes = USB_EP_TYPE_INTERRUPT,\
+ .ep_in.wMaxPacketSize = LE16(CONSOLE_EPSIZE),\
+ .ep_in.bInterval = CON_POLLING_INTERVAL,\
+}
+
+#define UDI_HID_CON_REPORT_SIZE CONSOLE_EPSIZE
+
+extern uint8_t udi_hid_con_report_set[UDI_HID_CON_REPORT_SIZE];
+
+//report buffer
+extern uint8_t udi_hid_con_report[UDI_HID_CON_REPORT_SIZE];
+
+COMPILER_PACK_RESET()
+
+#endif //CON
+
// **********************************************************************
// CDC Descriptor structure and content
// **********************************************************************
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c
index 1a6f7905e6..18f9784ae6 100644
--- a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c
+++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c
@@ -843,3 +843,149 @@ static void udi_hid_raw_setreport_valid(void)
}
#endif //RAW
+
+//********************************************************************************************
+// CON
+//********************************************************************************************
+#ifdef CON
+
+bool udi_hid_con_enable(void);
+void udi_hid_con_disable(void);
+bool udi_hid_con_setup(void);
+uint8_t udi_hid_con_getsetting(void);
+
+UDC_DESC_STORAGE udi_api_t udi_api_hid_con = {
+ .enable = (bool(*)(void))udi_hid_con_enable,
+ .disable = (void (*)(void))udi_hid_con_disable,
+ .setup = (bool(*)(void))udi_hid_con_setup,
+ .getsetting = (uint8_t(*)(void))udi_hid_con_getsetting,
+ .sof_notify = NULL,
+};
+
+COMPILER_WORD_ALIGNED
+static uint8_t udi_hid_con_rate;
+
+COMPILER_WORD_ALIGNED
+static uint8_t udi_hid_con_protocol;
+
+COMPILER_WORD_ALIGNED
+uint8_t udi_hid_con_report_set[UDI_HID_CON_REPORT_SIZE];
+
+bool udi_hid_con_b_report_valid;
+
+COMPILER_WORD_ALIGNED
+uint8_t udi_hid_con_report[UDI_HID_CON_REPORT_SIZE];
+
+volatile bool udi_hid_con_b_report_trans_ongoing;
+
+COMPILER_WORD_ALIGNED
+static uint8_t udi_hid_con_report_trans[UDI_HID_CON_REPORT_SIZE];
+
+COMPILER_WORD_ALIGNED
+UDC_DESC_STORAGE udi_hid_con_report_desc_t udi_hid_con_report_desc = {
+ {
+ 0x06, 0x31, 0xFF, // Vendor Page (PJRC Teensy compatible)
+ 0x09, 0x74, // Vendor Usage (PJRC Teensy compatible)
+ 0xA1, 0x01, // Collection (Application)
+ 0x09, 0x75, // Usage (Vendor)
+ 0x15, 0x00, // Logical Minimum (0x00)
+ 0x26, 0xFF, 0x00, // Logical Maximum (0x00FF)
+ 0x95, CONSOLE_EPSIZE, // Report Count
+ 0x75, 0x08, // Report Size (8)
+ 0x81, 0x02, // Input (Data)
+ 0x09, 0x76, // Usage (Vendor)
+ 0x15, 0x00, // Logical Minimum (0x00)
+ 0x26, 0xFF, 0x00, // Logical Maximum (0x00FF)
+ 0x95, CONSOLE_EPSIZE, // Report Count
+ 0x75, 0x08, // Report Size (8)
+ 0x91, 0x02, // Output (Data)
+ 0xC0, // End Collection
+ }
+};
+
+static bool udi_hid_con_setreport(void);
+static void udi_hid_con_setreport_valid(void);
+
+static void udi_hid_con_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep);
+
+bool udi_hid_con_enable(void)
+{
+ // Initialize internal values
+ udi_hid_con_rate = 0;
+ udi_hid_con_protocol = 0;
+ udi_hid_con_b_report_trans_ongoing = false;
+ memset(udi_hid_con_report, 0, UDI_HID_CON_REPORT_SIZE);
+ udi_hid_con_b_report_valid = false;
+ return UDI_HID_CON_ENABLE_EXT();
+}
+
+void udi_hid_con_disable(void)
+{
+ UDI_HID_CON_DISABLE_EXT();
+}
+
+bool udi_hid_con_setup(void)
+{
+ return udi_hid_setup(&udi_hid_con_rate,
+ &udi_hid_con_protocol,
+ (uint8_t *) &udi_hid_con_report_desc,
+ udi_hid_con_setreport);
+}
+
+uint8_t udi_hid_con_getsetting(void)
+{
+ return 0;
+}
+
+static bool udi_hid_con_setreport(void)
+{
+ if ((USB_HID_REPORT_TYPE_OUTPUT == (udd_g_ctrlreq.req.wValue >> 8))
+ && (0 == (0xFF & udd_g_ctrlreq.req.wValue))
+ && (UDI_HID_CON_REPORT_SIZE == udd_g_ctrlreq.req.wLength)) {
+ udd_g_ctrlreq.payload = udi_hid_con_report_set;
+ udd_g_ctrlreq.callback = udi_hid_con_setreport_valid;
+ udd_g_ctrlreq.payload_size = UDI_HID_CON_REPORT_SIZE;
+ return true;
+ }
+ return false;
+}
+
+bool udi_hid_con_send_report(void)
+{
+ if (!main_b_con_enable) {
+ return false;
+ }
+
+ if (udi_hid_con_b_report_trans_ongoing) {
+ return false;
+ }
+
+ memcpy(udi_hid_con_report_trans, udi_hid_con_report,UDI_HID_CON_REPORT_SIZE);
+ udi_hid_con_b_report_valid = false;
+ udi_hid_con_b_report_trans_ongoing =
+ udd_ep_run(UDI_HID_CON_EP_IN | USB_EP_DIR_IN,
+ false,
+ udi_hid_con_report_trans,
+ UDI_HID_CON_REPORT_SIZE,
+ udi_hid_con_report_sent);
+
+ return udi_hid_con_b_report_trans_ongoing;
+}
+
+static void udi_hid_con_report_sent(udd_ep_status_t status, iram_size_t nb_sent, udd_ep_id_t ep)
+{
+ UNUSED(status);
+ UNUSED(nb_sent);
+ UNUSED(ep);
+ udi_hid_con_b_report_trans_ongoing = false;
+ if (udi_hid_con_b_report_valid) {
+ udi_hid_con_send_report();
+ }
+}
+
+static void udi_hid_con_setreport_valid(void)
+{
+
+}
+
+#endif //CON
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h
index babfdb7a78..e442919a9b 100644
--- a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h
+++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h
@@ -85,6 +85,17 @@ extern uint8_t udi_hid_exk_report_set;
bool udi_hid_exk_send_report(void);
#endif //EXK
+//********************************************************************************************
+// CON Console
+//********************************************************************************************
+#ifdef CON
+extern UDC_DESC_STORAGE udi_api_t udi_api_hid_con;
+extern bool udi_hid_con_b_report_valid;
+extern uint8_t udi_hid_con_report_set[UDI_HID_CON_REPORT_SIZE];
+extern volatile bool udi_hid_con_b_report_trans_ongoing;
+bool udi_hid_con_send_report(void);
+#endif //CON
+
//********************************************************************************************
// MOU Mouse
//********************************************************************************************
diff --git a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c
index 16bd4e514c..2d6e35e254 100644
--- a/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c
+++ b/tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c
@@ -134,6 +134,9 @@ UDC_DESC_STORAGE udc_desc_t udc_desc = {
#ifdef EXK
.hid_exk = UDI_HID_EXK_DESC,
#endif
+#ifdef CON
+ .hid_con = UDI_HID_CON_DESC,
+#endif
#ifdef NKRO
.hid_nkro = UDI_HID_NKRO_DESC,
#endif
@@ -155,6 +158,9 @@ UDC_DESC_STORAGE udi_api_t *udi_apis[USB_DEVICE_NB_INTERFACE] = {
#ifdef EXK
&udi_api_hid_exk,
#endif
+ #ifdef CON
+ &udi_api_hid_con,
+ #endif
#ifdef NKRO
&udi_api_hid_nkro,
#endif
diff --git a/tmk_core/protocol/arm_atsam/usb/usb_main.h b/tmk_core/protocol/arm_atsam/usb/usb_main.h
index b7adaa1a72..76ced474dc 100644
--- a/tmk_core/protocol/arm_atsam/usb/usb_main.h
+++ b/tmk_core/protocol/arm_atsam/usb/usb_main.h
@@ -82,6 +82,12 @@ bool main_exk_enable(void);
void main_exk_disable(void);
#endif //EXK
+#ifdef CON
+extern volatile bool main_b_con_enable;
+bool main_con_enable(void);
+void main_con_disable(void);
+#endif //CON
+
#ifdef MOU
extern volatile bool main_b_mou_enable;
bool main_mou_enable(void);
--
cgit v1.2.3