|
Packit |
7d1034 |
/*
|
|
Packit |
7d1034 |
* Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti
|
|
Packit |
7d1034 |
* 2009 Tiago Vignatti
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* Permission is hereby granted, free of charge, to any person
|
|
Packit |
7d1034 |
* obtaining a copy of this software and associated documentation
|
|
Packit |
7d1034 |
* files (the "Software"), to deal in the Software without
|
|
Packit |
7d1034 |
* restriction, including without limitation the rights to use,
|
|
Packit |
7d1034 |
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
Packit |
7d1034 |
* copies of the Software, and to permit persons to whom the
|
|
Packit |
7d1034 |
* Software is furnished to do so, subject to the following
|
|
Packit |
7d1034 |
* conditions:
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* The above copyright notice and this permission notice shall be
|
|
Packit |
7d1034 |
* included in all copies or substantial portions of the Software.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
Packit |
7d1034 |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
Packit |
7d1034 |
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
Packit |
7d1034 |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
Packit |
7d1034 |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
Packit |
7d1034 |
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
Packit |
7d1034 |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
Packit |
7d1034 |
* OTHER DEALINGS IN THE SOFTWARE.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
7d1034 |
#include "config.h"
|
|
Packit |
7d1034 |
#endif
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#include <stdio.h>
|
|
Packit |
7d1034 |
#include <string.h>
|
|
Packit |
7d1034 |
#include <unistd.h>
|
|
Packit |
7d1034 |
#include <fcntl.h>
|
|
Packit |
7d1034 |
#include <errno.h>
|
|
Packit |
7d1034 |
#include <stdlib.h>
|
|
Packit |
7d1034 |
#include <limits.h>
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#include "pciaccess.h"
|
|
Packit |
7d1034 |
#include "pciaccess_private.h"
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#define BUFSIZE 64
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
parse_string_to_decodes_rsrc(char *input, int *vga_count, struct pci_slot_match *match)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
char *tok;
|
|
Packit |
7d1034 |
char *input_sp = NULL, *count_sp, *pci_sp;
|
|
Packit |
7d1034 |
char tmp[32];
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
tok = strtok_r(input,",",&input_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
strncpy(tmp, input, 15);
|
|
Packit |
7d1034 |
tmp[15] = 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
tok = strtok_r(tmp,":",&count_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
tok = strtok_r(NULL, ":",&count_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
*vga_count = strtoul(tok, NULL, 10);
|
|
Packit |
7d1034 |
if (*vga_count == LONG_MAX)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#ifdef DEBUG
|
|
Packit |
7d1034 |
fprintf(stderr,"vga count is %d\n", *vga_count);
|
|
Packit |
7d1034 |
#endif
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
tok = strtok_r(NULL, ",",&input_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (match) {
|
|
Packit |
7d1034 |
strncpy(tmp, tok, 32);
|
|
Packit |
7d1034 |
tmp[31] = 0;
|
|
Packit |
7d1034 |
tok = strtok_r(tmp, ":", &pci_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
tok = strtok_r(NULL, ":", &pci_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
match->domain = strtoul(tok, NULL, 16);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
tok = strtok_r(NULL, ":", &pci_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
match->bus = strtoul(tok, NULL, 16);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
tok = strtok_r(NULL, ".", &pci_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
match->dev = strtoul(tok, NULL, 16);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
tok = strtok_r(NULL, ".", &pci_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
match->func = strtoul(tok, NULL, 16);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
tok = strtok_r(NULL, ",",&input_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
tok = strtok_r(tok, "=", &input_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
tok = strtok_r(NULL, "=", &input_sp);
|
|
Packit |
7d1034 |
if (!tok)
|
|
Packit |
7d1034 |
goto fail;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!strncmp(tok, "io+mem", 6))
|
|
Packit |
7d1034 |
return VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM;
|
|
Packit |
7d1034 |
if (!strncmp(tok, "io", 2))
|
|
Packit |
7d1034 |
return VGA_ARB_RSRC_LEGACY_IO;
|
|
Packit |
7d1034 |
if (!strncmp(tok, "mem", 3))
|
|
Packit |
7d1034 |
return VGA_ARB_RSRC_LEGACY_MEM;
|
|
Packit |
7d1034 |
fail:
|
|
Packit |
7d1034 |
return VGA_ARB_RSRC_NONE;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
int
|
|
Packit |
7d1034 |
pci_device_vgaarb_init(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
struct pci_slot_match match;
|
|
Packit |
7d1034 |
char buf[BUFSIZE + 1]; /* reading BUFSIZE characters, + 1 for NULL */
|
|
Packit |
7d1034 |
int ret, rsrc;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!pci_sys)
|
|
Packit |
7d1034 |
return -1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if ((pci_sys->vgaarb_fd = open ("/dev/vga_arbiter", O_RDWR | O_CLOEXEC)) < 0) {
|
|
Packit |
7d1034 |
return errno;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
|
|
Packit |
7d1034 |
if (ret <= 0)
|
|
Packit |
7d1034 |
return -1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
buf[ret] = 0; /* ret will never be greater than BUFSIZE */
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
memset(&match, 0xff, sizeof(match));
|
|
Packit |
7d1034 |
/* need to find the device to go back to and what it was decoding */
|
|
Packit |
7d1034 |
rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, &match);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
pci_sys->vga_default_dev = pci_device_find_by_slot(match.domain, match.bus, match.dev, match.func);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (pci_sys->vga_default_dev)
|
|
Packit |
7d1034 |
pci_sys->vga_default_dev->vgaarb_rsrc = rsrc;
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
void
|
|
Packit |
7d1034 |
pci_device_vgaarb_fini(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (!pci_sys)
|
|
Packit |
7d1034 |
return;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
close(pci_sys->vgaarb_fd);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Writes message on vga device. The messages are defined by the kernel
|
|
Packit |
7d1034 |
* implementation.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* \param fd vga arbiter device.
|
|
Packit |
7d1034 |
* \param buf message itself.
|
|
Packit |
7d1034 |
* \param len message length.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* \return
|
|
Packit |
7d1034 |
* Zero on success, 1 if something gets wrong and 2 if fd is busy (only for
|
|
Packit |
7d1034 |
* 'trylock')
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
vgaarb_write(int fd, char *buf, int len)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
int ret;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
buf[len] = '\0';
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ret = write(fd, buf, len);
|
|
Packit |
7d1034 |
if (ret == -1) {
|
|
Packit |
7d1034 |
/* the user may have called "trylock" and didn't get the lock */
|
|
Packit |
7d1034 |
if (errno == EBUSY)
|
|
Packit |
7d1034 |
return 2;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#ifdef DEBUG
|
|
Packit |
7d1034 |
fprintf(stderr, "write error");
|
|
Packit |
7d1034 |
#endif
|
|
Packit |
7d1034 |
return 1;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
else if (ret != len) {
|
|
Packit |
7d1034 |
/* it's need to receive the exactly amount required. */
|
|
Packit |
7d1034 |
#ifdef DEBUG
|
|
Packit |
7d1034 |
fprintf(stderr, "write error: wrote different than expected\n");
|
|
Packit |
7d1034 |
#endif
|
|
Packit |
7d1034 |
return 1;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#ifdef DEBUG
|
|
Packit |
7d1034 |
fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf);
|
|
Packit |
7d1034 |
#endif
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static const char *
|
|
Packit |
7d1034 |
rsrc_to_str(int iostate)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
switch (iostate) {
|
|
Packit |
7d1034 |
case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM:
|
|
Packit |
7d1034 |
return "io+mem";
|
|
Packit |
7d1034 |
case VGA_ARB_RSRC_LEGACY_IO:
|
|
Packit |
7d1034 |
return "io";
|
|
Packit |
7d1034 |
case VGA_ARB_RSRC_LEGACY_MEM:
|
|
Packit |
7d1034 |
return "mem";
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return "none";
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
int
|
|
Packit |
7d1034 |
pci_device_vgaarb_set_target(struct pci_device *dev)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
int len;
|
|
Packit |
7d1034 |
char buf[BUFSIZE + 1]; /* reading BUFSIZE characters, + 1 for NULL */
|
|
Packit |
7d1034 |
int ret;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!dev)
|
|
Packit |
7d1034 |
dev = pci_sys->vga_default_dev;
|
|
Packit |
7d1034 |
if (!dev)
|
|
Packit |
7d1034 |
return -1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
len = snprintf(buf, BUFSIZE, "target PCI:%04x:%02x:%02x.%x",
|
|
Packit |
7d1034 |
dev->domain, dev->bus, dev->dev, dev->func);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
|
|
Packit |
7d1034 |
if (ret)
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
|
|
Packit |
7d1034 |
if (ret <= 0)
|
|
Packit |
7d1034 |
return -1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
buf[ret] = 0; /* ret will never be greater than BUFSIZE */
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL);
|
|
Packit |
7d1034 |
pci_sys->vga_target = dev;
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
int
|
|
Packit |
7d1034 |
pci_device_vgaarb_decodes(int new_vgaarb_rsrc)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
int len;
|
|
Packit |
7d1034 |
char buf[BUFSIZE + 1]; /* reading BUFSIZE characters, + 1 for NULL */
|
|
Packit |
7d1034 |
int ret;
|
|
Packit |
7d1034 |
struct pci_device *dev = pci_sys->vga_target;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!dev)
|
|
Packit |
7d1034 |
return -1;
|
|
Packit |
7d1034 |
if (dev->vgaarb_rsrc == new_vgaarb_rsrc)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(new_vgaarb_rsrc));
|
|
Packit |
7d1034 |
ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
|
|
Packit |
7d1034 |
if (ret == 0)
|
|
Packit |
7d1034 |
dev->vgaarb_rsrc = new_vgaarb_rsrc;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
|
|
Packit |
7d1034 |
if (ret <= 0)
|
|
Packit |
7d1034 |
return -1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
buf[ret] = 0; /* ret will never be greater than BUFSIZE */
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
int
|
|
Packit |
7d1034 |
pci_device_vgaarb_lock(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
int len;
|
|
Packit |
7d1034 |
char buf[BUFSIZE];
|
|
Packit |
7d1034 |
struct pci_device *dev = pci_sys->vga_target;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!dev)
|
|
Packit |
7d1034 |
return -1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc));
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
int
|
|
Packit |
7d1034 |
pci_device_vgaarb_trylock(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
int len;
|
|
Packit |
7d1034 |
char buf[BUFSIZE];
|
|
Packit |
7d1034 |
struct pci_device *dev = pci_sys->vga_target;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!dev)
|
|
Packit |
7d1034 |
return -1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc));
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
int
|
|
Packit |
7d1034 |
pci_device_vgaarb_unlock(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
int len;
|
|
Packit |
7d1034 |
char buf[BUFSIZE];
|
|
Packit |
7d1034 |
struct pci_device *dev = pci_sys->vga_target;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!dev)
|
|
Packit |
7d1034 |
return -1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc));
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
int pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count, int *rsrc_decodes)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
*vga_count = pci_sys->vga_count;
|
|
Packit |
7d1034 |
if (!dev)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
*rsrc_decodes = dev->vgaarb_rsrc;
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|