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 + 1]; /* reading BUFSIZE characters, + 1 for NULL */ 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 buf[ret] = 0; /* ret will never be greater than BUFSIZE */ 144 145 memset(&match, 0xff, sizeof(match)); 146 /* need to find the device to go back to and what it was decoding */ 147 rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, &match); 148 149 pci_sys->vga_default_dev = pci_device_find_by_slot(match.domain, match.bus, match.dev, match.func); 150 151 if (pci_sys->vga_default_dev) 152 pci_sys->vga_default_dev->vgaarb_rsrc = rsrc; 153 return 0; 154} 155 156void 157pci_device_vgaarb_fini(void) 158{ 159 if (!pci_sys) 160 return; 161 162 close(pci_sys->vgaarb_fd); 163} 164 165/** 166 * Writes message on vga device. The messages are defined by the kernel 167 * implementation. 168 * 169 * \param fd vga arbiter device. 170 * \param buf message itself. 171 * \param len message length. 172 * 173 * \return 174 * Zero on success, 1 if something gets wrong and 2 if fd is busy (only for 175 * 'trylock') 176 */ 177static int 178vgaarb_write(int fd, char *buf, int len) 179{ 180 int ret; 181 182 183 buf[len] = '\0'; 184 185 ret = write(fd, buf, len); 186 if (ret == -1) { 187 /* the user may have called "trylock" and didn't get the lock */ 188 if (errno == EBUSY) 189 return 2; 190 191#ifdef DEBUG 192 fprintf(stderr, "write error"); 193#endif 194 return 1; 195 } 196 else if (ret != len) { 197 /* it's need to receive the exactly amount required. */ 198#ifdef DEBUG 199 fprintf(stderr, "write error: wrote different than expected\n"); 200#endif 201 return 1; 202 } 203 204#ifdef DEBUG 205 fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf); 206#endif 207 208 return 0; 209} 210 211 212static const char * 213rsrc_to_str(int iostate) 214{ 215 switch (iostate) { 216 case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM: 217 return "io+mem"; 218 case VGA_ARB_RSRC_LEGACY_IO: 219 return "io"; 220 case VGA_ARB_RSRC_LEGACY_MEM: 221 return "mem"; 222 } 223 224 return "none"; 225} 226 227int 228pci_device_vgaarb_set_target(struct pci_device *dev) 229{ 230 int len; 231 char buf[BUFSIZE + 1]; /* reading BUFSIZE characters, + 1 for NULL */ 232 int ret; 233 234 if (!dev) 235 dev = pci_sys->vga_default_dev; 236 if (!dev) 237 return -1; 238 239 len = snprintf(buf, BUFSIZE, "target PCI:%04x:%02x:%02x.%x", 240 dev->domain, dev->bus, dev->dev, dev->func); 241 242 ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len); 243 if (ret) 244 return ret; 245 246 ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 247 if (ret <= 0) 248 return -1; 249 250 buf[ret] = 0; /* ret will never be greater than BUFSIZE */ 251 252 dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL); 253 pci_sys->vga_target = dev; 254 return 0; 255} 256 257int 258pci_device_vgaarb_decodes(int new_vgaarb_rsrc) 259{ 260 int len; 261 char buf[BUFSIZE + 1]; /* reading BUFSIZE characters, + 1 for NULL */ 262 int ret; 263 struct pci_device *dev = pci_sys->vga_target; 264 265 if (!dev) 266 return -1; 267 if (dev->vgaarb_rsrc == new_vgaarb_rsrc) 268 return 0; 269 270 len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(new_vgaarb_rsrc)); 271 ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len); 272 if (ret == 0) 273 dev->vgaarb_rsrc = new_vgaarb_rsrc; 274 275 ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 276 if (ret <= 0) 277 return -1; 278 279 buf[ret] = 0; /* ret will never be greater than BUFSIZE */ 280 281 parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL); 282 283 return ret; 284} 285 286int 287pci_device_vgaarb_lock(void) 288{ 289 int len; 290 char buf[BUFSIZE]; 291 struct pci_device *dev = pci_sys->vga_target; 292 293 if (!dev) 294 return -1; 295 296 if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 297 return 0; 298 299 len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc)); 300 301 return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 302} 303 304int 305pci_device_vgaarb_trylock(void) 306{ 307 int len; 308 char buf[BUFSIZE]; 309 struct pci_device *dev = pci_sys->vga_target; 310 311 if (!dev) 312 return -1; 313 314 if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 315 return 0; 316 317 len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc)); 318 319 return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 320} 321 322int 323pci_device_vgaarb_unlock(void) 324{ 325 int len; 326 char buf[BUFSIZE]; 327 struct pci_device *dev = pci_sys->vga_target; 328 329 if (!dev) 330 return -1; 331 332 if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 333 return 0; 334 335 len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc)); 336 337 return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 338} 339 340int pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count, int *rsrc_decodes) 341{ 342 *vga_count = pci_sys->vga_count; 343 if (!dev) 344 return 0; 345 346 *rsrc_decodes = dev->vgaarb_rsrc; 347 return 0; 348} 349