Index: linux-work/include/linux/pci.h
===================================================================
--- linux-work.orig/include/linux/pci.h	2005-03-09 12:48:54.000000000 +1100
+++ linux-work/include/linux/pci.h	2005-03-09 13:18:10.000000000 +1100
@@ -1064,5 +1064,6 @@
 #define PCIPCI_VSFX		16
 #define PCIPCI_ALIMAGIK		32
 
+
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */
Index: linux-work/drivers/pci/Makefile
===================================================================
--- linux-work.orig/drivers/pci/Makefile	2005-03-09 12:48:54.000000000 +1100
+++ linux-work/drivers/pci/Makefile	2005-03-09 13:18:10.000000000 +1100
@@ -4,7 +4,7 @@
 
 obj-y		+= access.o bus.o probe.o remove.o pci.o quirks.o \
 			names.o pci-driver.o search.o pci-sysfs.o \
-			rom.o
+			rom.o vga.o
 obj-$(CONFIG_PROC_FS) += proc.o
 
 ifndef CONFIG_SPARC64
Index: linux-work/drivers/pci/remove.c
===================================================================
--- linux-work.orig/drivers/pci/remove.c	2005-03-09 12:48:54.000000000 +1100
+++ linux-work/drivers/pci/remove.c	2005-03-09 13:18:10.000000000 +1100
@@ -26,6 +26,7 @@
 
 static void pci_destroy_dev(struct pci_dev *dev)
 {
+	vga_arbiter_del_pci_device(pdev);
 	pci_proc_detach_device(dev);
 	pci_remove_sysfs_dev_files(dev);
 	device_unregister(&dev->dev);
Index: linux-work/drivers/pci/pci.h
===================================================================
--- linux-work.orig/drivers/pci/pci.h	2005-03-09 12:48:54.000000000 +1100
+++ linux-work/drivers/pci/pci.h	2005-03-09 13:18:10.000000000 +1100
@@ -88,3 +88,7 @@
 	return NULL;
 }
 
+
+/* VGA arbiter functions */
+extern void vga_arbiter_add_pci_device(struct pci_dev *pdev);
+extern void vga_arbiter_del_pci_device(struct pci_dev *pdev);
Index: linux-work/drivers/pci/vga.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-work/drivers/pci/vga.c	2005-03-09 18:13:58.000000000 +1100
@@ -0,0 +1,704 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/poll.h>
+#include <linux/vga.h>
+#include <linux/miscdevice.h>
+
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include "pci.h"
+
+struct vga_arb_private;
+
+/*
+ * We keep a list of all vga devices in the system to speed
+ * up the various operations of the arbiter
+ */
+struct vga_device
+{
+	struct list_head	list;
+	struct pci_dev		*pdev;
+	unsigned int		decodes;	/* what does it decodes */
+	unsigned int		owns;		/* what does it owns */
+	unsigned int		locks;		/* what does it locks */
+	unsigned int		io_lock_cnt;	/* IO lock count */
+	unsigned int		mem_lock_cnt;	/* MEM lock count */
+};
+
+static LIST_HEAD(		vga_list);
+static spinlock_t	       	vga_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_WAIT_QUEUE_HEAD(	vga_wait_queue);
+
+#ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
+static struct pci_dev		*vga_default;
+#endif
+
+static void vga_arb_device_card_gone(struct pci_dev *pdev);
+
+/* Find somebody in our list */
+static struct vga_device *vgadev_find(struct pci_dev *pdev)
+{
+	struct vga_device *vgadev;
+
+	list_for_each_entry(vgadev, &vga_list, list)
+		if (pdev == vgadev->pdev)
+			return vgadev;
+	return NULL;
+}
+
+/* Returns the default VGA device (vgacon's babe) */
+#ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
+struct pci_dev *vga_default_device(void)
+{
+	return vga_default;
+}
+#endif
+
+/* Architecture can override enabling/disabling of a given
+ * device resources here
+ */
+#ifndef __ARCH_HAS_VGA_DISABLE_RESOURCES
+static inline void vga_disable_resources(struct pci_dev *pdev,
+					 unsigned int rsrc,
+					 unsigned int change_bridge)
+{
+	struct pci_bus *bus;
+	struct pci_dev *bridge;
+	u16 cmd;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	if (rsrc & VGA_RSRC_IO)
+		cmd &= ~PCI_COMMAND_IO;
+	if (rsrc & VGA_RSRC_MEM)
+		cmd &= ~PCI_COMMAND_MEMORY;
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+	if (!change_bridge)
+		return;
+
+	bus = pdev->bus;
+	while (bus) {
+		bridge = bus->self;
+		if (bridge) {
+			pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &cmd);
+			if (cmd & PCI_BRIDGE_CTL_VGA) {
+				cmd &= ~PCI_BRIDGE_CTL_VGA;
+				pci_write_config_word(bridge,
+						      PCI_BRIDGE_CONTROL, cmd);
+			}
+		}
+		bus = bus->parent;
+	}
+}
+#endif
+
+#ifndef __ARCH_HAS_VGA_ENABLE_RESOURCES
+static inline void vga_enable_resources(struct pci_dev *pdev,
+					 unsigned int rsrc)
+{
+	struct pci_bus *bus;
+	struct pci_dev *bridge;
+	u16 cmd;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	if (rsrc & VGA_RSRC_IO)
+		cmd |= PCI_COMMAND_IO;
+	if (rsrc & VGA_RSRC_MEM)
+		cmd |= PCI_COMMAND_MEMORY;
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
+
+	bus = pdev->bus;
+	while (bus) {
+		bridge = bus->self;
+		if (bridge) {
+			pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &cmd);
+			if (!(cmd & PCI_BRIDGE_CTL_VGA)) {
+				cmd |= PCI_BRIDGE_CTL_VGA;
+				pci_write_config_word(bridge,
+						      PCI_BRIDGE_CONTROL, cmd);
+			}
+		}
+		bus = bus->parent;
+	}
+}
+#endif
+
+static struct vga_device * __vga_tryget(struct vga_device *vgadev,
+					unsigned int rsrc)
+{
+	unsigned int wants, match;
+	struct vga_device *conflict;
+
+	/* Check what resources we need to acquire */
+	wants = rsrc & !vgadev->owns;
+
+	/* We already own everything, just mark locked & bye bye */
+	if (wants == 0)
+		goto lock_them;
+
+	/* Ok, we don't, let's find out how we need to kick off */
+	list_for_each_entry(conflict, &vga_list, list) {
+		unsigned int lwants = wants;
+		unsigned int change_bridge = 0;
+
+		/* Don't conflict with myself */
+		if (vgadev == conflict)
+			continue;
+
+		/* Check if the architecture allows a conflict between those
+		 * 2 devices or if they are on separate domains
+		 */
+		if (!vga_conflicts(vgadev->pdev, conflict->pdev))
+			continue;
+
+		/* We have a possible conflict. before we go further, we must
+		 * check if we sit on the same bus as the conflicting device.
+		 * if we don't, then we must tie both IO and MEM resources
+		 * together since there is only a single bit controlling
+		 * VGA forwarding on P2P bridges
+		 */
+		if (vgadev->pdev->bus != conflict->pdev->bus) {
+			change_bridge = 1;
+			lwants = VGA_RSRC_IO | VGA_RSRC_MEM;
+		}
+
+		/* Check if the guy has a lock on the resource. If he does,
+		 * return the conflicting entry
+		 */
+		if (conflict->locks & lwants)
+			return conflict;
+
+		/* Ok, now check if he owns the resource we want. We don't need
+		 * to check "decodes" since it should be impossible to have
+		 * own resources you don't decode unless I have a bug in this
+		 * code...
+		 */
+		WARN_ON(conflict->owns & !conflict->decodes);
+		match = lwants & conflict->owns;
+		if (!match)
+			continue;
+
+		/* looks like he doesn't have a lock, we can steal
+		 * them from him
+		 */
+		vga_disable_resources(conflict->pdev, lwants, change_bridge);
+		conflict->owns &= ~lwants;
+	}
+
+	/* ok dude, we got it, everybody has been disabled, let's
+	 * enable us. Make sure we don't mark a bit in "owns" that
+	 * we don't also have in "decodes". We can lock resources
+	 * we don't decode but not own them.
+	 */
+	vga_enable_resources(vgadev->pdev, wants);
+	vgadev->owns |= (wants & vgadev->decodes);
+ lock_them:
+	vgadev->locks |= rsrc;
+	if (rsrc & VGA_RSRC_IO)
+		vgadev->io_lock_cnt++;
+	if (rsrc & VGA_RSRC_MEM)
+		vgadev->mem_lock_cnt++;
+
+	return NULL;
+}
+
+static void __vga_put(struct vga_device *vgadev, unsigned int rsrc)
+{
+	unsigned int old_locks = vgadev->locks;
+
+	if ((rsrc & VGA_RSRC_IO) && vgadev->io_lock_cnt > 0)
+		vgadev->io_lock_cnt--;
+	if ((rsrc & VGA_RSRC_MEM) && vgadev->mem_lock_cnt > 0)
+		vgadev->mem_lock_cnt++;
+
+	/* Just clear lock bits, we do lazy operations so we don't really
+	 * have to bother about anything else at this point
+	 */
+	if (vgadev->io_lock_cnt == 0)
+		vgadev->locks &= ~VGA_RSRC_IO;
+	if (vgadev->mem_lock_cnt == 0)
+		vgadev->locks &= ~VGA_RSRC_MEM;
+
+	/* Kick the wait queue in case somebody was waiting if we actually
+	 * released something
+	 */
+	if (old_locks != vgadev->locks)
+		wake_up_all(&vga_wait_queue);
+}
+
+int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible)
+{
+	struct vga_device *vgadev, *conflict;
+	unsigned long flags;
+        wait_queue_t wait;
+	int rc = 0;
+
+	if (pdev == NULL)
+		pdev = vga_default_device();
+	if (pdev == NULL)
+		return 0;
+	for (;;) {
+		spin_lock_irqsave(&vga_lock, flags);
+		vgadev = vgadev_find(pdev);
+		if (vgadev == NULL) {
+			spin_unlock_irqrestore(&vga_lock, flags);
+			rc = -ENODEV;
+			break;
+		}
+		conflict = __vga_tryget(vgadev, rsrc);
+		spin_unlock_irqrestore(&vga_lock, flags);
+		if (conflict == NULL)
+			break;
+
+
+		/* We have a conflict, we wait until somebody kicks the
+		 * work queue. Currently we have one work queue that we
+		 * kick each time some resources are released, but it would
+		 * be fairly easy to have a per device one so that we only
+		 * need to attach to the conflicting device
+		 */
+		init_waitqueue_entry(&wait, current);
+		add_wait_queue(&vga_wait_queue, &wait);
+		set_current_state(interruptible ?
+				  TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+		if (signal_pending(current)) {
+			rc = -EINTR;
+			break;
+		}
+		schedule();
+		remove_wait_queue(&vga_wait_queue, &wait);
+		set_current_state(TASK_RUNNING);
+	}
+	return rc;
+}
+
+int vga_tryget(struct pci_dev *pdev, unsigned int rsrc)
+{
+	struct vga_device *vgadev;
+	unsigned long flags;
+	int rc = 0;
+
+	if (pdev == NULL)
+		pdev = vga_default_device();
+	if (pdev == NULL)
+		return 0;
+	spin_lock_irqsave(&vga_lock, flags);
+	vgadev = vgadev_find(pdev);
+	if (vgadev == NULL) {
+		rc = -ENODEV;
+		goto bail;
+	}
+	if (__vga_tryget(vgadev, rsrc))
+		rc = -EBUSY;
+ bail:
+	spin_unlock_irqrestore(&vga_lock, flags);
+	return rc;
+}
+
+void vga_put(struct pci_dev *pdev, unsigned int rsrc)
+{
+	struct vga_device *vgadev;
+	unsigned long flags;
+
+	if (pdev == NULL)
+		pdev = vga_default_device();
+	if (pdev == NULL)
+		return;
+	spin_lock_irqsave(&vga_lock, flags);
+	vgadev = vgadev_find(pdev);
+	if (vgadev == NULL)
+		goto bail;
+	__vga_put(vgadev, rsrc);
+ bail:
+	spin_unlock_irqrestore(&vga_lock, flags);
+}
+
+/*
+ * Currently, we assume that the "initial" setup of the system is
+ * sane, that is we don't come up with conflicting devices, which
+ * would be annoying. We could double check and be better at
+ * deciding who is the default here, but we don't. 
+ */
+void vga_arbiter_add_pci_device(struct pci_dev *pdev)
+{
+	struct vga_device *vgadev;
+	unsigned long flags;
+	struct pci_bus *bus;
+	struct pci_dev *bridge;
+	u16 cmd;
+
+	/* Only deal with VGA class devices */
+	if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+		return;
+
+	/* Allocate structure */
+	vgadev = kmalloc(sizeof(struct vga_device), GFP_KERNEL);
+	if (vgadev == NULL) {
+		/* What to do on allocation failure ? For now, let's
+		 * just do nothing, I'm not sure there is anything saner
+		 * to be done
+		 */
+		return;
+	}
+
+	memset(vgadev, 0, sizeof(*vgadev));
+
+	/* Take lock & check for duplicates */
+	spin_lock_irqsave(&vga_lock, flags);
+	if (vgadev_find(pdev) != NULL) {
+		BUG_ON(1);
+		goto fail;
+	}
+	vgadev->pdev = pdev;
+
+	/* By default, assume we decode everything */
+	vgadev->decodes = VGA_RSRC_IO | VGA_RSRC_MEM;
+
+	/* Mark that we "own" resources based on our enables, we will
+	 * clear that below if the bridge isn't forwarding
+	 */
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	if (cmd & PCI_COMMAND_IO)
+		vgadev->owns |= VGA_RSRC_IO;
+	if (cmd & PCI_COMMAND_MEMORY)
+		vgadev->owns |= VGA_RSRC_MEM;
+
+	/* Check if VGA cycles can get down to us */
+	bus = pdev->bus;
+	while (bus) {
+		bridge = bus->self;
+		if (bridge) {
+			u16 l;
+			pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &l);
+			if (!(l & PCI_BRIDGE_CTL_VGA)) {
+				vgadev->owns = 0;
+				break;
+			}
+		}
+		bus = bus->parent;
+	}
+
+	/* Deal with VGA default device. Use first enabled one
+	 * by default if arch doesn't have it's own hook
+	 */
+#ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
+	if (vga_default == NULL && (vgadev->owns & VGA_RSRC_MEM) &&
+	    (vgadev->owns & VGA_RSRC_IO))
+		vga_default = pdev;
+
+#endif
+
+	/* Add to the list */
+	list_add(&vgadev->list, &vga_list);
+	spin_unlock_irqrestore(&vga_lock, flags);
+	return;
+ fail:
+	spin_unlock_irqrestore(&vga_lock, flags);
+	kfree(vgadev);
+}
+
+void vga_arbiter_del_pci_device(struct pci_dev *pdev)
+{
+	struct vga_device *vgadev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vga_lock, flags);
+	vgadev = vgadev_find(pdev);
+	if (vgadev == NULL)
+		goto bail;
+
+	/* Remove entry from list */
+	list_del(&vgadev->list);
+
+	/* Notify userland driver that the device is gone so it discards
+	 * it's copies of the pci_dev pointer
+	 */
+	vga_arb_device_card_gone(pdev);
+
+	/* Wake up all possible waiters */
+	wake_up_all(&vga_wait_queue);
+ bail:
+	spin_unlock_irqrestore(&vga_lock, flags);
+	if (vgadev)
+		kfree(vgadev);
+}
+
+void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes)
+{
+	struct vga_device *vgadev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vga_lock, flags);
+	vgadev = vgadev_find(pdev);
+	if (vgadev == NULL)
+		goto bail;
+
+	vgadev->decodes = decodes;
+	vgadev->owns &= decodes;
+
+	/* XXX if somebody is going from "doesn't decode" to "decodes" state
+	 * here, additional care must be taken. Basically, we probably want
+	 * to disable it preventively in that case, but I have to make sure
+	 * of that...
+	 */
+ bail:
+	spin_unlock_irqrestore(&vga_lock, flags);
+}
+
+
+/*
+ * Char driver implementation
+ *
+ * Semantics is:
+ *
+ *  open	: open user instance of the arbitrer. by default, it's
+ *                attached to the default VGA device of the system.
+ *
+ *  close	: close user instance, release locks
+ *
+ *  read	: return a string indicating the status of the target.
+ *                an IO state string is of the form {io,mem,io+mem,none},
+ *                mc and ic are respectively mem and io lock counts (for
+ *                debugging/diagnostic only). "decodes" indicate what the
+ *                card currently decodes, "owns" indicates what is currently
+ *                enabled on it, and "locks" indicates what is locked by this
+ *                card. If the card is unplugged, we get "invalid" then for
+ *                card_ID and an -ENODEV error is returned for any command
+ *                until a new card is targeted
+ *
+ *   "<card_ID>,decodes=<io_state>,owns=<io_state>,locks=<io_state> (ic,mc)"
+ *
+ * write	: write a command to the arbiter. List of commands is:
+ *
+ *   target <card_ID>   : switch target to card <card_ID> (see below)
+ *   lock <io_state>    : acquires locks on target ("none" is invalid io_state)
+ *   trylock <io_state> : non-blocking acquire locks on target
+ *   unlock <io_state>  : release locks on target
+ *   unlock all         : release all locks on target held by this user
+ *   decodes <io_state> : set the legacy decoding attributes for the card
+ * 
+ * poll         : event if something change on any card (not just the target)
+ *
+ * card_ID is of the form "PCI:domain:bus:dev.fn". It can be set to "default"
+ * to go back to the system default card. Currently, only PCI is supported as
+ * a prefix, but the userland API may support other bus types in the future,
+ * even if the current kernel implementation doesn't.
+ * To switch back to the default card, use "default".
+ *
+ * Note about locks:
+ *
+ * The driver keeps track of which user has what locks on which card. It
+ * supports stacking, like the kernel one. This complexifies the implementation
+ * a bit, but makes the arbiter more tolerant to userspace problems and able
+ * to properly cleanup in all cases when a process dies.
+ * Currently, a max of 16 cards simultaneously can have locks issued from
+ * userspace for a given user (file descriptor instance) of the arbiter.
+ *
+ * If the device is hot-unplugged,
+ */
+
+#define MAX_USER_CARDS		16
+#define PCI_INVALID_CARD	((struct pci_dev *)-1UL)
+
+/*
+ * Each user has an array of these, tracking which cards have locks
+ */
+struct vga_arb_user_card
+{
+	struct pci_dev	*pdev;
+	unsigned int	mem_cnt;
+	unsigned int	io_cnt;
+};
+
+struct vga_arb_private
+{
+	struct list_head		list;
+	struct pci_dev 			*target;
+	struct vga_arb_user_card	cards[MAX_USER_CARDS];
+	spinlock_t			lock;
+};
+
+static LIST_HEAD(	vga_user_list);
+static spinlock_t	vga_user_lock = SPIN_LOCK_UNLOCKED;
+
+static const char *vga_iostate_to_str(unsigned int iostate)
+{
+	switch(iostate) {
+	case VGA_RSRC_IO | VGA_RSRC_MEM:
+		return "io+mem";
+	case VGA_RSRC_IO:
+		return "io";
+	case VGA_RSRC_MEM:
+		return "mem";
+	}
+	return "none";
+}
+
+static ssize_t vga_arb_read(struct file *file, char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct vga_arb_private *priv = file->private_data;
+	struct vga_device *vgadev;
+	struct pci_dev *pdev;
+	unsigned long flags;
+	size_t len;
+	int rc;
+	char *lbuf;
+
+	lbuf = kmalloc(1024, GFP_KERNEL);
+	if (lbuf == NULL)
+		return -ENOMEM;
+
+	/* Shields against vga_arb_device_card_gone (pci_dev going
+	 * away), and allows access to vga list
+	 */
+	spin_lock_irqsave(&vga_lock, flags);
+
+	/* If we are targetting the default, use it */
+	pdev = priv->target;
+	if (pdev == NULL)
+		pdev = vga_default_device();
+	if (pdev == NULL || pdev == PCI_INVALID_CARD) {
+		spin_unlock_irqrestore(&vga_lock, flags);
+		len = sprintf(lbuf, "invalid");
+		goto done;
+	}
+	
+	/* Find card vgadev structure */
+	vgadev = vgadev_find(pdev);
+	if (vgadev == NULL) {
+		/* Wow, it's not in the list, that shouldn't happen,
+		 * let's fix us up and return invalid card
+		 */
+		if (pdev == priv->target)
+			vga_arb_device_card_gone(pdev);
+		spin_unlock_irqrestore(&vga_lock, flags);
+		len = sprintf(lbuf, "invalid");
+		goto done;
+	}
+
+	/* Fill the buffer with infos */
+	len = snprintf(lbuf, 1024,
+		       "PCI:%s,decodes=%s,owns=%s,locks=%s (%d,%d)\n",
+		       pci_name(pdev),
+		       vga_iostate_to_str(vgadev->decodes),
+		       vga_iostate_to_str(vgadev->owns),
+		       vga_iostate_to_str(vgadev->locks),
+		       vgadev->io_lock_cnt, vgadev->mem_lock_cnt);
+
+	spin_unlock_irqrestore(&vga_lock, flags);
+ done:
+	/* Copy that to user */
+	if ((*ppos) > len)
+		return 0;
+	len = len - *ppos;
+	if (len > count)
+		len = count;
+	rc = copy_to_user(buf, lbuf, len);
+	kfree(buf);
+	if (rc)
+		return -EFAULT;
+	*ppos += len;
+	return len;
+		
+}
+
+static ssize_t vga_arb_write(struct file *file, const char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	return -1;
+}
+
+static unsigned int vga_arb_fpoll(struct file *file, poll_table *wait)
+{
+	struct vga_arb_private *priv = file->private_data;
+
+	if (priv == NULL)
+		return -ENODEV;
+	poll_wait(file, &vga_wait_queue, wait);	
+	return POLLIN;
+}
+
+static int vga_arb_open(struct inode *inode, struct file *file)
+{
+	struct vga_arb_private *priv;
+	unsigned long flags;
+
+	priv = kmalloc(sizeof(struct vga_arb_private), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+	memset(priv, 0, sizeof(*priv));
+	spin_lock_init(&priv->lock);
+	file->private_data = priv;
+
+	spin_lock_irqsave(&vga_user_lock, flags);
+	list_add(&priv->list, &vga_user_list);
+	spin_unlock_irqrestore(&vga_user_lock, flags);
+
+	return 0;
+}
+
+static int vga_arb_release(struct inode *inode, struct file *file)
+{
+	struct vga_arb_private *priv = file->private_data;
+	struct vga_arb_user_card *uc;
+	unsigned long flags;
+	int i;
+
+	if (priv == NULL)
+		return -ENODEV;
+
+	spin_lock_irqsave(&vga_user_lock, flags);
+	list_del(&priv->list);
+	for (i = 0; i < MAX_USER_CARDS; i ++) {
+		uc = &priv->cards[i];
+		if (uc->pdev == NULL)
+			continue;
+		while(uc->io_cnt--)
+			vga_put(uc->pdev, VGA_RSRC_MEM);
+		while(uc->mem_cnt--)
+			vga_put(uc->pdev, VGA_RSRC_MEM);
+	}
+	spin_unlock_irqrestore(&vga_user_lock, flags);
+
+	kfree(priv);
+
+	return 0;
+}
+
+static void vga_arb_device_card_gone(struct pci_dev *pdev)
+{
+}
+
+static struct file_operations vga_arb_device_fops = {
+	.read		= vga_arb_read,
+	.write		= vga_arb_write,
+	.poll		= vga_arb_fpoll,
+	.open		= vga_arb_open,
+	.release	= vga_arb_release,
+};
+
+static struct miscdevice vga_arb_device = {
+	MISC_DYNAMIC_MINOR, "vga_arbiter", &vga_arb_device_fops
+};
+
+static int __init vga_arb_device_init(void)
+{
+	int rc;
+
+	rc = misc_register(&vga_arb_device);
+	if (rc < 0)
+		printk(KERN_ERR "VGA Arbiter: error %d registering device\n",
+		       rc);	
+	return rc;
+}
+device_initcall(vga_arb_device_init);
+
Index: linux-work/include/linux/vga.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-work/include/linux/vga.h	2005-03-09 14:15:12.000000000 +1100
@@ -0,0 +1,161 @@
+/*
+ *	vga.h
+ *
+ *	VGA Arbiter functions
+ *
+ *	Copyright 2005 Benjamin Herrenschmidt
+ *	               <benh@kernel.crashing.org>
+ *
+ */
+
+#ifndef LINUX_VGA_H
+
+#include <asm/vga.h>
+
+/* Legacy VGA regions */
+#define VGA_RSRC_IO	0x01
+#define VGA_RSRC_MEM	0x02
+
+/* Passing that instead of a pci_dev to use the system "default"
+ * device, that is the one used by vgacon. Archs will probably
+ * have to provide their own vga_default_device();
+ */
+#define VGA_DEFAULT_DEVICE	(NULL)
+
+/* For use by clients */
+
+/**
+ *	vga_set_legacy_decoding
+ *
+ *	@pdev: pci device of the VGA card
+ *	@decodes: bit mask of what legacy regions the card decodes
+ *
+ *	Indicates to the arbiter if the card decodes legacy VGA IOs,
+ *	legacy VGA Memory, both, or none. All cards default to both,
+ *	the card driver (fbdev for example) should tell the arbiter
+ *	if it has disabled legacy decoding, so the card can be left
+ *	out of the arbitration process (and can be safe to take
+ *	interrupts at any time.
+ */
+extern void vga_set_legacy_decoding(struct pci_dev *pdev,
+				    unsigned int decodes);
+
+/**
+ *	vga_get		- acquire & locks legacy VGA resources
+ *
+ *	pdev: pci device of the VGA card or NULL for the system default
+ *	rsrc: bit mask of resources to acquire and lock
+ *	interruptible: blocking should be interruptible by signals ?
+ *
+ *	This function acquires legacy VGA resources for the given
+ *	card and mark those resources locked.
+ *	The arbiter will first look for all VGA cards that might conflict
+ *	and disable their IOs and/or Memory access, inlcuding VGA forwarding
+ *	on P2P bridges if necessary, so that the requested resources can
+ *	be used. Then, the card is marked as locking these resources and
+ *	the IO and/or Memory accesse are enabled on the card (including
+ *	VGA forwarding on parent P2P bridges if any).
+ *	This function will block if some conflicting card is already locking
+ *	one of the required resources (or any resource on a different bus
+ *	segment, since P2P bridges don't differenciate VGA memory and IO
+ *	afaik). You can indicate wether this blocking should be interruptible
+ *	by a signal (for userland interface) or not.
+ *	Must not be called at interrupt time or in atomic context.
+ *	If the card already owns the resources, the function succeeds.
+ *	Nested calls are supported (a per-resource counter is maintained)
+ */
+
+extern int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible);
+
+/**
+ *	vga_get_interruptible
+ *
+ *	Shortcut to vga_get
+ */
+
+static inline int vga_get_interruptible(struct pci_dev *pdev,
+					unsigned int rsrc)
+{
+	return vga_get(pdev, rsrc, 1);
+}
+
+/**
+ *	vga_get_interruptible
+ *
+ *	Shortcut to vga_get
+ */
+
+static inline int vga_get_uninterruptible(struct pci_dev *pdev,
+					  unsigned int rsrc)
+{
+	return vga_get(pdev, rsrc, 0);
+}
+
+/**
+ *	vga_tryget	- try to acquire & lock legacy VGA resources
+ *
+ *	@pdev: pci devivce of VGA card or NULL for system default
+ *	@rsrc: bit mask of resources to acquire and lock
+ *
+ *	This function performs the same operation as vga_get(), but
+ *	will return an error (-EBUSY) instead of blocking if the resources
+ *	are already locked by another card. It can be called in any context
+ */
+
+extern int vga_tryget(struct pci_dev *pdev, unsigned int rsrc);
+
+/**
+ *	vga_put		- release lock on legacy VGA resources
+ *
+ *	@pdev: pci device of VGA card or NULL for system default
+ *	@rsrc: but mask of resource to release
+ *
+ *	This function releases resources previously locked by vga_get()
+ *	or vga_tryget(). The resources aren't disabled right away, so
+ *	that a subsequence vga_get() on the same card will succeed
+ *	immediately. Resources have a counter, so locks are only
+ *	released if the counter reaches 0.
+ */
+
+extern void vga_put(struct pci_dev *pdev, unsigned int rsrc);
+
+
+/**
+ *	vga_default_device
+ *
+ * 	This can be defined by the platform. The default implementation
+ * 	is rather dumb and will probably only work properly on single
+ * 	vga card setups and/or x86 platforms.
+ *
+ * 	If your VGA default device is not PCI, you'll have to return
+ * 	NULL here. In this case, I assume it will not conflict with
+ * 	any PCI card. If this is not true, I'll have to define two archs
+ * 	hooks for enabling/disabling the VGA default device if that is
+ * 	possible. This may be a problem with real _ISA_ VGA cards, in
+ * 	addition to a PCI one. I don't know at this point how to deal
+ * 	with that card. Can theirs IOs be disabled at all ? If not, then
+ * 	I suppose it's a matter of having the proper arch hook telling
+ * 	us about it, so we basically never allow anybody to succeed a
+ * 	vga_get()...
+ */
+
+#ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
+extern struct pci_dev *vga_default_device(void);
+#endif
+
+/**
+ *	vga_conflicts
+ *
+ *	Architectures should define this if they have several
+ * 	independant PCI domains that can afford concurrent VGA
+ *	decoding
+ */
+
+#ifndef __ARCH_HAS_VGA_CONFLICT
+static inline int vga_conflicts(struct pci_dev *p1, struct pci_dev *p2)
+{
+	return 1;
+}
+#endif
+
+#endif /* LINUX_VGA_H */
