Mouse movement data packets... [SOLVED]

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.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Mouse movement data packets... [SOLVED]

Post by pcmattman »

I'm trying to get the mouse working in my OS, but it's not reading correctly. In a typcial run, the movement counters get mixed with the status byte... so instead of the status being the status, it might be the y movement byte. I have no idea how to check whether or not the bytes are coming in the right order, or how to order them properly. Any ideas?
Last edited by pcmattman on Fri Mar 09, 2007 2:58 am, edited 1 time in total.
grunge_asm
Posts: 6
Joined: Sun Feb 25, 2007 5:16 pm

Post by grunge_asm »

http://www.programmersheaven.com/downlo ... nload.aspx

I find it in my developement/research of mouse driver.... this source reads the bytes (separated)... I have suspect that it is my same problem... do you remember???

grunge
User avatar
bubach
Member
Member
Posts: 1223
Joined: Sat Oct 23, 2004 11:00 pm
Location: Sweden
Contact:

Post by bubach »

have you looked at this:
http://bos.asmhackers.net/docs/mouse/sn ... /mouse.inc

sanik's donated source. i might have other info in those folders too.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

No, it's not helping. The problem is that the bytes are being read in the wrong order sometimes... Is there any way to avoid this, because it's this mixing that causes the problems.
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

What are the sources, or at least the algorithm you are using to gather them? The best approach would be to read 1 at a time and return from the ISR and then the next, and the next. You should store them in a byte array for when you are done.

Remember that for standard PS/2 mouse you will gather 3 bytes per single movement packet, and IF YOU HAVE MOUSE WHEEL ENABLED, you will gather 4 bytes per single movement packet.


------------------------------
NOTE: Read this:

http://www.osdev.org/phpBB2/viewtopic.p ... ght=#90326

--------------------------------
It might help you since it directly relates to both mouse and keyboard since they communicate using the same ports and the same circuitry.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

I do that, when the mouse data needs to be read, the bytes are read one at a time. The problem is that if the mouse is moved too fast, often the y-movement information gets mixed into the status code, and after this the mouse never recovers and always gives mixed information.

Mouse driver:

Code: Select all

#include "sys/mattise.h"
#include "sys/kernel.h"
#include "sys/ps2.h"
#include "sys/kstdio.h"

// commands for PS2
#define ENABLE_PS2	0xA8
#define KBD_STAT	0x64
#define MOUSE		0xD4
#define MOUSE_STREAM	0xF4
#define MOUSE_DISABLE	0xF5
#define KBD_CMD		0x60
#define DISABLE_KBD	0xAD
#define ENABLE_KBD	0xAE

// checks the port
void CheckPort()
{
	unsigned char temp;
	while( true )
	{
		temp = inportb( KBD_STAT );
		if( (  temp & 2 ) == 0 )
			break;
	}
}

// set the ps2 bytes
void PS2Set()
{
	outportb( KBD_STAT, ENABLE_PS2 );
	CheckPort();
}

// waits for the mouse
void WaitMouse()
{
	outportb( KBD_STAT, MOUSE );
	CheckPort();
}

// waits for the ouse buffer to be full
void MouseBufferFull()
{
	unsigned char temp;
	while( true )
	{
		temp = inportb( KBD_STAT );
		if( (  temp & 0x20 ) == 0 )
			break;
	}
}

// checks the mouse
char CheckMouse()
{
	unsigned char temp;
	temp = inportb( KBD_STAT );

	if( temp & 1 )
		return 0;
	else
		return 1;
}

// sets the streaming mode
void StartStream()
{
	WaitMouse();
	outportb( KBD_CMD, MOUSE_STREAM );
	CheckPort();
	CheckMouse();
}

// disables the keyboard
void DisableKeyboard()
{
	outportb( KBD_STAT, DISABLE_KBD );
	CheckPort();
}

// enables the keyboard
void EnableKeyboard()
{
	outportb( KBD_STAT, ENABLE_KBD );
	CheckPort();
}

void MouseWait( char thetype )
{
	long timeout = 100000;
	if( thetype == 0 )
	{
		while( timeout-- )
		{
			if( inportb( 0x64 ) & 1 )
			{
				return;
			}
		}
		return;
	}
	if( thetype == 1 )
	{
		while( timeout-- )
		{
			if( ( inportb( 0x64 ) & 2 ) == 0 )
			{
				return;
			}
		}
		return;
	}
}

// get a byte from the port
char GetByte()
{
	DisableKeyboard();

	char ret = 1;

	while( ret )
		ret = CheckMouse();

	MouseWait( 0 );
	ret = inportb( 0x60 );
	EnableKeyboard();

	return ret;
}

// get data from the mouse
void GetMouseData( MOUSEDATA* data )
{
	// wait for the buffer to be full
	// MouseBufferFull();

	// get the data
	data->status = GetByte();
	data->xcoord = GetByte();
	data->ycoord = GetByte();
}

// init the mouse
void InitMouse()
{
	kputs( "Initializing PS2 mouse..." );
	PS2Set();
	StartStream();
}
Header:

Code: Select all

#include "mattise.h"

#ifndef PS2_H
#define PS2_H

/** PS2 **/

typedef struct tagMOUSEDATA
{ 
	char status; 
	char xcoord; 
	char ycoord; 
} MOUSEDATA;

// init the mouse
void InitMouse();

// get data from the mouse
void GetMouseData( MOUSEDATA* data );

/** END PS2 **/

#endif
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

Yes, the "GetMouseData( MOUSEDATA* data )" routine is supposed to be called by the IRQ as an interrupt (hope it's accurate), which in turn calls the "GetByte()" routine.

Note that this "GetByte()" routine has many things that make it TERRYBLY and DEADLY slow from the point of view of mouse speed:

Code: Select all

// get a byte from the port 
char GetByte() 
{ 
   DisableKeyboard();   //This is BAD (slow)

   char ret = 1;

   while( ret )                        //BAD (obsolete)
      ret = CheckMouse();       //BAD (obsolete)

   MouseWait( 0 );               //BAD (slow)
   ret = inportb( 0x60 );       //The only RELIABLE thing around here
   EnableKeyboard();          //This is BAD (slow)

   return ret;         //Here we return 1 byte
} 


Note that when I refer to 1 byte at a time I refer to something like this:

Code: Select all

char off=0;

void GetMouseData( MOUSEDATA* data ) 
{ 
   // get the data 
   (off==0)?(data->status = GetByte();off++;return;):(0);
   (off==1)?(data->xcoord = GetByte();off++;return;):(0); 
   (off==2)?(data->ycoord = GetByte();off++;return;):(0);

   if(off==3)
   {
    //Reset buffer:
      off=0;

    //Do some processing:
    ///////////
    ///////////
    ///////////
    ///////////
   }

 //Acknowledge IRQ by PIC:
 //
} 
As you can see, with this code we will only read ONE BYTE BY INTERRUPT TRIGGER. So, our mouse will trigger 3 times for each of the bytes of 1 standard packet and only after that we will make our final interpretation. The other things, if you do them, will give you big trouble as you have already seen by yourself, even when they look appropiate in practice. Things like disabling keyboard is not necessary since it will have its chance to automatically report its data bytes through its own IRQ handler, and it's better not to delay that not a bit because it will eventually cause the buffers, specially the mouse one, being the fastest one, and probably the keyboard's, to start becoming full and losing bytes which will cause everything to start going crazy.

By the way, i am not expecting the rapid pseudocode above to be bug-free, but to give the ideas.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

Thanks for that, I didn't realize I could use an ISR to handle the bytes. This should make my life much easier now, means I can spend more time actually implementing the graphical stuff instead of trying to figure out why the mouse is moving erratically.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

The mouse IRQ is not firing... Any ideas?

Code for new driver:

Code: Select all

#include "sys/mattise.h"
#include "sys/kernel.h"
#include "sys/ps2.h"
#include "sys/kstdio.h"

// commands for PS2
#define ENABLE_PS2	0xA8
#define KBD_STAT	0x64
#define MOUSE		0xD4
#define MOUSE_STREAM	0xF4
#define MOUSE_DISABLE	0xF5
#define KBD_CMD		0x60
#define DISABLE_KBD	0xAD
#define ENABLE_KBD	0xAE

// checks the port
void CheckPort()
{
	unsigned char temp;
	while( true )
	{
		temp = inportb( KBD_STAT );
		if( (  temp & 2 ) == 0 )
			break;
	}
}

// waits for the ouse buffer to be full
void MouseBufferFull()
{
	unsigned char temp;
	while( true )
	{
		temp = inportb( KBD_STAT );
		if( (  temp & 0x20 ) == 0 )
			break;
	}
}

// checks the mouse
char CheckMouse()
{
	unsigned char temp;
	temp = inportb( KBD_STAT );

	if( temp & 1 )
		return 0;
	else
		return 1;
}

// writes to the keyboard
void WriteKeyboard( unsigned char val )
{
	unsigned int n;

	n = 0xFFFF;
	while( n-- )
	{
		if( inportb( 0x64 ) & 2 == 0 )
		{
			n = 1;
			break;
		}
	}

	if( !n ) return;

	outportb( 0x60, val );

	n = 0xFFFF;
	while( n-- )
	{
		if( inportb( 0x64 ) & 2 == 0 )
		{
			n = 1;
			break;
		}
	}
}

unsigned char ReadKeyboard()
{
	unsigned char res;
	unsigned int n;

	n = 0xFFFF;
	while( n-- )
	{
		if( inportb( 0x64 ) & 1 )
		{
			n = 1;
			break;
		}
	}

	if( !n ) return;

	res = inportb( 0x60 );

	return res;
}

// sends a command to the keyboard
void KeyboardCmd( unsigned char cmd )
{
	outportb( 0x64, cmd );
}

// set the ps2 bytes
void PS2Set()
{
	outportb( KBD_STAT, ENABLE_PS2 );
	CheckPort();

	// enable the mouse irq
	unsigned char c;
	KeyboardCmd( 0x20 );
	c = ReadKeyboard() | 2;
	KeyboardCmd( 0x60 );
	WriteKeyboard( c );
}

// waits for the mouse
void WaitMouse()
{
	outportb( KBD_STAT, MOUSE );
	CheckPort();
}

// sets the streaming mode
void StartStream()
{
	WaitMouse();
	outportb( KBD_CMD, MOUSE_STREAM );
	CheckPort();
	CheckMouse();
}

// disables the keyboard
void DisableKeyboard()
{
	outportb( KBD_STAT, DISABLE_KBD );
	CheckPort();
}

// enables the keyboard
void EnableKeyboard()
{
	outportb( KBD_STAT, ENABLE_KBD );
	CheckPort();
}

void MouseWait( char thetype )
{
	long timeout = 100000;
	if( thetype == 0 )
	{
		while( timeout-- )
		{
			if( inportb( 0x64 ) & 1 )
			{
				return;
			}
		}
		return;
	}
	if( thetype == 1 )
	{
		while( timeout-- )
		{
			if( ( inportb( 0x64 ) & 2 ) == 0 )
			{
				return;
			}
		}
		return;
	}
}

// get a byte from the port
char GetByte()
{
//	DisableKeyboard();

	char ret = 1;

/*	while( ret )
		ret = CheckMouse();

	MouseWait( 0 );*/
	ret = inportb( 0x60 );
/*	EnableKeyboard();*/

	return ret;
}

// info
int getstat = 0;
int readable = 0;
MOUSEDATA LocalData;

// data pointer

// irq handler for the mouse
void MouseIRQ( struct regs* r )
{
	kputs( "MouseIRQ " );

	// check the counter
	if( getstat == 0 )
	{
		LocalData.status = GetByte();
		getstat = 1;
		return;
	}
	if( getstat == 1 )
	{
		LocalData.xcoord = GetByte();
		getstat = 2;
		return;
	}
	if( getstat == 2 )
	{
		LocalData.ycoord = GetByte();
		getstat = 3;
	}

	if( getstat == 3 )
	{
		readable = 1;
	}
}

// get data from the mouse
void GetMouseData( MOUSEDATA* data )
{
	kputs( "reading..." );

	// is there data?
	while( !readable )
	{
		pause();
	}

	// readable is false now
	readable = 0;

	// return the data
	*data = LocalData;

	// set sc to 0, so we can get more data
	getstat = 0;
}

// init the mouse
void InitMouse()
{
	kputs( "Initializing PS2 mouse... " );
	PS2Set();
	StartStream();

	kputs( "Installing irq handler..." );

	// install the irq handler
	irq_install_handler( 12, MouseIRQ );
}
"MouseIRQ " never gets printed...
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

Routine question: Have you enabled the Mouse IRQ at the PIC (both pics, actually)?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

I think so... I used Bran's development tutorial so that's where my irq installer is from, and it works for things like the keyboard and floppy. I think it might have something to do with enabling the mouse interrupt on the keyboard controller?
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

You probably need to use an IRET instruction instead of the C/C++ "return" in the "MouseIRQ( struct regs* r )". And make sure that you acknowledge the PIC before executing IRET.

You should poke 1 or more bytes to screen to find out how many times the mouse/keyboard IRQ gets called if any. If it's called only once an then it gets stuck, then definitely you need to acknowledge PICs now that you are using an ISR instead of polling, since I don't see any code that performs such acknowledgement.

Code: Select all

//For mouse:
  outportb(0xA0,0x20);
  outportb(0x20,0x20);



//For keyboard:
  outportb(0x20,0x20);

Remember that it should be the last thing to do (acknowledging) for each byte, so it should also be done when you finish receiving the third byte and using them.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

Well, actually, the way IRQ/ISRs work in my OS is that they point to an assembly stub, which then handles pushing/popping etc. and calls the C handler, and also has the IRET. Inside the C handler it chooses a handler function to run, and if the interrupt came from the second PIC, it sends the correct values.

At the moment, the mouse interrupt just isn't firing, and I think it might have something to do with the keyboard controller not having the mouse interrupt enabled.

Edit: I've come up with this to enable the mouse device interrupt (thanks to the Art of Assembly chapter 22)

Code: Select all

outportb( 0x64, 0x20 );
// wait for that to be sent
unsgined char c = inportb( 0x60 ) | 2;
outportb( 0x64, 0x60 );
// wait for that to be sent
outportb( 0x60, c );
Can anyone tell me if this is correct?
Last edited by pcmattman on Thu Mar 08, 2007 11:06 pm, edited 1 time in total.
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

Something like this should be done:

Code: Select all

asm{
             mov al,0xD1 ;WRITE OUTPUT PORT.
             out 0x64,al

            call KeybController_waitUntilReady

             mov al,11111111b
               ; 0-Normal
               ; 1-Enable A20
               ; 2-Data to Mouse
               ; 3-Mouse Clock
               ; 4-IRQ1 Active
               ; 5-IRQ12 Active
               ; 6-Keyboard Clock
               ; 7-Data to Keyboard
               out 0x60,al
}

asm{
  KeybController_waitUntilReady:
   in al,0x64
   test al,00000010b
   jnz KeybController_waitUntilReady
  ret
}
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

pcmattman wrote:Well, actually, the way IRQ/ISRs work in my OS is that they point to an assembly stub, which then handles pushing/popping etc. and calls the C handler, and also has the IRET. Inside the C handler it chooses a handler function to run, and if the interrupt came from the second PIC, it sends the correct values.

At the moment, the mouse interrupt just isn't firing, and I think it might have something to do with the keyboard controller not having the mouse interrupt enabled.

Edit: I've come up with this to enable the mouse device interrupt (thanks to the Art of Assembly chapter 22)

Code: Select all

outportb( 0x64, 0x20 );
// wait for that to be sent
unsgined char c = inportb( 0x60 ) | 2;
outportb( 0x64, 0x60 );
// wait for that to be sent
outportb( 0x60, c );
Can anyone tell me if this is correct?
It looks like it should work. I remember I do these two things, the one of the snippet above and the assembly code I posted, and a third one that consists of initializing mouse itself, for it to work and finally enabling the IRQ in the PIC. All those are required.
Post Reply