OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 12:37 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: Enabling keyboard
PostPosted: Fri Dec 28, 2018 1:49 am 
Offline

Joined: Wed Nov 07, 2018 10:15 am
Posts: 23
Hi.
I already implemented some subsystem of my kernel (without memory allocation, timer support, etc.). My build system allows to select, which drivers to compile with kernel - it append -DMODULE_mname_NUMBER=number to gcc parameters, so I can do checking if driver is compiled. It also supports GNU Grub modules, so GRUB can load for example LANG_en_GB_map or LANG_pl_PL_map to kernel and message driver (if compiled) can use it, so you can enable kernel messages during compile time and select language of kernel messages, when system is loading.

But.. There's no many device drivers. I have only module to support text video mode (writing a string to screen) and x86 driver. I cannot implement either keyboard support.

There's my x86 driver code:
Code:
#include "x86.h"
#include "objects.h"

void do_after_modules_loaded(char (*handler)(void *,struct drivers*, int driver_count));
struct git_entry interrupts[256];
struct git_header int_info;

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))

static int set_interrupt(int number, int csel, void *fnc)
{
 
  interrupts[number].addr_lower = (int)fnc & 0xffff;
  interrupts[number].addr_higher = ((int)fnc >> 16) & 0xffff;
  interrupts[number].mesh = 0;
  interrupts[number].flags = INT_DESC_BITS32 | INT_DESC_RING0 | INT_DESC_PRESENT;
  interrupts[number].sel_number = csel;
 
  return 1;
}

static struct driver_export_table robjects[] = {
 
  {1, (struct api_version_export[]) {
    {
      "processor",  0, 0, 1,
      1, (struct driver_symbol[]) {
        {"create_ide", parameter_int, parameter_int parameter_int parameter_function, set_interrupt},
      }
    }
  }
  }
};

void(*print_fnc)(void *,const char *);
void *print_module_addr;

void real_keyboard_interrupt()
{
  if (0 != print_fnc) {
 
    print_fnc(print_module_addr, "PRZYCISK ");
  }
}

extern void keyboard_interrupt(void);
extern void default_interrupt(void);

__asm__  (".global keyboard_interrupt\n"
"keyboard_interrupt:\n"
"cli\n"
"cld\n"
"pusha\n"
"call real_keyboard_interrupt\n"
"mov $32, %al\n"
"out %al, $160 \n"
"out %al, $32\n"
"popa\n"
"sti\n"
"iret");

__asm__ (".global default_interrupt\n"
"default_interrupt:\n"
"cli\n"
"pusha\n"
"mov $32, %al\n"
"out %al, $160\n"
"out %al, $32\n"
"popa\n"
"sti\n"
"iret");
static char init;

static char interrupts_init(void *mesh,struct drivers*drivers, int driver_count)
{
  int csel = 16;
 
  struct object *obj = ((struct object * (*)(const char *))drivers[DRIVER_objects_NUMBER].get_export_tables()->api_version_exports->symbols[0].procedure)("console_service");
 
  if (0 != obj) {
   
    print_module_addr = obj->owner;
    print_fnc = (void(*)(void *,const char *)) obj->exports->api_version_exports[0].symbols[0].procedure;
   
    set_interrupt(33, csel, keyboard_interrupt);
   
  }
 
  write_port(100,  0xae);
 
  write_port(33, 0xFD);

  __asm__ __volatile__ ("sti");
}

struct driver_export_table *driver_x86_init()
{

  if (0 == init) {
    int i;
 
    int_info.size = sizeof(interrupts) - 1;
    //int_info.size = 255;//sizeof(interrupts) - sizeof(interrupts[0]);
    int_info.ptr = &interrupts;
   
    int csel = 16;
       
    for (i = 0; i < ARRAY_SIZE(interrupts); ++i) {

      set_interrupt(i, csel, default_interrupt);
    }
   
    ++init;
   
    __asm__ __volatile__ ("lidt (int_info)":: :);
    write_port(32, 17);
    write_port(160, 17);
   
    write_port(33, 32);
    write_port(161, 40);
   
    write_port(33, 4);
    write_port(161, 2);
   
    write_port(33, 1);
    write_port(161, 1);
   
    write_port(33, 0xFF);
    write_port(161, 0xFF);

    do_after_modules_loaded(interrupts_init);
  }

  return robjects;
}


I have read to enable keyboard and keyboard interrupt, I have to write 0xae to 0x64 port. But I also read keyboard controller will suggest processor to run interrupt handler, when keyboard buffer is full. Is that true? Is that means I must first implement clock controller support and watch the buffer changes after some time and again?

Thanks!


Top
 Profile  
 
 Post subject: Re: Enabling keyboard
PostPosted: Fri Dec 28, 2018 4:47 am 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1593
Wow, you are doing port I/O in decimal? More power to you, but most people won't like that.

You are currently neglecting to check for spurious IRQs in the handlers for IRQ 7 and 15 (read the wiki and the 8259 data sheet if you want to know more). Also, you are sending EOI to the second PIC even for low IRQs. This means that if a high IRQ arrives while a low IRQ is being handled, you will miss the high IRQ.

As to your question: You typically don't need to send any command to the 8042 to enable the keyboard. The BIOS will have done it for you already and will have had no reason to disable it. Your bootloader might disable the keyboard for the A20 stuff, but GRUB will reenable the keyboard afterwards.

In the event of the keyboard being disabled, then yes, you do need to send 0xae to the keyboard port to enable processing again.

They keyboard itself will only send a byte over the wire (OK, or two) if a button is pressed. The keyboard controller will then raise an interrupt line. On a PC this will assert IRQ 1. You then need to read the data port to get the data byte the keyboard sent you. You will get a separate IRQ for each byte. You might want to turn these bytes into a standardized representation for keycodes. but this will only get you a keycode (e.g. "button number 21 pressed") and not the thing on the keycap (e.g. "Y"). This is because you will get the same keycodes for different keycaps on international keyboards. The sixth button in the first row of letters gets you keycode 21 on both American and German keyboards, but the American one has a Y there and the German one a Z.

On to the next question: No, you don't need any "clock controller" support. The 8042 will handle its clocks all by itself. You only need to react to IRQ 1 by reading out the keycode, maybe changing the shift state of an internal state machine, and maybe, if your code is very advanced, waking up any process waiting for keyboard input. The wiki has good ressources for this endeavor.

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: Enabling keyboard
PostPosted: Fri Dec 28, 2018 3:27 pm 
Offline

Joined: Wed Nov 07, 2018 10:15 am
Posts: 23
I have rewrite some code, creating interrupts handlers for pic1 and pic2. These handlers supports fake interrupts provided by PIC. If I set all interrupts to be handled by keyboard handler, it works (but I don't known if the keyboard interrupt is handled). If I set default_handler, pic1_handler and pic2_handler for all interrupts, but no keyboard, the keyboard interrupt handler isn't called.

When writing this post I discover maybe should I enable IRQ7 and IRQ15?

Anyway - I found this on the network - https://stackoverflow.com/questions/431 ... ssor-error
There exist a post telling grub messed up with GDT and I must recreate it from scratch. Before I write first post in this topic, I thought about creating custom GDT, but read about code selector and decided to have fun with my code - I discovered that I can use 16 value as an selector. Because some interrupt was fired, when I set keyboard_handler for all interrupt, I think I don't have to recreate GDT.
I know GDT is basics, because it is probably needed for mutitasking, but I decided to write support for it after write other things, especially I decided to add WebAssembly VM as an module, so user could decide to not use normal programs.


Top
 Profile  
 
 Post subject: Re: Enabling keyboard
PostPosted: Fri Dec 28, 2018 3:46 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5099
nintyfan wrote:
I have rewrite some code, creating interrupts handlers for pic1 and pic2. These handlers supports fake interrupts provided by PIC. If I set all interrupts to be handled by keyboard handler, it works (but I don't known if the keyboard interrupt is handled). If I set default_handler, pic1_handler and pic2_handler for all interrupts, but no keyboard, the keyboard interrupt handler isn't called.

Set IRQ1 to the keyboard handler. Set IRQ7 and IRQ15 to the spurious IRQ handler. If you enable any other IRQs, set up handlers for those too.

nintyfan wrote:
When writing this post I discover maybe should I enable IRQ7 and IRQ15?

No. Leave those disabled until you want to receive IRQs from the attached hardware. You'll still receive spurious IRQs.

nintyfan wrote:
Because some interrupt was fired, when I set keyboard_handler for all interrupt, I think I don't have to recreate GDT.

No. GRUB's GDT can change without warning. You need to set up your own GDT.


Top
 Profile  
 
 Post subject: Re: Enabling keyboard
PostPosted: Sat Dec 29, 2018 10:43 am 
Offline

Joined: Wed Nov 07, 2018 10:15 am
Posts: 23
Thanks.

Main problem was in write_port macrodefinition. I've write ax into port. After changing this everything worked, but still scancodes should been translated into keys. I don't know what causes my bug in emulator and I don't know what it can do on real hardware.

End of topic :-) .
Thank you.


Top
 Profile  
 
 Post subject: Re: Enabling keyboard
PostPosted: Sun Dec 30, 2018 12:35 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 671
Small FYI: This
Code:
__asm__ __volatile__ ("lidt (int_info)":: :);
is frowned upon and discouraged by the GCC documentation. Using global variables by name inside inline assembly can cause the compiler to not realize it is being referenced.If you turn on optimizations you could run into problems. You also can't pass a structure defined on the stack. It is better to do it this way:
Code:
__asm__ __volatile__ ("lidt int_info"::"m"(int_info));
. Inline assembly can cause hard to find bugs at times, and it is hard to get right


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot], Sa41848 and 81 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group