Autor Thema: Keyboard Controller - register_intr_handler?  (Gelesen 5018 mal)

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« am: 01. February 2013, 14:48 »
Beim Tutorial im Wiki, wie man auf die Tastatur zugreift, wird die Funktion register_intr_handler genutzt... Ich weiß allerdings nicht, was diese anstellen soll, wenn man im Wiki danach sucht, ist das Keyboard Controller-Tutorial das einzige Ergebnis... :S

Könnt ihr mir helfen?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 01. February 2013, 16:28 »
Das Tutorial erwartet, dass du ein Array mit Funktionszeigern hast, in das die Handler eingetragen werden. Wenn ein IRQ auftritt, kann die handle_interrupt-Methode dann in dem Array nachschauen, ob ein Handler eingetragen wurde (Zeiger != NULL), und wenn ja, kann sie die Funktion aufrufen.

Die Methode register_intr_handler trägt den angebenen Handler an den entsprechenden Index ein. (Vielleicht sollte man da 1 statt IRQ_BASE + 1 nehmen.)

Wenn dir das zu kompliziert ist, nennst du die irq_handler-Methode keyboard_irq_handler oder so und schreibst in die handle_interrupt-Methode einfach if (cpu->intr == 0x21) { keyboard_irq_handler(); }. Das ist dann nicht so dynamisch, aber reicht auch fürs erste.
Dieser Text wird unter jedem Beitrag angezeigt.

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 01. February 2013, 16:56 »
Hmm okay, ich hab es jetzt so gemacht:

keyboard.c
void init_keyboard(void);
static void keyboard_command(uint8_t command);
void keyboard_interrupt(void);

void init_keyboard(void)
{
    // Tastaturpuffer leeren
    while (inb(0x64) & 0x1) {
        inb(0x60);
    }   
 
    // Tastatur aktivieren
    keyboard_command(0xF4);

}
 
static void keyboard_command(uint8_t command)
{
    // Warten bis die Tastatur bereit ist, und der Befehlspuffer leer ist
    while ((inb(0x64) & 0x2)) {}
    outb(0x60, command);
}

void keyboard_interrupt(void){
echo("keyboard interrupt");
}

handle_interrupt
void handle_interrupt(struct cpu_state* cpu)
{
echo("interrupt");
if (cpu->intr == 0x21) {
keyboard_interrupt();
}
    else if (cpu->intr <= 0x1f) {
echo("%c SYSTEMFEHLER\n%c\n Exception %d\n ...\n ...\n ...\n ...\n\n%c", 0xC0, 0x4F, cpu->intr, screenDefaultColor);

        // TODO Hier den CPU-Zustand ausgeben

        while(1) {
            // Prozessor anhalten
            asm volatile("cli; hlt");
        }
    } else if (cpu->intr >= 0x20 && cpu->intr <= 0x2f) {
        if (cpu->intr >= 0x28) {
            // EOI an Slave-PIC
            outb(0xa0, 0x20);
        }
        // EOI an Master-PIC
        outb(0x20, 0x20);
    } else {
        echo("Unbekannter Interrupt");
        while(1) {
            // Prozessor anhalten
            asm volatile("cli; hlt");
        }
    }
}
Es kommt aber nur am Anfang, als init_keyboard ausgeführt wird, einmal "keyboard interrupt" in der konsole, wenn ich dann Tasten drücke, passiert nichts...

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 01. February 2013, 16:58 »
Du musst auch noch den IRQ beim PIC mit einem EOI bestätigen, sonst schickt er keine weiteren IRQs. Am besten verschiebst du if (cpu->intr == 0x21) ... direkt über das if (cpu->intr >= 0x28) {.
Dieser Text wird unter jedem Beitrag angezeigt.

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 01. February 2013, 17:04 »
void handle_interrupt(struct cpu_state* cpu)
{
echo("interrupt");
    if (cpu->intr <= 0x1f) {
echo("%c SYSTEMFEHLER\n%c\n Exception %d\n ...\n ...\n ...\n ...\n\n%c", 0xC0, 0x4F, cpu->intr, screenDefaultColor);

        // TODO Hier den CPU-Zustand ausgeben

        while(1) {
            // Prozessor anhalten
            asm volatile("cli; hlt");
        }
    } else if (cpu->intr >= 0x20 && cpu->intr <= 0x2f) {
if (cpu->intr == 0x21) {
keyboard_interrupt();
}
        if (cpu->intr >= 0x28) {
            // EOI an Slave-PIC
            outb(0xa0, 0x20);
        }
        // EOI an Master-PIC
        outb(0x20, 0x20);
    } else {
        echo("Unbekannter Interrupt");
        while(1) {
            // Prozessor anhalten
            asm volatile("cli; hlt");
        }
    }
}
So klappt es leider auch nicht :( :(

Was mache ich falsch?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 01. February 2013, 17:09 »
Oh ganz vergessen: Du musst im Handler auch den Scancode vom Tastaturcontroller auslesen, sonst sendet er ebenfalls keine Interrupts mehr.
int scancode = inb(0x60);
Dieser Text wird unter jedem Beitrag angezeigt.

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 01. February 2013, 17:17 »
OK, sieht jetzt so aus:
void init_keyboard(void);
static void keyboard_command(uint8_t command);
void keyboard_interrupt(void);

void init_keyboard(void)
{
    // Tastaturpuffer leeren
    while (inb(0x64) & 0x1) {
        inb(0x60);
    }   
 
    // Tastatur aktivieren
    keyboard_command(0xF4);

}
 
static void keyboard_command(uint8_t command)
{
    // Warten bis die Tastatur bereit ist, und der Befehlspuffer leer ist
    while ((inb(0x64) & 0x2)) {}
    outb(0x60, command);
}

void keyboard_interrupt(void){
int scancode = inb(0x60);
echo("keyboard interrupt %x",scancode);
}
Klappt aber nicht, nur sehe ich jetzt, dass der erste (und einzige) Interrupt den scancode 250 oder 0xfa hat, aber beim Drücken von Tasten passiert immer noch nichts :(

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 01. February 2013, 17:19 »
Ich bin hier jetzt am raten: Nimm mal das keyboard_command(0xF4); raus.
Dieser Text wird unter jedem Beitrag angezeigt.

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 01. February 2013, 17:23 »
Klappt leider nicht, jetzt ist zwar der erste Interrupt weg, aber es folgt auch keiner...  :cry:

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 01. February 2013, 17:27 »
Hast du am Ende deiner init-Methode eine Endlosschleife? Da brauchst du eine. Diese Methode darf nämlich nicht zurückkehren, weil in start.S (von vor ein paar Tagen) die Interrupts deaktiviert werden:

    // Falls wir jemals aus init zurueckkommen sollten, sperren wir die Interrupts und
    // halten einfach den Prozessor an. (man braucht ihn ja nicht unnötig heißlaufen lassen.)
_stop:
    cli
    hlt
Dieser Text wird unter jedem Beitrag angezeigt.

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 01. February 2013, 17:32 »
Aha!

Ich hab mal eine eingebaut!

Egal, ob ich keyboard_command(0xF4); drin habe oder nicht, es kommen ständig interrupts mit cpu->intr = 0x20 (nicht 0x21)... die spammen jetzt quasi permanent die konsole zu.

aber immerhin passiert etwas!

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 01. February 2013, 17:38 »
Die Interrupts kommen vom Timer (PIT). Standardmäßig ca. alle 55 ms.
Dieser Text wird unter jedem Beitrag angezeigt.

KtmnjjpfjsFvzG

  • Beiträge: 111
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 01. February 2013, 17:50 »
Geil, Timer-Interrupts werden jetzt einfach nicht mehr ausgegeben, deshalb spammen die nicht mehr, und jetzt kann ich die vom Keyboard sehen!

Klappt also alles!

Dann bau ich mir mal so eine translate_scancode-Funktion, hoffe ich hab da keinen Denkfehler drin: Ich drücke einfach jede Taste einmal und notiere mir den Scancode und baue dann einen Array mit den passenden buchstaben etc...

Danke erstmal auf jeden Fall!  :-D :-D :-) 8-)

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 01. February 2013, 17:56 »
Wenn dir das nicht zu aufwändig ist, kannst du das so machen. Ansonsten müssten glaube ich diese Scancodes passen: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html#ss1.4
Dieser Text wird unter jedem Beitrag angezeigt.

mineorbit

  • Beiträge: 55
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 26. May 2013, 17:46 »
Wie hast du am Ende das Problem gelöst?
Kannst du den Code posten?
Das wäre sehr nett,
Mineorbit

 

Einloggen