Mouse driver tutorial by houbysoft, contact here
-----------------------------------------------------------------




License:
ABSOLUTELY NO WARRANTY. Distribute freely, but do not modify without my permission. If you found something that is not right, a bug etc., feel free to email me.
Special thx:
SANiK for his ps/2 mouse code! As you will see, this tutorial in fact is just SANiK's code, but a little more explained to make thing clearer.

This is my first tutorial, so I know it may not be ideal, so I repeat that if you found anything that's not right, please email me. Let's start now.

In contrast to what you may think, writing a simple PS/2 mouse driver is not that hard. The first thing you need to do if you want to use your mouse is to initialize it.

1 - Mouse initialization
When you boot up your PC, the mouse is usually disabled, and data coming from it will not generate any interrupts. Because you want to use it, you must enable it. The first thing to do is to enable the auxiliary mouse device. This is done by sending the 0xA8 command to port 0x64. In C, this would look something like this

mouse_wait(1);
outportb(0x64,0xA8);

Note the mouse_wait() call. This just is a function that will wait for the mouse to be able to receive/send commands/data. Don't worry about it, because we will define it later.
After you have enabled the auxiliary mouse device, you must modify the "compaq status byte", to enable the interrupt. First you must get it, which is done by sending the 0x20 command to the 0x64 port:

mouse_wait(1);
outportb(0x64,0x20);

... and receiving your status byte at port 0x60 (yes, 0x60, not 0x64). Note that because you have to modify the status byte, and send it back, you should store it somewhere, so the code for getting the byte would look like this :

unsigned char status_byte;
mouse_wait(0);
status_byte = (inportb(0x60) | 2);
.
You have probably notified that "| 2" thing. This sets the bit number 1 (value = 2), which is the bit that is responsible for enabling the IRQ12. When your status byte is prepared, you obviously need to send it back to the controller. This task is done by first telling the controller that we will be sending a status byte, which is done by command 0x60 :

mouse_wait(1);
outportb(0x64, 0x60);
, and then we need to send the modified status byte to port 0x60 :

mouse_wait(1);
outportb(0x60, status_byte);
. We are almost at the end of the initialization. Next comes setting up the mouse, and, finally, enabling it. For the settings part, we will just tell the mouse to use default settings. The command that does this is 0xF6. But, to keep all this stuff complicated, we must first tell the mouse that we are sending a command. We won't care about this for now, so we will just use a function that we will write later. So we will tell the mouse to use default settings :

mouse_write(0xF6);
mouse_read();
. Note the mouse_read part; you must wait for the mouse to accept your command. This again is a function that we will define later. Now, the last part is to enable the mouse, which is done by sending the mouse the 0xF4 command :

mouse_write(0xF4);
mouse_read();
. Your mouse is now enabled! But wait, we must somewhat get the data that it is sending to us. That means to set up a IRQ 12 handler :

irq_install_handler(12, mouse_handler);
.
Finally, done! Now our mouse is enabled and will send data when you will move it, or click any of its buttons. The next part is defining the mouse_wait, read and write functions, that we were using without actually writing them.

2 - Mouse functions
The mouse_wait function is really simple, and all it does is that it waits for the mouse to be able to send or receive data, or for the timeout to pass. Its only argument, type, defines if we will be waiting to write a command (type = 1), or to receive a command (type = 0).

Code (on pastebin)
. I think that this is so simple it doesn't need any explanation. The next function that we must define is mouse_write(). This function is designed to simplify the process of sending commands to the mouse. All it does is wait to be able to send a command (using mouse_wait), then tell the mouse that we are sending a command, which is done by sending 0xD4 to the mouse (port 0x64), then wait again, and finally send the command. Implementation in C would be

void mouse_write(unsigned char a_write)
{
//Wait to be able to send a command
mouse_wait(1);
//Tell the mouse we are sending a command
outportb(0x64, 0xD4);
//Wait for the final part
mouse_wait(1);
//Finally write
outportb(0x60, a_write);
}
. Now, the last function that we will use is mouse_read. This function waits to be able to read data from the mouse, and then returns it to the caller.

unsigned char mouse_read()
{
//Get response from mouse
mouse_wait(0);
return inportb(0x60);
}
. This is all! Now comes the function that will handle the mouse IRQ.

3 - Mouse handler
Now, when our mouse is enabled, we just need to use the data it gives us. The mouse sends 3-bytes packets, the first byte being essentially flags, the second the x delta and the last, third byte is the y delta. NOTE THAT IT WILL TAKE THREE IRQs FOR YOU TO HAVE ALL THE BYTES, because the mouse can send just one byte at a time. I will write a sample mouse handler here, but from now, it is all up to you how you will use your mouse. My mouse handler just outputs a string telling you that one of the mouse's buttons were pressed. Feel free to adapt it exactly to your needs.

Code (on pastebin)
.

4 - Let's put it all together!
To finish your driver, you just need to put all the initialization stuff in a function, for example mouse_install, and call it when your kernel will start. Good luck! Any questions, comments, etc., please email me at dlabaljan at gmail dot com, or use info from my contact page.

Back to houbysoft