Add NKRO support for LUFA

This commit is contained in:
tmk 2013-07-28 17:34:41 +09:00
parent c7d309e34b
commit daa4a4235f
10 changed files with 168 additions and 177 deletions

View File

@ -37,8 +37,10 @@ static uint16_t last_consumer_report = 0;
static inline void add_key_byte(uint8_t code);
static inline void del_key_byte(uint8_t code);
#ifdef NKRO_ENABLE
static inline void add_key_bit(uint8_t code);
static inline void del_key_bit(uint8_t code);
#endif
void host_set_driver(host_driver_t *d)
@ -63,11 +65,11 @@ void host_keyboard_send(report_keyboard_t *report)
(*driver->send_keyboard)(report);
if (debug_keyboard) {
dprint("keys: ");
for (int i = 0; i < REPORT_KEYS; i++) {
dprintf("%02X ", keyboard_report->keys[i]);
dprint("keyboard_report: ");
for (uint8_t i = 0; i < REPORT_SIZE; i++) {
dprintf("%02X ", keyboard_report->raw[i]);
}
dprintf(" mods: %02X\n", keyboard_report->mods);
dprint("\n");
}
}
@ -122,8 +124,9 @@ void host_del_key(uint8_t key)
void host_clear_keys(void)
{
for (int8_t i = 0; i < REPORT_KEYS; i++) {
keyboard_report->keys[i] = 0;
// not clea mods
for (int8_t i = 1; i < REPORT_SIZE; i++) {
keyboard_report->raw[i] = 0;
}
}
@ -155,8 +158,8 @@ void host_clear_mods(void)
uint8_t host_has_anykey(void)
{
uint8_t cnt = 0;
for (int i = 0; i < REPORT_KEYS; i++) {
if (keyboard_report->keys[i])
for (uint8_t i = 1; i < REPORT_SIZE; i++) {
if (keyboard_report->raw[i])
cnt++;
}
return cnt;
@ -172,9 +175,9 @@ uint8_t host_get_first_key(void)
#ifdef NKRO_ENABLE
if (keyboard_nkro) {
uint8_t i = 0;
for (; i < REPORT_KEYS && !keyboard_report->keys[i]; i++)
for (; i < REPORT_BITS && !keyboard_report->nkro.bits[i]; i++)
;
return i<<3 | biton(keyboard_report->keys[i]);
return i<<3 | biton(keyboard_report->nkro.bits[i]);
}
#endif
return keyboard_report->keys[0];
@ -222,18 +225,18 @@ static inline void add_key_byte(uint8_t code)
static inline void del_key_byte(uint8_t code)
{
int i = 0;
for (; i < REPORT_KEYS; i++) {
for (uint8_t i = 0; i < REPORT_KEYS; i++) {
if (keyboard_report->keys[i] == code) {
keyboard_report->keys[i] = 0;
}
}
}
#ifdef NKRO_ENABLE
static inline void add_key_bit(uint8_t code)
{
if ((code>>3) < REPORT_KEYS) {
keyboard_report->keys[code>>3] |= 1<<(code&7);
if ((code>>3) < REPORT_BITS) {
keyboard_report->nkro.bits[code>>3] |= 1<<(code&7);
} else {
dprintf("add_key_bit: can't add: %02X\n", code);
}
@ -241,9 +244,10 @@ static inline void add_key_bit(uint8_t code)
static inline void del_key_bit(uint8_t code)
{
if ((code>>3) < REPORT_KEYS) {
keyboard_report->keys[code>>3] &= ~(1<<(code&7));
if ((code>>3) < REPORT_BITS) {
keyboard_report->nkro.bits[code>>3] &= ~(1<<(code&7));
} else {
dprintf("del_key_bit: can't del: %02X\n", code);
}
}
#endif

View File

@ -72,14 +72,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/* key report size(NKRO or boot mode) */
#if defined(PROTOCOL_PJRC)
#if defined(PROTOCOL_PJRC) && defined(NKRO_ENABLE)
# include "usb.h"
# if defined(KBD2_REPORT_KEYS) && KBD2_REPORT_KEYS > KBD_REPORT_KEYS
# define REPORT_KEYS KBD2_REPORT_KEYS
# else
# define REPORT_KEYS KBD_REPORT_KEYS
# endif
# define REPORT_SIZE KBD2_SIZE
# define REPORT_KEYS (KBD2_SIZE - 2)
# define REPORT_BITS (KBD2_SIZE - 1)
#elif defined(PROTOCOL_LUFA) && defined(NKRO_ENABLE)
# include "protocol/lufa/descriptor.h"
# define REPORT_SIZE NKRO_EPSIZE
# define REPORT_KEYS (NKRO_EPSIZE - 2)
# define REPORT_BITS (NKRO_EPSIZE - 1)
#else
# define REPORT_SIZE 8
# define REPORT_KEYS 6
#endif
@ -88,11 +94,27 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
extern "C" {
#endif
typedef union {
uint8_t raw[REPORT_SIZE];
struct {
uint8_t mods;
uint8_t reserved;
uint8_t keys[REPORT_KEYS];
};
#ifdef NKRO_ENABLE
struct {
uint8_t mods;
uint8_t bits[REPORT_BITS];
} nkro;
#endif
} __attribute__ ((packed)) report_keyboard_t;
/*
typedef struct {
uint8_t mods;
uint8_t rserved;
uint8_t reserved;
uint8_t keys[REPORT_KEYS];
} __attribute__ ((packed)) report_keyboard_t;
*/
typedef struct {
uint8_t buttons;

View File

@ -57,8 +57,8 @@ CONFIG_H = config.h
# MCU name
MCU = at90usb1286
#MCU = atmega32u4
#MCU = at90usb1286
MCU = atmega32u4
# Processor frequency.
# This will define a symbol, F_CPU, in all source code files equal to the
@ -103,7 +103,7 @@ OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
# Atmel DFU loader 4096
# LUFA bootloader 4096
# USBaspLoader 2048
OPT_DEFS += -DBOOTLOADER_SIZE=512
OPT_DEFS += -DBOOTLOADER_SIZE=4096
# Build Options
@ -114,7 +114,7 @@ MOUSEKEY_ENABLE = yes # Mouse keys
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = yes # Console for debug
COMMAND_ENABLE = yes # Commands for debug and configuration
#NKRO_ENABLE = yes # USB Nkey Rollover
NKRO_ENABLE = yes # USB Nkey Rollover
# Search Path

View File

@ -23,9 +23,9 @@ CONFIG_H = config.h
# MCU name, you MUST set this to match the board you are using
# type "make clean" after changing this, so all files will be rebuilt
#MCU = at90usb162 # Teensy 1.0
#MCU = atmega32u4 # Teensy 2.0
MCU = atmega32u4 # Teensy 2.0
#MCU = at90usb646 # Teensy++ 1.0
MCU = at90usb1286 # Teensy++ 2.0
#MCU = at90usb1286 # Teensy++ 2.0
# Processor frequency.

View File

@ -1,129 +0,0 @@
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device.
# Please customize your programmer settings(PROGRAM_CMD)
#
# make teensy = Download the hex file to the device, using teensy_loader_cli.
# (must have teensy_loader_cli installed).
#
# make dfu = Download the hex file to the device, using dfu-programmer (must
# have dfu-programmer installed).
#
# make flip = Download the hex file to the device, using Atmel FLIP (must
# have Atmel FLIP installed).
#
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
# (must have dfu-programmer installed).
#
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
# (must have Atmel FLIP installed).
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
# Target file name (without extension).
TARGET = hhkb_tmk
# Directory common source filess exist
TOP_DIR = ../..
# Directory keyboard dependent files exist
TARGET_DIR = .
# List C source files here. (C dependencies are automatically generated.)
SRC += keymap.c \
matrix.c \
led.c
CONFIG_H = config.h
# MCU name
#MCU = at90usb1286
MCU = atmega32u4
# Processor frequency.
# This will define a symbol, F_CPU, in all source code files equal to the
# processor frequency in Hz. You can then use this symbol in your source code to
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
# automatically to create a 32-bit value in your source code.
#
# This will be an integer division of F_USB below, as it is sourced by
# F_USB after it has run through any CPU prescalers. Note that this value
# does not *change* the processor frequency - it should merely be updated to
# reflect the processor speed set externally so that the code can use accurate
# software delays.
F_CPU = 16000000
#
# LUFA specific
#
# Target architecture (see library "Board Types" documentation).
ARCH = AVR8
# Input clock frequency.
# This will define a symbol, F_USB, in all source code files equal to the
# input clock frequency (before any prescaling is performed) in Hz. This value may
# differ from F_CPU if prescaling is used on the latter, and is required as the
# raw input clock is fed directly to the PLL sections of the AVR for high speed
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
# at the end, this will be done automatically to create a 32-bit value in your
# source code.
#
# If no clock division is performed on the input clock inside the AVR (via the
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
F_USB = $(F_CPU)
# Interrupt driven control endpoint task
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
# Boot Section Size in *bytes*
# Teensy halfKay 512
# Teensy++ halfKay 1024
# Atmel DFU loader 4096
# LUFA bootloader 4096
# USBaspLoader 2048
OPT_DEFS += -DBOOTLOADER_SIZE=4096
# Build Options
# comment out to disable the options.
#
#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration
MOUSEKEY_ENABLE = yes # Mouse keys
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = yes # Console for debug
COMMAND_ENABLE = yes # Commands for debug and configuration
#NKRO_ENABLE = yes # USB Nkey Rollover
# Search Path
VPATH += $(TARGET_DIR)
VPATH += $(TOP_DIR)
include $(TOP_DIR)/protocol/lufa.mk
include $(TOP_DIR)/common.mk
include $(TOP_DIR)/rules.mk
debug-on: EXTRAFLAGS += -DDEBUG
debug-on: all

View File

@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0xCAFE
#define DEVICE_VER 0x0103
#define DEVICE_VER 0x0104
#define MANUFACTURER t.m.k.
#define PRODUCT HHKB mod
#define DESCRIPTION t.m.k. keyboard firmware for HHKB mod

View File

@ -57,9 +57,11 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
HID_RI_REPORT_COUNT(8, 0x08),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_REPORT_COUNT(8, 0x01),
HID_RI_REPORT_SIZE(8, 0x08),
HID_RI_INPUT(8, HID_IOF_CONSTANT),
HID_RI_INPUT(8, HID_IOF_CONSTANT), /* reserved */
HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */
HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */
HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */
@ -69,6 +71,7 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
HID_RI_REPORT_COUNT(8, 0x01),
HID_RI_REPORT_SIZE(8, 0x03),
HID_RI_OUTPUT(8, HID_IOF_CONSTANT),
HID_RI_USAGE_PAGE(8, 0x07), /* Keyboard */
HID_RI_USAGE_MINIMUM(8, 0x00), /* Reserved (no event indicated) */
HID_RI_USAGE_MAXIMUM(8, 0xFF), /* Keyboard Application */
@ -210,11 +213,13 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM NKROReport[] =
HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
HID_RI_USAGE_MINIMUM(8, 0x00), /* Keyboard 0 */
HID_RI_USAGE_MAXIMUM(8, NKRO_SIZE*8-1), /* Keyboard Right GUI */
HID_RI_USAGE_MAXIMUM(8, (NKRO_EPSIZE-1)*8-1), /* Keyboard Right GUI */
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
HID_RI_REPORT_COUNT(8, NKRO_SIZE*8),
HID_RI_REPORT_COUNT(8, (NKRO_EPSIZE-1)*8),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
};
#endif
@ -439,6 +444,48 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.PollingIntervalMS = 0x01
},
#endif
/*
* NKRO
*/
#ifdef NKRO_ENABLE
.NKRO_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
.InterfaceNumber = NKRO_INTERFACE,
.AlternateSetting = 0x00,
.TotalEndpoints = 1,
.Class = HID_CSCP_HIDClass,
.SubClass = HID_CSCP_NonBootSubclass,
.Protocol = HID_CSCP_NonBootProtocol,
.InterfaceStrIndex = NO_DESCRIPTOR
},
.NKRO_HID =
{
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
.HIDSpec = VERSION_BCD(01.11),
.CountryCode = 0x00,
.TotalReportDescriptors = 1,
.HIDReportType = HID_DTYPE_Report,
.HIDReportLength = sizeof(NKROReport)
},
.NKRO_INEndpoint =
{
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
.EndpointAddress = (ENDPOINT_DIR_IN | NKRO_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = NKRO_EPSIZE,
.PollingIntervalMS = 0x01
},
#endif
};
@ -535,6 +582,12 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
Address = &ConfigurationDescriptor.Console_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#endif
#ifdef NKRO_ENABLE
case NKRO_INTERFACE:
Address = &ConfigurationDescriptor.NKRO_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#endif
}
break;
@ -561,6 +614,12 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
Address = &ConsoleReport;
Size = sizeof(ConsoleReport);
break;
#endif
#ifdef NKRO_ENABLE
case NKRO_INTERFACE:
Address = &NKROReport;
Size = sizeof(NKROReport);
break;
#endif
}
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012 Jun Wako <wakojun@gmail.com>
* Copyright 2012,2013 Jun Wako <wakojun@gmail.com>
* This file is based on:
* LUFA-120219/Demos/Device/Lowlevel/KeyboardMouse
* LUFA-120219/Demos/Device/Lowlevel/GenericHID
@ -78,6 +78,13 @@ typedef struct
USB_Descriptor_Endpoint_t Console_INEndpoint;
USB_Descriptor_Endpoint_t Console_OUTEndpoint;
#endif
#ifdef NKRO_ENABLE
// NKRO HID Interface
USB_Descriptor_Interface_t NKRO_Interface;
USB_HID_Descriptor_HID_t NKRO_HID;
USB_Descriptor_Endpoint_t NKRO_INEndpoint;
#endif
} USB_Descriptor_Configuration_t;
@ -102,9 +109,15 @@ typedef struct
# define CONSOLE_INTERFACE EXTRAKEY_INTERFACE
#endif
#ifdef NKRO_ENABLE
# define NKRO_INTERFACE (CONSOLE_INTERFACE + 1)
#else
# define NKRO_INTERFACE CONSOLE_INTERFACE
#endif
/* nubmer of interfaces */
#define TOTAL_INTERFACES (CONSOLE_INTERFACE + 1)
#define TOTAL_INTERFACES (NKRO_INTERFACE + 1)
// Endopoint number and size
@ -125,6 +138,12 @@ typedef struct
#ifdef CONSOLE_ENABLE
# define CONSOLE_IN_EPNUM (EXTRAKEY_IN_EPNUM + 1)
# define CONSOLE_OUT_EPNUM (EXTRAKEY_IN_EPNUM + 2)
#else
# define CONSOLE_OUT_EPNUM EXTRAKEY_IN_EPNUM
#endif
#ifdef NKRO_ENABLE
# define NKRO_IN_EPNUM (CONSOLE_OUT_EPNUM + 1)
#endif
@ -132,6 +151,7 @@ typedef struct
#define MOUSE_EPSIZE 8
#define EXTRAKEY_EPSIZE 8
#define CONSOLE_EPSIZE 32
#define NKRO_EPSIZE 16
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,

View File

@ -220,6 +220,12 @@ void EVENT_USB_Device_ConfigurationChanged(void)
ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
#endif
#ifdef NKRO_ENABLE
/* Setup NKRO HID Report Endpoints */
ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
#endif
}
/*
@ -350,15 +356,31 @@ static void send_keyboard(report_keyboard_t *report)
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
// TODO: handle NKRO report
/* Select the Keyboard Report Endpoint */
#ifdef NKRO_ENABLE
if (keyboard_nkro) {
Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
}
else
#endif
{
Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
}
/* Check if Keyboard Endpoint Ready for Read/Write */
while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
/* Write Keyboard Report Data */
Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
#ifdef NKRO_ENABLE
if (keyboard_nkro) {
Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
}
else
#endif
{
/* boot mode */
Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
}
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();

View File

@ -57,12 +57,12 @@ int8_t usb_keyboard_send_report(report_keyboard_t *report)
#ifdef NKRO_ENABLE
if (keyboard_nkro)
result = send_report(report, KBD2_ENDPOINT, 0, KBD2_REPORT_KEYS);
result = send_report(report, KBD2_ENDPOINT, 0, KBD2_SIZE);
else
#endif
{
if (usb_keyboard_protocol)
result = send_report(report, KBD_ENDPOINT, 0, KBD_REPORT_KEYS);
result = send_report(report, KBD_ENDPOINT, 0, KBD_SIZE);
else
result = send_report(report, KBD_ENDPOINT, 0, 6);
}
@ -104,15 +104,8 @@ static inline int8_t send_report(report_keyboard_t *report, uint8_t endpoint, ui
cli();
UENUM = endpoint;
}
UEDATX = report->mods;
#ifdef NKRO_ENABLE
if (!keyboard_nkro)
UEDATX = 0;
#else
UEDATX = 0;
#endif
for (uint8_t i = keys_start; i < keys_end; i++) {
UEDATX = report->keys[i];
UEDATX = report->raw[i];
}
UEINTX = 0x3A;
SREG = intr_state;