It took me a while to search for a good tutorial on how to write a PS/2 mouse driver for a hobby OS. Luckily, I was able to make an existing driver work. So for those who are having trouble writing one, I came up with this guide. However, I do not take full credit in the codes that I will be posting.
I assume that your hobby OS is 32-bit targetted on x86 machines. The following outlines the steps.
- Program the 8259 controller to enable IRQ2, the cascade line. The PS/2 mouse IRQ is IRQ12 which is in the slave PIC. Normally the IRQ numbers are remapped in 32-bit OSes.
#define IRQ_TIMER 1 #define IRQ_CASCADE 4 #define IRQ_KEYBOARD 2 #define IRQ_FDC 64 #define IRQ_MOUSE 16 void program8259(unsigned char b){ unsigned char b1=0xFF; //remap the IRQs outportb(0x20,0x11); outportb(0xA0,0x11); outportb(0x21,0x20); //IRQ0-IRQ7 -> interrupts 0x20-0x27 outportb(0xA1,0x28); //IRQ8-IRQ15 -> interrupts 0x28-0x2F outportb(0x21,4); outportb(0xA1,2); outportb(0x21,1); outportb(0xA1,1); b1^=b; outportb(0x21,b1); outportb(0xA1, inportb(0xA1) & ~0x10); //enable IRQ12 }; //Here's the call to enable needed IRQ Lines called usually in the main() function program8259(IRQ_TIMER | IRQ_KEYBOARD | IRQ_FDC | IRQ_CASCADE);
- And here's the driver code courtesy of SANiK.
//Mouse.inc by SANiK //License: Use as you wish, except to cause damage unsigned char mouse_cycle=0; signed char mouse_byte[3]; signed char mouse_x=0; signed char mouse_y=0; /* The interrupt handler */ void mouse_irq(){ DWORD flags; switch(mouse_cycle){ case 0: mouse_byte[0]=inportb(0x60); mouse_cycle++; break; case 1: mouse_byte[1]=inportb(0x60); mouse_cycle++; break; case 2: mouse_byte[2]=inportb(0x60); mouse_x=mouse_byte[1]; mouse_y=mouse_byte[2]; mouse_cycle=0; break; } } inline void mouse_wait(unsigned char a_type){ unsigned int _time_out=100000; //unsigned int if(a_type==0){ while(_time_out--){ //Data if((inportb(0x64) & 1)==1){ return; } } return; }else{ while(_time_out--){ //Signal if((inportb(0x64) & 2)==0){ return; } } return; } } inline void mouse_write(unsigned char a_write){ //Wait to be able to send a command mouse_wait(1); //Tell the mouse we are sending a command outportb(0x64, 0xD4); //Wait for the final part mouse_wait(1); //Finally write outportb(0x60, a_write); } unsigned char mouse_read(){ //Get's response from mouse mouse_wait(0); return inportb(0x60); } void installmouse(){ /* This enables the mouse, called in main() */ unsigned char _status; //Enable the auxiliary mouse device mouse_wait(1); outportb(0x64, 0xA8); //Enable the interrupts mouse_wait(1); outportb(0x64, 0x20); mouse_wait(0); _status=(inportb(0x60) | 2); mouse_wait(1); outportb(0x64, 0x60); mouse_wait(1); outportb(0x60, _status); //Tell the mouse to use default settings mouse_write(0xF6); mouse_read(); //Acknowledge //Enable the mouse mouse_write(0xF4); mouse_read(); //Acknowledge //Depends on your OS! setinterruptvector(0x2C,idtbase,0x8E,mousewrapper,SYS_CODE_SEL); printf("Mouse successfully initialized.\n"); } void get_mouse_pos(signed char *x,signed char *y){ *x=mouse_x; *y=mouse_y; }
- The mousewrapper code is important for the IRET so it is written in assembly. It just actually calls mouse_irq defined in the driver above..
global mousewrapper mousewrapper: push ebp push gs push fs push es push ss push ds pusha call mouse_irq ;re-enable interrupts, this is IMPORTANT! mov al,0x20 out 0xA0,al out 0x20,al popa pop ds pop ss pop es pop fs pop gs pop ebp iret
1 comments:
HUGE BOON.
Dos uses int33 and Linux uses hidden obscure code that cant be found.
HID references are nice, but I need to start with a base of operations as PS2 keyboard and mouse are on same controller. THANK YOU!!
--FPOS is at rjasmin.net and fpos.firmos.at/fpos for SVN, you need a client like tortoise.
Might be broken for a little while yet, but its taking off.
Post a Comment