@@ -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 | |||
@@ -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. | |||
Use PJRC's hid_listen.exe to see debug messages. | |||
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 |
@@ -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 |
@@ -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 |
@@ -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) | |||
* ,-----------------------------------------------------------. |
@@ -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(); |
@@ -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 |
@@ -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(); |
@@ -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; | |||
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; | |||
int8_t result = 0; | |||
#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); | |||
} | |||
} | |||
@@ -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 |
@@ -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; |
@@ -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; |