Page 1 of 1

[C++]Wrong keyboard scancodes (set 2) + IRQ1 didn't call

Posted: Thu Mar 06, 2014 9:41 am
by kubawal
Hi!

My problem is like that: I'm writing my first OS and currently i'm writing keyboard driver. It works properly, but when I turn scancodes into ASCII codes using scancode set 2, it was wrong. E.g when I type

Code: Select all

asdfghjkl[Enter]
it displays

Code: Select all

~~cxde43~w
(~ is key that is not defined in set 2). My function:

Code: Select all

char mosKbdToASCII( Key k, unsigned st ) // st - keyboard state bit enum
{
    const int maxKeynum = 0x66; // max implemented key
    if( st &( unsigned ) KbdState::Shift )
    {
        // with shift
        static char shiftMp[ maxKeynum + 1 ] =
        {
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, '\t', '~', 0, 0, 0, 0, 0,
            'Q', '!', 0, 0, 0, 'Z', 'S', 'A', 'W', '@',
            0, 0, 'C', 'X', 'D', 'E', '$', '#', 0, 0,
            ' ', 'V', 'F', 'T', 'R', '%', 0, 0, 'N',
            'B', 'H', 'G', 'Y', '^', 0, 0, 0, 'M', 'J',
            'U', '&', '*', 0, 0, '<', 'K', 'I', 'O', ')',
            '(', 0, 0, '>', '?', 'L', ':', 'P', '_', 0,
            0, 0, '\"', 0, '{', '+', 0, 0, 0, 0,
            '\n', '}', 0, '|', 0, 0, 0, 0, '\b'
        };
        if(( int ) k > maxKeynum + 1 )
             return 0;
        else
             return shiftMp[( int ) k ];
        
    }
    
    // normal   
    static char mp[ maxKeynum + 1 ] =
    {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, '\t', '`', 0, 0, 0, 0, 0,
        'q', '1', 0, 0, 0, 'z', 's', 'a', 'w', '2',
        0, 0, 'c', 'x', 'd', 'e', '4', '3', 0, 0,
        ' ', 'v', 'f', 't', 'r', '5', 0, 0, 'n',
        'b', 'h', 'g', 'y', '6', 0, 0, 0, 'm', 'j',
        'u', '7', '8', 0, 0, ',', 'k', 'i', 'o', '0',
        '9', 0, 0, '.', '/', 'l', ';', 'p', '-', 0,
        0, 0, '\'', 0, '[', '=', 0, 0, 0, 0,
        '\n', ']', 0, '\\', 0, 0, 0, 0, '\b',
    };
    
    
    
    if(( int ) k > maxKeynum + 1 )
         return 0;
    else
         return mp[( int ) k ];
    
}

// funcs to reading keys
Key mosReadKey()
{
    // mosReadKbd() gets key form keyboard without timeout
    // kbdBuf is simple queue
    if( kbdBuf.empty() ) // buffer is empty
    {
        Key k = mosReadKbd(); // mosReadKbd() wait until is any key is pressed and returns it
        while( !processKey( k ) || k == Key::None ) // processKey() support 'break' codes and keyboard states (e.g shift pressed), returns true if key can be gived to user
             k = mosReadKbd();
        
        return k;
    }
    else
         return kbdBuf.pop();
    
}

char mosReadChar() // simply read key and translate it into ASCII
{
    Key k = mosReadKey();
    return mosKbdToASCII( k, kbdSt );
}
And I've got second problem: when I trying to enable keyboard IRQ1, it doesn't call.

Code: Select all

// add record to IDT
#define _set_gate(gate_addr,type,dpl,addr) \
      __asm__ __volatile__("movw %%dx,%%ax\n\t" \
            "movw %0,%%dx\n\t" \
            "movl %%eax,%1\n\t" \
            "movl %%edx,%2\n\t" \
            : :"i"((short)(0x8000+(dpl<<13)+(type<<8))), \
              "o"(*((char *)(gate_addr))), \
              "o"(*(4+(char *)(gate_addr))), \
              "d"((char *)(addr)),"a"(0x00080000)) \
 	

void mosSetIntGate( int n, void * p ) // register interrupt
{
    _set_gate( & mosIDT[ n ], 14, 0, p );
}

// enable IRQ
void mosEnableIRQ( unsigned int num )
{
    unsigned int mask = ~( 1 << num );
    cached_irq_mask &= mask;
    if( irq & 8 ) {
        mosWritePort( cached_A1, 0xA1 );
    } else {
        mosWritePort( cached_21, 0x21 );
    }
}

#define ASMCALL extern "C" // to avoid c++ compiler name conversation


ASMCALL void doIrq1() // keyboard interrupt code
{
    Key k =( Key ) mosReadPort( KBD_DATA_PORT );
    if( processKey( k ) ) kbdBuf.push( k );
}

ASMCALL void irq1(); // asm interrupt function

void mosInitKbd()
{
    kbdSt = 0;
    while( !kbdBuf.empty() ) kbdBuf.pop(); // clear buffer
    
    mosSetIntGate( 0x21,( void * ) irq1 ); // set interrupt to propely address
    mosEnableIRQ( 1 );
}

Re: [C++]Wrong keyboard scancodes (set 2) + IRQ1 didn't call

Posted: Thu Mar 06, 2014 12:08 pm
by Gigasoft
You need to set the Controller Configuration Byte. It should be set to 7 to enable both IRQs and disable translation, which is what you probably want.

Code: Select all

_outp(0x64,0x60);
_outp(0x60,7);
By the way, having drivers install IDT entries directly might not be the best of ideas. In a multitasking system, an interrupt handler might wake up a higher priority thread, so you'll need to check for this after every interrupt, and you also need to keep track of whether you are already in an interrupt so you don't switch away from an executing interrupt handler, so there should be some system code that does all this without the involvement of driver code.

Re: [C++]Wrong keyboard scancodes (set 2) + IRQ1 didn't call

Posted: Fri Mar 07, 2014 9:42 am
by kubawal
I tried to this before i create this topic, and it's not working.
When I use this code i've got (for typing

Code: Select all

asdfghjkl
)

Code: Select all

wwaaeettyygguuii;;
(keys doubles)

Re: [C++]Wrong keyboard scancodes (set 2) + IRQ1 didn't call

Posted: Fri Mar 07, 2014 12:33 pm
by Combuster
keys doubles
That sounds like you're not separating up events from down events.

Re: [C++]Wrong keyboard scancodes (set 2) + IRQ1 didn't call

Posted: Sat Mar 08, 2014 5:09 am
by kubawal
i seperate this in mosProcessKey() (it returns true if key is pressed)

Re: [C++]Wrong keyboard scancodes (set 2) + IRQ1 didn't call

Posted: Sat Mar 08, 2014 5:43 am
by iansjack
Are you sure? You don't show us that function so it's not possible to check but iut certainly sounds logical that you are processing both key down and key up events.

Re: [C++]Wrong keyboard scancodes (set 2) + IRQ1 didn't call

Posted: Sat Mar 08, 2014 6:08 am
by Gigasoft
Your tables are wrong. The buffer mechanism is also highly suspicious. Implement a proper interrupt safe and blocking queue, and don't use std::queue. It comes as no surprise that data is being read twice or in the wrong order.

Re: [C++]Wrong keyboard scancodes (set 2) + IRQ1 didn't call

Posted: Sun Mar 09, 2014 7:27 am
by kubawal
Gigasoft wrote:and don't use std::queue. It comes as no surprise that data is being read twice or in the wrong order.
I use my implmentation of queue

Re: [C++]Wrong keyboard scancodes (set 2) + IRQ1 didn't call

Posted: Sun Mar 09, 2014 9:07 am
by iansjack
Another potential source of error that we can't really comment on as you haven't shown us the code. As you seem fairly sure that you know where the error doesn't lie perhaps it's time to do some debugging? That way you can narrow down the possibilities. Once you start debugging and gather some evidence it should be fairly simple to see what is causing this sort of error.

Re: [C++]Wrong keyboard scancodes (set 2) + IRQ1 didn't call

Posted: Mon Mar 10, 2014 9:43 am
by kubawal
Now it's OK, I simply use set 1. But it works only for my keyboard...