Page 1 of 1

Help with Mouse Programming

Posted: Sat Jan 24, 2004 12:00 am
by Gandalf
hi friends,

I have completed a reasonably stable multitasking os and its memory management. I want to continue on with support for mouse. I read a few documents available about PS/2 mouse and its I/O commands and data stream format(3byte format).

But none of those documents tell how to interface with the mouse. How am I to send and receive commands from the mouse. Can I access some mouse port like (port 0x60 for Keyboard) to do that ?

And in one of the documents there is info that the 8042 keyboard controller has built-in capability to handle one more auxilary device(like PS/2 mouse) apart from the keyboard. Is that true ?

Thanking you
Gandalf

RE:Help with Mouse Programming

Posted: Sat Jan 24, 2004 12:00 am
by St8ic
A very popular problem. Here is another thread on this board that may help:

http://www.osdev.org/board.jsp?message=5207  

You have to use the keyboard port for communication
(e.g. send 0x60 to 0x64 to enable mouse's interface)

of course this is just the very basics, and I can't guarentee that I'm right. When I tried to program PS/2 mouse I gave up and took out the whole GUI!

RE:Help with Mouse Programming

Posted: Sat Jan 24, 2004 12:00 am
by SystemHalted
yes I also gave up on mouse programming(for now) and trashed my GUI.

RE:Help with Mouse Programming

Posted: Sat Jan 24, 2004 12:00 am
by CodeSlasher
Programming the Ps2 mouse is easy.
You need to do two things
1st initialize the controller and mouse
2nd install a mouse handler at IRQ 12

void initialize_mouse()
{
  unsigned char data;
  while(test_keyboard_data()) //empty data buffer on keyboard controller
       inportb(0x60);

  wait_keyboard();      //wait for keyboard controller to be ready
  outportb(0x64,0xa8); /*tell controller to enable AUX interface*/
  wait_keyboard();

  outportb(0x64,0xd4); /*tell controller to send next command to Aux device*/
  wait_keyboard();
  outportb(0x60,0xea); /*tell device to enable itself*/
  wait_keyboard_data();

if(test_keyboard_data()) //this is for my personal debugging. I'm expecting an
    printf("KEYBOARD ACK 3 [%02x]\n",inportb(0x60)); //acknowledge from keyboard

  outportb(0x64,0x20); /*read command byte*/
  wait_keyboard_data();

data=inportb(0x60);
data=data|0x43;     //enable the int 12 bit. check docs

  outportb(0x64,0x60); /*write command byte*/
  wait_keyboard();
  outportb(0x60,data);

  wait_keyboard();

  k_memset(mouse_data,0,sizeof(mouse_data)); // clear driver mouse data buffer  

  outportb(0x64,0xd4); /*tell controller to send next command to Aux device*/
  wait_keyboard();

  outportb(0x60,0xf4); /*reset mode*/
  wait_keyboard_data();
if(test_keyboard_data())
    printf("KEYBOARD ACK 4 [%02x]\n",inportb(0x60)); //my debugging stuff.

  inportb(0x60);
  while(test_keyboard_data())
       inportb(0x60);

  kenable_level(12); //NOW This is the most important part. It it tells the PIC                                          
                     // to enables IRQ 12. That is both the Master and Slave.
return;
}

now for the IRQ 12 mouse ISR, you need to read a byte from port 60 and store it for each intterupt reported. They will be 3 that are needed to send the full mouse data i.e. mouse_data[0]=data from 1st int,mouse_data[1]=data from 2nd int and mouse_data[2]=data from 3rd int. Increment a counter during each int fired and acknowledge the int to the pic. Then when the counter is 3, you reset the counter to 0, and then interpret the 3 bytes you have stored based.

_mouse_int:
        push eax
        push edi
        push ecx
        push ebx

        movzx ebx,byte [_mouse_in]  ;number of bytes i've recieved so far
        lea edi,[_mouse_data]       ;buffer where i store mouse data bytes

              in al,0x60
              mov [edi+ebx],byte al ;store the byte
              inc ebx               ;increment counter
              cmp ebx,0x03          ;check if i've collected 3 byted
              jb .mouse_out_pre     ;not 3 bytes yet so can't process mouse info

              mov ch,byte [edi]     ;last byte from mouse is multi infor byte
              mov [_mouse_button],byte ch   ;store mouse button info
              test ch,0x40          ;check for X overflow
              jz .no_x_overflow
              mov [_mouse_dx],byte 0xff ;maximum x value
              jmp .check_y_overflow

.mouse_out_pre:
                jmp .mouse_out

.no_x_overflow:
              mov cl,byte [edi+0x01]  ;get change in x byte
              mov [_mouse_dx],byte cl

.check_y_overflow:
              test ch,0x80           ;check for Y overflow
              jz .no_y_overflow
              mov [_mouse_dy],byte 0xff ;sign bit set so 255 is maximum
              jmp .check_x_sign

.no_y_overflow:
              mov cl,byte [edi+0x02]   ;get change in y byte
              mov [_mouse_dy],byte cl

.check_x_sign:
               test ch,0x10
               jz .positive_x
               movsx eax,byte [_mouse_dx]
               jmp .check_y_sign
.positive_x:
               movzx eax,byte [_mouse_dx]
.check_y_sign:
               test ch,0x20
               jz .positive_y
               movsx ecx,byte [_mouse_dy]
               jmp .going_out
.positive_y:
               movzx ecx,byte [_mouse_dy]
.going_out:
               mov ebx,0
               add [_mouse_x],word ax
               neg cx
               add [_mouse_y],word cx

               push dword [_mouse_semaphore]
               call _wake
               pop eax
.mouse_out:
        mov [_mouse_in],byte bl

        mov al,0x20
        out 0xa0,al
        out 0x20,al

        pop ebx
        pop ecx
        pop edi
        pop eax

        iret
        jmp $

Remember to install the mouse Isr at the right place. If you reprogram the pic to use 0x20 - 0x27 for the master pic and 0x28 - 0x2f for the slave pic, then IRQ 12 is on the slave pic and uses ISR 0x2C.