Page 1 of 2

PS/2 Mouse Data Problem

Posted: Fri Mar 05, 2004 12:00 am
by Gandalf
hi friends,

I have a problem with the PS/2 Mouse. Though I could make a decent PS/2 mouse driver from your help(CodeSlasher and others) and using the chapweske tutorial from the panda site, there is a problem when I test my code with my system.(It runs perfectly with VMWare - trial version).

The problem is this:
====================

In VMWare I get 3 bytes of movement data for each mouse Interrupt whereas in the real system the mouse seems to send only one data byte at each interrupt.

That means I have to internally buffer two bytes of data till the third interrupt occurs and I send a mouse data message to my GUI Server only then. Though this approach works I still get a somewhat dizzy mouse pointer(looks like a drunkard mouse :-) )

Could you tell me what's wrong.

Thank you all and special thanx to CodeSlasher



rgds
Gandalf

RE:PS/2 Mouse Data Problem

Posted: Sat Mar 06, 2004 12:00 am
by gaf
Hi Gandalf

>In VMWare I get 3 bytes of movement data for each mouse Interrupt whereas in >the real system the mouse seems to send only one data byte at each interrupt.

I finally managed to get my driver working and on the two computers I tested it on the mouse only triggers one interrupt for the whole datapacket. You should doublecheck your waiting procedures. I'll post the code of mine tomorrow.

regards,
gaf

RE:PS/2 Mouse Data Problem

Posted: Sun Mar 07, 2004 12:00 am
by gaf
Hi Gandaf
Here's thge code of my mouse driver:

void Controller::Command(uchar command)
{
    // Wait for the controller to be ready, then send the command
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x64, command);
}

void Controller::Parameter(uchar parameter)
{
    // Wait for the controller to be ready, then send the command
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x60, parameter);
}
    
uchar Controller::Response()
{
    // Wait for the response and return
    while(!(Port::ReadByte(0x64) &output_buffer));
    return Port::ReadByte(0x60);
}
    
void Mouse::Command(uchar command)
{
    // Make sure that the mouse isn't busy
    while(Port::ReadByte(0x64) &mouse_buffer);

    // Check that the controller is idle, then send 0xD4 to it
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x64, 0xD4);
    
    // Send the command to the mouse by passing it to port 0x60
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x60, command);
}

void Mouse::Parameter(uchar parameter)
{
    // Wait for the controller to be ready, then send the command
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x60, parameter);
}

uchar Mouse::Response()
{
    // Wait for the mouse's response and return
    while(!(Port::ReadByte(0x64) &mouse_buffer));
    return Port::ReadByte(0x60);
}


MouseDriver::MouseDriver(void)
{
    uchar ret;
    
    console() << "\nEnabling Mouse-irq in the Command-byte\n";
    Controller::Command(0x60);
    Controller::Parameter(3);
    
    console() << "Enabling the Mouse\n";
    Controller::Command(0xA8);
    Mouse::Command(0xF4);
    
    console() << "Doing some selftest in order to test the low-level interface\n";
    Controller::Command(0xAA);
    ret = Controller::Response();
    console().WriteFormat("Controller: 0x%8x  ", ret);
    Controller::Command(0xA9);
    ret = Controller::Response();
    console().WriteFormat("Mouse: 0x%8x\n", ret);
    
    console() << "\nMouse driver was successfully started\n";
}

MouseDriver::~MouseDriver(void)
{
}

void MouseDriver::Execute() // ISR
{
    console().WriteFormat("1. 0x%8x  ", Controller::Response());
    console().WriteFormat("2. 0x%8x  ", Controller::Response());
    console().WriteFormat("3. 0x%8x\n", Controller::Response());
    
    Port::WriteByte(0xA0, 0x20);
    Port::WriteByte(0x20, 0x20);
}

I use the classes Mouse and Controller for more comfortable access to the hardware. They will later also assure mutual exclusion - keyboard and mouse may otherwise access the controller at the same time causing a big mess in the status register.

I've got a much more improved ISR aswell which outputs correct data but it's pretty long and propably not important for solving your problem.

regards,
gaf

RE:PS/2 Mouse Data Problem

Posted: Fri Mar 12, 2004 12:00 am
by Gandalf
hi friends,

Thank you gaf for your help - Im sorry that I took so long to reply. Im working on with my mouse driver (using the ideas from ur code). However my mouse still seems to be a bit crazy. I will try for few more days (nights included :-))

Thank you again gaf. The moment I will get my mouse to work I will post my code.

rgds
Gandalf

RE:PS/2 Mouse Data Problem

Posted: Sun Mar 14, 2004 12:00 am
by hartyl
hm;

i've already done my mouse-driver. i got to tell you, that a ps/2 mouse sends 3 bytes as a datapacket when there's an event.
BUT the mouse-handler (the interrupt) is called THREE times; once for every byte. so, you have an empty packet-buffer in the beginning. the interrupt is called, you get the byte from the controller and leave the ISR (don't forget to enable the interrupts, again), waiting for the second interrupt. when it comes, you get the second byte and wait for the third interrupt. once there, you have your data complete and can process it.

greets, hartyl

RE:PS/2 Mouse Data Problem

Posted: Mon Mar 15, 2004 12:00 am
by Gandalf
hi friend,

If u read my question(1st post) u will know that I have the same problem.        1 byte/intr in real system & 3byte/intr in VMWare.

rgds
Gandalf

RE:PS/2 Mouse Data Problem

Posted: Mon Mar 15, 2004 12:00 am
by gaf
Hi hartyl,
I thought that the code I posted was correct, however, it now looks like it only works on my computer and bochs. When I lately tested it on two other machines it failed (at different commands however). I'm now afraid that I don't wait properly. My code is uploaded here:
http://mitglied.lycos.de/cozmo86/mouse.zip

Could you please have a look at it (especially HAL.cpp) ? I really don't know what's wrong since it works perfectly with bochs.

regards,
cosmo86

RE:PS/2 Mouse Data Problem

Posted: Wed Mar 17, 2004 12:00 am
by gaf
Hi Gandalf,
Today I found another site about the ps/2 interface:
http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html

It looks like Adams micro resources (http://govschl.ndsu.nodak.edu/~achapwes ... index.html) really mixes up input- and ouput buffer. Here's how it really seems to be:

0x64 <write> input buffer (command)
0x60 <write> input buffer (data)
0x60 <read>  output buffer
0x60 <read>  status register

IBF - Controller is busy. Don't write to 0x64 nor to 0x60.
OBF - New data is available in the output buffer
MBF - 1: Data in the output buffer is from the mouse
      0: Data is from the kbd

I wrote a few lines in order to test whether this site is right and it worked on all three computers I tried.

<c++>
MouseDriver::MouseDriver(void)
{
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x64, 0xD4);
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x60, 0xEA);
    while(!(Port::ReadByte(0x64) &output_buffer + mouse_buffer));
    console().WriteFormat("\n\nACK: 0x%8x\n", Port::ReadByte(0x60));
    
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x64, 0x60);
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x60, 0x43);
    
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x64, 0xD4);
    while(Port::ReadByte(0x64) &input_buffer);
    Port::WriteByte(0x60, 0xF4);
    while(!(Port::ReadByte(0x64) &output_buffer + mouse_buffer));
    console().WriteFormat("ACK: 0x%8x\n\n", Port::ReadByte(0x60));

    //while(Port::ReadByte(0x64) &output_buffer)
    //    Port::ReadByte(0x60);
}

void MouseDriver::Execute()   // My ISR
{  
    static int index = 0;
    static uchar data[3];
    
    if(index < 3)
    {
        while(!(Port::ReadByte(0x64) &output_buffer + mouse_buffer));
                data[index] = Port::ReadByte(0x60);
                
        index++;
    }
    
    if(index == 3)
    {
        index = 0;
        console().WriteFormat("0x%8x  ", data[0]);
        console().WriteFormat("0x%8x  ", data[1]);
        console().WriteFormat("0x%8x\n", data[2]);
    }

    Port::WriteByte(0xA0, 0x20);    // master
    Port::WriteByte(0x20, 0x20);    // slave
}

You (and hartyl) are right that the ISR will called 3 times for each datapacket, however, this should go for VMWare aswell. I propose that you run my code and when the mouse still looks dizzy you'll at least know that it's not sth with your mouse driver. There might be some conflict with other drivers, especially the keyboard driver, so you could try to disabling them.

Let me know whether it worked.

regards,
gaf

RE:PS/2 Mouse Data Problem

Posted: Wed Mar 17, 2004 12:00 am
by hartyl
well, i just post my code right along; it works on a real system as well as on bochs. it just plots a pixel on the new position of the "mouse" - just a minimalistic testroutine.

#define KEYBD_CMD   0x64
#define KEYBD_READ  0x60
#define KEYBD_WRITE KEYBD_READ

void mouse_init()
{ byte tmp;
  out(KEYBD_CMD,0xa8)
  out(KEYBD_CMD,0x20)
  tmp=in(KEYBD_READ);
  out(KEYBD_CMD,0x60);
  out(KEYBD_WRITE,tmp | 0x02);
  out(KEYBD_CMD,0xd4);
  out(KEYBD_WRITE,0xf4);
  in(KEYBD_READ);
  
  mouse_x=max_x>>1;
  mouse_y=max_y>>1;
  cnt=0;
}

void mouse_handler()
{ ISR_ENTER
  byte tmp=in(KEYBD_READ);
  //printdword(tmp);
  switch(cnt++)
  { case 0:
            break;
    case 1: mouse_x+=(signed char)tmp;
            break;
    case 2: mouse_y-=(signed char)tmp;
            pixel_put(mouse_x,mouse_y,63);
            cnt=0;
  }
  if((int)mouse_x<0)
    mouse_x=0;
  else if((int)mouse_x>=max_x)
    mouse_x=max_x-1;
  if((int)mouse_y<0)
    mouse_y=0;
  else if((int)mouse_y>=max_y)
    mouse_y=max_y-1;
    
  out(PORT_8259M,0x20);
  out(PORT_8259S,0x20);
  ISR_LEAVE
}

RE:PS/2 Mouse Data Problem

Posted: Fri Mar 19, 2004 12:00 am
by gaf
Hello hartyl,
First of all thanks for posting your code. I'm a bit surprised that you seem not to check the flags in the status byte before accessing the controller. Is this done in in and out ? If not so you're code might work on bochs because kbd and mouse responde immediately there, but will most likely fail on real hardware.
Did you try to boot your OS ?

regards,
gaf

RE:PS/2 Mouse Data Problem

Posted: Sun Mar 21, 2004 12:00 am
by hartyl
i don't check the flags, just dropping one byte after the other. was too lazy to program that since it's just a test-code (just to see the mouse responding correctly). i think my os won't include a mouse - only for games and such. the software-cursor really complicates everything. i'm also searching a new gui-approach. anyway, the mouse works - on bochs as well as on a (only my?) real machine.

greets, hartyl

My Mouse is working on my System !!!

Posted: Wed Mar 24, 2004 12:00 am
by Gandalf
hi gaf and hartyl,

My mouse is now working properly in my system as well as in my college systems. So the actual trick is not the OBF / MOBF. The problem is that the controller is not able to set the OBF immediately after data has been read from port 0x60. So we have got to wait for some time till it sets the OBF.

That is why we were getting 3 bytes in VMWare/Bochs but not in real Systems.
Here's my code:
/*-------CODE BEGINS-------------*/
/*--------MOUSE.H----------------*/
#ifndef __MOUSE_H
#define __MOUSE_H

  #include "ktypes.h" //Contains typedef of DB, DW and DD - see at the end


  #define XOVR  1<<7
  #define YOVR  1<<6
  #define YSGN  1<<5
  #define XSGN  1<<4
  
  #define MBTN  1<<2
  #define RBTN  1<<1
  #define LBTN  1
  
  //PS/2 Status
  #define OBF       0x1
  #define IBF       0x2
  
  #define SYS       0x4
  #define A2        0x8
  #define INH       0x16
  #define MOBF      0x32
  #define TO        0x64
  #define PERR      0x128

  #define INT   0x1
  #define INT2  0x2
  #define SYS   0x4
  #define RESV  0x8
  #define _EN   0x16
  #define _EN2  0x32
  #define XLAT  0x64
  #define RESV2 0x128

  //This timeout is crucial - College System - 1024 but Home sys - 1625
  //So to be on the safer side I have set it as 8192
  #define PS2_TIMEOUT 8192

  #define readStatus() inb(0x64)

  extern DW mcurx, mcury;
  extern DB mbyte[];

  void mouse_init();
  void handle_mouse();

  void printStatus();
#endif


/*---------- MOUSE.C --------------*/

#include "mouse.h"

DB mbyte[3];
DW mcurx = TOTAL_WIDTH/2, mcury = TOTAL_HEIGHT/2;

void w64(DB val)
{
   printf("\nIn w64->%x",val);
   delay(0x3FFF);

   while(readStatus() & IBF)
    ;
   outb(0x64,val);
   printStatus();
   delay(0x3FFF);
}

DB r60()
{
   DB data;
   printf("\nIn r60");

   while(readStatus() & OBF)
   {
    data = inb(0x60);
    printf("\t %x",data);
    printStatus();
    return data;
   }
}

void w60(DB val)
{
   printf("\nIn w60->%x",val);
   delay(0x3FFF);

   while(readStatus() & OBF)
   {
    r60();
   }
   outb(0x60,val);
   printStatus();
}

void mouse_init()
{
   DB cmdByte;

   printf("\nMouse Init");
   printStatus();

   //Controller Self Test
   w64(0xAA);
   r60();

   delay(0x1FFF);

   //Enable PS/2 I/F
   w64(0xA8);
   r60();

   delay(0x1FFF);


   //Set INT2
   cls();
   w64(0x20);
   cmdByte = r60();
   printf("\nCMDBYTE %x %b",cmdByte,cmdByte);
   delay(0x1FFF);
   w64(0x60);
   w60(0x47);
   r60();
   w64(0x20);
   cmdByte = r60();
   printf("\nCMDBYTE %x %b",cmdByte,cmdByte);
   delay(0x1FFF);

   //Send Reset 2 Mouse
   w64(0xD4);
   w60(0xFF);
   while(readStatus() & OBF)
   {
     r60();
   }

   delay(0x1FFF);

   //Stream Mode
   w64(0xD4);
   w60(0xEA);
   while(readStatus() & OBF)
   {
     r60();
   }

   delay(0x1FFF);

   //Enable Data Reporting
   w64(0xD4);
   w60(0xF4);
   while(readStatus() & OBF)
   {
     r60();
   }

   delay(0x1FFF);
}



void handle_mouse()
{
   DB i = 0;
   DD count;

   printf("\nIn handle_mouse");

   while(readStatus() & OBF && i<3)
   {
       printStatus();
       mbyte[i] = inb(0x60);
       printf(" %x ",mbyte[i]);
       i++;

       //Wait till O/P avl
    for(count=0 ; !(readStatus() & OBF) && count < PS2_TIMEOUT && i<3; count++)
          ;
       printf(" %d ",count);
   }
  
   while(readStatus() & OBF)
   {
     inb(0x60);
   }

   printStatus();

   processData();

   //eoi
   outb(0x20,0x20);
   outb(0xA0,0x20);

   return;
}

void processData()
{
  DW _x = 0, _y = 0;
  DW xdel = 0, ydel = 0;

   //Taking care of 2's complement
   if(mbyte[0] & XSGN)
      mbyte[1] = ~mbyte[1] + 1;

   if(mbyte[0] & YSGN)
      mbyte[2] = ~mbyte[2] + 1;

   printf("\nm[0] %b m[1] %d m[2] %d ",mbyte[0],mbyte[1],mbyte[2]);

    xdel = 4 * mbyte[1]; //X Scaling
    ydel = 3 * mbyte[2]; //Y Scaling

   if(mbyte[0] & XSGN)
      _x = mcurx - xdel;
   else
      _x = mcurx + xdel;

   if(mbyte[0] & YSGN)
      _y = mcury + ydel;
   else
      _y = mcury - ydel;

    if( _x & 0x8000)
       _x = 1;

    if( _x > TOTAL_WIDTH - 16)
       _x =  TOTAL_WIDTH - 16;

    if( _y & 0x8000)
       _y = 1;

    if( _y > TOTAL_HEIGHT - 16)
       _y = TOTAL_HEIGHT - 16;

    mcurx = _x;
    mcury = _y;

   printf("\n _x: %d _y %d",_x,_y);
   printf("\n x: %d y %d",mcurx,mcury);

   if(mbyte[0] & MBTN)
   {
    printf("\nMBtn Pressed");
   }

   if(mbyte[0] & LBTN)
   {
    printf("\nLBtn Pressed");
   }

   if(mbyte[0] & RBTN)
   {
    printf("\nRBtn Pressed");
   }
}

void printStatus()
{
  printf("\nPERR TO MOBF INH A2 SYS IBF OBF");
  printf("\nStatus %x %b",readStatus(),readStatus());
}


/*-------- CODE ENDS --------------*/

Here
DB = unsigned char
DW = unsigned short
DD = unsigned int
Hope this works for you too.
Waiting for your responses.

rgds
Gandalf

PS: I have removed the message sending & reset handling part of the mouse driver - as I feel it is completely irrelevent to our problem.

RE:My Mouse is working on my System !!!

Posted: Thu Mar 25, 2004 12:00 am
by gaf
Hi Gandalf,
The controller can set the OBF immediately so there's no need for waiting. The problem rather seems to be that you're code doesn't make any difference between data sent by the kbd and data sent by the mouse. I finshed my own driver just yesterday: http://mitglied.lycos.de/cozmo86/code.zip
I hope the code will help you finding the problem.

regards,
gaf

RE:My Mouse is working on my System !!!

Posted: Fri Mar 26, 2004 12:00 am
by Gandalf
hi gaf,

Well I have changed my driver to take care from where the data comes (KBD or Mouse by using the MOBF bit). And now I am able to init my mouse within 2 secs (I have removed all my delays and the overall bootup time has been considerably reduced). Thanks for that.

But still the controller is not immediately setting the OBF & MOBF after reading a byte from 0x60(Well check by dumping the status after every read and u will find out). So I believe we have got to wait. Anyway I downloaded your code - its good. Did u check ur driver with real systems.

Right now I have reduced the init time but I have retained the waiting code in Mouse Interrupt handling. The mouse is damned smooth in my real sys.  

Waiting for ur reply.

rgds
Gandalf

RE:My Mouse is working on my System !!!

Posted: Fri Mar 26, 2004 12:00 am
by gaf
Hi Gnadalf,
2 seconds for booting the mouse driver IMHO show that there's still sth wrong. Are you sure you did remove all the delays - my driver boots more or less immediately.
As I already said, I'm pretty sure that the status byte gets set immediately. My code assumes that and it's working fine on all three systems I tested it on.
You may want to know that while adding Intelli mouse support to my driver yesterday, I encountert some minor bugs the mouse code (concerning parameters and return values). A updated version of my code and a trion image (including the driver) is available at http://mitglied.lycos.de/cozmo86/code.zip
(Please read the readme-file)

I read through you're code more carefully today and there're some thinks that look a bit strange to me:
1) In r60() you try to read data from the controller and when there's none available you simply give up. I think it'd be a better idea to wait until the data arrives. Note that while the ctrl reacts immediately, kbd and mouse may need some time to respond.
2) Your ISR tries to get all 3 data-packets at once but there's one interrupt for each packet. Try to rewrite it in order to get one byte per call, save it and process it as soon as you've received the whole packet.
3) (This one's more general) You should check the return values by the devices more carefully. This is not important for you're driver to work propery, but it might help you finding the bug.

If you still have any problems, please sent me a updated version of your code so I can have a look at it: gaffi<at>haefft<dot>de

cheers,
gaf