common_vgaarb.c revision cad31331
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#include <stdio.h> 29#include <string.h> 30#include <unistd.h> 31#include <fcntl.h> 32#include <errno.h> 33#include <stdlib.h> 34#include <limits.h> 35 36#include "config.h" 37#include "pciaccess.h" 38#include "pciaccess_private.h" 39 40#define BUFSIZE 64 41 42static int 43parse_string_to_decodes_rsrc(char *input, int *vga_count, struct pci_slot_match *match) 44{ 45 char *tok; 46 char *input_sp = NULL, *count_sp, *pci_sp; 47 char tmp[32]; 48 49 tok = strtok_r(input,",",&input_sp); 50 if (!tok) 51 goto fail; 52 53 strncpy(tmp, input, 15); 54 tmp[15] = 0; 55 56 tok = strtok_r(tmp,":",&count_sp); 57 if (!tok) 58 goto fail; 59 tok = strtok_r(NULL, ":",&count_sp); 60 if (!tok) 61 goto fail; 62 63 *vga_count = strtoul(tok, NULL, 10); 64 if (*vga_count == LONG_MAX) 65 goto fail; 66 67#ifdef DEBUG 68 fprintf(stderr,"vga count is %d\n", *vga_count); 69#endif 70 71 tok = strtok_r(NULL, ",",&input_sp); 72 if (!tok) 73 goto fail; 74 75 if (match) { 76 strncpy(tmp, tok, 32); 77 tmp[31] = 0; 78 tok = strtok_r(tmp, ":", &pci_sp); 79 if (!tok) 80 goto fail; 81 tok = strtok_r(NULL, ":", &pci_sp); 82 if (!tok) 83 goto fail; 84 match->domain = strtoul(tok, NULL, 16); 85 86 tok = strtok_r(NULL, ":", &pci_sp); 87 if (!tok) 88 goto fail; 89 match->bus = strtoul(tok, NULL, 16); 90 91 tok = strtok_r(NULL, ".", &pci_sp); 92 if (!tok) 93 goto fail; 94 match->dev = strtoul(tok, NULL, 16); 95 96 tok = strtok_r(NULL, ".", &pci_sp); 97 if (!tok) 98 goto fail; 99 match->func = strtoul(tok, NULL, 16); 100 } 101 102 tok = strtok_r(NULL, ",",&input_sp); 103 if (!tok) 104 goto fail; 105 tok = strtok_r(tok, "=", &input_sp); 106 if (!tok) 107 goto fail; 108 tok = strtok_r(NULL, "=", &input_sp); 109 if (!tok) 110 goto fail; 111 112 if (!strncmp(tok, "io+mem", 6)) 113 return VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM; 114 if (!strncmp(tok, "io", 2)) 115 return VGA_ARB_RSRC_LEGACY_IO; 116 if (!strncmp(tok, "mem", 3)) 117 return VGA_ARB_RSRC_LEGACY_MEM; 118fail: 119 return VGA_ARB_RSRC_NONE; 120} 121 122int 123pci_device_vgaarb_init(void) 124{ 125 struct pci_slot_match match; 126 char buf[BUFSIZE]; 127 int ret, rsrc; 128 129 if (!pci_sys) 130 return -1; 131 132 if ((pci_sys->vgaarb_fd = open ("/dev/vga_arbiter", O_RDWR | O_CLOEXEC)) < 0) { 133 return errno; 134 } 135 136 ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 137 if (ret <= 0) 138 return -1; 139 140 memset(&match, 0xff, sizeof(match)); 141 /* need to find the device to go back to and what it was decoding */ 142 rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, &match); 143 144 pci_sys->vga_default_dev = pci_device_find_by_slot(match.domain, match.bus, match.dev, match.func); 145 146 if (pci_sys->vga_default_dev) 147 pci_sys->vga_default_dev->vgaarb_rsrc = rsrc; 148 return 0; 149} 150 151void 152pci_device_vgaarb_fini(void) 153{ 154 if (!pci_sys) 155 return; 156 157 close(pci_sys->vgaarb_fd); 158} 159 160/** 161 * Writes message on vga device. The messages are defined by the kernel 162 * implementation. 163 * 164 * \param fd vga arbiter device. 165 * \param buf message itself. 166 * \param len message length. 167 * 168 * \return 169 * Zero on success, 1 if something gets wrong and 2 if fd is busy (only for 170 * 'trylock') 171 */ 172static int 173vgaarb_write(int fd, char *buf, int len) 174{ 175 int ret; 176 177 178 buf[len] = '\0'; 179 180 ret = write(fd, buf, len); 181 if (ret == -1) { 182 /* the user may have called "trylock" and didn't get the lock */ 183 if (errno == EBUSY) 184 return 2; 185 186#ifdef DEBUG 187 fprintf(stderr, "write error"); 188#endif 189 return 1; 190 } 191 else if (ret != len) { 192 /* it's need to receive the exactly amount required. */ 193#ifdef DEBUG 194 fprintf(stderr, "write error: wrote different than expected\n"); 195#endif 196 return 1; 197 } 198 199#ifdef DEBUG 200 fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf); 201#endif 202 203 return 0; 204} 205 206 207static const char * 208rsrc_to_str(int iostate) 209{ 210 switch (iostate) { 211 case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM: 212 return "io+mem"; 213 case VGA_ARB_RSRC_LEGACY_IO: 214 return "io"; 215 case VGA_ARB_RSRC_LEGACY_MEM: 216 return "mem"; 217 } 218 219 return "none"; 220} 221 222int 223pci_device_vgaarb_set_target(struct pci_device *dev) 224{ 225 int len; 226 char buf[BUFSIZE]; 227 int ret; 228 229 if (!dev) 230 dev = pci_sys->vga_default_dev; 231 if (!dev) 232 return -1; 233 234 len = snprintf(buf, BUFSIZE, "target PCI:%04x:%02x:%02x.%x", 235 dev->domain, dev->bus, dev->dev, dev->func); 236 237 ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len); 238 if (ret) 239 return ret; 240 241 ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 242 if (ret <= 0) 243 return -1; 244 245 dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL); 246 pci_sys->vga_target = dev; 247 return 0; 248} 249 250int 251pci_device_vgaarb_decodes(int new_vgaarb_rsrc) 252{ 253 int len; 254 char buf[BUFSIZE]; 255 int ret; 256 struct pci_device *dev = pci_sys->vga_target; 257 258 if (!dev) 259 return -1; 260 if (dev->vgaarb_rsrc == new_vgaarb_rsrc) 261 return 0; 262 263 len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(new_vgaarb_rsrc)); 264 ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len); 265 if (ret == 0) 266 dev->vgaarb_rsrc = new_vgaarb_rsrc; 267 268 ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE); 269 if (ret <= 0) 270 return -1; 271 272 parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL); 273 274 return ret; 275} 276 277int 278pci_device_vgaarb_lock(void) 279{ 280 int len; 281 char buf[BUFSIZE]; 282 struct pci_device *dev = pci_sys->vga_target; 283 284 if (!dev) 285 return -1; 286 287 if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 288 return 0; 289 290 len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc)); 291 292 return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 293} 294 295int 296pci_device_vgaarb_trylock(void) 297{ 298 int len; 299 char buf[BUFSIZE]; 300 struct pci_device *dev = pci_sys->vga_target; 301 302 if (!dev) 303 return -1; 304 305 if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 306 return 0; 307 308 len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc)); 309 310 return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 311} 312 313int 314pci_device_vgaarb_unlock(void) 315{ 316 int len; 317 char buf[BUFSIZE]; 318 struct pci_device *dev = pci_sys->vga_target; 319 320 if (!dev) 321 return -1; 322 323 if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1) 324 return 0; 325 326 len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc)); 327 328 return vgaarb_write(pci_sys->vgaarb_fd, buf, len); 329} 330 331int pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count, int *rsrc_decodes) 332{ 333 *vga_count = pci_sys->vga_count; 334 if (!dev) 335 return 0; 336 337 *rsrc_decodes = dev->vgaarb_rsrc; 338 return 0; 339} 340