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