(Solved) Keyboard decoder logic

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Keyboard decoder logic

Post by Brendan »

Hi,
octacone wrote:My keyboard is an USB keyboard, which means that I don't use that port at all.
Your keyboard is a USB keyboard, and therefore you probably shouldn't be using it for testing PS/2 drivers in the first place.

The firmware's code to do "legacy emulation for USB" (which you're relying on now) is almost always minimal and/or buggy, and this prevents an OS from doing adequate PS/2 controller initialisation and testing reliably. In addition to that, USB keyboard and USB mouse can have multiple modes - e.g. a "normal mode" where all of the device's features can be used and a (technically optional) "boot device mode" where the protocol the device uses is restricted to a standardised minimum set of features (to make it easier for the firmware's "legacy emulation of USB" code).
octacone wrote:When I checked all the scan codes I got, they corresponded to the first keyboard layout set. Doesn't disabling it mean that I will get a whole other set of key codes that I will have to map, bummer.
You checked all the scan codes that you got; and because your PS/2 controller initialisation is bad (and doesn't disable "scancode translation") you ended up getting scancode set 1 (even though keyboard is using scancode set 2).

For real PS/2 devices; if a keyboard only supports scancode set 2 and that keyboard is plugged into the 2nd PS/2 port (where the PS/2 controller doesn't support scancode translation); then there is only one possible choice. If you use scancode set 2 then you can cover all possible scenarios. If you try to use scancode set 1 then you will have to support scancode set 2 for some cases (or fail to support those cases).
octacone wrote:Am I handling those multi bytes the right way?
You mostly want a state machine to decode scancodes. For scancode set 1 the states would be:
  • state 0: no escape sequence bytes yet
    state 1: 0xE0 was received
    state 2: 0xE0, 0x2A was received (first 2 bytes of "print screen pressed")
    state 3: 0xE0, 0x2A, 0xE0 was received (first 3 bytes of "print screen pressed")
    state 4: 0xE0, 0xB7 was received (first 2 bytes of "print screen released")
    state 5: 0xE0, 0xB7, 0xE0 was received (first 3 bytes of "print screen released")
    state 6: 0xE1 was received
    state 7: 0xE1, 0x1D was received (first 2 bytes of "pause")
    state 8: 0xE1, 0x1D, 0x45 was received (first 3 bytes of "pause")
    state 9: 0xE1, 0x1D, 0x45, 0xE1 was received (first 4 bytes of "pause")
    state 10: 0xE1, 0x1D, 0x45, 0xE1, 0x9D was received (first 5 bytes of "pause")
For scancode set 2 the states would be:
  • state 0: no escape sequence bytes yet
    state 1: 0xE0 was received
    state 2: 0xE0, 0xF0 was received
    state 3: 0xF0 was received
    state 4: 0xE0, 0x12 was received (first 2 bytes of "print screen pressed")
    state 5: 0xE0, 0x12, 0xE0 was received (first 3 bytes of "print screen pressed")
    state 6: 0xE0, 0xF0, 0x7C was received (first 3 bytes of "print screen released")
    state 7: 0xE0, 0xF0, 0x7C, 0xE0 was received (first 4 bytes of "print screen released")
    state 8: 0xE0, 0xF0, 0x7C, 0xE0, 0xF0 was received (first 5 bytes of "print screen released")
    state 9: 0xE1 was received
    state 10: 0xE1, 0x14 (first 2 bytes of "pause")
    state 11: 0xE1, 0x14, 0x77 (first 3 bytes of "pause")
    state 12: 0xE1, 0x14, 0x77, 0xE1 (first 4 bytes of "pause")
    state 13: 0xE1, 0x14, 0x77, 0xE1, 0xF0 (first 5 bytes of "pause")
    state 14: 0xE1, 0x14, 0x77, 0xE1, 0xF0, 0x14 (first 6 bytes of "pause")
    state 15: 0xE1, 0x14, 0x77, 0xE1, 0xF0, 0x14, 0xF0 (first 7 bytes of "pause")
Each time you receive a byte, you use the current state and the received byte to determine the new state. For example, if you've received the byte 0x12 and you're in "state 15" (for scancode set 2) then something has gone wrong because that's not a valid byte for "state 15" (even though 0x12 is a valid byte for other states).

On top of that; you may receive any of the "special bytes" listed here at any time (even when you're in the middle of receiving a multi-byte scan code). Most of these indicate some sort of problem and either causes your state machine to be reset (because driver re-tested and reset the device), or causes your driver to tell the OS "device is faulty" and terminate itself. Some of the special bytes (command acknowledged, command needs to be resent and echo) don't effect the state machine.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Keyboard decoder logic

Post by Octacone »

Brendan wrote:Hi,
octacone wrote:My keyboard is an USB keyboard, which means that I don't use that port at all.
Your keyboard is a USB keyboard, and therefore you probably shouldn't be using it for testing PS/2 drivers in the first place.

The firmware's code to do "legacy emulation for USB" (which you're relying on now) is almost always minimal and/or buggy, and this prevents an OS from doing adequate PS/2 controller initialisation and testing reliably. In addition to that, USB keyboard and USB mouse can have multiple modes - e.g. a "normal mode" where all of the device's features can be used and a (technically optional) "boot device mode" where the protocol the device uses is restricted to a standardised minimum set of features (to make it easier for the firmware's "legacy emulation of USB" code).
octacone wrote:When I checked all the scan codes I got, they corresponded to the first keyboard layout set. Doesn't disabling it mean that I will get a whole other set of key codes that I will have to map, bummer.
You checked all the scan codes that you got; and because your PS/2 controller initialisation is bad (and doesn't disable "scancode translation") you ended up getting scancode set 1 (even though keyboard is using scancode set 2).

For real PS/2 devices; if a keyboard only supports scancode set 2 and that keyboard is plugged into the 2nd PS/2 port (where the PS/2 controller doesn't support scancode translation); then there is only one possible choice. If you use scancode set 2 then you can cover all possible scenarios. If you try to use scancode set 1 then you will have to support scancode set 2 for some cases (or fail to support those cases).
octacone wrote:Am I handling those multi bytes the right way?
You mostly want a state machine to decode scancodes. For scancode set 1 the states would be:
  • state 0: no escape sequence bytes yet
    state 1: 0xE0 was received
    state 2: 0xE0, 0x2A was received (first 2 bytes of "print screen pressed")
    state 3: 0xE0, 0x2A, 0xE0 was received (first 3 bytes of "print screen pressed")
    state 4: 0xE0, 0xB7 was received (first 2 bytes of "print screen released")
    state 5: 0xE0, 0xB7, 0xE0 was received (first 3 bytes of "print screen released")
    state 6: 0xE1 was received
    state 7: 0xE1, 0x1D was received (first 2 bytes of "pause")
    state 8: 0xE1, 0x1D, 0x45 was received (first 3 bytes of "pause")
    state 9: 0xE1, 0x1D, 0x45, 0xE1 was received (first 4 bytes of "pause")
    state 10: 0xE1, 0x1D, 0x45, 0xE1, 0x9D was received (first 5 bytes of "pause")
For scancode set 2 the states would be:
  • state 0: no escape sequence bytes yet
    state 1: 0xE0 was received
    state 2: 0xE0, 0xF0 was received
    state 3: 0xF0 was received
    state 4: 0xE0, 0x12 was received (first 2 bytes of "print screen pressed")
    state 5: 0xE0, 0x12, 0xE0 was received (first 3 bytes of "print screen pressed")
    state 6: 0xE0, 0xF0, 0x7C was received (first 3 bytes of "print screen released")
    state 7: 0xE0, 0xF0, 0x7C, 0xE0 was received (first 4 bytes of "print screen released")
    state 8: 0xE0, 0xF0, 0x7C, 0xE0, 0xF0 was received (first 5 bytes of "print screen released")
    state 9: 0xE1 was received
    state 10: 0xE1, 0x14 (first 2 bytes of "pause")
    state 11: 0xE1, 0x14, 0x77 (first 3 bytes of "pause")
    state 12: 0xE1, 0x14, 0x77, 0xE1 (first 4 bytes of "pause")
    state 13: 0xE1, 0x14, 0x77, 0xE1, 0xF0 (first 5 bytes of "pause")
    state 14: 0xE1, 0x14, 0x77, 0xE1, 0xF0, 0x14 (first 6 bytes of "pause")
    state 15: 0xE1, 0x14, 0x77, 0xE1, 0xF0, 0x14, 0xF0 (first 7 bytes of "pause")
Each time you receive a byte, you use the current state and the received byte to determine the new state. For example, if you've received the byte 0x12 and you're in "state 15" (for scancode set 2) then something has gone wrong because that's not a valid byte for "state 15" (even though 0x12 is a valid byte for other states).

On top of that; you may receive any of the "special bytes" listed here at any time (even when you're in the middle of receiving a multi-byte scan code). Most of these indicate some sort of problem and either causes your state machine to be reset (because driver re-tested and reset the device), or causes your driver to tell the OS "device is faulty" and terminate itself. Some of the special bytes (command acknowledged, command needs to be resent and echo) don't effect the state machine.


Cheers,

Brendan
I don't really have a choice since my only option is an USB keyboard. I do have PS/2 keyboards but not a place to plug them into. Not initializing them properly? Okay I will take a look into that, also I will let it use the second key set. I really really want to get this done properly. So I will give myself some time to do everything as it is supposed to be done. Are there any detailed PS/2 initialization documents? Right now I am not handling special bytes at all.

@dozniak @MichaelFarthing @Octocontrabass
I am quite shocked! :o I thought that was the way of handling multi bytes. Looks like I screwed something up. Then how am I supposed to handle them after all?
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Keyboard decoder logic

Post by Brendan »

Hi,
octacone wrote:I don't really have a choice since my only option is an USB keyboard. I do have PS/2 keyboards but not a place to plug them into. Not initializing them properly? Okay I will take a look into that, also I will let it use the second key set. I really really want to get this done properly.
If you don't have PS/2 (and only have USB emulating PS/2 badly) and do PS/2 initialisation properly, you probably won't be able to test your code properly (and if you do test your code you won't know if any problems are because of your code or because of the firmware).
octacone wrote:Are there any detailed PS/2 initialization documents?
Yes - the wiki page has a relatively thorough description of initialising the PS/2 controller.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
dozniak
Member
Member
Posts: 723
Joined: Thu Jul 12, 2012 7:29 am
Location: Tallinn, Estonia

Re: Keyboard decoder logic

Post by dozniak »

octacone wrote: Then how am I supposed to handle them after all?
EXACTLY as described in the Brendan post you over-quoted above. Did you even read it?
Learn to read.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Keyboard decoder logic

Post by Octacone »

Brendan wrote:Hi,
octacone wrote:I don't really have a choice since my only option is an USB keyboard. I do have PS/2 keyboards but not a place to plug them into. Not initializing them properly? Okay I will take a look into that, also I will let it use the second key set. I really really want to get this done properly.
If you don't have PS/2 (and only have USB emulating PS/2 badly) and do PS/2 initialisation properly, you probably won't be able to test your code properly (and if you do test your code you won't know if any problems are because of your code or because of the firmware).
octacone wrote:Are there any detailed PS/2 initialization documents?
Yes - the wiki page has a relatively thorough description of initialising the PS/2 controller.


Cheers,

Brendan
:( That is really disappointing. Even if I make it all work I won't know for sure. That is my only option then. What about a laptop keyboard, what kind of an interfaces does it use internally?
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Keyboard decoder logic

Post by Octacone »

dozniak wrote:
octacone wrote: Then how am I supposed to handle them after all?
EXACTLY as described in the Brendan post you over-quoted above. Did you even read it?
Sure I did. But HOW TO HANDLE MULTIPLE BYTES when I am only getting one specific hexadecimal value? Not getting that concept. :? What those states are??? How to get 7 scan codes when I am only getting one per interrupt? Do you even understand what I am saying?
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Keyboard decoder logic

Post by Brendan »

Hi,
octacone wrote: :( That is really disappointing. Even if I make it all work I won't know for sure. That is my only option then. What about a laptop keyboard, what kind of an interfaces does it use internally?
That depends on the laptop. Some use USB, some use PS/2 (and some do dodgy stuff with "auto-PS/2-port switching", and usually there's a touchpad and no mouse).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Keyboard decoder logic

Post by Brendan »

Hi,
octacone wrote:Sure I did. But HOW TO HANDLE MULTIPLE BYTES when I am only getting one specific hexadecimal value? Not getting that concept. :? What those states are??? How to get 7 scan codes when I am only getting one per interrupt? Do you even understand what I am saying?
Like...

Code: Select all

    switch(state) {
    case 0:
        switch(receivedByte) {
            case 0xE1:
                state = 9;      // 0xE1 was received
                return;
            default:
                handleUnexpected();
                return;
        }
        break;
    case 9:      // 0xE1 was received
        switch(receivedByte) {
            case 0x14:
                state = 10;     // 0xE1,0x14 was received
                return;
            default:
                handleUnexpected();
                return;
        }
        break;
    case 10:     // 0xE1,0x14 was received
        switch(receivedByte) {
            case 0x77:
                state = 11;     // 0xE1,0x14,0x77 was received
                return;
            default:
                handleUnexpected();
                return;
        }
        break;
    case 11:     // 0xE1,0x14,0x77 was received
        switch(receivedByte) {
            case 0xE1:
                state = 12;     // 0xE1,0x14,0x77,0xE1 was received
                return;
            default:
                handleUnexpected();
                return;
        }
        break;

    case 15:     // 0xE1,0x14,0x77,0xE1,0xF0,0x14,0xF0 was received
        switch(receivedByte) {
            case 0x77:     // 0xE1,0x14,0x77,0xE1,0xF0,0x14,0xF0,0x77 (entire "pause" scancode)
                handleKeycode(KEYCODE_PAUSE, PRESSED);
                handleKeycode(KEYCODE_PAUSE, RELEASED);
                state = 0;
                return;
            default:
                handleUnexpected();
                return;
        }
        break;
Of course I missed a lot of cases, and you'll want to use lookup tables to simplify some of the cases (otherwise your "switch()" will be massive).

Note that you can do something like "switch( state << 8 | receivedByte) {" so that there's only one "switch()"; and if you really want you can just have a big lookup table and do something like:

Code: Select all

    temp =  state << 8 | receivedByte;
    state = lookupTable[temp].nextState;
    if(state == 0) {    // Must've got the whole scancode
        keycode = lookupTable[temp].keycode;
        flags = lookupTable[temp].flags;
        if(flags says it was pressed) {
            handleKeycode(keycode, PRESSED);
        }
        if(flags says it was released) {
            handleKeycode(keycode, RELEASED);
        }

Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
dozniak
Member
Member
Posts: 723
Joined: Thu Jul 12, 2012 7:29 am
Location: Tallinn, Estonia

Re: Keyboard decoder logic

Post by dozniak »

octacone wrote: Sure I did. But HOW TO HANDLE MULTIPLE BYTES when I am only getting one specific hexadecimal value? Not getting that concept. :? What those states are??? How to get 7 scan codes when I am only getting one per interrupt? Do you even understand what I am saying?
You can't handle multiple bytes because you get bytes one at a time from the keyboard controller.

You'll have to save previously received bytes in some sort of "state". Google for Finite State Machine.
Learn to read.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Keyboard decoder logic

Post by Octacone »

I will leave that state machine alone for now. Need to take couple of months in order to understand how it works. :oops:

This thing right here is my first direct "text to code" contact: (It surely sucks, but at least it is my own creation)

Code: Select all

-removed-
-old code-
-now it is much better and properly written-
I (mostly) did it as Wiki suggested. How bad is it? It surely is bad since I am not getting any keyboard interrupts cause of that code.
Last edited by Octacone on Sat Feb 04, 2017 4:13 am, edited 1 time in total.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
FusT
Member
Member
Posts: 91
Joined: Wed Sep 19, 2012 3:43 am
Location: The Netherlands

Re: Keyboard decoder logic

Post by FusT »

You may be going way too fast for the PS/2 controller.
As I remember from writing my PS/2 driver's initialization routine you should read the answers from the PS/2 controller after sending a command to ensure it acknowledges the command (see the wiki for this).
Also, for some commands (like "disable port X") you should use a wait_and_poll_port kind of method (with a timeout!) to clear the controller's output buffer before sending another command or you'll get some really weird results.
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: Keyboard decoder logic

Post by Octocontrabass »

octacone wrote:How bad is it?
Port 0x20 has nothing to do with the keyboard controller. Perhaps you wanted command 0x20?
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Keyboard decoder logic

Post by Octacone »

FusT wrote:You may be going way too fast for the PS/2 controller.
As I remember from writing my PS/2 driver's initialization routine you should read the answers from the PS/2 controller after sending a command to ensure it acknowledges the command (see the wiki for this).
Also, for some commands (like "disable port X") you should use a wait_and_poll_port kind of method (with a timeout!) to clear the controller's output buffer before sending another command or you'll get some really weird results.
"Too fast" (working on this for past 2 weeks). :P

Whenever I try to read something, I get nothing. Like no response or wrong response.
I know I should add some timeout but don't know exactly where, like after every write call or only for specific commands.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Keyboard decoder logic

Post by Octacone »

Octocontrabass wrote:
octacone wrote:How bad is it?
Port 0x20 has nothing to do with the keyboard controller. Perhaps you wanted command 0x20?
Right now I am talking about the PS/2 controller itself.
I am generally very confused when it comes to PS/2-keyboard port relation. There are so many ports that are the same but do different things. Does any of you know for sure what ports am I supposed to use when reading and writing from/to my PS/2 controller? 0x64 or 0x60 or 0x20 for reading or something else for reading responses? Wiki is kind of messy + there is an edit made by Sortie that talks about wrong response replies and ports.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Keyboard decoder logic

Post by Schol-R-LEA »

octacone wrote:
FusT wrote:You may be going way too fast for the PS/2 controller
"Too fast" (working on this for past 2 weeks). :P
I think that FusT meant that your handler is going to fast, not the code development, and is saying that you need to insert a wait of some kind into the code.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Post Reply