OSDev.org

The Place to Start for Operating System Developers
It is currently Sat Jul 21, 2018 1:39 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: How do 0xE0 keyboard scancodes (PS/2) work?
PostPosted: Mon Jan 01, 2018 3:18 pm 
Offline

Joined: Thu May 25, 2017 10:41 pm
Posts: 19
I'm working on PS/2 keyboard support on my kernel. There are scancodes with "E0, xx", and I'm not too sure how these are supposed to work.
I think this means that I read the scancode, 0xE0, and if it's 0xE0 I read another byte, which is the scancode. This doesn't really work.
Here is my keyboard IRQ handler right now, stripped down for debugging purposes:

Code:
void kb_irq_handler(struct regs *r) {
   byte scancode;
   scancode = inb(0x60);
}


When pressing any keys with an E0 scancode it immediately prints the second part (i.e. 1D for RCTRL) which is correct, but I'm not getting an E0. Why might this be? Am I misunderstanding something?
edit: It works fine for keys without an E0.


Top
 Profile  
 
 Post subject: Re: How do 0xE0 keyboard scancodes (PS/2) work?
PostPosted: Mon Jan 01, 2018 5:37 pm 
Offline
Member
Member

Joined: Tue Feb 11, 2014 4:59 pm
Posts: 37
Just remember of 0xE0 appearance and leave interrupt.

In next interrupt check if 0xE0 occurred. If yes, then it was special key pressed.

For example, if i get scancode of 0x2A and 0xE0 occured before, then this is "Left Shift" key, after that just forget about 0xE0.

_________________
wataha.net - system programming, my own 64 bit kernel and software.


Top
 Profile  
 
 Post subject: Re: How do 0xE0 keyboard scancodes (PS/2) work?
PostPosted: Mon Jan 01, 2018 9:25 pm 
Offline
Member
Member
User avatar

Joined: Sat Jan 15, 2005 12:00 am
Posts: 8398
Location: At his keyboard!
Hi,

thumble wrote:
I'm working on PS/2 keyboard support on my kernel. There are scancodes with "E0, xx", and I'm not too sure how these are supposed to work.
I think this means that I read the scancode, 0xE0, and if it's 0xE0 I read another byte, which is the scancode. This doesn't really work.


Typically you have a state machine, where you have a default state (nothing received yet) and an "0xE0 received" state (and a bunch of other states for other sequences); and when you receive a byte you look at both the state and the byte received to determine what to do and which state to move into next.

The fastest and most flexible way to handle this might be with a table of function pointers; like:

Code:
int state = 0;
int newByte = 0;

void kb_irq_handler(void) {
    newByte = inb(0x60);
    state = (*functionTable[state << 8 | newByte])();
}


In this case; during initialisation you'd configure the table of function pointers; possibly starting with "pre-configuration" where you add table entries for special bytes (0x00 = keyboard error, 0xAA = self test passed, 0xEE = echo, ...) and set everything else to a generic "invalid sequence" function, and then you'd parse some kind of keyboard layout file to determine how the rest of the table of function pointers should be setup; so that the driver is able to handle radically different keyboards just by providing different keyboard layout files (potentially including being able to support different scan code sets).

thumble wrote:
When pressing any keys with an E0 scancode it immediately prints the second part (i.e. 1D for RCTRL) which is correct, but I'm not getting an E0. Why might this be? Am I misunderstanding something?
edit: It works fine for keys without an E0.


How do you know that you're not getting an 0xE0? For example, if you're doing some kind of "printChar(ASCII);" then maybe the problem is that there's no way to convert the 0xE0 byte into valid ASCII, if you're doing some kind of "printHex(byte)" then maybe your "printHex()" function is buggy, ...

Also note that some emulators struggle to emulate keyboards 100% accurately. For example, the host OS might tell the emulator that a control key was pressed (but not which one), so the emulator might tell the guest OS that left control was pressed (0x1D) even though the user actually pressed the right control key (0xE0, 0x1D).


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.


Top
 Profile  
 
 Post subject: Re: How do 0xE0 keyboard scancodes (PS/2) work?
PostPosted: Wed Jan 03, 2018 6:12 pm 
Offline
Member
Member

Joined: Wed Aug 17, 2016 4:55 am
Posts: 217
Yeah, as mentioned the next byte will come in the next interrupt, not immediately. You need to remember the previous bytes somehow.

This seems to be one of the most common mistakes when dealing with interrupt-based hardware, I think that a lot of tutorials and documentation just says you get two bytes without being explicit that they mean it comes in separate interrupts (when teaching something where a similar situation hadn't been brought up before). It gets even worse when sending multi-byte commands where you're expected to get an ACK after every byte, the ACK will come in interrupts (likely from an entirely unrelated context than the code sending the command) so you actually need to wait for them to come in which can take a long while (i.e. busylooping is not a good option!).

_________________
https://github.com/sikthehedgehog/indigo


Top
 Profile  
 
 Post subject: Re: How do 0xE0 keyboard scancodes (PS/2) work?
PostPosted: Wed Jan 03, 2018 11:35 pm 
Offline

Joined: Thu May 25, 2017 10:41 pm
Posts: 19
Ah! That makes sense now. Thank you so much.
edit: It works!
This may not be the best solution, but I store the last scancode and check if it is 0xE0 in my conversion function.


Top
 Profile  
 
 Post subject: Re: How do 0xE0 keyboard scancodes (PS/2) work?
PostPosted: Thu Jan 04, 2018 5:33 am 
Offline
Member
Member
User avatar

Joined: Fri Aug 07, 2015 6:13 am
Posts: 957
This is actually a very complex topic. It took me a while to realize how to do a state machine.
The main problem is that people don't know that one interrupt equals one byte of a scancode sequence.
0xE0 is not the only thing that you need to implement. There are also multi-byte (up to 6 if I remember) scancodes per key press that you need to handle.
State machine would be the best option.

_________________
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader


Top
 Profile  
 
 Post subject: Re: How do 0xE0 keyboard scancodes (PS/2) work?
PostPosted: Thu Jan 04, 2018 2:28 pm 
Offline
Member
Member

Joined: Wed Aug 17, 2016 4:55 am
Posts: 217
Octacone wrote:
There are also multi-byte (up to 6 if I remember) scancodes per key press that you need to handle.

Yeah, Pause key does it (sends the equivalent of Shift+* key down and key up, if I recall correctly). But that one is easier since it's the only scancode that starts with 0xE1 (presumably signaling that it's two extended bytes instead of one - again, remember it sends two state changes in a row), if you get it you know the next five scancodes are for that key. I imagine it was intended to trigger a shortcut used by very early PCs.

Every other key is limited to just one or two scancodes if you're using set 1 (which seems to be the case here, judging from 0xE0 being an extension prefix). A bigger issue is that keyboards may have trouble using set 1 (instead of set 2), so consider adding support for set 2 when feasible.

_________________
https://github.com/sikthehedgehog/indigo


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group