~ruther/qmk_firmware

5f82b0782f90645eee5926691dcc0ec617d0dff4 — Joel Challis 5 years ago 2e6959e
Initial vusb console support (#8559)

M tmk_core/common.mk => tmk_core/common.mk +1 -0
@@ 10,6 10,7 @@ TMK_COMMON_SRC +=	$(COMMON_DIR)/host.c \
	$(COMMON_DIR)/action_util.c \
	$(COMMON_DIR)/print.c \
	$(COMMON_DIR)/debug.c \
	$(COMMON_DIR)/sendchar_null.c \
	$(COMMON_DIR)/util.c \
	$(COMMON_DIR)/eeconfig.c \
	$(COMMON_DIR)/report.c \

M tmk_core/common/sendchar_null.c => tmk_core/common/sendchar_null.c +1 -1
@@ 16,4 16,4 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "sendchar.h"

int8_t sendchar(uint8_t c) { return 0; }
__attribute__((weak)) int8_t sendchar(uint8_t c) { return 0; }

M tmk_core/protocol/ibm4704.c => tmk_core/protocol/ibm4704.c +3 -1
@@ 161,7 161,9 @@ ISR(IBM4704_INT_VECT) {
        case STOP:
            // Data:Low
            WAIT(data_lo, 100, state);
            rbuf_enqueue(data);
            if (!rbuf_enqueue(data)) {
                print("rbuf: full\n");
            }
            ibm4704_error = IBM4704_ERR_NONE;
            goto DONE;
            break;

M tmk_core/protocol/lufa/lufa.c => tmk_core/protocol/lufa/lufa.c +0 -2
@@ 801,8 801,6 @@ ERROR_EXIT:
    Endpoint_SelectEndpoint(ep);
    return -1;
}
#else
int8_t sendchar(uint8_t c) { return 0; }
#endif

/*******************************************************************************

M tmk_core/protocol/vusb.mk => tmk_core/protocol/vusb.mk +3 -4
@@ 9,13 9,12 @@ SRC +=	$(VUSB_DIR)/main.c \
	$(VUSB_DIR)/usbdrv/oddebug.c


ifdef NO_UART
SRC +=	$(COMMON_DIR)/sendchar_null.c
else
ifneq ($(strip $(CONSOLE_ENABLE)), yes)
ifndef NO_UART
SRC +=	$(COMMON_DIR)/sendchar_uart.c \
	$(COMMON_DIR)/uart.c
endif

endif

# Search Path
VPATH += $(TMK_PATH)/$(VUSB_DIR)

M tmk_core/protocol/vusb/main.c => tmk_core/protocol/vusb/main.c +42 -5
@@ 21,12 21,23 @@
#include "uart.h"
#include "debug.h"
#include "suspend.h"
#include "wait.h"
#include "sendchar.h"

#ifdef SLEEP_LED_ENABLE
#    include "sleep_led.h"
#endif

#define UART_BAUD_RATE 115200

#ifdef CONSOLE_ENABLE
void console_task(void);
#endif

#ifdef RAW_ENABLE
void raw_hid_task(void);
#endif

/* This is from main.c of USBaspLoader */
static void initForUsbConnectivity(void) {
    uint8_t i = 0;


@@ 39,10 50,9 @@ static void initForUsbConnectivity(void) {
        _delay_ms(1);
    }
    usbDeviceConnect();
    sei();
}

void usb_remote_wakeup(void) {
static void usb_remote_wakeup(void) {
    cli();

    int8_t ddr_orig = USBDDR;


@@ 59,6 69,23 @@ void usb_remote_wakeup(void) {
    sei();
}

/** \brief Setup USB
 *
 * FIXME: Needs doc
 */
static void setup_usb(void) {
    // debug("initForUsbConnectivity()\n");
    initForUsbConnectivity();

    // for Console_Task
    print_set_sendchar(sendchar);
}

/** \brief Main
 *
 * FIXME: Needs doc
 */
int main(void) __attribute__((weak));
int main(void) {
    bool suspended = false;
#if USB_COUNT_SOF


@@ 76,8 103,10 @@ int main(void) {
    keyboard_setup();

    host_set_driver(vusb_driver());
    debug("initForUsbConnectivity()\n");
    initForUsbConnectivity();
    setup_usb();
    sei();

    wait_ms(50);

    keyboard_init();
#ifdef SLEEP_LED_ENABLE


@@ 120,12 149,13 @@ int main(void) {
        if (!suspended) {
            usbPoll();

            // TODO: configuration process is incosistent. it sometime fails.
            // TODO: configuration process is inconsistent. it sometime fails.
            // To prevent failing to configure NOT scan keyboard during configuration
            if (usbConfiguration && usbInterruptIsReady()) {
                keyboard_task();
            }
            vusb_transfer_keyboard();

#ifdef RAW_ENABLE
            usbPoll();



@@ 133,6 163,13 @@ int main(void) {
                raw_hid_task();
            }
#endif
#ifdef CONSOLE_ENABLE
            usbPoll();

            if (usbConfiguration && usbInterruptIsReady3()) {
                console_task();
            }
#endif
        } else if (suspend_wakeup_condition()) {
            usb_remote_wakeup();
        }

M tmk_core/protocol/vusb/vusb.c => tmk_core/protocol/vusb/vusb.c +187 -26
@@ 15,25 15,50 @@ You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <avr/eeprom.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include <stdint.h>
#include "usbdrv.h"
#include "usbconfig.h"
#include "host.h"
#include "report.h"
#include "print.h"
#include "debug.h"
#include "host_driver.h"
#include "vusb.h"
#include <util/delay.h>
#include "print.h"
#include "debug.h"

#ifdef 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."
#if defined(CONSOLE_ENABLE)
#    define RBUF_SIZE 128
#    include "ring_buffer.h"
#endif

#define NEXT_INTERFACE __COUNTER__

/*
 * Interface indexes
 */
enum usb_interfaces {
    KEYBOARD_INTERFACE = NEXT_INTERFACE,
#if (defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE))
    MOUSE_EXTRA_INTERFACE = NEXT_INTERFACE,
#endif
#ifdef RAW_ENABLE
    RAW_INTERFACE = NEXT_INTERFACE,
#endif
#ifdef CONSOLE_ENABLE
    CONSOLE_INTERFACE = NEXT_INTERFACE,
#endif
    TOTAL_INTERFACES = NEXT_INTERFACE,
};

#define MAX_INTERFACES 2

#if (NEXT_INTERFACE - 1) > MAX_INTERFACES
#    error There are not enough available interfaces to support all functions. Please disable one or more of the following: Mouse Keys, Extra Keys, Raw HID, Console
#endif

static uint8_t vusb_keyboard_leds = 0;


@@ 120,7 145,60 @@ void raw_hid_task(void) {
        raw_output_received_bytes = 0;
    }
}
#endif

/*------------------------------------------------------------------*
 * Console
 *------------------------------------------------------------------*/
#ifdef CONSOLE_ENABLE
#    define CONSOLE_BUFFER_SIZE 32
#    define CONSOLE_EPSIZE 8

int8_t sendchar(uint8_t c) {
    rbuf_enqueue(c);
    return 0;
}

static inline bool usbSendData3(char *data, uint8_t len) {
    uint8_t retries = 5;
    while (!usbInterruptIsReady3()) {
        if (!(retries--)) {
            return false;
        }
        usbPoll();
    }

    usbSetInterrupt3((unsigned char *)data, len);
    return true;
}

void console_task(void) {
    if (!usbConfiguration) {
        return;
    }

    if (!rbuf_has_data()) {
        return;
    }

    // Send in chunks of 8 padded to 32
    char    send_buf[CONSOLE_BUFFER_SIZE] = {0};
    uint8_t send_buf_count                = 0;
    while (rbuf_has_data() && send_buf_count < CONSOLE_EPSIZE) {
        send_buf[send_buf_count++] = rbuf_dequeue();
    }

    char *temp = send_buf;
    for (uint8_t i = 0; i < 4; i++) {
        if (!usbSendData3(temp, 8)) {
            break;
        }
        temp += 8;
    }

    usbSendData3(0, 0);
    usbPoll();
}
#endif

/*------------------------------------------------------------------*


@@ 429,7 507,30 @@ const PROGMEM uchar raw_hid_report[] = {
    0x95, RAW_BUFFER_SIZE,  //   Report Count
    0x75, 0x08,             //   Report Size (8)
    0x91, 0x02,             //   Output (Data, Variable, Absolute)
    0xC0,                   // End Collection
    0xC0                    // End Collection
};
#endif

#if defined(CONSOLE_ENABLE)
const PROGMEM uchar console_hid_report[] = {
    0x06, 0x31, 0xFF,  // Usage Page (Vendor Defined - PJRC Teensy compatible)
    0x09, 0x74,        // Usage (Vendor Defined - PJRC Teensy compatible)
    0xA1, 0x01,        // Collection (Application)
    // Data to host
    0x09, 0x75,                 //   Usage (Vendor Defined)
    0x15, 0x00,                 //   Logical Minimum (0x00)
    0x26, 0xFF, 0x00,           //   Logical Maximum (0x00FF)
    0x95, CONSOLE_BUFFER_SIZE,  //   Report Count
    0x75, 0x08,                 //   Report Size (8)
    0x81, 0x02,                 //   Input (Data, Variable, Absolute)
    // Data from host
    0x09, 0x76,                 //   Usage (Vendor Defined)
    0x15, 0x00,                 //   Logical Minimum (0x00)
    0x26, 0xFF, 0x00,           //   Logical Maximum (0x00FF)
    0x95, CONSOLE_BUFFER_SIZE,  //   Report Count
    0x75, 0x08,                 //   Report Size (8)
    0x91, 0x02,                 //   Output (Data)
    0xC0                        // End Collection
};
#endif



@@ 511,11 612,7 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
            .bDescriptorType = USBDESCR_CONFIG
        },
        .wTotalLength        = sizeof(usbConfigurationDescriptor_t),
#    if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE) || defined(RAW_ENABLE)
        .bNumInterfaces      = 2,
#    else
        .bNumInterfaces      = 1,
#    endif
        .bNumInterfaces      = TOTAL_INTERFACES,
        .bConfigurationValue = 0x01,
        .iConfiguration      = 0x00,
        .bmAttributes        = (1 << 7) | USBATTR_REMOTEWAKE,


@@ 530,7 627,7 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
            .bLength         = sizeof(usbInterfaceDescriptor_t),
            .bDescriptorType = USBDESCR_INTERFACE
        },
        .bInterfaceNumber    = 0,
        .bInterfaceNumber    = KEYBOARD_INTERFACE,
        .bAlternateSetting   = 0x00,
        .bNumEndpoints       = 1,
        .bInterfaceClass     = 0x03,


@@ 569,7 666,7 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
            .bLength         = sizeof(usbInterfaceDescriptor_t),
            .bDescriptorType = USBDESCR_INTERFACE
        },
        .bInterfaceNumber    = 1,
        .bInterfaceNumber    = MOUSE_EXTRA_INTERFACE,
        .bAlternateSetting   = 0x00,
        .bNumEndpoints       = 1,
        .bInterfaceClass     = 0x03,


@@ 597,14 694,15 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
        .bmAttributes        = 0x03,
        .wMaxPacketSize      = 8,
        .bInterval           = USB_POLLING_INTERVAL_MS
    }
#    elif defined(RAW_ENABLE)
    },
#    endif
#    if defined(RAW_ENABLE)
    .rawInterface = {
        .header = {
            .bLength         = sizeof(usbInterfaceDescriptor_t),
            .bDescriptorType = USBDESCR_INTERFACE
        },
        .bInterfaceNumber    = 1,
        .bInterfaceNumber    = RAW_INTERFACE,
        .bAlternateSetting   = 0x00,
        .bNumEndpoints       = 2,
        .bInterfaceClass     = 0x03,


@@ 642,7 740,56 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
        .bmAttributes        = 0x03,
        .wMaxPacketSize      = RAW_EPSIZE,
        .bInterval           = USB_POLLING_INTERVAL_MS
    }
    },
#    endif
#    if defined(CONSOLE_ENABLE)
    /*
     * Console
     */
    .consoleInterface = {
        .header = {
            .bLength         = sizeof(usbInterfaceDescriptor_t),
            .bDescriptorType = USBDESCR_INTERFACE
        },
        .bInterfaceNumber    = CONSOLE_INTERFACE,
        .bAlternateSetting   = 0x00,
        .bNumEndpoints       = 2,
        .bInterfaceClass     = 0x03,
        .bInterfaceSubClass  = 0x00,
        .bInterfaceProtocol  = 0x00,
        .iInterface          = 0x00
    },
    .consoleHID = {
        .header = {
            .bLength         = sizeof(usbHIDDescriptor_t),
            .bDescriptorType = USBDESCR_HID
        },
        .bcdHID              = 0x0111,
        .bCountryCode        = 0x00,
        .bNumDescriptors     = 1,
        .bDescriptorType     = USBDESCR_HID_REPORT,
        .wDescriptorLength   = sizeof(console_hid_report)
    },
    .consoleINEndpoint = {
        .header = {
            .bLength         = sizeof(usbEndpointDescriptor_t),
            .bDescriptorType = USBDESCR_ENDPOINT
        },
        .bEndpointAddress    = (USBRQ_DIR_DEVICE_TO_HOST | USB_CFG_EP3_NUMBER),
        .bmAttributes        = 0x03,
        .wMaxPacketSize      = CONSOLE_EPSIZE,
        .bInterval           = 0x01
    },
    .consoleOUTEndpoint = {
        .header = {
            .bLength         = sizeof(usbEndpointDescriptor_t),
            .bDescriptorType = USBDESCR_ENDPOINT
        },
        .bEndpointAddress    = (USBRQ_DIR_HOST_TO_DEVICE | USB_CFG_EP3_NUMBER),
        .bmAttributes        = 0x03,
        .wMaxPacketSize      = CONSOLE_EPSIZE,
        .bInterval           = 0x01
    },
#    endif
};



@@ 690,41 837,55 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
            break;
        case USBDESCR_HID:
            switch (rq->wValue.bytes[0]) {
                case 0:
                case KEYBOARD_INTERFACE:
                    usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.keyboardHID;
                    len       = sizeof(usbHIDDescriptor_t);
                    break;
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
                case 1:
                case MOUSE_EXTRA_INTERFACE:
                    usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.mouseExtraHID;
                    len       = sizeof(usbHIDDescriptor_t);
                    break;
#elif defined(RAW_ENABLE)
                case 1:
#endif
#if defined(RAW_ENABLE)
                case RAW_INTERFACE:
                    usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.rawHID;
                    len       = sizeof(usbHIDDescriptor_t);
                    break;
#endif
#if defined(CONSOLE_ENABLE)
                case CONSOLE_INTERFACE:
                    usbMsgPtr = (unsigned char *)&usbConfigurationDescriptor.consoleHID;
                    len       = sizeof(usbHIDDescriptor_t);
                    break;
#endif
            }
            break;
        case USBDESCR_HID_REPORT:
            /* interface index */
            switch (rq->wIndex.word) {
                case 0:
                case KEYBOARD_INTERFACE:
                    usbMsgPtr = (unsigned char *)keyboard_hid_report;
                    len       = sizeof(keyboard_hid_report);
                    break;
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
                case 1:
                case MOUSE_EXTRA_INTERFACE:
                    usbMsgPtr = (unsigned char *)mouse_extra_hid_report;
                    len       = sizeof(mouse_extra_hid_report);
                    break;
#elif defined(RAW_ENABLE)
                case 1:
#endif
#if defined(RAW_ENABLE)
                case RAW_INTERFACE:
                    usbMsgPtr = (unsigned char *)raw_hid_report;
                    len       = sizeof(raw_hid_report);
                    break;
#endif
#if defined(CONSOLE_ENABLE)
                case CONSOLE_INTERFACE:
                    usbMsgPtr = (unsigned char *)console_hid_report;
                    len       = sizeof(console_hid_report);
                    break;
#endif
            }
            break;
    }

M tmk_core/protocol/vusb/vusb.h => tmk_core/protocol/vusb/vusb.h +10 -5
@@ 93,19 93,24 @@ typedef struct usbConfigurationDescriptor {
    usbInterfaceDescriptor_t mouseExtraInterface;
    usbHIDDescriptor_t       mouseExtraHID;
    usbEndpointDescriptor_t  mouseExtraINEndpoint;
#elif defined(RAW_ENABLE)
#endif

#if defined(RAW_ENABLE)
    usbInterfaceDescriptor_t rawInterface;
    usbHIDDescriptor_t       rawHID;
    usbEndpointDescriptor_t  rawINEndpoint;
    usbEndpointDescriptor_t  rawOUTEndpoint;
#endif

#if defined(CONSOLE_ENABLE)
    usbInterfaceDescriptor_t consoleInterface;
    usbHIDDescriptor_t       consoleHID;
    usbEndpointDescriptor_t  consoleINEndpoint;
    usbEndpointDescriptor_t  consoleOUTEndpoint;
#endif
} __attribute__((packed)) usbConfigurationDescriptor_t;

#define USB_STRING_LEN(s) (sizeof(usbDescriptorHeader_t) + ((s) << 1))

host_driver_t *vusb_driver(void);
void           vusb_transfer_keyboard(void);

#ifdef RAW_ENABLE
void raw_hid_task(void);
#endif

M tmk_core/ring_buffer.h => tmk_core/ring_buffer.h +9 -4
@@ 3,21 3,26 @@
/*--------------------------------------------------------------------
 * Ring buffer to store scan codes from keyboard
 *------------------------------------------------------------------*/
#define RBUF_SIZE 32
#ifndef RBUF_SIZE
#    define RBUF_SIZE 32
#endif
#include <util/atomic.h>
#include <stdint.h>
#include <stdbool.h>
static uint8_t     rbuf[RBUF_SIZE];
static uint8_t     rbuf_head = 0;
static uint8_t     rbuf_tail = 0;
static inline void rbuf_enqueue(uint8_t data) {
static inline bool rbuf_enqueue(uint8_t data) {
    bool ret = false;
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        uint8_t next = (rbuf_head + 1) % RBUF_SIZE;
        if (next != rbuf_tail) {
            rbuf[rbuf_head] = data;
            rbuf_head       = next;
        } else {
            print("rbuf: full\n");
            ret             = true;
        }
    }
    return ret;
}
static inline uint8_t rbuf_dequeue(void) {
    uint8_t val = 0;