OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Apr 25, 2024 3:18 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: Keyboard driver portability
PostPosted: Fri Dec 30, 2016 12:59 pm 
Offline

Joined: Fri Dec 30, 2016 12:23 pm
Posts: 8
(This is my first post here. Hi.)

I've been working on a bootloader, and just got my keyboard "driver" to (barely) work on QEMU. It just disables the translator on the PS/2 controller and then each time it read a key press it writes the applicable ASCII character to the screen. However, just booted up on an old Athlon 64 desktop, and the driver doesn't look like it can correctly translate key presses. It "works" in the sense that it doesn't crash or do anything crazy, but the characters that show up on the screen have nothing to do with what I'm pressing.

The driver expects scan code set 2; since I've cleared the translate bit, isn't that what I should be getting? If I'm getting codes from another set, what do I need to do to ensure that I get set 2 on most systems?

For reference, here are a few keystrokes and what I see on screen:
Pause : "W)"
LShift: "V"
Right Arrow: "VP "

Since I can't get this problem in an emulator, it would be really cumbersome to try to test. I'm hoping someone here has dealt with it.

Keyboard "driver" w/o irrelevant parts:
Code:
#include "keyboard.h"
#include "keyboardtranslator.h"
#include "keyboardevent.h"
#include "pio.h"
#include "system.h"

bool Keyboard::keyflags[128];

void Keyboard::initialize()
{
   waitForBuffer(BUFFER_INPUT, false);
   outb(0x64, 0x20);
   waitForBuffer(BUFFER_OUTPUT, true);
   uint8_t config = inb(0x60);
   config &= 0xBF;
   
   waitForBuffer(BUFFER_INPUT, false);
   outb(0x64, 0x60);
   outb(0x60, config);
}

void Keyboard::sendEvent(KeyboardEvent event)
{
   keyflags[event.getKeycode()] = event.isPressed();
   if(event.isPressed() && KeyboardTranslator::keycodeToAscii(event.getKeycode()) != '\0')
      System::putChar(KeyboardTranslator::keycodeToAscii(keyflags[0x33] ? event.getKeycode() + 0x60 : event.getKeycode()));
}

void Keyboard::scan()
{
   uint8_t scancode[8] = {0};
   int scancodeLength = 0;
   bool pressed = true;

   uint8_t byte = 0;
   do
   {
      byte = readByte();
      if(byte != 0)
      {
         scancode[scancodeLength] = byte;
         scancodeLength++;
      }
   } while(byte != 0);
   
   if(scancode[0] == 0xF0)
   {
      
      pressed = false;
   }
   else if(scancode[0] == 0xE0)
   {
      if(scancode[1] == 0xF0)
      {
         pressed = false;
      }
   }
   
   if(scancodeLength > 0)
   {
      uint8_t lookup = scancode[scancodeLength - 1] + (scancode[0] == 0xE0 ? 0x80 : 0x00);
      KeyboardEvent event(KeyboardTranslator::lookupToKeycode(lookup), pressed);
      sendEvent(event);
   }
}

uint8_t Keyboard::readByte()
{
   if(waitForBuffer(BUFFER_OUTPUT, true))
   {
      uint8_t b = inb(0x60);
      return b;
   }
   else
      return 0;
}

bool Keyboard::waitForBuffer(uint8_t buffer, bool state)
{
   int counter = 0;
   uint8_t status = 0x00;
   do
   {
      status = inb(0x64);
      io_wait();
      counter++;
      if(counter > 16)
         return false;
   } while((status & buffer) != (state ? buffer : 0));
   return true;
}


And if it's relevant, the translator (with my spreadsheet):
https://docs.google.com/spreadsheets/d/1Yc823oVY4OgiJuzKS0bcee1Qbx-xGP7A2rcK0LwSBB4/edit#gid=0
Code:
#include "keyboardtranslator.h"
#include "system.h"

uint8_t KeyboardTranslator::keycodeLookup[256];

uint8_t KeyboardTranslator::asciiLookup[256];

void KeyboardTranslator::initialize()
{
   uint8_t keycodes[256] =
      {
         0xFF, 0x2C, 0xFF, 0x28, 0x26, 0x24, 0x25, 0x2F, 0xFF, 0x2D, 0x2B, 0x29, 0x27, 0x30, 0x3D, 0xFF, // 0
         0xFF, 0x32, 0x33, 0xFF, 0x34, 0x10, 0x1B, 0xFF, 0xFF, 0xFF, 0x19, 0x12, 0x00, 0x16, 0x1C, 0xFF, // 1
         0xFF, 0x02, 0x17, 0x03, 0x04, 0x1E, 0x1D, 0xFF, 0xFF, 0x31, 0x15, 0x05, 0x13, 0x11, 0x1F, 0xFF, // 2
         0xFF, 0x0D, 0x01, 0x07, 0x06, 0x18, 0x20, 0xFF, 0xFF, 0xFF, 0x0C, 0x09, 0x14, 0x21, 0x22, 0xFF, // 3
         0xFF, 0x36, 0x0A, 0x08, 0x0E, 0x1A, 0x23, 0xFF, 0xFF, 0x35, 0x37, 0x0B, 0x39, 0x0F, 0x38, 0xFF, // 4
         0xFF, 0xFF, 0x3E, 0xFF, 0x3A, 0x3C, 0xFF, 0xFF, 0x3F, 0x40, 0x41, 0x3B, 0xFF, 0x42, 0xFF, 0xFF, // 5
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x43, 0xFF, 0xFF, 0x45, 0xFF, 0x48, 0x4B, 0xFF, 0xFF, 0xFF, // 6
         0x44, 0x4E, 0x46, 0x49, 0x4A, 0x4C, 0x52, 0x53, 0x2E, 0x4F, 0x47, 0x50, 0x51, 0x4D, 0x54, 0xFF, // 7
         0xFF, 0xFF, 0xFF, 0x2A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8
         0x55, 0x56, 0xFF, 0xFF, 0x57, 0x58, 0xFF, 0xFF, 0x59, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5A, // 9
         0x5B, 0x5C, 0xFF, 0x5D, 0xFF, 0xFF, 0xFF, 0x5E, 0x5F, 0xFF, 0xFF, 0x60, 0xFF, 0xFF, 0xFF, 0x61, // A
         0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0xFF, 0x65, 0x66, 0xFF, 0x67, 0x68, 0xFF, 0xFF, 0xFF, 0x69, // B
         0x6A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0xFF, 0x6D, 0xFF, 0xFF, // C
         0x6E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6F, 0xFF, 0xFF, 0xFF, 0x70, 0xFF, // D
         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x71, 0xFF, 0x72, 0x73, 0xFF, 0xFF, 0xFF, // E
         0x74, 0x75, 0x76, 0xFF, 0x77, 0x78, 0xFF, 0xFF, 0xFF, 0xFF, 0x79, 0xFF, 0xFF, 0x7A, 0xFF, 0xFF  // F
      };
   
   uint8_t ascii[256] =
      {// 0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',      // 0
         'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',      // 1
         '6', '7', '8', '9', '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',   // 2
         '\t',' ', '\0','\0','\0','.', ',', '/', '-', ';', '[', ']', '=', '`', '\'','\0',   // 3
         '\0','\n','\\','\0','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '+',    // 4
         '-', '*', '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',   // 5
         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',      // 6
         'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ')', '!', '@', '#', '$', '%',      // 7
         '^', '&', '*', '(', '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',   // 8
         '\t',' ', '\0','\0','\0','>', '<', '?', '_', ':', '{', '}', '+', '~', '"', '\0',    // 9
         '\0','\n','|', '\0','0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '+',      // A
         '-', '*', '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',   // B
         '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',   // C
         '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',    // D
         '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',    // E
         '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',    // F
      };
   
   for(int i = 0; i < 256; i++)
   {
      keycodeLookup[i] = keycodes[i];
      asciiLookup[i] = ascii[i];
   }
}

uint8_t KeyboardTranslator::lookupToKeycode(uint8_t lookupID)
{
   return keycodeLookup[lookupID];
}

uint8_t KeyboardTranslator::keycodeToAscii(uint8_t keycode)
{
   return asciiLookup[keycode];
}

uint8_t KeyboardTranslator::asciiToKeycode(uint8_t ascii)
{
   
}


Top
 Profile  
 
 Post subject: Re: Keyboard driver portability
PostPosted: Fri Dec 30, 2016 1:30 pm 
Offline
Member
Member
User avatar

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

NGiddings wrote:
The driver expects scan code set 2; since I've cleared the translate bit, isn't that what I should be getting? If I'm getting codes from another set, what do I need to do to ensure that I get set 2 on most systems?


Is it a real PS/2 keyboard; or is it a USB keyboard where you can expect that the BIOS will do "PS/2 emulation" wrong?


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: Keyboard driver portability
PostPosted: Fri Dec 30, 2016 1:32 pm 
Offline

Joined: Fri Dec 30, 2016 12:23 pm
Posts: 8
Brendan wrote:
Hi,
Is it a real PS/2 keyboard; or is it a USB keyboard where you can expect that the BIOS will do "PS/2 emulation" wrong?


Shoot, I didn't even think of that!

It is a USB keyboard. I'll hook up a real PS/2 keyboard right now and see what happens.


Top
 Profile  
 
 Post subject: Re: Keyboard driver portability
PostPosted: Fri Dec 30, 2016 1:41 pm 
Offline

Joined: Fri Dec 30, 2016 12:23 pm
Posts: 8
Nope, still doesn't work. I have the exact same problem as before, but with an older keyboard.

This is very odd to me now. Are there any other steps needed to ensure that I'm getting the right code set? From everything I've read, set 2 is the default for the keyboard. I'll also mention that I've tried before to issue command 0xF0 (get/set scan code set), and QEMU just reboots. I found that that running

Code:
outb(0x64, 0xF0); // Crashes here
outb(0x60, 2);


will cause the emulator to reboot the computer. It seems like a triple fault, since but I haven't properly tested my double fault handler, but I have no idea why it's happening.

Is that in any way relevant?


Top
 Profile  
 
 Post subject: Re: Keyboard driver portability
PostPosted: Fri Dec 30, 2016 4:42 pm 
Offline
Member
Member
User avatar

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

NGiddings wrote:
I found that that running

Code:
outb(0x64, 0xF0); // Crashes here
outb(0x60, 2);


will cause the emulator to reboot the computer. It seems like a triple fault, since but I haven't properly tested my double fault handler, but I have no idea why it's happening.

Is that in any way relevant?


That one is easy. You're not sending that byte to the keyboard, it's a command for the PS/2 controller chip itself. The specific command 0xF0 tells the PS/2 controller chip to pulse "output lines 0 to 3" for 6 ms, and one of those output lines is connected to the computer's reset. It's not a triple fault...

To send bytes to a device connected to a PS/2 port (e.g. to send a keyboard plugged into the first PS/2 port), see this part of the wiki page.

For the original problem/code; I'm wondering if part of the problem is that you're ignoring the return value of "waitForBuffer()" everywhere, have a timeout that has nothing to do with time (e.g. depends on chipset and CPU speed and not time) and have a low "timeout" count.


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  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: awik, rdos and 219 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