From 51f17f02317700e64b3c1113fe230d78bac7fecd Mon Sep 17 00:00:00 2001 From: tmk Date: Wed, 8 Dec 2010 01:47:57 +0900 Subject: [PATCH] add build option: NKRO_ENABLE(remove: USB_12KRO) --- Makefile.common | 4 +- README | 109 ++++--------------------- USB_NKRO.txt | 99 +++++++++++++++++++++++ hhkb/Makefile | 5 +- hhkb/keymap.c | 6 +- key_process.c | 71 +++++++++++------ tmk.c | 10 ++- usb.c | 113 ++++++++++++++++++-------- usb_keyboard.c | 208 +++++++++++++++++++++++++++++------------------- usb_keyboard.h | 39 +++++---- usb_mouse.c | 6 +- util.c | 2 + 12 files changed, 413 insertions(+), 259 deletions(-) create mode 100644 USB_NKRO.txt mode change 100644 => 100755 usb.c diff --git a/Makefile.common b/Makefile.common index 7f3f9ae5..d2124243 100644 --- a/Makefile.common +++ b/Makefile.common @@ -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 diff --git a/README b/README index 4c19ddba..57bce575 100644 --- a/README +++ b/README @@ -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 (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 diff --git a/USB_NKRO.txt b/USB_NKRO.txt new file mode 100644 index 00000000..9bd8f704 --- /dev/null +++ b/USB_NKRO.txt @@ -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 diff --git a/hhkb/Makefile b/hhkb/Makefile index c248a675..bf5d75ee 100644 --- a/hhkb/Makefile +++ b/hhkb/Makefile @@ -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 diff --git a/hhkb/keymap.c b/hhkb/keymap.c index 42a830c5..fd9bcce8 100644 --- a/hhkb/keymap.c +++ b/hhkb/keymap.c @@ -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) * ,-----------------------------------------------------------. diff --git a/key_process.c b/key_process.c index c23d1727..bb1bca02 100644 --- a/key_process.c +++ b/key_process.c @@ -1,5 +1,6 @@ #include #include +#include #include #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(); diff --git a/tmk.c b/tmk.c index f7042bd6..b4f76f5d 100644 --- a/tmk.c +++ b/tmk.c @@ -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 diff --git a/usb.c b/usb.c old mode 100644 new mode 100755 index e633b963..215f05de --- a/usb.c +++ b/usb.c @@ -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<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<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<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); + } +} + diff --git a/usb_keyboard.h b/usb_keyboard.h index 872e2afc..88a641f7 100644 --- a/usb_keyboard.h +++ b/usb_keyboard.h @@ -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 diff --git a/usb_mouse.c b/usb_mouse.c index dd5d0b0a..98292bdd 100644 --- a/usb_mouse.c +++ b/usb_mouse.c @@ -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; diff --git a/util.c b/util.c index b02d077c..efc7c148 100644 --- a/util.c +++ b/util.c @@ -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;