From 94041d45fc789b1ed498c010486b1f4439b5a458 Mon Sep 17 00:00:00 2001 From: No0ne Date: Mon, 14 Aug 2023 08:34:31 +0200 Subject: [PATCH 01/10] pico hid: ps/2 keyboard support getting started (#139) --- hid/pico/src/CMakeLists.txt | 3 + hid/pico/src/ph_ps2.c | 154 +++++++++++++++++++++++++++++++++--- hid/pico/src/ph_ps2.pio | 86 ++++++++++++++++++++ 3 files changed, 230 insertions(+), 13 deletions(-) create mode 100644 hid/pico/src/ph_ps2.pio diff --git a/hid/pico/src/CMakeLists.txt b/hid/pico/src/CMakeLists.txt index cb1c7feb..0426110c 100644 --- a/hid/pico/src/CMakeLists.txt +++ b/hid/pico/src/CMakeLists.txt @@ -20,9 +20,12 @@ target_link_options(${target_name} PRIVATE -Xlinker --print-memory-usage) target_compile_options(${target_name} PRIVATE -Wall -Wextra) target_include_directories(${target_name} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) +pico_generate_pio_header(${target_name} ${CMAKE_CURRENT_LIST_DIR}/ph_ps2.pio) + target_link_libraries(${target_name} PRIVATE pico_stdlib pico_unique_id + hardware_pio hardware_spi hardware_watchdog tinyusb_device diff --git a/hid/pico/src/ph_ps2.c b/hid/pico/src/ph_ps2.c index 60723a1c..caddc174 100644 --- a/hid/pico/src/ph_ps2.c +++ b/hid/pico/src/ph_ps2.c @@ -24,25 +24,136 @@ #include "ph_types.h" #include "ph_outputs.h" - +#include "ph_ps2.pio.h" +#include "hardware/gpio.h" u8 ph_g_ps2_kbd_leds = 0; bool ph_g_ps2_kbd_online = 0; bool ph_g_ps2_mouse_online = 0; +uint8_t const mod2ps2[] = { 0x14, 0x12, 0x11, 0x1f, 0x14, 0x59, 0x11, 0x27 }; +uint8_t const hid2ps2[] = { + 0x00, 0x00, 0xfc, 0x00, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34, 0x33, 0x43, 0x3b, 0x42, 0x4b, + 0x3a, 0x31, 0x44, 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d, 0x22, 0x35, 0x1a, 0x16, 0x1e, + 0x26, 0x25, 0x2e, 0x36, 0x3d, 0x3e, 0x46, 0x45, 0x5a, 0x76, 0x66, 0x0d, 0x29, 0x4e, 0x55, 0x54, + 0x5b, 0x5d, 0x5d, 0x4c, 0x52, 0x0e, 0x41, 0x49, 0x4a, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03, 0x0b, + 0x83, 0x0a, 0x01, 0x09, 0x78, 0x07, 0x7c, 0x7e, 0x7e, 0x70, 0x6c, 0x7d, 0x71, 0x69, 0x7a, 0x74, + 0x6b, 0x72, 0x75, 0x77, 0x4a, 0x7c, 0x7b, 0x79, 0x5a, 0x69, 0x72, 0x7a, 0x6b, 0x73, 0x74, 0x6c, + 0x75, 0x7d, 0x70, 0x71, 0x61, 0x2f, 0x37, 0x0f, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, + 0x48, 0x50, 0x57, 0x5f +}; +uint8_t const maparray = sizeof(hid2ps2) / sizeof(uint8_t); + +PIO pio = pio0; +uint sm; +uint offset; + +uint16_t ph_ps2_frame(uint8_t data) { + uint8_t parity = 1; + for (uint8_t i = 0; i < 8; i++) { + parity = parity ^ (data >> i & 1); + } + + return ((1 << 10) | (parity << 9) | (data << 1)) ^ 0x7ff; +} + +void ph_ps2_kbd_send(uint8_t data) { + pio_sm_put(pio, sm, ph_ps2_frame(data)); +} + +void ph_ps2_kbd_maybe_send_e0(uint8_t data) { + if (data == 0x46 || + (data >= 0x49 && data <= 0x52) || + data == 0x54 || data == 0x58 || + data == 0x65 || data == 0x66 || + data >= 0x81) { + ph_ps2_kbd_send(0xe0); + } +} void ph_ps2_init(void) { - // TODO: PS2: Initialize PS/2 stuff here IF you have at least one PS/2 device, check ph_usb.c for the example - // Use macro PH_O_IS_KBD_PS2 and PH_O_IS_MOUSE_PS2 if (PH_O_IS_KBD_PS2 || PH_O_IS_MOUSE_PS2) { - // ... + gpio_init(13); + gpio_set_dir(13, GPIO_OUT); + gpio_put(13, 1); // LV pull-up voltage + + sm = pio_claim_unused_sm(pio, true); + offset = pio_add_program(pio, &ps2device_program); + ps2device_program_init(pio, sm, offset, 14); } } void ph_ps2_task(void) { - // TODO: PS2: Perform periodic stuff here IF you have at least one PS/2 device, check ph_usb.c if (PH_O_IS_KBD_PS2 || PH_O_IS_MOUSE_PS2) { - // ... + + if (!pio_sm_is_rx_fifo_empty(pio, sm)) { + uint32_t fifo = pio_sm_get(pio, sm); + fifo = fifo >> 23; + + uint8_t parity = 1; + for(uint8_t i = 0; i < 8; i++) { + parity = parity ^ (fifo >> i & 1); + } + + if(parity != fifo >> 8) { + ph_ps2_kbd_send(0xfe); + return; + } + + uint8_t data = fifo; + + /*switch() { + case 0xed: // CMD: Set LEDs + + break; + + case 0xf3: // CMD: Set typematic rate and delay + + break; + + default:*/ + switch(data) { + case 0xff: // CMD: Reset + pio_sm_clear_fifos(pio, sm); + pio_sm_drain_tx_fifo(pio, sm); + ph_ps2_kbd_send(0xfa); + ph_ps2_kbd_send(0xaa); + return; + + case 0xfe: // CMD: Resend + + return; + + case 0xee: // CMD: Echo + ph_ps2_kbd_send(0xee); + return; + + case 0xf2: // CMD: Identify keyboard + ph_ps2_kbd_send(0xfa); + ph_ps2_kbd_send(0xab); + ph_ps2_kbd_send(0x83); + return; + + case 0xf3: // CMD: Set typematic rate and delay + case 0xed: // CMD: Set LEDs + + break; + + case 0xf4: // CMD: Enable scanning + + break; + + case 0xf5: // CMD: Disable scanning, restore default parameters + case 0xf6: // CMD: Set default parameters + + break; + } + /* break; + }*/ + + ph_ps2_kbd_send(0xfa); + } + } // Here you should update some values: // - ph_g_ps2_kbd_leds - keyboard LEDs mask like on USB @@ -53,13 +164,30 @@ void ph_ps2_task(void) { } void ph_ps2_kbd_send_key(u8 key, bool state) { - // TODO: PS2: Send keyboard key - // @key - is a USB keycode, modifier keys has range 0xE0...0xE7, check ph_usb_kbd_send_key() - // @state - true if pressed, false if released - // The function should take care not to send duplicate events (if needed for PS/2) - // If the PS2 keyboard is not used (PH_O_IS_KBD_PS2 is false), the function should do nothing. - (void)key; // Remove this - (void)state; // Remove this + if (PH_O_IS_KBD_PS2) { + if (key >= 0xe0 && key <= 0xe7) { + key -= 0xe0; + if(key > 2 && key != 5) { + ph_ps2_kbd_send(0xe0); + } + + if(!state) { + ph_ps2_kbd_send(0xf0); + } + + ph_ps2_kbd_send(mod2ps2[key]); + + } else if (key < maparray) { + ph_ps2_kbd_maybe_send_e0(key); + + if(!state) { + ph_ps2_kbd_send(0xf0); + } + + ph_ps2_kbd_send(hid2ps2[key]); + + } + } } void ph_ps2_mouse_send_button(u8 button, bool state) { diff --git a/hid/pico/src/ph_ps2.pio b/hid/pico/src/ph_ps2.pio new file mode 100644 index 00000000..2313419d --- /dev/null +++ b/hid/pico/src/ph_ps2.pio @@ -0,0 +1,86 @@ +; +; Copyright (c) 2022 No0ne (https://github.com/No0ne) +; (c) 2023 Dustin Hoffman +; +; SPDX-License-Identifier: MIT +; + +.program ps2device +.side_set 1 opt pindirs + + //mov y ! null +start: +.wrap_target + set pindirs 0 side 0 // Clock and data to input mode. + jmp pin sendcheck // If clock is high, see if we have data to send. + // Clock is being pulled low. + wait 1 pin 1 // Wait for clock to be pulled high. + + // We are not sending, look for a start bit (Clock high, data low) + in pins 1 // Read in from data. + mov x isr // Move what we read to x. + mov isr null // Clear ISR. + jmp !x receive // If x is low, start the receive process. + jmp start // Not receiving, restart. + +receive: + set pindirs, 1 [6] // Clock low. + set x, 8 // Set loop counter. + +receiveloop: + set pindirs, 0 [6]// Clock high + in pins, 1 [4]// Read a bit into ISR. + set pindirs, 1 [6]// Clock low + jmp x-- receiveloop [4]// Iterate + set pindirs, 0 [6] // Clock high + nop side 1 [6]// Data low + set pindirs, 1 [7] // Clock low + //in null 1 +.wrap + +sendcheck: + jmp !osre wait_to_write // See if we have data to send. + jmp start // No data to send, restart. + +wait_to_write: + set x 10 // Number of bits to write out. + + sendloop: + set pindirs, 0 [6] // Clock set to input (high) + jmp pin sendcontinue // If clock is high, host is still receiving data. + // Pin was low, host wants to send data. + // Notify of failure to send data.. + //in null 8 + //in y 2 + jmp start +sendcontinue: + out pindirs, 1 [6] // Write out data. + set pindirs, 1 [6] // Set clock low. + jmp x-- sendloop [6] + //in y 10 + jmp start + +% c-sdk { + + void ps2device_program_init(PIO pio, uint sm, uint offset, uint dat) { + pio_sm_config c = ps2device_program_get_default_config(offset); + + uint clk = dat + 1; + pio_gpio_init(pio, clk); + pio_gpio_init(pio, dat); + + // Use a frequency high enough to effectivly sample clock and data. + sm_config_set_clkdiv(&c, 427); // 2560 is 20 us, 640 is 5 us, 427 is 3.3333 us + sm_config_set_jmp_pin(&c, clk); + sm_config_set_set_pins(&c, clk, 1); + sm_config_set_sideset_pins(&c, dat); + sm_config_set_out_pins(&c, dat, 1); + sm_config_set_out_shift(&c, true, true, 11); + sm_config_set_in_pins(&c, dat); + sm_config_set_in_shift(&c, true, true, 9); + + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); + } + +%} \ No newline at end of file From 72df81540751cda96fa6dac84a202246f1d92cba Mon Sep 17 00:00:00 2001 From: No0ne Date: Tue, 22 Aug 2023 23:22:36 +0200 Subject: [PATCH 02/10] pico hid: ps/2 bytes and packets queue (#142) --- hid/pico/src/CMakeLists.txt | 5 +- hid/pico/src/ph_ps2.c | 219 ++++++++++++++++++------------------ hid/pico/src/ph_ps2.pio | 86 -------------- hid/pico/src/ph_ps2_phy.c | 68 +++++++++++ hid/pico/src/ph_ps2_phy.h | 19 ++++ hid/pico/src/ph_ps2_phy.pio | 81 +++++++++++++ 6 files changed, 281 insertions(+), 197 deletions(-) delete mode 100644 hid/pico/src/ph_ps2.pio create mode 100644 hid/pico/src/ph_ps2_phy.c create mode 100644 hid/pico/src/ph_ps2_phy.h create mode 100644 hid/pico/src/ph_ps2_phy.pio diff --git a/hid/pico/src/CMakeLists.txt b/hid/pico/src/CMakeLists.txt index 0426110c..e2897198 100644 --- a/hid/pico/src/CMakeLists.txt +++ b/hid/pico/src/CMakeLists.txt @@ -8,19 +8,19 @@ target_sources(${target_name} PRIVATE ph_usb_kbd.c ph_usb_mouse.c ph_ps2.c + ph_ps2_phy.c ph_cmds.c ph_com.c ph_com_bridge.c ph_com_spi.c ph_com_uart.c ph_debug.c - # TODO: PS2: ${PS2_PATH}/foo.c ) target_link_options(${target_name} PRIVATE -Xlinker --print-memory-usage) target_compile_options(${target_name} PRIVATE -Wall -Wextra) target_include_directories(${target_name} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) -pico_generate_pio_header(${target_name} ${CMAKE_CURRENT_LIST_DIR}/ph_ps2.pio) +pico_generate_pio_header(${target_name} ${CMAKE_CURRENT_LIST_DIR}/ph_ps2_phy.pio) target_link_libraries(${target_name} PRIVATE pico_stdlib @@ -29,6 +29,5 @@ target_link_libraries(${target_name} PRIVATE hardware_spi hardware_watchdog tinyusb_device - # TODO: PS2: ... or make a library ) pico_add_extra_outputs(${target_name}) diff --git a/hid/pico/src/ph_ps2.c b/hid/pico/src/ph_ps2.c index caddc174..51c0a21b 100644 --- a/hid/pico/src/ph_ps2.c +++ b/hid/pico/src/ph_ps2.c @@ -24,15 +24,17 @@ #include "ph_types.h" #include "ph_outputs.h" -#include "ph_ps2.pio.h" +#include "ph_ps2_phy.h" #include "hardware/gpio.h" u8 ph_g_ps2_kbd_leds = 0; bool ph_g_ps2_kbd_online = 0; bool ph_g_ps2_mouse_online = 0; +ph_ps2_phy ph_ps2_kbd; +ph_ps2_phy ph_ps2_mouse; -uint8_t const mod2ps2[] = { 0x14, 0x12, 0x11, 0x1f, 0x14, 0x59, 0x11, 0x27 }; -uint8_t const hid2ps2[] = { +u8 const ph_ps2_mod2ps2[] = { 0x14, 0x12, 0x11, 0x1f, 0x14, 0x59, 0x11, 0x27 }; +u8 const ph_ps2_hid2ps2[] = { 0x00, 0x00, 0xfc, 0x00, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34, 0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44, 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d, 0x22, 0x35, 0x1a, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d, 0x3e, 0x46, 0x45, 0x5a, 0x76, 0x66, 0x0d, 0x29, 0x4e, 0x55, 0x54, @@ -42,32 +44,78 @@ uint8_t const hid2ps2[] = { 0x75, 0x7d, 0x70, 0x71, 0x61, 0x2f, 0x37, 0x0f, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x5f }; -uint8_t const maparray = sizeof(hid2ps2) / sizeof(uint8_t); +u8 const ph_ps2_maparray = sizeof(ph_ps2_hid2ps2); -PIO pio = pio0; -uint sm; -uint offset; +void ph_ps2_kbd_send(u8 byte) { + queue_try_add(&ph_ps2_kbd.qbytes, &byte); +} -uint16_t ph_ps2_frame(uint8_t data) { - uint8_t parity = 1; - for (uint8_t i = 0; i < 8; i++) { - parity = parity ^ (data >> i & 1); +void ph_ps2_kbd_maybe_send_e0(u8 byte) { + if (byte == 0x46 || + (byte >= 0x49 && byte <= 0x52) || + byte == 0x54 || byte == 0x58 || + byte == 0x65 || byte == 0x66 || + byte >= 0x81) { + ph_ps2_kbd_send(0xe0); + } +} + +void ph_ps2_kbd_receive(u8 byte) { + switch(byte) { + case 0xed: // CMD: Set LEDs + + break; + + case 0xf3: // CMD: Set typematic rate and delay + + break; + + default: + switch(byte) { + case 0xff: // CMD: Reset + //pio_sm_clear_fifos(pio, sm); + //pio_sm_drain_tx_fifo(pio, sm); + ph_ps2_kbd_send(0xfa); + ph_ps2_kbd_send(0xaa); + return; + + case 0xfe: // CMD: Resend + + return; + + case 0xee: // CMD: Echo + ph_ps2_kbd_send(0xee); + return; + + case 0xf2: // CMD: Identify keyboard + ph_ps2_kbd_send(0xfa); + ph_ps2_kbd_send(0xab); + ph_ps2_kbd_send(0x83); + return; + + case 0xf3: // CMD: Set typematic rate and delay + case 0xed: // CMD: Set LEDs + + break; + + case 0xf4: // CMD: Enable scanning + + break; + + case 0xf5: // CMD: Disable scanning, restore default parameters + case 0xf6: // CMD: Set default parameters + + break; + } + break; } - return ((1 << 10) | (parity << 9) | (data << 1)) ^ 0x7ff; + ph_ps2_kbd_send(0xfa); } -void ph_ps2_kbd_send(uint8_t data) { - pio_sm_put(pio, sm, ph_ps2_frame(data)); -} - -void ph_ps2_kbd_maybe_send_e0(uint8_t data) { - if (data == 0x46 || - (data >= 0x49 && data <= 0x52) || - data == 0x54 || data == 0x58 || - data == 0x65 || data == 0x66 || - data >= 0x81) { - ph_ps2_kbd_send(0xe0); +void ph_ps2_mouse_receive(u8 byte) { + switch(byte) { + } } @@ -75,85 +123,26 @@ void ph_ps2_init(void) { if (PH_O_IS_KBD_PS2 || PH_O_IS_MOUSE_PS2) { gpio_init(13); gpio_set_dir(13, GPIO_OUT); - gpio_put(13, 1); // LV pull-up voltage - - sm = pio_claim_unused_sm(pio, true); - offset = pio_add_program(pio, &ps2device_program); - ps2device_program_init(pio, sm, offset, 14); + gpio_put(13, 1); // GPIO13=LV pull-up voltage + } + + if (PH_O_IS_KBD_PS2) { + ph_ps2_phy_init(&ph_ps2_kbd, pio0, 11, &ph_ps2_kbd_receive); // keyboard: GPIO11=data, GPIO12=clock + ph_ps2_kbd_send(0xaa); + } + + if (PH_O_IS_MOUSE_PS2) { + ph_ps2_phy_init(&ph_ps2_mouse, pio1, 14, &ph_ps2_mouse_receive); // mouse: GPIO14=data, GPIO15=clock } } void ph_ps2_task(void) { - if (PH_O_IS_KBD_PS2 || PH_O_IS_MOUSE_PS2) { - - if (!pio_sm_is_rx_fifo_empty(pio, sm)) { - uint32_t fifo = pio_sm_get(pio, sm); - fifo = fifo >> 23; - - uint8_t parity = 1; - for(uint8_t i = 0; i < 8; i++) { - parity = parity ^ (fifo >> i & 1); - } - - if(parity != fifo >> 8) { - ph_ps2_kbd_send(0xfe); - return; - } - - uint8_t data = fifo; - - /*switch() { - case 0xed: // CMD: Set LEDs - - break; - - case 0xf3: // CMD: Set typematic rate and delay - - break; - - default:*/ - switch(data) { - case 0xff: // CMD: Reset - pio_sm_clear_fifos(pio, sm); - pio_sm_drain_tx_fifo(pio, sm); - ph_ps2_kbd_send(0xfa); - ph_ps2_kbd_send(0xaa); - return; - - case 0xfe: // CMD: Resend - - return; - - case 0xee: // CMD: Echo - ph_ps2_kbd_send(0xee); - return; - - case 0xf2: // CMD: Identify keyboard - ph_ps2_kbd_send(0xfa); - ph_ps2_kbd_send(0xab); - ph_ps2_kbd_send(0x83); - return; - - case 0xf3: // CMD: Set typematic rate and delay - case 0xed: // CMD: Set LEDs - - break; - - case 0xf4: // CMD: Enable scanning - - break; - - case 0xf5: // CMD: Disable scanning, restore default parameters - case 0xf6: // CMD: Set default parameters - - break; - } - /* break; - }*/ - - ph_ps2_kbd_send(0xfa); - } - + if (PH_O_IS_KBD_PS2) { + ph_ps2_phy_task(&ph_ps2_kbd); + } + + if (PH_O_IS_MOUSE_PS2) { + ph_ps2_phy_task(&ph_ps2_mouse); } // Here you should update some values: // - ph_g_ps2_kbd_leds - keyboard LEDs mask like on USB @@ -167,25 +156,39 @@ void ph_ps2_kbd_send_key(u8 key, bool state) { if (PH_O_IS_KBD_PS2) { if (key >= 0xe0 && key <= 0xe7) { key -= 0xe0; - if(key > 2 && key != 5) { + + if (key > 2 && key != 5) { ph_ps2_kbd_send(0xe0); } - if(!state) { + if (!state) { ph_ps2_kbd_send(0xf0); } - ph_ps2_kbd_send(mod2ps2[key]); + ph_ps2_kbd_send(ph_ps2_mod2ps2[key]); - } else if (key < maparray) { - ph_ps2_kbd_maybe_send_e0(key); + } else if (key < ph_ps2_maparray) { - if(!state) { - ph_ps2_kbd_send(0xf0); + if (key == 0x48) { + if (state) { + + if (false) { // TODO: is shift + ph_ps2_kbd_send(0xe0); ph_ps2_kbd_send(0x7e); ph_ps2_kbd_send(0xe0); ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x7e); + } else { + ph_ps2_kbd_send(0xe1); ph_ps2_kbd_send(0x14); ph_ps2_kbd_send(0x77); ph_ps2_kbd_send(0xe1); + ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x14); ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x77); + } + + } + } else { + ph_ps2_kbd_maybe_send_e0(key); + + if (!state) { + ph_ps2_kbd_send(0xf0); + } + + ph_ps2_kbd_send(ph_ps2_hid2ps2[key]); } - - ph_ps2_kbd_send(hid2ps2[key]); - } } } diff --git a/hid/pico/src/ph_ps2.pio b/hid/pico/src/ph_ps2.pio deleted file mode 100644 index 2313419d..00000000 --- a/hid/pico/src/ph_ps2.pio +++ /dev/null @@ -1,86 +0,0 @@ -; -; Copyright (c) 2022 No0ne (https://github.com/No0ne) -; (c) 2023 Dustin Hoffman -; -; SPDX-License-Identifier: MIT -; - -.program ps2device -.side_set 1 opt pindirs - - //mov y ! null -start: -.wrap_target - set pindirs 0 side 0 // Clock and data to input mode. - jmp pin sendcheck // If clock is high, see if we have data to send. - // Clock is being pulled low. - wait 1 pin 1 // Wait for clock to be pulled high. - - // We are not sending, look for a start bit (Clock high, data low) - in pins 1 // Read in from data. - mov x isr // Move what we read to x. - mov isr null // Clear ISR. - jmp !x receive // If x is low, start the receive process. - jmp start // Not receiving, restart. - -receive: - set pindirs, 1 [6] // Clock low. - set x, 8 // Set loop counter. - -receiveloop: - set pindirs, 0 [6]// Clock high - in pins, 1 [4]// Read a bit into ISR. - set pindirs, 1 [6]// Clock low - jmp x-- receiveloop [4]// Iterate - set pindirs, 0 [6] // Clock high - nop side 1 [6]// Data low - set pindirs, 1 [7] // Clock low - //in null 1 -.wrap - -sendcheck: - jmp !osre wait_to_write // See if we have data to send. - jmp start // No data to send, restart. - -wait_to_write: - set x 10 // Number of bits to write out. - - sendloop: - set pindirs, 0 [6] // Clock set to input (high) - jmp pin sendcontinue // If clock is high, host is still receiving data. - // Pin was low, host wants to send data. - // Notify of failure to send data.. - //in null 8 - //in y 2 - jmp start -sendcontinue: - out pindirs, 1 [6] // Write out data. - set pindirs, 1 [6] // Set clock low. - jmp x-- sendloop [6] - //in y 10 - jmp start - -% c-sdk { - - void ps2device_program_init(PIO pio, uint sm, uint offset, uint dat) { - pio_sm_config c = ps2device_program_get_default_config(offset); - - uint clk = dat + 1; - pio_gpio_init(pio, clk); - pio_gpio_init(pio, dat); - - // Use a frequency high enough to effectivly sample clock and data. - sm_config_set_clkdiv(&c, 427); // 2560 is 20 us, 640 is 5 us, 427 is 3.3333 us - sm_config_set_jmp_pin(&c, clk); - sm_config_set_set_pins(&c, clk, 1); - sm_config_set_sideset_pins(&c, dat); - sm_config_set_out_pins(&c, dat, 1); - sm_config_set_out_shift(&c, true, true, 11); - sm_config_set_in_pins(&c, dat); - sm_config_set_in_shift(&c, true, true, 9); - - pio_sm_init(pio, sm, offset, &c); - pio_sm_set_enabled(pio, sm, true); - } - -%} \ No newline at end of file diff --git a/hid/pico/src/ph_ps2_phy.c b/hid/pico/src/ph_ps2_phy.c new file mode 100644 index 00000000..b5ffba75 --- /dev/null +++ b/hid/pico/src/ph_ps2_phy.c @@ -0,0 +1,68 @@ +#include "ph_ps2_phy.h" +#include "ph_ps2_phy.pio.h" + +void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx) { + queue_init(&this->qbytes, sizeof(u8), 9); + queue_init(&this->qpacks, sizeof(u8) * 9, 16); + + this->pio = pio; + this->sm = pio_claim_unused_sm(this->pio, true); + ps2phy_program_init(this->pio, this->sm, pio_add_program(this->pio, &ps2phy_program), data_pin); + + this->sent = 0; + this->rx = rx; +} + +u16 ph_ps2_frame(u8 byte) { + u8 parity = 1; + for (u8 i = 0; i < 8; i++) { + parity = parity ^ (byte >> i & 1); + } + return ((1 << 10) | (parity << 9) | (byte << 1)) ^ 0x7ff; +} + +void ph_ps2_phy_task(ph_ps2_phy* this) { + u8 i = 0; + u8 pack[9]; + + if (!queue_is_empty(&this->qbytes)) { + u8 byte; + + while (i < 9 && queue_try_remove(&this->qbytes, &byte)) { + i++; + pack[i] = byte; + } + + pack[0] = i; + queue_try_add(&this->qpacks, &pack); + } + + if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && !pio_interrupt_get(this->pio, 0)) { + if (queue_try_peek(&this->qpacks, &pack)) { + if (this->sent == pack[0]) { + this->sent = 0; + queue_try_remove(&this->qpacks, &pack); + } else { + this->sent++; + pio_sm_put(this->pio, this->sm, ph_ps2_frame(pack[this->sent])); + } + } + } + + if (!pio_sm_is_rx_fifo_empty(this->pio, this->sm)) { + u32 fifo = pio_sm_get(this->pio, this->sm); + fifo = fifo >> 23; + + u8 parity = 1; + for (i = 0; i < 8; i++) { + parity = parity ^ (fifo >> i & 1); + } + + if (parity != fifo >> 8) { + //ph_ps2_kbd_send(0xfe); + return; + } + + (*this->rx)(fifo); + } +} diff --git a/hid/pico/src/ph_ps2_phy.h b/hid/pico/src/ph_ps2_phy.h new file mode 100644 index 00000000..17dd9e0d --- /dev/null +++ b/hid/pico/src/ph_ps2_phy.h @@ -0,0 +1,19 @@ +#pragma once + +#include "ph_types.h" +#include "hardware/pio.h" +#include "pico/util/queue.h" + +typedef void (*rx_callback)(u8 byte); + +typedef struct { + PIO pio; + uint sm; + queue_t qbytes; + queue_t qpacks; + u8 sent; + rx_callback rx; +} ph_ps2_phy; + +void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx); +void ph_ps2_phy_task(ph_ps2_phy* this); \ No newline at end of file diff --git a/hid/pico/src/ph_ps2_phy.pio b/hid/pico/src/ph_ps2_phy.pio new file mode 100644 index 00000000..055cc6d7 --- /dev/null +++ b/hid/pico/src/ph_ps2_phy.pio @@ -0,0 +1,81 @@ +; +; Copyright (c) 2022 No0ne (https://github.com/No0ne) +; (c) 2023 Dustin Hoffman +; +; SPDX-License-Identifier: MIT +; + +.program ps2phy +.side_set 1 opt pindirs + +restart: + irq clear 0 rel + set pindirs 0 side 0 // clock and data to input mode + +receivecheck: + jmp pin sendcheck // if clock is high, see if we have data to send + irq set 0 rel // clock is being pulled low, set busy flag + wait 1 pin 1 // wait for clock to be pulled high + + // we are not sending, look for a start bit (clock high, data low) + in pins 1 // read in from data + mov x isr // move what we read to x + mov isr null // clear ISR. + jmp !x receive // if x is low, start the receive process. + jmp restart // not receiving + +receive: + set pindirs, 1 [6] // clock low. + set x, 8 // set loop counter. + +receiveloop: + set pindirs, 0 [6] // clock high + in pins, 1 [4] // read a bit into ISR. + set pindirs, 1 [6] // clock low + jmp x-- receiveloop [4] // iterate + set pindirs, 0 [6] // clock high + nop side 1 [6] // data low + set pindirs, 1 [7] // clock low + jmp restart + +sendcheck: + jmp !osre wait_to_write // see if we have data to send + jmp receivecheck // no data to send, restart + +wait_to_write: + irq set 0 rel + set x 10 // number of bits to write out + +sendloop: + set pindirs, 0 [6] // clock set to input (high) + jmp pin sendcontinue // if clock is high, host is still receiving data + irq set 1 rel // clock was low, host wants to send data, notify of failure to send data + mov osr null // clear OSR + jmp restart +sendcontinue: + out pindirs, 1 [6] // write out data + set pindirs, 1 [6] // set clock low + jmp x-- sendloop [6] + +% c-sdk { + void ps2phy_program_init(PIO pio, uint sm, uint offset, uint dat) { + pio_sm_config c = ps2phy_program_get_default_config(offset); + + u8 clk = dat + 1; + pio_gpio_init(pio, clk); + pio_gpio_init(pio, dat); + + // Use a frequency high enough to effectivly sample clock and data. + sm_config_set_clkdiv(&c, 427); // 2560 is 20 µs, 640 is 5 µs, 427 is 3.3333 µs + sm_config_set_jmp_pin(&c, clk); + sm_config_set_set_pins(&c, clk, 1); + sm_config_set_sideset_pins(&c, dat); + sm_config_set_out_pins(&c, dat, 1); + sm_config_set_out_shift(&c, true, true, 11); + sm_config_set_in_pins(&c, dat); + sm_config_set_in_shift(&c, true, true, 9); + + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); + } +%} \ No newline at end of file From 1e46110a1259202f30cb94a4d7a814e59a91a38d Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Fri, 25 Aug 2023 13:38:28 +0300 Subject: [PATCH 03/10] new sponsor --- web/kvm/index.html | 1 + web/kvm/window-about.pug | 1 + 2 files changed, 2 insertions(+) diff --git a/web/kvm/index.html b/web/kvm/index.html index 5116e15b..b4b0740e 100644 --- a/web/kvm/index.html +++ b/web/kvm/index.html @@ -2327,6 +2327,7 @@
  • Marcos Wolf
  • Marek Marczykowski-Górecki
  • Marius
  • +
  • Mariusz Stępień
  • Mar. Balske
  • Mark Farrell
  • Mark Gilbert
  • diff --git a/web/kvm/window-about.pug b/web/kvm/window-about.pug index c8fcd5d6..69191bd9 100644 --- a/web/kvm/window-about.pug +++ b/web/kvm/window-about.pug @@ -390,6 +390,7 @@ div(id="about-window" class="window") li Marcos Wolf li Marek Marczykowski-Górecki li Marius + li Mariusz Stępień li Mar. Balske li Mark Farrell li Mark Gilbert From d4e5722b24cf63bc753da210eb7cd62646563019 Mon Sep 17 00:00:00 2001 From: No0ne Date: Sat, 26 Aug 2023 00:35:10 +0200 Subject: [PATCH 04/10] pico hid: ps/2 fix retransmission (#145) * pico hid: ps/2 keyboard support getting started (#139) * pico hid: ps/2 bytes and packets queue * pico hid: ps/2 bytes and packets queue (#142) * pico hid: ps/2 fix retransmission --- hid/pico/src/ph_ps2.c | 34 +++++++++++----------------------- hid/pico/src/ph_ps2_phy.c | 26 +++++++++++++++++++------- hid/pico/src/ph_ps2_phy.h | 4 +++- hid/pico/src/ph_ps2_phy.pio | 23 +++++++++++------------ 4 files changed, 44 insertions(+), 43 deletions(-) diff --git a/hid/pico/src/ph_ps2.c b/hid/pico/src/ph_ps2.c index 51c0a21b..4aca54ee 100644 --- a/hid/pico/src/ph_ps2.c +++ b/hid/pico/src/ph_ps2.c @@ -33,6 +33,7 @@ bool ph_g_ps2_mouse_online = 0; ph_ps2_phy ph_ps2_kbd; ph_ps2_phy ph_ps2_mouse; +u8 const ph_ps2_led2ps2[] = { 0, 4, 1, 5, 2, 6, 3, 7 }; u8 const ph_ps2_mod2ps2[] = { 0x14, 0x12, 0x11, 0x1f, 0x14, 0x59, 0x11, 0x27 }; u8 const ph_ps2_hid2ps2[] = { 0x00, 0x00, 0xfc, 0x00, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34, 0x33, 0x43, 0x3b, 0x42, 0x4b, @@ -60,10 +61,10 @@ void ph_ps2_kbd_maybe_send_e0(u8 byte) { } } -void ph_ps2_kbd_receive(u8 byte) { - switch(byte) { +void ph_ps2_kbd_receive(u8 byte, u8 prev_byte) { + switch(prev_byte) { case 0xed: // CMD: Set LEDs - + ph_g_ps2_kbd_leds = ph_ps2_led2ps2[byte]; break; case 0xf3: // CMD: Set typematic rate and delay @@ -73,16 +74,12 @@ void ph_ps2_kbd_receive(u8 byte) { default: switch(byte) { case 0xff: // CMD: Reset - //pio_sm_clear_fifos(pio, sm); - //pio_sm_drain_tx_fifo(pio, sm); + ph_g_ps2_kbd_online = true; + ph_g_ps2_kbd_leds = 0; ph_ps2_kbd_send(0xfa); ph_ps2_kbd_send(0xaa); return; - case 0xfe: // CMD: Resend - - return; - case 0xee: // CMD: Echo ph_ps2_kbd_send(0xee); return; @@ -93,18 +90,14 @@ void ph_ps2_kbd_receive(u8 byte) { ph_ps2_kbd_send(0x83); return; - case 0xf3: // CMD: Set typematic rate and delay - case 0xed: // CMD: Set LEDs - - break; - case 0xf4: // CMD: Enable scanning - + ph_g_ps2_kbd_online = true; break; case 0xf5: // CMD: Disable scanning, restore default parameters case 0xf6: // CMD: Set default parameters - + ph_g_ps2_kbd_online = byte == 0xf6; + ph_g_ps2_kbd_leds = 0; break; } break; @@ -129,6 +122,7 @@ void ph_ps2_init(void) { if (PH_O_IS_KBD_PS2) { ph_ps2_phy_init(&ph_ps2_kbd, pio0, 11, &ph_ps2_kbd_receive); // keyboard: GPIO11=data, GPIO12=clock ph_ps2_kbd_send(0xaa); + ph_g_ps2_kbd_online = true; } if (PH_O_IS_MOUSE_PS2) { @@ -144,16 +138,10 @@ void ph_ps2_task(void) { if (PH_O_IS_MOUSE_PS2) { ph_ps2_phy_task(&ph_ps2_mouse); } - // Here you should update some values: - // - ph_g_ps2_kbd_leds - keyboard LEDs mask like on USB - // - ph_g_ps2_kbd_online - if keyboard online (by clock?) - // - ph_g_ps2_mouse_online if mouse online (by clock?) - // It is important not to have ANY sleep() call inside it. - // There should also be no freezes if the keyboard or mouse is not available. } void ph_ps2_kbd_send_key(u8 key, bool state) { - if (PH_O_IS_KBD_PS2) { + if (PH_O_IS_KBD_PS2 && ph_g_ps2_kbd_online) { if (key >= 0xe0 && key <= 0xe7) { key -= 0xe0; diff --git a/hid/pico/src/ph_ps2_phy.c b/hid/pico/src/ph_ps2_phy.c index b5ffba75..6f19a7ca 100644 --- a/hid/pico/src/ph_ps2_phy.c +++ b/hid/pico/src/ph_ps2_phy.c @@ -11,9 +11,11 @@ void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx) { this->sent = 0; this->rx = rx; + this->last_rx = 0; + this->last_tx = 0; } -u16 ph_ps2_frame(u8 byte) { +u32 ph_ps2_frame(u8 byte) { u8 parity = 1; for (u8 i = 0; i < 8; i++) { parity = parity ^ (byte >> i & 1); @@ -23,11 +25,10 @@ u16 ph_ps2_frame(u8 byte) { void ph_ps2_phy_task(ph_ps2_phy* this) { u8 i = 0; + u8 byte; u8 pack[9]; if (!queue_is_empty(&this->qbytes)) { - u8 byte; - while (i < 9 && queue_try_remove(&this->qbytes, &byte)) { i++; pack[i] = byte; @@ -37,18 +38,25 @@ void ph_ps2_phy_task(ph_ps2_phy* this) { queue_try_add(&this->qpacks, &pack); } - if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && !pio_interrupt_get(this->pio, 0)) { + if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && !pio_interrupt_get(this->pio, this->sm * 2 + 0)) { if (queue_try_peek(&this->qpacks, &pack)) { if (this->sent == pack[0]) { this->sent = 0; queue_try_remove(&this->qpacks, &pack); } else { this->sent++; - pio_sm_put(this->pio, this->sm, ph_ps2_frame(pack[this->sent])); + this->last_tx = pack[this->sent]; + pio_sm_put(this->pio, this->sm, ph_ps2_frame(this->last_tx)); } } } + if (pio_interrupt_get(this->pio, this->sm * 2 + 1)) { + this->sent = 0; + pio_sm_drain_tx_fifo(this->pio, this->sm); + pio_interrupt_clear(this->pio, this->sm * 2 + 1); + } + if (!pio_sm_is_rx_fifo_empty(this->pio, this->sm)) { u32 fifo = pio_sm_get(this->pio, this->sm); fifo = fifo >> 23; @@ -59,10 +67,14 @@ void ph_ps2_phy_task(ph_ps2_phy* this) { } if (parity != fifo >> 8) { - //ph_ps2_kbd_send(0xfe); + pio_sm_put(this->pio, this->sm, ph_ps2_frame(0xfe)); return; } - (*this->rx)(fifo); + while(queue_try_remove(&this->qbytes, &byte)); + while(queue_try_remove(&this->qpacks, &pack)); + + (*this->rx)(fifo, this->last_rx); + this->last_rx = fifo; } } diff --git a/hid/pico/src/ph_ps2_phy.h b/hid/pico/src/ph_ps2_phy.h index 17dd9e0d..19008c99 100644 --- a/hid/pico/src/ph_ps2_phy.h +++ b/hid/pico/src/ph_ps2_phy.h @@ -4,7 +4,7 @@ #include "hardware/pio.h" #include "pico/util/queue.h" -typedef void (*rx_callback)(u8 byte); +typedef void (*rx_callback)(u8 byte, u8 prev_byte); typedef struct { PIO pio; @@ -13,6 +13,8 @@ typedef struct { queue_t qpacks; u8 sent; rx_callback rx; + u8 last_rx; + u8 last_tx; } ph_ps2_phy; void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx); diff --git a/hid/pico/src/ph_ps2_phy.pio b/hid/pico/src/ph_ps2_phy.pio index 055cc6d7..a2e4c81f 100644 --- a/hid/pico/src/ph_ps2_phy.pio +++ b/hid/pico/src/ph_ps2_phy.pio @@ -9,8 +9,8 @@ .side_set 1 opt pindirs restart: - irq clear 0 rel - set pindirs 0 side 0 // clock and data to input mode + set pindirs 0 [4] // set clock to input mode + irq clear 0 rel side 0 // clear busy flag, set data to input mode receivecheck: jmp pin sendcheck // if clock is high, see if we have data to send @@ -20,17 +20,17 @@ receivecheck: // we are not sending, look for a start bit (clock high, data low) in pins 1 // read in from data mov x isr // move what we read to x - mov isr null // clear ISR. - jmp !x receive // if x is low, start the receive process. + mov isr null // clear ISR + jmp !x receive // if x is low, start the receive process jmp restart // not receiving receive: - set pindirs, 1 [6] // clock low. - set x, 8 // set loop counter. + set pindirs, 1 [6] // clock low + set x, 8 // set loop counter receiveloop: set pindirs, 0 [6] // clock high - in pins, 1 [4] // read a bit into ISR. + in pins, 1 [4] // read a bit into ISR set pindirs, 1 [6] // clock low jmp x-- receiveloop [4] // iterate set pindirs, 0 [6] // clock high @@ -43,15 +43,14 @@ sendcheck: jmp receivecheck // no data to send, restart wait_to_write: - irq set 0 rel - set x 10 // number of bits to write out + irq set 0 rel // set busy flag + set x 10 // number of bits to write out sendloop: set pindirs, 0 [6] // clock set to input (high) jmp pin sendcontinue // if clock is high, host is still receiving data - irq set 1 rel // clock was low, host wants to send data, notify of failure to send data - mov osr null // clear OSR - jmp restart + irq wait 1 rel // clock was low, host wants to send data, notify of failure to send data + jmp restart // and wait for restart sendcontinue: out pindirs, 1 [6] // write out data set pindirs, 1 [6] // set clock low From 546a8cef8bfaf15e6fe3ac02d9c1f916e95c230d Mon Sep 17 00:00:00 2001 From: No0ne Date: Sun, 27 Aug 2023 04:47:58 +0200 Subject: [PATCH 05/10] pico hid: ps/2 keyboard support finished (#146) --- hid/pico/src/ph_ps2.c | 135 ++++++++++++++++++++++++++++++++------ hid/pico/src/ph_ps2_phy.c | 35 ++++++---- hid/pico/src/ph_ps2_phy.h | 1 + 3 files changed, 136 insertions(+), 35 deletions(-) diff --git a/hid/pico/src/ph_ps2.c b/hid/pico/src/ph_ps2.c index 4aca54ee..587500ac 100644 --- a/hid/pico/src/ph_ps2.c +++ b/hid/pico/src/ph_ps2.c @@ -30,9 +30,18 @@ u8 ph_g_ps2_kbd_leds = 0; bool ph_g_ps2_kbd_online = 0; bool ph_g_ps2_mouse_online = 0; + ph_ps2_phy ph_ps2_kbd; ph_ps2_phy ph_ps2_mouse; +bool ph_ps2_kbd_scanning; +u32 ph_ps2_kbd_repeat_us; +u16 ph_ps2_kbd_delay_ms; +u8 ph_ps2_kbd_repeat = 0; +bool ph_ps2_kbd_repeatmod = false; +alarm_id_t ph_ps2_kbd_repeater; +s8 ph_ps2_is_ctrl = 0; + u8 const ph_ps2_led2ps2[] = { 0, 4, 1, 5, 2, 6, 3, 7 }; u8 const ph_ps2_mod2ps2[] = { 0x14, 0x12, 0x11, 0x1f, 0x14, 0x59, 0x11, 0x27 }; u8 const ph_ps2_hid2ps2[] = { @@ -46,6 +55,13 @@ u8 const ph_ps2_hid2ps2[] = { 0x48, 0x50, 0x57, 0x5f }; u8 const ph_ps2_maparray = sizeof(ph_ps2_hid2ps2); +u32 const ph_ps2_repeats[] = { + 33333, 37453, 41667, 45872, 48309, 54054, 58480, 62500, + 66667, 75188, 83333, 91743, 100000, 108696, 116279, 125000, + 133333, 149254, 166667, 181818, 200000, 217391, 232558, 250000, + 270270, 303030, 333333, 370370, 400000, 434783, 476190, 500000 +}; +u16 const ph_ps2_delays[] = { 250, 500, 750, 1000 }; void ph_ps2_kbd_send(u8 byte) { queue_try_add(&ph_ps2_kbd.qbytes, &byte); @@ -61,24 +77,59 @@ void ph_ps2_kbd_maybe_send_e0(u8 byte) { } } +int64_t ph_ps2_repeat_callback() { + if (ph_ps2_kbd_repeat) { + if (ph_ps2_kbd_repeatmod) { + + if (ph_ps2_kbd_repeat > 3 && ph_ps2_kbd_repeat != 6) ph_ps2_kbd_send(0xe0); + ph_ps2_kbd_send(ph_ps2_mod2ps2[ph_ps2_kbd_repeat - 1]); + + } else { + + ph_ps2_kbd_maybe_send_e0(ph_ps2_kbd_repeat); + ph_ps2_kbd_send(ph_ps2_hid2ps2[ph_ps2_kbd_repeat]); + + } + + return ph_ps2_kbd_repeat_us; + } + + ph_ps2_kbd_repeater = 0; + return 0; +} + +int64_t ph_ps2_blink_callback() { + ph_g_ps2_kbd_leds = 0; + ph_ps2_kbd_send(0xaa); + return 0; +} + +void ph_ps2_kbd_reset() { + ph_ps2_kbd_scanning = true; + ph_ps2_kbd_repeat_us = 91743; + ph_ps2_kbd_delay_ms = 500; + ph_ps2_kbd_repeat = 0; + ph_g_ps2_kbd_leds = 7; + add_alarm_in_ms(500, ph_ps2_blink_callback, NULL, false); +} + void ph_ps2_kbd_receive(u8 byte, u8 prev_byte) { - switch(prev_byte) { + switch (prev_byte) { case 0xed: // CMD: Set LEDs + if (byte > 7) byte = 0; ph_g_ps2_kbd_leds = ph_ps2_led2ps2[byte]; break; case 0xf3: // CMD: Set typematic rate and delay - + ph_ps2_kbd_repeat_us = ph_ps2_repeats[byte & 0x1f]; + ph_ps2_kbd_delay_ms = ph_ps2_delays[(byte & 0x60) >> 5]; break; default: - switch(byte) { + switch (byte) { case 0xff: // CMD: Reset - ph_g_ps2_kbd_online = true; - ph_g_ps2_kbd_leds = 0; - ph_ps2_kbd_send(0xfa); - ph_ps2_kbd_send(0xaa); - return; + ph_ps2_kbd_reset(); + break; case 0xee: // CMD: Echo ph_ps2_kbd_send(0xee); @@ -91,12 +142,15 @@ void ph_ps2_kbd_receive(u8 byte, u8 prev_byte) { return; case 0xf4: // CMD: Enable scanning - ph_g_ps2_kbd_online = true; + ph_ps2_kbd_scanning = true; break; case 0xf5: // CMD: Disable scanning, restore default parameters case 0xf6: // CMD: Set default parameters - ph_g_ps2_kbd_online = byte == 0xf6; + ph_ps2_kbd_scanning = byte == 0xf6; + ph_ps2_kbd_repeat_us = 91743; + ph_ps2_kbd_delay_ms = 500; + ph_ps2_kbd_repeat = 0; ph_g_ps2_kbd_leds = 0; break; } @@ -107,7 +161,7 @@ void ph_ps2_kbd_receive(u8 byte, u8 prev_byte) { } void ph_ps2_mouse_receive(u8 byte) { - switch(byte) { + switch (byte) { } } @@ -121,35 +175,61 @@ void ph_ps2_init(void) { if (PH_O_IS_KBD_PS2) { ph_ps2_phy_init(&ph_ps2_kbd, pio0, 11, &ph_ps2_kbd_receive); // keyboard: GPIO11=data, GPIO12=clock - ph_ps2_kbd_send(0xaa); - ph_g_ps2_kbd_online = true; + ph_ps2_kbd_reset(); } if (PH_O_IS_MOUSE_PS2) { - ph_ps2_phy_init(&ph_ps2_mouse, pio1, 14, &ph_ps2_mouse_receive); // mouse: GPIO14=data, GPIO15=clock + //ph_ps2_phy_init(&ph_ps2_mouse, pio1, 14, &ph_ps2_mouse_receive); // mouse: GPIO14=data, GPIO15=clock } } void ph_ps2_task(void) { if (PH_O_IS_KBD_PS2) { ph_ps2_phy_task(&ph_ps2_kbd); + ph_g_ps2_kbd_online = ph_ps2_kbd_scanning && ph_ps2_kbd.idle; } if (PH_O_IS_MOUSE_PS2) { - ph_ps2_phy_task(&ph_ps2_mouse); + //ph_ps2_phy_task(&ph_ps2_mouse); } } void ph_ps2_kbd_send_key(u8 key, bool state) { - if (PH_O_IS_KBD_PS2 && ph_g_ps2_kbd_online) { + if (PH_O_IS_KBD_PS2 && ph_ps2_kbd_scanning) { if (key >= 0xe0 && key <= 0xe7) { + + if (key == 0xe0 || key == 0xe4) { + if (state) { + ph_ps2_is_ctrl++; + } else { + ph_ps2_is_ctrl--; + } + + if (ph_ps2_is_ctrl < 0 || ph_ps2_is_ctrl > 2) { + ph_ps2_is_ctrl = 0; + } + } + key -= 0xe0; if (key > 2 && key != 5) { ph_ps2_kbd_send(0xe0); } - if (!state) { + if (state) { + ph_ps2_kbd_repeat = key + 1; + ph_ps2_kbd_repeatmod = true; + + if (ph_ps2_kbd_repeater) { + cancel_alarm(ph_ps2_kbd_repeater); + } + + ph_ps2_kbd_repeater = add_alarm_in_ms(ph_ps2_kbd_delay_ms, ph_ps2_repeat_callback, NULL, false); + } else { + if (ph_ps2_kbd_repeat == key + 1 && ph_ps2_kbd_repeatmod) { + ph_ps2_kbd_repeat = 0; + } + ph_ps2_kbd_send(0xf0); } @@ -158,20 +238,33 @@ void ph_ps2_kbd_send_key(u8 key, bool state) { } else if (key < ph_ps2_maparray) { if (key == 0x48) { + ph_ps2_kbd_repeat = 0; + if (state) { - - if (false) { // TODO: is shift + if (ph_ps2_is_ctrl) { ph_ps2_kbd_send(0xe0); ph_ps2_kbd_send(0x7e); ph_ps2_kbd_send(0xe0); ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x7e); } else { ph_ps2_kbd_send(0xe1); ph_ps2_kbd_send(0x14); ph_ps2_kbd_send(0x77); ph_ps2_kbd_send(0xe1); ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x14); ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x77); } - } } else { ph_ps2_kbd_maybe_send_e0(key); - if (!state) { + if (state) { + ph_ps2_kbd_repeat = key; + ph_ps2_kbd_repeatmod = false; + + if (ph_ps2_kbd_repeater) { + cancel_alarm(ph_ps2_kbd_repeater); + } + + ph_ps2_kbd_repeater = add_alarm_in_ms(ph_ps2_kbd_delay_ms, ph_ps2_repeat_callback, NULL, false); + } else { + if (ph_ps2_kbd_repeat == key && !ph_ps2_kbd_repeatmod) { + ph_ps2_kbd_repeat = 0; + } + ph_ps2_kbd_send(0xf0); } diff --git a/hid/pico/src/ph_ps2_phy.c b/hid/pico/src/ph_ps2_phy.c index 6f19a7ca..670e625a 100644 --- a/hid/pico/src/ph_ps2_phy.c +++ b/hid/pico/src/ph_ps2_phy.c @@ -1,6 +1,14 @@ #include "ph_ps2_phy.h" #include "ph_ps2_phy.pio.h" +u32 ph_ps2_phy_frame(u8 byte) { + bool parity = 1; + for (u8 i = 0; i < 8; i++) { + parity = parity ^ (byte >> i & 1); + } + return ((1 << 10) | (parity << 9) | (byte << 1)) ^ 0x7ff; +} + void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx) { queue_init(&this->qbytes, sizeof(u8), 9); queue_init(&this->qpacks, sizeof(u8) * 9, 16); @@ -13,14 +21,7 @@ void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx) { this->rx = rx; this->last_rx = 0; this->last_tx = 0; -} - -u32 ph_ps2_frame(u8 byte) { - u8 parity = 1; - for (u8 i = 0; i < 8; i++) { - parity = parity ^ (byte >> i & 1); - } - return ((1 << 10) | (parity << 9) | (byte << 1)) ^ 0x7ff; + this->idle = true; } void ph_ps2_phy_task(ph_ps2_phy* this) { @@ -38,7 +39,9 @@ void ph_ps2_phy_task(ph_ps2_phy* this) { queue_try_add(&this->qpacks, &pack); } - if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && !pio_interrupt_get(this->pio, this->sm * 2 + 0)) { + this->idle = !pio_interrupt_get(this->pio, this->sm * 2); + + if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && this->idle) { if (queue_try_peek(&this->qpacks, &pack)) { if (this->sent == pack[0]) { this->sent = 0; @@ -46,7 +49,7 @@ void ph_ps2_phy_task(ph_ps2_phy* this) { } else { this->sent++; this->last_tx = pack[this->sent]; - pio_sm_put(this->pio, this->sm, ph_ps2_frame(this->last_tx)); + pio_sm_put(this->pio, this->sm, ph_ps2_phy_frame(this->last_tx)); } } } @@ -58,16 +61,20 @@ void ph_ps2_phy_task(ph_ps2_phy* this) { } if (!pio_sm_is_rx_fifo_empty(this->pio, this->sm)) { - u32 fifo = pio_sm_get(this->pio, this->sm); - fifo = fifo >> 23; + u32 fifo = pio_sm_get(this->pio, this->sm) >> 23; - u8 parity = 1; + bool parity = 1; for (i = 0; i < 8; i++) { parity = parity ^ (fifo >> i & 1); } if (parity != fifo >> 8) { - pio_sm_put(this->pio, this->sm, ph_ps2_frame(0xfe)); + pio_sm_put(this->pio, this->sm, ph_ps2_phy_frame(0xfe)); + return; + } + + if (fifo == 0xfe) { + pio_sm_put(this->pio, this->sm, ph_ps2_phy_frame(this->last_tx)); return; } diff --git a/hid/pico/src/ph_ps2_phy.h b/hid/pico/src/ph_ps2_phy.h index 19008c99..3ed7dcfb 100644 --- a/hid/pico/src/ph_ps2_phy.h +++ b/hid/pico/src/ph_ps2_phy.h @@ -15,6 +15,7 @@ typedef struct { rx_callback rx; u8 last_rx; u8 last_tx; + bool idle; } ph_ps2_phy; void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx); From 19c1c7b933619d82695851831aa0a063f2e027a1 Mon Sep 17 00:00:00 2001 From: No0ne Date: Wed, 30 Aug 2023 22:51:30 +0200 Subject: [PATCH 06/10] pico hid: basic ps/2 mouse support (#147) --- hid/pico/src/CMakeLists.txt | 2 + hid/pico/src/ph_ps2.c | 255 +----------------------------------- hid/pico/src/ph_ps2.h | 4 + hid/pico/src/ph_ps2_kbd.c | 222 +++++++++++++++++++++++++++++++ hid/pico/src/ph_ps2_mouse.c | 191 +++++++++++++++++++++++++++ hid/pico/src/ph_ps2_phy.c | 21 ++- hid/pico/src/ph_ps2_phy.pio | 9 +- 7 files changed, 445 insertions(+), 259 deletions(-) create mode 100644 hid/pico/src/ph_ps2_kbd.c create mode 100644 hid/pico/src/ph_ps2_mouse.c diff --git a/hid/pico/src/CMakeLists.txt b/hid/pico/src/CMakeLists.txt index e2897198..743759c2 100644 --- a/hid/pico/src/CMakeLists.txt +++ b/hid/pico/src/CMakeLists.txt @@ -9,6 +9,8 @@ target_sources(${target_name} PRIVATE ph_usb_mouse.c ph_ps2.c ph_ps2_phy.c + ph_ps2_kbd.c + ph_ps2_mouse.c ph_cmds.c ph_com.c ph_com_bridge.c diff --git a/hid/pico/src/ph_ps2.c b/hid/pico/src/ph_ps2.c index 587500ac..d5bc9beb 100644 --- a/hid/pico/src/ph_ps2.c +++ b/hid/pico/src/ph_ps2.c @@ -24,281 +24,38 @@ #include "ph_types.h" #include "ph_outputs.h" -#include "ph_ps2_phy.h" #include "hardware/gpio.h" u8 ph_g_ps2_kbd_leds = 0; bool ph_g_ps2_kbd_online = 0; bool ph_g_ps2_mouse_online = 0; -ph_ps2_phy ph_ps2_kbd; -ph_ps2_phy ph_ps2_mouse; - -bool ph_ps2_kbd_scanning; -u32 ph_ps2_kbd_repeat_us; -u16 ph_ps2_kbd_delay_ms; -u8 ph_ps2_kbd_repeat = 0; -bool ph_ps2_kbd_repeatmod = false; -alarm_id_t ph_ps2_kbd_repeater; -s8 ph_ps2_is_ctrl = 0; - -u8 const ph_ps2_led2ps2[] = { 0, 4, 1, 5, 2, 6, 3, 7 }; -u8 const ph_ps2_mod2ps2[] = { 0x14, 0x12, 0x11, 0x1f, 0x14, 0x59, 0x11, 0x27 }; -u8 const ph_ps2_hid2ps2[] = { - 0x00, 0x00, 0xfc, 0x00, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34, 0x33, 0x43, 0x3b, 0x42, 0x4b, - 0x3a, 0x31, 0x44, 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d, 0x22, 0x35, 0x1a, 0x16, 0x1e, - 0x26, 0x25, 0x2e, 0x36, 0x3d, 0x3e, 0x46, 0x45, 0x5a, 0x76, 0x66, 0x0d, 0x29, 0x4e, 0x55, 0x54, - 0x5b, 0x5d, 0x5d, 0x4c, 0x52, 0x0e, 0x41, 0x49, 0x4a, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03, 0x0b, - 0x83, 0x0a, 0x01, 0x09, 0x78, 0x07, 0x7c, 0x7e, 0x7e, 0x70, 0x6c, 0x7d, 0x71, 0x69, 0x7a, 0x74, - 0x6b, 0x72, 0x75, 0x77, 0x4a, 0x7c, 0x7b, 0x79, 0x5a, 0x69, 0x72, 0x7a, 0x6b, 0x73, 0x74, 0x6c, - 0x75, 0x7d, 0x70, 0x71, 0x61, 0x2f, 0x37, 0x0f, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, - 0x48, 0x50, 0x57, 0x5f -}; -u8 const ph_ps2_maparray = sizeof(ph_ps2_hid2ps2); -u32 const ph_ps2_repeats[] = { - 33333, 37453, 41667, 45872, 48309, 54054, 58480, 62500, - 66667, 75188, 83333, 91743, 100000, 108696, 116279, 125000, - 133333, 149254, 166667, 181818, 200000, 217391, 232558, 250000, - 270270, 303030, 333333, 370370, 400000, 434783, 476190, 500000 -}; -u16 const ph_ps2_delays[] = { 250, 500, 750, 1000 }; - -void ph_ps2_kbd_send(u8 byte) { - queue_try_add(&ph_ps2_kbd.qbytes, &byte); -} - -void ph_ps2_kbd_maybe_send_e0(u8 byte) { - if (byte == 0x46 || - (byte >= 0x49 && byte <= 0x52) || - byte == 0x54 || byte == 0x58 || - byte == 0x65 || byte == 0x66 || - byte >= 0x81) { - ph_ps2_kbd_send(0xe0); - } -} - -int64_t ph_ps2_repeat_callback() { - if (ph_ps2_kbd_repeat) { - if (ph_ps2_kbd_repeatmod) { - - if (ph_ps2_kbd_repeat > 3 && ph_ps2_kbd_repeat != 6) ph_ps2_kbd_send(0xe0); - ph_ps2_kbd_send(ph_ps2_mod2ps2[ph_ps2_kbd_repeat - 1]); - - } else { - - ph_ps2_kbd_maybe_send_e0(ph_ps2_kbd_repeat); - ph_ps2_kbd_send(ph_ps2_hid2ps2[ph_ps2_kbd_repeat]); - - } - - return ph_ps2_kbd_repeat_us; - } - - ph_ps2_kbd_repeater = 0; - return 0; -} - -int64_t ph_ps2_blink_callback() { - ph_g_ps2_kbd_leds = 0; - ph_ps2_kbd_send(0xaa); - return 0; -} - -void ph_ps2_kbd_reset() { - ph_ps2_kbd_scanning = true; - ph_ps2_kbd_repeat_us = 91743; - ph_ps2_kbd_delay_ms = 500; - ph_ps2_kbd_repeat = 0; - ph_g_ps2_kbd_leds = 7; - add_alarm_in_ms(500, ph_ps2_blink_callback, NULL, false); -} - -void ph_ps2_kbd_receive(u8 byte, u8 prev_byte) { - switch (prev_byte) { - case 0xed: // CMD: Set LEDs - if (byte > 7) byte = 0; - ph_g_ps2_kbd_leds = ph_ps2_led2ps2[byte]; - break; - - case 0xf3: // CMD: Set typematic rate and delay - ph_ps2_kbd_repeat_us = ph_ps2_repeats[byte & 0x1f]; - ph_ps2_kbd_delay_ms = ph_ps2_delays[(byte & 0x60) >> 5]; - break; - - default: - switch (byte) { - case 0xff: // CMD: Reset - ph_ps2_kbd_reset(); - break; - - case 0xee: // CMD: Echo - ph_ps2_kbd_send(0xee); - return; - - case 0xf2: // CMD: Identify keyboard - ph_ps2_kbd_send(0xfa); - ph_ps2_kbd_send(0xab); - ph_ps2_kbd_send(0x83); - return; - - case 0xf4: // CMD: Enable scanning - ph_ps2_kbd_scanning = true; - break; - - case 0xf5: // CMD: Disable scanning, restore default parameters - case 0xf6: // CMD: Set default parameters - ph_ps2_kbd_scanning = byte == 0xf6; - ph_ps2_kbd_repeat_us = 91743; - ph_ps2_kbd_delay_ms = 500; - ph_ps2_kbd_repeat = 0; - ph_g_ps2_kbd_leds = 0; - break; - } - break; - } - - ph_ps2_kbd_send(0xfa); -} - -void ph_ps2_mouse_receive(u8 byte) { - switch (byte) { - - } -} - void ph_ps2_init(void) { if (PH_O_IS_KBD_PS2 || PH_O_IS_MOUSE_PS2) { - gpio_init(13); + gpio_init(13); // GPIO13=LV pull-up voltage gpio_set_dir(13, GPIO_OUT); - gpio_put(13, 1); // GPIO13=LV pull-up voltage + gpio_put(13, 1); } if (PH_O_IS_KBD_PS2) { - ph_ps2_phy_init(&ph_ps2_kbd, pio0, 11, &ph_ps2_kbd_receive); // keyboard: GPIO11=data, GPIO12=clock - ph_ps2_kbd_reset(); + ph_ps2_kbd_init(11); // keyboard: GPIO11=data, GPIO12=clock } if (PH_O_IS_MOUSE_PS2) { - //ph_ps2_phy_init(&ph_ps2_mouse, pio1, 14, &ph_ps2_mouse_receive); // mouse: GPIO14=data, GPIO15=clock + ph_ps2_mouse_init(14); // mouse: GPIO14=data, GPIO15=clock } } void ph_ps2_task(void) { if (PH_O_IS_KBD_PS2) { - ph_ps2_phy_task(&ph_ps2_kbd); - ph_g_ps2_kbd_online = ph_ps2_kbd_scanning && ph_ps2_kbd.idle; + ph_ps2_kbd_task(); } if (PH_O_IS_MOUSE_PS2) { - //ph_ps2_phy_task(&ph_ps2_mouse); + ph_ps2_mouse_task(); } } -void ph_ps2_kbd_send_key(u8 key, bool state) { - if (PH_O_IS_KBD_PS2 && ph_ps2_kbd_scanning) { - if (key >= 0xe0 && key <= 0xe7) { - - if (key == 0xe0 || key == 0xe4) { - if (state) { - ph_ps2_is_ctrl++; - } else { - ph_ps2_is_ctrl--; - } - - if (ph_ps2_is_ctrl < 0 || ph_ps2_is_ctrl > 2) { - ph_ps2_is_ctrl = 0; - } - } - - key -= 0xe0; - - if (key > 2 && key != 5) { - ph_ps2_kbd_send(0xe0); - } - - if (state) { - ph_ps2_kbd_repeat = key + 1; - ph_ps2_kbd_repeatmod = true; - - if (ph_ps2_kbd_repeater) { - cancel_alarm(ph_ps2_kbd_repeater); - } - - ph_ps2_kbd_repeater = add_alarm_in_ms(ph_ps2_kbd_delay_ms, ph_ps2_repeat_callback, NULL, false); - } else { - if (ph_ps2_kbd_repeat == key + 1 && ph_ps2_kbd_repeatmod) { - ph_ps2_kbd_repeat = 0; - } - - ph_ps2_kbd_send(0xf0); - } - - ph_ps2_kbd_send(ph_ps2_mod2ps2[key]); - - } else if (key < ph_ps2_maparray) { - - if (key == 0x48) { - ph_ps2_kbd_repeat = 0; - - if (state) { - if (ph_ps2_is_ctrl) { - ph_ps2_kbd_send(0xe0); ph_ps2_kbd_send(0x7e); ph_ps2_kbd_send(0xe0); ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x7e); - } else { - ph_ps2_kbd_send(0xe1); ph_ps2_kbd_send(0x14); ph_ps2_kbd_send(0x77); ph_ps2_kbd_send(0xe1); - ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x14); ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x77); - } - } - } else { - ph_ps2_kbd_maybe_send_e0(key); - - if (state) { - ph_ps2_kbd_repeat = key; - ph_ps2_kbd_repeatmod = false; - - if (ph_ps2_kbd_repeater) { - cancel_alarm(ph_ps2_kbd_repeater); - } - - ph_ps2_kbd_repeater = add_alarm_in_ms(ph_ps2_kbd_delay_ms, ph_ps2_repeat_callback, NULL, false); - } else { - if (ph_ps2_kbd_repeat == key && !ph_ps2_kbd_repeatmod) { - ph_ps2_kbd_repeat = 0; - } - - ph_ps2_kbd_send(0xf0); - } - - ph_ps2_kbd_send(ph_ps2_hid2ps2[key]); - } - } - } -} - -void ph_ps2_mouse_send_button(u8 button, bool state) { - // TODO: PS2: Send mouse button - // @button - USB button code - // @state - true if pressed, false if released - // The function should take care not to send duplicate events (if needed for PS/2) - // If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing. - (void)button; // Remove this - (void)state; // Remove this -} - -void ph_ps2_mouse_send_rel(s8 x, s8 y) { - // TODO: PS2: Send relative move event - // If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing. - (void)x; // Remove this - (void)y; // Remove this -} - -void ph_ps2_mouse_send_wheel(s8 h, s8 v) { - (void)h; - // TODO: PS2: Send wheel. As I understand, PS/2 has no horizontal scrolling, so @h just can be ignored. - // @v - vertical scrolling like on USB - // If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing. - (void)v; // Remove this -} - void ph_ps2_send_clear(void) { // TODO: PS2: Release all pressed buttons and keys. // If PH_O_IS_KBD_PS2, release all PS/2 buttons diff --git a/hid/pico/src/ph_ps2.h b/hid/pico/src/ph_ps2.h index 057299f3..6766cbf9 100644 --- a/hid/pico/src/ph_ps2.h +++ b/hid/pico/src/ph_ps2.h @@ -33,8 +33,12 @@ extern bool ph_g_ps2_mouse_online; void ph_ps2_init(void); void ph_ps2_task(void); +void ph_ps2_kbd_init(u8 gpio); +void ph_ps2_kbd_task(void); void ph_ps2_kbd_send_key(u8 key, bool state); +void ph_ps2_mouse_init(u8 gpio); +void ph_ps2_mouse_task(void); void ph_ps2_mouse_send_button(u8 button, bool state); void ph_ps2_mouse_send_rel(s8 x, s8 y); void ph_ps2_mouse_send_wheel(s8 h, s8 v); diff --git a/hid/pico/src/ph_ps2_kbd.c b/hid/pico/src/ph_ps2_kbd.c new file mode 100644 index 00000000..f9e0caa3 --- /dev/null +++ b/hid/pico/src/ph_ps2_kbd.c @@ -0,0 +1,222 @@ +#include "ph_outputs.h" +#include "ph_ps2_phy.h" + +extern u8 ph_g_ps2_kbd_leds; +extern bool ph_g_ps2_kbd_online; + +ph_ps2_phy ph_ps2_kbd; +bool ph_ps2_kbd_scanning; +u32 ph_ps2_kbd_repeat_us; +u16 ph_ps2_kbd_delay_ms; +u8 ph_ps2_kbd_repeat = 0; +bool ph_ps2_kbd_repeatmod = false; +alarm_id_t ph_ps2_kbd_repeater; +s8 ph_ps2_is_ctrl = 0; + +u8 const ph_ps2_led2ps2[] = { 0, 4, 1, 5, 2, 6, 3, 7 }; +u8 const ph_ps2_mod2ps2[] = { 0x14, 0x12, 0x11, 0x1f, 0x14, 0x59, 0x11, 0x27 }; +u8 const ph_ps2_hid2ps2[] = { + 0x00, 0x00, 0xfc, 0x00, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34, 0x33, 0x43, 0x3b, 0x42, 0x4b, + 0x3a, 0x31, 0x44, 0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d, 0x22, 0x35, 0x1a, 0x16, 0x1e, + 0x26, 0x25, 0x2e, 0x36, 0x3d, 0x3e, 0x46, 0x45, 0x5a, 0x76, 0x66, 0x0d, 0x29, 0x4e, 0x55, 0x54, + 0x5b, 0x5d, 0x5d, 0x4c, 0x52, 0x0e, 0x41, 0x49, 0x4a, 0x58, 0x05, 0x06, 0x04, 0x0c, 0x03, 0x0b, + 0x83, 0x0a, 0x01, 0x09, 0x78, 0x07, 0x7c, 0x7e, 0x7e, 0x70, 0x6c, 0x7d, 0x71, 0x69, 0x7a, 0x74, + 0x6b, 0x72, 0x75, 0x77, 0x4a, 0x7c, 0x7b, 0x79, 0x5a, 0x69, 0x72, 0x7a, 0x6b, 0x73, 0x74, 0x6c, + 0x75, 0x7d, 0x70, 0x71, 0x61, 0x2f, 0x37, 0x0f, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, + 0x48, 0x50, 0x57, 0x5f +}; +u8 const ph_ps2_maparray = sizeof(ph_ps2_hid2ps2); +u32 const ph_ps2_repeats[] = { + 33333, 37453, 41667, 45872, 48309, 54054, 58480, 62500, + 66667, 75188, 83333, 91743, 100000, 108696, 116279, 125000, + 133333, 149254, 166667, 181818, 200000, 217391, 232558, 250000, + 270270, 303030, 333333, 370370, 400000, 434783, 476190, 500000 +}; +u16 const ph_ps2_delays[] = { 250, 500, 750, 1000 }; + +void ph_ps2_kbd_send(u8 byte) { + queue_try_add(&ph_ps2_kbd.qbytes, &byte); +} + +void ph_ps2_kbd_maybe_send_e0(u8 byte) { + if (byte == 0x46 || + (byte >= 0x49 && byte <= 0x52) || + byte == 0x54 || byte == 0x58 || + byte == 0x65 || byte == 0x66 || + byte >= 0x81) { + ph_ps2_kbd_send(0xe0); + } +} + +int64_t ph_ps2_repeat_callback() { + if (ph_ps2_kbd_repeat) { + if (ph_ps2_kbd_repeatmod) { + + if (ph_ps2_kbd_repeat > 3 && ph_ps2_kbd_repeat != 6) ph_ps2_kbd_send(0xe0); + ph_ps2_kbd_send(ph_ps2_mod2ps2[ph_ps2_kbd_repeat - 1]); + + } else { + + ph_ps2_kbd_maybe_send_e0(ph_ps2_kbd_repeat); + ph_ps2_kbd_send(ph_ps2_hid2ps2[ph_ps2_kbd_repeat]); + + } + + return ph_ps2_kbd_repeat_us; + } + + ph_ps2_kbd_repeater = 0; + return 0; +} + +int64_t ph_ps2_blink_callback() { + ph_g_ps2_kbd_leds = 0; + ph_ps2_kbd_send(0xaa); + return 0; +} + +void ph_ps2_kbd_reset() { + ph_ps2_kbd_scanning = true; + ph_ps2_kbd_repeat_us = 91743; + ph_ps2_kbd_delay_ms = 500; + ph_ps2_kbd_repeat = 0; + ph_g_ps2_kbd_leds = 7; + add_alarm_in_ms(500, ph_ps2_blink_callback, NULL, false); +} + +void ph_ps2_kbd_send_key(u8 key, bool state) { + if (PH_O_IS_KBD_PS2 && ph_ps2_kbd_scanning) { + if (key >= 0xe0 && key <= 0xe7) { + + if (key == 0xe0 || key == 0xe4) { + if (state) { + ph_ps2_is_ctrl++; + } else { + ph_ps2_is_ctrl--; + } + + if (ph_ps2_is_ctrl < 0 || ph_ps2_is_ctrl > 2) { + ph_ps2_is_ctrl = 0; + } + } + + key -= 0xe0; + + if (key > 2 && key != 5) { + ph_ps2_kbd_send(0xe0); + } + + if (state) { + ph_ps2_kbd_repeat = key + 1; + ph_ps2_kbd_repeatmod = true; + + if (ph_ps2_kbd_repeater) { + cancel_alarm(ph_ps2_kbd_repeater); + } + + ph_ps2_kbd_repeater = add_alarm_in_ms(ph_ps2_kbd_delay_ms, ph_ps2_repeat_callback, NULL, false); + } else { + if (ph_ps2_kbd_repeat == key + 1 && ph_ps2_kbd_repeatmod) { + ph_ps2_kbd_repeat = 0; + } + + ph_ps2_kbd_send(0xf0); + } + + ph_ps2_kbd_send(ph_ps2_mod2ps2[key]); + + } else if (key < ph_ps2_maparray) { + + if (key == 0x48) { + ph_ps2_kbd_repeat = 0; + + if (state) { + if (ph_ps2_is_ctrl) { + ph_ps2_kbd_send(0xe0); ph_ps2_kbd_send(0x7e); ph_ps2_kbd_send(0xe0); ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x7e); + } else { + ph_ps2_kbd_send(0xe1); ph_ps2_kbd_send(0x14); ph_ps2_kbd_send(0x77); ph_ps2_kbd_send(0xe1); + ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x14); ph_ps2_kbd_send(0xf0); ph_ps2_kbd_send(0x77); + } + } + } else { + ph_ps2_kbd_maybe_send_e0(key); + + if (state) { + ph_ps2_kbd_repeat = key; + ph_ps2_kbd_repeatmod = false; + + if (ph_ps2_kbd_repeater) { + cancel_alarm(ph_ps2_kbd_repeater); + } + + ph_ps2_kbd_repeater = add_alarm_in_ms(ph_ps2_kbd_delay_ms, ph_ps2_repeat_callback, NULL, false); + } else { + if (ph_ps2_kbd_repeat == key && !ph_ps2_kbd_repeatmod) { + ph_ps2_kbd_repeat = 0; + } + + ph_ps2_kbd_send(0xf0); + } + + ph_ps2_kbd_send(ph_ps2_hid2ps2[key]); + } + } + } +} + +void ph_ps2_kbd_receive(u8 byte, u8 prev_byte) { + switch (prev_byte) { + case 0xed: // Set LEDs + if (byte > 7) byte = 0; + ph_g_ps2_kbd_leds = ph_ps2_led2ps2[byte]; + break; + + case 0xf3: // Set typematic rate and delay + ph_ps2_kbd_repeat_us = ph_ps2_repeats[byte & 0x1f]; + ph_ps2_kbd_delay_ms = ph_ps2_delays[(byte & 0x60) >> 5]; + break; + + default: + switch (byte) { + case 0xff: // Reset + ph_ps2_kbd_reset(); + break; + + case 0xee: // Echo + ph_ps2_kbd_send(0xee); + return; + + case 0xf2: // Identify keyboard + ph_ps2_kbd_send(0xfa); + ph_ps2_kbd_send(0xab); + ph_ps2_kbd_send(0x83); + return; + + case 0xf4: // Enable scanning + ph_ps2_kbd_scanning = true; + break; + + case 0xf5: // Disable scanning, restore default parameters + case 0xf6: // Set default parameters + ph_ps2_kbd_scanning = byte == 0xf6; + ph_ps2_kbd_repeat_us = 91743; + ph_ps2_kbd_delay_ms = 500; + ph_ps2_kbd_repeat = 0; + ph_g_ps2_kbd_leds = 0; + break; + } + break; + } + + ph_ps2_kbd_send(0xfa); +} + +void ph_ps2_kbd_task(void) { + ph_ps2_phy_task(&ph_ps2_kbd); + ph_g_ps2_kbd_online = ph_ps2_kbd_scanning && ph_ps2_kbd.idle; +} + +void ph_ps2_kbd_init(u8 gpio) { + ph_ps2_phy_init(&ph_ps2_kbd, pio0, gpio, &ph_ps2_kbd_receive); + ph_ps2_kbd_reset(); +} \ No newline at end of file diff --git a/hid/pico/src/ph_ps2_mouse.c b/hid/pico/src/ph_ps2_mouse.c new file mode 100644 index 00000000..279a06d6 --- /dev/null +++ b/hid/pico/src/ph_ps2_mouse.c @@ -0,0 +1,191 @@ +#include "ph_outputs.h" +#include "ph_ps2_phy.h" + +extern bool ph_g_ps2_mouse_online; + +ph_ps2_phy ph_ps2_mouse; +u8 ms_type = 0; +u8 ms_mode = 0; +u8 ms_input_mode = 0; +u8 ms_rate = 100; +u32 ms_magic_seq = 0x00; + +u8 buttons = 0; + +#define MS_TYPE_STANDARD 0x00 +#define MS_TYPE_WHEEL_3 0x03 +#define MS_TYPE_WHEEL_5 0x04 + +#define MS_MODE_IDLE 0 +#define MS_MODE_STREAMING 1 + +#define MS_INPUT_CMD 0 +#define MS_INPUT_SET_RATE 1 + +void ph_ps2_mouse_send(u8 byte) { + queue_try_add(&ph_ps2_mouse.qbytes, &byte); +} + +void ph_ps2_mouse_packet(u8 button, u8 x1, u8 y1) { + if(ms_mode == MS_MODE_STREAMING) { + u8 s = (button & 7) + 8; + u8 x = x1 & 0x7f; + u8 y = y1 & 0x7f; + u8 z = 0; + + if(x1 >> 7) { + s += 0x10; + x += 0x80; + } + + if(y1 >> 7) { + y = 0x80 - y; + } else if(y) { + s += 0x20; + y = 0x100 - y; + } + + ph_ps2_mouse_send(s); + ph_ps2_mouse_send(x); + ph_ps2_mouse_send(y); + + if (ms_type == MS_TYPE_WHEEL_3 || ms_type == MS_TYPE_WHEEL_5) { + /*if(report[3] >> 7) { + z = 0x8 - z; + } else if(z) { + z = 0x10 - z; + } + + if (ms_type == MS_TYPE_WHEEL_5) { + if (report[0] & 0x8) { + z += 0x10; + } + + if (report[0] & 0x10) { + z += 0x20; + } + }*/ + + ph_ps2_mouse_send(z); + } + } +} + +void ph_ps2_mouse_send_button(u8 button, bool state) { + // TODO: PS2: Send mouse button + // @button - USB button code + // @state - true if pressed, false if released + // The function should take care not to send duplicate events (if needed for PS/2) + // If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing. + (void)button; // Remove this + (void)state; // Remove this + + u8 bitval = 1; + + button--; + + if(state) { + buttons = buttons | (bitval << button); + } else { + buttons = buttons & ~(bitval << button); + } + + ph_ps2_mouse_packet(buttons, 0, 0); +} + +void ph_ps2_mouse_send_rel(s8 x1, s8 y1) { + // TODO: PS2: Send relative move event + // If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing. + ph_ps2_mouse_packet(buttons, x1, y1); +} + +void ph_ps2_mouse_send_wheel(s8 h, s8 v) { + (void)h; + // TODO: PS2: Send wheel. As I understand, PS/2 has no horizontal scrolling, so @h just can be ignored. + // @v - vertical scrolling like on USB + // If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing. + (void)v; // Remove this +} + +void ph_ps2_mouse_receive(u8 byte, u8 prev_byte) { + + if(ms_input_mode == MS_INPUT_SET_RATE) { + ms_rate = byte; + ms_input_mode = MS_INPUT_CMD; + ph_ps2_mouse_send(0xfa); + + ms_magic_seq = (ms_magic_seq << 8) | byte; + if(ms_type == MS_TYPE_STANDARD && ms_magic_seq == 0xc86450) { + ms_type = MS_TYPE_WHEEL_3; + } else if (ms_type == MS_TYPE_WHEEL_3 && ms_magic_seq == 0xc8c850) { + ms_type = MS_TYPE_WHEEL_5; + } + return; + } + + if(byte != 0xf3) { + ms_magic_seq = 0x00; + } + + switch(byte) { + case 0xff: // Reset + ms_type = MS_TYPE_STANDARD; + ms_mode = MS_MODE_IDLE; + ms_rate = 100; + + ph_ps2_mouse_send(0xfa); + ph_ps2_mouse_send(0xaa); + ph_ps2_mouse_send(ms_type); + return; + + case 0xf6: // Set Defaults + ms_type = MS_TYPE_STANDARD; + ms_rate = 100; + case 0xf5: // Disable Data Reporting + case 0xea: // Set Stream Mode + ms_mode = MS_MODE_IDLE; + ph_ps2_mouse_send(0xfa); + return; + + case 0xf4: // Enable Data Reporting + ms_mode = MS_MODE_STREAMING; + ph_ps2_mouse_send(0xfa); + return; + + case 0xf3: // Set Sample Rate + ms_input_mode = MS_INPUT_SET_RATE; + ph_ps2_mouse_send(0xfa); + return; + + case 0xf2: // Get Device ID + ph_ps2_mouse_send(0xfa); + ph_ps2_mouse_send(ms_type); + return; + + case 0xe9: // Status Request + ph_ps2_mouse_send(0xfa); + ph_ps2_mouse_send(0x00); // Bit6: Mode, Bit 5: Enable, Bit 4: Scaling, Bits[2,1,0] = Buttons[L,M,R] + ph_ps2_mouse_send(0x02); // Resolution + ph_ps2_mouse_send(ms_rate); // Sample Rate + return; + + // TODO: Implement (more of) these? + // case 0xf0: // Set Remote Mode + // case 0xee: // Set Wrap Mode + // case 0xec: // Reset Wrap Mode + // case 0xeb: // Read Data + // case 0xe8: // Set Resolution + // case 0xe7: // Set Scaling 2:1 + // case 0xe6: // Set Scaling 1:1 + } + + ph_ps2_mouse_send(0xfa); +} + +void ph_ps2_mouse_task(void) { + ph_ps2_phy_task(&ph_ps2_mouse); +} + +void ph_ps2_mouse_init(u8 gpio) { + ph_ps2_phy_init(&ph_ps2_mouse, pio0, gpio, &ph_ps2_mouse_receive); +} diff --git a/hid/pico/src/ph_ps2_phy.c b/hid/pico/src/ph_ps2_phy.c index 670e625a..05046b2b 100644 --- a/hid/pico/src/ph_ps2_phy.c +++ b/hid/pico/src/ph_ps2_phy.c @@ -1,6 +1,11 @@ +// Source: https://github.com/No0ne/ps2x2pico/blob/main/ps2phy.c +// replace ps2phy with ph_ps2_phy + #include "ph_ps2_phy.h" #include "ph_ps2_phy.pio.h" +uint prog = 0; + u32 ph_ps2_phy_frame(u8 byte) { bool parity = 1; for (u8 i = 0; i < 8; i++) { @@ -10,13 +15,17 @@ u32 ph_ps2_phy_frame(u8 byte) { } void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx) { + if(!prog) { + prog = pio_add_program(pio, &ph_ps2_phy_program); + } + queue_init(&this->qbytes, sizeof(u8), 9); queue_init(&this->qpacks, sizeof(u8) * 9, 16); - this->pio = pio; - this->sm = pio_claim_unused_sm(this->pio, true); - ps2phy_program_init(this->pio, this->sm, pio_add_program(this->pio, &ps2phy_program), data_pin); + this->sm = pio_claim_unused_sm(pio, true); + ph_ps2_phy_program_init(pio, this->sm, prog, data_pin); + this->pio = pio; this->sent = 0; this->rx = rx; this->last_rx = 0; @@ -39,7 +48,7 @@ void ph_ps2_phy_task(ph_ps2_phy* this) { queue_try_add(&this->qpacks, &pack); } - this->idle = !pio_interrupt_get(this->pio, this->sm * 2); + this->idle = !pio_interrupt_get(this->pio, this->sm); if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && this->idle) { if (queue_try_peek(&this->qpacks, &pack)) { @@ -54,10 +63,10 @@ void ph_ps2_phy_task(ph_ps2_phy* this) { } } - if (pio_interrupt_get(this->pio, this->sm * 2 + 1)) { + if (pio_interrupt_get(this->pio, this->sm + 4)) { this->sent = 0; pio_sm_drain_tx_fifo(this->pio, this->sm); - pio_interrupt_clear(this->pio, this->sm * 2 + 1); + pio_interrupt_clear(this->pio, this->sm + 4); } if (!pio_sm_is_rx_fifo_empty(this->pio, this->sm)) { diff --git a/hid/pico/src/ph_ps2_phy.pio b/hid/pico/src/ph_ps2_phy.pio index a2e4c81f..f2d7578c 100644 --- a/hid/pico/src/ph_ps2_phy.pio +++ b/hid/pico/src/ph_ps2_phy.pio @@ -4,8 +4,9 @@ ; ; SPDX-License-Identifier: MIT ; +; Source: https://github.com/No0ne/ps2x2pico/blob/main/ps2phy.pio -.program ps2phy +.program ph_ps2_phy .side_set 1 opt pindirs restart: @@ -49,7 +50,7 @@ wait_to_write: sendloop: set pindirs, 0 [6] // clock set to input (high) jmp pin sendcontinue // if clock is high, host is still receiving data - irq wait 1 rel // clock was low, host wants to send data, notify of failure to send data + irq wait 4 rel // clock was low, host wants to send data, notify of failure to send data jmp restart // and wait for restart sendcontinue: out pindirs, 1 [6] // write out data @@ -57,8 +58,8 @@ sendcontinue: jmp x-- sendloop [6] % c-sdk { - void ps2phy_program_init(PIO pio, uint sm, uint offset, uint dat) { - pio_sm_config c = ps2phy_program_get_default_config(offset); + void ph_ps2_phy_program_init(PIO pio, uint sm, uint offset, uint dat) { + pio_sm_config c = ph_ps2_phy_program_get_default_config(offset); u8 clk = dat + 1; pio_gpio_init(pio, clk); From a03c3c2367fc950c7ea8d4557fc24de8580dfd74 Mon Sep 17 00:00:00 2001 From: No0ne Date: Fri, 8 Sep 2023 09:29:15 +0200 Subject: [PATCH 07/10] pico hid: ps/2 mouse support (#148) --- hid/pico/src/ph_ps2_kbd.c | 4 +- hid/pico/src/ph_ps2_mouse.c | 254 +++++++++++++++--------------------- hid/pico/src/ph_ps2_phy.c | 30 +++-- hid/pico/src/ph_ps2_phy.h | 4 +- hid/pico/src/ph_ps2_phy.pio | 66 +++++----- 5 files changed, 160 insertions(+), 198 deletions(-) diff --git a/hid/pico/src/ph_ps2_kbd.c b/hid/pico/src/ph_ps2_kbd.c index f9e0caa3..e2fd7faf 100644 --- a/hid/pico/src/ph_ps2_kbd.c +++ b/hid/pico/src/ph_ps2_kbd.c @@ -213,10 +213,10 @@ void ph_ps2_kbd_receive(u8 byte, u8 prev_byte) { void ph_ps2_kbd_task(void) { ph_ps2_phy_task(&ph_ps2_kbd); - ph_g_ps2_kbd_online = ph_ps2_kbd_scanning && ph_ps2_kbd.idle; + ph_g_ps2_kbd_online = ph_ps2_kbd_scanning && !ph_ps2_kbd.busy; } void ph_ps2_kbd_init(u8 gpio) { ph_ps2_phy_init(&ph_ps2_kbd, pio0, gpio, &ph_ps2_kbd_receive); ph_ps2_kbd_reset(); -} \ No newline at end of file +} diff --git a/hid/pico/src/ph_ps2_mouse.c b/hid/pico/src/ph_ps2_mouse.c index 279a06d6..c825ca03 100644 --- a/hid/pico/src/ph_ps2_mouse.c +++ b/hid/pico/src/ph_ps2_mouse.c @@ -4,179 +4,134 @@ extern bool ph_g_ps2_mouse_online; ph_ps2_phy ph_ps2_mouse; -u8 ms_type = 0; -u8 ms_mode = 0; -u8 ms_input_mode = 0; -u8 ms_rate = 100; -u32 ms_magic_seq = 0x00; - -u8 buttons = 0; - -#define MS_TYPE_STANDARD 0x00 -#define MS_TYPE_WHEEL_3 0x03 -#define MS_TYPE_WHEEL_5 0x04 - -#define MS_MODE_IDLE 0 -#define MS_MODE_STREAMING 1 - -#define MS_INPUT_CMD 0 -#define MS_INPUT_SET_RATE 1 +bool ph_ps2_mouse_streaming = false; +u32 ph_ps2_mouse_magic_seq = 0; +u8 ph_ps2_mouse_type = 0; +u8 ph_ps2_mouse_buttons = 0; void ph_ps2_mouse_send(u8 byte) { queue_try_add(&ph_ps2_mouse.qbytes, &byte); } -void ph_ps2_mouse_packet(u8 button, u8 x1, u8 y1) { - if(ms_mode == MS_MODE_STREAMING) { - u8 s = (button & 7) + 8; - u8 x = x1 & 0x7f; - u8 y = y1 & 0x7f; - u8 z = 0; +void ph_ps2_mouse_pack(s8 x, s8 y, s8 h, s8 v) { + if (ph_ps2_mouse_streaming) { + u8 byte1 = 0x8 | (ph_ps2_mouse_buttons & 0x7); + s8 byte2 = x; + s8 byte3 = 0x100 - y; + s8 byte4 = 0; // = 0x100 - z; - if(x1 >> 7) { - s += 0x10; - x += 0x80; - } + if (byte2 < 0) byte1 |= 0x10; + if (byte3 < 0) byte1 |= 0x20; - if(y1 >> 7) { - y = 0x80 - y; - } else if(y) { - s += 0x20; - y = 0x100 - y; - } + ph_ps2_mouse_send(byte1); + ph_ps2_mouse_send(byte2); + ph_ps2_mouse_send(byte3); - ph_ps2_mouse_send(s); - ph_ps2_mouse_send(x); - ph_ps2_mouse_send(y); - - if (ms_type == MS_TYPE_WHEEL_3 || ms_type == MS_TYPE_WHEEL_5) { - /*if(report[3] >> 7) { - z = 0x8 - z; - } else if(z) { - z = 0x10 - z; + if (ph_ps2_mouse_type == 3 || ph_ps2_mouse_type == 4) { + //if (byte4 < -8) byte4 = -8; + //if (byte4 > 7) byte4 = 7; + //if (byte4 < 0) byte4 |= 0xf8; + + if (v < 0) byte4 = 0x01; + if (v > 0) byte4 = 0xff; + if (h < 0) byte4 = 0x02; + if (h > 0) byte4 = 0xfe; + + if (ph_ps2_mouse_type == 4) { + byte4 &= 0xf; + byte4 |= (ph_ps2_mouse_buttons << 1) & 0x30; } - - if (ms_type == MS_TYPE_WHEEL_5) { - if (report[0] & 0x8) { - z += 0x10; - } - - if (report[0] & 0x10) { - z += 0x20; - } - }*/ - - ph_ps2_mouse_send(z); + + ph_ps2_mouse_send(byte4); } } } void ph_ps2_mouse_send_button(u8 button, bool state) { - // TODO: PS2: Send mouse button - // @button - USB button code - // @state - true if pressed, false if released - // The function should take care not to send duplicate events (if needed for PS/2) - // If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing. - (void)button; // Remove this - (void)state; // Remove this - - u8 bitval = 1; - - button--; - - if(state) { - buttons = buttons | (bitval << button); - } else { - buttons = buttons & ~(bitval << button); + if (PH_O_IS_MOUSE_PS2) { + button--; + + if (state) { + ph_ps2_mouse_buttons = ph_ps2_mouse_buttons | (1 << button); + } else { + ph_ps2_mouse_buttons = ph_ps2_mouse_buttons & ~(1 << button); + } + + ph_ps2_mouse_pack(0, 0, 0, 0); } - - ph_ps2_mouse_packet(buttons, 0, 0); } -void ph_ps2_mouse_send_rel(s8 x1, s8 y1) { - // TODO: PS2: Send relative move event - // If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing. - ph_ps2_mouse_packet(buttons, x1, y1); +void ph_ps2_mouse_send_rel(s8 x, s8 y) { + if (PH_O_IS_MOUSE_PS2) { + ph_ps2_mouse_pack(x, y, 0, 0); + } } void ph_ps2_mouse_send_wheel(s8 h, s8 v) { - (void)h; - // TODO: PS2: Send wheel. As I understand, PS/2 has no horizontal scrolling, so @h just can be ignored. - // @v - vertical scrolling like on USB - // If the PS2 keyboard is not used (PH_O_IS_MOUSE_PS2 is false), the function should do nothing. - (void)v; // Remove this + if (PH_O_IS_MOUSE_PS2) { + ph_ps2_mouse_pack(0, 0, h, v); + } } void ph_ps2_mouse_receive(u8 byte, u8 prev_byte) { - - if(ms_input_mode == MS_INPUT_SET_RATE) { - ms_rate = byte; - ms_input_mode = MS_INPUT_CMD; - ph_ps2_mouse_send(0xfa); - - ms_magic_seq = (ms_magic_seq << 8) | byte; - if(ms_type == MS_TYPE_STANDARD && ms_magic_seq == 0xc86450) { - ms_type = MS_TYPE_WHEEL_3; - } else if (ms_type == MS_TYPE_WHEEL_3 && ms_magic_seq == 0xc8c850) { - ms_type = MS_TYPE_WHEEL_5; - } - return; - } - - if(byte != 0xf3) { - ms_magic_seq = 0x00; - } - - switch(byte) { - case 0xff: // Reset - ms_type = MS_TYPE_STANDARD; - ms_mode = MS_MODE_IDLE; - ms_rate = 100; - - ph_ps2_mouse_send(0xfa); - ph_ps2_mouse_send(0xaa); - ph_ps2_mouse_send(ms_type); - return; - - case 0xf6: // Set Defaults - ms_type = MS_TYPE_STANDARD; - ms_rate = 100; - case 0xf5: // Disable Data Reporting - case 0xea: // Set Stream Mode - ms_mode = MS_MODE_IDLE; - ph_ps2_mouse_send(0xfa); - return; - - case 0xf4: // Enable Data Reporting - ms_mode = MS_MODE_STREAMING; - ph_ps2_mouse_send(0xfa); - return; - + switch (prev_byte) { case 0xf3: // Set Sample Rate - ms_input_mode = MS_INPUT_SET_RATE; - ph_ps2_mouse_send(0xfa); - return; - - case 0xf2: // Get Device ID - ph_ps2_mouse_send(0xfa); - ph_ps2_mouse_send(ms_type); - return; - - case 0xe9: // Status Request - ph_ps2_mouse_send(0xfa); - ph_ps2_mouse_send(0x00); // Bit6: Mode, Bit 5: Enable, Bit 4: Scaling, Bits[2,1,0] = Buttons[L,M,R] - ph_ps2_mouse_send(0x02); // Resolution - ph_ps2_mouse_send(ms_rate); // Sample Rate - return; - - // TODO: Implement (more of) these? - // case 0xf0: // Set Remote Mode - // case 0xee: // Set Wrap Mode - // case 0xec: // Reset Wrap Mode - // case 0xeb: // Read Data - // case 0xe8: // Set Resolution - // case 0xe7: // Set Scaling 2:1 - // case 0xe6: // Set Scaling 1:1 + ph_ps2_mouse_magic_seq = ((ph_ps2_mouse_magic_seq << 8) | byte) & 0xffffff; + + if (ph_ps2_mouse_type == 0 && ph_ps2_mouse_magic_seq == 0xc86450) { + ph_ps2_mouse_type = 3; + } else if (ph_ps2_mouse_type == 3 && ph_ps2_mouse_magic_seq == 0xc8c850) { + ph_ps2_mouse_type = 4; + } + break; + + default: + switch (byte) { + case 0xff: // Reset + ph_ps2_mouse_streaming = false; + ph_ps2_mouse_type = 0; + + ph_ps2_mouse_send(0xfa); + ph_ps2_mouse_send(0xaa); + ph_ps2_mouse_send(ph_ps2_mouse_type); + return; + + case 0xf6: // Set Defaults + ph_ps2_mouse_streaming = false; + ph_ps2_mouse_type = 0; + break; + + case 0xf5: // Disable Data Reporting + case 0xea: // Set Stream Mode + ph_ps2_mouse_streaming = false; + break; + + case 0xf4: // Enable Data Reporting + ph_ps2_mouse_streaming = true; + break; + + case 0xf2: // Get Device ID + ph_ps2_mouse_send(0xfa); + ph_ps2_mouse_send(ph_ps2_mouse_type); + return; + + case 0xe9: // Status Request + ph_ps2_mouse_send(0xfa); + ph_ps2_mouse_send(0x00); // Bit6: Mode, Bit 5: Enable, Bit 4: Scaling, Bits[2,1,0] = Buttons[L,M,R] + ph_ps2_mouse_send(0x02); // Resolution + ph_ps2_mouse_send(100); // Sample Rate + return; + + // TODO: Implement (more of) these? + // case 0xf0: // Set Remote Mode + // case 0xee: // Set Wrap Mode + // case 0xec: // Reset Wrap Mode + // case 0xeb: // Read Data + // case 0xe8: // Set Resolution + // case 0xe7: // Set Scaling 2:1 + // case 0xe6: // Set Scaling 1:1 + } + break; } ph_ps2_mouse_send(0xfa); @@ -184,6 +139,7 @@ void ph_ps2_mouse_receive(u8 byte, u8 prev_byte) { void ph_ps2_mouse_task(void) { ph_ps2_phy_task(&ph_ps2_mouse); + ph_g_ps2_mouse_online = ph_ps2_mouse_streaming && !ph_ps2_mouse.busy; } void ph_ps2_mouse_init(u8 gpio) { diff --git a/hid/pico/src/ph_ps2_phy.c b/hid/pico/src/ph_ps2_phy.c index 05046b2b..edaa165c 100644 --- a/hid/pico/src/ph_ps2_phy.c +++ b/hid/pico/src/ph_ps2_phy.c @@ -4,7 +4,7 @@ #include "ph_ps2_phy.h" #include "ph_ps2_phy.pio.h" -uint prog = 0; +s8 prog = -1; u32 ph_ps2_phy_frame(u8 byte) { bool parity = 1; @@ -15,7 +15,7 @@ u32 ph_ps2_phy_frame(u8 byte) { } void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx) { - if(!prog) { + if (prog == -1) { prog = pio_add_program(pio, &ph_ps2_phy_program); } @@ -30,7 +30,7 @@ void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx) { this->rx = rx; this->last_rx = 0; this->last_tx = 0; - this->idle = true; + this->busy = 0; } void ph_ps2_phy_task(ph_ps2_phy* this) { @@ -48,9 +48,18 @@ void ph_ps2_phy_task(ph_ps2_phy* this) { queue_try_add(&this->qpacks, &pack); } - this->idle = !pio_interrupt_get(this->pio, this->sm); + if (pio_interrupt_get(this->pio, this->sm)) { + this->busy = 1; + } else { + this->busy &= 2; + } - if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && this->idle) { + if (pio_interrupt_get(this->pio, this->sm + 4)) { + this->sent--; + pio_interrupt_clear(this->pio, this->sm + 4); + } + + if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && !this->busy) { if (queue_try_peek(&this->qpacks, &pack)) { if (this->sent == pack[0]) { this->sent = 0; @@ -58,17 +67,12 @@ void ph_ps2_phy_task(ph_ps2_phy* this) { } else { this->sent++; this->last_tx = pack[this->sent]; + this->busy |= 2; pio_sm_put(this->pio, this->sm, ph_ps2_phy_frame(this->last_tx)); } } } - if (pio_interrupt_get(this->pio, this->sm + 4)) { - this->sent = 0; - pio_sm_drain_tx_fifo(this->pio, this->sm); - pio_interrupt_clear(this->pio, this->sm + 4); - } - if (!pio_sm_is_rx_fifo_empty(this->pio, this->sm)) { u32 fifo = pio_sm_get(this->pio, this->sm) >> 23; @@ -87,8 +91,8 @@ void ph_ps2_phy_task(ph_ps2_phy* this) { return; } - while(queue_try_remove(&this->qbytes, &byte)); - while(queue_try_remove(&this->qpacks, &pack)); + while (queue_try_remove(&this->qbytes, &byte)); + while (queue_try_remove(&this->qpacks, &pack)); (*this->rx)(fifo, this->last_rx); this->last_rx = fifo; diff --git a/hid/pico/src/ph_ps2_phy.h b/hid/pico/src/ph_ps2_phy.h index 3ed7dcfb..a6a0fc13 100644 --- a/hid/pico/src/ph_ps2_phy.h +++ b/hid/pico/src/ph_ps2_phy.h @@ -11,11 +11,11 @@ typedef struct { uint sm; queue_t qbytes; queue_t qpacks; - u8 sent; rx_callback rx; u8 last_rx; u8 last_tx; - bool idle; + u8 sent; + u8 busy; } ph_ps2_phy; void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx); diff --git a/hid/pico/src/ph_ps2_phy.pio b/hid/pico/src/ph_ps2_phy.pio index f2d7578c..19786168 100644 --- a/hid/pico/src/ph_ps2_phy.pio +++ b/hid/pico/src/ph_ps2_phy.pio @@ -10,52 +10,54 @@ .side_set 1 opt pindirs restart: - set pindirs 0 [4] // set clock to input mode - irq clear 0 rel side 0 // clear busy flag, set data to input mode + set pindirs, 0 // set clock to input mode + irq clear 0 rel side 0 // clear busy flag, set data to input mode receivecheck: - jmp pin sendcheck // if clock is high, see if we have data to send - irq set 0 rel // clock is being pulled low, set busy flag - wait 1 pin 1 // wait for clock to be pulled high + jmp pin, sendcheck // if clock is high, see if we have data to send + irq nowait 0 rel // clock is being pulled low, set busy flag + wait 1 pin, 1 // wait for clock to be pulled high // we are not sending, look for a start bit (clock high, data low) - in pins 1 // read in from data - mov x isr // move what we read to x - mov isr null // clear ISR - jmp !x receive // if x is low, start the receive process - jmp restart // not receiving + in pins, 1 // read in from data + mov x, isr // move what we read to x + mov isr, null // clear ISR + jmp !x, receive // if x is low, start the receive process + jmp restart // not receiving receive: - set pindirs, 1 [6] // clock low - set x, 8 // set loop counter + set pindirs, 1 [6] // clock low + set x, 8 // set loop counter receiveloop: - set pindirs, 0 [6] // clock high - in pins, 1 [4] // read a bit into ISR - set pindirs, 1 [6] // clock low - jmp x-- receiveloop [4] // iterate - set pindirs, 0 [6] // clock high - nop side 1 [6] // data low - set pindirs, 1 [7] // clock low - jmp restart + set pindirs, 0 [6] // clock high + in pins, 1 [4] // read a bit into ISR + set pindirs, 1 [6] // clock low + jmp x--, receiveloop [4] // iterate + set pindirs, 0 [6] // clock high + nop side 1 [6] // data low + set pindirs, 1 [7] // clock low + jmp restart [7] sendcheck: - jmp !osre wait_to_write // see if we have data to send - jmp receivecheck // no data to send, restart + jmp !osre, send // see if we have data to send + jmp receivecheck // no data to send, restart -wait_to_write: - irq set 0 rel // set busy flag - set x 10 // number of bits to write out +send: + irq nowait 0 rel // set busy flag + set x, 10 // number of bits to write out sendloop: - set pindirs, 0 [6] // clock set to input (high) - jmp pin sendcontinue // if clock is high, host is still receiving data - irq wait 4 rel // clock was low, host wants to send data, notify of failure to send data - jmp restart // and wait for restart + set pindirs, 0 [6] // clock set to input (high) + jmp pin, sendcontinue // if clock is high, host is still receiving data + out null, 32 // clear OSR + irq wait 4 rel // clock was low, host wants to send data, notify of failure to send data + jmp restart // and wait for restart + sendcontinue: - out pindirs, 1 [6] // write out data - set pindirs, 1 [6] // set clock low - jmp x-- sendloop [6] + out pindirs, 1 [6] // write out data + set pindirs, 1 [6] // set clock low + jmp x--, sendloop [6] % c-sdk { void ph_ps2_phy_program_init(PIO pio, uint sm, uint offset, uint dat) { From 2189b77c07533c5ed7bfc3f7d58b98f0622419dd Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Sat, 9 Sep 2023 13:07:30 +0300 Subject: [PATCH 08/10] using ps2x2pico as a library --- hid/pico/.gitignore | 1 + hid/pico/CMakeLists.txt | 2 +- hid/pico/Makefile | 7 +-- hid/pico/src/CMakeLists.txt | 7 +-- hid/pico/src/ph_ps2_kbd.c | 9 ++-- hid/pico/src/ph_ps2_mouse.c | 9 ++-- hid/pico/src/ph_ps2_phy.c | 100 ------------------------------------ hid/pico/src/ph_ps2_phy.h | 22 -------- hid/pico/src/ph_ps2_phy.pio | 83 ------------------------------ 9 files changed, 20 insertions(+), 220 deletions(-) delete mode 100644 hid/pico/src/ph_ps2_phy.c delete mode 100644 hid/pico/src/ph_ps2_phy.h delete mode 100644 hid/pico/src/ph_ps2_phy.pio diff --git a/hid/pico/.gitignore b/hid/pico/.gitignore index 21d09ea3..6d0c9883 100644 --- a/hid/pico/.gitignore +++ b/hid/pico/.gitignore @@ -1,4 +1,5 @@ /.pico-sdk* /.tinyusb* +/.ps2x2pico* /.build/ /*.uf2 diff --git a/hid/pico/CMakeLists.txt b/hid/pico/CMakeLists.txt index edf93cec..819a5300 100644 --- a/hid/pico/CMakeLists.txt +++ b/hid/pico/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) set(PICO_SDK_PATH ${CMAKE_CURRENT_LIST_DIR}/.pico-sdk) set(PICO_TINYUSB_PATH ${CMAKE_CURRENT_LIST_DIR}/.tinyusb) -# TODO: PS2: set(PS2_PATH ${CMAKE_CURRENT_LIST_DIR}/.yourlib/subdir) +SET(PS2_PATH ${CMAKE_CURRENT_LIST_DIR}/.ps2x2pico) # For TinyUSB set(FAMILY rp2040) diff --git a/hid/pico/Makefile b/hid/pico/Makefile index fbfd963e..7baca263 100644 --- a/hid/pico/Makefile +++ b/hid/pico/Makefile @@ -15,7 +15,7 @@ install: all clean: rm -rf .build hid.uf2 clean-all: clean - rm -rf .pico-sdk* .tinyusb* + rm -rf .pico-sdk* .tinyusb* .ps2x2pico define libdep @@ -30,8 +30,9 @@ endef $(call libdep,pico-sdk,raspberrypi/pico-sdk,6a7db34ff63345a7badec79ebea3aaef1712f374) .tinyusb: $(call libdep,tinyusb,hathach/tinyusb,d713571cd44f05d2fc72efc09c670787b74106e0) -# TODO: PS2: Add your library here and add it to "all" and "clean-all" targets -deps: .pico-sdk .tinyusb +.ps2x2pico: + $(call libdep,ps2x2pico,No0ne/ps2x2pico,706b5c34cb6a2fcefeb7f1ee0f673c7de9452fc6) +deps: .pico-sdk .tinyusb .ps2x2pico .PHONY: deps diff --git a/hid/pico/src/CMakeLists.txt b/hid/pico/src/CMakeLists.txt index 743759c2..facab804 100644 --- a/hid/pico/src/CMakeLists.txt +++ b/hid/pico/src/CMakeLists.txt @@ -8,7 +8,6 @@ target_sources(${target_name} PRIVATE ph_usb_kbd.c ph_usb_mouse.c ph_ps2.c - ph_ps2_phy.c ph_ps2_kbd.c ph_ps2_mouse.c ph_cmds.c @@ -17,12 +16,14 @@ target_sources(${target_name} PRIVATE ph_com_spi.c ph_com_uart.c ph_debug.c + + ${PS2_PATH}/ps2phy.c ) target_link_options(${target_name} PRIVATE -Xlinker --print-memory-usage) target_compile_options(${target_name} PRIVATE -Wall -Wextra) -target_include_directories(${target_name} PRIVATE ${CMAKE_CURRENT_LIST_DIR}) +target_include_directories(${target_name} PRIVATE ${CMAKE_CURRENT_LIST_DIR} ${PS2_PATH}) -pico_generate_pio_header(${target_name} ${CMAKE_CURRENT_LIST_DIR}/ph_ps2_phy.pio) +pico_generate_pio_header(${target_name} ${PS2_PATH}/ps2phy.pio) target_link_libraries(${target_name} PRIVATE pico_stdlib diff --git a/hid/pico/src/ph_ps2_kbd.c b/hid/pico/src/ph_ps2_kbd.c index e2fd7faf..02229e96 100644 --- a/hid/pico/src/ph_ps2_kbd.c +++ b/hid/pico/src/ph_ps2_kbd.c @@ -1,10 +1,11 @@ +#include "ps2phy.h" + #include "ph_outputs.h" -#include "ph_ps2_phy.h" extern u8 ph_g_ps2_kbd_leds; extern bool ph_g_ps2_kbd_online; -ph_ps2_phy ph_ps2_kbd; +ps2phy ph_ps2_kbd; bool ph_ps2_kbd_scanning; u32 ph_ps2_kbd_repeat_us; u16 ph_ps2_kbd_delay_ms; @@ -212,11 +213,11 @@ void ph_ps2_kbd_receive(u8 byte, u8 prev_byte) { } void ph_ps2_kbd_task(void) { - ph_ps2_phy_task(&ph_ps2_kbd); + ps2phy_task(&ph_ps2_kbd); ph_g_ps2_kbd_online = ph_ps2_kbd_scanning && !ph_ps2_kbd.busy; } void ph_ps2_kbd_init(u8 gpio) { - ph_ps2_phy_init(&ph_ps2_kbd, pio0, gpio, &ph_ps2_kbd_receive); + ps2phy_init(&ph_ps2_kbd, pio0, gpio, &ph_ps2_kbd_receive); ph_ps2_kbd_reset(); } diff --git a/hid/pico/src/ph_ps2_mouse.c b/hid/pico/src/ph_ps2_mouse.c index c825ca03..a56b814a 100644 --- a/hid/pico/src/ph_ps2_mouse.c +++ b/hid/pico/src/ph_ps2_mouse.c @@ -1,9 +1,10 @@ +#include "ps2phy.h" + #include "ph_outputs.h" -#include "ph_ps2_phy.h" extern bool ph_g_ps2_mouse_online; -ph_ps2_phy ph_ps2_mouse; +ps2phy ph_ps2_mouse; bool ph_ps2_mouse_streaming = false; u32 ph_ps2_mouse_magic_seq = 0; u8 ph_ps2_mouse_type = 0; @@ -138,10 +139,10 @@ void ph_ps2_mouse_receive(u8 byte, u8 prev_byte) { } void ph_ps2_mouse_task(void) { - ph_ps2_phy_task(&ph_ps2_mouse); + ps2phy_task(&ph_ps2_mouse); ph_g_ps2_mouse_online = ph_ps2_mouse_streaming && !ph_ps2_mouse.busy; } void ph_ps2_mouse_init(u8 gpio) { - ph_ps2_phy_init(&ph_ps2_mouse, pio0, gpio, &ph_ps2_mouse_receive); + ps2phy_init(&ph_ps2_mouse, pio0, gpio, &ph_ps2_mouse_receive); } diff --git a/hid/pico/src/ph_ps2_phy.c b/hid/pico/src/ph_ps2_phy.c deleted file mode 100644 index edaa165c..00000000 --- a/hid/pico/src/ph_ps2_phy.c +++ /dev/null @@ -1,100 +0,0 @@ -// Source: https://github.com/No0ne/ps2x2pico/blob/main/ps2phy.c -// replace ps2phy with ph_ps2_phy - -#include "ph_ps2_phy.h" -#include "ph_ps2_phy.pio.h" - -s8 prog = -1; - -u32 ph_ps2_phy_frame(u8 byte) { - bool parity = 1; - for (u8 i = 0; i < 8; i++) { - parity = parity ^ (byte >> i & 1); - } - return ((1 << 10) | (parity << 9) | (byte << 1)) ^ 0x7ff; -} - -void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx) { - if (prog == -1) { - prog = pio_add_program(pio, &ph_ps2_phy_program); - } - - queue_init(&this->qbytes, sizeof(u8), 9); - queue_init(&this->qpacks, sizeof(u8) * 9, 16); - - this->sm = pio_claim_unused_sm(pio, true); - ph_ps2_phy_program_init(pio, this->sm, prog, data_pin); - - this->pio = pio; - this->sent = 0; - this->rx = rx; - this->last_rx = 0; - this->last_tx = 0; - this->busy = 0; -} - -void ph_ps2_phy_task(ph_ps2_phy* this) { - u8 i = 0; - u8 byte; - u8 pack[9]; - - if (!queue_is_empty(&this->qbytes)) { - while (i < 9 && queue_try_remove(&this->qbytes, &byte)) { - i++; - pack[i] = byte; - } - - pack[0] = i; - queue_try_add(&this->qpacks, &pack); - } - - if (pio_interrupt_get(this->pio, this->sm)) { - this->busy = 1; - } else { - this->busy &= 2; - } - - if (pio_interrupt_get(this->pio, this->sm + 4)) { - this->sent--; - pio_interrupt_clear(this->pio, this->sm + 4); - } - - if (!queue_is_empty(&this->qpacks) && pio_sm_is_tx_fifo_empty(this->pio, this->sm) && !this->busy) { - if (queue_try_peek(&this->qpacks, &pack)) { - if (this->sent == pack[0]) { - this->sent = 0; - queue_try_remove(&this->qpacks, &pack); - } else { - this->sent++; - this->last_tx = pack[this->sent]; - this->busy |= 2; - pio_sm_put(this->pio, this->sm, ph_ps2_phy_frame(this->last_tx)); - } - } - } - - if (!pio_sm_is_rx_fifo_empty(this->pio, this->sm)) { - u32 fifo = pio_sm_get(this->pio, this->sm) >> 23; - - bool parity = 1; - for (i = 0; i < 8; i++) { - parity = parity ^ (fifo >> i & 1); - } - - if (parity != fifo >> 8) { - pio_sm_put(this->pio, this->sm, ph_ps2_phy_frame(0xfe)); - return; - } - - if (fifo == 0xfe) { - pio_sm_put(this->pio, this->sm, ph_ps2_phy_frame(this->last_tx)); - return; - } - - while (queue_try_remove(&this->qbytes, &byte)); - while (queue_try_remove(&this->qpacks, &pack)); - - (*this->rx)(fifo, this->last_rx); - this->last_rx = fifo; - } -} diff --git a/hid/pico/src/ph_ps2_phy.h b/hid/pico/src/ph_ps2_phy.h deleted file mode 100644 index a6a0fc13..00000000 --- a/hid/pico/src/ph_ps2_phy.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "ph_types.h" -#include "hardware/pio.h" -#include "pico/util/queue.h" - -typedef void (*rx_callback)(u8 byte, u8 prev_byte); - -typedef struct { - PIO pio; - uint sm; - queue_t qbytes; - queue_t qpacks; - rx_callback rx; - u8 last_rx; - u8 last_tx; - u8 sent; - u8 busy; -} ph_ps2_phy; - -void ph_ps2_phy_init(ph_ps2_phy* this, PIO pio, u8 data_pin, rx_callback rx); -void ph_ps2_phy_task(ph_ps2_phy* this); \ No newline at end of file diff --git a/hid/pico/src/ph_ps2_phy.pio b/hid/pico/src/ph_ps2_phy.pio deleted file mode 100644 index 19786168..00000000 --- a/hid/pico/src/ph_ps2_phy.pio +++ /dev/null @@ -1,83 +0,0 @@ -; -; Copyright (c) 2022 No0ne (https://github.com/No0ne) -; (c) 2023 Dustin Hoffman -; -; SPDX-License-Identifier: MIT -; -; Source: https://github.com/No0ne/ps2x2pico/blob/main/ps2phy.pio - -.program ph_ps2_phy -.side_set 1 opt pindirs - -restart: - set pindirs, 0 // set clock to input mode - irq clear 0 rel side 0 // clear busy flag, set data to input mode - -receivecheck: - jmp pin, sendcheck // if clock is high, see if we have data to send - irq nowait 0 rel // clock is being pulled low, set busy flag - wait 1 pin, 1 // wait for clock to be pulled high - - // we are not sending, look for a start bit (clock high, data low) - in pins, 1 // read in from data - mov x, isr // move what we read to x - mov isr, null // clear ISR - jmp !x, receive // if x is low, start the receive process - jmp restart // not receiving - -receive: - set pindirs, 1 [6] // clock low - set x, 8 // set loop counter - -receiveloop: - set pindirs, 0 [6] // clock high - in pins, 1 [4] // read a bit into ISR - set pindirs, 1 [6] // clock low - jmp x--, receiveloop [4] // iterate - set pindirs, 0 [6] // clock high - nop side 1 [6] // data low - set pindirs, 1 [7] // clock low - jmp restart [7] - -sendcheck: - jmp !osre, send // see if we have data to send - jmp receivecheck // no data to send, restart - -send: - irq nowait 0 rel // set busy flag - set x, 10 // number of bits to write out - -sendloop: - set pindirs, 0 [6] // clock set to input (high) - jmp pin, sendcontinue // if clock is high, host is still receiving data - out null, 32 // clear OSR - irq wait 4 rel // clock was low, host wants to send data, notify of failure to send data - jmp restart // and wait for restart - -sendcontinue: - out pindirs, 1 [6] // write out data - set pindirs, 1 [6] // set clock low - jmp x--, sendloop [6] - -% c-sdk { - void ph_ps2_phy_program_init(PIO pio, uint sm, uint offset, uint dat) { - pio_sm_config c = ph_ps2_phy_program_get_default_config(offset); - - u8 clk = dat + 1; - pio_gpio_init(pio, clk); - pio_gpio_init(pio, dat); - - // Use a frequency high enough to effectivly sample clock and data. - sm_config_set_clkdiv(&c, 427); // 2560 is 20 µs, 640 is 5 µs, 427 is 3.3333 µs - sm_config_set_jmp_pin(&c, clk); - sm_config_set_set_pins(&c, clk, 1); - sm_config_set_sideset_pins(&c, dat); - sm_config_set_out_pins(&c, dat, 1); - sm_config_set_out_shift(&c, true, true, 11); - sm_config_set_in_pins(&c, dat); - sm_config_set_in_shift(&c, true, true, 9); - - pio_sm_init(pio, sm, offset, &c); - pio_sm_set_enabled(pio, sm, true); - } -%} \ No newline at end of file From 1b772aace2df1413a7a8d555ecd04d55f64cfb2b Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Sat, 9 Sep 2023 13:08:34 +0300 Subject: [PATCH 09/10] refactoring --- hid/pico/src/ph_outputs.h | 1 + hid/pico/src/ph_ps2.c | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/hid/pico/src/ph_outputs.h b/hid/pico/src/ph_outputs.h index ce68ac30..d2487327 100644 --- a/hid/pico/src/ph_outputs.h +++ b/hid/pico/src/ph_outputs.h @@ -26,6 +26,7 @@ #include "ph_proto.h" +#define PH_O_HAS_PS2 (!!(ph_g_outputs_avail & PH_PROTO_OUT2_HAS_PS2)) #define PH_O_KBD(x_id) ((ph_g_outputs_active & PH_PROTO_OUT1_KBD_MASK) == PH_PROTO_OUT1_KBD_##x_id) #define PH_O_MOUSE(x_id) ((ph_g_outputs_active & PH_PROTO_OUT1_MOUSE_MASK) == PH_PROTO_OUT1_MOUSE_##x_id) #define PH_O_IS_KBD_USB PH_O_KBD(USB) diff --git a/hid/pico/src/ph_ps2.c b/hid/pico/src/ph_ps2.c index d5bc9beb..ec74dc22 100644 --- a/hid/pico/src/ph_ps2.c +++ b/hid/pico/src/ph_ps2.c @@ -24,25 +24,33 @@ #include "ph_types.h" #include "ph_outputs.h" + #include "hardware/gpio.h" + +#define _LS_POWER_PIN 13 +#define _KBD_DATA_PIN 11 // CLK == 12 +#define _MOUSE_DATA_PIN 14 // CLK == 15 + + u8 ph_g_ps2_kbd_leds = 0; bool ph_g_ps2_kbd_online = 0; bool ph_g_ps2_mouse_online = 0; + void ph_ps2_init(void) { - if (PH_O_IS_KBD_PS2 || PH_O_IS_MOUSE_PS2) { - gpio_init(13); // GPIO13=LV pull-up voltage - gpio_set_dir(13, GPIO_OUT); - gpio_put(13, 1); + if (PH_O_HAS_PS2) { + gpio_init(_LS_POWER_PIN); + gpio_set_dir(_LS_POWER_PIN, GPIO_OUT); + gpio_put(_LS_POWER_PIN, true); } if (PH_O_IS_KBD_PS2) { - ph_ps2_kbd_init(11); // keyboard: GPIO11=data, GPIO12=clock + ph_ps2_kbd_init(_KBD_DATA_PIN); } if (PH_O_IS_MOUSE_PS2) { - ph_ps2_mouse_init(14); // mouse: GPIO14=data, GPIO15=clock + ph_ps2_mouse_init(_MOUSE_DATA_PIN); } } From 5d587d1d417bab8fc862447d63cf416882d6812e Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Sat, 9 Sep 2023 13:23:30 +0300 Subject: [PATCH 10/10] ps2 pin stubs --- hid/pico/src/ph_ps2.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/hid/pico/src/ph_ps2.c b/hid/pico/src/ph_ps2.c index ec74dc22..a814103c 100644 --- a/hid/pico/src/ph_ps2.c +++ b/hid/pico/src/ph_ps2.c @@ -44,21 +44,32 @@ void ph_ps2_init(void) { gpio_set_dir(_LS_POWER_PIN, GPIO_OUT); gpio_put(_LS_POWER_PIN, true); } - + +# define INIT_STUB(x_pin) { \ + gpio_init(x_pin); gpio_set_dir(x_pin, GPIO_IN); \ + gpio_init(x_pin + 1); gpio_set_dir(x_pin + 1, GPIO_IN); \ + } + if (PH_O_IS_KBD_PS2) { ph_ps2_kbd_init(_KBD_DATA_PIN); + } else { + INIT_STUB(_KBD_DATA_PIN); } - + if (PH_O_IS_MOUSE_PS2) { ph_ps2_mouse_init(_MOUSE_DATA_PIN); + } else { + INIT_STUB(_MOUSE_DATA_PIN); } + +# undef INIT_STUB } void ph_ps2_task(void) { if (PH_O_IS_KBD_PS2) { ph_ps2_kbd_task(); } - + if (PH_O_IS_MOUSE_PS2) { ph_ps2_mouse_task(); }