Index: kernel/genarch/src/drivers/via-cuda/cuda.c
===================================================================
--- kernel/genarch/src/drivers/via-cuda/cuda.c	(revision c2417bcc6cc9caba6dca867e322c9cc5723b35f4)
+++ kernel/genarch/src/drivers/via-cuda/cuda.c	(revision 2a77841d908e049448d19c7d0534c127cd8b1b3f)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2006 Martin Decky
+ * Copyright (c) 2009 Jiri Svoboda
  * All rights reserved.
  *
@@ -39,12 +40,85 @@
 #include <mm/slab.h>
 #include <ddi/device.h>
+#include <synch/spinlock.h>
+
+static void cuda_packet_handle(cuda_instance_t *instance, size_t len);
+
+/** B register fields */
+enum {
+	TREQ	= 0x08,
+	TACK	= 0x10,
+	TIP	= 0x20
+};
+
+/** IER register fields */
+enum {
+	IER_SET	= 0x80,
+	SR_INT	= 0x04
+};
 
 static irq_ownership_t cuda_claim(irq_t *irq)
 {
-	return IRQ_DECLINE;
+	cuda_instance_t *instance = irq->instance;
+	cuda_t *dev = instance->cuda;
+	uint8_t ifr;
+
+	ifr = pio_read_8(&dev->ifr);
+
+	if ((ifr & SR_INT) != 0)
+		return IRQ_ACCEPT;
+	else
+		return IRQ_DECLINE;
 }
 
 static void cuda_irq_handler(irq_t *irq)
 {
+	cuda_instance_t *instance = irq->instance;
+	cuda_t *dev = instance->cuda;
+	uint8_t b, data;
+	size_t pos;
+
+	spinlock_lock(&instance->dev_lock);
+
+	/* We have received one or more CUDA packets. Process them all. */
+	while (true) {
+		b = pio_read_8(&dev->b);
+
+		if ((b & TREQ) != 0)
+			break;	/* No data */
+
+		pio_write_8(&dev->b, b & ~TIP);
+
+		/* Read one packet. */
+
+		pos = 0;
+		do {
+			data = pio_read_8(&dev->sr);
+			b = pio_read_8(&dev->b);
+			pio_write_8(&dev->b, b ^ TACK);
+
+			if (pos < CUDA_RCV_BUF_SIZE)
+				instance->rcv_buf[pos++] = data;
+		} while ((b & TREQ) == 0);
+
+		pio_write_8(&dev->b, b | TACK | TIP);
+
+		cuda_packet_handle(instance, pos);
+	}
+
+	spinlock_unlock(&instance->dev_lock);
+}
+
+static void cuda_packet_handle(cuda_instance_t *instance, size_t len)
+{
+	uint8_t *data = instance->rcv_buf;
+
+	if (data[0] != 0x00 || data[1] != 0x40 || data[2] != 0x2c)
+		return;
+
+	/* The packet contains one or two scancodes. */
+	if (data[3] != 0xff)
+		indev_push_character(instance->kbrdin, data[3]);		
+	if (data[4] != 0xff)
+		indev_push_character(instance->kbrdin, data[4]);
 }
 
@@ -56,5 +130,7 @@
 		instance->cuda = dev;
 		instance->kbrdin = NULL;
-		
+
+		spinlock_initialize(&instance->dev_lock, "cuda_dev");
+
 		irq_initialize(&instance->irq);
 		instance->irq.devno = device_assign_devno();
@@ -72,6 +148,13 @@
 void cuda_wire(cuda_instance_t *instance, indev_t *kbrdin)
 {
+	ASSERT(instance);
+	ASSERT(kbrdin);
+
+	instance->kbrdin = kbrdin;
+	irq_register(&instance->irq);
+
+	/* Enable SR interrupt. */
+	pio_write_8(&instance->cuda->ier, IER_SET | SR_INT);
 }
-
 
 /** @}
