Merge remote-tracking branch 'tmk/master'

This commit is contained in:
Mark Sikora 2022-03-06 10:57:13 -05:00
commit c9659f3048
48 changed files with 14033 additions and 14737 deletions

220
README.md
View file

@ -1,80 +1,16 @@
TMK Keyboard Firmware Collection
================================
This repository includes keyboard and converter firmware projects built with [`tmk_core`][tmk_core] keyboard library.
This repository includes keyboard and converter firmware projects built with [`tmk_core`](https://github.com/tmk/tmk_core) keyboard library.
The latest source code is available here: <http://github.com/tmk/tmk_keyboard>
Updates
-------
#### 2017/01/11
Changed action code for `ACTION_LAYER_MODS` and this may cause incompatibility with existent shared URL and downloaded firmwware of keymap editor. If you are using the action you just have to redefine it on keymap editor. Existent keymap code should not suffer.
#### 2016/06/26
Keymap framework was updated. `fn_actions[]` should be defined as `action_t` instead of `uint16_t`. And default code for keymap handling is now included in core you just need define `uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS]` and `action_t fn_actions[]`.
Documentation
-------------
Refer to wiki pages for further info.
#### 2016/06/22
Some projects were moved from `converter` and `keyboard` to `orphan` directory. Those might be removed in some future but you will be able to access them with `orphans` tag. See <https://github.com/tmk/tmk_keyboard/issues/173>
#### 2016/02/10
core: flabbergast's Chibios protocol was merged from <https://github.com/flabbergast/tmk_keyboard/tree/chibios> (@72b1668). See [tmk_core/protocol/chibios/README.md](tmk_core/protocol/chibios/README.md). Chibios protocol supports Cortex-M such as STM32 and Kinetis.
#### 2015/04/22
Core library was separated to other branch `core`. <https://github.com/tmk/tmk_keyboard/tree/core>
In `Makefile` you need to set `TMK_DIR` to indicate core library location now.
TMK_DIR = ../../tmk_core
Projects
--------
You can find some keyboard specific projects under `converter` and `keyboard` directory.
### converter
* [ps2_usb](converter/ps2_usb/) - [PS/2 keyboard to USB][GH_ps2]
* [adb_usb](converter/adb_usb/) - [ADB keyboard to USB][GH_adb]
* [m0110_usb](converter/m0110_usb) - [Macintosh 128K/512K/Plus keyboard to USB][GH_m0110]
* [terminal_usb](converter/terminal_usb/) - [IBM Model M terminal keyboard(PS/2 scancode set3) to USB][GH_terminal]
* [news_usb](converter/news_usb/) - [Sony NEWS keyboard to USB][GH_news]
* [x68k_usb](converter/x68k_usb/) - [Sharp X68000 keyboard to USB][GH_x68k]
* [sun_usb](converter/sun_usb/) - [Sun] to USB(type4, 5 and 3?)
* [pc98_usb](converter/pc98_usb/) - [PC98] to USB
* [usb_usb](converter/usb_usb/) - [USB to USB][GH_usb]
* [ibm4704_usb](converter/ibm4704_usb) - [IBM 4704 keyboard to USB][GH_ibm4704]
* [next_usb](converter/next_usb) - NeXT(Non-ADB) to USB, contributed by [BCG](https://github.com/bgould) and based on [Adafruit's work](https://learn.adafruit.com/usb-next-keyboard-with-arduino-micro/overview)
### keyboard
* [hhkb](keyboard/hhkb/) - [Happy Hacking Keyboard pro][GH_hhkb] **my main board**
* [alps64](keyboard/alps64/) - [Alps64 PCB](https://geekhack.org/index.php?topic=69740.0)
* [hbkb](keyboard/hbkb/) - [Happy Buckling spring keyboard][GH_hbkb](IBM Model M 60% mod)
* [Infinity](keyboard/infinity/) - Massdrop [Infinity keyboard][Infinity]
* [gh60](keyboard/gh60/) - [GH60] DIY 60% keyboard [prototype][GH60_proto] **my second board**
* [onekey](keyboard/onekey/) - Simple one key keyboard example
### Projects based tmk_keyboard or tmk_core
https://github.com/tmk/tmk_keyboard/wiki/TMK-Based-Projects
[GH_hhkb]: http://geekhack.org/showwiki.php?title=Island:12047
[GH_ps2]: http://geekhack.org/showwiki.php?title=Island:14618
[GH_adb]: http://geekhack.org/showwiki.php?title=Island:14290
[GH_hhkb_bt]: http://geekhack.org/showwiki.php?title=Island:20851
[GH_m0110]: http://geekhack.org/showwiki.php?title=Island:24965
[GH_news]: http://geekhack.org/showwiki.php?title=Island:25759
[GH_terminal]: http://geekhack.org/showwiki.php?title=Island:27272
[GH_x68k]: http://geekhack.org/showwiki.php?title=Island:29060
[GH_hbkb]: http://geekhack.org/showwiki.php?title=Island:29483
[GH_ibm4704]: http://geekhack.org/index.php?topic=54706.0
[GH60]: http://geekhack.org/index.php?topic=34959
[GH60_proto]: http://geekhack.org/index.php?topic=37570.0
[PC98]: http://en.wikipedia.org/wiki/NEC_PC-9801
[Sun]: http://en.wikipedia.org/wiki/Sun-3
[Infinity]: https://www.massdrop.com/buy/infinity-keyboard-kit
[tmk_core]: https://github.com/tmk/tmk_core
https://github.com/tmk/tmk_keyboard/wiki
@ -83,149 +19,3 @@ License
**GPLv2** or later. Some protocol files are under **Modified BSD License**.
Third party libraries like LUFA, PJRC and V-USB have their own license respectively.
Build Firmware and Program Controller
-------------------------------------
See [tmk_core/doc/build.md](tmk_core/doc/build.md).
Change your keymap
------------------
See [tmk_core/doc/keymap.md](tmk_core/doc/keymap.md).
Magic Commands
--------------
To see help press `Magic` + `H`.
`Magic` key combination is `LShift` + `RShift` in many projects, but `Power` key on ADB converter.
`Magic` keybind can be vary on each project, check `config.h` in project directory.
Following commands can be also executed with `Magic` + key. In console mode `Magic` keybind is not needed.
----- Command Help -----
c: enter console mode
d: toggle debug enable
x: toggle matrix debug
k: toggle keyboard debug
m: toggle mouse debug
v: print device version & info
t: print timer count
s: print status
e: print eeprom config
n: toggle NKRO
0/F10: switch to Layer0
1/F1: switch to Layer1
2/F2: switch to Layer2
3/F3: switch to Layer3
4/F4: switch to Layer4
PScr: power down/remote wake-up
Caps: Lock Keyboard(Child Proof)
Paus: jump to bootloader
Boot Magic Configuration - Virtual DIP Switch
---------------------------------------------
Boot Magic are executed during boot up time. Press Magic key below then plug in keyboard cable.
Note that you must use keys of **Layer 0** as Magic keys. These settings are stored in EEPROM so that retain your configure over power cycles.
To avoid configuring accidentally additive salt key `KC_SPACE` also needs to be pressed along with the following configuration keys. The salt key is configurable in `config.h`. See [tmk_core/common/bootmagic.h](tmk_core/common/bootmagic.h).
#### General
- Skip reading EEPROM to start with default configuration(`ESC`)
- Clear configuration stored in EEPROM to reset configuration(`Backspace`)
#### Bootloader
- Kick up Bootloader(`B`)
#### Debug
- Debug enable(`D`)
- Debug matrix enable(`D`+`X`)
- Debug keyboard enable(`D`+`K`)
- Debug mouse enable(`D`+`M`)
#### Keymap
- Swap Control and CapsLock(`Left Control`)
- Change CapsLock to Control(`Caps Lock`)
- Swap LeftAlt and Gui(`Left Alt`)
- Swap RightAlt and Gui(`Right Alt`)
- Disable Gui(`Left Gui`)
- Swap Grave and Escape(`Grave`)
- Swap BackSlash and BackSpace(`Back Slash`)
- Enable NKRO on boot(`N`)
#### Default Layer
- Set Default Layer to 0(`0`)
- Set Default Layer to 1(`1`)
- Set Default Layer to 2(`2`)
- Set Default Layer to 3(`3`)
- Set Default Layer to 4(`4`)
- Set Default Layer to 5(`5`)
- Set Default Layer to 6(`6`)
- Set Default Layer to 7(`7`)
Mechanical Locking support
--------------------------
This feature makes it possible for you to use mechanical locking switch for `CapsLock`, `NumLock`
or `ScrollLock`. To enable this feature define these macros in `config.h` and use `KC_LCAP`, `KC_LN
UM` or `KC_LSCR` in keymap for locking key instead of normal `KC_CAPS`, `KC_NLCK` or `KC_SLCK`. Res
ync option tries to keep switch state consistent with keyboard LED state.
#define LOCKING_SUPPORT_ENABLE
#define LOCKING_RESYNC_ENABLE
Start Your Own Project
-----------------------
1. Add `tmk_core` into your repository using `git submodule` or `git subtree`.
2. Copy files from `tmk_keybaord` or other project similar to yours
3. Edit those files to support your keyboard.
See these as examples.
- https://github.com/tmk/infinity_ergodox
- https://github.com/tmk/whitefox
Debugging
--------
Use PJRC's `hid_listen` to see debug messages. You can use xprintf() to display debug info, see `tmk_core/common/xprintf.h`.
- https://www.pjrc.com/teensy/hid_listen.html
Files and Directories
-------------------
### Top
* keyboard/ - keyboard projects
* converter/ - protocol converter projects
* tmk_core/ - core library
* tmk_core/doc/ - documents
Contribution
------------
- Report bugs in github **[Issues](https://github.com/tmk/tmk_keyboard/issues)**.
- Pull requets are also welcomed.
Coding Style
-------------
- Doesn't use Tab to indent, use 4-spaces instead.
Other Keyboard Firmware Projects
------------------
You can learn a lot about keyboard firmware from these. See [Other Projects](https://github.com/tmk/tmk_keyboard/wiki/Other-Protjects) other than TMK.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -41,7 +41,7 @@ static bool is_iso_layout = false;
#if ADB_MOUSE_ENABLE
#define dmprintf(fmt, ...) do { /* if (debug_mouse) */ xprintf("M:" fmt, ##__VA_ARGS__); } while (0)
static uint16_t mouse_cpi = 100;
static void mouse_init(uint8_t addr);
static void mouse_init(void);
#endif
// matrix state buffer(1:on, 0:off)
@ -58,6 +58,65 @@ static void device_scan(void)
xprintf(" addr:%d, reg3:%04X\n", addr, reg3);
}
}
xprintf("\n");
}
static void keyboard_init(void)
{
uint16_t reg3;
uint8_t handler;
// Check if there is keyboard at default address
reg3 = adb_host_talk(ADB_ADDR_KEYBOARD, ADB_REG_3);
if (!reg3) return;
if (reg3) {
xprintf("K:found: addr:" xstr(ADB_ADDR_KEYBOARD) " reg3:%04X\n", reg3);
adb_host_listen(ADB_ADDR_KEYBOARD, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_KBD_TMP, 0xFE);
}
// Check if there is device to setup at temporary address
reg3 = adb_host_talk(ADB_ADDR_KBD_TMP, ADB_REG_3);
if (!reg3) {
xprintf("K:fail: move\n");
return;
}
// Determine ISO keyboard by handler id
// http://lxr.free-electrons.com/source/drivers/macintosh/adbhid.c?v=4.4#L815
handler = reg3 & 0xFF;
switch (handler) {
case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D:
case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1:
case 0xC4: case 0xC7:
is_iso_layout = true;
break;
default:
is_iso_layout = false;
break;
}
// Adjustable keyboard media keys: address=0x07 and handlerID=0x02
has_media_keys = (0x02 == (adb_host_talk(ADB_ADDR_APPLIANCE, ADB_REG_3) & 0xff));
if (has_media_keys) {
xprintf("K:Media keys\n");
}
// Enable keyboard left/right modifier distinction
// Listen Register3
// upper byte: reserved bits 0000, keyboard address 0010
// lower byte: device handler 00000011
adb_host_listen(ADB_ADDR_KBD_TMP, ADB_REG_3, ADB_ADDR_KBD_TMP, ADB_HANDLER_EXTENDED_KEYBOARD);
reg3 = adb_host_talk(ADB_ADDR_KBD_TMP, ADB_REG_3);
adb_host_kbd_led(ADB_ADDR_KBD_TMP, ~(host_keyboard_leds()));
// Move to keyboard polling address
adb_host_listen(ADB_ADDR_KBD_TMP, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_KBD_POLL, 0xFE);
if (adb_host_talk(ADB_ADDR_KBD_TMP, ADB_REG_3)) {
xprintf("K:fail: move\n");
}
xprintf("K:setup: addr:" xstr(ADB_ADDR_KBD_POLL) " reg3:%04X, ISO:%s\n",
reg3, (is_iso_layout ? "yes" : "no"));
}
void matrix_init(void)
@ -81,106 +140,69 @@ void matrix_init(void)
// M0115J(AEK), M3501(AEKII), M0116(Standard), M1242(Adjustable),
// G5431(Mouse), 64210(Kensington Trubo Mouse 5)
wait_ms(1000);
device_scan();
//
// Keyboard
//
xprintf("\nKeyboard:\n");
// Determine ISO keyboard by handler id
// http://lxr.free-electrons.com/source/drivers/macintosh/adbhid.c?v=4.4#L815
uint8_t handler_id = (uint8_t) adb_host_talk(ADB_ADDR_KEYBOARD, ADB_REG_3);
switch (handler_id) {
case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D:
case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1:
case 0xC4: case 0xC7:
is_iso_layout = true;
break;
default:
is_iso_layout = false;
break;
}
xprintf("handler: %02X, ISO: %s\n", handler_id, (is_iso_layout ? "yes" : "no"));
// Adjustable keyboard media keys: address=0x07 and handlerID=0x02
has_media_keys = (0x02 == (adb_host_talk(ADB_ADDR_APPLIANCE, ADB_REG_3) & 0xff));
if (has_media_keys) {
xprintf("Media keys\n");
}
// Enable keyboard left/right modifier distinction
// Listen Register3
// upper byte: reserved bits 0000, keyboard address 0010
// lower byte: device handler 00000011
adb_host_listen(ADB_ADDR_KEYBOARD, ADB_REG_3, ADB_ADDR_KEYBOARD, ADB_HANDLER_EXTENDED_KEYBOARD);
// initialize matrix state: all keys off
for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
led_set(host_keyboard_leds());
device_scan();
// LED off
DDRD |= (1<<6); PORTD &= ~(1<<6);
return;
}
#ifdef ADB_MOUSE_ENABLE
static void mouse_init(uint8_t orig_addr)
static void mouse_init(void)
{
uint16_t reg3;
uint8_t mouse_handler;
uint8_t addr;
again:
// Move to tmp address 15 to setup mouse function
mouse_handler = (reg3 = adb_host_talk(orig_addr, ADB_REG_3)) & 0xFF;
if (!reg3) return;
dmprintf("addr%d reg3: %04X\n", orig_addr, reg3);
// Move device to tmp address
adb_host_flush(orig_addr);
adb_host_listen(orig_addr, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_TMP, 0xFE);
adb_host_flush(ADB_ADDR_TMP);
mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_TMP, ADB_REG_3)) & 0xFF;
if (!reg3) {
dmprintf("move fail\n");
goto again;
// Check if there is mouse device at default address 3
reg3 = adb_host_talk(ADB_ADDR_MOUSE, ADB_REG_3);
if (reg3) {
// Move device to tmp address
// Collision detection can fail sometimes in fact when two devices are connected on startup
// and the devices can be moved to tmp address at same time in the result. In that case
// initialization of mouse can fail. To recover this you may have to replug mouse or converter.
// It is safe to have just one mouse device, but more than one device can be handled somehow.
adb_host_flush(ADB_ADDR_MOUSE);
adb_host_listen(ADB_ADDR_MOUSE, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_MOUSE_TMP, 0xFE);
adb_host_flush(ADB_ADDR_MOUSE_TMP);
}
addr = ADB_ADDR_TMP;
// Check if there is mouse device to setup at temporary address 15
mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_MOUSE_TMP, ADB_REG_3)) & 0xFF;
if (!reg3) {
return;
}
dmprintf("TMP: reg3:%04X\n", reg3);
detect_again:
// Try to escalate into extended/classic2 protocol
if (mouse_handler == ADB_HANDLER_CLASSIC1_MOUSE || mouse_handler == ADB_HANDLER_CLASSIC2_MOUSE) {
adb_host_flush(addr);
adb_host_listen(addr, ADB_REG_3, (reg3 >> 8), ADB_HANDLER_EXTENDED_MOUSE);
mouse_handler = (reg3 = adb_host_talk(addr, ADB_REG_3)) & 0xFF;
adb_host_flush(ADB_ADDR_MOUSE_TMP);
adb_host_listen(ADB_ADDR_MOUSE_TMP, ADB_REG_3, (reg3 >> 8), ADB_HANDLER_EXTENDED_MOUSE);
mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_MOUSE_TMP, ADB_REG_3)) & 0xFF;
if (mouse_handler == ADB_HANDLER_CLASSIC1_MOUSE) {
adb_host_flush(addr);
adb_host_listen(addr, ADB_REG_3, (reg3 >> 8), ADB_HANDLER_CLASSIC2_MOUSE);
mouse_handler = (reg3 = adb_host_talk(addr, ADB_REG_3)) & 0xFF;
adb_host_flush(ADB_ADDR_MOUSE_TMP);
adb_host_listen(ADB_ADDR_MOUSE_TMP, ADB_REG_3, (reg3 >> 8), ADB_HANDLER_CLASSIC2_MOUSE);
mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_MOUSE_TMP, ADB_REG_3)) & 0xFF;
}
dmprintf("addr%d reg3: %04X\n", addr, reg3);
dmprintf("EXT: reg3:%04X\n", reg3);
}
// Classic Protocol 100cpi
if (mouse_handler == ADB_HANDLER_CLASSIC1_MOUSE) {
xprintf("Classic 100cpi\n");
dmprintf("Classic 100cpi\n");
mouse_cpi = 100;
}
// Classic Protocol 200cpi
if (mouse_handler == ADB_HANDLER_CLASSIC2_MOUSE) {
xprintf("Classic 200cpi\n");
dmprintf("Classic 200cpi\n");
mouse_cpi = 200;
}
@ -193,7 +215,7 @@ detect_again:
// 7 : num of buttons
uint8_t len;
uint8_t buf[8];
len = adb_host_talk_buf(addr, ADB_REG_1, buf, sizeof(buf));
len = adb_host_talk_buf(ADB_ADDR_MOUSE_TMP, ADB_REG_1, buf, sizeof(buf));
if (len > 5) {
mouse_cpi = (buf[4]<<8) | buf[5];
@ -202,15 +224,13 @@ detect_again:
}
if (len) {
xprintf("Ext: [", len);
for (int8_t i = 0; i < len; i++) xprintf("%02X ", buf[i]);
xprintf("] cpi=%d\n", mouse_cpi);
dmprintf("EXT: [%02X %02X %02X %02X %02X %02X %02X %02X] cpi=%d\n",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], mouse_cpi);
}
// Kensington Turbo Mouse 5: default device
if (buf[0] == 0x4B && buf[1] == 0x4D && buf[2] == 0x4C && buf[3] == 0x31) {
xprintf("TM5: default\n");
dmprintf("TM5: found\n");
// Move it to addr0 to remove this device and get new device with handle id 50 on addr 3
// and the new device on address 3 should be handled with command sequence later.
//
@ -219,77 +239,77 @@ detect_again:
// The mouse has the two devices at same time transiently in the result. The default device is
// removed automatically after the another device receives command sequence.
// NOTE: The mouse hangs if you try moving the two deivces to same address.
adb_host_flush(addr);
adb_host_listen(addr, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_0, 0xFE);
adb_host_flush(ADB_ADDR_MOUSE_TMP);
adb_host_listen(ADB_ADDR_MOUSE_TMP, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_0, 0xFE);
goto again;
} else {
xprintf("Unknown\n");
dmprintf("Unknown\n");
}
}
// Kensington Turbo Mouse 5: setup
if (mouse_handler == ADB_HANDLER_TURBO_MOUSE) {
xprintf("TM5: ext\n");
xprintf("TM5: setup\n");
/* byte0: speed
* 0xa0, 0xa5, 0xb0 and 0xb5 seem to work
* uppper nibble:
* 0x00-70, 0xc0-f0 no movement and button event
* 0x80 enables mouse output speed slow
* 0x90 enables mouse output
* 0xa0 enables mouse output
* 0xb0 enables mouse output speed fast -126 to 126
* lower nibble:
* 0x08 makes cursor not smooth, bit4 should be 0
* 0x02 disables button4, bit1 should be 0
* how other bits work is not clear.
* byte1: button mapping - upper nibble for button1 and lower for button2
* 0x14 button1 and button2 mapped as themselves
* 0x0 disabled
* 0x1 button1
* 0x2 button1 toggle
* 0x3 no effect key event FFFF
* 0x4 button2
* 0x5 button2 toggle
* 0x6 button3
* 0x7 button3 toggle
* 0x8 ?toggle weirdly?
* 0x9 button4
* 0xa button4 toggle
* 0xb ?disabled?
* 0xc Left
* 0xd Right
* 0xe Alt+Left
* 0xf Alt+Right
/* byte0: 0xb5 speed - 0xa0, 0xa5, 0xb0 and 0xb5 seem to work
* uppper nibble:
* 0x00-70, 0xc0-f0 no movement and button event
* 0x80 enables mouse output speed slow
* 0x90 enables mouse output
* 0xa0 enables mouse output
* 0xb0 enables mouse output speed fast -126 to 126
* lower nibble:
* 0x08 makes cursor not smooth, bit3 should be 0
* 0x02 disables button4, bit1 should be 0
* how other bits work is not clear.
* byte1: 0x14 button mapping - upper nibble for button1 and lower for button2
* button1 and button2 mapped as themselves
* 0x0 disabled
* 0x1 button1
* 0x2 button1 toggle
* 0x3 no effect key event FFFF
* 0x4 button2
* 0x5 button2 toggle
* 0x6 button3
* 0x7 button3 toggle
* 0x8 ?toggle weirdly?
* 0x9 button4
* 0xa button4 toggle
* 0xb ?disabled?
* 0xc Left
* 0xd Right
* 0xe Alt+Left
* 0xf Alt+Right
* byte2: 0x00 - 0x40 on powerup, seems to do nothing
* byte3: 0x00 - 0x01 on powerup, seems to do nothing
* byte4: button mapping - upper nibble for button3 and lower for button4
* 0x69 button3 and button4 mapped as themselves(see byte1)
* byte4: 0x69 button mapping - upper nibble for button3 and lower for button4
* button3 and button4 mapped as themselves(see byte1)
* byte5: 0xff unknown
* byte6: 0xff unknown
* byte7: 0xff checksum - must be 0xff before calculating
* byte7: 0x?? checksum
* byte7 = byte0 ^ byte1 ^ byte2 ^ byte3 ^ byte4 ^ byte5 ^ byte6 ^ 0xFF;
* https://github.com/NetBSD/src/blob/8966d5b1cf335756dd9bba3331e84c659bf917e1/sys/dev/adb/adb_ktm.c#L181
*/
//static uint8_t cmd[] = { 0xA5, 0x14, 0x00, 0x00, 0x69, 0xFF, 0xFF, 0xFF };
static uint8_t cmd[] = { 0xB5, 0x14, 0x00, 0x00, 0x69, 0xFF, 0xFF, 0xFF };
cmd[7] = cmd[0] ^ cmd[1] ^ cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5] ^ cmd[6] ^ cmd[7];
adb_host_flush(addr);
adb_host_listen_buf(addr, ADB_REG_2, cmd, sizeof(cmd));
uint8_t cmd[] = { 0xB5, 0x14, 0x00, 0x00, 0x69, 0xFF, 0xFF, 0x37 };
// cmd[7] = cmd[0] ^ cmd[1] ^ cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5] ^ cmd[6] ^ 0xFF;
adb_host_flush(ADB_ADDR_MOUSE_TMP);
adb_host_listen_buf(ADB_ADDR_MOUSE_TMP, ADB_REG_2, cmd, sizeof(cmd));
}
// Move to address 10 for mouse polling
adb_host_flush(addr);
adb_host_listen(addr, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_MOUSE_POLL, 0xFE);
adb_host_flush(ADB_ADDR_MOUSE_TMP);
adb_host_listen(ADB_ADDR_MOUSE_TMP, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_MOUSE_POLL, 0xFE);
adb_host_flush(ADB_ADDR_MOUSE_POLL);
mouse_handler = (reg3 = adb_host_talk(addr, ADB_REG_3)) & 0xFF;
reg3 = adb_host_talk(ADB_ADDR_MOUSE_TMP, ADB_REG_3);
if (reg3) {
dmprintf("detect again\n");
goto detect_again;
dmprintf("POL: fail reg3:%04X\n", reg3);
} else {
dmprintf("POL: done\n");
}
goto again;
device_scan();
return;
}
static report_mouse_t mouse_report = {};
@ -315,7 +335,7 @@ void adb_mouse_task(void)
if (timer_elapsed(detect_ms) > 1000) {
detect_ms = timer_read();
// check new device on addr3
mouse_init(ADB_ADDR_MOUSE);
mouse_init();
}
// Extended Mouse Protocol data can be 2-5 bytes
@ -414,6 +434,11 @@ void adb_mouse_task(void)
return;
}
uint8_t adb_mouse_buttons(void)
{
return mouse_report.buttons;
}
#endif
uint8_t matrix_scan(void)
@ -440,7 +465,7 @@ uint8_t matrix_scan(void)
if (timer_elapsed(tick_ms) < 12) return 0;
tick_ms = timer_read();
codes = adb_host_kbd_recv(ADB_ADDR_KEYBOARD);
codes = adb_host_kbd_recv(ADB_ADDR_KBD_POLL);
if (codes) xprintf("%04X ", codes);
// Adjustable keybaord media keys
@ -490,7 +515,13 @@ uint8_t matrix_scan(void)
key0 = codes>>8;
key1 = codes&0xFF;
if (codes == 0) { // no keys
if (codes == 0) { // no keys
static uint16_t detect_ms;
if (timer_elapsed(detect_ms) > 1000) {
detect_ms = timer_read();
// check new device on addr2
keyboard_init();
}
return 0;
} else if (codes == 0x7F7F) { // power key press
register_key(0x7F);
@ -576,5 +607,5 @@ static void register_key(uint8_t key)
void led_set(uint8_t usb_led)
{
adb_host_kbd_led(ADB_ADDR_KEYBOARD, ~usb_led);
adb_host_kbd_led(ADB_ADDR_KBD_POLL, ~usb_led);
}

View file

@ -8,8 +8,10 @@ TMK_DIR ?= ../../tmk_core
TARGET_DIR ?= .
# project specific files
SRC ?= protocol/ibmpc.c \
ibmpc_usb.c
#SRC ?= protocol/ibmpc.c \
# ibmpc_usb.c
SRC ?= protocol/ibmpc.cpp \
ibmpc_usb.cpp
CONFIG_H ?= config.h
@ -68,19 +70,19 @@ OPT_DEFS += -DSUSPEND_MODE_STANDBY
# Build Options
# comment out to disable the options.
#
BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000)
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
NKRO_ENABLE ?= yes # USB Nkey Rollover
BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1150)
MOUSEKEY_ENABLE ?= yes # Mouse keys(+2200)
EXTRAKEY_ENABLE ?= yes # Audio control and System control(+400)
CONSOLE_ENABLE ?= yes # Console for debug(+4150)
COMMAND_ENABLE ?= no # Commands for debug and configuration(+3600)
NKRO_ENABLE ?= yes # USB Nkey Rollover(+350)
KEYMAP_SECTION_ENABLE ?= yes
UNIMAP_ENABLE ?= yes
# IBMPC Options
IBMPC_SECONDARY ?= no # enable secondary interface
IBMPC_MOUSE_ENABLE ?= no # enable mouse support
IBMPC_SECONDARY ?= yes # enable secondary interface(+800)
IBMPC_MOUSE_ENABLE ?= yes # enable mouse support(+2000)
# Optimize size but this may cause error "relocation truncated to fit"

View file

@ -1,12 +0,0 @@
# 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

@ -51,6 +51,8 @@ Firmware
### Build Options
Secondary interface and PS/2 mouses can be supported.
In Makefiile:
# IBMPC Options
@ -88,21 +90,22 @@ Pull up resistors of 1-4.7K Ohm on both Data and Clock line are recommended, wit
- Data PD0
- Clock PD1
- Reset PB6 or PB7 (For some of XT keyboards. Not needed for AT, PS/2 and Terminal)
- Reset PB6 or PB7
For optional secondary interface use these pins.
- Data PD2
- Clock PD3
For optional secondary interface use these pins. See PS/2 connector pinouts below.
- Data2 PD2
- Clock2 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.
Use pin3 of DIN-5(180-degree) connector for Reset.
Zenith Z-150 XT and Leading Edge DC-2014 are also known to need this.
Reset should not harm keyboards even if they don't require it. It is safe and recommended to have Reset pin on AT/XT converter.
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
Old Type-1 IBM XT keyboard and some of XT clones including Zenith Z-150 XT and Leading Edge DC-2014 are known to need Reset pin. AT, PS/2 and Terminal keyboards don't need it.
See this for details: https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol#keyboard-hard-reset
### Connector pinouts
@ -124,6 +127,15 @@ See this for IBM XT Type-1 vs Type-2: https://github.com/tmk/tmk_keyboard/wiki/I
#### PS/2 - Mini-DIN-6
- https://pinouts.ru/InputCables/KeyboardPC6_pinout.shtml
PS/2 female socket from the front:
,--_--. 1: Data
/ o6 5o \ 2: Data2
| o4 3o | 3: GND
- 2o o1 - 4: VCC
`-___-' 5: Clock
6: Clock2
For secondary interface use pin2 and pin6 for data and clock respectively.
You can use PS/2 Y-splitter cable to access secondary interface.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -21,11 +21,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <avr/interrupt.h>
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0x1bee
#define DEVICE_VER 0x0001
#define MANUFACTURER t.m.k.
#define PRODUCT_ID 0x1BEE
#define DEVICE_VER 0x0201
#define MANUFACTURER TMK
#define PRODUCT IBM PC keyboard converter
#define DESCRIPTION convert IBM PC keyboard to USB
/* matrix size */
@ -39,12 +38,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
keyboard_report->mods == (MOD_BIT(KC_LALT) | MOD_BIT(KC_RALT)) \
)
// CS2 80-prefixed codes support
#define CS2_80CODE_SUPPORT
// G80-2551 terminal keyboard support
#define G80_2551_SUPPORT
// PS/2 Mouse support
//#define IBMPC_MOUSE_ENABLE
// Mouse Extended Report
//#define MOUSE_EXT_REPORT

File diff suppressed because it is too large Load diff

View file

@ -85,6 +85,14 @@ 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]) };
}
#ifdef IBMPC_MOUSE_ENABLE
static uint8_t last_buttons;
uint8_t ibmpc_mouse_buttons(void)
{
return last_buttons;
}
#endif
void IBMPCConverter::set_led(uint8_t usb_led)
{
@ -137,7 +145,8 @@ uint16_t IBMPCConverter::read_keyboard_id(void)
uint16_t id = 0;
int16_t code = 0;
// temporary fix Z-150 AT should response with ID
// Z-150 AT doesn't response to ID commnd at all.
// https://deskthority.net/viewtopic.php?p=495196#p495196
if (ibmpc.protocol == IBMPC_PROTOCOL_AT_Z150) return 0xFFFD;
// Disable
@ -171,11 +180,15 @@ uint8_t IBMPCConverter::process_interface(void)
// when recv error, neither send error nor buffer full
if (!(ibmpc.error & (IBMPC_ERR_SEND | IBMPC_ERR_FULL))) {
// keyboard init again
if (state == LOOP) {
xprintf("[RST] ");
// Reset
state = ERROR;
}
if (ibmpc.error == IBMPC_ERR_PARITY_AA) {
// AT/XT Auto-Switching support
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-Keyboard-Converter#atxt-auto-switching
state = ERROR_PARITY_AA;
}
}
// clear or process error
@ -205,15 +218,9 @@ uint8_t IBMPCConverter::process_interface(void)
switch (state) {
case INIT:
xprintf("I%u ", timer_read());
keyboard_kind = NONE;
keyboard_id = 0x0000;
current_protocol = 0;
matrix_clear();
init_time = timer_read();
state = WAIT_SETTLE;
ibmpc.host_enable();
state = WAIT_SETTLE;
break;
case WAIT_SETTLE:
while (ibmpc.host_recv() != -1) ; // read data
@ -331,11 +338,12 @@ uint8_t IBMPCConverter::process_interface(void)
keyboard_kind = PC_AT;
}
} else if (0xAB90 == keyboard_id || // IBM 5576-002
0xAB91 == keyboard_id) { // IBM 5576-003
0xAB91 == keyboard_id) { // IBM 5576-003 or Televideo DEC
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ab90
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ab91
xprintf("\n5576_CS82h:");
keyboard_kind = PC_AT;
if ((0xFA == ibmpc.host_send(0xF0)) &&
(0xFA == ibmpc.host_send(0x82))) {
// switch to code set 82h
@ -343,8 +351,18 @@ uint8_t IBMPCConverter::process_interface(void)
xprintf("OK ");
} else {
xprintf("NG ");
if (0xAB91 == keyboard_id) {
// This must be a Televideo DEC keyboard, which piggybacks on the same keyboard_id as IBM 5576-003
// This keyboard normally starts up using code set 1, but we request code set 2 here:
if ((0xFA == ibmpc.host_send(0xF0)) &&
(0xFA == ibmpc.host_send(0x03))) {
xprintf("OK ");
keyboard_kind = PC_TERMINAL;
} else {
xprintf("NG ");
}
}
}
keyboard_kind = PC_AT;
} else if (0xBFB0 == keyboard_id) { // IBM RT Keyboard
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#bfb0
// TODO: LED indicator fix
@ -440,7 +458,7 @@ MOUSE_INTELLI:
ibmpc.host_send(0xF3); ibmpc.host_send(0xC8);
ibmpc.host_send(0xF3); ibmpc.host_send(0xC8);
ibmpc.host_send(0xF3); ibmpc.host_send(0x50);
mouse_id = ((read_keyboard_id() >> 8) == MOUSE_EXPLORER ? MOUSE_EXPLORER : MOUSE_DEFAULT);
mouse_id = ((read_keyboard_id() >> 8) == MOUSE_EXPLORER ? MOUSE_EXPLORER : mouse_id);
// Not Intellimouse
if (mouse_id == 0) {
@ -597,6 +615,7 @@ MOUSE_DONE:
mouse_report.v = -CHOP8(v);
mouse_report.h = CHOP8(h);
host_mouse_send(&mouse_report);
last_buttons = mouse_report.buttons;
xprintf("M[x:%d y:%d v:%d h:%d b:%02X]\n", mouse_report.x, mouse_report.y,
mouse_report.v, mouse_report.h, mouse_report.buttons);
break; }
@ -606,8 +625,22 @@ MOUSE_DONE:
}
}
break;
case ERROR_PARITY_AA:
{
xprintf("P%u ", timer_read());
// AT/XT Auto-Switching support: Send Resend command to select AT
uint16_t code = ibmpc.host_send(0xFE);
if (0xAA == code) {
state = READ_ID;
break;
}
}
// FALL THROUGH
case ERROR:
// something goes wrong
xprintf("E%u ", timer_read());
// reinit state
init();
matrix_clear();
clear_keyboard();
state = INIT;
break;
@ -842,13 +875,13 @@ uint8_t IBMPCConverter::cs2_e0code(uint8_t code) {
switch(code) {
// E0 prefixed codes translation See [a].
case 0x11: return 0x0F; // right alt
case 0x14: return 0x17; // right control
case 0x1F: return 0x19; // left GUI
case 0x14: return 0x19; // right control
case 0x1F: return 0x17; // left GUI
case 0x27: return 0x1F; // right GUI
case 0x2F: return 0x5C; // apps
case 0x2F: return 0x27; // apps
case 0x4A: return 0x60; // keypad /
case 0x5A: return 0x62; // keypad enter
case 0x69: return 0x27; // end
case 0x69: return 0x5C; // end
case 0x6B: return 0x53; // cursor left
case 0x6C: return 0x2F; // home
case 0x70: return 0x39; // insert
@ -895,26 +928,57 @@ uint8_t IBMPCConverter::cs2_e0code(uint8_t code) {
}
}
#ifdef CS2_80CODE_SUPPORT
// 80-prefixed codes
uint8_t IBMPCConverter::cs2_80code(uint8_t code) {
// Tandberg TDV 5020
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#tandberg-tdv-5020
switch (code) {
case 0x2B: return 0x08; // TDV:MERK (mark) -> F13
case 0x34: return 0x10; // TDV:ANGRE (undo) -> F14
case 0x33: return 0x18; // TDV:SKRIV (print) -> F15
case 0x42: return 0x20; // TDV:SLUTT (end) -> F16
case 0x2C: return 0x28; // TDV:STRYK (cut) -> F17
case 0x3C: return 0x30; // TDV:KOPI (copy) -> F18
case 0x43: return 0x38; // TDV:FLYTT (move) -> F19
case 0x4B: return 0x40; // TDV:FELT (cell) -> F20
case 0x2A: return 0x48; // TDV:AVSN (paragraph) -> F21
case 0x32: return 0x50; // TDV:SETN (sentence) -> F22
case 0x3A: return 0x57; // TDV:ORD (word) -> F23
case 0x61: return 0x6A; // TDV:⮎ (?) -> JYEN Japanese Yen
case 0x1D: return 0x5F; // TDV:HJELP (help) -> F24
case 0x24: return 0x17; // TDV:^^^ (?) -> LGUI
case 0x44: return 0x65; // TDV:>>/<< (left/right adjust) -> VOLD Volume Down
case 0x4D: return 0x6E; // TDV:JUST (adjust) -> VOLU Volume Up
case 0x1C: return 0x6F; // TDV:>< <> (center/block) -> MUTE
case 0x2D: return 0x51; // TDV:⇟ (three lines down) -> RO Japanese Ro
case 0x1B: return 0x1F; // TDV:⇤ (start of line) -> RGUI
case 0x23: return 0x27; // TDV:⇥ (end of line) -> APP
}
return code;
}
#endif
// IBM 5576-002/003 Scan code translation
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ibm-5576-code-set-82h
uint8_t IBMPCConverter::translate_5576_cs2(uint8_t code) {
switch (code) {
case 0x11: return 0x0F; // Zenmen -> RALT
case 0x13: return 0x11; // Kanji -> LALT
case 0x0E: return 0x54; // @
case 0x54: return 0x5B; // [
case 0x5B: return 0x5D; // ]
case 0x5C: return 0x6A; // JYEN
case 0x5D: return 0x6A; // JYEN
case 0x62: return 0x0E; // Han/Zen -> `~
case 0x7C: return 0x77; // Keypad *
case 0x0E: return 0x54; // @ -> [
case 0x54: return 0x5B; // [ -> ]
case 0x5B: return 0x5D; // ] -> Backslash
case 0x5C: return 0x6A; // -> JPY
case 0x5D: return 0x6A; // ¥ -> JPY
case 0x62: return 0x0E; // Han/Zen -> Grave
case 0x7C: return 0x77; // Keypad * -> NumLock
}
return code;
}
uint8_t IBMPCConverter::translate_5576_cs2_e0(uint8_t code) {
switch (code) {
case 0x11: return 0x13; // Hiragana -> KANA
case 0x41: return 0x7C; // Keypad '
case 0x41: return 0x7C; // Keypad , -> Keypad *
}
return code;
}
@ -936,6 +1000,11 @@ int8_t IBMPCConverter::process_cs2(uint8_t code)
case 0xE1:
state_cs2 = CS2_E1;
break;
#ifdef CS2_80CODE_SUPPORT
case 0x80:
state_cs2 = CS2_80;
break;
#endif
case 0x83: // F7
matrix_make(0x02);
state_cs2 = CS2_INIT;
@ -1077,6 +1146,25 @@ int8_t IBMPCConverter::process_cs2(uint8_t code)
state_cs2 = CS2_INIT;
}
break;
#ifdef CS2_80CODE_SUPPORT
case CS2_80:
switch (code) {
case 0xF0:
state_cs2 = CS2_80_F0;
break;
default:
state_cs2 = CS2_INIT;
matrix_make(cs2_80code(code));
}
break;
case CS2_80_F0:
switch (code) {
default:
state_cs2 = CS2_INIT;
matrix_break(cs2_80code(code));
}
break;
#endif
default:
state_cs2 = CS2_INIT;
}
@ -1103,6 +1191,38 @@ uint8_t IBMPCConverter::translate_5576_cs3(uint8_t code) {
return code;
}
// Televideo DEC Scan code translation
uint8_t IBMPCConverter::translate_televideo_dec_cs3(uint8_t code) {
switch (code) {
case 0x08: return 0x76; // Esc
case 0x8D: return 0x77; // Num Lock
case 0x8E: return 0x67; // Numeric Keypad Slash
case 0x8F: return 0x7F; // Numeric Keypad Asterisk
case 0x90: return 0x7B; // Numeric Keypad Minus
case 0x6E: return 0x65; // Insert
case 0x65: return 0x6d; // Delete
case 0x67: return 0x62; // Home
case 0x6d: return 0x64; // End
case 0x64: return 0x6e; // PageUp
case 0x84: return 0x7c; // Numeric Keypad Plus (Legend says minus)
case 0x87: return 0x02; // Print Screen
case 0x88: return 0x7e; // Scroll Lock
case 0x89: return 0x0c; // Pause
case 0x8A: return 0x03; // VOLD
case 0x8B: return 0x04; // VOLU
case 0x8C: return 0x05; // MUTE
case 0x85: return 0x08; // F13
case 0x86: return 0x10; // F14
case 0x91: return 0x01; // LGUI
case 0x92: return 0x09; // RGUI
case 0x77: return 0x58; // RCTRL
case 0x57: return 0x5C; // Backslash
case 0x5C: return 0x53; // Non-US Hash
case 0x7c: return 0x68; // Kp Comma
}
return code;
}
int8_t IBMPCConverter::process_cs3(uint8_t code)
{
switch (code) {
@ -1120,6 +1240,10 @@ int8_t IBMPCConverter::process_cs3(uint8_t code)
if (0xAB92 == keyboard_id) {
code = translate_5576_cs3(code);
}
if (0xAB91 == keyboard_id) {
// This must be the Televideo DEC keyboard. (For 5576-003 we don't use scan code set 3)
code = translate_televideo_dec_cs3(code);
}
switch (code) {
case 0xF0:
state_cs3 = CS3_F0;
@ -1166,6 +1290,10 @@ int8_t IBMPCConverter::process_cs3(uint8_t code)
if (0xAB92 == keyboard_id) {
code = translate_5576_cs3(code);
}
if (0xAB91 == keyboard_id) {
// This must be the Televideo DEC keyboard. (For 5576-003 we don't use scan code set 3)
code = translate_televideo_dec_cs3(code);
}
switch (code) {
case 0x83: // PrintScreen
matrix_break(0x02);

View file

@ -1,12 +0,0 @@
#ifndef IBMPC_USB_H
#define IBMPC_USB_H
typedef enum { NONE, PC_XT, PC_AT, PC_TERMINAL, PC_MOUSE } keyboard_kind_t;
#define KEYBOARD_KIND_STR(kind) \
(kind == PC_XT ? "XT" : \
kind == PC_AT ? "AT" : \
kind == PC_TERMINAL ? "TERMINAL" : \
kind == PC_MOUSE ? "MOUSE" : \
"NONE")
#endif

View file

@ -4,10 +4,18 @@
#include <avr/pgmspace.h>
#include "matrix.h"
#include "unimap_trans.h"
#include "ibmpc_usb.h"
typedef enum { NONE, PC_XT, PC_AT, PC_TERMINAL, PC_MOUSE } keyboard_kind_t;
#define KEYBOARD_KIND_STR(kind) \
(kind == PC_XT ? "XT" : \
kind == PC_AT ? "AT" : \
kind == PC_TERMINAL ? "TERMINAL" : \
kind == PC_MOUSE ? "MOUSE" : \
"NONE")
#define ID_STR(id) (id == 0xFFFE ? "_????" : \
(id == 0xFFFD ? "_Z150" : \
(id == 0x0000 ? "_AT84" : \
@ -16,6 +24,10 @@
#define ROW(code) ((code>>4)&0x07)
#define COL(code) (code&0x0F)
#ifdef IBMPC_MOUSE_ENABLE
extern "C" uint8_t ibmpc_mouse_buttons(void);
#endif
class IBMPCConverter {
public:
@ -28,6 +40,10 @@ class IBMPCConverter {
}
void init(void) {
keyboard_id = 0x0000;
keyboard_kind = NONE;
current_protocol = 0;
matrix_clear();
ibmpc.host_init();
}
@ -64,6 +80,7 @@ class IBMPCConverter {
SETUP,
LOOP,
ERROR,
ERROR_PARITY_AA,
} state = INIT;
enum CS1_state {
@ -86,6 +103,10 @@ class IBMPCConverter {
CS2_E1_F0,
CS2_E1_F0_14,
CS2_E1_F0_14_F0,
#ifdef CS2_80CODE_SUPPORT
CS2_80,
CS2_80_F0,
#endif
} state_cs2 = CS2_INIT;
enum CS3_state {
@ -103,9 +124,13 @@ class IBMPCConverter {
int8_t process_cs3(uint8_t code);
uint8_t cs1_e0code(uint8_t code);
uint8_t cs2_e0code(uint8_t code);
#ifdef CS2_80CODE_SUPPORT
uint8_t cs2_80code(uint8_t code);
#endif
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);
uint8_t translate_televideo_dec_cs3(uint8_t code);
int16_t read_wait(uint16_t wait_ms);
uint16_t read_keyboard_id(void);

View file

@ -23,7 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/*
* Scan Code Set 1:
* 83-key:
* IBM XT 83-key:
* ,-------. ,--------------------------------------------------------------------------.
* | F1| F2| |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| BS |NumLck |ScrLck |
* |-------| |--------------------------------------------------------------------------|
@ -60,7 +60,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* |-----------------------------------------------------------| `-----------' |---------------|
* |CapsL | A| S| D| F| G| H| J| K| L| ;| '| #|Entr| | 4| 5| 6|KP,|
* |-----------------------------------------------------------| ,---. |---------------|
* |Shft| ^a| Z| X| C| V| B| N| M| ,| .| /| RO|Shift | |Up | | 1| 2| 3|Ent|
* |Shft| <| Z| X| C| V| B| N| M| ,| .| /| RO|Shift | |Up | | 1| 2| 3|Ent|
* |-----------------------------------------------------------| ,-----------. |---------------|
* |Ctl|Gui|Alt|MHEN| Space |HENK|KANA|Alt|Gui|App|Ctl| |Lef|Dow|Rig| | 0| .|KP=|
* `-----------------------------------------------------------' `-----------' `---------------'
@ -74,17 +74,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* |-----------------------------------------------------------| |-----------| |---------------|
* | 0F | 10| 11| 12| 13| 14| 15| 16| 17| 18| 19| 1A| 1B| 2B | |*53|*4F|*51| | 47| 48| 49| 4E|
* |-----------------------------------------------------------| `-----------' |---------------|
* | 3A | 1E| 1F| 20| 21| 22| 23| 24| 25| 26| 27| 28| 56| 1C | | 4B| 4C| 4D| 7E|
* | 3A | 1E| 1F| 20| 21| 22| 23| 24| 25| 26| 27| 28| ^a| 1C | | 4B| 4C| 4D| 7E|
* |-----------------------------------------------------------| ,---. |---------------|
* | 2A | ^a| 2C| 2D| 2E| 2F| 30| 31| 32| 33| 34| 35| 73| 36 | |*48| | 4F| 50| 51|*1C|
* | 2A | 56| 2C| 2D| 2E| 2F| 30| 31| 32| 33| 34| 35| 73| 36 | |*48| | 4F| 50| 51|*1C|
* |-----------------------------------------------------------| ,-----------. |---------------|
* | 1D|*5B| 38| 7B | 39 | 79 | 70 |*38|*5C|*5D|*1D| |*4B|*50|*4D| | 52| 53| 59|
* `-----------------------------------------------------------' `-----------' `---------------'
* *: E0-prefixed codes. See cs1_e0code() for remapping to unimap array.
* PrintScreen: E0 37 or 54(with Alt) -> 54
* Pause: E1 1D 45 or E0 46(with Ctrl) -> 55
* ^a: ISO backslash and US backslash use identical code 2B. [3], [a]
* Unsupported codes or error -> 00. UNIMAP_NUBS is unused.
* ^a: 2B(ISO XT) is handled as BSLASH. NUHS is unused.
* Unsupported codes or error -> 00.
*/
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 */
@ -97,7 +97,7 @@ const uint8_t PROGMEM unimap_cs1[MATRIX_ROWS][MATRIX_COLS] = {
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_P2, UNIMAP_P3, UNIMAP_P0, UNIMAP_PDOT, UNIMAP_PSCR, UNIMAP_PAUSE, UNIMAP_NUBS, 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 */
@ -149,16 +149,16 @@ const uint8_t PROGMEM unimap_cs1[MATRIX_ROWS][MATRIX_COLS] = {
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_F14, UNIMAP_LALT, UNIMAP_LSHIFT,UNIMAP_KANA, UNIMAP_LCTL, UNIMAP_Q, UNIMAP_1, UNIMAP_LGUI, /* 10-17 */
UNIMAP_F15, UNIMAP_RCTL, 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_APP, /* 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_CAPS, UNIMAP_RSHIFT,UNIMAP_ENTER, UNIMAP_RBRC, UNIMAP_END, 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 */
@ -182,7 +182,7 @@ const uint8_t PROGMEM unimap_cs2[MATRIX_ROWS][MATRIX_COLS] = {
* |-------| |-----------------------------------------------------------| ,-----------. |---------------|
* |PrS|App| |Shif| \| Z| X| C| V| B| N| M| ,| ,| /| RO| Shift| |Lef|Hom|Rig| | 1| 2| 3|Ent|
* |-------| |-----------------------------------------------------------| `-----------' |-----------|---|
* |Gui|Gui| |Ctrl| |Alt | Space |Alt | |Ctrl| | RO|Dow|KAN| | ,| 0| .| =|
* |Gui|Gui| |Ctrl| | Alt | P, | Space | P= | KANA| Alt | |Ctrl| | RO|Dow|KAN| | ,| 0| .| =|
* `-------' `----' `---------------------------------------' `----' ---`---'--- `---------------'
*
* ,-----------------------------------------------.
@ -191,18 +191,18 @@ const uint8_t PROGMEM unimap_cs2[MATRIX_ROWS][MATRIX_COLS] = {
* | 07| 0F| 17| 1F| 27| 2F| 37| 3F| 47| 4F| 56| 5E|
* `-----------------------------------------------'
* ,-------. ,-----------------------------------------------------------. ,-----------. ,---------------.
* | 05| 06| | 0E| 16| 1E| 26| 25| 2E| 36| 3D| 3E| 46| 45| 4E| 55| 5D| 66| | 67| 6E| 6F| | 76| 77| 7E|*84|
* | 05| 06| | 0E| 16| 1E| 26| 25| 2E| 36| 3D| 3E| 46| 45| 4E| 55| 5D| 66| | 67| 6E| 6F| | 76| 77| 7E| 84|
* |-------| |-----------------------------------------------------------| |-----------| |---------------|
* | 04| 0C| | 0D | 15| 1D| 24| 2D| 2C| 35| 3C| 43| 44| 4D| 54| 5B| 5C | | 64| 65| 6D| | 6C| 75| 7D| 7C|
* |-------| |-----------------------------------------------------------| `-----------' |---------------|
* | 03| 0B| | 14 | 1C| 1B| 23| 2B| 34| 33| 3B| 42| 4B| 4C| 52| 53| 5A | |-26| 63|-25| | 6B| 73| 74| 7B|
* |-------| |-----------------------------------------------------------| ,-----------. |---------------|
* |*83| 0A| | 12 | 13| 1A| 22| 21| 2A| 32| 31| 3A| 41| 49| 4A| 51| 59 | | 61| 62| 6A| | 69| 72| 7A| 79|
* | 83| 0A| | 12 | 13| 1A| 22| 21| 2A| 32| 31| 3A| 41| 49| 4A| 51| 59 | | 61| 62| 6A| | 69| 72| 7A| 79|
* |-------| |-----------------------------------------------------------| `-----------' |---------------|
* | 01| 09| | 11 | |19 | 29 |39 | | 58 | |-16| 60|-1E| | 68| 70| 71| 78|
* | 01| 09| | 11 | | 19 | ^85 | 29 | ^86 | 87 | 39 | | 58 | |-16| 60|-1E| | 68| 70| 71| 78|
* `-------' `-----' `---------------------------------------' `-----' ---`---'--- `---------------'
* *: Special codes remapped 83->02, 84->7F
* -: G80-2551 specific 80-prefixed codes remapped: 26->5D, 25->53, 16->51, 1E->00
* ^: 5576-001 Japanese keys
* 51, 5C, 5D, 68, 78: Hidden keys in IBM 122-key terminal keyboard [7]
*/
const uint8_t PROGMEM unimap_cs3[MATRIX_ROWS][MATRIX_COLS] = {

View file

@ -59,6 +59,7 @@ CONSOLE_ENABLE ?= yes # Console for debug
COMMAND_ENABLE ?= yes # Commands for debug and configuration
#NKRO_ENABLE ?= yes # USB Nkey Rollover
UNIMAP_ENABLE ?= yes
#KYMAP_SECTION_ENABLE ?= yes
# Boot Section Size in bytes

View file

@ -1,11 +1,17 @@
PC98 to USB keyboard protocol converter
=======================================
Target MCU is ATMega32u2 but other USB capable AVR will also work.
Main target is TMK prebuilt converter(ATMega32u2) but it will work on dev boards with ATMega32u4.
To initialize keyboard correctly you have to connect keyboard with converter first and then plug them into USB port.
Otherwise, keyboard may not work.
You can buy [TMK prebuilt converter](https://geekhack.org/index.php?topic=72052.0) here to support this project.
Discuss or report issue on github or [this thread](https://geekhack.org/index.php?topic=110094.0).
Connector
---------
On host/converter:
@ -35,7 +41,6 @@ Wiring: You can change this with editing config.h.
Protocol
--------
Signal: Asynchronous, Positive logic, 19200baud, Least bit first
@ -60,7 +65,7 @@ To flash firmware run this command
$ make dfu
then push button on converter to flash firmware.
then push button on the converter to flash firmware.
If you are using ATMega32u4 based board use following commands to get firmware HEX file.
@ -156,19 +161,22 @@ Its scan code map is very different from standard types. This is not tested.
Other PC98 converter projects and resource
------------------------------------------
PC-9800シリーズ テクニカルデータブック HARDWARE 編 1993年 p139, p343
https://archive.org/stream/PC9800TechnicalDataBookHARDWARE1993/PC-9800TechnicalDataBook_HARDWARE1993#page/n151
https://archive.org/stream/PC9800TechnicalDataBookHARDWARE1993/PC-9800TechnicalDataBook_HARDWARE1993#page/n355
### TMK wiki
- https://github.com/tmk/tmk_keyboard/wiki/PC-9801-Keyboard
PC98 to USB
http://davy.nyacom.net/kbd98usb/
### PC-9800シリーズ テクニカルデータブック HARDWARE 編 1993年 p139, p343
- https://archive.org/stream/PC9800TechnicalDataBookHARDWARE1993/PC-9800TechnicalDataBook_HARDWARE1993#page/n151
- https://archive.org/stream/PC9800TechnicalDataBookHARDWARE1993/PC-9800TechnicalDataBook_HARDWARE1993#page/n355
PC98 to PS/2
http://www.tsp.ne.jp/~sawada/mago/c_gka98at.htm
http://www.tsp.ne.jp/~sawada/mago/src/gka98at.asm
### PC98 to USB
- http://davy.nyacom.net/kbd98usb/
scan code:
http://ixsvr.dyndns.org/usb2pc98
### PC98 to PS/2
- http://www.tsp.ne.jp/~sawada/mago/c_gka98at.htm
- http://www.tsp.ne.jp/~sawada/mago/src/gka98at.asm
### Scan code
- http://ixsvr.dyndns.org/usb2pc98
@ -182,9 +190,9 @@ NOTES
### RDY
PC98 host keeps RDY line high to prevent keyboard from sending data while processing.
https://archive.org/stream/PC9800TechnicalDataBookHARDWARE1993/PC-9800TechnicalDataBook_HARDWARE1993#page/n359
- https://archive.org/stream/PC9800TechnicalDataBookHARDWARE1993/PC-9800TechnicalDataBook_HARDWARE1993#page/n359
PC-9801V keyboard requires RDY pulse as acknowledgement from host, it doesn't next data without this. Dboard doens't need this.
PC-9801V keyboard requires RDY pulse as acknowledgement from host, it doesn't next data without this. Dboard doesn't need this.
### Inhibit key repeating

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -123,15 +123,12 @@ RETRY:
void matrix_init(void)
{
PC98_RST_DDR |= (1<<PC98_RST_BIT);
PC98_RDY_DDR |= (1<<PC98_RDY_BIT);
PC98_RTY_DDR |= (1<<PC98_RTY_BIT);
PC98_RST_PORT |= (1<<PC98_RST_BIT);
PC98_RST_DDR |= (1<<PC98_RST_BIT);
PC98_RDY_PORT |= (1<<PC98_RDY_BIT);
PC98_RDY_DDR |= (1<<PC98_RDY_BIT);
PC98_RTY_PORT |= (1<<PC98_RTY_BIT);
serial_init();
PC98_RTY_DDR |= (1<<PC98_RTY_BIT);
// PC98 reset
// https://archive.org/stream/PC9800TechnicalDataBookHARDWARE1993/PC-9800TechnicalDataBook_HARDWARE1993#page/n359
@ -140,6 +137,8 @@ void matrix_init(void)
_delay_us(15); // > 13us
PC98_RST_PORT |= (1<<PC98_RST_BIT); // RST: high
serial_init();
_delay_ms(50);
if (pc98_is_newtype()) xprintf("new type\n"); else xprintf("old type\n");
pc98_inhibit_repeat();

View file

@ -17,4 +17,8 @@ OPT_DEFS += -DDEBUG_USB_HOST
CONSOLE_ENABLE = yes
MOUSEKEY_ENABLE = no
EXTRAKEY_ENABLE = no
COMMAND_ENABLE = no
OPT_DEFS += -DNO_ACTION_TAPPING
OPT_DEFS += -DNO_ACTION_LAYER
OPT_DEFS += -DNO_ACTION_MACRO
include Makefile

View file

@ -44,6 +44,14 @@ In case of Leonardo push reset button then run command. Serial port name(COM17)
or
$ avrdude -patmega32u4 -cavr109 -b57600 -Uflash:w:usb_usb.hex -PCOM17
To build debug firmware use `master_debug` branch of `USB_Host_Shield_2.0-tmk` submodule
$ cd tmk_keyboard/tmk_core/protocol/usb_hid/USB_Host_Shield_2.0-tmk
$ git chceckout master_debug
$ cd tmk_keyboard/converter/usb_usb
$ make -f Makefile.debug
$ make -f Makefile.debug dfu
Limitation

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -21,8 +21,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0x005B
#define DEVICE_VER 0x0814
#define MANUFACTURER t.m.k.
#define DEVICE_VER 0x0815
#define MANUFACTURER TMK
#define PRODUCT USB to USB keyboard converter

View file

@ -105,13 +105,13 @@ ifeq (yes,$(strip $(KEYMAP_SECTION_ENABLE)))
OPT_DEFS += -DKEYMAP_SECTION_ENABLE
ifeq ($(strip $(MCU)),atmega32u2)
EXTRALDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr35.x
EXTRALDFLAGS += -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr35.x
else ifeq ($(strip $(MCU)),atmega32u4)
EXTRALDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr5.x
EXTRALDFLAGS += -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr5.x
else ifeq ($(strip $(MCU)),at90usb1286)
EXTRALDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr51.x
EXTRALDFLAGS += -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr51.x
else
EXTRALDFLAGS = $(error no ldscript for keymap section)
EXTRALDFLAGS += $(error no ldscript for keymap section)
endif
endif

View file

@ -353,8 +353,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define AC_RO ACTION_KEY(KC_INT1)
#define AC_KANA ACTION_KEY(KC_INT2)
#define AC_JYEN ACTION_KEY(KC_INT3)
#define AC_JPY ACTION_KEY(KC_INT3)
#define AC_HENK ACTION_KEY(KC_INT4)
#define AC_MHEN ACTION_KEY(KC_INT5)
#define AC_MACJ ACTION_KEY(KC_LANG1)
#define AC_MACE ACTION_KEY(KC_LANG2)
/* Korean specific */
#define AC_HAEN ACTION_KEY(KC_LANG1)
#define AC_HANJ ACTION_KEY(KC_LANG2)
/* Keypad */
#define AC_P1 ACTION_KEY(KC_KP_1)
#define AC_P2 ACTION_KEY(KC_KP_2)
@ -376,6 +382,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define AC_PPLS ACTION_KEY(KC_KP_PLUS)
#define AC_PEQL ACTION_KEY(KC_KP_EQUAL)
#define AC_PENT ACTION_KEY(KC_KP_ENTER)
/* Unix function key */
#define AC_EXEC ACTION_KEY(KC_EXECUTE)
#define AC_SLCT ACTION_KEY(KC_SELECT)
#define AC_AGIN ACTION_KEY(KC_AGAIN)
#define AC_PSTE ACTION_KEY(KC_PASTE)
/* Mousekey */
#define AC_MS_U ACTION_MOUSEKEY(KC_MS_UP)
#define AC_MS_D ACTION_MOUSEKEY(KC_MS_DOWN)

View file

@ -22,6 +22,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "util.h"
#include "debug.h"
#ifdef MOUSEKEY_ENABLE
# include "mousekey.h"
#endif
#ifdef PS2_MOUSE_ENABLE
# include "ps2_mouse.h"
#endif
#ifdef SERIAL_MOUSE_ENABLE
# include "serial_mouse.h"
#endif
#ifdef ADB_MOUSE_ENABLE
# include "adb.h"
#endif
#ifdef IBMPC_MOUSE_ENABLE
uint8_t ibmpc_mouse_buttons(void);
#endif
#if defined(NKRO_ENABLE) || defined(NKRO_6KRO_ENABLE)
bool keyboard_nkro = true;
@ -70,7 +86,26 @@ void host_mouse_send(report_mouse_t *report)
report->boot_x = (report->x > 127) ? 127 : ((report->x < -127) ? -127 : report->x);
report->boot_y = (report->y > 127) ? 127 : ((report->y < -127) ? -127 : report->y);
#endif
/* Mouse buttons integration */
uint8_t b = report->buttons;
#ifdef MOUSEKEY_ENABLE
report->buttons |= mousekey_buttons();
#endif
#ifdef PS2_MOUSE_ENABLE
report->buttons |= ps2_mouse_buttons();
#endif
#ifdef SERIAL_MOUSE_ENABLE
report->buttons |= serial_mouse_buttons();
#endif
#ifdef ADB_MOUSE_ENABLE
report->buttons |= adb_mouse_buttons();
#endif
#ifdef IBMPC_MOUSE_ENABLE
report->buttons |= ibmpc_mouse_buttons();
#endif
(*driver->send_mouse)(report);
report->buttons = b;
}
void host_system_send(uint16_t report)

View file

@ -103,6 +103,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define KC_JPY KC_INT3
#define KC_HENK KC_INT4
#define KC_MHEN KC_INT5
#define KC_MACJ KC_LANG1
#define KC_MACE KC_LANG2
/* Korean specific */
#define KC_HAEN KC_LANG1
#define KC_HANJ KC_LANG2

View file

@ -182,6 +182,11 @@ void mousekey_clear(void)
mousekey_accel = 0;
}
uint8_t mousekey_buttons(void)
{
return mouse_report.buttons;
}
static void mousekey_debug(void)
{
if (!debug_mouse) return;

View file

@ -69,6 +69,7 @@ void mousekey_on(uint8_t code);
void mousekey_off(uint8_t code);
void mousekey_clear(void);
void mousekey_send(void);
uint8_t mousekey_buttons(void);
#ifdef __cplusplus
}

View file

@ -30,6 +30,9 @@
#include "util.h"
// https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html
#define xstr(s) str(s)
#define str(s) #s
#ifndef NO_PRINT

View file

@ -69,8 +69,10 @@ POSSIBILITY OF SUCH DAMAGE.
#define ADB_ADDR_14 14
#define ADB_ADDR_15 15
// for temporary purpose, do not use for polling
#define ADB_ADDR_TMP 15
#define ADB_ADDR_KBD_POLL 9
#define ADB_ADDR_MOUSE_POLL 10
#define ADB_ADDR_KBD_TMP 14
#define ADB_ADDR_MOUSE_TMP 15
// Command Type
#define ADB_CMD_RESET 0
#define ADB_CMD_FLUSH 1
@ -109,6 +111,7 @@ void adb_host_reset_hard(void);
void adb_host_kbd_led(uint8_t addr, uint8_t led);
void adb_mouse_task(void);
void adb_mouse_init(void);
uint8_t adb_mouse_buttons(void);
#endif

View file

@ -1,394 +0,0 @@
/*
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 "ibmpc.h"
#include "debug.h"
#include "timer.h"
#include "wait.h"
#include "ringbuf.h"
#define WAIT(stat, us, err) do { \
if (!wait_##stat(us)) { \
ibmpc_error = err; \
goto ERROR; \
} \
} while (0)
volatile uint16_t ibmpc_isr_debug = 0;
volatile uint8_t ibmpc_protocol = IBMPC_PROTOCOL_NO;
volatile uint8_t ibmpc_error = IBMPC_ERR_NONE;
/* buffer for data received from device */
#define RINGBUF_SIZE 16
static uint8_t rbuf[RINGBUF_SIZE];
static ringbuf_t rb = {};
/* internal state of receiving data */
static volatile uint16_t isr_state = 0x8000;
static uint8_t timer_start = 0;
void ibmpc_host_init(void)
{
// initialize reset pin to HiZ
IBMPC_RST_HIZ();
inhibit();
IBMPC_INT_INIT();
IBMPC_INT_OFF();
ringbuf_init(&rb, rbuf, RINGBUF_SIZE);
}
void ibmpc_host_enable(void)
{
IBMPC_INT_ON();
idle();
}
void ibmpc_host_disable(void)
{
IBMPC_INT_OFF();
inhibit();
}
int16_t ibmpc_host_send(uint8_t data)
{
bool parity = true;
ibmpc_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));
IBMPC_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
ibmpc_host_isr_clear();
idle();
IBMPC_INT_ON();
return ibmpc_host_recv_response();
ERROR:
// Retry for Z-150 AT start bit error
if (ibmpc_error == 1 && retry++ < 10) {
ibmpc_error = IBMPC_ERR_NONE;
dprintf("R ");
goto RETRY;
}
ibmpc_error |= IBMPC_ERR_SEND;
inhibit();
wait_ms(2);
idle();
IBMPC_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(&rb)) {
ibmpc_host_isr_clear();
IBMPC_INT_ON();
idle();
}
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
ret = ringbuf_get(&rb);
}
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 = ibmpc_host_recv()) == -1) {
wait_ms(1);
}
return data;
}
void ibmpc_host_isr_clear(void)
{
ibmpc_isr_debug = 0;
ibmpc_protocol = 0;
ibmpc_error = 0;
isr_state = 0x8000;
ringbuf_reset(&rb);
}
// 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;
dbit = IBMPC_DATA_PIN&(1<<IBMPC_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) {
ibmpc_isr_debug = isr_state;
ibmpc_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 | x 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
while (!(IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT)) && us) { wait_us(1); us--; }
while ( IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT) && us) { wait_us(1); us--; }
if (us) {
// XT_IBM-error: read start(0) as 1
goto NEXT;
} else {
// XT_Clone-done
ibmpc_isr_debug = isr_state;
isr_state = isr_state>>8;
ibmpc_protocol = IBMPC_PROTOCOL_XT_CLONE;
goto DONE;
}
}
break;
case 0b11100000:
// XT_IBM-error-done
ibmpc_isr_debug = isr_state;
isr_state = isr_state>>8;
ibmpc_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
while (!(IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT)) && us) { wait_us(1); us--; }
while ( IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT) && us) { wait_us(1); us--; }
if (us) {
// found stop bit: AT-midway - process the stop bit in next ISR
goto NEXT;
} else {
// no stop bit: XT_IBM-done
ibmpc_isr_debug = isr_state;
isr_state = isr_state>>8;
ibmpc_protocol = IBMPC_PROTOCOL_XT_IBM;
goto DONE;
}
}
break;
case 0b00010000:
case 0b10010000:
case 0b01010000:
case 0b11010000:
// AT-done
// TODO: parity check?
ibmpc_isr_debug = isr_state;
// stop bit check
if (isr_state & 0x8000) {
ibmpc_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
ibmpc_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
ibmpc_isr_debug = isr_state;
ibmpc_error = IBMPC_ERR_ILLEGAL;
goto ERROR;
break;
}
DONE:
// store data
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;
NEXT:
return;
}
/* send LED state to keyboard */
void ibmpc_host_set_led(uint8_t led)
{
if (0xFA == ibmpc_host_send(0xED)) {
ibmpc_host_send(led);
}
}

View file

@ -92,15 +92,12 @@ int16_t IBMPC::host_send(uint8_t data)
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));
// Return when receiving data
//if (isr_state & 0x0FFF) {
if (isr_state != 0x8000) {
dprintf("isr:%04X ", isr_state);
return -1;
}
int_off();
@ -113,7 +110,7 @@ RETRY:
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
WAIT(clock_lo, 15000, 1); // [5]p.54 T13M, -10ms [5]p.50
/* Data bit[2-9] */
for (uint8_t i = 0; i < 8; i++) {
@ -157,6 +154,7 @@ ERROR:
goto RETRY;
}
isr_debug = isr_state;
error |= IBMPC_ERR_SEND;
inhibit();
wait_ms(2);
@ -206,7 +204,7 @@ void IBMPC::host_isr_clear(void)
ringbuf_reset();
}
inline void IBMPC::isr(void)
void IBMPC::isr(void)
{
uint8_t dbit;
dbit = IBMPC_DATA_PIN&(1<<data_bit);
@ -220,7 +218,7 @@ inline void IBMPC::isr(void)
timer_start = t;
} else {
// This gives 2.0ms at least before timeout
if ((uint8_t)(t - timer_start) >= 3) {
if ((uint8_t)(t - timer_start) >= 5) {
isr_debug = isr_state;
error = IBMPC_ERR_TIMEOUT;
goto ERROR;
@ -253,13 +251,12 @@ inline void IBMPC::isr(void)
// 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
// b7 b6 b5 b4 b3 b2 b1 b0 | 1 *1 0 0 0 0 0 0 XT_Clone-done
// 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
// x x x x x x x x | 1 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
@ -275,34 +272,11 @@ inline void IBMPC::isr(void)
// 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
case 0b11000000:
// XT_Clone-done
isr_debug = isr_state;
isr_state = isr_state>>8;
protocol = IBMPC_PROTOCOL_XT_ERROR;
protocol = IBMPC_PROTOCOL_XT_CLONE;
goto DONE;
break;
case 0b10100000: // ^2
@ -326,15 +300,39 @@ inline void IBMPC::isr(void)
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;
// Detect AA with parity error for AT/XT Auto-Switching support
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-Keyboard-Converter#atxt-auto-switching
// isr_state: st pr b7 b6 b5 b4 b3 b2 | b1 b0 0 *1 0 0 0 0
// 1 '0' 1 0 1 0 1 0 | 1 0 0 *1 0 0 0 0
if (isr_state == 0xAA90) {
error = IBMPC_ERR_PARITY_AA;
goto ERROR;
}
// parit bit check
{
// isr_state: st pr b7 b6 b5 b4 b3 b2 | b1 b0 0 *1 0 0 0 0
uint8_t p = (isr_state & 0x4000) ? 1 : 0;
p ^= (isr_state >> 6);
while (p & 0xFE) {
p = (p >> 1) ^ (p & 0x01);
}
if (p == 0) {
error = IBMPC_ERR_PARITY;
goto ERROR;
}
}
// stop bit check
if (isr_state & 0x8000) {
protocol = IBMPC_PROTOCOL_AT;
@ -347,6 +345,7 @@ inline void IBMPC::isr(void)
goto DONE;
break;
case 0b01100000:
case 0b11100000:
case 0b00110000:
case 0b10110000:
case 0b01110000:
@ -373,7 +372,11 @@ DONE:
// buffer overflow
error = IBMPC_ERR_FULL;
}
goto END;
ERROR:
// inhibit: Use clock_lo() instead of inhibit() for ISR optimization
clock_lo();
END:
// clear for next data
isr_state = 0x8000;
NEXT:

View file

@ -1,204 +0,0 @@
/*
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_H
#define IBMPC_H
#include <stdbool.h>
#include "wait.h"
#include "print.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
extern volatile uint16_t ibmpc_isr_debug;
extern volatile uint8_t ibmpc_protocol;
extern volatile uint8_t ibmpc_error;
void ibmpc_host_init(void);
void ibmpc_host_enable(void);
void ibmpc_host_disable(void);
int16_t ibmpc_host_send(uint8_t data);
int16_t ibmpc_host_recv_response(void);
int16_t ibmpc_host_recv(void);
void ibmpc_host_isr_clear(void);
void ibmpc_host_set_led(uint8_t usb_led);
/*--------------------------------------------------------------------
* static functions
*------------------------------------------------------------------*/
#if defined(__AVR__)
/*
* Clock
*/
static inline void clock_lo(void)
{
IBMPC_CLOCK_PORT &= ~(1<<IBMPC_CLOCK_BIT);
IBMPC_CLOCK_DDR |= (1<<IBMPC_CLOCK_BIT);
}
static inline void clock_hi(void)
{
/* input with pull up */
IBMPC_CLOCK_DDR &= ~(1<<IBMPC_CLOCK_BIT);
IBMPC_CLOCK_PORT |= (1<<IBMPC_CLOCK_BIT);
}
static inline bool clock_in(void)
{
IBMPC_CLOCK_DDR &= ~(1<<IBMPC_CLOCK_BIT);
IBMPC_CLOCK_PORT |= (1<<IBMPC_CLOCK_BIT);
wait_us(1);
return IBMPC_CLOCK_PIN&(1<<IBMPC_CLOCK_BIT);
}
/*
* Data
*/
static inline void data_lo(void)
{
IBMPC_DATA_PORT &= ~(1<<IBMPC_DATA_BIT);
IBMPC_DATA_DDR |= (1<<IBMPC_DATA_BIT);
}
static inline void data_hi(void)
{
/* input with pull up */
IBMPC_DATA_DDR &= ~(1<<IBMPC_DATA_BIT);
IBMPC_DATA_PORT |= (1<<IBMPC_DATA_BIT);
}
static inline bool data_in(void)
{
IBMPC_DATA_DDR &= ~(1<<IBMPC_DATA_BIT);
IBMPC_DATA_PORT |= (1<<IBMPC_DATA_BIT);
wait_us(1);
return IBMPC_DATA_PIN&(1<<IBMPC_DATA_BIT);
}
#endif
static inline uint16_t wait_clock_lo(uint16_t us)
{
while (clock_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
static inline uint16_t wait_clock_hi(uint16_t us)
{
while (!clock_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
static inline uint16_t wait_data_lo(uint16_t us)
{
while (data_in() && us) { asm(""); wait_us(1); us--; }
return us;
}
static 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 */
static inline void idle(void)
{
clock_hi();
data_hi();
}
/* inhibit device to send(AT), soft reset(XT) */
static inline void inhibit(void)
{
clock_lo();
data_hi();
}
/* inhibit device to send(XT) */
static inline void inhibit_xt(void)
{
clock_hi();
data_lo();
}
#endif

View file

@ -75,11 +75,11 @@ POSSIBILITY OF SUCH DAMAGE.
#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_PARITY 0x01
#define IBMPC_ERR_PARITY_AA 0x02
#define IBMPC_ERR_SEND 0x10
#define IBMPC_ERR_TIMEOUT 0x20
#define IBMPC_ERR_FULL 0x40
@ -118,7 +118,7 @@ class IBMPC
clock_mask(1 << clock), data_mask(1 << data) {
};
inline void isr(void) __attribute__((__always_inline__));
void isr(void);
private:

View file

@ -430,7 +430,8 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.InterfaceNumber = CONSOLE_INTERFACE,
.AlternateSetting = 0x00,
.TotalEndpoints = 2,
//.TotalEndpoints = 2,
.TotalEndpoints = 1,
.Class = HID_CSCP_HIDClass,
.SubClass = HID_CSCP_NonBootSubclass,
@ -460,6 +461,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.PollingIntervalMS = 0x01
},
/*
.Console_OUTEndpoint =
{
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
@ -469,6 +471,7 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.EndpointSize = CONSOLE_EPSIZE,
.PollingIntervalMS = 0x01
},
*/
#endif
/*

View file

@ -71,7 +71,7 @@ typedef struct
USB_Descriptor_Interface_t Console_Interface;
USB_HID_Descriptor_HID_t Console_HID;
USB_Descriptor_Endpoint_t Console_INEndpoint;
USB_Descriptor_Endpoint_t Console_OUTEndpoint;
// USB_Descriptor_Endpoint_t Console_OUTEndpoint;
#endif
#if !defined(NO_KEYBOARD) && defined(NKRO_6KRO_ENABLE)
@ -127,8 +127,14 @@ typedef struct
#endif
#ifdef CONSOLE_ENABLE
# define CONSOLE_IN_EPNUM (MOUSE_IN_EPNUM + 1)
# define CONSOLE_OUT_EPNUM (MOUSE_IN_EPNUM + 1)
// ATMega32U2 doesn't support double bank on endpoint 1 and 2, use 3 or 4
# if MOUSE_IN_EPNUM < 2
# define CONSOLE_IN_EPNUM 3
# define CONSOLE_OUT_EPNUM 3
# else
# define CONSOLE_IN_EPNUM (MOUSE_IN_EPNUM + 1)
# define CONSOLE_OUT_EPNUM (MOUSE_IN_EPNUM + 1)
# endif
#else
# define CONSOLE_OUT_EPNUM MOUSE_IN_EPNUM
#endif
@ -153,7 +159,7 @@ typedef struct
#define MOUSE_EPSIZE 8
#endif
#define CONSOLE_EPSIZE 32
#define CONSOLE_EPSIZE 64
#define NKRO_EPSIZE 32

View file

@ -354,9 +354,10 @@ void EVENT_USB_Device_ConfigurationChanged(void)
#endif
#ifdef CONSOLE_ENABLE
// ATMega32U2 doesn't support double bank on endpoint 1 and 2, use 3 or 4
/* Setup Console HID Report Endpoints */
ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
#if 0
ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
@ -761,7 +762,11 @@ int main(void)
#ifndef NO_USB_STARTUP_WAIT_LOOP
/* wait for USB startup */
while (USB_DeviceState != DEVICE_STATE_Configured) {
while (USB_DeviceState != DEVICE_STATE_Configured
#ifdef CONSOLE_ENABLE
|| !console_is_ready()
#endif
) {
#if defined(INTERRUPT_CONTROL_ENDPOINT)
;
#else

View file

@ -28,6 +28,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
static report_mouse_t mouse_report = {};
static uint8_t last_buttons;
static void print_usb_data(void);
@ -161,6 +162,7 @@ void ps2_mouse_task(void)
host_mouse_send(&mouse_report);
last_buttons = mouse_report.buttons;
print_usb_data();
}
// clear report
@ -171,6 +173,11 @@ void ps2_mouse_task(void)
mouse_report.buttons = 0;
}
uint8_t ps2_mouse_buttons(void)
{
return last_buttons;
}
static void print_usb_data(void)
{
if (!debug_mouse) return;

View file

@ -62,5 +62,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
uint8_t ps2_mouse_init(void);
void ps2_mouse_task(void);
uint8_t ps2_mouse_buttons(void);
#endif

View file

@ -29,5 +29,6 @@ static inline uint8_t serial_mouse_init(void)
}
void serial_mouse_task(void);
uint8_t serial_mouse_buttons(void);
#endif

View file

@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
static uint8_t last_buttons;
static void print_usb_data(const report_mouse_t *report);
void serial_mouse_task(void)
@ -71,6 +72,7 @@ void serial_mouse_task(void)
print_usb_data(&report);
host_mouse_send(&report);
last_buttons = report.buttons;
return;
}
@ -111,6 +113,12 @@ void serial_mouse_task(void)
print_usb_data(&report);
host_mouse_send(&report);
last_buttons = report.buttons;
}
uint8_t serial_mouse_buttons(void)
{
return last_buttons;
}
static void print_usb_data(const report_mouse_t *report)

View file

@ -34,6 +34,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//#define SERIAL_MOUSE_CENTER_SCROLL
static uint8_t last_buttons;
static void print_usb_data(const report_mouse_t *report);
void serial_mouse_task(void)
@ -78,6 +79,7 @@ void serial_mouse_task(void)
print_usb_data(&report);
host_mouse_send(&report);
last_buttons = report.buttons;
if (buffer[3] || buffer[4]) {
report.h = MAX((int8_t)buffer[3], -127);
@ -85,6 +87,7 @@ void serial_mouse_task(void)
print_usb_data(&report);
host_mouse_send(&report);
last_buttons = report.buttons;
}
return;
@ -117,9 +120,15 @@ void serial_mouse_task(void)
print_usb_data(&report);
host_mouse_send(&report);
last_buttons = report.buttons;
}
}
uint8_t serial_mouse_buttons(void)
{
return last_buttons;
}
static void print_usb_data(const report_mouse_t *report)
{
if (!debug_mouse)

View file

@ -63,7 +63,9 @@ void serial_init(void)
}
// RX ring buffer
#ifndef RBUF_SIZE
#define RBUF_SIZE 256
#endif
static uint8_t rbuf[RBUF_SIZE];
static uint8_t rbuf_head = 0;
static uint8_t rbuf_tail = 0;

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