Index: uspace/srv/pci/Makefile
===================================================================
--- uspace/srv/pci/Makefile	(revision 8344d0a447c14dcaa3d5a68b0a5172624baea0fe)
+++ uspace/srv/pci/Makefile	(revision 86554e71a1dd77b66b874136837c0b9cd1957907)
@@ -45,4 +45,5 @@
 SOURCES = \
 	main.c \
+	pic.c \
 	pci.c \
 	intel_piix3.c \
Index: uspace/srv/pci/main.c
===================================================================
--- uspace/srv/pci/main.c	(revision 8344d0a447c14dcaa3d5a68b0a5172624baea0fe)
+++ uspace/srv/pci/main.c	(revision 86554e71a1dd77b66b874136837c0b9cd1957907)
@@ -4,4 +4,5 @@
 
 #include "intel_piix3.h"
+#include "pic.h"
 #include "pci.h"
 #include "pci_bus.h"
@@ -10,7 +11,13 @@
 
 
+
 int main(int argc, char **argv) 
 {
 	printf("PCI bus driver\n");
+	
+	if (!pic_init()) {
+		printf("PIC initialization failed.\n");
+		return 1;
+	}
 	
 	if (!pci_bus_init()) {
@@ -22,6 +29,5 @@
 		printf("ISA bus initialization failed.\n");
 		return 1;
-	}
-	
+	}	
 	
 	// pci-to-isa bridge device
Index: uspace/srv/pci/pic.c
===================================================================
--- uspace/srv/pci/pic.c	(revision 86554e71a1dd77b66b874136837c0b9cd1957907)
+++ uspace/srv/pci/pic.c	(revision 86554e71a1dd77b66b874136837c0b9cd1957907)
@@ -0,0 +1,67 @@
+#include <unistd.h>
+#include <ddi.h>
+#include <libarch/ddi.h>
+#include <stdio.h>
+
+#include "pic.h"
+
+#define PIC1		0x20		/* IO base address for master PIC */
+#define PIC2		0xA0		/* IO base address for slave PIC */
+#define REG_COUNT	2			/* command and data */
+
+#define NAME "PIC"
+
+static ioport8_t *pic1_cmd, *pic1_data, *pic2_cmd, *pic2_data;
+
+static int pic_enable_ports(void *base_phys_addr, ioport8_t **pic_cmd, ioport8_t **pic_data);
+
+
+int pic_init()
+{	
+	printf(NAME ": enabling ports 0x%x - 0x%x.\n", PIC1, PIC1 + 1);
+	if (!pic_enable_ports((void *)PIC1, &pic1_cmd, &pic1_data)) {
+		printf(NAME ": Error - master PIC initialization failed.\n");
+		return 0;
+	}
+	
+	printf(NAME ": enabling ports 0x%x - 0x%x.\n", PIC2, PIC2 + 1);
+	if (!pic_enable_ports((void *)PIC2, &pic2_cmd, &pic2_data)) {
+		printf(NAME ": Error - slave PIC initialization failed.");
+		return 0;
+	}
+	
+	printf(NAME ": initialization was successful.\n");
+	return 1;
+}
+
+static int pic_enable_ports(void *base_phys_addr, ioport8_t **pic_cmd, ioport8_t **pic_data)
+{
+	if (pio_enable(base_phys_addr, REG_COUNT, (void **)(pic_cmd))) {  // Gain control over port's registers.
+		printf(NAME ": Error - cannot gain the port %lx.\n", base_phys_addr);
+		return 0;
+	}
+	
+	*pic_data = *pic_cmd + 1;
+	return 1;
+}
+
+void pic_enable_interrupt(int irq)
+{
+	printf(NAME ": pic_enable_interrupt %d.", irq);
+	pic_enable_irqs(1 << irq);
+	printf(NAME ": interrupt %d enabled.", irq);
+}
+
+void pic_enable_irqs(uint16_t irqmask)
+{
+	uint8_t x;
+
+	if (irqmask & 0xff) {
+		x = pio_read_8(pic1_data);
+		pio_write_8(pic1_data, (uint8_t) (x & (~(irqmask & 0xff))));
+	}
+	if (irqmask >> 8) {
+		x = pio_read_8(pic2_data);
+		pio_write_8(pic2_data, (uint8_t) (x & (~(irqmask >> 8))));
+	}
+}
Index: uspace/srv/pci/pic.h
===================================================================
--- uspace/srv/pci/pic.h	(revision 86554e71a1dd77b66b874136837c0b9cd1957907)
+++ uspace/srv/pci/pic.h	(revision 86554e71a1dd77b66b874136837c0b9cd1957907)
@@ -0,0 +1,10 @@
+#ifndef PIC_H
+#define PIC_H
+
+#include <stdlib.h>
+
+int pic_init();
+void pic_enable_interrupt(int irq);
+void pic_enable_irqs(uint16_t irqmask);
+
+#endif
Index: uspace/srv/pci/serial.c
===================================================================
--- uspace/srv/pci/serial.c	(revision 8344d0a447c14dcaa3d5a68b0a5172624baea0fe)
+++ uspace/srv/pci/serial.c	(revision 86554e71a1dd77b66b874136837c0b9cd1957907)
@@ -18,4 +18,5 @@
 #include "isa.h"
 #include "serial.h"
+#include "pic.h"
 
 #define NAME "serial"
@@ -24,19 +25,80 @@
 
 #define MAX_NAME_LEN 8
+#define BUF_LEN 256  // the length of the input buffer
+
+struct cyclic_buffer {
+	uint8_t buf[BUF_LEN];  // cyclic buffer 
+	int start;
+	int cnt;
+};
+
+typedef struct cyclic_buffer cyclic_buffer_t;
+
+// returns false if the buffer is full
+static bool buf_push_back(cyclic_buffer_t *buf, uint8_t item) 
+{
+	if (buf->cnt >= BUF_LEN) {
+		return false;
+	}
+	
+	int pos = (buf->start + buf->cnt) % BUF_LEN;
+	buf->buf[pos] = item;
+	buf->cnt++;
+	return true;
+}
+
+static bool buf_is_empty(cyclic_buffer_t *buf) 
+{
+	return buf->cnt == 0;
+}
+
+// call it on non empty buffer!
+static uint8_t buf_pop_front(cyclic_buffer_t *buf) 
+{
+	assert(!buf_is_empty(buf));
+	
+	uint8_t res = buf->buf[buf->start];
+	buf->start = (buf->start + 1) % BUF_LEN;	
+	buf->cnt--;
+	return res;
+}
+
+static void buf_clear(cyclic_buffer_t *buf) 
+{
+	buf->cnt = 0;
+}
 
 struct serial_dev {
 	link_t link;
 	char name[MAX_NAME_LEN];
-	int handle;
+	int handle; // devmapper device handle
+	int devno; // unique device number; used in irq registration (cannot be handle used instead of it?) 
 	bool client_connected;
 	ioport8_t *port;
 	void *phys_addr;
+	int irq;
 	bridge_to_isa_t *parent;
+	cyclic_buffer_t input_buffer;
+	futex_t futex;
 };
 
 typedef struct serial_dev serial_dev_t;
 
+static irq_cmd_t serial_cmds[] = {
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+
+static irq_code_t serial_pseudocode = {
+	sizeof(serial_cmds) / sizeof(irq_cmd_t),
+	serial_cmds
+};
+
 static void * serial_phys_addresses[] = { (void *)0x3F8, (void *)0x2F8 };
+static int serial_irqs[] = { 4, 3 }; // TODO - what about if there were more than two serial ports?
 static int serial_phys_addr_cnt = sizeof(serial_phys_addresses)/sizeof(void *);
+static int serial_irq_cnt = sizeof(serial_irqs)/sizeof(int);
+
 // number, which should be assigned to a newly found serial device - increment first, then assign to the device
 static int serial_idx = 0; 
@@ -61,4 +123,8 @@
 static void serial_getchar(serial_dev_t *dev, ipc_callid_t rid);
 static void serial_client_conn(ipc_callid_t iid, ipc_call_t *icall);
+static void serial_irq_handler(ipc_callid_t iid, ipc_call_t *icall);
+static serial_dev_t * serial_devno_to_dev(int devno);
+static serial_dev_t * serial_handle_to_dev(int handle);
+static void serial_enable_interrupt(serial_dev_t *dev);
 
 static isa_drv_ops_t serial_isa_ops = {
@@ -77,6 +143,10 @@
     if (serial_driver_phone < 0) {
 		printf(NAME ": Unable to register driver\n");
-		return false;
-	}
+		return 0;
+	}
+	
+	// register irq handler
+	printf(NAME ": Registering interrup notification callback function.\n");
+	async_set_interrupt_received(serial_irq_handler);
 	   
 	// register this driver by generic isa bus driver	
@@ -92,9 +162,5 @@
 static uint8_t serial_read_8(ioport8_t *port) 
 {
-	while (!serial_received(port)) 
-		;
-
-	uint8_t c = pio_read_8(port);
-	return c;
+	return pio_read_8(port);
 }
 
@@ -120,5 +186,17 @@
 	pio_write_8(port + 3, 0x07);    // 8 bits, no parity, two stop bits
 	pio_write_8(port + 2, 0xC7);    // Enable FIFO, clear them, with 14-byte threshold
-	pio_write_8(port + 4, 0x0B);    // RTS/DSR set (Request to Send and Data Terminal Ready lines enabled), Aux Output2 set 
+	pio_write_8(port + 4, 0x0B);    // RTS/DSR set (Request to Send and Data Terminal Ready lines enabled), 
+									// Aux Output2 set - needed for interrupts
+	 
+}
+
+static void serial_enable_interrupt(serial_dev_t *dev)
+{
+	futex_down(&(dev->futex));
+	// TODO do not call pic directly, do it more generally
+	pic_enable_interrupt(dev->irq);
+	pio_write_8(dev->port + 1 , 0x01);   // Interrupt when data received
+	pio_write_8(dev->port + 4, 0x0B);
+	futex_up(&(dev->futex));
 }
 
@@ -137,6 +215,9 @@
 	dev->parent = parent;
 	dev->phys_addr = dev->parent->ops->absolutize(serial_phys_addresses[idx % serial_phys_addr_cnt]);
+	dev->irq = serial_irqs[idx % serial_irq_cnt];
 	snprintf(dev->name, MAX_NAME_LEN, "com%d", idx + 1);
-	dev->client_connected = false;	
+	dev->devno = -1;
+	dev->client_connected = false;
+	futex_initialize(&(dev->futex), 1);
 }
 
@@ -145,5 +226,4 @@
 	assert(dev != NULL);
 	
-	printf(NAME " driver: probing %s \n", dev->name);
 	return (dev->port = (ioport8_t *)serial_probe_port(dev->phys_addr)) != NULL;	
 }
@@ -160,14 +240,24 @@
 	
 	int i;
-	for (i = 0; i < serial_phys_addr_cnt; i++) {		
+	for (i = 0; i < serial_phys_addr_cnt; i++) {			
 		serial_init_dev(dev, parent, serial_idx);
+		printf(NAME ": probing %s. \n", dev->name);
 		if (serial_probe_dev(dev)) {
 			printf(NAME " driver: initializing %s.\n", dev->name);
 			serial_init_port(dev->port);
 			if (EOK != serial_device_register(serial_driver_phone, dev->name, &(dev->handle))) {
-				printf(NAME ": Unable to register device %s\n", dev->name);
-			}	
-			list_append(&(dev->link), &serial_devices_list);
-			dev = serial_alloc_dev();
+				printf(NAME ": unable to register device %s\n", dev->name);
+			} else {
+				dev->devno = device_assign_devno();
+				
+				// 3rd argument called method is equal devno,this enables us to identify the device 
+				// which caused the interrupt in the irq notification callback function
+				printf(NAME ": registering irq = %d for %s.\n", dev->irq, dev->name);
+				ipc_register_irq(dev->irq, dev->devno, dev->devno, &serial_pseudocode);  
+				list_append(&(dev->link), &serial_devices_list);
+				printf(NAME ": enabling irq = %d for %s.\n", dev->irq, dev->name);
+				serial_enable_interrupt(dev);
+				dev = serial_alloc_dev();
+			}
 		} else {
 			printf(NAME " driver: %s is not present \n", dev->name);
@@ -210,5 +300,7 @@
 {
 	int c = IPC_GET_ARG1(*request);
+	futex_down(&(dev->futex));
 	serial_write_8(dev->port, (uint8_t)c);	
+	futex_up(&(dev->futex));
 	ipc_answer_0(rid, EOK);
 }
@@ -216,10 +308,23 @@
 static void serial_getchar(serial_dev_t *dev, ipc_callid_t rid)
 {
-	uint8_t c = serial_read_8(dev->port);	
+	uint8_t c;
+	printf(NAME ": trying to read from serial port %s\n", dev->name);
+	while (true) {  // TODO: fix it - the queue of requests to read ?
+		futex_down(&(dev->futex));
+		if (!buf_is_empty(&(dev->input_buffer))) {
+			c = buf_pop_front(&(dev->input_buffer));
+			futex_up(&(dev->futex));
+			break;
+		}
+		//printf(NAME "no data ready, trying to read again after some while.\n", dev->name);
+		futex_up(&(dev->futex));
+		async_usleep(10000);
+	}
+	printf(NAME ": serial_getchar: sending characer %c read from %s to client.\n", c, dev->name);
 	ipc_answer_1(rid, EOK, c);		
 }
 
-static serial_dev_t * serial_handle_to_dev(int handle) {
-	
+static serial_dev_t * serial_handle_to_dev(int handle) 
+{	
 	futex_down(&serial_futex);	
 	
@@ -230,4 +335,24 @@
 		dev = list_get_instance(item, serial_dev_t, link);
 		if (dev->handle == handle) {
+			futex_up(&serial_futex);
+			return dev;
+		}
+		item = item->next;
+	}
+	
+	futex_up(&serial_futex);
+	return NULL;
+}
+
+static serial_dev_t * serial_devno_to_dev(int devno)
+{		
+	futex_down(&serial_futex);	
+	
+	link_t *item = serial_devices_list.next;
+	serial_dev_t *dev = NULL; 
+	
+	while (item != &serial_devices_list) {
+		dev = list_get_instance(item, serial_dev_t, link);
+		if (dev->devno == devno) {
 			futex_up(&serial_futex);
 			return dev;
@@ -262,5 +387,6 @@
 		return;
 	}
-	
+		
+	buf_clear(&(dev->input_buffer));  // synchronization with interrupt service routine ?
 	dev->client_connected = true;
 	ipc_answer_0(iid, EOK);
@@ -310,6 +436,5 @@
 	while (phone < 0) {
 		usleep(10000);
-		phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
-		    DEVMAP_DRIVER, 0);
+		phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_DRIVER, 0);
 	}
 	
@@ -336,4 +461,8 @@
 	aid_t req;
 	ipc_call_t answer;
+	
+	if (handle != NULL) {
+		*handle = -1;
+	}
 
 	req = async_send_2(driver_phone, DEVMAP_DEVICE_REGISTER, 0, 0, &answer);
@@ -347,7 +476,4 @@
 
 	async_wait_for(req, &retval);
-
-	if (handle != NULL)
-		*handle = -1;
 	
 	if (EOK == retval) {
@@ -358,2 +484,41 @@
 	return retval;
 }
+
+static void serial_read_from_device(serial_dev_t *dev)
+{	
+	bool cont = true;
+	
+	while (cont) {	
+		futex_down(&(dev->futex));
+		if (cont = serial_received(dev->port)) {
+			uint8_t val = serial_read_8(dev->port);
+			printf(NAME ": character %c read from %s.\n", val, dev->name);
+			if (dev->client_connected) {
+				if (!buf_push_back(&(dev->input_buffer), val)) {
+					printf(NAME ": buffer overflow on %s.\n", dev->name);
+				} else {
+					printf(NAME ": the character %c saved to the buffer of %s.\n", val, dev->name);
+				}
+			} else {
+				printf(NAME ": no client is connected to %s, discarding the character which was read.\n", dev->name);
+			}
+		}
+		futex_up(&(dev->futex));
+		usleep(10000);
+	}	
+}
+
+// TODO - this is the only irq handling function registered by this task.
+// (A task can register only one such function.)
+// If more drivers within the task needed to handle interrupts, 
+// there will have to be one generic handler redistributing
+// irq notification messages among them. 
+// Or the change of ansync framework will be needed.
+static void serial_irq_handler(ipc_callid_t iid, ipc_call_t *icall)
+{
+	printf(NAME ": irq handler\n");
+	int devno = IPC_GET_METHOD(*icall);
+	serial_dev_t *dev = serial_devno_to_dev(devno);
+	serial_read_from_device(dev);	
+}
+
