Merge remote-tracking branch 'tmk/master'

This commit is contained in:
Mark Sikora 2021-08-05 11:18:22 -04:00
commit ae2234765e
40 changed files with 4259 additions and 434 deletions

View file

@ -69,7 +69,7 @@ OPT_DEFS += -DSUSPEND_MODE_STANDBY
# comment out to disable the options.
#
BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE ?= no # Mouse keys(+4700)
MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700)
EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450)
CONSOLE_ENABLE ?= yes # Console for debug(+400)
COMMAND_ENABLE ?= yes # Commands for debug and configuration
@ -78,6 +78,10 @@ NKRO_ENABLE ?= yes # USB Nkey Rollover
KEYMAP_SECTION_ENABLE ?= yes
UNIMAP_ENABLE ?= yes
# IBMPC Options
IBMPC_SECONDARY ?= no # enable secondary interface
IBMPC_MOUSE_ENABLE ?= no # enable mouse support
# Optimize size but this may cause error "relocation truncated to fit"
#EXTRALDFLAGS = -Wl,--relax
@ -102,6 +106,16 @@ else
endif
ifeq (yes,$(strip $(IBMPC_SECONDARY)))
OPT_DEFS += -DIBMPC_SECONDARY
endif
ifeq (yes,$(strip $(IBMPC_MOUSE_ENABLE)))
OPT_DEFS += -DIBMPC_MOUSE_ENABLE
OPT_DEFS += -DMOUSE_ENABLE
endif
# Search Path
VPATH += $(TARGET_DIR)
VPATH += $(TMK_DIR)

View file

@ -0,0 +1,12 @@
# With two interfaces on PS/2 connector
TARGET ?= ibmpc_usb_x2
MCU = atmega32u2
SRC ?= protocol/ibmpc.cpp \
ibmpc_usb.cpp
COMMAND_ENABLE ?= no # Commands for debug and configuration
IBMPC_SECONDARY ?= yes # enable secondary interface
IBMPC_MOUSE_ENABLE ?= yes # enable mouse support
include Makefile

View file

@ -1,22 +1,23 @@
IBM PC Keyboard Converter
=========================
The converter translates IBM PC keyboard protocols to use classic keyboards with modern computer with USB ports.
It supports both IBM XT and AT protocols, and all of scan code set 1, 2 and 3 with one firmware.
This is not finished project and still work in progress as of 2020-03-02. Test in the field and feedback from users are needed to improve firmware code.
You can discuss about this project here.
https://geekhack.org/index.php?topic=103648.0
The converter translates IBM PC keyboard protocols into USB HID to use classic keyboards on modern computer with USB ports.
This can supports IBM XT and AT protocols and recognize scan code set 1, 2 and 3 with just one firmware.
This project is intended to integrated existent TMK XT, PS/2 and Terminal converters.
This project is intended to integrated existent TMK XT, PS/2 and Terminal keyboard converters.
- IBM XT converter: https://geekhack.org/index.php?topic=94649.0
- PS/2 converter: https://geekhack.org/index.php?topic=14618.0
- IBM Terminal converter: http://geekhack.org/index.php?topic=27272.0
Test in the field and feedback from users are needed to improve firmware code.
Discuss in this thread or on github. https://geekhack.org/index.php?topic=103648.0
You can buy prebuilt TMK converter to support this project here. https://geekhack.org/index.php?topic=72052.0
Keyboard supported
------------------
@ -27,87 +28,46 @@ Keyboard supported
- PC Terminal keyboard of IBM 5271(3270 PC)
- 122-key: 6110344 6110345 1397000
- 102-key: 1390680 1395764 1392595
- PS/2 keyboards(AT+CodeSet2)
- Clones of above models
- IBM 5576-001
- PS/2 keyboards
- Other IBM PC compatible keyboards
Optionally PS/2 mouses can be supported.
- PS/2 mouse
- Default
- Microsoft IntelliMouse
- Microsoft ExplorerMouse
- Logitech PS/2++
Hardware
Firmware
--------
Firmware supports ATMega32u4 and ATMega32u2 by default, Teensy2 or ProMicro can be used.
Wire controller pins below to keyboard signals, besides VCC and GND. This is compatible for Soarer's converter.
- Data PD0
- Clock PD1
- Reset PB6 or PB7 (For some of XT keyboards. Not needed for AT, PS/2 and Terminal)
Pull up resistors of 1-4.7K Ohm on both Data and Clock line are recommended, without them it won't work in some cases.
### Reset
Old Type-1 IBM XT keyboard and some of XT clones need this to reset its controller on startup. Many of IBM XT keyboards available are Type-2 and don't need the reset pin.
See this for Type-1 vs Type-2:
https://vintagecomputer.ca/ibm-pc-model-f-keyboard-type-1-vs-type-2/
As for clones Zenith Z-150 XT and Leading Edge DC-2014 are known to need this.
### Connector pinouts
#### XT
- http://www.kbdbabel.org/conn/kbd_connector_ibmpc.png
- https://allpinouts.org/pinouts/connectors/input_device/keyboard-xt-5-pin/
#### AT
- http://www.kbdbabel.org/conn/kbd_connector_ps2.png
- https://old.pinouts.ru/InputCables/KeyboardPC5_pinout.shtml
#### PS/2
- https://pinouts.ru/InputCables/KeyboardPC6_pinout.shtml
#### Terminal
- http://www.kbdbabel.org/conn/kbd_connector_ibmterm.png
- http://www.kbdbabel.org/conn/kbd_connector_ibm3179_318x_319x.png
Source Code
-----------
https://github.com/tmk/tmk_keyboard/tree/master/converter/ibmpc_usb
Build Firmware
--------------
### Build Firmware
$ cd converter/ibmpc_usb
$ make clean
$ make
$ make -f Makefile.<variant> clean
$ make -f Makefile.<variant>
### Build Options
In Makefiile:
# IBMPC Options
IBMPC_SECONDARY ?= no
IBMPC_MOUSE_ENABLE ?= no
These options bloat firmware size and you may need to disable other options.
- `IBMPC_SECONDARY` - enables secondary interface for converter with PS/2 Mini-DIN-6 connector
- `IBMPC_MOUSE_ENABLE` - enables PS/2 mouse support
Keyboard discrimination
-----------------------
This section explains how the converter determines proper protocol and scan code set for keyboard. The converter need to do that before starting to receive and translate scan codes from keyboard.
### Keymap Editor
You can edit keymap on web browser and download prebuilt firmware here.
### Keyboard ID
After startup the converter sends 0xF2 command to get keyboard ID and sees how the keyboard responds to the command.
Response from keyboard:
- XT keyboard doesn't support any command and returns no response.
- AT keyboard should respond with 0xFA to the command but returns no keyboard ID.
- PS/2 keyboard should respond with 0xFA to the command, followd by keyboard ID, such as 0xAB86.
- Terminal keyboard should respond with 0xFA to the command, followed by keyboard ID, such as 0xBFBF.
Now we can dscriminate the keyboard and determine suitable protocol and scan code set as described below.
### Protocol
- Signals from XT keyboard are recognized by XT protocol.
- Signals from AT, PS/2 and Terminal keyboard are recognized by AT protocol.
### Scan code Set
- Scan codes from XT keyboard are handled as CodeSet1.
- Scan codes from AT and PS/2 keyboard are handled as CodeSet2.
- Scan codes from Terminal keyhboard are handled as CodeSet3.
http://www.tmk-kbd.com/tmk_keyboard/editor/#ibmpc_usb
@ -115,62 +75,74 @@ Debug
-----
Use hid_listen to see debug outputs from the converter.
https://www.pjrc.com/teensy/hid_listen.html
https://github.com/tmk/tmk_keyboard/wiki#debug
Converter Hardware
------------------
This firmware supports ATMega32u4, ATMega32u2 and AT90USB1286 by default, Teensy2/2++ or ProMicro can be used.
Wire microcontroller pins below to keyboard signals, besides VCC and GND. This pin configuration is compatible for Soarer's converter.
Pull up resistors of 1-4.7K Ohm on both Data and Clock line are recommended, without them it won't work in some cases.
- Data PD0
- Clock PD1
- Reset PB6 or PB7 (For some of XT keyboards. Not needed for AT, PS/2 and Terminal)
For optional secondary interface use these pins.
- Data PD2
- Clock PD3
### Reset
Old Type-1 IBM XT keyboard and some of XT clones need Reset pin to starup its controller.
Connect Reset pin to pin3 of DIN-5(180-degree) connector. This should not harm keyboards which don't require reset,
it is safe and recommended to have Reset pin on AT/XT converter.
Zenith Z-150 XT and Leading Edge DC-2014 are also known to need this.
See this for IBM XT Type-1 vs Type-2: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol#type-1-vs-type-2
### Connector pinouts
- DIN: https://en.wikipedia.org/wiki/DIN_connector#Circular_connectors
- Mini-DIN: https://en.wikipedia.org/wiki/Mini-DIN_connector
#### XT - DIN-5(180-degree)
- http://www.kbdbabel.org/conn/kbd_connector_ibmpc.png
- https://allpinouts.org/pinouts/connectors/input_device/keyboard-xt-5-pin/
#### AT - DIN-5(180-degree)
- http://www.kbdbabel.org/conn/kbd_connector_ps2.png
- https://old.pinouts.ru/InputCables/KeyboardPC5_pinout.shtml
#### Terminal - DIN-5(240-degree) or DIN-6
- http://www.kbdbabel.org/conn/kbd_connector_ibmterm.png
- http://www.kbdbabel.org/conn/kbd_connector_ibm3179_318x_319x.png
#### PS/2 - Mini-DIN-6
- https://pinouts.ru/InputCables/KeyboardPC6_pinout.shtml
For secondary interface use pin2 and pin6 for data and clock respectively.
You can use PS/2 Y-splitter cable to access secondary interface.
Scan Code Mapping
-----------------
This is how the converter map keyboard scan code to USB key.
https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-Keyboard-Converter#default-mapping
Resources
---------
IBM PC Keyboard Protocol Resources:
[a] [Microsoft USB HID to PS/2 Translation Table - Scan Code Set 1 and 2](
http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf)
[b] [Microsoft Keyboard Scan Code Specification - Special rules of Scan Code Set 1 and 2](
http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc)
[1] [PS/2 Reference Manuals - Collection of IBM Personal System/2 documents](
http://www.mcamafia.de/pdf/pdfref.htm)
[2] [Keyboard and Auxiliary Device Controller - Signal Timing and Format](
http://www.mcamafia.de/pdf/ibm_hitrc07.pdf)
[3] [Keyboards(101- and 102-key) - Keyboard Layout, Scan Code Set, POR, and Commands](
http://www.mcamafia.de/pdf/ibm_hitrc11.pdf)
[4] [IBM PC XT Keyboard Protocol](
https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol)
[5] [IBM Keyboard Scan Code by John Elliott - 83-key, 84-key, 102-key and 122-key](
https://www.seasip.info/VintagePC/index.html)
[6] [IBM 1391406 Keyboard - Scan Code Set 2 of 102-key PS/2 keyboard](
https://www.seasip.info/VintagePC/ibm_1391406.html)
[7] [The IBM 6110344 Keyboard - Scan Code Set 3 of 122-key terminal keyboard](
https://www.seasip.info/VintagePC/ibm_6110344.html)
[8] [IBM PC AT Technical Reference 1986](
(http://bitsavers.org/pdf/ibm/pc/at/6183355_PC_AT_Technical_Reference_Mar86.pdf)
[y] [TrackPoint Engineering Specifications for version 3E](
https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html)
[z] [Soarer's XT/AT/PS2/Terminal to USB converter](
https://geekhack.org/index.php?topic=17458.0)
TODO
----
### Reset method for rescue
For converter without accesible reset button when magickey combo doesn't work.
Check pin status at powerup:
- if Data and/or Clock are pull down to GND
### Force protocol and scan code set
Keyboard discrimination may fail and you have to configure them by hand.
### Add AT90usb1286 support for Teensy2++
- Source Code: https://github.com/tmk/tmk_keyboard/tree/master/converter/ibmpc_usb
- Discussion: https://geekhack.org/index.php?topic=103648.0
- Conveter impl: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-Keyboard-Converter
- XT Protocol: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol
- AT Protocol: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol
- Scan Code: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#scan-codes
- PS/2 Mouse: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-Mouse

View file

@ -29,8 +29,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/* matrix size */
#define MATRIX_ROWS 16 // keycode bit: 6-3
#define MATRIX_COLS 8 // keycode bit: 2-0
#define MATRIX_ROWS 8
#define MATRIX_COLS 16
/* key combination for command */
@ -53,56 +53,77 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* Pin and interrupt configuration
*/
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32U2__) || defined(__AVR_AT90USB1286__)
/* clock line */
// clock requires External Interrupt pin(INT*)
#define IBMPC_CLOCK_PORT PORTD
#define IBMPC_CLOCK_PIN PIND
#define IBMPC_CLOCK_DDR DDRD
#define IBMPC_CLOCK_BIT 1
/* data line */
#define IBMPC_DATA_PORT PORTD
#define IBMPC_DATA_PIN PIND
#define IBMPC_DATA_DDR DDRD
// primary interface
#define IBMPC_CLOCK_BIT 1
#define IBMPC_DATA_BIT 0
/* reset line */
#define IBMPC_RST_PORT PORTB
#define IBMPC_RST_PIN PINB
#define IBMPC_RST_DDR DDRB
#define IBMPC_RST_BIT1 6
#define IBMPC_RST_BIT2 7
/* reset for XT Type-1 keyboard: low pulse for 500ms */
#define IBMPC_RST_HIZ() do { \
IBMPC_RST_PORT &= ~(1<<IBMPC_RST_BIT1); \
IBMPC_RST_DDR &= ~(1<<IBMPC_RST_BIT1); \
IBMPC_RST_PORT &= ~(1<<IBMPC_RST_BIT2); \
IBMPC_RST_DDR &= ~(1<<IBMPC_RST_BIT2); \
} while (0)
#define IBMPC_RST_LO() do { \
IBMPC_RST_PORT &= ~(1<<IBMPC_RST_BIT1); \
IBMPC_RST_DDR |= (1<<IBMPC_RST_BIT1); \
IBMPC_RST_PORT &= ~(1<<IBMPC_RST_BIT2); \
IBMPC_RST_DDR |= (1<<IBMPC_RST_BIT2); \
} while (0)
/* interrupt for clock line */
#define IBMPC_INT_INIT() do { \
EICRA |= ((1<<ISC11) | \
(0<<ISC10)); \
} while (0)
/* NOTE: clear flag and enabling to ditch unwanted interrupt */
#define IBMPC_INT_ON() do { \
EIFR |= (1<<INTF1); \
EIMSK |= (1<<INT1); \
} while (0)
#define IBMPC_INT_OFF() do { \
EIMSK &= ~(1<<INT1); \
} while (0)
#define IBMPC_INT_VECT INT1_vect
// secondary interface
#ifdef IBMPC_SECONDARY
#define IBMPC_CLOCK_BIT1 3
#define IBMPC_DATA_BIT1 2
#define IBMPC_INT_INIT1() do { \
EICRA |= ((1<<ISC31) | \
(0<<ISC30)); \
} while (0)
#define IBMPC_INT_ON1() do { \
EIFR |= (1<<INTF3); \
EIMSK |= (1<<INT3); \
} while (0)
#define IBMPC_INT_OFF1() do { \
EIMSK &= ~(1<<INT3); \
} while (0)
#define IBMPC_INT_VECT1 INT3_vect
#endif
/* reset line */
#define IBMPC_RST_PORT PORTB
#define IBMPC_RST_PIN PINB
#define IBMPC_RST_DDR DDRB
#define IBMPC_RST_BIT0 6
#define IBMPC_RST_BIT1 7
/* reset for XT Type-1 keyboard: low pulse for 500ms */
#define IBMPC_RST_HIZ() do { \
IBMPC_RST_PORT &= ~(1<<IBMPC_RST_BIT0); \
IBMPC_RST_DDR &= ~(1<<IBMPC_RST_BIT0); \
IBMPC_RST_PORT &= ~(1<<IBMPC_RST_BIT1); \
IBMPC_RST_DDR &= ~(1<<IBMPC_RST_BIT1); \
} while (0)
#define IBMPC_RST_LO() do { \
IBMPC_RST_PORT &= ~(1<<IBMPC_RST_BIT0); \
IBMPC_RST_DDR |= (1<<IBMPC_RST_BIT0); \
IBMPC_RST_PORT &= ~(1<<IBMPC_RST_BIT1); \
IBMPC_RST_DDR |= (1<<IBMPC_RST_BIT1); \
} while (0)
// for debug
#define LED_ON() do { DDRD |= (1<<6); PORTD |= (1<<6); } while (0)
#define LED_OFF() do { DDRD |= (1<<6); PORTD &= ~(1<<6); } while (0)
#else
#error "No pin configuration in config.h"
#endif

View file

@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdint.h>
#include <stdbool.h>
#include <avr/pgmspace.h>
#include "print.h"
#include "util.h"
#include "debug.h"
@ -26,6 +27,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "matrix.h"
#include "timer.h"
#include "action.h"
#include "unimap.h"
#include "unimap_trans.h"
#include "ibmpc_usb.h"
#include "ibmpc.h"
@ -38,9 +41,9 @@ static int8_t process_cs2(uint8_t code);
static int8_t process_cs3(uint8_t code);
static uint8_t matrix[MATRIX_ROWS];
#define ROW(code) ((code>>3)&0x0F)
#define COL(code) (code&0x07)
static matrix_row_t matrix[MATRIX_ROWS];
#define ROW(code) ((code>>4)&0x07)
#define COL(code) (code&0x0F)
static int16_t read_wait(uint16_t wait_ms)
{
@ -131,6 +134,7 @@ uint8_t matrix_scan(void)
READ_ID,
SETUP,
LOOP,
ERROR,
} state = INIT;
static uint16_t init_time;
@ -152,7 +156,7 @@ uint8_t matrix_scan(void)
// keyboard init again
if (state == LOOP) {
xprintf("[RST] ");
state = INIT;
state = ERROR;
}
}
@ -172,7 +176,7 @@ uint8_t matrix_scan(void)
((current_protocol&IBMPC_PROTOCOL_AT) && (ibmpc_protocol&IBMPC_PROTOCOL_XT))) {
if (state == LOOP) {
xprintf("[CHG] ");
state = INIT;
state = ERROR;
}
}
@ -188,7 +192,6 @@ uint8_t matrix_scan(void)
current_protocol = 0;
matrix_clear();
clear_keyboard();
init_time = timer_read();
state = WAIT_SETTLE;
@ -473,13 +476,13 @@ MOUSE_DONE:
switch (keyboard_kind) {
case PC_XT:
if (process_cs1(code) == -1) state = INIT;
if (process_cs1(code) == -1) state = ERROR;
break;
case PC_AT:
if (process_cs2(code) == -1) state = INIT;
if (process_cs2(code) == -1) state = ERROR;
break;
case PC_TERMINAL:
if (process_cs3(code) == -1) state = INIT;
if (process_cs3(code) == -1) state = ERROR;
break;
#ifdef IBMPC_MOUSE_ENABLE
case PC_MOUSE: {
@ -493,9 +496,9 @@ MOUSE_DONE:
b0 = code;
b1 = ibmpc_host_recv_response();
if (b1 == -1) break;
if (b1 == -1) { state = ERROR; break; }
b2 = ibmpc_host_recv_response();
if (b2 == -1) break;
if (b2 == -1) { state = ERROR; break; }
switch (mouse_id) {
case MOUSE_DEFAULT:
@ -593,6 +596,11 @@ MOUSE_DONE:
}
}
break;
case ERROR:
// something goes wrong
clear_keyboard();
state = INIT;
break;
default:
break;
}
@ -606,7 +614,7 @@ bool matrix_is_on(uint8_t row, uint8_t col)
}
inline
uint8_t matrix_get_row(uint8_t row)
matrix_row_t matrix_get_row(uint8_t row)
{
return matrix[row];
}
@ -620,20 +628,44 @@ uint8_t matrix_key_count(void)
return count;
}
extern const action_t actionmaps[][UNIMAP_ROWS][UNIMAP_COLS];
action_t action_for_key(uint8_t layer, keypos_t key)
{
return (action_t){ .code = pgm_read_word(&actionmaps[(layer)][key.row & 0x07][key.col & 0x0F]) };
}
static uint8_t to_unimap(uint8_t code) {
uint8_t row = ROW(code);
uint8_t col = COL(code);
switch (keyboard_kind) {
case PC_XT:
return pgm_read_byte(&unimap_cs1[row][col]);
case PC_AT:
return pgm_read_byte(&unimap_cs2[row][col]);
case PC_TERMINAL:
return pgm_read_byte(&unimap_cs3[row][col]);
default:
return UNIMAP_NO;
}
}
inline
static void matrix_make(uint8_t code)
{
if (!matrix_is_on(ROW(code), COL(code))) {
matrix[ROW(code)] |= 1<<COL(code);
uint8_t u = to_unimap(code);
if (u > 0x7F) return;
if (!matrix_is_on(ROW(u), COL(u))) {
matrix[ROW(u)] |= 1<<COL(u);
}
}
inline
static void matrix_break(uint8_t code)
{
if (matrix_is_on(ROW(code), COL(code))) {
matrix[ROW(code)] &= ~(1<<COL(code));
uint8_t u = to_unimap(code);
if (u > 0x7F) return;
if (matrix_is_on(ROW(u), COL(u))) {
matrix[ROW(u)] &= ~(1<<COL(u));
}
}

File diff suppressed because it is too large Load diff

View file

@ -9,8 +9,4 @@ typedef enum { NONE, PC_XT, PC_AT, PC_TERMINAL, PC_MOUSE } keyboard_kind_t;
kind == PC_MOUSE ? "MOUSE" : \
"NONE")
extern uint16_t keyboard_id;
extern keyboard_kind_t keyboard_kind;
#endif

View file

@ -0,0 +1,164 @@
#ifndef IBMPC_USB_HPP
#define IBMPC_USB_HPP
#include <avr/pgmspace.h>
#include "matrix.h"
#include "unimap_trans.h"
#include "ibmpc_usb.h"
#define ID_STR(id) (id == 0xFFFE ? "_????" : \
(id == 0xFFFD ? "_Z150" : \
(id == 0x0000 ? "_AT84" : \
"")))
#define ROW(code) ((code>>4)&0x07)
#define COL(code) (code&0x0F)
class IBMPCConverter {
public:
static matrix_row_t matrix[MATRIX_ROWS];
IBMPC &ibmpc;
IBMPCConverter(IBMPC &_ibmpc) : ibmpc(_ibmpc), keyboard_id(0), keyboard_kind(NONE), current_protocol(0) {
matrix_clear();
}
void init(void) {
ibmpc.host_init();
}
uint8_t process_interface(void);
void set_led(uint8_t usb_led);
static inline void matrix_clear(void) {
for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
}
static inline matrix_row_t matrix_get_row(uint8_t row) {
return matrix[row];
}
private:
uint16_t keyboard_id = 0x0000;
keyboard_kind_t keyboard_kind = NONE;
uint8_t current_protocol = 0;
uint16_t init_time;
enum Converter_state {
INIT,
WAIT_SETTLE,
AT_RESET,
XT_RESET,
XT_RESET_WAIT,
XT_RESET_DONE,
WAIT_AA,
WAIT_AABF,
WAIT_AABFBF,
READ_ID,
SETUP,
LOOP,
ERROR,
} state = INIT;
enum CS1_state {
CS1_INIT,
CS1_E0,
// Pause: E1 1D 45, E1 9D C5 [a]
CS1_E1,
CS1_E1_1D,
CS1_E1_9D,
} state_cs1 = CS1_INIT;
enum CS2_state {
CS2_INIT,
CS2_F0,
CS2_E0,
CS2_E0_F0,
// Pause
CS2_E1,
CS2_E1_14,
CS2_E1_F0,
CS2_E1_F0_14,
CS2_E1_F0_14_F0,
} state_cs2 = CS2_INIT;
enum CS3_state {
CS3_READY,
CS3_F0,
#ifdef G80_2551_SUPPORT
// G80-2551 four extra keys around cursor keys
CS3_G80,
CS3_G80_F0,
#endif
} state_cs3 = CS3_READY;
int8_t process_cs1(uint8_t code);
int8_t process_cs2(uint8_t code);
int8_t process_cs3(uint8_t code);
uint8_t cs1_e0code(uint8_t code);
uint8_t cs2_e0code(uint8_t code);
uint8_t translate_5576_cs2(uint8_t code);
uint8_t translate_5576_cs2_e0(uint8_t code);
uint8_t translate_5576_cs3(uint8_t code);
int16_t read_wait(uint16_t wait_ms);
uint16_t read_keyboard_id(void);
// translate to Unimap before storing in matrix
inline void matrix_make(uint8_t code) {
uint8_t u = to_unimap(code);
if (u > 0x7F) return;
if (!matrix_is_on(ROW(u), COL(u))) {
matrix[ROW(u)] |= 1<<COL(u);
}
}
inline void matrix_break(uint8_t code) {
uint8_t u = to_unimap(code);
if (u > 0x7F) return;
if (matrix_is_on(ROW(u), COL(u))) {
matrix[ROW(u)] &= ~(1<<COL(u));
}
}
uint8_t to_unimap(uint8_t code) {
uint8_t row = ROW(code);
uint8_t col = COL(code);
switch (keyboard_kind) {
case PC_XT:
return pgm_read_byte(&unimap_cs1[row][col]);
case PC_AT:
return pgm_read_byte(&unimap_cs2[row][col]);
case PC_TERMINAL:
return pgm_read_byte(&unimap_cs3[row][col]);
default:
return UNIMAP_NO;
}
}
#ifdef IBMPC_MOUSE_ENABLE
enum {
MOUSE_DEFAULT = 0, // Default three-button
MOUSE_INTELLI = 3, // Intellimouse Explorer 3-button & wheel
MOUSE_EXPLORER = 4, // Intellimouse Explorer 5-button & wheel
MOUSE_LOGITECH = 9 // Logitech PS/2++
} mouse_id = MOUSE_DEFAULT;
uint8_t mouse_btn = 0;
void mouse_read_status(uint8_t *s) {
ibmpc.host_send(0xE9);
s[0] = ibmpc.host_recv_response();
s[1] = ibmpc.host_recv_response();
s[2] = ibmpc.host_recv_response();
xprintf("S[%02X %02X %02X] ", s[0], s[1], s[2]);
}
#endif
};
matrix_row_t IBMPCConverter::matrix[MATRIX_ROWS];
#endif

View file

@ -14,7 +14,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "unimap_trans.h"
#include "unimap.h"
#define AC_FN0 ACTION_LAYER_TAP_KEY(1, KC_APPLICATION)

View file

@ -17,12 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef UNIMAP_TRANS_H
#define UNIMAP_TRANS_H
#include <stdint.h>
#include <avr/pgmspace.h>
#include "unimap.h"
#include "action.h"
#include "ibmpc_usb.h"
/*
@ -91,22 +87,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* Unsupported codes or error -> 00. UNIMAP_NUBS is unused.
*/
const uint8_t PROGMEM unimap_cs1[MATRIX_ROWS][MATRIX_COLS] = {
{ UNIMAP_NO, UNIMAP_ESC, UNIMAP_1, UNIMAP_2, UNIMAP_3, UNIMAP_4, UNIMAP_5, UNIMAP_6 }, /* 00-07 */
{ UNIMAP_7, UNIMAP_8, UNIMAP_9, UNIMAP_0, UNIMAP_MINUS, UNIMAP_EQUAL, UNIMAP_BSPACE,UNIMAP_TAB }, /* 08-0F */
{ UNIMAP_Q, UNIMAP_W, UNIMAP_E, UNIMAP_R, UNIMAP_T, UNIMAP_Y, UNIMAP_U, UNIMAP_I }, /* 10-17 */
{ UNIMAP_O, UNIMAP_P, UNIMAP_LBRC, UNIMAP_RBRC, UNIMAP_ENTER, UNIMAP_LCTL, UNIMAP_A, UNIMAP_S, }, /* 18-1F */
{ UNIMAP_D, UNIMAP_F, UNIMAP_G, UNIMAP_H, UNIMAP_J, UNIMAP_K, UNIMAP_L, UNIMAP_SCLN }, /* 20-27 */
{ UNIMAP_QUOTE, UNIMAP_GRAVE, UNIMAP_LSHIFT,UNIMAP_BSLASH,UNIMAP_Z, UNIMAP_X, UNIMAP_C, UNIMAP_V, }, /* 28-2F */
{ UNIMAP_B, UNIMAP_N, UNIMAP_M, UNIMAP_COMMA, UNIMAP_DOT, UNIMAP_SLASH, UNIMAP_RSHIFT,UNIMAP_PAST }, /* 30-37 */
{ UNIMAP_LALT, UNIMAP_SPACE, UNIMAP_CAPS, UNIMAP_F1, UNIMAP_F2, UNIMAP_F3, UNIMAP_F4, UNIMAP_F5 }, /* 38-3F */
{ UNIMAP_F6, UNIMAP_F7, UNIMAP_F8, UNIMAP_F9, UNIMAP_F10, UNIMAP_NLCK, UNIMAP_SLCK, UNIMAP_P7 }, /* 40-47 */
{ UNIMAP_P8, UNIMAP_P9, UNIMAP_PMNS, UNIMAP_P4, UNIMAP_P5, UNIMAP_P6, UNIMAP_PPLS, UNIMAP_P1 }, /* 48-4F */
{ UNIMAP_P2, UNIMAP_P3, UNIMAP_P0, UNIMAP_PDOT, UNIMAP_PSCR, UNIMAP_PAUSE, UNIMAP_NUHS, UNIMAP_F11 }, /* 50-57 */
{ UNIMAP_F12, UNIMAP_PEQL, UNIMAP_LGUI, UNIMAP_RGUI, UNIMAP_APP, UNIMAP_MUTE, UNIMAP_VOLD, UNIMAP_VOLU }, /* 58-5F */
{ UNIMAP_UP, UNIMAP_LEFT, UNIMAP_DOWN, UNIMAP_RIGHT, UNIMAP_F13, UNIMAP_F14, UNIMAP_F15, UNIMAP_F16 }, /* 60-67 */
{ UNIMAP_F17, UNIMAP_F18, UNIMAP_F19, UNIMAP_F20, UNIMAP_F21, UNIMAP_F22, UNIMAP_F23, UNIMAP_PENT }, /* 68-6F */
{ UNIMAP_KANA, UNIMAP_INSERT,UNIMAP_DELETE,UNIMAP_RO, UNIMAP_HOME, UNIMAP_END, UNIMAP_F24, UNIMAP_PGUP }, /* 70-77 */
{ UNIMAP_PGDN, UNIMAP_HENK, UNIMAP_RCTL, UNIMAP_MHEN, UNIMAP_RALT, UNIMAP_JYEN, UNIMAP_PCMM, UNIMAP_PSLS }, /* 78-7F */
{ UNIMAP_NO, UNIMAP_ESC, UNIMAP_1, UNIMAP_2, UNIMAP_3, UNIMAP_4, UNIMAP_5, UNIMAP_6, /* 00-07 */
UNIMAP_7, UNIMAP_8, UNIMAP_9, UNIMAP_0, UNIMAP_MINUS, UNIMAP_EQUAL, UNIMAP_BSPACE,UNIMAP_TAB }, /* 08-0F */
{ UNIMAP_Q, UNIMAP_W, UNIMAP_E, UNIMAP_R, UNIMAP_T, UNIMAP_Y, UNIMAP_U, UNIMAP_I, /* 10-17 */
UNIMAP_O, UNIMAP_P, UNIMAP_LBRC, UNIMAP_RBRC, UNIMAP_ENTER, UNIMAP_LCTL, UNIMAP_A, UNIMAP_S, }, /* 18-1F */
{ UNIMAP_D, UNIMAP_F, UNIMAP_G, UNIMAP_H, UNIMAP_J, UNIMAP_K, UNIMAP_L, UNIMAP_SCLN, /* 20-27 */
UNIMAP_QUOTE, UNIMAP_GRAVE, UNIMAP_LSHIFT,UNIMAP_BSLASH,UNIMAP_Z, UNIMAP_X, UNIMAP_C, UNIMAP_V, }, /* 28-2F */
{ UNIMAP_B, UNIMAP_N, UNIMAP_M, UNIMAP_COMMA, UNIMAP_DOT, UNIMAP_SLASH, UNIMAP_RSHIFT,UNIMAP_PAST, /* 30-37 */
UNIMAP_LALT, UNIMAP_SPACE, UNIMAP_CAPS, UNIMAP_F1, UNIMAP_F2, UNIMAP_F3, UNIMAP_F4, UNIMAP_F5 }, /* 38-3F */
{ UNIMAP_F6, UNIMAP_F7, UNIMAP_F8, UNIMAP_F9, UNIMAP_F10, UNIMAP_NLCK, UNIMAP_SLCK, UNIMAP_P7, /* 40-47 */
UNIMAP_P8, UNIMAP_P9, UNIMAP_PMNS, UNIMAP_P4, UNIMAP_P5, UNIMAP_P6, UNIMAP_PPLS, UNIMAP_P1 }, /* 48-4F */
{ UNIMAP_P2, UNIMAP_P3, UNIMAP_P0, UNIMAP_PDOT, UNIMAP_PSCR, UNIMAP_PAUSE, UNIMAP_NUHS, UNIMAP_F11, /* 50-57 */
UNIMAP_F12, UNIMAP_PEQL, UNIMAP_LGUI, UNIMAP_RGUI, UNIMAP_APP, UNIMAP_MUTE, UNIMAP_VOLD, UNIMAP_VOLU }, /* 58-5F */
{ UNIMAP_UP, UNIMAP_LEFT, UNIMAP_DOWN, UNIMAP_RIGHT, UNIMAP_F13, UNIMAP_F14, UNIMAP_F15, UNIMAP_F16, /* 60-67 */
UNIMAP_F17, UNIMAP_F18, UNIMAP_F19, UNIMAP_F20, UNIMAP_F21, UNIMAP_F22, UNIMAP_F23, UNIMAP_PENT }, /* 68-6F */
{ UNIMAP_KANA, UNIMAP_INSERT,UNIMAP_DELETE,UNIMAP_RO, UNIMAP_HOME, UNIMAP_END, UNIMAP_F24, UNIMAP_PGUP, /* 70-77 */
UNIMAP_PGDN, UNIMAP_HENK, UNIMAP_RCTL, UNIMAP_MHEN, UNIMAP_RALT, UNIMAP_JYEN, UNIMAP_PCMM, UNIMAP_PSLS }, /* 78-7F */
};
@ -151,22 +147,22 @@ const uint8_t PROGMEM unimap_cs1[MATRIX_ROWS][MATRIX_COLS] = {
* 51, 63, 68, 6A, 6D: Hidden keys in IBM model M [6]
*/
const uint8_t PROGMEM unimap_cs2[MATRIX_ROWS][MATRIX_COLS] = {
{ UNIMAP_PAUS, UNIMAP_F9, UNIMAP_F7, UNIMAP_F5, UNIMAP_F3, UNIMAP_F1, UNIMAP_F2, UNIMAP_F12 }, /* 00-07 */
{ UNIMAP_F13, UNIMAP_F10, UNIMAP_F8, UNIMAP_F6, UNIMAP_F4, UNIMAP_TAB, UNIMAP_GRV, UNIMAP_RALT }, /* 08-0F */
{ UNIMAP_F14, UNIMAP_LALT, UNIMAP_LSHIFT,UNIMAP_KANA, UNIMAP_LCTL, UNIMAP_Q, UNIMAP_1, UNIMAP_RCTL }, /* 10-17 */
{ UNIMAP_F15, UNIMAP_LGUI, UNIMAP_Z, UNIMAP_S, UNIMAP_A, UNIMAP_W, UNIMAP_2, UNIMAP_RGUI }, /* 18-1F */
{ UNIMAP_F16, UNIMAP_C, UNIMAP_X, UNIMAP_D, UNIMAP_E, UNIMAP_4, UNIMAP_3, UNIMAP_END }, /* 20-27 */
{ UNIMAP_F17, UNIMAP_SPACE, UNIMAP_V, UNIMAP_F, UNIMAP_T, UNIMAP_R, UNIMAP_5, UNIMAP_HOME }, /* 28-2F */
{ UNIMAP_F18, UNIMAP_N, UNIMAP_B, UNIMAP_H, UNIMAP_G, UNIMAP_Y, UNIMAP_6, UNIMAP_DEL }, /* 30-37 */
{ UNIMAP_F19, UNIMAP_INS, UNIMAP_M, UNIMAP_J, UNIMAP_U, UNIMAP_7, UNIMAP_8, UNIMAP_DOWN }, /* 38-3F */
{ UNIMAP_F20, UNIMAP_COMMA, UNIMAP_K, UNIMAP_I, UNIMAP_O, UNIMAP_0, UNIMAP_9, UNIMAP_RIGHT }, /* 40-47 */
{ UNIMAP_F21, UNIMAP_DOT, UNIMAP_SLASH, UNIMAP_L, UNIMAP_SCOLON,UNIMAP_P, UNIMAP_MINUS, UNIMAP_UP }, /* 48-4F */
{ UNIMAP_F22, UNIMAP_RO, UNIMAP_QUOTE, UNIMAP_LEFT, UNIMAP_LBRC, UNIMAP_EQUAL, UNIMAP_PGDN, UNIMAP_F23 }, /* 50-57 */
{ UNIMAP_CAPS, UNIMAP_RSHIFT,UNIMAP_ENTER, UNIMAP_RBRC, UNIMAP_APP, UNIMAP_BSLASH,UNIMAP_PGUP, UNIMAP_F24 }, /* 58-5F */
{ UNIMAP_PSLS, UNIMAP_NUBS, UNIMAP_PENT, UNIMAP_PEQL, UNIMAP_HENK, UNIMAP_VOLD, UNIMAP_BSPACE,UNIMAP_MHEN }, /* 60-67 */
{ UNIMAP_NUHS, UNIMAP_P1, UNIMAP_JYEN, UNIMAP_P4, UNIMAP_P7, UNIMAP_PCMM, UNIMAP_VOLU, UNIMAP_MUTE }, /* 68-6F */
{ UNIMAP_P0, UNIMAP_PDOT, UNIMAP_P2, UNIMAP_P5, UNIMAP_P6, UNIMAP_P8, UNIMAP_ESC, UNIMAP_NLCK }, /* 70-77 */
{ UNIMAP_F11, UNIMAP_PPLS, UNIMAP_P3, UNIMAP_PMNS, UNIMAP_PAST, UNIMAP_P9, UNIMAP_SLCK, UNIMAP_PSCR }, /* 78-7F */
{ UNIMAP_PAUS, UNIMAP_F9, UNIMAP_F7, UNIMAP_F5, UNIMAP_F3, UNIMAP_F1, UNIMAP_F2, UNIMAP_F12, /* 00-07 */
UNIMAP_F13, UNIMAP_F10, UNIMAP_F8, UNIMAP_F6, UNIMAP_F4, UNIMAP_TAB, UNIMAP_GRV, UNIMAP_RALT }, /* 08-0F */
{ UNIMAP_F14, UNIMAP_LALT, UNIMAP_LSHIFT,UNIMAP_KANA, UNIMAP_LCTL, UNIMAP_Q, UNIMAP_1, UNIMAP_RCTL, /* 10-17 */
UNIMAP_F15, UNIMAP_LGUI, UNIMAP_Z, UNIMAP_S, UNIMAP_A, UNIMAP_W, UNIMAP_2, UNIMAP_RGUI }, /* 18-1F */
{ UNIMAP_F16, UNIMAP_C, UNIMAP_X, UNIMAP_D, UNIMAP_E, UNIMAP_4, UNIMAP_3, UNIMAP_END, /* 20-27 */
UNIMAP_F17, UNIMAP_SPACE, UNIMAP_V, UNIMAP_F, UNIMAP_T, UNIMAP_R, UNIMAP_5, UNIMAP_HOME }, /* 28-2F */
{ UNIMAP_F18, UNIMAP_N, UNIMAP_B, UNIMAP_H, UNIMAP_G, UNIMAP_Y, UNIMAP_6, UNIMAP_DEL, /* 30-37 */
UNIMAP_F19, UNIMAP_INS, UNIMAP_M, UNIMAP_J, UNIMAP_U, UNIMAP_7, UNIMAP_8, UNIMAP_DOWN }, /* 38-3F */
{ UNIMAP_F20, UNIMAP_COMMA, UNIMAP_K, UNIMAP_I, UNIMAP_O, UNIMAP_0, UNIMAP_9, UNIMAP_RIGHT, /* 40-47 */
UNIMAP_F21, UNIMAP_DOT, UNIMAP_SLASH, UNIMAP_L, UNIMAP_SCOLON,UNIMAP_P, UNIMAP_MINUS, UNIMAP_UP }, /* 48-4F */
{ UNIMAP_F22, UNIMAP_RO, UNIMAP_QUOTE, UNIMAP_LEFT, UNIMAP_LBRC, UNIMAP_EQUAL, UNIMAP_PGDN, UNIMAP_F23, /* 50-57 */
UNIMAP_CAPS, UNIMAP_RSHIFT,UNIMAP_ENTER, UNIMAP_RBRC, UNIMAP_APP, UNIMAP_BSLASH,UNIMAP_PGUP, UNIMAP_F24 }, /* 58-5F */
{ UNIMAP_PSLS, UNIMAP_NUBS, UNIMAP_PENT, UNIMAP_PEQL, UNIMAP_HENK, UNIMAP_VOLD, UNIMAP_BSPACE,UNIMAP_MHEN, /* 60-67 */
UNIMAP_NUHS, UNIMAP_P1, UNIMAP_JYEN, UNIMAP_P4, UNIMAP_P7, UNIMAP_PCMM, UNIMAP_VOLU, UNIMAP_MUTE }, /* 68-6F */
{ UNIMAP_P0, UNIMAP_PDOT, UNIMAP_P2, UNIMAP_P5, UNIMAP_P6, UNIMAP_P8, UNIMAP_ESC, UNIMAP_NLCK, /* 70-77 */
UNIMAP_F11, UNIMAP_PPLS, UNIMAP_P3, UNIMAP_PMNS, UNIMAP_PAST, UNIMAP_P9, UNIMAP_SLCK, UNIMAP_PSCR }, /* 78-7F */
};
@ -210,45 +206,22 @@ const uint8_t PROGMEM unimap_cs2[MATRIX_ROWS][MATRIX_COLS] = {
* 51, 5C, 5D, 68, 78: Hidden keys in IBM 122-key terminal keyboard [7]
*/
const uint8_t PROGMEM unimap_cs3[MATRIX_ROWS][MATRIX_COLS] = {
{ UNIMAP_KANA, UNIMAP_LGUI, UNIMAP_PSCR, UNIMAP_VOLD, UNIMAP_VOLU, UNIMAP_MUTE, UNIMAP_HENK, UNIMAP_F1 }, /* 00-07 */
{ UNIMAP_F13, UNIMAP_RGUI, UNIMAP_APP, UNIMAP_MHEN, UNIMAP_PAUS, UNIMAP_TAB, UNIMAP_GRV, UNIMAP_F2 }, /* 08-0F */
{ UNIMAP_F14, UNIMAP_LCTL, UNIMAP_LSHIFT,UNIMAP_NUBS, UNIMAP_CAPS, UNIMAP_Q, UNIMAP_1, UNIMAP_F3 }, /* 10-17 */
{ UNIMAP_F15, UNIMAP_LALT, UNIMAP_Z, UNIMAP_S, UNIMAP_A, UNIMAP_W, UNIMAP_2, UNIMAP_F4 }, /* 18-1F */
{ UNIMAP_F16, UNIMAP_C, UNIMAP_X, UNIMAP_D, UNIMAP_E, UNIMAP_4, UNIMAP_3, UNIMAP_F5 }, /* 20-27 */
{ UNIMAP_F17, UNIMAP_SPACE, UNIMAP_V, UNIMAP_F, UNIMAP_T, UNIMAP_R, UNIMAP_5, UNIMAP_F6 }, /* 28-2F */
{ UNIMAP_F18, UNIMAP_N, UNIMAP_B, UNIMAP_H, UNIMAP_G, UNIMAP_Y, UNIMAP_6, UNIMAP_F7 }, /* 30-37 */
{ UNIMAP_F19, UNIMAP_RALT, UNIMAP_M, UNIMAP_J, UNIMAP_U, UNIMAP_7, UNIMAP_8, UNIMAP_F8 }, /* 38-3F */
{ UNIMAP_F20, UNIMAP_COMMA, UNIMAP_K, UNIMAP_I, UNIMAP_O, UNIMAP_0, UNIMAP_9, UNIMAP_F9 }, /* 40-47 */
{ UNIMAP_F21, UNIMAP_DOT, UNIMAP_SLASH, UNIMAP_L, UNIMAP_SCOLON,UNIMAP_P, UNIMAP_MINUS, UNIMAP_F10 }, /* 48-4F */
{ UNIMAP_F22, UNIMAP_RO, UNIMAP_QUOTE, UNIMAP_NUHS, UNIMAP_LBRC, UNIMAP_EQUAL, UNIMAP_F11, UNIMAP_F23 }, /* 50-57 */
{ UNIMAP_RCTL, UNIMAP_RSHIFT,UNIMAP_ENTER, UNIMAP_RBRC, UNIMAP_BSLASH,UNIMAP_JYEN, UNIMAP_F12, UNIMAP_F24 }, /* 58-5F */
{ UNIMAP_DOWN, UNIMAP_LEFT, UNIMAP_HOME, UNIMAP_UP, UNIMAP_END, UNIMAP_INS, UNIMAP_BSPACE,UNIMAP_PSLS }, /* 60-67 */
{ UNIMAP_PCMM, UNIMAP_P1, UNIMAP_RIGHT, UNIMAP_P4, UNIMAP_P7, UNIMAP_DEL, UNIMAP_PGUP, UNIMAP_PGDN }, /* 68-6F */
{ UNIMAP_P0, UNIMAP_PDOT, UNIMAP_P2, UNIMAP_P5, UNIMAP_P6, UNIMAP_P8, UNIMAP_ESC, UNIMAP_NLCK }, /* 70-77 */
{ UNIMAP_PEQL, UNIMAP_PENT, UNIMAP_P3, UNIMAP_PMNS, UNIMAP_PPLS, UNIMAP_P9, UNIMAP_SLCK, UNIMAP_PAST }, /* 78-7F */
{ UNIMAP_KANA, UNIMAP_LGUI, UNIMAP_PSCR, UNIMAP_VOLD, UNIMAP_VOLU, UNIMAP_MUTE, UNIMAP_HENK, UNIMAP_F1, /* 00-07 */
UNIMAP_F13, UNIMAP_RGUI, UNIMAP_APP, UNIMAP_MHEN, UNIMAP_PAUS, UNIMAP_TAB, UNIMAP_GRV, UNIMAP_F2 }, /* 08-0F */
{ UNIMAP_F14, UNIMAP_LCTL, UNIMAP_LSHIFT,UNIMAP_NUBS, UNIMAP_CAPS, UNIMAP_Q, UNIMAP_1, UNIMAP_F3, /* 10-17 */
UNIMAP_F15, UNIMAP_LALT, UNIMAP_Z, UNIMAP_S, UNIMAP_A, UNIMAP_W, UNIMAP_2, UNIMAP_F4 }, /* 18-1F */
{ UNIMAP_F16, UNIMAP_C, UNIMAP_X, UNIMAP_D, UNIMAP_E, UNIMAP_4, UNIMAP_3, UNIMAP_F5, /* 20-27 */
UNIMAP_F17, UNIMAP_SPACE, UNIMAP_V, UNIMAP_F, UNIMAP_T, UNIMAP_R, UNIMAP_5, UNIMAP_F6 }, /* 28-2F */
{ UNIMAP_F18, UNIMAP_N, UNIMAP_B, UNIMAP_H, UNIMAP_G, UNIMAP_Y, UNIMAP_6, UNIMAP_F7, /* 30-37 */
UNIMAP_F19, UNIMAP_RALT, UNIMAP_M, UNIMAP_J, UNIMAP_U, UNIMAP_7, UNIMAP_8, UNIMAP_F8 }, /* 38-3F */
{ UNIMAP_F20, UNIMAP_COMMA, UNIMAP_K, UNIMAP_I, UNIMAP_O, UNIMAP_0, UNIMAP_9, UNIMAP_F9, /* 40-47 */
UNIMAP_F21, UNIMAP_DOT, UNIMAP_SLASH, UNIMAP_L, UNIMAP_SCOLON,UNIMAP_P, UNIMAP_MINUS, UNIMAP_F10 }, /* 48-4F */
{ UNIMAP_F22, UNIMAP_RO, UNIMAP_QUOTE, UNIMAP_NUHS, UNIMAP_LBRC, UNIMAP_EQUAL, UNIMAP_F11, UNIMAP_F23, /* 50-57 */
UNIMAP_RCTL, UNIMAP_RSHIFT,UNIMAP_ENTER, UNIMAP_RBRC, UNIMAP_BSLASH,UNIMAP_JYEN, UNIMAP_F12, UNIMAP_F24 }, /* 58-5F */
{ UNIMAP_DOWN, UNIMAP_LEFT, UNIMAP_HOME, UNIMAP_UP, UNIMAP_END, UNIMAP_INS, UNIMAP_BSPACE,UNIMAP_PSLS, /* 60-67 */
UNIMAP_PCMM, UNIMAP_P1, UNIMAP_RIGHT, UNIMAP_P4, UNIMAP_P7, UNIMAP_DEL, UNIMAP_PGUP, UNIMAP_PGDN }, /* 68-6F */
{ UNIMAP_P0, UNIMAP_PDOT, UNIMAP_P2, UNIMAP_P5, UNIMAP_P6, UNIMAP_P8, UNIMAP_ESC, UNIMAP_NLCK, /* 70-77 */
UNIMAP_PEQL, UNIMAP_PENT, UNIMAP_P3, UNIMAP_PMNS, UNIMAP_PPLS, UNIMAP_P9, UNIMAP_SLCK, UNIMAP_PAST }, /* 78-7F */
};
extern const action_t actionmaps[][UNIMAP_ROWS][UNIMAP_COLS];
action_t action_for_key(uint8_t layer, keypos_t key)
{
uint8_t unimap_pos;
switch (keyboard_kind) {
case PC_XT:
unimap_pos = pgm_read_byte(&unimap_cs1[key.row][key.col]);
break;
case PC_AT:
unimap_pos = pgm_read_byte(&unimap_cs2[key.row][key.col]);
break;
case PC_TERMINAL:
unimap_pos = pgm_read_byte(&unimap_cs3[key.row][key.col]);
break;
default:
return (action_t)ACTION_NO;
}
if (unimap_pos == UNIMAP_NO) return (action_t)ACTION_NO;
return (action_t)pgm_read_word(&actionmaps[(layer)][(unimap_pos & 0x70) >> 4][(unimap_pos & 0x0f)]);
}
#endif

View file

@ -0,0 +1,88 @@
TARGET ?= usb_desc_dump
TMK_DIR ?= ../../tmk_core
TARGET_DIR ?= .
SRC ?= ino.cpp
CONFIG_H ?= config.h
# MCU name
MCU ?= atmega32u4
# Processor frequency.
F_CPU ?= 16000000
#
# LUFA specific
#
ARCH ?= AVR8
F_USB ?= $(F_CPU)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
#
# Build Options
#
MOUSEKEY_ENABLE ?= no # Mouse keys
EXTRAKEY_ENABLE ?= no # Media control and System control
CONSOLE_ENABLE ?= yes # Console for debug
COMMAND_ENABLE ?= no # Commands for debug and configuration
NKRO_ENABLE ?= no # USB Nkey Rollover
NO_KEYBOARD ?= yes # No keyboard interface
# Boot Section Size in bytes
OPT_DEFS += -DBOOTLOADER_SIZE=4096
OPT_DEFS += -DNO_DEBUG
EXTRACPPFLAGS = -fpermissive
# program Leonardo
PROGRAM_CMD = avrdude -p$(MCU) -cavr109 -b57600 -Uflash:w:$(TARGET).hex -P$(DEV)
# Search Path
VPATH += $(TARGET_DIR)
VPATH += $(TMK_DIR)
#
# USB_desc_dump build setting
#
include $(TMK_DIR)/protocol/usb_hid.mk
USB_DESC_DUMP_DIR = $(USB_HOST_SHIELD_DIR)/examples/USB_desc_dump
SRC += $(USB_DESC_DUMP_DIR)/USB_desc_dump.cpp
SRC += $(USB_HOST_SHIELD_DIR)/hidescriptorparser.cpp
# Print Standard descriptor
OPT_DEFS += -DPRINT_DESC
#OPT_DEFS += -DNO_PRINT_DESC
# Print High-speed Hub descriptor
#OPT_DEFS += -DPRINT_DESC_HSHUB
OPT_DEFS += -DNO_PRINT_DESC_HSHUB
# Print HID Report descriptor
#OPT_DEFS += -DPRINT_DESC_REPORT
OPT_DEFS += -DNO_PRINT_DESC_REPORT
include $(TMK_DIR)/protocol/lufa.mk
include $(TMK_DIR)/common.mk
include $(TMK_DIR)/rules.mk
$(OBJDIR)/$(USB_DESC_DUMP_DIR)/USB_desc_dump.cpp.o : $(OBJDIR)/$(USB_DESC_DUMP_DIR)/USB_desc_dump.cpp $(OBJDIR)/$(USB_DESC_DUMP_DIR)/desc.h
@echo
mkdir -p $(@D)
@echo $(MSG_COMPILING_CPP) $<
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
$(OBJDIR)/$(USB_DESC_DUMP_DIR)/USB_desc_dump.cpp : $(TMK_DIR)/$(USB_DESC_DUMP_DIR)/USB_desc_dump.ino
@echo
mkdir -p $(@D)
$(COPY) $< $@
$(OBJDIR)/$(USB_DESC_DUMP_DIR)/desc.h : $(TMK_DIR)/$(USB_DESC_DUMP_DIR)/desc.h
@echo
mkdir -p $(@D)
$(COPY) $< $@

View file

@ -0,0 +1,163 @@
USB Descriptor Dumper
=====================
2021-07-20
`Usb_desc_dump` gets USB descriptors and shows in HEX dump and human readable form.
This works on TMK USB-USB converter and USB Host Shield with Arduino Leonardo.
Following descriptors are supported.
- Device Descriptor
- Configuration Descriptor
- Interface Descriptor
- Endpoint Descriptor
- HID Descriptor
- HID Report descriptor
- String Descriptor
- Device Qualifier*
- Other Speed*
- Audio/MIDI Class*
*: partly supported
See source code for the detail.
- https://github.com/tmk/USB_Host_Shield_2.0/tree/master/examples/USB_desc_dump
Example optput:
```
usb_state: 90
//////////////////////////////////////////////////////////////////////
// USB_desc_dump
// Address: 01
// Lowspeed: 00
// Devicer dump:
12 01 00 02 00 00 00 08 6A 04 11 00 00 01 00 00
00 01
// Device:
bLength: 12
bDescriptorType: 01
bcdUSB: 0200
bDeviceClass: 00
bDeviceSubClass: 00
bDeviceProtocol: 00
bMaxPacketSize0: 08
idVendor: 046A
idProduct: 0011
bcdDevice: 0100
iManufacturer: 00
iProduct: 00
iSerialNumber: 00
bNumConfigurations: 01
// Config0 dump: len: 0022
09 02 22 00 01 01 00 A0 32 09 04 00 00 01 03 01
01 00 09 21 11 01 00 01 22 40 00 07 05 81 03 08
00 0A
// Config:
bLength: 09
bDescriptorType: 02
wTotalLength: 0022
bNumInterfaces: 01
bConfigurationValue: 01
iConfiguration: 00
bmAttributes: A0
bMaxPower: 32
// Interface0.0:
bLength: 09
bDescriptorType: 04
bInterfaceNumber: 00
bAlternateSetting: 00
bNumEndpoints: 01
bInterfaceClass: 03
bInterfaceSubClass: 01
bInterfaceProtocol: 01
iInterface: 00
// HID:
bLength: 09
bDescriptorType: 21
bcdHID: 0111
bCountryCode: 00
bNumDescriptors: 01
bDescrType: 22
wDescriptorLength: 0040
// Report0 dump: len: 0040
05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01
75 01 95 08 81 02 95 01 75 08 81 01 95 03 75 01
05 08 19 01 29 03 91 02 95 05 75 01 91 01 95 06
75 08 15 00 26 DD 00 05 07 19 00 29 DD 81 00 C0
// Endpoint:
bLength: 07
bDescriptorType: 05
bEndpointAddress: 81
bmAttributes: 03
wMaxPacketSize: 0008
bInterval: 0A
// Parse data here: http://eleccelerator.com/usbdescreqparser/
```
To inspect descriptor content closely use 'USB Descriptor and Request Parser' on line.
- https://eleccelerator.com/usbdescreqparser/
Also you can use command line tool `hidrd-convert` like below.
- https://github.com/DIGImend/hidrd
```
$ cat | hidrd-convert -i hex -o spec
05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01
75 01 95 08 81 02 95 01 75 08 81 01 95 03 75 01
05 08 19 01 29 03 91 02 95 05 75 01 91 01 95 06
75 08 15 00 26 DD 00 05 07 19 00 29 DD 81 00 C0
^D
Usage Page (Desktop), ; Generic desktop controls (01h)
Usage (Keyboard), ; Keyboard (06h, application collection)
Collection (Application),
Usage Page (Keyboard), ; Keyboard/keypad (07h)
Usage Minimum (KB Leftcontrol), ; Keyboard left control (E0h, dynamic value)
Usage Maximum (KB Right GUI), ; Keyboard right GUI (E7h, dynamic value)
Logical Minimum (0),
Logical Maximum (1),
Report Size (1),
Report Count (8),
Input (Variable),
Report Count (1),
Report Size (8),
Input (Constant),
Report Count (3),
Report Size (1),
Usage Page (LED), ; LEDs (08h)
Usage Minimum (01h),
Usage Maximum (03h),
Output (Variable),
Report Count (5),
Report Size (1),
Output (Constant),
Report Count (6),
Report Size (8),
Logical Minimum (0),
Logical Maximum (221),
Usage Page (Keyboard), ; Keyboard/keypad (07h)
Usage Minimum (None), ; No event (00h, selector)
Usage Maximum (KP Hexadecimal), ; Keypad Hexadecimal (DDh, selector)
Input,
End Collection
```

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,52 @@
/*
Copyright 2012 Jun Wako <wakojun@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONFIG_H
#define CONFIG_H
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0x005B
#define DEVICE_VER 0x0814
#define MANUFACTURER TMK
#define PRODUCT USB Descriptor Dumper
#define DESCRIPTION Product from TMK keyboard firmware project
/* matrix size */
#define MATRIX_ROWS 0
#define MATRIX_COLS 0
/* key combination for command */
#define IS_COMMAND() (keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)))
// Disable power saving in USB suspend loop but remote wakeup is still valid.
// This allows keep USB::Task() going during suspend without power down time delay.
//#define NO_SUSPEND_POWER_DOWN
// Disable USB startup wait, which can delays starting UHS2 Task() for 350-600ms.
//#define NO_USB_STARTUP_WAIT_LOOP
// Disable USB suspend loop, which blocks UHS2 Task() while power saving.
// Note that this also disables power saving and remote wakeup from keyboard completely.
//#define NO_USB_SUSPEND_LOOP
#endif

View file

@ -0,0 +1,37 @@
/*
Copyright 2021 Jun Wako <wakojun@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "Arduino.h"
#include "hook.h"
void hook_early_init(void) {
// arduino
setup();
}
void hook_late_init(void) {
}
void hook_main_loop(void) {
// arduino
loop();
}

View file

@ -17,7 +17,10 @@ SRC += $(COMMON_DIR)/host.c \
$(COMMON_DIR)/avr/bootloader.c
# Option modules
ifeq (yes,$(strip $(NO_KEYBOARD)))
OPT_DEFS += -DNO_KEYBOARD
endif
ifeq (yes,$(strip $(UNIMAP_ENABLE)))
SRC += $(COMMON_DIR)/unimap.c
OPT_DEFS += -DUNIMAP_ENABLE
@ -75,6 +78,10 @@ ifeq (yes,$(strip $(NKRO_ENABLE)))
OPT_DEFS += -DNKRO_ENABLE
endif
ifeq (yes,$(strip $(NKRO_6KRO_ENABLE)))
OPT_DEFS += -DNKRO_6KRO_ENABLE
endif
ifeq (yes,$(strip $(USB_6KRO_ENABLE)))
OPT_DEFS += -DUSB_6KRO_ENABLE
endif
@ -109,7 +116,7 @@ ifeq (yes,$(strip $(KEYMAP_SECTION_ENABLE)))
endif
# Version string
TMK_VERSION := $(shell (git describe --always --dirty=+ || echo 'unknown') 2> /dev/null)
TMK_VERSION := $(shell (git rev-parse --short=6 HEAD || echo 'unknown') 2> /dev/null)
OPT_DEFS += -DTMK_VERSION=$(TMK_VERSION)

View file

@ -22,7 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
static inline void add_key_byte(uint8_t code);
static inline void del_key_byte(uint8_t code);
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
static inline void add_key_bit(uint8_t code);
static inline void del_key_bit(uint8_t code);
#endif
@ -75,7 +75,7 @@ void send_keyboard_report(void) {
/* key */
void add_key(uint8_t key)
{
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
if (keyboard_protocol && keyboard_nkro) {
add_key_bit(key);
return;
@ -86,7 +86,7 @@ void add_key(uint8_t key)
void del_key(uint8_t key)
{
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
if (keyboard_protocol && keyboard_nkro) {
del_key_bit(key);
return;
@ -159,7 +159,7 @@ uint8_t has_anymod(void)
uint8_t get_first_key(void)
{
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
if (keyboard_protocol && keyboard_nkro) {
uint8_t i = 0;
for (; i < KEYBOARD_REPORT_BITS && !keyboard_report->nkro.bits[i]; i++)
@ -286,7 +286,7 @@ static inline void del_key_byte(uint8_t code)
#endif
}
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
static inline void add_key_bit(uint8_t code)
{
if ((code>>3) < KEYBOARD_REPORT_BITS) {

View file

@ -115,21 +115,25 @@ void suspend_power_down(void)
bool suspend_wakeup_condition(void)
{
#ifndef NO_KEYBOARD
matrix_power_up();
matrix_scan();
matrix_power_down();
for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
if (matrix_get_row(r)) return true;
}
#endif
return false;
}
// run immediately after wakeup
void suspend_wakeup_init(void)
{
#ifndef NO_KEYBOARD
// clear keyboard state
matrix_clear();
clear_keyboard();
#endif
#ifdef BACKLIGHT_ENABLE
backlight_init();
#endif

View file

@ -88,7 +88,7 @@ void bootmagic(void)
}
eeconfig_write_keymap(keymap_config.raw);
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
keyboard_nkro = keymap_config.nkro;
#endif

View file

@ -134,7 +134,7 @@ static void command_common_help(void)
"e: eeprom\n"
#endif
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
"n: NKRO\n"
#endif
@ -314,7 +314,7 @@ static bool command_common(uint8_t code)
#ifdef COMMAND_ENABLE
" COMMAND"
#endif
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
" NKRO"
#endif
#ifdef KEYMAP_SECTION_ENABLE
@ -336,7 +336,7 @@ static bool command_common(uint8_t code)
print_val_hex8(host_keyboard_leds());
print_val_hex8(keyboard_protocol);
print_val_hex8(keyboard_idle);
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
print_val_hex8(keyboard_nkro);
#endif
print_val_hex32(timer_read32());
@ -355,7 +355,7 @@ static bool command_common(uint8_t code)
# endif
#endif
break;
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
case KC_N:
clear_keyboard(); //Prevents stuck keys.
keyboard_nkro = !keyboard_nkro;

View file

@ -22,6 +22,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* Definitions of default hooks
* ------------------------------------------------- */
__attribute__((weak))
void hook_main_loop(void) {}
__attribute__((weak))
void hook_keyboard_loop(void) {}

View file

@ -56,6 +56,10 @@ void hook_usb_wakeup(void);
/* Default behaviour: do nothing. */
void hook_usb_startup_wait_loop(void);
/* Called periodically from main loop */
/* Default behaviour: do nothing. */
void hook_main_loop(void);
/* -------------------------------------
* Keyboard hooks

View file

@ -23,7 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "debug.h"
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
bool keyboard_nkro = true;
#endif

View file

@ -28,7 +28,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
extern "C" {
#endif
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
extern bool keyboard_nkro;
#endif

View file

@ -171,10 +171,6 @@ static action_t keycode_to_action(uint8_t keycode)
* Legacy keymap support
* Consider using new keymap API instead.
*/
extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
extern const uint8_t fn_layer[];
extern const uint8_t fn_keycode[];
__attribute__ ((weak))
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col)
{
@ -223,10 +219,6 @@ action_t keymap_fn_to_action(uint8_t keycode)
#else
/* user keymaps should be defined somewhere */
extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
extern const action_t fn_actions[];
__attribute__ ((weak))
uint8_t keymap_key_to_keycode(uint8_t layer, keypos_t key)
{

View file

@ -23,6 +23,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "action.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef BOOTMAGIC_ENABLE
/* NOTE: Not portable. Bit field order depends on implementation */
typedef union {
@ -40,6 +44,8 @@ typedef union {
} keymap_config_t;
#endif
extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
extern const action_t fn_actions[];
/* translates key to keycode */
uint8_t keymap_key_to_keycode(uint8_t layer, keypos_t key);
@ -54,6 +60,10 @@ action_t keymap_fn_to_action(uint8_t keycode);
* Legacy keymap
* Consider using new keymap API above instead.
*/
extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
extern const uint8_t fn_layer[];
extern const uint8_t fn_keycode[];
/* keycode of key */
__attribute__ ((deprecated))
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col);
@ -65,6 +75,16 @@ uint8_t keymap_fn_layer(uint8_t fn_bits);
/* keycode to send when release Fn key without using */
__attribute__ ((deprecated))
uint8_t keymap_fn_keycode(uint8_t fn_bits);
#else
/* user keymaps should be defined somewhere */
extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
extern const action_t fn_actions[];
#endif
#ifdef __cplusplus
}
#endif
#endif

View file

@ -100,6 +100,12 @@ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t));
#else /* NO_PRINT */
#define xprintf(s,...) ((void)0)
#define xsprintf(s,...) ((void)0)
#define xfprintf(s,...) ((void)0)
#define xputs(s) ((void)0)
#define xputc(c) ((void)0)
#define xitoa(v, r, w) ((void)0)
#define xatoi(s, r) ((void)0)
#define print(s) ((void)0)
#define println(s) ((void)0)
#define print_set_sendchar(func) ((void)0)

View file

@ -94,7 +94,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# define KEYBOARD_REPORT_KEYS (KBD2_SIZE - 2)
# define KEYBOARD_REPORT_BITS (KBD2_SIZE - 1)
#elif defined(PROTOCOL_LUFA) && defined(NKRO_ENABLE)
#elif defined(PROTOCOL_LUFA) && (defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE))
# include "protocol/lufa/descriptor.h"
# define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
# define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
@ -142,7 +142,7 @@ typedef union {
uint8_t reserved;
uint8_t keys[KEYBOARD_REPORT_KEYS];
};
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
struct {
uint8_t mods;
uint8_t bits[KEYBOARD_REPORT_BITS];

View file

@ -19,6 +19,7 @@ static inline void ringbuf_write(ringbuf_t *buf, uint8_t data);
static inline bool ringbuf_is_empty(ringbuf_t *buf);
static inline bool ringbuf_is_full(ringbuf_t *buf);
static inline void ringbuf_reset(ringbuf_t *buf);
static inline void ringbuf_push(ringbuf_t *buf, uint8_t data);
static inline void ringbuf_init(ringbuf_t *buf, uint8_t *array, uint8_t size)
{
@ -70,4 +71,10 @@ static inline void ringbuf_reset(ringbuf_t *buf)
buf->head = 0;
buf->tail = 0;
}
static inline void ringbuf_push(ringbuf_t *buf, uint8_t data)
{
buf->buffer[buf->head] = data;
buf->head++;
buf->head &= buf->size_mask;
}
#endif

View file

@ -214,11 +214,10 @@ void ibmpc_host_isr_clear(void)
ringbuf_reset(&rb);
}
#define LO8(w) (*((uint8_t *)&(w)))
#define HI8(w) (*(((uint8_t *)&(w))+1))
// NOTE: With this ISR data line can be read within 2us after clock falling edge.
// To read data line early as possible:
// write naked ISR with asembly code to read the line and call C func to do other job?
// NOTE: With this ISR data line should be read within 5us after clock falling edge.
// Confirmed that ATmega32u4 can read data line in 2.5us from interrupt after
// ISR prologue pushs r18, r19, r20, r21, r24, r25 r30 and r31 with GCC 5.4.0
ISR(IBMPC_INT_VECT)
{
uint8_t dbit;
@ -366,16 +365,19 @@ ISR(IBMPC_INT_VECT)
DONE:
// store data
if (!ringbuf_put(&rb, isr_state & 0xFF)) {
// buffer overflow
ibmpc_error = IBMPC_ERR_FULL;
ringbuf_push(&rb, isr_state & 0xFF);
if (ringbuf_is_full(&rb)) {
// just became full
// Disable ISR if buffer is full
IBMPC_INT_OFF();
// inhibit: clock_lo
IBMPC_CLOCK_PORT &= ~(1<<IBMPC_CLOCK_BIT);
IBMPC_CLOCK_DDR |= (1<<IBMPC_CLOCK_BIT);
}
if (ringbuf_is_empty(&rb)) {
// buffer overflow
ibmpc_error = IBMPC_ERR_FULL;
}
ERROR:
// clear for next data
isr_state = 0x8000;

405
tmk_core/protocol/ibmpc.cpp Normal file
View file

@ -0,0 +1,405 @@
/*
Copyright 2010,2011,2012,2013,2019 Jun WAKO <wakojun@gmail.com>
This software is licensed with a Modified BSD License.
All of this is supposed to be Free Software, Open Source, DFSG-free,
GPL-compatible, and OK to use in both free and proprietary applications.
Additions and corrections to this file are welcome.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
* IBM PC keyboard protocol
*/
#include <stdbool.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include "debug.h"
#include "timer.h"
#include "wait.h"
#include "ibmpc.hpp"
#define WAIT(stat, us, err) do { \
if (!wait_##stat(us)) { \
error = err; \
goto ERROR; \
} \
} while (0)
IBMPC IBMPC::interface0 = IBMPC(IBMPC_CLOCK_BIT, IBMPC_DATA_BIT);
#if defined(IBMPC_CLOCK_BIT1) && defined(IBMPC_DATA_BIT1)
IBMPC IBMPC::interface1 = IBMPC(IBMPC_CLOCK_BIT1, IBMPC_DATA_BIT1);
#endif
void IBMPC::host_init(void)
{
// initialize reset pin to HiZ
IBMPC_RST_HIZ();
inhibit();
int_init();
int_off();
host_isr_clear();
}
void IBMPC::host_enable(void)
{
int_on();
idle();
}
void IBMPC::host_disable(void)
{
int_off();
inhibit();
}
int16_t IBMPC::host_send(uint8_t data)
{
bool parity = true;
error = IBMPC_ERR_NONE;
uint8_t retry = 0;
dprintf("w%02X ", data);
// Not receiving data
if (isr_state != 0x8000) dprintf("isr:%04X ", isr_state);
while (isr_state != 0x8000) ;
// Not clock Lo
if (!clock_in()) dprintf("c:%u ", wait_clock_hi(1000));
// Not data Lo
if (!data_in()) dprintf("d:%u ", wait_data_hi(1000));
int_off();
RETRY:
/* terminate a transmission if we have */
inhibit();
wait_us(200); // [5]p.54
/* 'Request to Send' and Start bit */
data_lo();
wait_us(200);
clock_hi(); // [5]p.54 [clock low]>100us [5]p.50
WAIT(clock_lo, 10000, 1); // [5]p.53, -10ms [5]p.50
/* Data bit[2-9] */
for (uint8_t i = 0; i < 8; i++) {
wait_us(15);
if (data&(1<<i)) {
parity = !parity;
data_hi();
} else {
data_lo();
}
WAIT(clock_hi, 50, 2);
WAIT(clock_lo, 50, 3);
}
/* Parity bit */
wait_us(15);
if (parity) { data_hi(); } else { data_lo(); }
WAIT(clock_hi, 50, 4);
WAIT(clock_lo, 50, 5);
/* Stop bit */
wait_us(15);
data_hi();
/* Ack */
WAIT(data_lo, 300, 6);
WAIT(data_hi, 300, 7);
WAIT(clock_hi, 300, 8);
// clear buffer to get response correctly
host_isr_clear();
idle();
int_on();
return host_recv_response();
ERROR:
// Retry for Z-150 AT start bit error
if (error == 1 && retry++ < 10) {
error = IBMPC_ERR_NONE;
dprintf("R ");
goto RETRY;
}
error |= IBMPC_ERR_SEND;
inhibit();
wait_ms(2);
idle();
int_on();
return -1;
}
/*
* Receive data from keyboard
*/
int16_t IBMPC::host_recv(void)
{
int16_t ret = -1;
// Enable ISR if buffer was full
if (ringbuf_is_full()) {
host_isr_clear();
int_on();
idle();
}
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
ret = ringbuf_get();
}
if (ret != -1) dprintf("r%02X ", ret&0xFF);
return ret;
}
int16_t IBMPC::host_recv_response(void)
{
// Command may take 25ms/20ms at most([5]p.46, [3]p.21)
uint8_t retry = 25;
int16_t data = -1;
while (retry-- && (data = host_recv()) == -1) {
wait_ms(1);
}
return data;
}
void IBMPC::host_isr_clear(void)
{
isr_debug = 0;
protocol = 0;
error = 0;
isr_state = 0x8000;
ringbuf_reset();
}
inline void IBMPC::isr(void)
{
uint8_t dbit;
dbit = IBMPC_DATA_PIN&(1<<data_bit);
// Timeout check
uint8_t t;
// use only the least byte of millisecond timer
asm("lds %0, %1" : "=r" (t) : "p" (&timer_count));
//t = (uint8_t)timer_count; // compiler uses four registers instead of one
if (isr_state == 0x8000) {
timer_start = t;
} else {
// This gives 2.0ms at least before timeout
if ((uint8_t)(t - timer_start) >= 3) {
isr_debug = isr_state;
error = IBMPC_ERR_TIMEOUT;
goto ERROR;
// timeout error recovery - start receiving new data
// it seems to work somehow but may not under unstable situation
//timer_start = t;
//isr_state = 0x8000;
}
}
isr_state = isr_state>>1;
if (dbit) isr_state |= 0x8000;
// isr_state: state of receiving data from keyboard
//
// This should be initialized with 0x8000 before receiving data and
// the MSB '*1' works as marker to discrimitate between protocols.
// It stores sampled bit at MSB after right shift on each clock falling edge.
//
// XT protocol has two variants of signaling; XT_IBM and XT_Clone.
// XT_IBM uses two start bits 0 and 1 while XT_Clone uses just start bit 1.
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol
//
// 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
// -----------------------------------------------------
// *1 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 Initial state(0x8000)
//
// x x x x x x x x | 0 0 0 0 0 0 0 0 midway(0-7 bits received)
// x x x x x x x x | *1 0 0 0 0 0 0 0 midway(8 bits received)
// b6 b5 b4 b3 b2 b1 b0 1 | 0 *1 0 0 0 0 0 0 XT_IBM-midway ^1
// b7 b6 b5 b4 b3 b2 b1 b0 | 0 *1 0 0 0 0 0 0 AT-midway ^1
// b7 b6 b5 b4 b3 b2 b1 b0 | 1 *1 0 0 0 0 0 0 XT_Clone-done ^3
// b6 b5 b4 b3 b2 b1 b0 1 | 1 *1 0 0 0 0 0 0 XT_IBM-error ^3
// pr b7 b6 b5 b4 b3 b2 b1 | 0 0 *1 0 0 0 0 0 AT-midway[b0=0]
// b7 b6 b5 b4 b3 b2 b1 b0 | 1 0 *1 0 0 0 0 0 XT_IBM-done ^2
// pr b7 b6 b5 b4 b3 b2 b1 | 1 0 *1 0 0 0 0 0 AT-midway[b0=1] ^2
// b7 b6 b5 b4 b3 b2 b1 b0 | 1 1 *1 0 0 0 0 0 XT_IBM-error-done
// x x x x x x x x | 0 1 *1 0 0 0 0 0 illegal
// st pr b7 b6 b5 b4 b3 b2 | b1 b0 0 *1 0 0 0 0 AT-done
// x x x x x x x x | x x 1 *1 0 0 0 0 illegal
// all other states than above illegal
//
// ^1: AT and XT_IBM takes same state.
// ^2: AT and XT_IBM takes same state in case that AT b0 is 1,
// we have to check AT stop bit to discriminate between the two protocol.
switch (isr_state & 0xFF) {
case 0b00000000:
case 0b10000000:
case 0b01000000: // ^1
case 0b00100000:
// midway
goto NEXT;
break;
case 0b11000000: // ^3
{
uint8_t us = 100;
// wait for rising and falling edge of b7 of XT_IBM
if (!protocol) {
while (!(IBMPC_CLOCK_PIN & clock_mask) && us) { wait_us(1); us--; }
while ( (IBMPC_CLOCK_PIN & clock_mask) && us) { wait_us(1); us--; }
} else if (protocol == IBMPC_PROTOCOL_XT_CLONE) {
us = 0;
}
if (us) {
// XT_IBM-error: read start(0) as 1
goto NEXT;
} else {
// XT_Clone-done
isr_debug = isr_state;
isr_state = isr_state>>8;
protocol = IBMPC_PROTOCOL_XT_CLONE;
goto DONE;
}
}
break;
case 0b11100000:
// XT_IBM-error-done
isr_debug = isr_state;
isr_state = isr_state>>8;
protocol = IBMPC_PROTOCOL_XT_ERROR;
goto DONE;
break;
case 0b10100000: // ^2
{
uint8_t us = 100;
// wait for rising and falling edge of AT stop bit to discriminate between XT and AT
if (!protocol) {
while (!(IBMPC_CLOCK_PIN & clock_mask) && us) { wait_us(1); us--; }
while ( (IBMPC_CLOCK_PIN & clock_mask) && us) { wait_us(1); us--; }
} else if (protocol == IBMPC_PROTOCOL_XT_IBM) {
us = 0;
}
if (us) {
// found stop bit: AT-midway - process the stop bit in next ISR
goto NEXT;
} else {
// no stop bit: XT_IBM-done
isr_debug = isr_state;
isr_state = isr_state>>8;
protocol = IBMPC_PROTOCOL_XT_IBM;
goto DONE;
}
}
break;
case 0b00010000:
case 0b10010000:
case 0b01010000:
case 0b11010000:
// AT-done
// TODO: parity check?
isr_debug = isr_state;
// stop bit check
if (isr_state & 0x8000) {
protocol = IBMPC_PROTOCOL_AT;
} else {
// Zenith Z-150 AT(beige/white lable) asserts stop bit as low
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#zenith-z-150-beige
protocol = IBMPC_PROTOCOL_AT_Z150;
}
isr_state = isr_state>>6;
goto DONE;
break;
case 0b01100000:
case 0b00110000:
case 0b10110000:
case 0b01110000:
case 0b11110000:
default: // xxxx_oooo(any 1 in low nibble)
// Illegal
protocol = 0;
isr_debug = isr_state;
error = IBMPC_ERR_ILLEGAL;
goto ERROR;
break;
}
DONE:
// store data
ringbuf_put(isr_state & 0xFF);
if (ringbuf_is_full()) {
// Disable ISR if buffer is full
int_off();
// inhibit: clock_lo() instead of inhibit() for ISR optimization
clock_lo();
}
if (ringbuf_is_empty()) {
// buffer overflow
error = IBMPC_ERR_FULL;
}
ERROR:
// clear for next data
isr_state = 0x8000;
NEXT:
return;
}
/* send LED state to keyboard */
void IBMPC::host_set_led(uint8_t led)
{
if (0xFA == host_send(0xED)) {
host_send(led);
}
}
// NOTE: With this ISR data line should be read within 5us after clock falling edge.
// Confirmed that ATmega32u4 can read data line in 2.5us from interrupt after
// ISR prologue pushs r18, r19, r20, r21, r24, r25 r30 and r31 with GCC 5.4.0
ISR(IBMPC_INT_VECT)
{
IBMPC::interface0.isr();
}
#if defined(IBMPC_CLOCK_BIT1) && defined(IBMPC_DATA_BIT1) && defined(IBMPC_INT_VECT1)
ISR(IBMPC_INT_VECT1)
{
IBMPC::interface1.isr();
}
#endif

276
tmk_core/protocol/ibmpc.hpp Normal file
View file

@ -0,0 +1,276 @@
/*
Copyright 2010,2011,2012,2013,2019 Jun WAKO <wakojun@gmail.com>
This software is licensed with a Modified BSD License.
All of this is supposed to be Free Software, Open Source, DFSG-free,
GPL-compatible, and OK to use in both free and proprietary applications.
Additions and corrections to this file are welcome.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef IBMPC_HPP
#define IBMPC_HPP
#include <stdbool.h>
#include "wait.h"
/*
* IBM PC keyboard protocol
*
* PS/2 Resources
* --------------
* [1] The PS/2 Mouse/Keyboard Protocol
* http://www.computer-engineering.org/ps2protocol/
* Concise and thorough primer of PS/2 protocol.
*
* [2] Keyboard and Auxiliary Device Controller
* http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
* Signal Timing and Format
*
* [3] Keyboards(101- and 102-key)
* http://www.mcamafia.de/pdf/ibm_hitrc11.pdf
* Keyboard Layout, Scan Code Set, POR, and Commands.
*
* [4] PS/2 Reference Manuals
* http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
* Collection of IBM Personal System/2 documents.
*
* [5] TrackPoint Engineering Specifications for version 3E
* https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html
*/
#define IBMPC_ACK 0xFA
#define IBMPC_RESEND 0xFE
#define IBMPC_SET_LED 0xED
#define IBMPC_PROTOCOL_NO 0
#define IBMPC_PROTOCOL_AT 0x10
#define IBMPC_PROTOCOL_AT_Z150 0x11
#define IBMPC_PROTOCOL_XT 0x20
#define IBMPC_PROTOCOL_XT_IBM 0x21
#define IBMPC_PROTOCOL_XT_CLONE 0x22
#define IBMPC_PROTOCOL_XT_ERROR 0x23
// Error numbers
#define IBMPC_ERR_NONE 0
#define IBMPC_ERR_RECV 0x00
#define IBMPC_ERR_SEND 0x10
#define IBMPC_ERR_TIMEOUT 0x20
#define IBMPC_ERR_FULL 0x40
#define IBMPC_ERR_ILLEGAL 0x80
#define IBMPC_ERR_FF 0xF0
#define IBMPC_LED_SCROLL_LOCK 0
#define IBMPC_LED_NUM_LOCK 1
#define IBMPC_LED_CAPS_LOCK 2
class IBMPC
{
public:
static IBMPC interface0;
#if defined(IBMPC_CLOCK_BIT1) && defined(IBMPC_DATA_BIT1)
static IBMPC interface1;
#endif
volatile uint16_t isr_debug;
volatile uint8_t protocol;
volatile uint8_t error;
void host_init(void);
void host_enable(void);
void host_disable(void);
int16_t host_send(uint8_t data);
int16_t host_recv_response(void);
int16_t host_recv(void);
void host_isr_clear(void);
void host_set_led(uint8_t led);
IBMPC(uint8_t clock, uint8_t data) :
isr_debug(IBMPC_ERR_NONE), protocol(IBMPC_PROTOCOL_NO), error(IBMPC_ERR_NONE),
isr_state(0x8000), timer_start(0), clock_bit(clock), data_bit(data),
clock_mask(1 << clock), data_mask(1 << data) {
};
inline void isr(void) __attribute__((__always_inline__));
private:
volatile uint16_t isr_state;
uint8_t timer_start;
/* ring buffer */
// Size should be power of 2
#define RINGBUF_SIZE 16
uint8_t rb_head;
uint8_t rb_tail;
uint8_t rb_buffer[RINGBUF_SIZE];
const uint8_t clock_bit, data_bit;
const uint8_t clock_mask, data_mask;
inline void clock_lo(void) __attribute__((__always_inline__)) // needed for ISR optimization
{
IBMPC_CLOCK_PORT &= ~clock_mask;
IBMPC_CLOCK_DDR |= clock_mask;
}
inline void clock_hi(void)
{
/* input with pull up */
IBMPC_CLOCK_DDR &= ~clock_mask;
IBMPC_CLOCK_PORT |= clock_mask;
}
inline bool clock_in(void)
{
IBMPC_CLOCK_DDR &= ~clock_mask;
IBMPC_CLOCK_PORT |= clock_mask;
wait_us(1);
return IBMPC_CLOCK_PIN & clock_mask;
}
inline void data_lo(void)
{
IBMPC_DATA_PORT &= ~data_mask;
IBMPC_DATA_DDR |= data_mask;
}
inline void data_hi(void)
{
/* input with pull up */
IBMPC_DATA_DDR &= ~data_mask;
IBMPC_DATA_PORT |= data_mask;
}
inline bool data_in(void)
{
IBMPC_DATA_DDR &= ~data_mask;
IBMPC_DATA_PORT |= data_mask;
wait_us(1);
return IBMPC_DATA_PIN & data_mask;
}
inline uint16_t wait_clock_lo(uint16_t us)
{
while (clock_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
inline uint16_t wait_clock_hi(uint16_t us)
{
while (!clock_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
inline uint16_t wait_data_lo(uint16_t us)
{
while (data_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
inline uint16_t wait_data_hi(uint16_t us)
{
while (!data_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
/* idle state that device can send */
inline void idle(void)
{
clock_hi();
data_hi();
}
/* inhibit device to send(AT), soft reset(XT) */
inline void inhibit(void)
{
clock_lo();
data_hi();
}
/* inhibit device to send(XT) */
inline void inhibit_xt(void)
{
clock_hi();
data_lo();
}
void int_init(void)
{
// interrupt at falling edge
if (clock_bit < 4) {
EICRA |= (0x2 << ((clock_bit&0x3)*2));
} else {
EICRB |= (0x2 << ((clock_bit&0x3)*2));
}
}
void int_on(void)
{
EIFR |= clock_mask;
EIMSK |= clock_mask;
}
inline void int_off(void) __attribute__((__always_inline__)) // needed for ISR optimization
{
EIMSK &= ~clock_mask;
}
/*
* ring buffer
*/
inline int16_t ringbuf_get(void) __attribute__((__always_inline__))
{
if (ringbuf_is_empty()) return -1;
uint8_t data = rb_buffer[rb_tail];
rb_tail++;
rb_tail &= (RINGBUF_SIZE - 1);
return data;
}
inline void ringbuf_put(uint8_t data) __attribute__((__always_inline__))
{
rb_buffer[rb_head] = data;
rb_head++;
rb_head &= (RINGBUF_SIZE - 1);
}
inline bool ringbuf_is_empty(void) __attribute__((__always_inline__))
{
return (rb_head == rb_tail);
}
inline bool ringbuf_is_full(void) __attribute__((__always_inline__))
{
return (((rb_head + 1) & (RINGBUF_SIZE - 1)) == rb_tail);
}
inline void ringbuf_reset(void) __attribute__((__always_inline__))
{
rb_head = 0;
rb_tail = 0;
}
};
#endif

View file

@ -4,6 +4,10 @@ TMK_LUFA_DIR = protocol/lufa
TMK_LUFA_PATH ?= $(TMK_LUFA_DIR)/lufa-abcminiuser
# Version string
TMK_LUFA_VERSION := $(shell (cd $(TMK_DIR)/$(TMK_LUFA_PATH); git rev-parse --short=6 HEAD || echo 'unknown') 2> /dev/null)
OPT_DEFS += -DTMK_LUFA_VERSION=$(TMK_LUFA_VERSION)
# Create the LUFA source path variables by including the LUFA makefile
ifneq (, $(wildcard $(TMK_DIR)/$(TMK_LUFA_PATH)/LUFA/Build/LUFA/lufa-sources.mk))
LUFA_PATH = $(TMK_LUFA_PATH)/LUFA

View file

@ -44,8 +44,11 @@
/*******************************************************************************
* HID Report Descriptors
******************************************************************************/
#ifndef NO_KEYBOARD
const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
{
#ifndef NKRO_ENABLE
/* 6KRO - Boot protocol */
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x06), /* Keyboard */
HID_RI_COLLECTION(8, 0x01), /* Application */
@ -81,17 +84,55 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
HID_RI_REPORT_SIZE(8, 0x08),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
};
#else
/* NKRO - Report protocol */
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x06), /* Keyboard */
HID_RI_COLLECTION(8, 0x01), /* Application */
HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */
HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
HID_RI_REPORT_COUNT(8, 0x08),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
#ifdef MOUSE_ENABLE
HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */
HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */
HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */
HID_RI_REPORT_COUNT(8, 0x05),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE),
HID_RI_REPORT_COUNT(8, 0x01),
HID_RI_REPORT_SIZE(8, 0x03),
HID_RI_OUTPUT(8, HID_IOF_CONSTANT),
HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */
HID_RI_USAGE_MINIMUM(8, 0x00), /* Keyboard 0 */
HID_RI_USAGE_MAXIMUM(8, (NKRO_EPSIZE-1)*8-1), /* Keyboard Right GUI */
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
HID_RI_REPORT_COUNT(8, (NKRO_EPSIZE-1)*8),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
#endif
};
#endif
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] =
{
#ifdef MOUSE_ENABLE
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x02), /* Mouse */
HID_RI_COLLECTION(8, 0x01), /* Application */
HID_RI_USAGE(8, 0x01), /* Pointer */
HID_RI_COLLECTION(8, 0x00), /* Physical */
HID_RI_REPORT_ID(8, REPORT_ID_MOUSE),
HID_RI_USAGE_PAGE(8, 0x09), /* Button */
HID_RI_USAGE_MINIMUM(8, 0x01), /* Button 1 */
HID_RI_USAGE_MAXIMUM(8, 0x08), /* Button 8 */
@ -147,12 +188,9 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] =
HID_RI_END_COLLECTION(0),
HID_RI_END_COLLECTION(0),
};
#endif
#ifdef EXTRAKEY_ENABLE
const USB_Descriptor_HIDReport_Datatype_t PROGMEM ExtrakeyReport[] =
{
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x80), /* System Control */
HID_RI_COLLECTION(8, 0x01), /* Application */
@ -178,6 +216,7 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ExtrakeyReport[] =
HID_RI_REPORT_COUNT(8, 1),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_ARRAY | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
#endif
};
#endif
@ -203,7 +242,7 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] =
};
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
const USB_Descriptor_HIDReport_Datatype_t PROGMEM NKROReport[] =
{
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
@ -289,6 +328,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
/*
* Keyboard
*/
#ifndef NO_KEYBOARD
.Keyboard_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
@ -322,14 +362,20 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointAddress = (ENDPOINT_DIR_IN | KEYBOARD_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
#ifdef NKRO_ENABLE
.EndpointSize = NKRO_EPSIZE,
.PollingIntervalMS = 0x01
#else
.EndpointSize = KEYBOARD_EPSIZE,
.PollingIntervalMS = 0x0A
#endif
},
#endif
/*
* Mouse
*/
#ifdef MOUSE_ENABLE
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
.Mouse_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
@ -340,8 +386,13 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.TotalEndpoints = 1,
.Class = HID_CSCP_HIDClass,
#if defined(MOUSE_ENABLE)
.SubClass = HID_CSCP_BootSubclass,
.Protocol = HID_CSCP_MouseBootProtocol,
#else
.SubClass = HID_CSCP_NonBootSubclass,
.Protocol = HID_CSCP_NonBootProtocol,
#endif
.InterfaceStrIndex = NO_DESCRIPTOR
},
@ -364,49 +415,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointAddress = (ENDPOINT_DIR_IN | MOUSE_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = MOUSE_EPSIZE,
.PollingIntervalMS = 0x0A
},
#endif
/*
* Extra
*/
#ifdef EXTRAKEY_ENABLE
.Extrakey_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
.InterfaceNumber = EXTRAKEY_INTERFACE,
.AlternateSetting = 0x00,
.TotalEndpoints = 1,
.Class = HID_CSCP_HIDClass,
.SubClass = HID_CSCP_NonBootSubclass,
.Protocol = HID_CSCP_NonBootProtocol,
.InterfaceStrIndex = NO_DESCRIPTOR
},
.Extrakey_HID =
{
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
.HIDSpec = VERSION_BCD(1,1,1),
.CountryCode = 0x00,
.TotalReportDescriptors = 1,
.HIDReportType = HID_DTYPE_Report,
.HIDReportLength = sizeof(ExtrakeyReport)
},
.Extrakey_INEndpoint =
{
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
.EndpointAddress = (ENDPOINT_DIR_IN | EXTRAKEY_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = EXTRAKEY_EPSIZE,
.PollingIntervalMS = 0x0A
.PollingIntervalMS = 0x01
},
#endif
@ -465,7 +474,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
/*
* NKRO
*/
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
.NKRO_Interface =
{
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
@ -578,29 +587,25 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
break;
case HID_DTYPE_HID:
switch (wIndex) {
#ifndef NO_KEYBOARD
case KEYBOARD_INTERFACE:
Address = &ConfigurationDescriptor.Keyboard_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#ifdef MOUSE_ENABLE
#endif
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
case MOUSE_INTERFACE:
Address = &ConfigurationDescriptor.Mouse_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#endif
#ifdef EXTRAKEY_ENABLE
case EXTRAKEY_INTERFACE:
Address = &ConfigurationDescriptor.Extrakey_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#endif
#ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE:
Address = &ConfigurationDescriptor.Console_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
case NKRO_INTERFACE:
Address = &ConfigurationDescriptor.NKRO_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
@ -610,29 +615,25 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
break;
case HID_DTYPE_Report:
switch (wIndex) {
#ifndef NO_KEYBOARD
case KEYBOARD_INTERFACE:
Address = &KeyboardReport;
Size = sizeof(KeyboardReport);
break;
#ifdef MOUSE_ENABLE
#endif
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
case MOUSE_INTERFACE:
Address = &MouseReport;
Size = sizeof(MouseReport);
break;
#endif
#ifdef EXTRAKEY_ENABLE
case EXTRAKEY_INTERFACE:
Address = &ExtrakeyReport;
Size = sizeof(ExtrakeyReport);
break;
#endif
#ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE:
Address = &ConsoleReport;
Size = sizeof(ConsoleReport);
break;
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
case NKRO_INTERFACE:
Address = &NKROReport;
Size = sizeof(NKROReport);

View file

@ -52,25 +52,20 @@ typedef struct
{
USB_Descriptor_Configuration_Header_t Config;
#ifndef NO_KEYBOARD
// Keyboard HID Interface
USB_Descriptor_Interface_t Keyboard_Interface;
USB_HID_Descriptor_HID_t Keyboard_HID;
USB_Descriptor_Endpoint_t Keyboard_INEndpoint;
#endif
#ifdef MOUSE_ENABLE
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
// Mouse HID Interface
USB_Descriptor_Interface_t Mouse_Interface;
USB_HID_Descriptor_HID_t Mouse_HID;
USB_Descriptor_Endpoint_t Mouse_INEndpoint;
#endif
#ifdef EXTRAKEY_ENABLE
// Extrakey HID Interface
USB_Descriptor_Interface_t Extrakey_Interface;
USB_HID_Descriptor_HID_t Extrakey_HID;
USB_Descriptor_Endpoint_t Extrakey_INEndpoint;
#endif
#ifdef CONSOLE_ENABLE
// Console HID Interface
USB_Descriptor_Interface_t Console_Interface;
@ -79,7 +74,7 @@ typedef struct
USB_Descriptor_Endpoint_t Console_OUTEndpoint;
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
// NKRO HID Interface
USB_Descriptor_Interface_t NKRO_Interface;
USB_HID_Descriptor_HID_t NKRO_HID;
@ -89,27 +84,25 @@ typedef struct
/* index of interface */
#define KEYBOARD_INTERFACE 0
#ifndef NO_KEYBOARD
# define KEYBOARD_INTERFACE 0
#else
# define KEYBOARD_INTERFACE -1
#endif
#ifdef MOUSE_ENABLE
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
# define MOUSE_INTERFACE (KEYBOARD_INTERFACE + 1)
#else
# define MOUSE_INTERFACE KEYBOARD_INTERFACE
#endif
#ifdef EXTRAKEY_ENABLE
# define EXTRAKEY_INTERFACE (MOUSE_INTERFACE + 1)
#else
# define EXTRAKEY_INTERFACE MOUSE_INTERFACE
#endif
#ifdef CONSOLE_ENABLE
# define CONSOLE_INTERFACE (EXTRAKEY_INTERFACE + 1)
# define CONSOLE_INTERFACE (MOUSE_INTERFACE + 1)
#else
# define CONSOLE_INTERFACE EXTRAKEY_INTERFACE
# define CONSOLE_INTERFACE MOUSE_INTERFACE
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
# define NKRO_INTERFACE (CONSOLE_INTERFACE + 1)
#else
# define NKRO_INTERFACE CONSOLE_INTERFACE
@ -121,28 +114,26 @@ typedef struct
// Endopoint number and size
#define KEYBOARD_IN_EPNUM 1
#ifndef NO_KEYBOARD
# define KEYBOARD_IN_EPNUM 1
#else
# define KEYBOARD_IN_EPNUM 0
#endif
#ifdef MOUSE_ENABLE
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
# define MOUSE_IN_EPNUM (KEYBOARD_IN_EPNUM + 1)
#else
# define MOUSE_IN_EPNUM KEYBOARD_IN_EPNUM
#endif
#ifdef EXTRAKEY_ENABLE
# define EXTRAKEY_IN_EPNUM (MOUSE_IN_EPNUM + 1)
#else
# define EXTRAKEY_IN_EPNUM MOUSE_IN_EPNUM
#endif
#ifdef CONSOLE_ENABLE
# define CONSOLE_IN_EPNUM (EXTRAKEY_IN_EPNUM + 1)
# define CONSOLE_OUT_EPNUM (EXTRAKEY_IN_EPNUM + 1)
# define CONSOLE_IN_EPNUM (MOUSE_IN_EPNUM + 1)
# define CONSOLE_OUT_EPNUM (MOUSE_IN_EPNUM + 1)
#else
# define CONSOLE_OUT_EPNUM EXTRAKEY_IN_EPNUM
# define CONSOLE_OUT_EPNUM MOUSE_IN_EPNUM
#endif
#ifdef NKRO_ENABLE
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
# define NKRO_IN_EPNUM (CONSOLE_OUT_EPNUM + 1)
#else
# define NKRO_IN_EPNUM CONSOLE_OUT_EPNUM
@ -150,13 +141,18 @@ typedef struct
/* Check number of endpoints. ATmega32u2 has only four except for control endpoint. */
#if defined(__AVR_ATmega32U2__) && NKRO_IN_EPNUM > 4
# error "Endpoints are not available enough to support all functions. Disable some of build options in Makefile.(MOUSEKEY, EXTRAKEY, CONSOLE, NKRO)"
# error "Endpoints are not available enough to support all functions. Disable some of build options in Makefile.(MOUSEKEY, CONSOLE, NKRO)"
#endif
#define KEYBOARD_EPSIZE 8
#if defined(MOUSE_EXT_REPORT)
#define MOUSE_EPSIZE 10
#else
#define MOUSE_EPSIZE 8
#define EXTRAKEY_EPSIZE 8
#endif
#define CONSOLE_EPSIZE 32
#define NKRO_EPSIZE 32

View file

@ -68,26 +68,35 @@
//#define TMK_LUFA_DEBUG
#ifndef NO_KEYBOARD
uint8_t keyboard_idle = 0;
/* 0: Boot Protocol, 1: Report Protocol(default) */
uint8_t keyboard_protocol = 1;
static uint8_t keyboard_led_stats = 0;
static report_keyboard_t keyboard_report_sent;
#endif
#ifdef MOUSE_ENABLE
uint8_t mouse_protocol = 1;
#endif
/* Host driver */
#ifndef NO_KEYBOARD
static uint8_t keyboard_leds(void);
static void send_keyboard(report_keyboard_t *report);
#endif
static void send_mouse(report_mouse_t *report);
static void send_system(uint16_t data);
static void send_consumer(uint16_t data);
host_driver_t lufa_driver = {
keyboard_leds,
send_keyboard,
send_mouse,
send_system,
send_consumer
#ifndef NO_KEYBOARD
.keyboard_leds = keyboard_leds,
.send_keyboard = send_keyboard,
#endif
.send_mouse = send_mouse,
.send_system = send_system,
.send_consumer = send_consumer
};
@ -327,22 +336,23 @@ void EVENT_USB_Device_ConfigurationChanged(void)
#endif
bool ConfigSuccess = true;
#ifndef NO_KEYBOARD
/* Setup Keyboard HID Report Endpoints */
ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
#ifdef NKRO_ENABLE
NKRO_EPSIZE,
#else
KEYBOARD_EPSIZE,
#endif
ENDPOINT_BANK_SINGLE);
#endif
#ifdef MOUSE_ENABLE
#if defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)
/* Setup Mouse HID Report Endpoint */
ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
#endif
#ifdef EXTRAKEY_ENABLE
/* Setup Extra HID Report Endpoint */
ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
#endif
#ifdef CONSOLE_ENABLE
/* Setup Console HID Report Endpoints */
ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
@ -353,7 +363,7 @@ void EVENT_USB_Device_ConfigurationChanged(void)
#endif
#endif
#ifdef NKRO_ENABLE
#ifdef NKRO_6KRO_ENABLE
/* Setup NKRO HID Report Endpoints */
ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
@ -378,15 +388,16 @@ Other Device Required Optional Optional Optional Optional Opti
*/
void EVENT_USB_Device_ControlRequest(void)
{
uint8_t* ReportData = NULL;
uint8_t ReportSize = 0;
/* Handle HID Class specific requests */
switch (USB_ControlRequest.bRequest)
{
case HID_REQ_GetReport:
#ifndef NO_KEYBOARD
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
uint8_t* ReportData = NULL;
uint8_t ReportSize = 0;
Endpoint_ClearSETUP();
// Interface
@ -405,6 +416,7 @@ void EVENT_USB_Device_ControlRequest(void)
xprintf("[r%d]", USB_ControlRequest.wIndex);
#endif
}
#endif
break;
case HID_REQ_SetReport:
@ -413,8 +425,9 @@ void EVENT_USB_Device_ControlRequest(void)
// Interface
switch (USB_ControlRequest.wIndex) {
#ifndef NO_KEYBOARD
case KEYBOARD_INTERFACE:
#ifdef NKRO_ENABLE
#ifdef NKRO_6KRO_ENABLE
case NKRO_INTERFACE:
#endif
Endpoint_ClearSETUP();
@ -431,6 +444,7 @@ void EVENT_USB_Device_ControlRequest(void)
xprintf("[L%d]", USB_ControlRequest.wIndex);
#endif
break;
#endif
}
}
@ -440,6 +454,7 @@ void EVENT_USB_Device_ControlRequest(void)
case HID_REQ_GetProtocol:
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
#ifndef NO_KEYBOARD
if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
Endpoint_ClearSETUP();
while (!(Endpoint_IsINReady()));
@ -450,12 +465,23 @@ void EVENT_USB_Device_ControlRequest(void)
print("[p]");
#endif
}
#endif
#if defined(MOUSE_ENABLE)
if (USB_ControlRequest.wIndex == MOUSE_INTERFACE) {
Endpoint_ClearSETUP();
while (!(Endpoint_IsINReady()));
Endpoint_Write_8(mouse_protocol);
Endpoint_ClearIN();
Endpoint_ClearStatusStage();
}
#endif
}
break;
case HID_REQ_SetProtocol:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
#ifndef NO_KEYBOARD
if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
@ -466,18 +492,30 @@ void EVENT_USB_Device_ControlRequest(void)
print("[P]");
#endif
}
#endif
#if defined(MOUSE_ENABLE)
if (USB_ControlRequest.wIndex == MOUSE_INTERFACE) {
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
mouse_protocol = (USB_ControlRequest.wValue & 0xFF);
clear_keyboard();
}
#endif
}
break;
case HID_REQ_SetIdle:
if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
{
#ifndef NO_KEYBOARD
Endpoint_ClearSETUP();
Endpoint_ClearStatusStage();
keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
#ifdef TMK_LUFA_DEBUG
xprintf("[I%d]%d", USB_ControlRequest.wIndex, (USB_ControlRequest.wValue & 0xFF00) >> 8);
#endif
#endif
}
@ -485,6 +523,7 @@ void EVENT_USB_Device_ControlRequest(void)
case HID_REQ_GetIdle:
if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
{
#ifndef NO_KEYBOARD
Endpoint_ClearSETUP();
while (!(Endpoint_IsINReady()));
Endpoint_Write_8(keyboard_idle);
@ -492,6 +531,7 @@ void EVENT_USB_Device_ControlRequest(void)
Endpoint_ClearStatusStage();
#ifdef TMK_LUFA_DEBUG
print("[i]");
#endif
#endif
}
@ -502,6 +542,7 @@ void EVENT_USB_Device_ControlRequest(void)
/*******************************************************************************
* Host driver
******************************************************************************/
#ifndef NO_KEYBOARD
static uint8_t keyboard_leds(void)
{
return keyboard_led_stats;
@ -515,10 +556,14 @@ static void send_keyboard(report_keyboard_t *report)
return;
/* Select the Keyboard Report Endpoint */
#ifdef NKRO_ENABLE
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
if (keyboard_protocol && keyboard_nkro) {
/* Report protocol - NKRO */
#if defined(NKRO_6KRO_ENABLE)
Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
#else
Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
#endif
/* Check if write ready for a polling interval around 1ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(8);
@ -546,6 +591,7 @@ static void send_keyboard(report_keyboard_t *report)
keyboard_report_sent = *report;
}
#endif
static void send_mouse(report_mouse_t *report)
{
@ -563,7 +609,14 @@ static void send_mouse(report_mouse_t *report)
if (!Endpoint_IsReadWriteAllowed()) return;
/* Write Mouse Report Data */
Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
if (mouse_protocol) {
// Report
Endpoint_Write_8(REPORT_ID_MOUSE);
Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
} else {
// Boot
Endpoint_Write_Stream_LE(report, 3, NULL);
}
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();
@ -578,11 +631,13 @@ static void send_system(uint16_t data)
if (USB_DeviceState != DEVICE_STATE_Configured)
return;
report_extra_t r = {
.report_id = REPORT_ID_SYSTEM,
.usage = data - SYSTEM_POWER_DOWN + 1
};
Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
report_extra_t r = { .report_id = REPORT_ID_SYSTEM };
if (data < SYSTEM_POWER_DOWN) {
r.usage = 0;
} else {
r.usage = data - SYSTEM_POWER_DOWN + 1;
}
Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
/* Check if write ready for a polling interval around 10ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
@ -605,7 +660,7 @@ static void send_consumer(uint16_t data)
.report_id = REPORT_ID_CONSUMER,
.usage = data
};
Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
/* Check if write ready for a polling interval around 10ms */
while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
@ -677,17 +732,32 @@ int main(void)
print_set_sendchar(sendchar);
host_set_driver(&lufa_driver);
print("\n\nTMK:" STR(TMK_VERSION) "/LUFA\n\n");
print("\nTMK:" STR(TMK_VERSION) "/LUFA:" STR(TMK_LUFA_VERSION)
#ifdef TMK_USB_HOST_SHIELD_VERSION
"/UHS2:" STR(TMK_USB_HOST_SHIELD_VERSION)
#endif
"\n");
hook_early_init();
#ifndef NO_KEYBOARD
keyboard_setup();
#endif
setup_usb();
#ifdef SLEEP_LED_ENABLE
sleep_led_init();
#endif
sei();
#ifndef NO_KEYBOARD
keyboard_init();
#else
// TODO: keyboard_init() should be used only for things related to keyboard
timer_init();
#endif
#ifndef NO_USB_STARTUP_WAIT_LOOP
/* wait for USB startup */
@ -704,7 +774,7 @@ int main(void)
hook_late_init();
print("\nKeyboard start.\n");
print("\nLoop start.\n");
while (1) {
#ifndef NO_USB_SUSPEND_LOOP
while (USB_DeviceState == DEVICE_STATE_Suspended) {
@ -712,7 +782,11 @@ int main(void)
}
#endif
hook_main_loop();
#ifndef NO_KEYBOARD
keyboard_task();
#endif
#ifdef CONSOLE_ENABLE
console_task();
@ -732,10 +806,13 @@ void hook_early_init(void) {}
__attribute__((weak))
void hook_late_init(void) {}
#ifndef NO_KEYBOARD
static uint8_t _led_stats = 0;
#endif
__attribute__((weak))
void hook_usb_suspend_entry(void)
{
#ifndef NO_KEYBOARD
// Turn off LED to save power and keep its status to resotre it later.
// LED status will be updated by keyboard_task() in main loop hopefully.
_led_stats = keyboard_led_stats;
@ -745,6 +822,7 @@ void hook_usb_suspend_entry(void)
matrix_clear();
clear_keyboard();
#endif
#ifdef SLEEP_LED_ENABLE
sleep_led_enable();
#endif
@ -770,8 +848,10 @@ void hook_usb_wakeup(void)
sleep_led_disable();
#endif
#ifndef NO_KEYBOARD
// Restore LED status and update at keyboard_task() in main loop
keyboard_led_stats = _led_stats;
#endif
// Calling long task here can prevent USB state transition
}

View file

@ -12,6 +12,10 @@ USB_HOST_SHIELD_SRC = \
$(USB_HOST_SHIELD_DIR)/parsetools.cpp \
$(USB_HOST_SHIELD_DIR)/message.cpp
# Version string
TMK_USB_HOST_SHIELD_VERSION := $(shell (cd $(TMK_DIR)/$(USB_HOST_SHIELD_DIR); git rev-parse --short=6 HEAD || echo 'unknown') 2> /dev/null)
OPT_DEFS += -DTMK_USB_HOST_SHIELD_VERSION=$(TMK_USB_HOST_SHIELD_VERSION)
#

@ -1 +1 @@
Subproject commit b6128f252700a8dd2d12400c55680ef67cdcac86
Subproject commit 96112d43858b5c5327565c36bd8ea2192ec77d1b

View file

@ -51,8 +51,10 @@ size_t Serial_::write(uint8_t c)
size_t Serial_::write(const uint8_t *buffer, size_t size)
{
sendchar(*buffer);
return 1;
for (int i = 0; i < size; i++) {
sendchar(buffer[i]);
}
return size;
}
Serial_::operator bool() {

View file

@ -334,10 +334,10 @@ MSG_CREATING_LIBRARY = Creating library:
# Define all object files.
OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(patsubst %.cpp,$(OBJDIR)/%.o,$(patsubst %.S,$(OBJDIR)/%.o,$(SRC))))
OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(patsubst %.cpp,$(OBJDIR)/%.cpp.o,$(patsubst %.S,$(OBJDIR)/%.o,$(SRC))))
# Define all listing files.
LST = $(patsubst %.c,$(OBJDIR)/%.lst,$(patsubst %.cpp,$(OBJDIR)/%.lst,$(patsubst %.S,$(OBJDIR)/%.lst,$(SRC))))
LST = $(patsubst %.c,$(OBJDIR)/%.lst,$(patsubst %.cpp,$(OBJDIR)/%.cpp.lst,$(patsubst %.S,$(OBJDIR)/%.lst,$(SRC))))
# Compiler flags to generate dependency files.
@ -348,9 +348,9 @@ GENDEPFLAGS = -MMD -MP -MF .dep/$(subst /,_,$@).d
# Combine all necessary flags and optional flags.
# Add target processor to flags.
# You can give extra flags at 'make' command line like: make EXTRAFLAGS=-DFOO=bar
ALL_CFLAGS = -mmcu=$(MCU) $(CFLAGS) $(GENDEPFLAGS) $(EXTRAFLAGS)
ALL_CPPFLAGS = -mmcu=$(MCU) -x c++ $(CPPFLAGS) $(GENDEPFLAGS) $(EXTRAFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -x assembler-with-cpp $(ASFLAGS) $(EXTRAFLAGS)
ALL_CFLAGS = -mmcu=$(MCU) $(CFLAGS) $(GENDEPFLAGS) $(EXTRAFLAGS) $(EXTRACFLAGS)
ALL_CPPFLAGS = -mmcu=$(MCU) -x c++ $(CPPFLAGS) $(GENDEPFLAGS) $(EXTRAFLAGS) $(EXTRACPPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -x assembler-with-cpp $(ASFLAGS) $(EXTRAFLAGS) $(EXTRAASFLAGS)
@ -561,7 +561,7 @@ $(OBJDIR)/%.o : %.c
# Compile: create object files from C++ source files.
$(OBJDIR)/%.o : %.cpp
$(OBJDIR)/%.cpp.o : %.cpp
@echo
mkdir -p $(@D)
@echo $(MSG_COMPILING_CPP) $<