Index: kernel/arch/sparc64/include/drivers/kbd.h
===================================================================
--- kernel/arch/sparc64/include/drivers/kbd.h	(revision 7dcf22a389ae4373e29fc2686bf9bae2ac3a8d39)
+++ kernel/arch/sparc64/include/drivers/kbd.h	(revision 63530c623718a69d8b980518b5dec7e17f4d991d)
@@ -47,6 +47,4 @@
 extern kbd_type_t kbd_type;
 
-extern volatile uint8_t *kbd_virt_address;
-
 extern void kbd_init(ofw_tree_node_t *node);
 
Index: kernel/arch/sparc64/include/drivers/ns16550.h
===================================================================
--- kernel/arch/sparc64/include/drivers/ns16550.h	(revision 7dcf22a389ae4373e29fc2686bf9bae2ac3a8d39)
+++ kernel/arch/sparc64/include/drivers/ns16550.h	(revision 63530c623718a69d8b980518b5dec7e17f4d991d)
@@ -51,42 +51,48 @@
 #define LCR_DLAB	0x80	/** Divisor Latch Access bit. */
 
-static inline uint8_t ns16550_rbr_read(void)
+/** Structure representing the ns16550 device. */
+typedef struct {
+	devno_t devno;
+	volatile uint8_t *reg;	/** Memory mapped registers of the ns16550. */
+} ns16550_t;
+
+static inline uint8_t ns16550_rbr_read(ns16550_t *dev)
 {
-	return kbd_virt_address[RBR_REG];
+	return dev->reg[RBR_REG];
 }
 
-static inline uint8_t ns16550_ier_read(void)
+static inline uint8_t ns16550_ier_read(ns16550_t *dev)
 {
-	return kbd_virt_address[IER_REG];
+	return dev->reg[IER_REG];
 }
 
-static inline void ns16550_ier_write(uint8_t v)
+static inline void ns16550_ier_write(ns16550_t *dev, uint8_t v)
 {
-	kbd_virt_address[IER_REG] = v;
+	dev->reg[IER_REG] = v;
 }
 
-static inline uint8_t ns16550_iir_read(void)
+static inline uint8_t ns16550_iir_read(ns16550_t *dev)
 {
-	return kbd_virt_address[IIR_REG];
+	return dev->reg[IIR_REG];
 }
 
-static inline void ns16550_fcr_write(uint8_t v)
+static inline void ns16550_fcr_write(ns16550_t *dev, uint8_t v)
 {
-	kbd_virt_address[FCR_REG] = v;
+	dev->reg[FCR_REG] = v;
 }
 
-static inline uint8_t ns16550_lcr_read(void)
+static inline uint8_t ns16550_lcr_read(ns16550_t *dev)
 {
-	return kbd_virt_address[LCR_REG];
+	return dev->reg[LCR_REG];
 }
 
-static inline void ns16550_lcr_write(uint8_t v)
+static inline void ns16550_lcr_write(ns16550_t *dev, uint8_t v)
 {
-	kbd_virt_address[LCR_REG] = v;
+	dev->reg[LCR_REG] = v;
 }
 
-static inline uint8_t ns16550_lsr_read(void)
+static inline uint8_t ns16550_lsr_read(ns16550_t *dev)
 {
-	return kbd_virt_address[LSR_REG];
+	return dev->reg[LSR_REG];
 }
 
Index: kernel/arch/sparc64/include/drivers/z8530.h
===================================================================
--- kernel/arch/sparc64/include/drivers/z8530.h	(revision 7dcf22a389ae4373e29fc2686bf9bae2ac3a8d39)
+++ kernel/arch/sparc64/include/drivers/z8530.h	(revision 63530c623718a69d8b980518b5dec7e17f4d991d)
@@ -92,5 +92,11 @@
 #define RR0_RCA		(0x1<<0)	/** Receive Character Available. */
 
-static inline void z8530_write(index_t chan, uint8_t reg, uint8_t val)
+/** Structure representing the z8530 device. */
+typedef struct {
+	devno_t devno;
+	volatile uint8_t *reg;		/** Memory mapped registers of the z8530. */
+} z8530_t;
+
+static inline void z8530_write(z8530_t *dev, index_t chan, uint8_t reg, uint8_t val)
 {
 	/*
@@ -98,18 +104,18 @@
 	 * command as their bit 3 is 1.
 	 */
-	kbd_virt_address[WR0+chan] = reg;	/* select register */
-	kbd_virt_address[WR0+chan] = val;	/* write value */
+	dev->reg[WR0+chan] = reg;	/* select register */
+	dev->reg[WR0+chan] = val;	/* write value */
 }
 
-static inline void z8530_write_a(uint8_t reg, uint8_t val)
+static inline void z8530_write_a(z8530_t *dev, uint8_t reg, uint8_t val)
 {
-	z8530_write(Z8530_CHAN_A, reg, val);
+	z8530_write(dev, Z8530_CHAN_A, reg, val);
 }
-static inline void z8530_write_b(uint8_t reg, uint8_t val)
+static inline void z8530_write_b(z8530_t *dev, uint8_t reg, uint8_t val)
 {
-	z8530_write(Z8530_CHAN_B, reg, val);
+	z8530_write(dev, Z8530_CHAN_B, reg, val);
 }
 
-static inline uint8_t z8530_read(index_t chan, uint8_t reg) 
+static inline uint8_t z8530_read(z8530_t *dev, index_t chan, uint8_t reg) 
 {
 	/*
@@ -117,15 +123,15 @@
 	 * command as their bit 3 is 1.
 	 */
-	kbd_virt_address[WR0+chan] = reg;	/* select register */
-	return kbd_virt_address[WR0+chan];
+	dev->reg[WR0+chan] = reg;	/* select register */
+	return dev->reg[WR0+chan];
 }
 
-static inline uint8_t z8530_read_a(uint8_t reg)
+static inline uint8_t z8530_read_a(z8530_t *dev, uint8_t reg)
 {
-	return z8530_read(Z8530_CHAN_A, reg);
+	return z8530_read(dev, Z8530_CHAN_A, reg);
 }
-static inline uint8_t z8530_read_b(uint8_t reg)
+static inline uint8_t z8530_read_b(z8530_t *dev, uint8_t reg)
 {
-	return z8530_read(Z8530_CHAN_B, reg);
+	return z8530_read(dev, Z8530_CHAN_B, reg);
 }
 
Index: kernel/arch/sparc64/src/drivers/kbd.c
===================================================================
--- kernel/arch/sparc64/src/drivers/kbd.c	(revision 7dcf22a389ae4373e29fc2686bf9bae2ac3a8d39)
+++ kernel/arch/sparc64/src/drivers/kbd.c	(revision 63530c623718a69d8b980518b5dec7e17f4d991d)
@@ -50,9 +50,5 @@
 #include <print.h>
 
-volatile uint8_t *kbd_virt_address = NULL;
-
 kbd_type_t kbd_type = KBD_UNKNOWN;
-
-static irq_t kbd_irq;
 
 /** Initialize keyboard.
@@ -103,7 +99,6 @@
 	uintptr_t pa;
 	size_t size;
-	int inr;
-	
-	irq_initialize(&kbd_irq);
+	inr_t inr;
+	devno_t devno = device_assign_devno();
 	
 	switch (kbd_type) {
@@ -117,11 +112,4 @@
 			printf("Failed to determine keyboard interrupt.\n");
 			return;
-		} else {
-			kbd_irq.inr = inr;
-			kbd_irq.devno = device_assign_devno();
-			kbd_irq.trigger = IRQ_TRIGGER_LEVEL;
-			kbd_irq.claim = z8530_claim;
-			kbd_irq.handler = z8530_irq_handler;
-			irq_register(&kbd_irq);
 		}
 		break;
@@ -136,12 +124,5 @@
 			printf("Failed to determine keyboard interrupt.\n");
 			return;
-		} else {
-			kbd_irq.inr = inr;
-			kbd_irq.devno = device_assign_devno();
-			kbd_irq.trigger = IRQ_TRIGGER_LEVEL;
-			kbd_irq.claim = ns16550_claim;
-			kbd_irq.handler = ns16550_irq_handler;
-			irq_register(&kbd_irq);
-		}
+		};
 		break;
 
@@ -158,15 +139,15 @@
 	aligned_addr = ALIGN_DOWN(pa, PAGE_SIZE);
 	offset = pa - aligned_addr;
-	kbd_virt_address = (uint8_t *) hw_map(aligned_addr, offset + size) + offset;
+	uintptr_t vaddr = hw_map(aligned_addr, offset + size) + offset;
 
 	switch (kbd_type) {
 #ifdef CONFIG_Z8530
 	case KBD_Z8530:
-		z8530_init();
+		z8530_init(devno, inr, vaddr);
 		break;
 #endif
 #ifdef CONFIG_NS16550
 	case KBD_NS16550:
-		ns16550_init();
+		ns16550_init(devno, inr, vaddr);
 		break;
 #endif
Index: kernel/genarch/include/kbd/ns16550.h
===================================================================
--- kernel/genarch/include/kbd/ns16550.h	(revision 7dcf22a389ae4373e29fc2686bf9bae2ac3a8d39)
+++ kernel/genarch/include/kbd/ns16550.h	(revision 63530c623718a69d8b980518b5dec7e17f4d991d)
@@ -41,5 +41,5 @@
 #include <ddi/irq.h>
 
-extern void ns16550_init(void);
+extern void ns16550_init(devno_t devno, inr_t inr, uintptr_t vaddr);
 extern void ns16550_poll(void);
 extern void ns16550_grab(void);
Index: kernel/genarch/include/kbd/z8530.h
===================================================================
--- kernel/genarch/include/kbd/z8530.h	(revision 7dcf22a389ae4373e29fc2686bf9bae2ac3a8d39)
+++ kernel/genarch/include/kbd/z8530.h	(revision 63530c623718a69d8b980518b5dec7e17f4d991d)
@@ -43,5 +43,5 @@
 extern bool z8530_belongs_to_kernel;
 
-extern void z8530_init(void);
+extern void z8530_init(devno_t devno, inr_t inr, uintptr_t vaddr);
 extern void z8530_poll(void);
 extern void z8530_grab(void);
Index: kernel/genarch/src/kbd/ns16550.c
===================================================================
--- kernel/genarch/src/kbd/ns16550.c	(revision 7dcf22a389ae4373e29fc2686bf9bae2ac3a8d39)
+++ kernel/genarch/src/kbd/ns16550.c	(revision 63530c623718a69d8b980518b5dec7e17f4d991d)
@@ -1,4 +1,4 @@
 /*
- * Copyright (C) 2001-2004 Jakub Jermar
+ * Copyright (C) 2001-2006 Jakub Jermar
  * All rights reserved.
  *
@@ -53,4 +53,10 @@
 #define LSR_DATA_READY	0x01
 
+/** Structure representing the ns16550. */
+static ns16550_t ns16550;
+
+/** Structure for ns16550's IRQ. */
+static irq_t ns16550_irq;
+
 /*
  * These codes read from ns16550 data register are silently ignored.
@@ -82,6 +88,11 @@
 }
 
-/** Initialize ns16550. */
-void ns16550_init(void)
+/** Initialize ns16550.
+ *
+ * @param devno Device number.
+ * @param inr Interrupt number.
+ * @param vaddr Virtual address of device's registers.
+ */
+void ns16550_init(devno_t devno, inr_t inr, uintptr_t vaddr)
 {
 	ns16550_grab();
@@ -89,12 +100,23 @@
 	stdin = &kbrd;
 	
+	ns16550.devno = devno;
+	ns16550.reg = (uint8_t *) vaddr;
+	
+	irq_initialize(&ns16550_irq);
+	ns16550_irq.devno = devno;
+	ns16550_irq.inr = inr;
+	ns16550_irq.claim = ns16550_claim;
+	ns16550_irq.handler = ns16550_irq_handler;
+	irq_register(&ns16550_irq);
+	
 	sysinfo_set_item_val("kbd", NULL, true);
-	sysinfo_set_item_val("kbd.irq", NULL, 0);
-	sysinfo_set_item_val("kbd.address.virtual", NULL, (uintptr_t) kbd_virt_address);
+	sysinfo_set_item_val("kbd.devno", NULL, devno);
+	sysinfo_set_item_val("kbd.inr", NULL, inr);
+	sysinfo_set_item_val("kbd.address.virtual", NULL, vaddr);
 	
-	ns16550_ier_write(IER_ERBFI);				/* enable receiver interrupt */
+	ns16550_ier_write(&ns16550, IER_ERBFI);		/* enable receiver interrupt */
 	
-	while (ns16550_lsr_read() & LSR_DATA_READY)
-		(void) ns16550_rbr_read();
+	while (ns16550_lsr_read(&ns16550) & LSR_DATA_READY)
+		(void) ns16550_rbr_read(&ns16550);
 }
 
@@ -130,7 +152,7 @@
 	while(!(ch = active_read_buff_read())) {
 		uint8_t x;
-		while (!(ns16550_lsr_read() & LSR_DATA_READY))
+		while (!(ns16550_lsr_read(&ns16550) & LSR_DATA_READY))
 			;
-		x = ns16550_rbr_read();
+		x = ns16550_rbr_read(&ns16550);
 		if (x != IGNORE_CODE) {
 			if (x & KEY_RELEASE)
@@ -151,6 +173,6 @@
 	uint8_t x;
 
-	while (ns16550_lsr_read() & LSR_DATA_READY) {
-		x = ns16550_rbr_read();
+	while (ns16550_lsr_read(&ns16550) & LSR_DATA_READY) {
+		x = ns16550_rbr_read(&ns16550);
 		if (x != IGNORE_CODE) {
 			if (x & KEY_RELEASE)
Index: kernel/genarch/src/kbd/z8530.c
===================================================================
--- kernel/genarch/src/kbd/z8530.c	(revision 7dcf22a389ae4373e29fc2686bf9bae2ac3a8d39)
+++ kernel/genarch/src/kbd/z8530.c	(revision 63530c623718a69d8b980518b5dec7e17f4d991d)
@@ -61,4 +61,7 @@
 bool z8530_belongs_to_kernel = true;
 
+static z8530_t z8530;		/**< z8530 device structure. */
+static irq_t z8530_irq;		/**< z8530's IRQ. */ 
+
 static void z8530_suspend(chardev_t *);
 static void z8530_resume(chardev_t *);
@@ -85,14 +88,25 @@
 
 /** Initialize z8530. */
-void z8530_init(void)
+void z8530_init(devno_t devno, inr_t inr, uintptr_t vaddr)
 {
 	chardev_initialize("z8530_kbd", &kbrd, &ops);
 	stdin = &kbrd;
 
+	z8530.devno = devno;
+	z8530.reg = (uint8_t *) vaddr;
+
+	irq_initialize(&z8530_irq);
+	z8530_irq.devno = devno;
+	z8530_irq.inr = inr;
+	z8530_irq.claim = z8530_claim;
+	z8530_irq.handler = z8530_irq_handler;
+	irq_register(&z8530_irq);
+
 	sysinfo_set_item_val("kbd", NULL, true);
-	sysinfo_set_item_val("kbd.irq", NULL, 0);
-	sysinfo_set_item_val("kbd.address.virtual", NULL, (uintptr_t) kbd_virt_address);
-
-	(void) z8530_read_a(RR8);
+	sysinfo_set_item_val("kbd.devno", NULL, devno);
+	sysinfo_set_item_val("kbd.inr", NULL, inr);
+	sysinfo_set_item_val("kbd.address.virtual", NULL, vaddr);
+
+	(void) z8530_read_a(&z8530, RR8);
 
 	/*
@@ -100,12 +114,12 @@
 	 * to set FHC UART interrupt state to idle.
 	 */
-	z8530_write_a(WR0, WR0_TX_IP_RST);
-
-	z8530_write_a(WR1, WR1_IARCSC);		/* interrupt on all characters */
+	z8530_write_a(&z8530, WR0, WR0_TX_IP_RST);
+
+	z8530_write_a(&z8530, WR1, WR1_IARCSC);		/* interrupt on all characters */
 
 	/* 8 bits per character and enable receiver */
-	z8530_write_a(WR3, WR3_RX8BITSCH | WR3_RX_ENABLE);
+	z8530_write_a(&z8530, WR3, WR3_RX8BITSCH | WR3_RX_ENABLE);
 	
-	z8530_write_a(WR9, WR9_MIE);		/* Master Interrupt Enable. */
+	z8530_write_a(&z8530, WR9, WR9_MIE);		/* Master Interrupt Enable. */
 }
 
@@ -140,7 +154,7 @@
 	while(!(ch = active_read_buff_read())) {
 		uint8_t x;
-		while (!(z8530_read_a(RR0) & RR0_RCA))
+		while (!(z8530_read_a(&z8530, RR0) & RR0_RCA))
 			;
-		x = z8530_read_a(RR8);
+		x = z8530_read_a(&z8530, RR8);
 		if (x != IGNORE_CODE) {
 			if (x & KEY_RELEASE)
@@ -161,6 +175,6 @@
 	uint8_t x;
 
-	while (z8530_read_a(RR0) & RR0_RCA) {
-		x = z8530_read_a(RR8);
+	while (z8530_read_a(&z8530, RR0) & RR0_RCA) {
+		x = z8530_read_a(&z8530, RR8);
 		if (x != IGNORE_CODE) {
 			if (x & KEY_RELEASE)
@@ -174,5 +188,5 @@
 irq_ownership_t z8530_claim(void)
 {
-	return (z8530_read_a(RR0) & RR0_RCA);
+	return (z8530_read_a(&z8530, RR0) & RR0_RCA);
 }
 
Index: kernel/generic/include/ddi/irq.h
===================================================================
--- kernel/generic/include/ddi/irq.h	(revision 7dcf22a389ae4373e29fc2686bf9bae2ac3a8d39)
+++ kernel/generic/include/ddi/irq.h	(revision 63530c623718a69d8b980518b5dec7e17f4d991d)
@@ -38,4 +38,8 @@
 #include <arch/types.h>
 #include <adt/list.h>
+#include <ipc/ipc.h>
+#include <ipc/irq.h>
+#include <atomic.h>
+#include <synch/spinlock.h>
 
 typedef enum {
@@ -63,4 +67,11 @@
 	link_t link;
 
+	/** Lock protecting everything in this structure
+	 *  except the link member. When both the IRQ
+	 *  hash table lock and this lock are to be acquired,
+	 *  this lock must not be taken first.
+	 */
+	SPINLOCK_DECLARE(lock);
+
 	/** Unique device number. -1 if not yet assigned. */
 	devno_t devno;
@@ -68,6 +79,4 @@
 	/** Actual IRQ number. -1 if not yet assigned. */
 	inr_t inr;
-	/** Task ID of the task to be notified about the IRQ or 0. */
-	task_id_t notif;
 	/** Trigger level of the IRQ.*/
 	irq_trigger_t trigger;
@@ -78,4 +87,12 @@
 	/** Argument for the handler. */
 	void *arg;
+
+	/** Answerbox of the task that wanted to be notified. */
+	answerbox_t *notif_answerbox;
+	/** Pseudo-code to be performed by the top-half
+	 *  before a notification is sent. */
+	irq_code_t *code;
+	/** Counter of IRQ notifications. */
+	atomic_t counter;
 };
 
Index: kernel/generic/src/ddi/irq.c
===================================================================
--- kernel/generic/src/ddi/irq.c	(revision 7dcf22a389ae4373e29fc2686bf9bae2ac3a8d39)
+++ kernel/generic/src/ddi/irq.c	(revision 63530c623718a69d8b980518b5dec7e17f4d991d)
@@ -64,4 +64,5 @@
 #include <typedefs.h>
 #include <synch/spinlock.h>
+#include <atomic.h>
 #include <arch.h>
 
@@ -128,11 +129,14 @@
 {
 	link_initialize(&irq->link);
+	spinlock_initialize(&irq->lock, "irq.lock");
 	irq->inr = -1;
 	irq->devno = -1;
-	irq->notif = 0;
 	irq->trigger = 0;
 	irq->claim = NULL;
 	irq->handler = NULL;
 	irq->arg = NULL;
+	irq->notif_answerbox = NULL;
+	irq->code = NULL;
+	atomic_set(&irq->counter, 0);
 }
 
@@ -221,6 +225,11 @@
 	irq_t *irq = hash_table_get_instance(item, irq_t, link);
 	inr_t *inr = (inr_t *) key;
-	
-	return ((irq->inr == *inr) && (irq->claim() == IRQ_ACCEPT));
+	bool rv;
+	
+	spinlock_lock(&irq->lock);
+	rv = ((irq->inr == *inr) && (irq->claim() == IRQ_ACCEPT));
+	spinlock_unlock(&irq->lock);
+
+	return rv;
 }
 
@@ -260,6 +269,11 @@
 {
 	irq_t *irq = list_get_instance(item, irq_t, link);
-	
-	return (irq->claim() == IRQ_ACCEPT);
+	bool rv;
+	
+	spinlock_lock(&irq->lock);
+	rv = (irq->claim() == IRQ_ACCEPT);
+	spinlock_unlock(&irq->lock);
+	
+	return rv;
 }
 
