PS/2 Mouse Issues

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.
iProgramInCpp
Member
Member
Posts: 88
Joined: Sun Apr 21, 2019 7:39 am

PS/2 Mouse Issues

Post by iProgramInCpp »

I am trying to implement mouse interrupts in my operating system, yet it doesn't work.

Here's my mouse code:

Code: Select all

// SANiK source code adaptation

#define WorkAreaW 640
#define WorkAreaH 480

#define MousePort 0x60
#define MouseStatus 0x64
#define MouseABit 0x02
#define MouseBBit 0x01
#define MouseWriteC 0xd4
#define MouseFBit 0x20
#define MouseVBit 0x08

#define MouseDefault 0
#define MouseScrollWheel 1
#define MouseButtons 2

int MousePosX = 0;
int MousePosY = 0;

#define Cursor struct cursor_t
Cursor
{
	int64_t bitmap[12 * 21];
	uint8_t w, h;
};

#define X 0xffffff,
#define B 0x000000,
#define o (-1),
Cursor cursor = {
	{
		B o o o o o o o o o o o
		B B o o o o o o o o o o
		B X B o o o o o o o o o
		B X B B o o o o o o o o
		B X X X B o o o o o o o
		B X X X X B o o o o o o
		B X X X X X B o o o o o
		B X X X X X X B o o o o
		B X X X X X X X B o o o
		B X X X X X X X X B o o
		B X X X X X X X X X B o
		B X X X X X X B B B B B
		B X X X B X X B o o o o
		B X X B B X X B o o o o
		B X B o o B X X B o o o
		B B o o o B X X B o o o
		B o o o o o B X X B o o
		o o o o o o B X X B o o
		o o o o o o o B X X B o
		o o o o o o o B X X B o
		o o o o o o o o B B o o
	},
	12, 21
};
#undef X
#undef B
#undef o

uint8_t ps2_mouse_cycle = 0;
int8_t ps2_mouse_byte[3];
int8_t ps2_mouse_x = 0;
int8_t ps2_mouse_y = 0;

bool MouseAvailable = true;

// This is supposed to be called, but it doesn't, as to be expected.
void MouseHandlerMain()
{
	puts("FIRED");
	if (!MouseAvailable) puts("HOW");
}

// This function fails right at the beginning.
void MouseWait(uint8_t type, int linenum, int linenum2)
{
	if (!MouseAvailable) return;
	int timeout = 100000; //unsigned int
	
	while (timeout--)
	{
		if ((ReadPort(0x64) & (type + 1)) == 1) return;
	}
	MouseAvailable = false;
	printf("Mouse timeout reached, guessed that the mouse is unavailable. (failed at %d or %d)\n", linenum, linenum2);
	return;
}

// NOTE: ReadPort and WritePort work like inportb and outportb respectively.
void MouseWrite(uint8_t write, int line)
{
	if (!MouseAvailable) return;
	MouseWait(1, line, __LINE__);
	WritePort(0x64, 0xD4);
	MouseWait(1, line, __LINE__);
	WritePort(0x60, write);
}

uint8_t MouseRead(int line)
{
	if (!MouseAvailable) return 0xff;
	MouseWait(0, line, __LINE__);
	return ReadPort(0x60);
}

void InitMouse()
{
	puts("[INIT] Initializing Mouse...\n");
	uint8_t _status;
	
	// Enable the auxiliary mouse device.
	MouseWait(1, __LINE__, __LINE__); // THIS is where the code fails.
	WritePort(0x64, 0xA8);
	
	// Enable the interrupts
	MouseWait(1, __LINE__, __LINE__);
	WritePort(0x64, 0x20);
	MouseWait(0, __LINE__, __LINE__);
	_status = (ReadPort(0x60) | 2);
	MouseWait(1, __LINE__, __LINE__);
	WritePort(0x64, 0x60);
	MouseWait(1, __LINE__, __LINE__);
	WritePort(0x60, _status);
	
	// Tell the mouse to use default settings
	MouseWrite(0xF6, __LINE__);
	MouseRead(__LINE__);
	
	// Enable data reporting
	MouseWrite(0xF4, __LINE__);
	MouseRead(__LINE__);
	
	// The mouse handler is already set up
	// in the PIC.
	
	if (MouseAvailable)
		puts("[INIT] Init finished.\n");
	else
		puts("Mouse failed to initialize.\n");
}

Code: Select all

// This is what I use to load the mouse interrupt.
IDT[0x2c].offset_lowerbits = mouse_address & 0xffff;
IDT[0x2c].selector = KERNEL_CODE_SEGMENT_OFFSET;
IDT[0x2c].zero = 0;
IDT[0x2c].type_attr = INTERRUPT_GATE;
IDT[0x2c].offset_higherbits = (mouse_address & 0xffff0000) >> 16;

Code: Select all

#define INTERRUPT_ENABLE_BITS_0 0b11111100
#define INTERRUPT_ENABLE_BITS_1 0b11101111
// Setting the interrupt mask flags...
WritePort(0x21 , INTERRUPT_ENABLE_BITS_0);
WritePort(0xA1 , INTERRUPT_ENABLE_BITS_1);
NOTE: The __LINE__ is for debugging and will be removed.

This is an adaptation of http://forum.osdev.org/viewtopic.php?t=10247 without the handler part (I'll add that later when I get interrupts properly).
Hey! I'm developing two operating systems:

NanoShell --- A 32-bit operating system whose GUI takes inspiration from Windows 9x and early UNIX desktop managers.
Boron --- A portable SMP operating system taking inspiration from the design of the Windows NT kernel.
User avatar
portasynthinca3
Posts: 19
Joined: Sun Dec 22, 2019 12:52 pm
Location: Kazan, Russia

Re: PS/2 Mouse Issues

Post by portasynthinca3 »

Hi!
According to OSDev Wiki,
Even though the data shows up on port 0x60 (the keyboard port), it does not trigger an IRQ1.
So I don't think your interrupt-based approach will work.

Code: Select all

if ((ReadPort(0x64) & (type + 1)) == 1) return;
According to your code comments, this function fails when type equals 1. If type equals 1, type + 1 equals 2. You're constantly polling an I/O port and ANDing it with 2, but this will never be equal to one. If you want to check if a certain bit is set, you should compare it with zero, or just don't excplicitly compare it at all. if does that for you, so I think you need to change this line of code to

Code: Select all

if (ReadPort(0x64) & (type + 1)) return;
iProgramInCpp
Member
Member
Posts: 88
Joined: Sun Apr 21, 2019 7:39 am

Re: PS/2 Mouse Issues

Post by iProgramInCpp »

portasynthinca3 wrote:Hi!
According to OSDev Wiki,
Even though the data shows up on port 0x60 (the keyboard port), it does not trigger an IRQ1.
So I don't think your interrupt-based approach will work.

Code: Select all

if ((ReadPort(0x64) & (type + 1)) == 1) return;
According to your code comments, this function fails when type equals 1. If type equals 1, type + 1 equals 2. You're constantly polling an I/O port and ANDing it with 2, but this will never be equal to one. If you want to check if a certain bit is set, you should compare it with zero, or just don't excplicitly compare it at all. if does that for you, so I think you need to change this line of code to

Code: Select all

if (ReadPort(0x64) & (type + 1)) return;
If you were to take a look at the code here: viewtopic.php?t=10247 (which I adapted my code from), you would see:

Code: Select all

inline void mouse_wait(byte a_type) //unsigned char
{
  dword _time_out=100000; //unsigned int
  if(a_type==0)
  {
    while(_time_out--) //Data
    {
      if((inportb(0x64) & 1)==1) // <==
      {
        return;
      }
    }
    return;
  }
  else
  {
    while(_time_out--) //Signal
    {
      if((inportb(0x64) & 2)==0) // <==
      {
        return;
      }
    }
    return;
  }
}
When a_type is 0, it checks for bit 1, otherwise it checks for bit 2.
My code for MouseWait does roughly the same thing. The code does not fail, the return indicates it is done waiting, unless it isn't and it reached the timeout, in which case MouseAvailable (which is a bool) is set to false (by default it is true). If I were to remove the timeout, the code would freeze right at that point.

About your second comment, I use IRQ 12 for mouse and IRQ 1 for keyboard.
Hey! I'm developing two operating systems:

NanoShell --- A 32-bit operating system whose GUI takes inspiration from Windows 9x and early UNIX desktop managers.
Boron --- A portable SMP operating system taking inspiration from the design of the Windows NT kernel.
User avatar
portasynthinca3
Posts: 19
Joined: Sun Dec 22, 2019 12:52 pm
Location: Kazan, Russia

Re: PS/2 Mouse Issues

Post by portasynthinca3 »

iProgramInCpp wrote:When a_type is 0, it checks for bit 1, otherwise it checks for bit 2.
Please note that it checks for bit 2 being equal to zero, not one
iProgramInCpp
Member
Member
Posts: 88
Joined: Sun Apr 21, 2019 7:39 am

Re: PS/2 Mouse Issues

Post by iProgramInCpp »

portasynthinca3 wrote:
iProgramInCpp wrote:When a_type is 0, it checks for bit 1, otherwise it checks for bit 2.
Please note that it checks for bit 2 being equal to zero, not one

Ohh thanks! I'll try it out now. Thought I was being slick, but that didn't work.
Hey! I'm developing two operating systems:

NanoShell --- A 32-bit operating system whose GUI takes inspiration from Windows 9x and early UNIX desktop managers.
Boron --- A portable SMP operating system taking inspiration from the design of the Windows NT kernel.
iProgramInCpp
Member
Member
Posts: 88
Joined: Sun Apr 21, 2019 7:39 am

Re: PS/2 Mouse Issues

Post by iProgramInCpp »

Now it fails at line 125, or in my InitMouse function,

Code: Select all

void InitMouse()
{
	puts("[INIT] Initializing Mouse...\n");
	uint8_t _status;
	
	// Enable the auxiliary mouse device.
	MouseWait(1, __LINE__, __LINE__);
	WritePort(0x64, 0xA8);
	
	// Enable the interrupts
	MouseWait(1, __LINE__, __LINE__);
	WritePort(0x64, 0x20);
	MouseWait(0, __LINE__, __LINE__); // <== HERE.
	_status = (ReadPort(0x60) | 2);
	MouseWait(1, __LINE__, __LINE__);
	WritePort(0x64, 0x60);
	MouseWait(1, __LINE__, __LINE__);
	WritePort(0x60, _status);
	
	// Tell the mouse to use default settings
	MouseWrite(0xF6, __LINE__);
	MouseRead(__LINE__);
	
	// Enable data reporting
	MouseWrite(0xF4, __LINE__);
	MouseRead(__LINE__);
	
	// Set up the mouse handler
	WritePort(0x21, INTERRUPT_ENABLE_BITS_0);
	WritePort(0xA1, INTERRUPT_ENABLE_BITS_1);
	
	if (MouseAvailable)
		puts("[INIT] Init finished.\n");
	else
		puts("Mouse failed to initialize.\n");
}
Hey! I'm developing two operating systems:

NanoShell --- A 32-bit operating system whose GUI takes inspiration from Windows 9x and early UNIX desktop managers.
Boron --- A portable SMP operating system taking inspiration from the design of the Windows NT kernel.
User avatar
portasynthinca3
Posts: 19
Joined: Sun Dec 22, 2019 12:52 pm
Location: Kazan, Russia

Re: PS/2 Mouse Issues

Post by portasynthinca3 »

Hmm. Have you just replaced the entire comparison operand (io_port_input_and_an_and == 1 => io_port_input_and_an_and == 0)? Seems fairly strange to me :shock:
iProgramInCpp
Member
Member
Posts: 88
Joined: Sun Apr 21, 2019 7:39 am

Re: PS/2 Mouse Issues

Post by iProgramInCpp »

portasynthinca3 wrote:Hmm. Have you just replaced the entire comparison operand (io_port_input_and_an_and == 1 => io_port_input_and_an_and == 0)? Seems fairly strange to me :shock:
No. I have rewritten the MouseWait function the same way SANiK did it, this time mostly unchanged. Here's the code...

Code: Select all

void MouseWait(uint8_t type, int linenum, int linenum2)
{
	if (!MouseAvailable) return;
	int timeout = 100000; //unsigned int
	
	if (type == 0)
	{
		while (timeout--)
		{
			if ((ReadPort(0x64) & 1) == 1) return;
		}
	}
	else
	{
		while (timeout--)
		{
			if ((ReadPort(0x64) & 2) == 0) return;
		}
	}
	//MouseAvailable = false;
	printf("Mouse timeout reached, guessed that the mouse is unavailable. (failed at %d or %d)\n", linenum, linenum2);
	return;
}
Hey! I'm developing two operating systems:

NanoShell --- A 32-bit operating system whose GUI takes inspiration from Windows 9x and early UNIX desktop managers.
Boron --- A portable SMP operating system taking inspiration from the design of the Windows NT kernel.
User avatar
portasynthinca3
Posts: 19
Joined: Sun Dec 22, 2019 12:52 pm
Location: Kazan, Russia

Re: PS/2 Mouse Issues

Post by portasynthinca3 »

I think that the issue may be caused by your timeout loop. You're waiting 100000 iterations to wait for data to come. That might delay for several seconds on older CPUs, but just several milliseconds on newer CPUs. In my driver implementation I don't have any timeout at all. Yes, that's kind of janky, but it allows me to cope with this issue while I didn't fully implement timer drivers.
iProgramInCpp
Member
Member
Posts: 88
Joined: Sun Apr 21, 2019 7:39 am

Re: PS/2 Mouse Issues

Post by iProgramInCpp »

portasynthinca3 wrote:I think that the issue may be caused by your timeout loop. You're waiting 100000 iterations to wait for data to come. That might delay for several seconds on older CPUs, but just several milliseconds on newer CPUs. In my driver implementation I don't have any timeout at all. Yes, that's kind of janky, but it allows me to cope with this issue while I didn't fully implement timer drivers.
Interesting. I have some sort of "timing" on the PIT, so maybe I can replace the timeout with something based on that. What do you think?
Hey! I'm developing two operating systems:

NanoShell --- A 32-bit operating system whose GUI takes inspiration from Windows 9x and early UNIX desktop managers.
Boron --- A portable SMP operating system taking inspiration from the design of the Windows NT kernel.
User avatar
portasynthinca3
Posts: 19
Joined: Sun Dec 22, 2019 12:52 pm
Location: Kazan, Russia

Re: PS/2 Mouse Issues

Post by portasynthinca3 »

Sounds reasonable to me!
iProgramInCpp
Member
Member
Posts: 88
Joined: Sun Apr 21, 2019 7:39 am

Re: PS/2 Mouse Issues

Post by iProgramInCpp »

Alright, so I tried doing this with the global time. Even after I wait approximately 5 seconds (My PIT timing system is not THAT precise) it still fails to do anything at that exact line. Even if I don't use a timeout at all, it still fails. I'm using QEMU to test right now, will test with other emulators later.
Hey! I'm developing two operating systems:

NanoShell --- A 32-bit operating system whose GUI takes inspiration from Windows 9x and early UNIX desktop managers.
Boron --- A portable SMP operating system taking inspiration from the design of the Windows NT kernel.
Octocontrabass
Member
Member
Posts: 6283
Joined: Mon Mar 25, 2013 7:01 pm

Re: PS/2 Mouse Issues

Post by Octocontrabass »

iProgramInCpp wrote:This is an adaptation of http://forum.osdev.org/viewtopic.php?t=10247 without the handler part (I'll add that later when I get interrupts properly).
I don't think that's a good example to copy from. The PS/2 ports are both attached to a single controller, so your mouse and keyboard drivers may step on each other if you haven't properly separated the "PS/2 controller" functionality from the "devices attached to the PS/2 controller" functionality. In fact, this may be the cause of your current troubles: when the keyboard controller places its response to your command 0x20 in its buffer, it typically also raises IRQ1. Your keyboard driver might receive this IRQ1 and empty the buffer before your mouse driver has a chance to see it.

Personally, I'd recommend having a separate driver for the PS/2 controller itself, and have the mouse and keyboard drivers communicate through the shared PS/2 controller driver. You could then treat the PS/2 controller like the pair of generic serial ports that it really is, and allow any PS/2 device to be connected to either port.

You may also need to look out for firmware emulating a PS/2 controller for USB keyboards. This firmware emulation is terrible and often won't allow you to do basic things like turn off translation on the keyboard port. Fortunately, most firmware will get out of your way once you have USB drivers. (But pay attention to the ACPI FADT: there may not be a PS/2 controller at all once you've bypassed the emulation.)

When you're using the legacy PIC, you must enable IRQ2 in order to receive IRQ12.
iProgramInCpp
Member
Member
Posts: 88
Joined: Sun Apr 21, 2019 7:39 am

Re: PS/2 Mouse Issues

Post by iProgramInCpp »

Octocontrabass wrote:
iProgramInCpp wrote:This is an adaptation of http://forum.osdev.org/viewtopic.php?t=10247 without the handler part (I'll add that later when I get interrupts properly).
I don't think that's a good example to copy from. The PS/2 ports are both attached to a single controller, so your mouse and keyboard drivers may step on each other if you haven't properly separated the "PS/2 controller" functionality from the "devices attached to the PS/2 controller" functionality. In fact, this may be the cause of your current troubles: when the keyboard controller places its response to your command 0x20 in its buffer, it typically also raises IRQ1. Your keyboard driver might receive this IRQ1 and empty the buffer before your mouse driver has a chance to see it.

Personally, I'd recommend having a separate driver for the PS/2 controller itself, and have the mouse and keyboard drivers communicate through the shared PS/2 controller driver. You could then treat the PS/2 controller like the pair of generic serial ports that it really is, and allow any PS/2 device to be connected to either port.

You may also need to look out for firmware emulating a PS/2 controller for USB keyboards. This firmware emulation is terrible and often won't allow you to do basic things like turn off translation on the keyboard port. Fortunately, most firmware will get out of your way once you have USB drivers. (But pay attention to the ACPI FADT: there may not be a PS/2 controller at all once you've bypassed the emulation.)

When you're using the legacy PIC, you must enable IRQ2 in order to receive IRQ12.
How would I go about moving the PS/2 keyboard handler to common PS/2 controller and separate devices?

Oh and I'm talking about initialization not interrupt handling.
Hey! I'm developing two operating systems:

NanoShell --- A 32-bit operating system whose GUI takes inspiration from Windows 9x and early UNIX desktop managers.
Boron --- A portable SMP operating system taking inspiration from the design of the Windows NT kernel.
iProgramInCpp
Member
Member
Posts: 88
Joined: Sun Apr 21, 2019 7:39 am

Re: PS/2 Mouse Issues

Post by iProgramInCpp »

any ideas on how to fix?
Hey! I'm developing two operating systems:

NanoShell --- A 32-bit operating system whose GUI takes inspiration from Windows 9x and early UNIX desktop managers.
Boron --- A portable SMP operating system taking inspiration from the design of the Windows NT kernel.
Post Reply