Mouse movement data packets... [SOLVED]
-
- 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]
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.
-
- Posts: 6
- Joined: Sun Feb 25, 2007 5:16 pm
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
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
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.
http://bos.asmhackers.net/docs/mouse/sn ... /mouse.inc
sanik's donated source. i might have other info in those folders too.
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.
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.
-
- 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:
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:
Header:
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();
}
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
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:
Note that when I refer to 1 byte at a time I refer to something like this:
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.
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:
//
}
By the way, i am not expecting the rapid pseudocode above to be bug-free, but to give the ideas.
-
- 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:
The mouse IRQ is not firing... Any ideas?
Code for new driver:
"MouseIRQ " never gets printed...
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 );
}
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.
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.
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.
-
- 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:
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)
Can anyone tell me if this is correct?
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 );
Last edited by pcmattman on Thu Mar 08, 2007 11:06 pm, edited 1 time in total.
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
}
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.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)Can anyone tell me if this is correct?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 );