diff --git a/tools/kvm/include/kvm/virtio-pci-dev.h b/tools/kvm/include/kvm/virtio-pci-dev.h
index 431289d..d2274d0 100644
--- a/tools/kvm/include/kvm/virtio-pci-dev.h
+++ b/tools/kvm/include/kvm/virtio-pci-dev.h
@@ -16,25 +16,4 @@
 #define PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE		0x0003
 #define PCI_SUBSYSTEM_ID_VIRTIO_RNG		0x0004
 
-enum {
-	PCI_VIRTIO_BLK_DEVNUM			= 10,
-	PCI_VIRTIO_CONSOLE_DEVNUM		= 2,
-	PCI_VIRTIO_NET_DEVNUM			= 3,
-	PCI_VIRTIO_RNG_DEVNUM			= 4,
-};
-
-enum {
-	VIRTIO_BLK_PIN				= 1,
-	VIRTIO_CONSOLE_PIN			= 2,
-	VIRTIO_NET_PIN				= 3,
-	VIRTIO_RNG_PIN				= 4,
-};
-
-enum {
-	VIRTIO_RNG_IRQ				= 11,
-	VIRTIO_CONSOLE_IRQ			= 13,
-	VIRTIO_NET_IRQ				= 14,
-	VIRTIO_BLK_IRQ				= 15,
-};
-
 #endif /* VIRTIO_PCI_DEV_H_ */
diff --git a/tools/kvm/virtio/blk.c b/tools/kvm/virtio/blk.c
index 5a73dd6..accfc3e 100644
--- a/tools/kvm/virtio/blk.c
+++ b/tools/kvm/virtio/blk.c
@@ -2,7 +2,7 @@
 
 #include "kvm/virtio-pci.h"
 #include "kvm/virtio-pci-dev.h"
-
+#include "kvm/irq.h"
 #include "kvm/disk-image.h"
 #include "kvm/virtio.h"
 #include "kvm/ioport.h"
@@ -103,7 +103,7 @@ static bool virtio_blk_pci_io_in(struct kvm *self, u16 port, void *data, int siz
 		break;
 	case VIRTIO_PCI_ISR:
 		ioport__write8(data, 0x1);
-		kvm__irq_line(self, VIRTIO_BLK_IRQ + bdev->idx, 0);
+		kvm__irq_line(self, bdev->pci_device.irq_line, 0);
 		break;
 	case VIRTIO_MSI_CONFIG_VECTOR:
 		ioport__write16(data, bdev->config_vector);
@@ -167,7 +167,7 @@ static void virtio_blk_do_io(struct kvm *kvm, void *param)
 	while (virt_queue__available(vq))
 		virtio_blk_do_io_request(kvm, bdev, vq);
 
-	kvm__irq_line(kvm, VIRTIO_BLK_IRQ + bdev->idx, 1);
+	kvm__irq_line(kvm, bdev->pci_device.irq_line, 1);
 }
 
 static bool virtio_blk_pci_io_out(struct kvm *self, u16 port, void *data, int size, u32 count)
@@ -257,6 +257,7 @@ static int virtio_blk_find_empty_dev(void)
 void virtio_blk__init(struct kvm *self, struct disk_image *disk)
 {
 	u16 blk_dev_base_addr;
+	u8 dev, pin, line;
 	struct blk_dev *bdev;
 	int new_dev_idx;
 
@@ -291,12 +292,16 @@ void virtio_blk__init(struct kvm *self, struct disk_image *disk)
 			.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
 			.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_BLK,
 			.bar[0]			= blk_dev_base_addr | PCI_BASE_ADDRESS_SPACE_IO,
-			.irq_pin		= VIRTIO_BLK_PIN,
-			.irq_line		= VIRTIO_BLK_IRQ + new_dev_idx,
 		},
 	};
 
-	pci__register(&bdev->pci_device, PCI_VIRTIO_BLK_DEVNUM + new_dev_idx);
+	if (irq__register_device(PCI_DEVICE_ID_VIRTIO_BLK, &dev, &pin, &line) < 0)
+		return;
+
+	bdev->pci_device.irq_pin	= pin;
+	bdev->pci_device.irq_line	= line;
+
+	pci__register(&bdev->pci_device, dev);
 
 	ioport__register(blk_dev_base_addr, &virtio_blk_io_ops, IOPORT_VIRTIO_BLK_SIZE);
 }
diff --git a/tools/kvm/virtio/console.c b/tools/kvm/virtio/console.c
index 02272b4..188227b 100644
--- a/tools/kvm/virtio/console.c
+++ b/tools/kvm/virtio/console.c
@@ -10,6 +10,7 @@
 #include "kvm/kvm.h"
 #include "kvm/pci.h"
 #include "kvm/threadpool.h"
+#include "kvm/irq.h"
 
 #include <linux/virtio_console.h>
 #include <linux/virtio_ring.h>
@@ -28,6 +29,17 @@
 #define VIRTIO_CONSOLE_RX_QUEUE		0
 #define VIRTIO_CONSOLE_TX_QUEUE		1
 
+static struct pci_device_header virtio_console_pci_device = {
+	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
+	.device_id		= PCI_DEVICE_ID_VIRTIO_CONSOLE,
+	.header_type		= PCI_HEADER_TYPE_NORMAL,
+	.revision_id		= 0,
+	.class			= 0x078000,
+	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
+	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE,
+	.bar[0]			= IOPORT_VIRTIO_CONSOLE | PCI_BASE_ADDRESS_SPACE_IO,
+};
+
 struct con_dev {
 	pthread_mutex_t			mutex;
 
@@ -73,7 +85,7 @@ static void virtio_console__inject_interrupt_callback(struct kvm *self, void *pa
 		head = virt_queue__get_iov(vq, iov, &out, &in, self);
 		len = term_getc_iov(CONSOLE_VIRTIO, iov, in);
 		virt_queue__set_used_elem(vq, head, len);
-		kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 1);
+		kvm__irq_line(self, virtio_console_pci_device.irq_line, 1);
 	}
 
 	mutex_unlock(&cdev.mutex);
@@ -128,7 +140,7 @@ static bool virtio_console_pci_io_in(struct kvm *self, u16 port, void *data, int
 		break;
 	case VIRTIO_PCI_ISR:
 		ioport__write8(data, 0x1);
-		kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 0);
+		kvm__irq_line(self, virtio_console_pci_device.irq_line, 0);
 		break;
 	case VIRTIO_MSI_CONFIG_VECTOR:
 		ioport__write16(data, cdev.config_vector);
@@ -158,7 +170,7 @@ static void virtio_console_handle_callback(struct kvm *self, void *param)
 		virt_queue__set_used_elem(vq, head, len);
 	}
 
-	kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 1);
+	kvm__irq_line(self, virtio_console_pci_device.irq_line, 1);
 }
 
 static bool virtio_console_pci_io_out(struct kvm *self, u16 port, void *data, int size, u32 count)
@@ -222,21 +234,15 @@ static struct ioport_operations virtio_console_io_ops = {
 	.io_out			= virtio_console_pci_io_out,
 };
 
-static struct pci_device_header virtio_console_pci_device = {
-	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
-	.device_id		= PCI_DEVICE_ID_VIRTIO_CONSOLE,
-	.header_type		= PCI_HEADER_TYPE_NORMAL,
-	.revision_id		= 0,
-	.class			= 0x078000,
-	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
-	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE,
-	.bar[0]			= IOPORT_VIRTIO_CONSOLE | PCI_BASE_ADDRESS_SPACE_IO,
-	.irq_pin		= VIRTIO_CONSOLE_PIN,
-	.irq_line		= VIRTIO_CONSOLE_IRQ,
-};
-
 void virtio_console__init(struct kvm *self)
 {
-	pci__register(&virtio_console_pci_device, PCI_VIRTIO_CONSOLE_DEVNUM);
+	u8 dev, line, pin;
+
+	if (irq__register_device(PCI_DEVICE_ID_VIRTIO_CONSOLE, &dev, &pin, &line) < 0)
+		return;
+
+	virtio_console_pci_device.irq_pin	= pin;
+	virtio_console_pci_device.irq_line	= line;
+	pci__register(&virtio_console_pci_device, dev);
 	ioport__register(IOPORT_VIRTIO_CONSOLE, &virtio_console_io_ops, IOPORT_VIRTIO_CONSOLE_SIZE);
 }
diff --git a/tools/kvm/virtio/net.c b/tools/kvm/virtio/net.c
index df69ab3..99ea22a 100644
--- a/tools/kvm/virtio/net.c
+++ b/tools/kvm/virtio/net.c
@@ -8,6 +8,7 @@
 #include "kvm/util.h"
 #include "kvm/kvm.h"
 #include "kvm/pci.h"
+#include "kvm/irq.h"
 
 #include <linux/virtio_net.h>
 #include <linux/if_tun.h>
@@ -26,6 +27,17 @@
 #define VIRTIO_NET_RX_QUEUE		0
 #define VIRTIO_NET_TX_QUEUE		1
 
+static struct pci_device_header virtio_net_pci_device = {
+	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
+	.device_id		= PCI_DEVICE_ID_VIRTIO_NET,
+	.header_type		= PCI_HEADER_TYPE_NORMAL,
+	.revision_id		= 0,
+	.class			= 0x020000,
+	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
+	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_NET,
+	.bar[0]			= IOPORT_VIRTIO_NET | PCI_BASE_ADDRESS_SPACE_IO,
+};
+
 struct net_device {
 	pthread_mutex_t			mutex;
 
@@ -89,7 +101,7 @@ static void *virtio_net_rx_thread(void *p)
 			len	= readv(net_device.tap_fd, iov, in);
 			virt_queue__set_used_elem(vq, head, len);
 			/* We should interrupt guest right now, otherwise latency is huge. */
-			kvm__irq_line(self, VIRTIO_NET_IRQ, 1);
+			kvm__irq_line(self, virtio_net_pci_device.irq_line, 1);
 		}
 
 	}
@@ -123,7 +135,7 @@ static void *virtio_net_tx_thread(void *p)
 			virt_queue__set_used_elem(vq, head, len);
 		}
 
-		kvm__irq_line(self, VIRTIO_NET_IRQ, 1);
+		kvm__irq_line(self, virtio_net_pci_device.irq_line, 1);
 	}
 
 	pthread_exit(NULL);
@@ -176,7 +188,7 @@ static bool virtio_net_pci_io_in(struct kvm *self, u16 port, void *data, int siz
 		break;
 	case VIRTIO_PCI_ISR:
 		ioport__write8(data, 0x1);
-		kvm__irq_line(self, VIRTIO_NET_IRQ, 0);
+		kvm__irq_line(self, virtio_net_pci_device.irq_line, 0);
 		break;
 	case VIRTIO_MSI_CONFIG_VECTOR:
 		ioport__write16(data, net_device.config_vector);
@@ -266,19 +278,6 @@ static struct ioport_operations virtio_net_io_ops = {
 	.io_out	= virtio_net_pci_io_out,
 };
 
-static struct pci_device_header virtio_net_pci_device = {
-	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
-	.device_id		= PCI_DEVICE_ID_VIRTIO_NET,
-	.header_type		= PCI_HEADER_TYPE_NORMAL,
-	.revision_id		= 0,
-	.class			= 0x020000,
-	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
-	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_NET,
-	.bar[0]			= IOPORT_VIRTIO_NET | PCI_BASE_ADDRESS_SPACE_IO,
-	.irq_pin		= VIRTIO_NET_PIN,
-	.irq_line		= VIRTIO_NET_IRQ,
-};
-
 static bool virtio_net__tap_init(const struct virtio_net_parameters *params)
 {
 	int sock = socket(AF_INET, SOCK_STREAM, 0);
@@ -380,7 +379,14 @@ static void virtio_net__io_thread_init(struct kvm *self)
 void virtio_net__init(const struct virtio_net_parameters *params)
 {
 	if (virtio_net__tap_init(params)) {
-		pci__register(&virtio_net_pci_device, PCI_VIRTIO_NET_DEVNUM);
+		u8 dev, line, pin;
+
+		if (irq__register_device(PCI_DEVICE_ID_VIRTIO_NET, &dev, &pin, &line) < 0)
+			return;
+
+		virtio_net_pci_device.irq_pin	= pin;
+		virtio_net_pci_device.irq_line	= line;
+		pci__register(&virtio_net_pci_device, dev);
 		ioport__register(IOPORT_VIRTIO_NET, &virtio_net_io_ops, IOPORT_VIRTIO_NET_SIZE);
 
 		virtio_net__io_thread_init(params->self);
diff --git a/tools/kvm/virtio/rng.c b/tools/kvm/virtio/rng.c
index f6034e4..d355cf8 100644
--- a/tools/kvm/virtio/rng.c
+++ b/tools/kvm/virtio/rng.c
@@ -11,6 +11,7 @@
 #include "kvm/kvm.h"
 #include "kvm/pci.h"
 #include "kvm/threadpool.h"
+#include "kvm/irq.h"
 
 #include <linux/virtio_ring.h>
 #include <linux/virtio_rng.h>
@@ -23,15 +24,26 @@
 #define NUM_VIRT_QUEUES				1
 #define VIRTIO_RNG_QUEUE_SIZE			128
 
+static struct pci_device_header virtio_rng_pci_device = {
+	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
+	.device_id		= PCI_DEVICE_ID_VIRTIO_RNG,
+	.header_type		= PCI_HEADER_TYPE_NORMAL,
+	.revision_id		= 0,
+	.class			= 0x010000,
+	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
+	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_RNG,
+	.bar[0]			= IOPORT_VIRTIO_RNG | PCI_BASE_ADDRESS_SPACE_IO,
+};
+
 struct rng_dev {
-	u8					status;
-	u16					config_vector;
-	int					fd;
+	u8			status;
+	u16			config_vector;
+	int			fd;
 
 	/* virtio queue */
-	u16					queue_selector;
-	struct virt_queue			vqs[NUM_VIRT_QUEUES];
-	void					*jobs[NUM_VIRT_QUEUES];
+	u16			queue_selector;
+	struct virt_queue	vqs[NUM_VIRT_QUEUES];
+	void			*jobs[NUM_VIRT_QUEUES];
 };
 
 static struct rng_dev rdev;
@@ -61,7 +73,7 @@ static bool virtio_rng_pci_io_in(struct kvm *kvm, u16 port, void *data, int size
 		break;
 	case VIRTIO_PCI_ISR:
 		ioport__write8(data, 0x1);
-		kvm__irq_line(kvm, VIRTIO_RNG_IRQ, 0);
+		kvm__irq_line(kvm, virtio_rng_pci_device.irq_line, 0);
 		break;
 	case VIRTIO_MSI_CONFIG_VECTOR:
 		ioport__write16(data, rdev.config_vector);
@@ -94,7 +106,7 @@ static void virtio_rng_do_io(struct kvm *kvm, void *param)
 
 	while (virt_queue__available(vq)) {
 		virtio_rng_do_io_request(kvm, vq);
-		kvm__irq_line(kvm, VIRTIO_RNG_IRQ, 1);
+		kvm__irq_line(kvm, virtio_rng_pci_device.irq_line, 1);
 	}
 }
 
@@ -151,26 +163,20 @@ static struct ioport_operations virtio_rng_io_ops = {
 	.io_out				= virtio_rng_pci_io_out,
 };
 
-static struct pci_device_header virtio_rng_pci_device = {
-	.vendor_id			= PCI_VENDOR_ID_REDHAT_QUMRANET,
-	.device_id			= PCI_DEVICE_ID_VIRTIO_RNG,
-	.header_type			= PCI_HEADER_TYPE_NORMAL,
-	.revision_id			= 0,
-	.class				= 0x010000,
-	.subsys_vendor_id		= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
-	.subsys_id			= PCI_SUBSYSTEM_ID_VIRTIO_RNG,
-	.bar[0]				= IOPORT_VIRTIO_RNG | PCI_BASE_ADDRESS_SPACE_IO,
-	.irq_pin			= VIRTIO_RNG_PIN,
-	.irq_line			= VIRTIO_RNG_IRQ,
-};
-
 void virtio_rng__init(struct kvm *kvm)
 {
+	u8 pin, line, dev;
+
 	rdev.fd = open("/dev/urandom", O_RDONLY);
 	if (rdev.fd < 0)
 		die("Failed initializing RNG");
 
-	pci__register(&virtio_rng_pci_device, PCI_VIRTIO_RNG_DEVNUM);
+	if (irq__register_device(PCI_DEVICE_ID_VIRTIO_RNG, &dev, &pin, &line) < 0)
+		return;
+
+	virtio_rng_pci_device.irq_pin	= pin;
+	virtio_rng_pci_device.irq_line	= line;
+	pci__register(&virtio_rng_pci_device, dev);
 
 	ioport__register(IOPORT_VIRTIO_RNG, &virtio_rng_io_ops, IOPORT_VIRTIO_RNG_SIZE);
 }
