Mouse Problems

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.
Midas
Member
Member
Posts: 140
Joined: Sat Jun 24, 2006 4:40 pm
Location: Falkirk, Scotland
Contact:

Post by Midas »

inflater wrote:
Good luck finding a Pascal OSDev Forum
*** EXPLETIVES! ***

inflater
Well, there goes any chance you had of getting help.

[EDIT]This post was modified by Brendan too - quotes from the previously deleted post modified[/EDIT]
Regards,
Angus [Óengus] 'Midas' Lepper
User avatar
inflater
Member
Member
Posts: 1309
Joined: Thu Sep 28, 2006 10:32 am
Location: Slovakia
Contact:

Post by inflater »

Yep. Only Dex here can understand, what are the nerves and how strong are they, if some protected-mode programmer wants to help a real-mode programmer.

inflater
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
inflater wrote:The problem is:
When trying to write text on console, it works fine, but when i try to read from keyboard (all BIOS ints), it freezes.
Your code has a few problems....

First, can't do this in the mouse interrupt handler:

Code: Select all

data[0] := inportb($60);
data[1] := inportb($60);
data[2] := inportb($60);
You need to get one byte for each IRQ, not more, not less.

Also, you shouldn't access other "things" from within an IRQ handler (like the video BIOS functions).

At the end of every IRQ handler you need to send an EOI to the PIC chip. Because IRQ 12 is connected to both PIC chips you actually need to send an EOI to both of them. To do this, add something like this to the end of your IRQ handler:

Code: Select all

Port[$20] := $20;
Port[$A0] := $20;
If you don't send the EOI, then the PIC chips wont send other (equal or lower priority) IRQs to the CPU.

Lastly, the PIC chips are being used by the BIOS for the timer IRQ, keyboard IRQ, disk drive IRQs, etc. You can't remap the PIC chips without completely breaking the BIOS, unless you do something to trick the BIOS into thinking the IRQs are still the same.

For now, just delete the "{Init8259;}" line in the "mouse_install" procedure so that the PIC chips stays in it's default state. The PS/2 mouse uses IRQ 12, which the BIOS maps to interrupt $74. To install the interrupt handler you'd need to use:

Code: Select all

SetIntVec($74,ADDR(Mouse_ISR));
I'm not sure what other problems you've got there, but that's a start.... ;)


BTW, to remap the PIC chips (your "Init8259" procedure), I'd recommend using IRQ0 = $68 and IRQ8 = $70. This means that for IRQs 8 to 15 it's the same as the BIOS expects, and you don't need to do anything for them. Then for IRQs 0 to 7 you need to have dummy interrupt handlers that jump to the BIOS's IRQ handlers. For these you need a little assembly:

Code: Select all

dummy_IRQ0:
    push ax
    push ds
    xor ax,ax
    mov ds,ax
    push word [ (8 + 0) * 4 + 2]
    push word [ (8 + 0) * 4]
    pop ds
    pop ax
    retf

dummy_IRQ1:
    push ax
    push ds
    xor ax,ax
    mov ds,ax
    push word [ (8 + 1) * 4 + 2]
    push word [ (8 + 1) * 4]
    pop ds
    pop ax
    retf

dummy_IRQ2:
    push ax
    push ds
    xor ax,ax
    mov ds,ax
    push word [ (8 + 2) * 4 + 2]
    push word [ (8 + 2) * 4]
    pop ds
    pop ax
    retf
Of course I've only shown the dummy handlers for 3 of the IRQs - you should be able to figure out the other 5 of them....

This is a little tricky, and if you can guarantee that any variables you store (in Pascal) can be accessed via. the code segment register (CS) there's an easier way.

First, create an array of 8 pointers and copy the BIOS's IDT entries for IRQs 0 to 7 into this array. Then you can use dumy handlers like this:

Code: Select all

dummy_IRQ0:
    jmp far [ cs: <offset_for_array> + 0 * 4 ]

dummy_IRQ1:
    jmp far [ cs: <offset_for_array> + 1 * 4 ]

dummy_IRQ2:
    jmp far [ cs: <offset_for_array> + 2 * 4 ]
I'm not too sure if CS can be used to access your Pascal code's data though. If your compiler supports different "memory models" (like tiny, small, large, etc) then it might work if you're using the "tiny" memory model (i.e. if your code and data is limited to a single 64 KB segment). Otherwise the easy method will crash the computer and you need the messier method above.



Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
inflater
Member
Member
Posts: 1309
Joined: Thu Sep 28, 2006 10:32 am
Location: Slovakia
Contact:

Post by inflater »

Thanks !!!

I will try it :D

//EDIT:
What should I do with these?

Code: Select all

data[0] := inportb($60);
data[1] := inportb($60);
data[2] := inportb($60);
(This is from myself converted mouse driver [on page 1])
inflater
User avatar
inflater
Member
Member
Posts: 1309
Joined: Thu Sep 28, 2006 10:32 am
Location: Slovakia
Contact:

Post by inflater »

The keyb buffer is full!
What should I do? ;(

inflater
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
inflater wrote:What should I do with these?

Code: Select all

data[0] := inportb($60);
data[1] := inportb($60);
data[2] := inportb($60);
(This is from myself converted mouse driver [on page 1])/quote]

Only read one byte per IRQ. For example:

Code: Select all

    static int index = 0;

    data[index++] := inportb($60);
    if(index > 2) {

        // Process the 3 bytes here


       index = 0;
    }
    send_EOI();
}
inflater wrote:The keyb buffer is full!
What should I do? ;(
For the PS/2 controller's buffer, either the keyboard IRQ handler removes the byte in the buffer (when IRQ 1 occurs) or the mouse IRQ handler removes the byte in the buffer (when IRQ 12 occurs). If this buffer is full, then either your keyboard or mouse IRQ handler didn't work.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
inflater
Member
Member
Posts: 1309
Joined: Thu Sep 28, 2006 10:32 am
Location: Slovakia
Contact:

Post by inflater »

Still not working...

The code:

Code: Select all

procedure Mouse_ISR;
var index: integer;
label biger_2;
begin
data[index] := inportb($60);
if index > 2 then goto biger_2;
Inc(index);
data[index] := inportb($60);
if index > 2 then goto biger_2;
Inc(index);
data[index] := inportb($60);
if index > 2 then goto biger_2;
Inc(index);
data[index] := inportb($60);
if index > 2 then goto biger_2;
biger_2:
asm cli end;
x := 80;
y := 80;
if data[0] and $01 <> button[0] then begin
button[0] := button[0] xor $01;
if button[0] = 1 then left_button_down(x, y) else
left_button_up(x, y);
end;
if data[0] and $04 <> button[1] then begin
button[1] := button[1] xor $01;
if button[1] = 1 then middle_button_down(x, y) else
middle_button_up(x, y);
end;
if data[0] and $02 <> button[2] then begin
button[2] := button[2]xor $01;
if button[1] = 1 then right_button_down(x, y) else
right_button_up(x, y);
end;
if data[0] and $10 = 1 then x := x + 256 - data[1] * -1 else
x := x + data[1];
if data[0] and $20 = 1 then y := y + 256 - data[2] else
y := y + data[2] * -1;
if y > 184 then y := 184 else if y < 0 then y := 0;
if x > 311 then x := 311 else if x < 0 then x := 0;
index := 0;
asm sti end;

Port[$20] := $20;
Port[$A0] := $20;
pos_mouse(x, y);

end;
I really dont know where is the error...
inflater
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,

Hehe - I wish I knew Pascal. Try something more like this:

Code: Select all

procedure Mouse_ISR;
    var index: integer;

    data[index] := inportb($60);
    index := index + 1;

    if index > 2 then begin
        index := 0;

        // Pre-process the 3 bytes (from the 3 IRQs) here.

    end;
    Port[$20] := $20;
    Port[$A0] := $20;
end;
Some notes...

The "var index: integer;" is probably completely wrong. It must be initialised to zero (not sure if Pascal does this or if it should be "var index: integer = 0;"). It must also be "static" so that it keeps it's old value and isn't re-initialised every time the IRQ occurs. I'm not sure how to do this in Pascal, or if it needs to be defined as a global variable instead.

There's no point processing any of the received bytes until you know that you're receiving them correctly. There's also different mouse protocols, and a way to synchronise the device driver with the start of each sent packet (to ensure that byte 1 of the received packet is treated as byte 1, and not byte 2, byte 3 or byte 4).

In real mode, the CPU automatically disables IRQs before starting your IRQ handler, and automatically enables IRQs when you return from your IRQ handler. There is no need to do the CLI and STI, and if you must do the STI then do it after you send the EOI, not before (otherwise it's possible to get another IRQ 12 while you're handling the first IRQ12).

I'm also worried by the line "pos_mouse(x, y);". What does it do? In general the only thing your IRQ handler should do is put the received packet into some sort of buffer or queue, so that it can be processed by other code when you're not in the IRQ handler. If your "pos_mouse(x, y);" procedure does anything (like accessing video) then you'll get re-entrancy problems (and interrupt latency problems, once you remove the STI).

I'm going to assume your OS currently lacks some way of delivering events to processes. In this case you need some sort of "get_mouse" procedure which takes the next packet from the queue, processes it, and returns the result to the caller. The problem here is what to do if your queue becomes full. For example, for the BIOS's keyboard buffer, if the buffer becomes full the BIOS ignores received data and makes the speaker beep to alert the user.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Post by Jeko »

Did you enable IRQ 12 and IRQ 2.
I getted the same problem, and when I enabled also the IRQ 2, it worked!
User avatar
inflater
Member
Member
Posts: 1309
Joined: Thu Sep 28, 2006 10:32 am
Location: Slovakia
Contact:

Post by inflater »

IRQ 2 was ALREADY enabled because I did not use function "init8259"; i dont know why i should remap the PIC.

inflater
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Post by JAAman »

i dont know why i should remap the PIC.
because if you dont, you cant tell the differenve between hard-ints, and exceptions
User avatar
inflater
Member
Member
Posts: 1309
Joined: Thu Sep 28, 2006 10:32 am
Location: Slovakia
Contact:

Post by inflater »

because if you dont, you cant tell the differenve between hard-ints, and exceptions
Again, I am programming REAL mode, so that means - in RM is not required to remap PIC due to CPU errors - in RM is only INT 0 - a divide overflow.
In PM it is different - there are many CPU errors and you MUST remap the PIC.

inflater
User avatar
Assembler
Member
Member
Posts: 30
Joined: Fri Oct 27, 2006 5:26 am
Contact:

Post by Assembler »

Hi
For pascal osdeving why didn't anyone mention FPC (Freepascal)
Dex4u has an archive of AnonymOS written if FPC http://www.dex4u.com/pascal/AnonymOS.zip
I don't think this helps real-mode coders
Systems and Computer Engineering Researcher
"Do you pine for the nice days of Minix-1.1, when men were men and wrote their own device drivers?" -- Linus Torvalds
http://sce.carleton.ca/~maslan
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
JAAman wrote:
i dont know why i should remap the PIC.
because if you dont, you cant tell the differenve between hard-ints, and exceptions
Yes - for example, the double fault handler conflicts with IRQ 0.

Of course the BIOS itself also conflicts with exceptions. If you get a general protection fault the CPU will decide to run BIOS disk services, and for an FPU error the CPU might change video modes for you... :roll:
inflater wrote:Again, I am programming REAL mode, so that means - in RM is not required to remap PIC due to CPU errors - in RM is only INT 0 - a divide overflow.
In PM it is different - there are many CPU errors and you MUST remap the PIC.
No.

You can always get divide error, NMI, breakpoint exception, device not available, overflow exception, BOUND, invalid opcode, double fault, stack fault, and general protection fault. The only case where some of these aren't possible is if you're using an ancient 8086. Also, the device not available exception can't happen if CR0 is set properly.

The co-processor segment overrun exception can't happen on 32-bit CPUs but can happen in older CPUs (it was made obsolete).

Some exceptions can't happen unless certain features are enabled - debug exception, alignment check exception, floating point error, machine check exception, and SIMD floating point error. These can all be enabled and used in real mode though.

The only exceptions you can't get in real mode are page fault and invalid TSS.

Of course just because your OS runs in real mode and doesn't enable certain features doesn't mean applications won't use protected mode or enable those features. This is actually fairly likely considering how limiting real mode can be.

For example, if I were writing a boring text editor, the first thing I'd do is setup virtual 8086 mode and run the text editor in 1024 * 768 graphics mode, with full access to video memory via. the linear frame buffer and all of memory (640 KB might be enough for my font data). Of course this should be no surprise - it's exactly what everyone did on DOS.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Post by JAAman »

not true-- check the manuals!

in REAL MODE:

#DE -- divide error Exception(0)
#NMI -- this exception(2) is rare, and (on the PC) generally means your computer is not working
#BP -- breakpoint exception(3) wont likely occur unexpectedly, but valid in RMode
#OF -- overflow exception(4) used for handling overflow in ADD/ADC/SUB/SBC
#BR -- bound range exceeded(5) -- not commonly used, but perfectly valid (not in LMode though)
#UD -- invalid opcode exception(6) -- perfectly valid in RMode
#NM -- Device not availible(7) -- has to do with the FPU/emulation of FPU/ task switch handling
#9 -- FPU segment overrun -- not on newer CPUs
#SS -- stack segment fault(12)
#GP -- General Protection Fault(13) -- this can occur under RMode
#DB -- debug exception(1) -- no reason it cannot occur in RMode
#DF -- double fault( 8 ) -- not likely in RMode
#MF -- FPU floating point error(16)
#MC -- machine check, indicates internal or bus error
#XF -- SIMD floating point error(19)


not RMode:
#TS -- Not in RMode
#NP -- not in RMode
#PF -- not in RMode
#AC -- not in RMode
-----------------------------------------------------------------
exceptions 15, 20-32 are reserved and may be used in RMode on future CPUs


so as you can see, this issue is just as important in RMode as it is in PMode/LMode 15 of 19 exceptions can be received in RMode

this information is taken straight from intel manuals, vol.3, ch5 (table 5-1 mostly, supported by specific info from section 5.15), and the ISR (vol.2)


ps. brenden beat me because i spent the time to lookup exactly which exceptions were valid in RMode -- almost all of them are
Post Reply