Autor Thema: IRQ1 / Tastatur funktioniert nicht?  (Gelesen 7325 mal)

Developer30

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« am: 04. August 2013, 12:57 »
Hallo  :-)

Ich möchte gerne Tastatureingaben mit dem IRQ1 abfangen. Dazu habe ich die PICs initialisiert und für jeden IRQ eine Funktion in der IDT eingetragen. Die Funktionen sind über den int Befehl auch alle erreichbar (d.h. meine IDT scheint schonmal korrekt zu sein).

Den PIC habe ich folgendermaßen initialisiert:

// Master-PIC initialisieren
outb(0x20, 0x11); // Initialisierungsbefehl fuer den PIC
outb(0x21, 0x20); // Interruptnummer fuer IRQ 0
outb(0x21, 0x04); // An IRQ 2 haengt der Slave
outb(0x21, 0x01); // ICW 4

// Slave-PIC initialisieren
outb(0xa0, 0x11); // Initialisierungsbefehl fuer den PIC
outb(0xa1, 0x28); // Interruptnummer fuer IRQ 8
outb(0xa1, 0x02); // An IRQ 2 haengt der Slave
outb(0xa1, 0x01); // ICW 4

// Interrupts verknüpfen
IDT::SetGate(0x20, _irq0, 0x08, 0x8E);
IDT::SetGate(0x21, _irq1, 0x08, 0x8E);
IDT::SetGate(0x22, _irq2, 0x08, 0x8E);
IDT::SetGate(0x23, _irq3, 0x08, 0x8E);
IDT::SetGate(0x24, _irq4, 0x08, 0x8E);
IDT::SetGate(0x25, _irq5, 0x08, 0x8E);
IDT::SetGate(0x26, _irq6, 0x08, 0x8E);
IDT::SetGate(0x27, _irq7, 0x08, 0x8E);
IDT::SetGate(0x28, _irq8, 0x08, 0x8E);
IDT::SetGate(0x29, _irq9, 0x08, 0x8E);
IDT::SetGate(0x2A, _irq10, 0x08, 0x8E);
IDT::SetGate(0x2B, _irq11, 0x08, 0x8E);
IDT::SetGate(0x2C, _irq12, 0x08, 0x8E);
IDT::SetGate(0x2D, _irq13, 0x08, 0x8E);
IDT::SetGate(0x2E, _irq14, 0x08, 0x8E);
IDT::SetGate(0x2F, _irq15, 0x08, 0x8E);

// Alle IRQs aktivieren (demaskieren)
outb(0x20, 0x0);
outb(0xa0, 0x0);

Anschließend lade ich die IDT und initialisiere dann die Tastatur:
// Tastaturpuffer leeren
while (inb(0x64) & 0x1)
    inb(0x60);

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

In meiner _irq1 Prozedur erzeuge ich eine Bildschirmausgabe, sodass ich ja sehen sollte, wenn eine Taste gedrückt wird. Außerdem lade ich mit inb(0x60) den Scancode und setze danach EOI für den IRQ1.

Wenn ich meinen Kernel mit bochs ausführe, dann erscheint zu beginn direkt einmal, dass eine Taste gedrückt wurde, obwohl ich noch gar nichts gedrückt habe. Wenn ich dann weitere Tasten auf der Tastatur drücke passiert nichts. Irgendwann steht dann auch in der bochs Konsole:

00103620000i[KBD  ] internal keyboard buffer full, ignoring scancode.(1e)
00105448000i[KBD  ] internal keyboard buffer full, ignoring scancode.(1f)
00106000000i[KBD  ] internal keyboard buffer full, ignoring scancode.(20)
00106516000i[KBD  ] internal keyboard buffer full, ignoring scancode.(9e)

Es ist mir bald schon peinlich, dass das, woran ich hier scheitere, auf der Tutorialseite mit einem Stern als "einfach" eingestuft wird. Ich hoffe dennoch auf Hilfe und Verständnis für Anfängerfehler.

lg
Developer30

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 04. August 2013, 13:33 »
Die Tastatur löst genau einen IRQ aus, wenn eine Taste gedrückt wurde. Danach schweigt sie, bis sie gefragt wurde.

Lies den Scancode in der ISR von der Tastatur, dann kommen auch wieder IRQs.

Developer30

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 04. August 2013, 14:27 »
Lies den Scancode in der ISR von der Tastatur, dann kommen auch wieder IRQs.

Bezwecke ich das nicht mit inb(0x60)?

In meiner _irq1 Prozedur erzeuge ich eine Bildschirmausgabe, sodass ich ja sehen sollte, wenn eine Taste gedrückt wird. Außerdem lade ich mit inb(0x60) den Scancode und setze danach EOI für den IRQ1.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 04. August 2013, 16:19 »
Sendest du nach der Bearbeitung des Keyboard-Interrupts auch ein EOI an den PIC? http://www.lowlevel.eu/wiki/PIC_Tutorial#ISRs_programmieren
Dieser Text wird unter jedem Beitrag angezeigt.

Developer30

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 04. August 2013, 16:50 »
Ja, ich sende ein EOI.

Ich habe mein kleines Projekt mal hochgeladen. Ich wäre sehr dankbar, wenn ihr eventuell selbst mal einen Blick in mein Code werfen könntet. Ich bin für (sonstige, stilistsiche) Verbesserungsvorschläge gerne offen und hoffe, dass der Fehler so besser gefunden werden kann.

Hier der Downloadlink: http://www.file-upload.net/download-7922666/os.tar.gz.html

lg
Developer30
« Letzte Änderung: 04. August 2013, 16:53 von Developer30 »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 04. August 2013, 17:05 »
Du musst Assembler-Stubs in die IDT eintragen. C-Funktionen (PIC::_irq0, etc...) gehen nicht. Der Grund dafür ist (unter anderem), dass du aus einem Interrupt mit dem Maschinenbefehl IRET zurückkehren musst, aber der C-Code verwendet RET. Wir haben dazu ein Tutorial, das GAS-Syntax verwendet, und ein etwas geschwätzigeres mit NASM-Syntax.
Dieser Text wird unter jedem Beitrag angezeigt.

Developer30

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 04. August 2013, 17:08 »
d.h. ich definiere in Assembler Labels, die ich dann über extern in C/C++ eintragen kann und rufe meine eigentliche C/C++ Funktion dann mit call auf? Habe ich das richtig verstanden?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 04. August 2013, 17:09 »
Jep.
Dieser Text wird unter jedem Beitrag angezeigt.

Developer30

  • Beiträge: 16
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 04. August 2013, 18:25 »
Ok, ich habe das mal so umgesetzt. Es funktioniert, wie zu erwarten war  :-)
Danke :wink:

 

Einloggen