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