summaryrefslogtreecommitdiff
path: root/hid/pico/src/ph_outputs.c
diff options
context:
space:
mode:
Diffstat (limited to 'hid/pico/src/ph_outputs.c')
-rw-r--r--hid/pico/src/ph_outputs.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/hid/pico/src/ph_outputs.c b/hid/pico/src/ph_outputs.c
new file mode 100644
index 00000000..40d10983
--- /dev/null
+++ b/hid/pico/src/ph_outputs.c
@@ -0,0 +1,137 @@
+/* ========================================================================= #
+# #
+# KVMD - The main PiKVM daemon. #
+# #
+# Copyright (C) 2018-2023 Maxim Devaev <[email protected]> #
+# #
+# 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 3 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 <https://www.gnu.org/licenses/>. #
+# #
+# ========================================================================= */
+
+
+#include "ph_outputs.h"
+
+#include "hardware/gpio.h"
+#include "hardware/structs/watchdog.h"
+
+#include "ph_types.h"
+#include "ph_tools.h"
+#include "ph_proto.h"
+
+
+#define _PS2_ENABLED_PIN 2
+#define _PS2_SET_KBD_PIN 3
+#define _PS2_SET_MOUSE_PIN 4
+
+#define _USB_DISABLED_PIN 6
+#define _USB_ENABLE_W98_PIN 7
+#define _USB_SET_MOUSE_REL_PIN 8
+#define _USB_SET_MOUSE_W98_PIN 9
+
+
+u8 ph_g_outputs_active = 0;
+u8 ph_g_outputs_avail = 0;
+
+
+static int _read_outputs(void);
+
+
+void ph_outputs_init(void) {
+# define INIT_SWITCH(x_pin) { gpio_init(x_pin); gpio_set_dir(x_pin, GPIO_IN); gpio_pull_down(x_pin); }
+ INIT_SWITCH(_PS2_ENABLED_PIN);
+ INIT_SWITCH(_PS2_SET_KBD_PIN);
+ INIT_SWITCH(_PS2_SET_MOUSE_PIN);
+
+ INIT_SWITCH(_USB_DISABLED_PIN);
+ INIT_SWITCH(_USB_ENABLE_W98_PIN);
+ INIT_SWITCH(_USB_SET_MOUSE_REL_PIN);
+ INIT_SWITCH(_USB_SET_MOUSE_W98_PIN);
+# undef INIT_SWITCH
+
+ const bool o_ps2_enabled = gpio_get(_PS2_ENABLED_PIN);
+ const bool o_ps2_kbd = gpio_get(_PS2_SET_KBD_PIN);
+ const bool o_ps2_mouse = gpio_get(_PS2_SET_MOUSE_PIN);
+
+ const bool o_usb_disabled = gpio_get(_USB_DISABLED_PIN);
+ const bool o_usb_enabled_w98 = gpio_get(_USB_ENABLE_W98_PIN);
+ const bool o_usb_mouse_rel = gpio_get(_USB_SET_MOUSE_REL_PIN);
+ const bool o_usb_mouse_w98 = gpio_get(_USB_SET_MOUSE_W98_PIN);
+
+ int outputs = _read_outputs();
+ if (outputs < 0) {
+ outputs = 0;
+
+ if (o_ps2_enabled && o_ps2_kbd) {
+ outputs |= PH_PROTO_OUT1_KBD_PS2;
+ } else if (!o_usb_disabled) {
+ outputs |= PH_PROTO_OUT1_KBD_USB;
+ }
+
+ if (o_ps2_enabled && o_ps2_mouse) {
+ outputs |= PH_PROTO_OUT1_MOUSE_PS2;
+ } else if (!o_usb_disabled) {
+ if (o_usb_enabled_w98 && o_usb_mouse_w98) {
+ outputs |= PH_PROTO_OUT1_MOUSE_USB_W98;
+ } else if (o_usb_mouse_rel) {
+ outputs |= PH_PROTO_OUT1_MOUSE_USB_REL;
+ } else {
+ outputs |= PH_PROTO_OUT1_MOUSE_USB_ABS;
+ }
+ }
+
+ ph_outputs_write(0xFF, outputs, true);
+ }
+
+ if (!o_usb_disabled) {
+ ph_g_outputs_avail |= PH_PROTO_OUT2_HAS_USB;
+ if (o_usb_enabled_w98) {
+ ph_g_outputs_avail |= PH_PROTO_OUT2_HAS_USB_W98;
+ }
+ }
+ if (o_ps2_enabled) {
+ ph_g_outputs_avail |= PH_PROTO_OUT2_HAS_PS2;
+ }
+
+ ph_g_outputs_active = outputs & 0xFF;
+}
+
+void ph_outputs_write(u8 mask, u8 outputs, bool force) {
+ int old = 0;
+ if (!force) {
+ old = _read_outputs();
+ if (old < 0) {
+ old = 0;
+ }
+ }
+ u8 data[4] = {0};
+ data[0] = PH_PROTO_MAGIC;
+ data[1] = (old & ~mask) | outputs;
+ ph_split16(ph_crc16(data, 2), &data[2], &data[3]);
+ const u32 s0 = ((u32)data[0] << 24) | ((u32)data[1] << 16) | ((u32)data[2] << 8) | (u32)data[3];
+ watchdog_hw->scratch[0] = s0;
+}
+
+static int _read_outputs(void) {
+ const u32 s0 = watchdog_hw->scratch[0];
+ const u8 data[4] = {
+ (s0 >> 24) & 0xFF,
+ (s0 >> 16) & 0xFF,
+ (s0 >> 8) & 0xFF,
+ s0 & 0xFF,
+ };
+ if (data[0] != PH_PROTO_MAGIC || ph_crc16(data, 2) != ph_merge8_u16(data[2], data[3])) {
+ return -1;
+ }
+ return data[1];
+}