Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Viktor Engelmann authored and Viktor Engelmann committed Jul 4, 2016
1 parent a2f1cad commit 48959b0
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 2 deletions.
3 changes: 2 additions & 1 deletion kernel.cpp
Expand Up @@ -3,7 +3,7 @@
#include "gdt.h"
#include "interrupts.h"
#include "keyboard.h"

#include "mouse.h"

void printf(char* str)
{
Expand Down Expand Up @@ -62,6 +62,7 @@ extern "C" void kernelMain(const void* multiboot_structure, uint32_t /*multiboot
GlobalDescriptorTable gdt;
InterruptManager interrupts(0x20, &gdt);
KeyboardDriver keyboard(&interrupts);
MouseDriver mouse(&interrupts);
interrupts.Activate();

while(1);
Expand Down
2 changes: 1 addition & 1 deletion makefile
Expand Up @@ -6,7 +6,7 @@ GCCPARAMS = -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-excep
ASPARAMS = --32
LDPARAMS = -melf_i386

objects = loader.o gdt.o port.o interruptstubs.o interrupts.o keyboard.o kernel.o
objects = loader.o gdt.o port.o interruptstubs.o interrupts.o keyboard.o mouse.o kernel.o


run: mykernel.iso
Expand Down
78 changes: 78 additions & 0 deletions mouse.cpp
@@ -0,0 +1,78 @@

This comment has been minimized.

Copy link
@amr98khaled

amr98khaled Jan 26, 2021

The mouse itself and the sending of the IRQ12 must first be activated by the keyboard controller. The keyboard controller can be addressed via ports 0x60 and 0x64. Port 0x60 serves as a data buffer, port 0x64 as status and command register:

Reading 0x60 : supplies the content of the output buffer.
Writing 0x60 : after sending command 0x60 to commandport 0x64, data is written into the input buffer.
Reading 0x64 supplies the status byte of the keyboard controller.
Writing to 0x64 sends a command to the keyboard controller.

Status Register :
-Bit 0 : (clear=0){There is no data in the output buffer.} , (set=1){There is data in the output buffer, reading from port 0x60 is therefore permitted.}
-Bit 1 : (clear=0){The input buffer is empty. Commands may be sent via ports 0x60 and 0x64.} , (set=1){There is still data in the input buffer. The keyboard controller is currently not accepting any commands.}

Commands to the keyboard controller:
0xA8 | Activate mouse
0xA7 | Deactivate mouse
0x20 | Read command byte
0x60 | Write command byte
0xD4 | send the next command to the mouse instead of the keyboard

After 0xD4 is sent to the keyboard controller, it forwards the following commands to the mouse instead of the keyboard , these commands are written to the dataport 0x60:
0xF4 | Tell the mouse to send data to the CPU , Enable Packet streaming when mouse is moved or clicked .
0xF5 | Tell the mouse not to send any data to the CPU
0xF6 | Reset mouse settings to default settings
-The mouse responds to all of these commands by placing the value 0xFA (called ACK - Acknowledge) in the output buffer . In the following code the ACK byte is not checked .

-To read the command byte you first have to send the command 0x20 to the keyboard controller, whereupon the keyboard controller places the byte in the output buffer (dataport 0x60).
-To write the command byte, you must first send the command 0x60 to the keyboard controller and then place the command byte in the input buffer(dataport 0x60).

-All output to port 0x60 or 0x64 must be preceded by waiting for bit 1 (value=2) of port 0x64 to become clear. Similarly, bytes cannot be read from port 0x60 until bit 0 (value=1) of port 0x64 is set.

-Sending a command or data byte to the mouse (to port 0x60) must be preceded by sending a 0xD4 byte to port 0x64 (with appropriate waits on port 0x64, bit 1, before sending each output byte). Note: this 0xD4 byte does not generate any ACK, from either the keyboard or mouse.

-It is required to wait until the mouse sends back the 0xFA acknowledgement byte after each command or data byte before sending the next byte (Note: reset commands might not be ACK'ed -- wait for the 0xAA after a reset). A few commands require an additional data byte, and both bytes will generate an ACK.

#include "mouse.h"

MouseDriver::MouseDriver(InterruptManager* manager)
: InterruptHandler(manager, 0x2C),
dataport(0x60),
commandport(0x64)
{
uint16_t* VideoMemory = (uint16_t*)0xb8000;
offset = 0;
buttons = 0;
x = 40;
y = 12;

This comment has been minimized.

Copy link
@amr98khaled

amr98khaled Jan 28, 2021

The mouse cursor is set initially at the center of the screen .

VideoMemory[80*y+x] = (VideoMemory[80*y+x] & 0x0F00) << 4
| (VideoMemory[80*y+x] & 0xF000) >> 4
| (VideoMemory[80*y+x] & 0x00FF);

This comment has been minimized.

Copy link
@amr98khaled

amr98khaled Jan 28, 2021

Wherever the cursor points , swap the foreground and background colors of that char .


This comment has been minimized.

Copy link
@amr98khaled

amr98khaled Jan 27, 2021

We are supposed to empty the data buffer first like we did with the keyboard
while (inb (0x64) & 0x01) { inb (0x60); }

commandport.Write(0xA8);
commandport.Write(0x20); // command 0x60 = read controller command byte
uint8_t status = dataport.Read() | 2;

This comment has been minimized.

Copy link
@amr98khaled

amr98khaled Jan 27, 2021

Setting Bit 1 : Enables IRQ12 , Activates the activation of IRQ12 if mouse data, such as the MouseDataPacket, are present in the buffer.
On some systems you also have to clear bit number 5 (value=0x20, Disable Mouse Clock) .

commandport.Write(0x60); // command 0x60 = set controller command byte
dataport.Write(status);

commandport.Write(0xD4);
dataport.Write(0xF4);
dataport.Read();
}

MouseDriver::~MouseDriver()
{
}

uint32_t MouseDriver::HandleInterrupt(uint32_t esp)
{
uint8_t status = commandport.Read();

This comment has been minimized.

Copy link
@amr98khaled

amr98khaled Jan 27, 2021

In that status byte from commandport 0x64, bit number 5 (value=0x20), indicates that this next byte came from the mouse, if the bit is set.

if (!(status & 0x20))
return esp;

buffer[offset] = dataport.Read();
offset = (offset + 1) % 3;

if(offset == 0)
{
if(buffer[1] != 0 || buffer[2] != 0)
{
static uint16_t* VideoMemory = (uint16_t*)0xb8000;
VideoMemory[80*y+x] = (VideoMemory[80*y+x] & 0x0F00) << 4
| (VideoMemory[80*y+x] & 0xF000) >> 4
| (VideoMemory[80*y+x] & 0x00FF);

x += buffer[1];
if(x >= 80) x = 79;
if(x < 0) x = 0;
y -= buffer[2];

This comment has been minimized.

Copy link
@amr98khaled

amr98khaled Jan 27, 2021

We make y -= buffer[2] because "delta Y", with down (toward the user) being negative. So if we move the mouse down we are actually increasing with respect to the video memory , so we subtract so that we get a +ve increase in video memory address.

This comment has been minimized.

Copy link
@AraHaan

AraHaan Jan 27, 2021

Could all of those above be the reason why my laptop's built in mouse pad does not work with my OS using this mouse code even within virtualbox?

if(y >= 25) y = 24;
if(y < 0) y = 0;

VideoMemory[80*y+x] = (VideoMemory[80*y+x] & 0x0F00) << 4
| (VideoMemory[80*y+x] & 0xF000) >> 4
| (VideoMemory[80*y+x] & 0x00FF);
}

/*
for(uint8_t i = 0; i < 3; i++)
{
if((buffer[0] & (0x1<<i)) != (buttons & (0x1<<i)))
{
if(buttons & (0x1<<i))
handler->OnMouseButtonReleased(i+1);
else
handler->OnMouseButtonPressed(i+1);
}
}
buttons = buffer[0];
*/
}
return esp;
}
24 changes: 24 additions & 0 deletions mouse.h
@@ -0,0 +1,24 @@

#ifndef __MOUSE_H
#define __MOUSE_H

#include "types.h"
#include "port.h"
#include "interrupts.h"

class MouseDriver : public InterruptHandler
{
Port8Bit dataport;
Port8Bit commandport;
uint8_t buffer[3];

This comment has been minimized.

Copy link
@amr98khaled

amr98khaled Jan 27, 2021

Byte 1 : Y overflow | X overflow | Y sign bit | X sign bit | Reserved (1) | Middle button pressed | Right button pressed | Left button pressed
Byte 2 : X Movement since the last data packet. "delta X" value -- that is, it measures horizontal mouse movement, with left being negative.
Byte 3 : Y Movement since the last data packet, "delta Y", with down (toward the user) being negative.

  • The mouse triggers 3 interrupts , one for each byte .
uint8_t offset;
uint8_t buttons;

int8_t x, y;
public:
MouseDriver(InterruptManager* manager);
~MouseDriver();
virtual uint32_t HandleInterrupt(uint32_t esp);
};

#endif

4 comments on commit 48959b0

@AraHaan
Copy link

@AraHaan AraHaan commented on 48959b0 Sep 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mouse driver does not work with the one built-in to my laptop. @AlgorithMan-de
image

@johndemlon
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use virtaul box and click on the screen

@AraHaan
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was, just the mouse on it would not work for some reason. Also I wish I could figure out touch screen support too. I plan to make a gui interface that allows touch input somehow and get what the touch does and respond the same way Windows does to touch.

@sytzemeijer
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot type when I run this in qemu

Please sign in to comment.