Page 1 of 1

Setting the Scan Code set

Posted: Sun Dec 03, 2017 10:16 am
by zvoncika
I'm using the following code to try and set the Scan Code set ( 2 ).

Code: Select all

outb(0x60,0xF0);
	outb(0x64,0x02);
However,when I try to boot my OS in QEMU or VirtualBox they both reset.
Bochs doesn't.
What am I doing wrong here?
Here is my init function:

Code: Select all

void ps2_keyboard_install()
{
	while(inb(PS2_KB_CMD) & 0x1)
		inb(PS2_KB_DATA);
	// Test the PS/2 controller
	outb(PS2_KB_CMD,0xAA);
	if(inb(PS2_KB_DATA) != 0x55)
	{
		// PS/2 Controller test failed
		// Kernel Panic
		asm volatile("int $19");
	}
	// Test the first port
	outb(PS2_KB_CMD,0xAB);
	if(inb(PS2_KB_DATA) != 0x00)
	{
		// First port didn't pass the test
		// Kernel Panic
		asm volatile("int $19");
	}
	// Enable the first port
	outb(PS2_KB_CMD,0xAE);
	// Set SCS
	outb(PS2_KB_CMD,0xF0);
	outb(PS2_KB_DATA,0x02);
	// Get config
	outb(PS2_KB_CMD,0x20);
	uint8_t cfg = (inb(PS2_KB_DATA) | 1) & ~0x10;
	// Set config
	outb(PS2_KB_CMD,0x60);
	outb(PS2_KB_DATA,cfg);
	// Set scan code set
	// Install our handler
	irq_install_handler(1, ps2_keyboard_handler);
}

Re: Setting the Scan Code set

Posted: Sun Dec 03, 2017 1:16 pm
by Octocontrabass

Code: Select all

outb(0x60,0xF0);
	outb(0x64,0x02);
This code sends the first byte to the keyboard, and then (without waiting for the keyboard controller to send that byte to the keyboard or receive the keyboard's response) sends an undocumented command to the keyboard controller. This code does not appear to match your ps2_keyboard_install function.

For the rest of your code, I'll assume PS2_KB_CMD is 0x64 and PS2_KB_DATA is 0x60.

Code: Select all

	while(inb(PS2_KB_CMD) & 0x1)
		inb(PS2_KB_DATA);
If there is a fault with the keyboard controller, this may become an infinite loop.

Code: Select all

	outb(PS2_KB_CMD,0xAA);
	if(inb(PS2_KB_DATA) != 0x55)
	{
Keyboard controller command 0xAA may take a long time to execute, and it may completely reset the keyboard controller to its power-on defaults. You must wait for the keyboard controller to respond, and you may also need to reconfigure it (e.g. to disable translation and set the "system flag").

Code: Select all

	outb(PS2_KB_CMD,0xAB);
	if(inb(PS2_KB_DATA) != 0x00)
	{
Again, you need to wait for the keyboard controller to respond.

Code: Select all

	outb(PS2_KB_CMD,0xAE);
Seriously. Old keyboard controllers are slow. You have to wait.

Code: Select all

	outb(PS2_KB_CMD,0xF0);
This reboots the computer, assuming the keyboard controller is ready to accept this command.

Code: Select all

	outb(PS2_KB_DATA,0x02);
This is not a documented keyboard command. The keyboard may misbehave after you send this.

Code: Select all

	outb(PS2_KB_CMD,0x20);
	uint8_t cfg = (inb(PS2_KB_DATA) | 1) & ~0x10;
	// Set config
	outb(PS2_KB_CMD,0x60);
	outb(PS2_KB_DATA,cfg);
You can probably guess what I'm going to say here: not enough waiting. Also, it's a race condition, since you're enabling IRQ1 before you install an IRQ1 handler.

It looks like you might be confusing the keyboard controller with the keyboard. Both can accept and respond to commands, but sending commands to the keyboard is different from sending commands to the keyboard controller. You should finish initializing your keyboard controller, installing the IRQ handler(s), and enabling the IRQ(s) before you enable the keyboard port and start initializing the keyboard.

Re: Setting the Scan Code set

Posted: Sun Dec 03, 2017 2:23 pm
by zvoncika
How long should I wait?

Re: Setting the Scan Code set

Posted: Sun Dec 03, 2017 2:28 pm
by zvoncika
Should I have a temporary IRQ handler that I'll use while I, configure my PS/2 controller?

Re: Setting the Scan Code set

Posted: Sun Dec 03, 2017 2:34 pm
by isaacwoods
The PS/2 controller tells you when it's ready to be issued commands and whatnot. This is what I use:

Code: Select all

  /*
   * Bit 0 of the status register must be SET before attempting to read data from port 0x60
   * Bit 1 of the status register must be CLEAR before attempting to write data to port 0x60
   */
  #define WAIT_FOR_READ()   while ((inb(PS2_COMMAND) & 1u) == 0u) asm volatile("rep nop");
  #define WAIT_FOR_WRITE()  while ((inb(PS2_COMMAND) & 2u) != 0u) asm volatile("rep nop");

Re: Setting the Scan Code set

Posted: Sun Dec 03, 2017 2:40 pm
by zvoncika
Huh, thanks!
Really appreciate all the help you guys give me [-o<