add build option: NKRO_ENABLE(remove: USB_12KRO)

This commit is contained in:
tmk 2010-12-08 01:47:57 +09:00
parent 66ece29b0e
commit 51f17f0231
12 changed files with 413 additions and 259 deletions

View file

@ -129,8 +129,8 @@ CDEFS += -DPRODUCT=$(PRODUCT)
ifdef MOUSE_DELAY_TIME
CDEFS += -DMOUSE_DELAY_TIME=$(MOUSE_DELAY_TIME)
endif
ifdef USB_12KRO
CDEFS += -DUSB_12KRO
ifdef NKRO_ENABLE
CDEFS += -DNKRO_ENABLE
endif

109
README
View file

@ -2,42 +2,23 @@ t.m.k. Keyboard Firmware
========================
http://github.com/tmk/tmk_keyboard
This is keyboard firmware for PFU HHKB style keyboard and Teensy/Teensy++ 2.0.
OS see this as composite device which has keyboard and mouse.
This is keyboard firmware for AVR USB MCUs or Teensy/Teensy++ 2.0.
The project is heavily based on PJRC USB Keyboard/Mouse Example and
owes a debt to preceding keyboard firmware projects.
http://www.pjrc.com/teensy
Version
-------
0.1 2010/08/23
It works as normal keyboard.
It is for modified Macway keyboard(TP-999KB-E).
1.0 2010/10/02
keyboard has mouse key now.
keyboard with layers.(see keymap.c)
FN_1(right cmd):
vi style layer
FN_2(next to right shift):
HHKB style layer
FN_3(left bottom):
h j k l: mouse move
a s d spc: mouse buttons
m ,: mouse wheel
1.1 2010/10/08
Matrix wiring changed for casing.
(and my Teensy PD3 seems to be latchuped and unusable. :<)
1.2 2010/10/13
HHKB support
horizontal mouse wheel support
change keymaps
2.0 2010/10/27
HHKB/Macway support merged
Functions
---------
Mouse key
System Control Key
Power Down, Sleep, Wake Up & USB Remote Wake up
Media Control Key
Volume Down/Up, Mute
USB NKRO
Build
@ -47,17 +28,16 @@ Compiling sources need AVR GCC, AVR Libc and GNU make.(You can use WinAVR on Win
$ cd <target> (hhkb or macway)
$ make
http://winavr.sourceforge.net/
Debuging
--------
Debug print is on if 4 keys are pressed during booting.
Debuging & Rescue
-----------------
Use PJRC's hid_listen.exe to see debug messages.
Press right Control + Shift + Alt + GUI + H to debug menu.
AVR Target board
----------------
Teensy/Teensy++
http://www.pjrc.com/teensy
Pressing any 3 keys when connected enables debug output.
Pressing any 4 keys when connected makes bootloader comes up.
Projects related
@ -83,59 +63,4 @@ ps2avr
http://sourceforge.net/projects/ps2avr/
TODO & ideas
------------
licensing notes(GPL)
I think GPL is not infringement of PJRC license.
souce code cleaning
sleep&wakeup
debouncing logic
will be coded when bouncing occurs.
bouncing doesnt occur on my ALPS switch so far.
scan rate is too slow?(to be measure)
Trackpoint(PS/2)
receive PS/2 signal from TrackPoint
send USB HID report
Thinkpad keyboard support
turn keyboard to USB keyboard/mouse composite device
setting menu(configure without changing firmware)
console for display
keymap/layer setting
mouse speed/acceleration
matrix display
PS/2 keyboard mode
with USB to PS/2 dumb adapter(possible?)
AT90USBKEY support
and other AVR USB boards
DONE:
support for HHKB pro matrix signal
exchange controller board with teensy
2010/10/11
keymap
Matias half keyboard style
2010/10/23
souce code cleaning
2010/10/23
debug on/off
debug off by default
pressing keys during booting
2010/10/23
mouse horizontal wheel
http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
http://www.keil.com/forum/15671/
http://www.microsoft.com/whdc/device/input/wheel.mspx
2010/10/13
debug on/off
Fn key conbination during normal operation
matrix print on/off
key print on/off
mouse print on/off
2010/10/26
layer switching
time before switching
timeout when not used during specific time
2010/10/30
EOF

99
USB_NKRO.txt Normal file
View file

@ -0,0 +1,99 @@
USB NKRO MEMO
=============
2010/12/07
References
----------
USB - boot mode, NKRO, compatibility, etc...
http://geekhack.org/showthread.php?t=13162
NKey Rollover - Overview, Testing Methodology, and Results
http://geekhack.org/showwiki.php?title=NKey+Rollover+-+Overview+Testing+Methodology+and+Results
Terminogy
---------
NKRO
ghost
matrix
mechanical with diodes
membrane
OS Support Status
-----------------
NKRO is possible at least relatively new OS.
Following OS supports both Extended and Bitmarp report.
Windows7 64bit
Windows2000 SP4
Ubuntu 10.4(Linux 2.6)
USB NKRO methods
----------------
1. Virtual keyboards
Keyboard can increase its KRO by using virtual keyboards with Standard or Extended report.
If the keyboard has 2 virtul keyboard with Standard report(6KRO), it gets 12KRO.
Using this method means the keyboard is a composite device.
2. Exteded report
It needs large report size for this method to achive NKRO.
If a keyboard has 101keys, it needs 103byte report. It seems to be inefficient.
3. Bitmap report
If the keyboard has less than 128keys, 16byte report will be enough for NKRO.
The 16byte report seems to be reasonable cost to get NKRO.
Report Format
-------------
Other report formats than followings are possible, though these format are typical one.
1. Standard 8bytes
modifiers(bitmap) 1byte
reserved 1byte(not used)
keys(array) 1byte*6
Standard report can send 6keys plus 8modifiers simultaneously.
Standard report is used by most keyboards in the marketplace.
Standard report is identical to boot protocol report.
Standard report is hard to suffer from compatibility problems.
2. Extended standard 16,32,64bytes
modifiers(bitmap) 1byte
reserved 1byte(not used)
keys(array) 1byte*(14,32,62)
Extended report can send N-keys by using N+2bytes.
Extended report is expected to be compatible with boot protocol.
3. Bitmap 16,32,64bytes
keys(bitmap) (16,32)bytes
Bitmap report can send at most 128keys by 16bytes and 256keys by 32bytes.
Bitmap report can achieve USB NKRO efficiently in terms of report size.
Bitmap report needs a deliberation for boot protocol implementation.
Compatibility Problem
---------------------
Some BIOS doesn't send SET_PROTCOL request, a keyboard can't switch to boot protocol mode.
This may cuase a problem on a keyboard which uses other report than Standard.
Windows Problem
---------------
1. Windows accepts only 6keys in case of Standard report.
It should be able to send 6keys plus 8modifiers.
2. Windows accepts only 10keys in case of 16bytes Extended report.
It should be able to send 14keys plus 8modifiers.
3. Windows accepts only 18keys in case of 32bytes Extended report.
It should be able to send 30keys plus 8modifiers.
If keys are pressed in excess of the number, wrong keys are registered on Windows.
This problem will be reportedly fixed soon.(2010/12/05)
http://forums.anandtech.com/showpost.php?p=30873364&postcount=17
EOF

View file

@ -39,14 +39,15 @@
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
# TODO: use config.h for build options?
VENDOR_ID = 0xFEED
PRODUCT_ID = 0xCAFE
MANUFACTURER = 't.m.k.'
PRODUCT = 't.m.k. HHKB pro'
PRODUCT = 'HHKB Mod'
DESCRIPTION = 't.m.k. firmware for HHKB pro'
MOUSE_DELAY_TIME = 127
USB_12KRO = yes
NKRO_ENABLE = true
# Target file name (without extension).
TARGET = tmk_hhkb

View file

@ -42,8 +42,8 @@ static const uint8_t PROGMEM fn_keycode[] = {
KB_NO, // FN_0 [NOT USED]
KB_NO, // FN_1 layer 1
KB_SLSH, // FN_2 layer 2
KB_SCOLON, // FN_3 layer 3
KB_SPACE, // FN_4 layer 4
KB_SCLN, // FN_3 layer 3
KB_SPC, // FN_4 layer 4
KB_NO, // FN_5 [NOT USED]
KB_NO, // FN_6 [NOT USED]
KB_NO // FN_7 layer 1
@ -67,7 +67,7 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KB_TAB, KB_Q, KB_W, KB_E, KB_R, KB_T, KB_Y, KB_U, KB_I, KB_O, KB_P, KB_LBRC,KB_RBRC,KB_BSPC, \
KB_LCTL,KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, FN_3, KB_QUOT,KB_ENT, \
KB_LSFT,KB_Z, KB_X, KB_C, KB_V, KB_B, KB_N, KB_M, KB_COMM,KB_DOT, FN_2, KB_RSFT,FN_1, \
KB_LGUI,KB_LALT,FN_4, KB_RALT,FN_7),
KB_LGUI,KB_LALT,FN_4, KB_RALT,KB_RGUI),
/* Layer 1: HHKB mode (HHKB Fn)
* ,-----------------------------------------------------------.

View file

@ -1,5 +1,6 @@
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "print.h"
#include "debug.h"
@ -68,7 +69,7 @@ void proc_matrix(void) {
if (code == KB_NO) {
// do nothing
} else if (IS_MOD(code)) {
usb_keyboard_mods |= MOD_BIT(code);
usb_keyboard_add_mod(code);
} else if (IS_FN(code)) {
fn_bits |= FN_BIT(code);
} else if (IS_MOUSE(code)) {
@ -111,22 +112,7 @@ void proc_matrix(void) {
// normal keys
else {
// TODO: fix ugly code
int8_t i = 0;
int8_t empty = -1;
for (; i < KEYBOARD_REPORT_MAX; i++) {
if (usb_keyboard_keys_prev[i] == code) {
usb_keyboard_keys[i] = code;
break;
} else if (empty == -1 && usb_keyboard_keys_prev[i] == 0 && usb_keyboard_keys[i] == 0) {
empty = i;
}
}
if (i == KEYBOARD_REPORT_MAX) {
if (empty != -1) {
usb_keyboard_keys[empty] = code;
}
}
usb_keyboard_add_key(code);
}
}
}
@ -142,20 +128,24 @@ void proc_matrix(void) {
layer_switching(fn_bits);
// TODO: clean code
// when 4 left modifier keys down
// special mode for control, develop and debug
if (keymap_is_special_mode(fn_bits)) {
switch (usb_keyboard_keys[0]) {
switch (usb_keyboard_get_key()) {
case KB_H: // help
print_enable = true;
print("b: jump to bootloader\n");
print("d: debug print toggle\n");
print("x: matrix debug toggle\n");
print("k: keyboard debug toggle\n");
print("m: mouse debug toggle\n");
print("p: print enable toggle\n");
print("d: toggle debug enable\n");
print("x: toggle matrix debug\n");
print("k: toggle keyboard debug\n");
print("m: toggle mouse debug\n");
print("p: toggle print enable\n");
print("v: print version\n");
print("t: print timer count\n");
print("r: print registers\n");
print("s: print status\n");
print("`: toggle protcol(boot/report)\n");
#ifdef NKRO_ENABLE
print("n: toggle NKRO\n");
#endif
print("ESC: power down/wake up\n");
_delay_ms(500);
print_enable = false;
@ -243,13 +233,42 @@ void proc_matrix(void) {
}
_delay_ms(1000);
break;
case KB_R:
case KB_S:
usb_keyboard_clear_report();
usb_keyboard_send();
print("UDCON: "); phex(UDCON); print("\n");
print("UDIEN: "); phex(UDIEN); print("\n");
print("UDINT: "); phex(UDINT); print("\n");
print("usb_keyboard_leds:"); phex(usb_keyboard_leds); print("\n");
print("usb_keyboard_protocol:"); phex(usb_keyboard_protocol); print("\n");
print("usb_keyboard_idle_config:"); phex(usb_keyboard_idle_config); print("\n");
print("usb_keyboard_idle_count:"); phex(usb_keyboard_idle_count); print("\n");
print("mouse_protocol:"); phex(mouse_protocol); print("\n");
if (usb_keyboard_nkro) print("NKRO: enabled\n"); else print("NKRO: disabled\n");
_delay_ms(500);
break;
case KB_GRV:
usb_keyboard_clear_report();
usb_keyboard_send();
usb_keyboard_protocol = !usb_keyboard_protocol;
mouse_protocol = !mouse_protocol;
print("keyboard protcol: ");
if (usb_keyboard_protocol) print("report"); else print("boot");
print("\n");
print("mouse protcol: ");
if (mouse_protocol) print("report"); else print("boot");
print("\n");
_delay_ms(1000);
break;
#ifdef NKRO_ENABLE
case KB_N:
usb_keyboard_clear_report();
usb_keyboard_send();
usb_keyboard_nkro = !usb_keyboard_nkro;
if (usb_keyboard_nkro) print("NKRO: enabled\n"); else print("NKRO: disabled\n");
_delay_ms(1000);
break;
#endif
case KB_ESC:
usb_keyboard_clear_report();
usb_keyboard_send();

10
tmk.c
View file

@ -66,8 +66,7 @@ int main(void)
matrix_init();
matrix_scan();
// bootloader comes up when any 4 or more keys are pressed at startup
if (matrix_key_count() >= 4) {
if (matrix_key_count() >= 3) {
#ifdef DEBUG_LED
for (int i = 0; i < 6; i++) {
DEBUG_LED_CONFIG;
@ -80,6 +79,13 @@ int main(void)
_delay_ms(5000);
#endif
print_enable = true;
debug_enable = true;
debug_matrix = true;
debug_keyboard = true;
debug_mouse = true;
print("debug enabled.\n");
}
if (matrix_key_count() >= 4) {
print("jump to bootloader...\n");
_delay_ms(1000);
jump_bootloader(); // not return

113
usb.c Normal file → Executable file
View file

@ -90,12 +90,12 @@ bool suspend = false;
// 0:control endpoint is enabled automatically by controller.
static const uint8_t PROGMEM endpoint_config_table[] = {
// enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation)
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, // 1
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD_SIZE) | KBD_BUFFER, // 1
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, // 2
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, // 3
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(EXTRA_SIZE) | EXTRA_BUFFER, // 4
#ifdef USB_12KRO
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, // 5
#ifdef NKRO_ENABLE
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD2_SIZE) | KBD2_BUFFER, // 5
#else
0, // 5
#endif
@ -158,16 +158,52 @@ static uint8_t PROGMEM keyboard_hid_report_desc[] = {
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x03, // Output (Constant), ;LED report padding
0x95, 0x06, // Report Count (6),
0x95, KBD_REPORT_KEYS, // Report Count (),
0x75, 0x08, // Report Size (8),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x68, // Logical Maximum(104),
0x25, 0xFF, // Logical Maximum(255),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, 0x68, // Usage Maximum (104),
0x29, 0xFF, // Usage Maximum (255),
0x81, 0x00, // Input (Data, Array),
0xc0 // End Collection
};
#ifdef NKRO_ENABLE
static uint8_t PROGMEM keyboard2_hid_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
0x75, 0x01, // Report Size (1),
0x95, 0x08, // Report Count (8),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0xE0, // Usage Minimum (224),
0x29, 0xE7, // Usage Maximum (231),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
0x95, 0x01, // Report Count (1),
0x75, 0x08, // Report Size (8),
0x81, 0x03, // Input (Constant), ;Reserved byte
0x95, 0x05, // Report Count (5),
0x75, 0x01, // Report Size (1),
0x05, 0x08, // Usage Page (LEDs),
0x19, 0x01, // Usage Minimum (1),
0x29, 0x05, // Usage Maximum (5),
0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x03, // Output (Constant), ;LED report padding
0x95, KBD2_REPORT_KEYS*8, // Report Count (),
0x75, 0x01, // Report Size (1),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum(1),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, KBD2_REPORT_KEYS*8-1, // Usage Maximum (),
0x81, 0x02, // Input (Data, Variable, Absolute),
0xc0 // End Collection
};
#endif
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
// http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
@ -296,17 +332,17 @@ static uint8_t PROGMEM extra_hid_report_desc[] = {
0xc0 // END_COLLECTION
};
#define KEYBOARD_HID_DESC_OFFSET (9+(9+9+7)*0+9)
#define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*1+9)
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)*2+9)
#define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*3+9)
#ifdef USB_12KRO
# define NUM_INTERFACES 5
# define KEYBOARD2_HID_DESC_OFFSET (9+(9+9+7)*4+9)
#define KBD_HID_DESC_OFFSET (9+(9+9+7)*0+9)
#define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*1+9)
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)*2+9)
#define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*3+9)
#ifdef NKRO_ENABLE
# define NUM_INTERFACES 5
# define KBD2_HID_DESC_OFFSET (9+(9+9+7)*4+9)
#else
# define NUM_INTERFACES 4
# define NUM_INTERFACES 4
#endif
#define CONFIG1_DESC_SIZE (9+(9+9+7)*NUM_INTERFACES)
#define CONFIG1_DESC_SIZE (9+(9+9+7)*NUM_INTERFACES)
static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
@ -322,7 +358,7 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
KEYBOARD_INTERFACE, // bInterfaceNumber
KBD_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
@ -341,10 +377,10 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress
KBD_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
KEYBOARD_SIZE, 0, // wMaxPacketSize
1, // bInterval
KBD_SIZE, 0, // wMaxPacketSize
10, // bInterval
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
@ -353,8 +389,13 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
// ThinkPad T23 BIOS doesn't work with boot mouse.
0x00, // bInterfaceSubClass (0x01 = Boot)
0x00, // bInterfaceProtocol (0x02 = Mouse)
/*
0x01, // bInterfaceSubClass (0x01 = Boot)
0x02, // bInterfaceProtocol (0x02 = Mouse)
*/
0, // iInterface
// HID descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
@ -427,11 +468,11 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
EXTRA_SIZE, 0, // wMaxPacketSize
10, // bInterval
#ifdef USB_12KRO
#ifdef NKRO_ENABLE
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
KEYBOARD_INTERFACE2, // bInterfaceNumber
KBD2_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
@ -445,14 +486,14 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(keyboard_hid_report_desc), // wDescriptorLength
sizeof(keyboard2_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
KEYBOARD_ENDPOINT2 | 0x80, // bEndpointAddress
KBD2_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
KEYBOARD_SIZE, 0, // wMaxPacketSize
KBD2_SIZE, 0, // wMaxPacketSize
1, // bInterval
#endif
};
@ -494,17 +535,17 @@ static struct descriptor_list_struct {
// CONFIGURATION descriptor
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
// HID/REPORT descriptors
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
{0x2100, KBD_INTERFACE, config1_descriptor+KBD_HID_DESC_OFFSET, 9},
{0x2200, KBD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
{0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9},
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)},
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9},
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
{0x2100, EXTRA_INTERFACE, config1_descriptor+EXTRA_HID_DESC_OFFSET, 9},
{0x2200, EXTRA_INTERFACE, extra_hid_report_desc, sizeof(extra_hid_report_desc)},
#ifdef USB_12KRO
{0x2100, KEYBOARD_INTERFACE2, config1_descriptor+KEYBOARD2_HID_DESC_OFFSET, 9},
{0x2200, KEYBOARD_INTERFACE2, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
#ifdef NKRO_ENABLE
{0x2100, KBD2_INTERFACE, config1_descriptor+KBD2_HID_DESC_OFFSET, 9},
{0x2200, KBD2_INTERFACE, keyboard2_hid_report_desc, sizeof(keyboard2_hid_report_desc)},
#endif
// STRING descriptors
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
@ -603,7 +644,7 @@ ISR(USB_GEN_vect)
}
}
if (usb_keyboard_idle_config && (++div4 & 3) == 0) {
UENUM = KEYBOARD_ENDPOINT;
UENUM = KBD_ENDPOINT;
if (UEINTX & (1<<RWAL)) {
usb_keyboard_idle_count++;
if (usb_keyboard_idle_count == usb_keyboard_idle_config) {
@ -728,10 +769,12 @@ ISR(USB_COM_vect)
for (i=1; i<=6; i++) {
UENUM = i;
en = pgm_read_byte(cfg++);
UECONX = en;
if (en) {
UECFG0X = pgm_read_byte(cfg++);
UECFG1X = pgm_read_byte(cfg++);
if (en) {
UECONX = (1<<EPEN);
UECFG0X = pgm_read_byte(cfg++);
UECFG1X = pgm_read_byte(cfg++);
} else {
UECONX = 0;
}
}
UERST = 0x7E;
@ -788,7 +831,7 @@ ISR(USB_COM_vect)
return;
}
}
if (wIndex == KEYBOARD_INTERFACE) {
if (wIndex == KBD_INTERFACE) {
if (bmRequestType == 0xA1) {
if (bRequest == HID_GET_REPORT) {
usb_wait_in_ready();

View file

@ -4,11 +4,12 @@
#include "usb_keyboard.h"
#include "print.h"
#include "debug.h"
#include "util.h"
// keyboard report.
static usb_keyboard_report_t _report0 = { {0}, 0 };
static usb_keyboard_report_t _report1 = { {0}, 0 };
static usb_keyboard_report_t _report0 = { {0}, 0, false };
static usb_keyboard_report_t _report1 = { {0}, 0, false };
usb_keyboard_report_t *usb_keyboard_report = &_report0;
usb_keyboard_report_t *usb_keyboard_report_prev = &_report1;
@ -27,75 +28,37 @@ uint8_t usb_keyboard_idle_count=0;
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana
volatile uint8_t usb_keyboard_leds=0;
// enable NKRO
bool usb_keyboard_nkro = false;
int8_t usb_keyboard_send(void)
{
return usb_keyboard_send_report(usb_keyboard_report);
}
static inline int8_t _send_report(usb_keyboard_report_t *report, uint8_t endpoint, uint8_t keys_start, uint8_t keys_end);
int8_t usb_keyboard_send_report(usb_keyboard_report_t *report)
{
uint8_t i, intr_state, timeout;
int8_t result = 0;
if (!usb_configured()) return -1;
intr_state = SREG;
cli();
UENUM = KEYBOARD_ENDPOINT;
timeout = UDFNUML + 50;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// has the USB gone offline?
if (!usb_configured()) return -1;
// have we waited too long?
if (UDFNUML == timeout) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = KEYBOARD_ENDPOINT;
}
UEDATX = report->mods;
UEDATX = 0;
for (i = 0; i < 6; i++) {
UEDATX = report->keys[i];
}
UEINTX = 0x3A;
SREG = intr_state;
#ifdef USB_12KRO
if (!usb_configured()) return -1;
intr_state = SREG;
cli();
UENUM = KEYBOARD_ENDPOINT2;
timeout = UDFNUML + 50;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// has the USB gone offline?
if (!usb_configured()) return -1;
// have we waited too long?
if (UDFNUML == timeout) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = KEYBOARD_ENDPOINT2;
}
UEDATX = report->mods;
UEDATX = 0;
for (i = 6; i < 12; i++) {
UEDATX = report->keys[i];
}
UEINTX = 0x3A;
SREG = intr_state;
#ifdef NKRO_ENABLE
if (usb_keyboard_nkro)
result = _send_report(report, KBD2_ENDPOINT, 0, KBD2_REPORT_KEYS);
else
#endif
{
if (usb_keyboard_protocol)
result = _send_report(report, KBD_ENDPOINT, 0, KBD_REPORT_KEYS);
else
result = _send_report(report, KBD_ENDPOINT, 0, 6);
}
usb_keyboard_idle_count = 0;
report->is_sent =true;
usb_keyboard_print_report(report);
return 0;
if (result) return result;
usb_keyboard_idle_count = 0;
report->is_sent =true;
usb_keyboard_print_report(report);
return 0;
}
void usb_keyboard_swap_report(void) {
@ -111,7 +74,7 @@ void usb_keyboard_clear_report(void) {
}
void usb_keyboard_clear_keys(void) {
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) usb_keyboard_report->keys[i] = 0;
for (int i = 0; i < KEYS_MAX; i++) usb_keyboard_report->keys[i] = 0;
}
void usb_keyboard_clear_mods(void)
@ -119,6 +82,17 @@ void usb_keyboard_clear_mods(void)
usb_keyboard_report->mods = 0;
}
void usb_keyboard_set_keys(uint8_t *keys)
{
for (int i = 0; i < KEYS_MAX; i++)
usb_keyboard_report->keys[i] = keys[i];
}
void usb_keyboard_set_mods(uint8_t mods)
{
usb_keyboard_report->mods = mods;
}
void usb_keyboard_add_code(uint8_t code)
{
if (IS_MOD(code)) {
@ -128,25 +102,17 @@ void usb_keyboard_add_code(uint8_t code)
}
}
static inline void _add_key_byte(uint8_t code);
static inline void _add_key_bit(uint8_t code);
void usb_keyboard_add_key(uint8_t code)
{
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) {
if (!usb_keyboard_report->keys[i]) {
usb_keyboard_report->keys[i] = code;
return;
}
#ifdef NKRO_ENABLE
if (usb_keyboard_nkro) {
_add_key_bit(code);
return;
}
}
void usb_keyboard_set_keys(uint8_t *keys)
{
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++)
usb_keyboard_report->keys[i] = keys[i];
}
void usb_keyboard_set_mods(uint8_t mods)
{
usb_keyboard_report->mods = mods;
#endif
_add_key_byte(code);
}
void usb_keyboard_add_mod(uint8_t code)
@ -165,12 +131,18 @@ void usb_keyboard_del_code(uint8_t code)
void usb_keyboard_del_key(uint8_t code)
{
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) {
#ifdef NKRO_ENABLE
if ((code>>3) < KEYS_MAX) {
usb_keyboard_keys[code>>3] &= ~(1<<(code&7));
}
#else
for (int i = 0; i < KEYS_MAX; i++) {
if (usb_keyboard_report->keys[i] == code) {
usb_keyboard_report->keys[i] = KB_NO;
return;
}
}
#endif
}
void usb_keyboard_del_mod(uint8_t code)
@ -186,7 +158,7 @@ bool usb_keyboard_is_sent(void)
bool usb_keyboard_has_key(void)
{
uint8_t keys = 0;
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) keys |= usb_keyboard_report->keys[i];
for (int i = 0; i < KEYS_MAX; i++) keys |= usb_keyboard_report->keys[i];
return keys ? true : false;
}
@ -195,10 +167,86 @@ bool usb_keyboard_has_mod(void)
return usb_keyboard_report->mods ? true : false;
}
uint8_t usb_keyboard_get_key(void)
{
#ifdef NKRO_ENABLE
if (usb_keyboard_nkro) {
uint8_t i = 0;
for (; i < KEYS_MAX && !usb_keyboard_keys[i]; i++);
return i<<3 | biton(usb_keyboard_keys[i]);
}
#endif
return usb_keyboard_keys[0];
}
void usb_keyboard_print_report(usb_keyboard_report_t *report)
{
if (!debug_keyboard) return;
print("keys: ");
for (int i = 0; i < KEYBOARD_REPORT_MAX; i++) { phex(report->keys[i]); print(" "); }
for (int i = 0; i < KEYS_MAX; i++) { phex(report->keys[i]); print(" "); }
print(" mods: "); phex(report->mods); print("\n");
}
static inline int8_t _send_report(usb_keyboard_report_t *report, uint8_t endpoint, uint8_t keys_start, uint8_t keys_end)
{
uint8_t intr_state, timeout;
if (!usb_configured()) return -1;
intr_state = SREG;
cli();
UENUM = endpoint;
timeout = UDFNUML + 50;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// has the USB gone offline?
if (!usb_configured()) return -1;
// have we waited too long?
if (UDFNUML == timeout) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = endpoint;
}
UEDATX = report->mods;
UEDATX = 0;
for (uint8_t i = keys_start; i < keys_end; i++) {
UEDATX = report->keys[i];
}
UEINTX = 0x3A;
SREG = intr_state;
return 0;
}
static inline void _add_key_byte(uint8_t code)
{
// TODO: fix ugly code
int8_t i = 0;
int8_t empty = -1;
for (; i < KEYS_MAX; i++) {
if (usb_keyboard_keys_prev[i] == code) {
usb_keyboard_keys[i] = code;
break;
}
if (empty == -1 &&
usb_keyboard_keys_prev[i] == 0 &&
usb_keyboard_keys[i] == 0) {
empty = i;
}
}
if (i == KEYS_MAX) {
if (empty != -1) {
usb_keyboard_keys[empty] = code;
}
}
}
static inline void _add_key_bit(uint8_t code)
{
if ((code>>3) < KEYS_MAX) {
usb_keyboard_keys[code>>3] |= 1<<(code&7);
}
}

View file

@ -6,14 +6,26 @@
#include "usb.h"
#define KEYBOARD_INTERFACE 0
#define KEYBOARD_ENDPOINT 1
#ifdef USB_12KRO
#define KEYBOARD_INTERFACE2 4
#define KEYBOARD_ENDPOINT2 5
#define KBD_INTERFACE 0
#define KBD_ENDPOINT 1
#define KBD_SIZE 8
#define KBD_BUFFER EP_DOUBLE_BUFFER
#define KBD_REPORT_KEYS (KBD_SIZE - 2)
// secondary keyboard
#ifdef NKRO_ENABLE
#define KBD2_INTERFACE 4
#define KBD2_ENDPOINT 5
#define KBD2_SIZE 16
#define KBD2_BUFFER EP_DOUBLE_BUFFER
#define KBD2_REPORT_KEYS (KBD2_SIZE - 2)
#endif
#if defined(KBD2_REPORT_KEYS) && KBD2_REPORT_KEYS > KBD_REPORT_KEYS
#define KEYS_MAX KBD2_REPORT_KEYS
#else
#define KEYS_MAX KBD_REPORT_KEYS
#endif
#define KEYBOARD_SIZE 8
#define KEYBOARD_BUFFER EP_DOUBLE_BUFFER
#define BIT_LCTRL (1<<0)
#define BIT_LSHIFT (1<<1)
@ -28,13 +40,8 @@
#define BIT_LSFT BIT_LSHIFT
#define BIT_RSFT BIT_RSHIFT
#ifdef USB_12KRO
# define KEYBOARD_REPORT_MAX 12
#else
# define KEYBOARD_REPORT_MAX 6
#endif
typedef struct report {
uint8_t keys[KEYBOARD_REPORT_MAX];
uint8_t keys[KEYS_MAX];
uint8_t mods;
bool is_sent;
} usb_keyboard_report_t;
@ -52,9 +59,9 @@ extern uint8_t usb_keyboard_protocol;
extern uint8_t usb_keyboard_idle_config;
extern uint8_t usb_keyboard_idle_count;
extern volatile uint8_t usb_keyboard_leds;
extern bool usb_keyboard_nkro;
int8_t usb_keyboard_press(uint8_t key, uint8_t modifier);
int8_t usb_keyboard_send(void);
int8_t usb_keyboard_send_report(usb_keyboard_report_t *report);
@ -64,7 +71,7 @@ void usb_keyboard_clear_report(void);
void usb_keyboard_clear_keys(void);
void usb_keyboard_clear_mods(void);
void usb_keyboard_set_keys(uint8_t keys[6]);
void usb_keyboard_set_keys(uint8_t *keys);
void usb_keyboard_set_mods(uint8_t mods);
void usb_keyboard_add_code(uint8_t code);
@ -79,6 +86,8 @@ bool usb_keyboard_is_sent(void);
bool usb_keyboard_has_key(void);
bool usb_keyboard_has_mod(void);
uint8_t usb_keyboard_get_key(void);
void usb_keyboard_print_report(usb_keyboard_report_t *report);
#endif

View file

@ -59,8 +59,10 @@ int8_t usb_mouse_move(int8_t x, int8_t y, int8_t wheel, int8_t hwheel)
UEDATX = mouse_buttons;
UEDATX = x;
UEDATX = y;
UEDATX = wheel;
UEDATX = hwheel;
if (mouse_protocol) {
UEDATX = wheel;
UEDATX = hwheel;
}
UEINTX = 0x3A;
SREG = intr_state;

2
util.c
View file

@ -1,5 +1,6 @@
#include "util.h"
// bit population
int bitpop(uint8_t bits)
{
int c;
@ -8,6 +9,7 @@ int bitpop(uint8_t bits)
return c;
}
// most significant on-bit
int biton(uint8_t bits)
{
int n = 0;