common_vgaarb.c revision 6a94483f
1/* 2 * Copyright (c) 2007 Paulo R. Zanoni, Tiago Vignatti 3 * 2009 Tiago Vignatti 4 * 5 * Permission is hereby granted, free of charge, to any person 6 * obtaining a copy of this software and associated documentation 7 * files (the "Software"), to deal in the Software without 8 * restriction, including without limitation the rights to use, 9 * copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following 12 * conditions: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 * OTHER DEALINGS IN THE SOFTWARE. 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include <stdio.h> 33#include <string.h> 34#include <unistd.h> 35#include <fcntl.h> 36#include <errno.h> 37#include <stdlib.h> 38#include <limits.h> 39 40#include "pciaccess.h" 41#include "pciaccess_private.h" 42 43#define BUFSIZE 64 44 45static int 46parse_string_to_decodes_rsrc(char *input, int *vga_count, struct pci_slot_match *match) 47{ 48 char *tok; 49 char *input_sp = NULL, *count_sp, *pci_sp; 50 char tmp[32]; 51 52 tok = strtok_r(input,",",&input_sp); 53 if (!tok) 54 goto fail; 55 56 strncpy(tmp, input, 15); 57 tmp[15] = 0; 58 59 tok = strtok_r(tmp,":",&count_sp); 60 if (!tok) 61 goto fail; 62 tok = strtok_r(NULL, ":",&count_sp); 63 if (!tok) 64 goto fail; 65 66 *vga_count = strtoul(tok, NULL, 10); 67 if (*vga_count == LONG_MAX) 68 goto fail; 69 70#ifdef DEBUG 71 fprintf(stderr,"vga count is %d\n", *vga_count); 72#endif 73 74 tok = strtok_r(NULL, ",",&input_sp); 75 if (!tok) 76 goto fail; 77 78 if (match) { 79 strncpy(tmp, tok, 32); 80 tmp[31] = 0; 81 tok = strtok_r(tmp, ":", &pci_sp); 82 if (!tok) 83 goto fail; 84 tok = strtok_r(NULL, ":", &pci_sp); 85 if (!tok) 86 goto fail; 87 match->domain = strtoul(tok, NULL, 16); 88 89 tok = strtok_r(NULL, ":", &pci_sp); 90 if (!tok) 91 goto fail; 92 match->bus = strtoul(tok, NULL, 16); 93 94 tok = strtok_r(NULL, ".", &pci_sp); 95 if (!tok) 96 goto fail; 97 match->dev = strtoul(tok, NULL, 16); 98 99 tok = strtok_r(NULL, ".", &pci_sp); 100 if (!tok) 101 goto fail; 102 match->func = strtoul(tok, NULL, 16); 103 } 104 105 tok = strtok_r(NULL, ",",&input_sp); 106 if (!tok) 107 goto fail; 108 tok = strtok_r(tok, "=", &input_sp); 109 if (!tok) 110 goto fail; 111 tok = strtok_r(NULL, "=", &input_sp); 112 if (!tok) 113 goto fail; 114 115 if (!strncmp(tok, "io+mem", 6)) 116 return VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM; 117 if (!strncmp(tok, "io", 2)) 118 return VGA_ARB_RSRC_LEGACY_IO; 119 if (!strncmp(tok, "mem", 3)) 120 return VGA_ARB_RSRC_LEGACY_MEM; 121fail: 122 return VGA_ARB_RSRC_NONE; 123} 124 125int 126pci_device_vgaarb_init(void) 127{ 128 struct pci_slot_match match; 129 char buf[BUFSIZE]; 130 int ret, rsrc; 131 132 if (!pci_sys) 133 return -1; 134 135 if ((pci_sys->vgaarb_fd = open ("/dev/vga_arbiter", O_RDWR | O_CLOEXEC)) < 0) { 136 return errno; 137 } 138 139 ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 140 if (ret <= 0) 141 return -1; 142 143 memset(&match, 0xff, sizeof(match)); 144 /* need to find the device to go back to and what it was decoding */ 145 rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, &match); 146 147 pci_sys->vga_default_dev = pci_device_find_by_slot(match.domain, match.bus, match.dev, match.func); 148 149 if (pci_sys->vga_default_dev) 150 pci_sys->vga_default_dev->vgaarb_rsrc = rsrc; 151 return 0; 152} 153 154void 155pci_device_vgaarb_fini(void) 156{ 157 if (!pci_sys) 158 return; 159 160 close(pci_sys->vgaarb_fd); 161} 162 163/** 164 * Writes message on vga device. The messages are defined by the kernel 165 * implementation. 166 * 167 * \param fd vga arbiter device. 168 * \param buf message itself. 169 * \param len message length. 170 * 171 * \return 172 * Zero on success, 1 if something gets wrong and 2 if fd is busy (only for 173 * 'trylock') 174 */ 175static int 176vgaarb_write(int fd, char *buf, int len) 177{ 178 int ret; 179 180 181 buf[len] = '\0'; 182 183 ret = write(fd, buf, len); 184 if (ret == -1) { 185 /* the user may have called "trylock" and didn't get the lock */ 186 if (errno == EBUSY) 187 return 2; 188 189#ifdef DEBUG 190 fprintf(stderr, "write error"); 191#endif 192 return 1; 193 } 194 else if (ret != len) { 195 /* it's need to receive the exactly amount required. */ 196#ifdef DEBUG 197 fprintf(stderr, "write error: wrote different than expected\n"); 198#endif 199 return 1; 200 } 201 202#ifdef DEBUG 203 fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf); 204#endif 205 206 return 0; 207} 208 209 210static const char * 211rsrc_to_str(int iostate) 212{ 213 switch (iostate) { 214 case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM: 215 return "io+mem"; 216 case VGA_ARB_RSRC_LEGACY_IO: 217 return "io"; 218 case VGA_ARB_RSRC_LEGACY_MEM: 219 return "mem"; 220 } 221 222 return "none"; 223} 224 225int 226pci_device_vgaarb_set_target(struct pci_device *dev) 227{ 228 int len; 229 char buf[BUFSIZE]; 230 int ret; 231 232 if (!dev) 233 dev = pci_sys->vga_default_dev; 234 if (!dev) 235 return -1; 236 237 len = snprintf(buf, BUFSIZE, "target PCI:%04x:%02x:%02x.%x", 238 dev->domain, dev->bus, dev->dev, dev->func); 239 240 ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len); 241 if (ret) 242 return ret; 243 244 ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 245 if (ret <= 0) 246 return -1; 247 248 dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL); 249 pci_sys->vga_target = dev; 250 return 0; 251} 252 253int 254pci_device_vgaarb_decodes(int new_vgaarb_rsrc) 255{ 256 int len; 257 char buf[BUFSIZE]; 258 int ret; 259 struct pci_device *dev = pci_sys->vga_target; 260 261 if (!dev) 262 return -1; 263 if (dev->vgaarb_rsrc == new_vgaarb_rsrc) 264 return 0; 265 266 len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(new_vgaarb_rsrc)); 267 ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len); 268 if (ret == 0) 269 dev->vgaarb_rsrc = new_vgaarb_rsrc; 270 271 ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 272 if (ret <= 0) 273 return -1; 274 275 parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL); 276 277 return ret; 278} 279 280int 281pci_device_vgaarb_lock(void) 282{ 283 int len; 284 char buf[BUFSIZE]; 285 struct pci_device *dev = pci_sys->vga_target; 286 287 if (!dev) 288 return -1; 289 290 if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 291 return 0; 292 293 len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc)); 294 295 return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 296} 297 298int 299pci_device_vgaarb_trylock(void) 300{ 301 int len; 302 char buf[BUFSIZE]; 303 struct pci_device *dev = pci_sys->vga_target; 304 305 if (!dev) 306 return -1; 307 308 if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 309 return 0; 310 311 len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc)); 312 313 return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 314} 315 316int 317pci_device_vgaarb_unlock(void) 318{ 319 int len; 320 char buf[BUFSIZE]; 321 struct pci_device *dev = pci_sys->vga_target; 322 323 if (!dev) 324 return -1; 325 326 if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 327 return 0; 328 329 len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc)); 330 331 return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 332} 333 334int pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count, int *rsrc_decodes) 335{ 336 *vga_count = pci_sys->vga_count; 337 if (!dev) 338 return 0; 339 340 *rsrc_decodes = dev->vgaarb_rsrc; 341 return 0; 342} 343