next up previous contents index
Next: Symmetrical Multi-Processing Up: Interrupt Handlers Previous: Interrupt Handlers

    
Keyboards on the Intel Architecture

Warning: The rest of this chapter is completely Intel specific. If you're not running on an Intel platform, it will not work. Don't even try to compile the code here.

I had a problem with writing the sample code for this chapter. On one hand, for an example to be useful it has to run on everybody's computer with meaningful results. On the other hand, the kernel already includes device drivers for all of the common devices, and those device drivers won't coexist with what I'm going to write. The solution I've found was to write something for the keyboard interrupt, and disable the regular keyboard interrupt handler first. Since it is defined as a static symbol in the kernel source files (specifically, drivers/char/keyboard.c), there is no way to restore it. Before insmod'ing this code, do on another terminal sleep 120 ; reboot if you value your file system.

This code binds itself to IRQ 1, which is the IRQ of the keyboard controlled under Intel architectures. Then, when it receives a keyboard interrupt, it reads the keyboard's status (that's the purpose of the inb(0x64)) and the scan code, which is the value returned by the keyboard. Then, as soon as the kernel think it's feasible, it runs got_char which gives the code of the key used (the first seven bits of the scan code) and whether it has been pressed (if the 8th bit is zero) or released (if it's one).  

ex intrpt.c   

 
/* intrpt.c - An interrupt handler. */


/* Copyright (C) 1998 by Ori Pomerantz */



/* The necessary header files */

/* Standard in kernel modules */
#include <linux/kernel.h>   /* We're doing kernel work */
#include <linux/module.h>   /* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif        

#include <linux/sched.h>
#include <linux/tqueue.h>

/* We want an interrupt */
#include <linux/interrupt.h>

#include <asm/io.h>


/* Bottom Half - this will get called by the kernel as soon as it's safe to
 * do everything normally allowed by kernel modules. */
static void got_char(void *scancode)
{
  printk("Scan Code %x %s.\n",
    (int) *((char *) scancode) & 0x7F,
    *((char *) scancode) & 0x80 ? "Released" : "Pressed");
}


/* This function services keyboard interrupts. It reads the relevant information
 * from the keyboard and then scheduales the bottom half to run when the kernel
 * considers it safe. */
void irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
  /* This variables are static because they need to be accessible (through 
   * pointers) to the bottom half routine. */
  static unsigned char scancode;
  static struct tq_struct task = {NULL, 0, got_char, &scancode};
  unsigned char status;

  /* Read keyboard status */
  status = inb(0x64);
  scancode = inb(0x60);
  
  /* Scheduale bottom half to run */
  queue_task_irq(&task, &tq_immediate);
  mark_bh(IMMEDIATE_BH);
}



/* Initialize the module - register the IRQ handler */
int init_module()
{
  /* Since the keyboard handler won't co-exist with another handler,
   * such as us, we have to disable it (free its IRQ) before we do anything.
   * Since we don't know where it is, there's no way to reinstate it later -
   * so the computer will have to be rebooted when we're done.
   */
  free_irq(1, NULL);

  /* Request IRQ 1, the keyboard IRQ, to go to our irq_handler. */
  return request_irq(1,            /* The number of the keyboard IRQ on PCs */ 
                     irq_handler,  /* our handler */
                     SA_SHIRQ, /* SA_SHIRQ means we're willing to have other
                                * handlers on this IRQ.
                                *
				* SA_INTERRUPT can be used to make the
				* handler into a fast interrupt. 
				*/
		     "test_keyboard_irq_handler", NULL);
}


/* Cleanup */
void cleanup_module()
{
  /* This is only here for completeness. It's totally irrelevant, since we
   * don't have a way to restore the normal keyboard interrupt so the computer
   * is completely useless and has to be rebooted. */
  free_irq(1, NULL);
}


next up previous contents index
Next: Symmetrical Multi-Processing Up: Interrupt Handlers Previous: Interrupt Handlers
Ori Pomerantz
1999-03-20