Keyboard: Problem with the (re)programmed Interrupt handler

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.
j.vimal

Keyboard: Problem with the (re)programmed Interrupt handler

Post by j.vimal »

Hi all
I recently started on this project of devving a nice personal tool kit that would boot off from a CD, and instead went to OS Development.
I have worked hard for 2 weeks or so, and got the bootsector working. Successful linking of assembler code to start my kernel.
Loading sectors properly.
Reaching the PMode.
Loaded the GDT, IDT ... no LDT so far.
Now, I left assembly and started coding in C. :)

Now, the problematic part.

I got my keyboard interrupt written. It *works*. The function runs whenever I hit a key. Thats fine.
But, how do I *wait* for a key to be pressed? i.e. to program the getch() function?

I did:
(Pseudo code)
Buffer [0 ... 0xFF] //Software buffer
While the buffer position of the software buffer isnt zero, run an infinite loop:

while(buffer_pos == 0);
buffer_pos is zero initially.

But, now, if i hit a key, it doenst even respond. I have found that it gets stuck at this while loop.
And, the buffer_pos is *volatile* data type. So, no optimizations are done.

So, how do i solve this problem?
My question is: If the CPU is interrupted (IRQ1, Keyboard), does it stop executing *whatever* it is executing? i.e.: even an infinite looP?

Thanks!

PS:
I am using VMWare for testing.
Floppy image / an El-Torito bootable CD is used.
earlz

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by earlz »

that is very weird because that is exactly how my keyboard irq works. I noticed with some compilers that "char volatile" doesnt make it volatile but "volatile char" does.
if it helps any this is my keyboard irq and getkey

Code: Select all

volatile shift_locks shifts;
volatile unsigned int keycount=0;
volatile unsigned char keys[128];

unsigned char get_kbd_buffer(unsigned char *scan_buf,unsigned char *asc_buf){
   keycount--;
     *scan_buf=keys[keycount];
   keycount--;
   *asc_buf=keys[keycount];
   return *asc_buf;
}


char getkey(char *buf){ 
   //char tmp[1]; error! allocated on stack
   
   while(keycount==0){}
   get_kbd_buffer(&buf[0],&buf[1]);
   return buf[1];
}

void waitkey(){
   char tmp[1];
   while(keycount==0){}
   get_kbd_buffer(&tmp[0],&tmp[1]);
}

/*F6-F10 are reserved for window functions and are not useable in applications*/
extern int TextUI;
extern WINDOW mcon;
void kbd_handler(r){
   unsigned char scancode;unsigned char tmp;
   if (keycount==128){return 0;}
     scancode = inportb(0x60);
     if (scancode & 0x80) { //this i thought meant that the key was released
          switch (scancode) {
               case 42|0x80:
               shifts.shift=0;
               break;
               case 54|0x80:
               shifts.shift=0;
               break;
               case 29|0x80:
               shifts.ctrl=0;
               break;
               case 56|0x80:
               shifts.alt=0;
               break;
          }
     }else{

     switch (scancode){
        case 42: 
        shifts.shift=1;
        break;
        case 54:
        shifts.shift=1;
        break;
        case 29:
        shifts.ctrl=1;
        break;
        case 56:
          shifts.alt=1;
          break;
          case 58:
          shifts.caps=shifts.caps ^ 1;
          break;
          case 69:
          shifts.num=shifts.num ^ 1;
          break;
          case 70:
          shifts.scroll=shifts.scroll ^ 1;
          break;
          
     }
     if (TextUI==1){
        switch(scancode){
           case 0x40:
           cwin=def_console;
           break;
           case 0x41:
           cwin=&mcon;
           break;
           case 0x42:
           
           break;
           case 0x43:
           
           break;
           case 0x44:
           
           break;
        }
     }
          
     tmp=scan2asc(scancode);
     put_kbd_buffer(scancode,tmp);


     }
     
}
j.vimal

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by j.vimal »

Thanks.
I will try both
volatile char
and
char volatile

and check.
But, is it better to code the driver in assembly?
If i do it in assembly, do i need to specify like: extern kbd_driver blah blah in the C code? I hope the linker takes care of it.

But, then, I need to know the calling convention of C right? To know the parameters passed. I can return data, etc.

Thanks for your time though!

Vimal
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by Solar »

j.vimal wrote: My question is: If the CPU is interrupted (IRQ1, Keyboard), does it stop executing *whatever* it is executing? i.e.: even an infinite looP?
Yes.
I noticed with some compilers that "char volatile" doesnt make it volatile but "volatile char" does.
That would be a compiler bug. I wouldn't expect that to happen with e.g. GCC.
But, is it better to code the driver in assembly?
You might want to check out the FAQ on interrupt handlers and what to take care of if you want them written in C. (They require special return handling.)
If i do it in assembly, do i need to specify like: extern kbd_driver blah blah in the C code?
For any function you call in C, you should have a declaration, i.e. the function name, parameter list, and return type be written in a header file and included prior to using it. A function declaration is by default "extern", so you don't have to say so explicitly (except if you are coding C++, in which case you need [tt]extern "C"[/tt] to make the compiler use the C naming / calling convention.
But, then, I need to know the calling convention of C right?
Yes.
Every good solution is obvious once you've found it.
j.vimal_

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by j.vimal_ »

Ok.
Got the point.
This is the code I had... I didn't understand it quite well.

void kbd_interrupt()
{
   unsigned char kbd_ascii_code=0;
   disable();
outportb(0x20,0x20); //ack
   kbd_scancode = inportb(0x60);
.... rest of the handling code ....
...i.e choose the character
outportb(0x20,0x20);
   enable();
   interrupted = 1;
   asm("mov %ebp,%esp");
   asm("pop %ebp");
   asm("iret");      
}

So, this is the main problem? The last iret line?
But, I have not saved the initial stage... But ... ?
I dont get it!

:)

Vimal
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by Pype.Clicker »

asm("mov %ebp,%esp");
asm("pop %ebp");
asm("iret");
this is horrible black magic ... you shouldn't use that. consider writing a proper ISR stub that calls your C function instead. That should be easy to find in the FAQ.
http://www.osdev.org/osfaq2/
j.vimal_

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by j.vimal_ »

Exactly what I had thought. Thanks... I will let you all know if it works :)

Vimal
j.vimal_

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by j.vimal_ »

Hi all
Tried it... didn't work. Using Bochs now.
I had written the assembly wrapper, the calls are working fine... but the main problem now is that it again get stuck with the while loop / even the if conditions i had put.

Code: Select all

void kbd_interrupt()
{
   //our new Keyboard Interrupt
   unsigned char kbd_ascii_code=0;
   
   disable(); //Let an interrupt not interrupt another
   kbd_scancode = inportb(0x60);
   outportb(0x20,0x20); //Acknowledge it
   kbd_shift=0,kbd_caps=0;
   if(1/*!kbd_special(kbd_scancode)*/)
   {
      if(kbd_shift)
      {
         if(!kbd_caps)
            kbd_ascii_code = kbd_shifted[kbd_scancode];
         else
            kbd_ascii_code = kbd_caps_shifted[kbd_scancode];
      }
      else 
      {
         if(!kbd_caps)
            kbd_ascii_code = kbd_normal[kbd_scancode];
         else
            kbd_ascii_code = kbd_capsnormal[kbd_scancode];
      }
      
      if(kbd_buffer_pos != eob)
         kbd_buffer[kbd_buffer_pos++]=kbd_ascii_code;
      else
      {
         kbd_buffer[kbd_buffer_pos]  =kbd_ascii_code;
         kbd_buffer_pos=0;
      }
   }
   outportb(0x20,0x20);
   enable();
   kbd_flush_buffer(); //flush
   interrupted = 1;
}      

unsigned char kbd_getch()      // Waits for a key to enter the buffer and returns it
{
   int i = 0;
   //print((unsigned char *)"I am here");
   loop:
   if(interrupted == 0) goto loop;
   //print((unsigned char *)"Done!");
   interrupted=0;      
         
   disable(); //something in the buffer... Disable all other interrupts
   for(i=0; i < kbd_buffer_pos; i++)
   {
      kbd_buffer[i] = kbd_buffer[i + 1];
   }
   kbd_buffer_pos--; //immediately Shift the buffer back
   enable();
   
   return (unsigned char)kbd_buffer[0];
}
The "I am here" messages were for debugging. But, they didnt work. The while loop / if statement gets stuck...

Thanks for your time to help me out

Vimal
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by Pype.Clicker »

i see no definition of your "interrupted" variable. Make sure you declared it volatile: that's why that keyword exist :P
j.vimal_

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by j.vimal_ »

:)
interrupted is declared as unsigned volatile char

The only thing is that the CPU is NOT getting interrupted when the while loop is going on. Otherwise, its fine.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by Pype.Clicker »

disable() and enable() are not welcome in an interrupt handler. Make sure you used an interrupt gate in your IDT if that's not the case.

Have you tried setting a breakpoint in your ISR handler ? Can you confirm interrupts are enable()d in your main code ? Can you confirm the PIC (and more specifically its mask bits) have been correctly set up?
j.vimal

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by j.vimal »

So, I am NOT supposed to disable other interrupts at all?
The sad thing is that, the interrupt actually works if I remove the checking of the (kbd_buffer_pos). Thats what I dont understand. The assembler wrapper works perfectly.

and the Interrupted IS called if I remove the while loop (or if, jump).i didnt debug to check that, but I printed some message and it does print, only when the keyboard button is hit, which means its right. but, the while loop, lol. thats the main problem... :)
Its getting very very bugging. I might as well code it in assembly. Just waiting for that moment of 'truth' :)

Vimal
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by Pype.Clicker »

i think you should give us the declaration and initialization of any global variable you use aswell.

I think i can spot a mistake around here:

Code: Select all

- interrupt received, kp_buffer_pos == 0.
- decoded keystroke is stored in kb_buffer[0]
- interupted is set to 1, which "unlocks" the "goto loop" (i suppose the reason you're not using "while (!interrupted)" is just that you had trouble with it.
- getch() will now find kb_buffer_pos==1 and will do the "for" loop with i=0
- that means kb_buffer[0] <-- kb_buffer[1];
- and then you return kb_buffer[1] (which is likely to be zero unless you managed to receive two bytes.
Since you are more fluent in assembly than in C, i suggest you give a look at what the compiler produces to validate your assumptions on what it should produce.

e.g. "objdump -drS keyboard.o" might reveal you thing you haven't expected.
j.vimal

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by j.vimal »

Yes, that was a wrong code. I will look into that.
Also, I have attached the code for my kernel. kernel0.zip.
Please look into that code, if you have some free time.

Since I dont have internet at my house, I might take a while to reply! Sorry about that!

Vimal

PS: Also, I had checked the disassemlbled object code in a debugger. I find that the volatile is mainted... i.e. I found this:

Code: Select all

loc_sme number:
mov eax,ds:[some address of the kbd_buffer_pos]
cmp eax,0 ;or some equivalent of this.
je loc_sme number
So, no optimization was done.
j.vimal_

Re:Keyboard: Problem with the (re)programmed Interrupt handl

Post by j.vimal_ »

I have resolved this problem.
The assembly code produced was NOT

Code: Select all

cmp eax,1
But

Code: Select all

test eax,eax
Is this valid? Doesnt this always return TRUE?

That was the problem. Is this a bug? with gcc?

:)

Vimal
Post Reply