/*
* vgaarb.c: Implements the VGA arbitration. For details refer to
* Documentation/vgaarbiter.txt
*
*
* (C) Copyright 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
* (C) Copyright 2007 Paulo R. Zanoni <przanoni@gmail.com>
* (C) Copyright 2007, 2009 Tiago Vignatti <vignatti@freedesktop.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS
* IN THE SOFTWARE.
*
*/
#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/miscdevice.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/vgaarb.h>
static void vga_arbiter_notify_clients(void);
/*
* 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; /* legacy IO lock count */
unsigned int mem_lock_cnt; /* legacy MEM lock count */
unsigned int io_norm_cnt; /* normal IO count */
unsigned int mem_norm_cnt; /* normal MEM count */
/* allow IRQ enable/disable hook */
void *cookie;
void (*irq_set_state)(void *cookie, bool enable);
unsigned int (*set_vga_decode)(void *cookie, bool decode);
};
static LIST_HEAD(vga_list);
static int vga_count, vga_decode_count;
static bool vga_arbiter_used;
static DEFINE_SPINLOCK(vga_lock);
static DECLARE_WAIT_QUEUE_HEAD(vga_wait_queue);
static const char *vga_iostate_to_str(unsigned int iostate)
{
/* Ignore VGA_RSRC_IO and VGA_RSRC_MEM */
iostate &= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
switch (iostate) {
case VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM:
return "io+mem";
case VGA_RSRC_LEGACY_IO:
return "io";
case VGA_RSRC_LEGACY_MEM:
return "mem";
}
return "none";
}
static int vga_str_to_iostate(char *buf, int str_size, int *io_state)
{
/* we could in theory hand out locks on IO and mem
* separately to userspace but it can cause deadlocks */
if (strncmp(buf, "none", 4) == 0) {
*io_state = VGA_RSRC_NONE;
return 1;
}
/* XXX We're not chekcing the str_size! */
if (strncmp(buf, "io+mem", 6) == 0)
goto both;
else if (strncmp(buf, "io", 2) == 0)
goto both;
else if (strncmp(buf