diff --git a/converter/ibmpc_usb/Makefile b/converter/ibmpc_usb/Makefile index 96de9cea44..44edaf2b39 100644 --- a/converter/ibmpc_usb/Makefile +++ b/converter/ibmpc_usb/Makefile @@ -71,7 +71,7 @@ OPT_DEFS += -DSUSPEND_MODE_STANDBY # comment out to disable the options. # BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1150) -MOUSEKEY_ENABLE ?= yes # Mouse keys(+2200) +MOUSEKEY_ENABLE ?= no # Mouse keys(+2200) EXTRAKEY_ENABLE ?= yes # Audio control and System control(+400) CONSOLE_ENABLE ?= yes # Console for debug(+4150) COMMAND_ENABLE ?= yes # Commands for debug and configuration(+3600) diff --git a/converter/ibmpc_usb/ibmpc_usb.cpp b/converter/ibmpc_usb/ibmpc_usb.cpp index 247d556c7d..b559c491f9 100644 --- a/converter/ibmpc_usb/ibmpc_usb.cpp +++ b/converter/ibmpc_usb/ibmpc_usb.cpp @@ -29,6 +29,7 @@ along with this program. If not, see . #include "hook.h" #include "ibmpc.hpp" #include "ibmpc_usb.hpp" +#include "led_pins.h" // Converter @@ -71,8 +72,50 @@ uint8_t matrix_scan(void) #endif } +void write_led_pin(uint8_t usb_led, uint8_t pin) +{ + uint8_t relevant_bit; + switch (pin) { +#ifdef CAPS_LOCK_PIN + case CAPS_LOCK_PIN: + relevant_bit = USB_LED_CAPS_LOCK; + break; +#endif +#ifdef NUM_LOCK_PIN + case NUM_LOCK_PIN: + relevant_bit = USB_LED_NUM_LOCK; + break; +#endif +#ifdef SCROLL_LOCK_PIN + case SCROLL_LOCK_PIN: + relevant_bit = USB_LED_SCROLL_LOCK; + break; +#endif + default: + return; + } + if (usb_led & (1 << relevant_bit)) { + LOCK_INDICATOR_DDR |= (1 << pin); + LOCK_INDICATOR_PORT |= (1 << pin); + } else { + LOCK_INDICATOR_DDR &= ~(1 << pin); + LOCK_INDICATOR_PORT &= ~(1 << pin); + } +} + void led_set(uint8_t usb_led) { + // Write lock states to indicators on the converter itself +#ifdef NUM_LOCK_PIN + write_led_pin(usb_led, NUM_LOCK_PIN); +#endif +#ifdef CAPS_LOCK_PIN + write_led_pin(usb_led, CAPS_LOCK_PIN); +#endif +#ifdef SCROLL_LOCK_PIN + write_led_pin(usb_led, SCROLL_LOCK_PIN); +#endif + // Send lock states out to connected input device(s), if appropriate converter0.set_led(usb_led); #if defined(IBMPC_CLOCK_BIT1) && defined(IBMPC_DATA_BIT1) converter1.set_led(usb_led); @@ -96,28 +139,49 @@ uint8_t ibmpc_mouse_buttons(void) void IBMPCConverter::set_led(uint8_t usb_led) { - // Sending before keyboard recognition may be harmful for XT keyboard - if (keyboard_kind == NONE) return; - - // XT keyobard doesn't support any command and it is harmful perhaps - // https://github.com/tmk/tmk_keyboard/issues/635#issuecomment-626993437 - if (keyboard_kind == PC_XT) return; - if (keyboard_kind == PC_MOUSE) return; - - // It should be safe to send the command to keyboards with AT protocol - // - IBM Terminal doesn't support the command and response with 0xFE but it is not harmful. - // - Some other Terminals like G80-2551 supports the command. - // https://geekhack.org/index.php?topic=103648.msg2894921#msg2894921 - + /* Pointing devices and original IBM PC ("XT") protocol keyboards do not + * support receiving data signals, only sending them, so it's probably not a + * good idea to send any to them: + * https://github.com/tmk/tmk_keyboard/issues/635#issuecomment-626993437 + * + * IBM terminal boards don't have LEDs, but are capable of receiving and + * responding to incoming data. This is useful, because it means we can send + * the enquiry byte to terminal keyboards, which will facilitate updating + * the lock state LEDs on terminal keyboards that do have them, like the + * Cherry G80-2551: + * https://geekhack.org/index.php?topic=103648.msg2894921#msg2894921 + * + * The USB HID and IBM PC/AT protocols both set keyboards' lock state LEDs + * by sending a single byte in which each lock state is represented by one + * bit, but the bit order differs between protocols (see led.h and ibmpc.h). + */ + switch (keyboard_kind) { + /* If the connected device is unidentified (temporarily or otherwise), a + * pointing device, or an "XT" protocol keyboard, do nothing */ + case NONE: + case PC_XT: + case PC_MOUSE: + break; + /* If keyboard returns "ACK" acknowledgement byte (0xFA) when LED update + * enquiry byte (0xED) is sent, reorganise USB HID LED byte into IBM bit + * order and send to keyboard to update all 3 of its lock state LEDs */ + default: + if (ibmpc.host_send(IBMPC_SET_LED) == IBMPC_ACK) { + uint8_t ibm_led = 0; + if (usb_led & (1 << USB_LED_SCROLL_LOCK)) { + ibm_led |= (1 << IBMPC_LED_SCROLL_LOCK); + } + if (usb_led & (1 << USB_LED_NUM_LOCK)) { + ibm_led |= (1 << IBMPC_LED_NUM_LOCK); + } + if (usb_led & (1 << USB_LED_CAPS_LOCK)) { + ibm_led |= (1 << IBMPC_LED_CAPS_LOCK); + } + ibmpc.host_send(ibm_led); + } + break; // TODO: PC_TERMINAL_IBM_RT support - uint8_t ibmpc_led = 0; - if (usb_led & (1< + +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 . +*/ + +#pragma once + +/* +The default pin assignments in this file have been chosen to retain full +backwards compatibility with Soarer's old converter solution: +https://geekhack.org/index.php?topic=17458.0 +*/ + +// The Data Direction Register and port must match (default is F) +#define LOCK_INDICATOR_DDR DDRF +#define LOCK_INDICATOR_PORT PORTF + +// These pin numbers correspond with the chosen port, e.g. port F pin 5 is PF5 +#define CAPS_LOCK_PIN 5 +#define NUM_LOCK_PIN 6 +#define SCROLL_LOCK_PIN 7 diff --git a/tmk_core/protocol/ibmpc.cpp b/tmk_core/protocol/ibmpc.cpp index 074a20189a..3f899745d4 100644 --- a/tmk_core/protocol/ibmpc.cpp +++ b/tmk_core/protocol/ibmpc.cpp @@ -401,15 +401,6 @@ void IBMPC::isr(void) 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 diff --git a/tmk_core/protocol/ibmpc.hpp b/tmk_core/protocol/ibmpc.hpp index d1765e7f09..3d0b06d241 100644 --- a/tmk_core/protocol/ibmpc.hpp +++ b/tmk_core/protocol/ibmpc.hpp @@ -110,7 +110,6 @@ class IBMPC 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),