xref: /libpciaccess/src/common_vgaarb.c (revision 790e93c3)
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 #ifndef ANDROID
37 #include "config.h"
38 #endif
39 
40 #include "pciaccess.h"
41 #include "pciaccess_private.h"
42 
43 #define BUFSIZE 64
44 
45 static int
parse_string_to_decodes_rsrc(char * input,int * vga_count,struct pci_slot_match * match)46 parse_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;
121 fail:
122     return VGA_ARB_RSRC_NONE;
123 }
124 
125 int
pci_device_vgaarb_init(void)126 pci_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)) < 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 
156 void
pci_device_vgaarb_fini(void)157 pci_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  */
177 static int
vgaarb_write(int fd,char * buf,int len)178 vgaarb_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 
212 static const char *
rsrc_to_str(int iostate)213 rsrc_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 
227 int
pci_device_vgaarb_set_target(struct pci_device * dev)228 pci_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 
257 int
pci_device_vgaarb_decodes(int new_vgaarb_rsrc)258 pci_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 
286 int
pci_device_vgaarb_lock(void)287 pci_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 
304 int
pci_device_vgaarb_trylock(void)305 pci_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 
322 int
pci_device_vgaarb_unlock(void)323 pci_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 
pci_device_vgaarb_get_info(struct pci_device * dev,int * vga_count,int * rsrc_decodes)340 int 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