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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 + * + * ",decodes=,owns=,locks= (ic,mc)" + * + * write : write a command to the arbiter. List of commands is: + * + * target : switch target to card (see below) + * lock : acquires locks on target ("none" is invalid io_state) + * trylock : non-blocking acquire locks on target + * unlock : release locks on target + * unlock all : release all locks on target held by this user + * decodes : 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 + * + * + */ + +#ifndef LINUX_VGA_H + +#include + +/* 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 */