Low Cost KVM Switch

This is a KVM switch built from cheap HDMI switch + USB MUX

Similar projects worth following
KVM is a hardware device that allows you to control/manage several computers from one set of keyboard/mouse and monitor. It is a bit different than a software solution as you can use it at preboot or other situations where the remote viewing software isn't working.

There seems to be a void for affordable modern KVM switches even though all the pieces are out there. Cheap $5 HDMI 1.4 switch has already most of the parts except for switching keyboard and mouse. It is a matter of adding a USB MUX for a minimal functioning KVM. I'll try to use as much off the shelf parts as possible to lower the complexity/cost.

HDMI Switching

I have previously opened up a $5 3-to-1 HDMI switch. The HDMI switch is implemented with AZHW37 HDMI mux that is controlled by logic level signals controlled with a 8-pin microcontroller to handle the buttons and selection LED.

Details: HDMI Switch Reverse Engineering.
HDMI switch datasheet:

The physically mapping on PCB is in blue.


PS/2 devices are not hot pluggable, so a KVM emulates a pair of PS/2 mouse/keyboards for each of the computers. It pass through key strokes, mouse events and commands. It also has to remember the LED states of the keyboard/mouse so that it can restore the states switching between different computers.

Unlike PS/2, USB is designed to be hot pluggable. i.e. The KVM (Hub Based) connects/disconnects the USB port for each time it switches. The OS level support simplifies the design a lot. Windows even saves the LED states of keyboard and restores it upon reconnecting.

USB 1.X Switching - The easy way

If you want to switch USB 1.X signals, you can probably get by with a 74HC4052 (Dual 4:1 Analog MUX). The 74HC4052 covers all the logical combinations, so it is a matter of taking advantage of that to match up with the HDMI switch and discarding the combination not covered by the HDMI.

The connections on the 74HC4052 would probably look like this. S1, S2 are fed from the HDMI switch.

Most of the commodity keyboard/mouse are USB 1.X devices, so this is probably good enough.

You do have to make sure that the USB HUB you are using is only USB 1.x (i.e. 1.5 or 12Mbps) as the MUX is not rated for USB 2.0. USB unlikely Ethernet doesn't falls back gracefully if the signal quality is bad. You just have to shop for the cheapest $2 hubs from China which are still USB 1.1.

When not to switch

You have to be careful not to switch while inside BIOS/UEFI/OS Installation as the software side have small primitive USB stacks that might not handle the hot plugging. Switching mass storage devices without letting the OS knowing will likely results in files or file system level corruption.

Hardware Design

I have decided to try to make a USB 2.0 switch. If used carefully I can attach a USB memory stick to the hub.

There are proper USB 2.0 MUX out there e.g. On Semi NCN9252. It is a fine pitched (0.4mm) DFN parts targeted for skinny consumer electronic devices. Their pin placements doesn't exactly make sense without a multilayer PCB, but I have to work with what is available.

As an alternative, one could possibly make a USB 2.0 MUX out of 3 DTDP relays. Short pieces of twist pair from CAT5/6 could be used to wire things together. CAT5/6 have 100 ohms impedance which is within the USB specs.

They have decided to use a different combination for selecting the channels than the HDMI switch. There are a couple of ways to connect the control pins to the USB MUX.
  • Invert one of the logic signals e.g. S1 from HDMI and relabel the ports
  • A Dual 4 to 1 MUX (e.g. 74HC153) can be used as a pair of 4 entries lookup table.
  • Use a $0.24 microcontroller to remap the ports.

I have thrown together a breakout PCB that I am going to order because of the tight tolerances and the high speed signals. There are some additional requirements that I haven't sorted out yet, so those are going to be on a separate PCB with a modular approach.

I use 3 schottky diodes as Or'ing diodes to provide power for the USB hub. The diodes prevent power from leaking back to unpowered PCs. Cheap hubs do away with the protection Schottky diode, so we only have 1 diode drop to worry about. A self powered hub can also be used.

0.52x1.48 inch (13.08x37.46 mm) 2 layer board. 3 boards at $3.75 per batch of three.

PCB Signal Impedance

It is hard to get the right impedance on a 0.062" (1.6mm) doubled sided PCB on thin tracks and prototype design rules. (Online impedance calculator: here)

Due to the relative distances, edge coupling will have a significant effect. Normally you are supposed to maintain a few d clearance...

Read more »

PS2 Hotkey test code

Zip Archive - 67.22 kB - 04/28/2017 at 21:42


  • status update

    K.C. Lee04/28/2017 at 20:30 0 comments

    Still waiting for stuff I ordered from China. It has been 2 months now. Stuff is most likely sitting at the big ware house at Canada Custom. When it comes to clearing customs for stuff that are not first class or couriers, it usually takes ~2.5 months (used to be from about 1 month last Oct.) Sometimes I feel like I am in south America. Not even the Energizer Bunnies can out last waiting for Canada Custom.

    Here is what others have documented about the slowness of Canada Custom/Canada Post.

    The longest shipment took 165 days, the shortest 18 days (both free shipping). Anything with China Post was consistently sluggish at 147 (!) days [= 5 MONTHS], followed by tightly clustered Switzerland unregistered at 104 days [= 3.5 MONTHS], and rather erratic aliexpress standard shipping at 84 days [= ~3 MONTHS].

    The keyboard dongle finally arrived today. It took exactly 4 months! They must have the big warehouse like the end of the first Indiana Jones movie. For all that expensive rent in the Canada Custom in Vancouver that handles imports, they could simply hire more people.

    Here is what's inside:

    It is minimalist design with the black epoxy encapsulated chip, a decoupling cap and the connectors. The good part is that the PS/2 interface supports hot plugging for both mouse and keyboard. It supports scroll mouse.

    They really should solder in the shield tabs for the USB connector to provide extra mechanical support.

  • Snooping PS/2 keystrokes for hotkey - part 2

    K.C. Lee03/31/2017 at 17:04 0 comments

    It works. :) The key pressed trace shows the duration while Digital 3 shows the pause between key presses. The final glitch is the detection of double click. The "!" is the output when it detects a double click. My delays are around 70-75ms.

    Here is the preliminary state machine that does the checking. Basically each state checks against expected scan code and within countdown timer limits before proceeding to the next state. If it fails, then reset to the idle state and start again.

    // high level polling task
    void PS2_Task(void)
      uint16_t ScanCode, Parity;
      { // Critical section
        ScanCode = PS2.ScanCode;
        PS2.Avail = 0;
        Parity = PS2.ScanCode & 0x01;	
        ScanCode = (ScanCode >> 1) & 0xff;
        if (ScanCode == PS2_KBD_CODE_RELEASE)
          Hotkeys.KeyAttr |= Key_Release;
        else if (ScanCode == PS2_KBD_CODE_EXTENDED)
          Hotkeys.KeyAttr |= Key_Extend;
        { switch(Hotkeys.State)
            case HK_Idle:
              if((ScanCode == HOTKEY_SCANCODE) && !Hotkeys.KeyAttr)
              { Hotkeys.State = HK_KeyMake_1;
                Milli_Timer1 = HOTKEY_RELEASE_DELAY;
            case HK_KeyMake_1:
              if((ScanCode == HOTKEY_SCANCODE) && 
                 (Hotkeys.KeyAttr==Key_Release) && Milli_Timer1)
              { Hotkeys.KeyAttr = 0;
                Hotkeys.State = HK_KeyBreak_1;
                Milli_Timer1 = HOTKEY_WAIT_DELAY;				
            case HK_KeyBreak_1:
              if((ScanCode == HOTKEY_SCANCODE) && 
                 !Hotkeys.KeyAttr && Milli_Timer1)
              { Hotkeys.State = HK_KeyMake_2;
                Milli_Timer1 = HOTKEY_RELEASE_DELAY;				
            case HK_KeyMake_2:
              if((ScanCode == HOTKEY_SCANCODE) && 
                 (Hotkeys.KeyAttr==Key_Release) && Milli_Timer1)
              { PutC('!');
         // default to idle
         Hotkeys.State = HK_Idle;
         Hotkeys.KeyAttr = 0;
    Pretty mechanical and boring code. There are probably ways to improve and what not. I am skimping on the error checking for now. As with all coding exercises, there are things I might have missed etc., but probably enough to the next part.

    The test code is under the file area. The project is for Cosmic C.

  • Snooping PS/2 keystrokes for hotkey

    K.C. Lee03/29/2017 at 23:49 0 comments

    The idea is to snoop the PS/2 keystrokes passively for supporting hotkey for switching to a different PC. It is a bit different than interfacing to the keyboard directly.


    I have decided to use the I2C pins as they are "True Open Drain" pins and the only 5V tolerant pins in the STM8.


    The PS/2 protocol is bidirectional and the protocols are slightly different. If Data = '0' on the first falling edge of Clock, then it is a response or scan code from keyboard to PC.

    If Data = '1' on the falling edge of Clock, then it is a PS/2 command for the keyboard.


    We have to keep track of the different number of data bits of the two protocols. A count down timer is used to determine if synchronization is lost.

    I use the falling edge of clock for interrupt. Inside the IRQ, the Data bits are LSB first. A state machine is used to keep track of the protocol. A timer is used to determine whether or not synchronization has been lost and is used to reset the state machine.

    @far @interrupt void PORTB_IRQ(void)
      if((PS2.State == PS2_Idle)||(!Micro_Timer1))	// Start bit or resynchronized
      { // rewind timer
        Micro_Timer1 = us_TO_TICKS(PS2_BIT_TIMEOUT);
        // first bit determines source: keyboard or PC
        PS2.State = (PS2_PORT->IDR & PS2_DATA)?PS2_CMD_1:PS2_KBD_1;
      else // Scan/respond code
      { if(PS2.State++ & PS2_KBD)
        { if(PS2.State == PS2_KBD_LAST)
          {	PS2.Avail = 1;
            PS2.State = PS2_Idle;
          { PS2.ScanCode >>= 1;
            if(PS2_PORT->IDR & PS2_DATA)
              PS2.ScanCode |= 0x200;
        else  // Ignore Cmd to keyboard
          if(PS2.State == PS2_CMD_LAST)
            PS2.State = PS2_Idle;

    Here is the scan code decoding output (in Hex, P: parity bit.) from my main event loop.
    PS/2 uses odd parity.

    Hotkey Detection

    This is a time stamp of the PS/2 scan code generated from me double clicking the Left Control key captured and decoded from a logic analyzer.

    So let's make an upper limit of 250ms, 200ms, 250ms for the 3 timing intervals.

    For a successful double click event:

    • The scan code sequence is: 0x14, ( 0xf0,0x14), 0x14
    • 3 sets of timings that needs to be satisfied for a double click event.

    I have to add a state machine and some additional timer routines for detecting the hotkey sequence.

    My development set up:

    • My new STM8 Breakout board with on board USB serial port
    • PS/2 splitter to monitor traffic between a PS/2 keyboard and a hub with PS/2 converter
    • Logic analyzer

    I have put together a keyboard scan code chart:

  • Assembly

    K.C. Lee03/29/2017 at 21:15 0 comments

    The PCB finally arrived. After a bit of filing down the rat bites, I solder down the Micro USB connectors. I went into a bit of problem as their alignment pins sort of melted, but aligned it by eyes.

    I tinned the UQFN footprint with 0.4mm pitch. (You know it is worse than QFN when they have to add a U in front of it.)

    Here is a zoomed in picture with the part. The reversed L shaped is pin 1 which goes to the slightly wider pad.

    I held it down while applying hot air to reflow the part. It actually takes less efforts than those pesky Micro USB connectors.

    I use step 3 from here to test out the connectivity. tl;dr Connect the + terminal of DMM in diode test mode to Ground, and test out all the connections with the - terminal. This forward biased the protection diodes on the ground side inside the MUX, so you should see about 0.6V for all the connections.

    I put away the PCB as it's time for a bit more work on the mechanical side. I have to file down one of the standoff on the other half shell as it has an interlocking bit sticking out.

    I used a sharp knife and file to work on the standoffs so that the PCB can be mounted flush.

    I connected the PCB to the connector with fine wires. I spliced the wires to an old telephone cord.

    This is how it looks.

    The last couple of USB cables from the dollar store has some really thick connectors. The remaining ones on the shelve were some flimsy pink cables. :(

    This is how the other side fits.

    I didn't have the mechanical drawings, so I had to measure everything. I guess I forgot to factor in some mechanical tolerance as everything is a tight fit.

    Case construction here.

  • The long wait for UPS

    K.C. Lee03/22/2017 at 18:53 0 comments

    Thus begins the long wait for UPS to drop it off to USPS. Record from last year was 1 month.

    I might get this hopefully this week. Meanwhile my other package mailed out a week earlier hasn't even made it to customs.

  • HDMI Switch Reverse Engineering

    K.C. Lee03/18/2017 at 20:47 0 comments

    I am trying to document some of the connections inside the HDMI switch.
    (Blue wire is my mod as my new GPU doesn't output +5V on the HDMI connector)


    U3 is an unmarked microcontroller in SOIC-8 that is controlling the HDMI switch. It is probably a good place to attach external cables to the USB MUX.

    Pin 1: Vcc
    Pin 2: HDMI Switch: S1
    Pin 3: HDMI Switch: S2
    Pin 4: Push button
    Pin 5: J1 +5V sense via 10K series resistor
    Pin 6: J3 +5V sense via 10K series resistor
    Pin 7: J4 +5V sense via 10K series resistor
    Pin 8: Gnd

    The +5V presence tells the microcontroller which port has active video. The microcontroller cycles through them each time the Push button get grounded. It'll also switch to the next available video source if the current one is no longer active. This is all we'll need for a minimalist KVM.

    The 3 Blue LEDs are buffered by transistors Q1- Q3 scattered on the PCB. They are controlled by the HDP[1..3] (Hot Plug Detect Status) signals which tells the video source that the monitor is present. That save them some extra I/O on the microcontroller.

    R10 (1K) control the brightness of the three LED. I swapped it out with a 4K7 as last thing I want is a blue spot light shinning just below my monitor.

    HDMI Switch:

    U2 Pin 9 PS: Power saving Selector - pull up by R2.
    U2 Pin 22 HDP_ctl: HPD output selector - pull up by R4.

    This means that the truth table on page 8 of the datasheet is being used.


    U1 is a switch mode power supply providing +3.3V for all the circuits. C10 is a bulk cap for the input after 3 Or'ing diodes. On my PCB, it is about 4.22V.

    The output connector J2 on the PCB is a bit off centered with respect to the opening in the case. This leaves a gap on the left side where a ribbon cable (up to 8 conductors) can exit.

View all 6 project logs

  • 1
    Step 1

    Those cheap $0.50 DB-25 hood is an artifact from the 1980's that looks suitable for this hack. I bought a bunch from surplus places a long while ago. This looks to be similar to the USB2LPT project which as a part#: Kappe CG25G, Cinch 40-9725H on Digikey and possibly others. (Mine were made in Taiwan.)

    The PCB is installed with solder side facing up. Hopefully it would It lines up with the two mounting holes. I made a rectangle hole with a box cutter, nibbler and a small file.

    The spacing is just right for the USB connector. I just have to prevent the connector from sliding out.

  • 2
    Step 2

    I clean up the area around the USB connector on an old motherboard. A single USB connector fits the footprint of double USB connector.

    Some rough cut with a cutting wheel using a Dremel tool. Remember eyes protection!

    After some cleanups, I eyeball the alignment and mark the cuts with a knife.

  • 3
    Step 3

    The "wings" on the sides fits in the cable retainer slot in opposite clam shell. Time for some elbow grease - cut, filing and finally cleanup.

    Something like this would probably work. There are manufacturing tolerances, (possibly part was designed in metric), so needs to be verified.

View all 4 instructions

Enjoy this project?



zakqwy wrote 03/16/2017 at 17:24 point

usb in a DB-25 hood is excellent!

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates