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