Mouse & Timing

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.
purevoid

Mouse & Timing

Post by purevoid »

Hi,

I have a very obscure bug affecting my mouse driver that seems only reproducible on select hardware, and I'm lost as to how to fix it.

My interrupt handler uses a simple loop that reads in data when bits 1 & 5 of the status port are both 1. Initially, I was just testing bit 5, but seemed to break it on my nforce2-based system.

My friend has a similar system, who told me about the problem, and testing for bit 1 fixed it for him, but still remains for me.

It works for a little while, but if the system gets loaded a little, the sync seems to get out of whack. I don't know how to figure out if it's occurred, so I can somehow rectify it. Even better still would be avoiding this problem occuring at all...
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Mouse & Timing

Post by Pype.Clicker »

i'd suggest you read only one byte per mouse IRQ ... this will be safe even when data from the keyboard and the mouse are available together.
purevoid

Re:Mouse & Timing

Post by purevoid »

I tried reading one byte per interrupt, but it didn't seem to like that. For instance, pressing a mouse button down should generate a complete 3-byte packet. However, the interrupt fired only once, generating a single byte. So in order to even register the user pressing the button would require some other mouse event to complete the 3-byte packet for processing.

I'm not sure if this behaviour occured on all systems, but certainly on the test system giving the odd behaviour with my current implementation.

My driver works on four diff emulators, and my P-III system, so I dunno what exactly is wrong =(

Does someone have a working mouse driver I could look at? Especially with a bootable image to test on this machine? Or point to a good tutorial that illustrates the exact steps to initialize a standard PS/2 mouse (no extensions or anything), and reading data from it correctly?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Mouse & Timing

Post by Pype.Clicker »

purevoid wrote: I tried reading one byte per interrupt, but it didn't seem to like that. For instance, pressing a mouse button down should generate a complete 3-byte packet.
Indeed, the mouse will generate a 3-bytes packet, but then the packet is sent byte-per-byte to the PC on a serial line. The 8042 will raise an interrupt as soon as the first byte has arrived, so you cannot assume the whole 3-bytes are here.

I suggest you get a look at SANik's driver ...
purevoid

Re:Mouse & Timing

Post by purevoid »

SANiKs driver doesn't have much comments =( Especially in the installing part. It doesn't say what it's actually doing .. just a basic overview. Commenting each line to say what's being done and why would be helpful...

And if I only read one byte, why don't I get another interrupt for the remaining two bytes?

My OS is interrupt driven at the moment. No scheduler, no separate processes, no memory protection or anything.

What happens is during the mouse interrupt, it does whatever it has to once it's read a 3-byte packet. In my case, it processes the mouse event data and updates the GUI as a result, so my interrupt handler doesn't always return very quickly.... such as during an entire screen redraw.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Mouse & Timing

Post by Pype.Clicker »

hm. That may explain some of your trouble: if *one* mouse interrupt is received while redrawing occurs (in the mouse handler), everything should be fine (e.g. the pending interrupt will be kept by the PIC), but if *two* are received, you're in trouble since the PIC cannot remember a second interrupt has been raised.

Imho, you should try to find a way to extract the 'GUI redraw" logic from your handlers. E.g.

Code: Select all

  while (1) {
     asm ("hlt"); // wait for an interrupt
     processMouseEvent();
     if (redraw_request) redraw_gui();
  }
SANiK

Re:Mouse & Timing

Post by SANiK »

purevoid, didn't you say my mouse driver worked on your nforce system?
I didn't think the loop was that hard... do note you need to send an EOI command. (I don't have it in my code cause it's part of the ISR switching routine)
purevoid

Re:Mouse & Timing

Post by purevoid »

I did. But I don't understand the init code.

Also, it's responsiveness is limited, so I can't be certain. As mine works at first until it has to do some work (in my case, a full screen redraw).
purevoid

Re:Mouse & Timing

Post by purevoid »

Even if two interrupts are received during the redraw, isn't the same amount of data available when I process the one pending interrupt (while other is lost), since I currently read all available data?

And on the unloaded system when I was reading just one byte per interrupt, I never received the whole packet.

I guess adding an event queue to separate the interrupts from the GUI would help a little, but it feels like it is shadowing the problem rather than dealing to it. I don't want to have to see this same problem crop up again simply because I changed the behaviour of my OS to hide the real problem.

Also, with the hlt instruction, does that simply make the CPU do nothing for one instruction? Or does the CPU stay halted until an interrupt fires? In which case, the interrupt handler would get processed, then my loop 'woken up' right?
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Mouse & Timing

Post by Pype.Clicker »

hlt's behaviour is the second one. "Halt until an interrupt is received". "Do nothing for one cycle" is "NOP" ...

The problem (imho) may arise when 8042 still has things to deliver, but not for the mouse. Let's take the following example :

- a mouse byte is received by 8042, IRQ raised
- your mouse handler is called
- a keyboard byte is received by 8042, which waits for mouse byte to be read
- your mouse handler successfully extracts one mouse byte

now the 8042 has a pending keyboard byte and your code is in mouse handler, waiting for more mouse byte to come ...

i'm not 100% certain that's what's going wrong, but even Mobius does read it "one byte a time"

Code: Select all

bool ps2Isr(device_t *dev, uint8_t irq)
{
    if ((in(KEYB_CTRL) & 0x01) != 0)
    {
   Ps2Mouse *mouse;
        mouse = (Ps2Mouse*) dev;
        mouse->data[mouse->bytes++] = in(KEYB_PORT);
   if (mouse->bytes >= 3 + mouse->has_wheel)
   {
       ps2StartIo(mouse);
       mouse->bytes = 0;
   }
   
   return true;
    }

    return false;
}
purevoid

Re:Mouse & Timing

Post by purevoid »

Okay, I tried doing byte-by-byte again. Still with doing a full-screen redraw in particular cases on a mouse event called from the interrupt handler. And same behaviour as before.

I tried in console mode too, holding down a key until the mouse packets started getting mucked up. Now holding down a key and moving the mouse isn't a great deal of work, yet my problem still remains. BTW, the keyboard only reads byte-by-byte already.

Now, I should do an event queue to separate the interrupt handler from the GUI... but even in console mode, when all it does is print a status line reflecting X,Y, and button status on a full packet received, it can still get out of sync.

My sources are online if that may help... they're in OCaml, but shouldn't be too hard to figure out.

http://glek.net/subversion/os/kernel/modules/ with the files of interest being PS2.ml (my init code etc), and Mouse.ml (which reads in the data and decides if a packet has arrived).

I really want to get rid of this stupid problem soon as, so I can focus on redoing my GUI code... Only thing I can think of is that my init code should be different or something. I am totally lost =(
purevoid

Re:Mouse & Timing

Post by purevoid »

Okay, I've got it reading a single byte per interrupt. I do minimal work in processing of a packet (get dx/dy/buttons pressed), and put into event queue (I currently cli/sti around anything manipulating this queue at the moment). It does nothing else, so is seemingly quite simple.

Now I've moved processing this event data into a separate loop, like you showed, and only wakes up to try do some processing after an interrupt wakes up the hlt.

The GUI is updated from this loop, so one would expect interrupts to be processed quickly, and the slower GUI redraw to be done outside of interrupt handling.

However, I still have the SAME behaviour! =( Do some CPU intensive work, and the mouse bytes get out of sync...

I have to be doing something fundamentally wrong =(

Can you point me to an OS that has a mouse working in a gui, that can also drag around windows (something relatively CPU intensive compared to simply moving cursor), which has both a compiled binary I can make a bootable floppy out of and source code to compare to my mouse driver?

I NEED to know whether this affects other OS too. If so, I'll switch to a polling mouse driver, cause I'm running out of ideas with what's wrong. Odds of someone discovering what's wrong seem to drop daily.... =(
SANiK

Re:Mouse & Timing

Post by SANiK »

The seperate loops that draws the mouse and stuff, it needs to be updated 60 times every second, and set the current DELTA mouse values to 0, 0.

If you fail to do so, the mouse will look like it doesn't even work.
purevoid

Re:Mouse & Timing

Post by purevoid »

Huh? Deltas? And why so quickly? It's worked before on all other hardware and VMs.
purevoid

Re:Mouse & Timing

Post by purevoid »

I integrated SANiKs C mouse-driver into my code. The only changes were registering the IRQ handler, and to call into OCaml to do something with the mouse data.

Basically, all it does is tell OCaml dx, dy, and whether left button is pressed (so I can do dragging of window). Fairly lightweight. This is put on the end of an event queue.

Another separate loop does event queue processing (like before). Updates the GUI and all. And STILL the same buggy mouse problems as before.

Is polling going to be the only way to create a proper mouse driver? Sure, it's just one machine that this happens on so far, but there could be more. And having a properly working mouse is very important =(
Post Reply