149f872b5Smrg/* 249f872b5Smrg * Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti 349f872b5Smrg * 2009 Tiago Vignatti 449f872b5Smrg * 549f872b5Smrg * Permission is hereby granted, free of charge, to any person 649f872b5Smrg * obtaining a copy of this software and associated documentation 749f872b5Smrg * files (the "Software"), to deal in the Software without 849f872b5Smrg * restriction, including without limitation the rights to use, 949f872b5Smrg * copy, modify, merge, publish, distribute, sublicense, and/or sell 1049f872b5Smrg * copies of the Software, and to permit persons to whom the 1149f872b5Smrg * Software is furnished to do so, subject to the following 1249f872b5Smrg * conditions: 1349f872b5Smrg * 1449f872b5Smrg * The above copyright notice and this permission notice shall be 1549f872b5Smrg * included in all copies or substantial portions of the Software. 1649f872b5Smrg * 1749f872b5Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1849f872b5Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 1949f872b5Smrg * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2049f872b5Smrg * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 2149f872b5Smrg * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 2249f872b5Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2349f872b5Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2449f872b5Smrg * OTHER DEALINGS IN THE SOFTWARE. 2549f872b5Smrg * 2649f872b5Smrg */ 2749f872b5Smrg 286a94483fSmrg#ifdef HAVE_CONFIG_H 296a94483fSmrg#include "config.h" 306a94483fSmrg#endif 316a94483fSmrg 3249f872b5Smrg#include <stdio.h> 3349f872b5Smrg#include <string.h> 3449f872b5Smrg#include <unistd.h> 3549f872b5Smrg#include <fcntl.h> 3649f872b5Smrg#include <errno.h> 3749f872b5Smrg#include <stdlib.h> 3849f872b5Smrg#include <limits.h> 3949f872b5Smrg 4049f872b5Smrg#include "pciaccess.h" 4149f872b5Smrg#include "pciaccess_private.h" 4249f872b5Smrg 4349f872b5Smrg#define BUFSIZE 64 4449f872b5Smrg 4549f872b5Smrgstatic int 4649f872b5Smrgparse_string_to_decodes_rsrc(char *input, int *vga_count, struct pci_slot_match *match) 4749f872b5Smrg{ 4849f872b5Smrg char *tok; 4949f872b5Smrg char *input_sp = NULL, *count_sp, *pci_sp; 5049f872b5Smrg char tmp[32]; 5149f872b5Smrg 5249f872b5Smrg tok = strtok_r(input,",",&input_sp); 5349f872b5Smrg if (!tok) 5449f872b5Smrg goto fail; 5549f872b5Smrg 5649f872b5Smrg strncpy(tmp, input, 15); 5749f872b5Smrg tmp[15] = 0; 5849f872b5Smrg 5949f872b5Smrg tok = strtok_r(tmp,":",&count_sp); 6049f872b5Smrg if (!tok) 6149f872b5Smrg goto fail; 6249f872b5Smrg tok = strtok_r(NULL, ":",&count_sp); 6349f872b5Smrg if (!tok) 6449f872b5Smrg goto fail; 6549f872b5Smrg 6649f872b5Smrg *vga_count = strtoul(tok, NULL, 10); 6749f872b5Smrg if (*vga_count == LONG_MAX) 6849f872b5Smrg goto fail; 6949f872b5Smrg 7049f872b5Smrg#ifdef DEBUG 7149f872b5Smrg fprintf(stderr,"vga count is %d\n", *vga_count); 7249f872b5Smrg#endif 7349f872b5Smrg 7449f872b5Smrg tok = strtok_r(NULL, ",",&input_sp); 7549f872b5Smrg if (!tok) 7649f872b5Smrg goto fail; 7749f872b5Smrg 7849f872b5Smrg if (match) { 7949f872b5Smrg strncpy(tmp, tok, 32); 8049f872b5Smrg tmp[31] = 0; 8149f872b5Smrg tok = strtok_r(tmp, ":", &pci_sp); 8249f872b5Smrg if (!tok) 8349f872b5Smrg goto fail; 8449f872b5Smrg tok = strtok_r(NULL, ":", &pci_sp); 8549f872b5Smrg if (!tok) 8649f872b5Smrg goto fail; 8749f872b5Smrg match->domain = strtoul(tok, NULL, 16); 8849f872b5Smrg 8949f872b5Smrg tok = strtok_r(NULL, ":", &pci_sp); 9049f872b5Smrg if (!tok) 9149f872b5Smrg goto fail; 9249f872b5Smrg match->bus = strtoul(tok, NULL, 16); 9349f872b5Smrg 9449f872b5Smrg tok = strtok_r(NULL, ".", &pci_sp); 9549f872b5Smrg if (!tok) 9649f872b5Smrg goto fail; 9749f872b5Smrg match->dev = strtoul(tok, NULL, 16); 9849f872b5Smrg 9949f872b5Smrg tok = strtok_r(NULL, ".", &pci_sp); 10049f872b5Smrg if (!tok) 10149f872b5Smrg goto fail; 10249f872b5Smrg match->func = strtoul(tok, NULL, 16); 10349f872b5Smrg } 10449f872b5Smrg 10549f872b5Smrg tok = strtok_r(NULL, ",",&input_sp); 10649f872b5Smrg if (!tok) 10749f872b5Smrg goto fail; 10849f872b5Smrg tok = strtok_r(tok, "=", &input_sp); 10949f872b5Smrg if (!tok) 11049f872b5Smrg goto fail; 11149f872b5Smrg tok = strtok_r(NULL, "=", &input_sp); 11249f872b5Smrg if (!tok) 11349f872b5Smrg goto fail; 11449f872b5Smrg 11549f872b5Smrg if (!strncmp(tok, "io+mem", 6)) 11649f872b5Smrg return VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM; 11749f872b5Smrg if (!strncmp(tok, "io", 2)) 11849f872b5Smrg return VGA_ARB_RSRC_LEGACY_IO; 11949f872b5Smrg if (!strncmp(tok, "mem", 3)) 12049f872b5Smrg return VGA_ARB_RSRC_LEGACY_MEM; 12149f872b5Smrgfail: 12249f872b5Smrg return VGA_ARB_RSRC_NONE; 12349f872b5Smrg} 12449f872b5Smrg 12549f872b5Smrgint 12649f872b5Smrgpci_device_vgaarb_init(void) 12749f872b5Smrg{ 12849f872b5Smrg struct pci_slot_match match; 12949310723Smrg char buf[BUFSIZE + 1]; /* reading BUFSIZE characters, + 1 for NULL */ 13049f872b5Smrg int ret, rsrc; 13149f872b5Smrg 13249f872b5Smrg if (!pci_sys) 13349f872b5Smrg return -1; 13449f872b5Smrg 135cad31331Smrg if ((pci_sys->vgaarb_fd = open ("/dev/vga_arbiter", O_RDWR | O_CLOEXEC)) < 0) { 13649f872b5Smrg return errno; 13749f872b5Smrg } 13849f872b5Smrg 13949f872b5Smrg ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 14049f872b5Smrg if (ret <= 0) 14149f872b5Smrg return -1; 14249f872b5Smrg 14349310723Smrg buf[ret] = 0; /* ret will never be greater than BUFSIZE */ 14449310723Smrg 14549f872b5Smrg memset(&match, 0xff, sizeof(match)); 14649f872b5Smrg /* need to find the device to go back to and what it was decoding */ 14749f872b5Smrg rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, &match); 14849f872b5Smrg 14949f872b5Smrg pci_sys->vga_default_dev = pci_device_find_by_slot(match.domain, match.bus, match.dev, match.func); 15049f872b5Smrg 15149f872b5Smrg if (pci_sys->vga_default_dev) 15249f872b5Smrg pci_sys->vga_default_dev->vgaarb_rsrc = rsrc; 15349f872b5Smrg return 0; 15449f872b5Smrg} 15549f872b5Smrg 15649f872b5Smrgvoid 15749f872b5Smrgpci_device_vgaarb_fini(void) 15849f872b5Smrg{ 15949f872b5Smrg if (!pci_sys) 16049f872b5Smrg return; 16149f872b5Smrg 16249f872b5Smrg close(pci_sys->vgaarb_fd); 16349f872b5Smrg} 16449f872b5Smrg 16549f872b5Smrg/** 16649f872b5Smrg * Writes message on vga device. The messages are defined by the kernel 16749f872b5Smrg * implementation. 16849f872b5Smrg * 16949f872b5Smrg * \param fd vga arbiter device. 17049f872b5Smrg * \param buf message itself. 17149f872b5Smrg * \param len message length. 17249f872b5Smrg * 17349f872b5Smrg * \return 17449f872b5Smrg * Zero on success, 1 if something gets wrong and 2 if fd is busy (only for 17549f872b5Smrg * 'trylock') 17649f872b5Smrg */ 17749f872b5Smrgstatic int 17849f872b5Smrgvgaarb_write(int fd, char *buf, int len) 17949f872b5Smrg{ 18049f872b5Smrg int ret; 18149f872b5Smrg 18249f872b5Smrg 18349f872b5Smrg buf[len] = '\0'; 18449f872b5Smrg 18549f872b5Smrg ret = write(fd, buf, len); 18649f872b5Smrg if (ret == -1) { 18749f872b5Smrg /* the user may have called "trylock" and didn't get the lock */ 18849f872b5Smrg if (errno == EBUSY) 18949f872b5Smrg return 2; 19049f872b5Smrg 19149f872b5Smrg#ifdef DEBUG 19249f872b5Smrg fprintf(stderr, "write error"); 19349f872b5Smrg#endif 19449f872b5Smrg return 1; 19549f872b5Smrg } 19649f872b5Smrg else if (ret != len) { 19749f872b5Smrg /* it's need to receive the exactly amount required. */ 19849f872b5Smrg#ifdef DEBUG 19949f872b5Smrg fprintf(stderr, "write error: wrote different than expected\n"); 20049f872b5Smrg#endif 20149f872b5Smrg return 1; 20249f872b5Smrg } 20349f872b5Smrg 20449f872b5Smrg#ifdef DEBUG 20549f872b5Smrg fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf); 20649f872b5Smrg#endif 20749f872b5Smrg 20849f872b5Smrg return 0; 20949f872b5Smrg} 21049f872b5Smrg 21149f872b5Smrg 21249f872b5Smrgstatic const char * 21349f872b5Smrgrsrc_to_str(int iostate) 21449f872b5Smrg{ 21549f872b5Smrg switch (iostate) { 21649f872b5Smrg case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM: 21749f872b5Smrg return "io+mem"; 21849f872b5Smrg case VGA_ARB_RSRC_LEGACY_IO: 21949f872b5Smrg return "io"; 22049f872b5Smrg case VGA_ARB_RSRC_LEGACY_MEM: 22149f872b5Smrg return "mem"; 22249f872b5Smrg } 22349f872b5Smrg 22449f872b5Smrg return "none"; 22549f872b5Smrg} 22649f872b5Smrg 22749f872b5Smrgint 22849f872b5Smrgpci_device_vgaarb_set_target(struct pci_device *dev) 22949f872b5Smrg{ 23049f872b5Smrg int len; 23149310723Smrg char buf[BUFSIZE + 1]; /* reading BUFSIZE characters, + 1 for NULL */ 23249f872b5Smrg int ret; 23349f872b5Smrg 23449f872b5Smrg if (!dev) 23549f872b5Smrg dev = pci_sys->vga_default_dev; 23649f872b5Smrg if (!dev) 23749f872b5Smrg return -1; 23849f872b5Smrg 23949f872b5Smrg len = snprintf(buf, BUFSIZE, "target PCI:%04x:%02x:%02x.%x", 24049f872b5Smrg dev->domain, dev->bus, dev->dev, dev->func); 24149f872b5Smrg 24249f872b5Smrg ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len); 24349f872b5Smrg if (ret) 24449f872b5Smrg return ret; 24549f872b5Smrg 24649f872b5Smrg ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 24749f872b5Smrg if (ret <= 0) 24849f872b5Smrg return -1; 24949f872b5Smrg 25049310723Smrg buf[ret] = 0; /* ret will never be greater than BUFSIZE */ 25149310723Smrg 25249f872b5Smrg dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL); 25349f872b5Smrg pci_sys->vga_target = dev; 25449f872b5Smrg return 0; 25549f872b5Smrg} 25649f872b5Smrg 25749f872b5Smrgint 25849f872b5Smrgpci_device_vgaarb_decodes(int new_vgaarb_rsrc) 25949f872b5Smrg{ 26049f872b5Smrg int len; 26149310723Smrg char buf[BUFSIZE + 1]; /* reading BUFSIZE characters, + 1 for NULL */ 26249f872b5Smrg int ret; 26349f872b5Smrg struct pci_device *dev = pci_sys->vga_target; 26449f872b5Smrg 26549f872b5Smrg if (!dev) 26649f872b5Smrg return -1; 26749f872b5Smrg if (dev->vgaarb_rsrc == new_vgaarb_rsrc) 26849f872b5Smrg return 0; 26949f872b5Smrg 27028d65773Smrg len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(new_vgaarb_rsrc)); 27149f872b5Smrg ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len); 27249f872b5Smrg if (ret == 0) 27349f872b5Smrg dev->vgaarb_rsrc = new_vgaarb_rsrc; 27428d65773Smrg 27528d65773Smrg ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 27628d65773Smrg if (ret <= 0) 27728d65773Smrg return -1; 27828d65773Smrg 27949310723Smrg buf[ret] = 0; /* ret will never be greater than BUFSIZE */ 28049310723Smrg 28128d65773Smrg parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL); 28228d65773Smrg 28349f872b5Smrg return ret; 28449f872b5Smrg} 28549f872b5Smrg 28649f872b5Smrgint 28749f872b5Smrgpci_device_vgaarb_lock(void) 28849f872b5Smrg{ 28949f872b5Smrg int len; 29049f872b5Smrg char buf[BUFSIZE]; 29149f872b5Smrg struct pci_device *dev = pci_sys->vga_target; 29249f872b5Smrg 29349f872b5Smrg if (!dev) 29449f872b5Smrg return -1; 29549f872b5Smrg 29649f872b5Smrg if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 29749f872b5Smrg return 0; 29849f872b5Smrg 29949f872b5Smrg len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc)); 30049f872b5Smrg 30149f872b5Smrg return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 30249f872b5Smrg} 30349f872b5Smrg 30449f872b5Smrgint 30549f872b5Smrgpci_device_vgaarb_trylock(void) 30649f872b5Smrg{ 30749f872b5Smrg int len; 30849f872b5Smrg char buf[BUFSIZE]; 30949f872b5Smrg struct pci_device *dev = pci_sys->vga_target; 31049f872b5Smrg 31149f872b5Smrg if (!dev) 31249f872b5Smrg return -1; 31349f872b5Smrg 31449f872b5Smrg if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 31549f872b5Smrg return 0; 31649f872b5Smrg 31749f872b5Smrg len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc)); 31849f872b5Smrg 31949f872b5Smrg return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 32049f872b5Smrg} 32149f872b5Smrg 32249f872b5Smrgint 32349f872b5Smrgpci_device_vgaarb_unlock(void) 32449f872b5Smrg{ 32549f872b5Smrg int len; 32649f872b5Smrg char buf[BUFSIZE]; 32749f872b5Smrg struct pci_device *dev = pci_sys->vga_target; 32849f872b5Smrg 32949f872b5Smrg if (!dev) 33049f872b5Smrg return -1; 33149f872b5Smrg 33249f872b5Smrg if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 33349f872b5Smrg return 0; 33449f872b5Smrg 33549f872b5Smrg len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc)); 33649f872b5Smrg 33749f872b5Smrg return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 33849f872b5Smrg} 33949f872b5Smrg 34049f872b5Smrgint pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count, int *rsrc_decodes) 34149f872b5Smrg{ 34249f872b5Smrg *vga_count = pci_sys->vga_count; 34349f872b5Smrg if (!dev) 34449f872b5Smrg return 0; 34549f872b5Smrg 34649f872b5Smrg *rsrc_decodes = dev->vgaarb_rsrc; 34749f872b5Smrg return 0; 34849f872b5Smrg} 349