vgaarb: check pci_sys exists before initing vga arb
[platform/upstream/libpciaccess.git] / src / common_vgaarb.c
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
41 static int
42 parse_string_to_decodes_rsrc(char *input, int *vga_count, struct pci_slot_match *match)
43 {
44     char *tok;
45     char *input_sp, *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;
117 fail:
118     return VGA_ARB_RSRC_NONE;
119 }
120
121 int
122 pci_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
150 void
151 pci_device_vgaarb_fini(void)
152 {
153     close(pci_sys->vgaarb_fd);
154 }
155
156 /**
157  * Writes message on vga device. The messages are defined by the kernel
158  * implementation.
159  *
160  * \param fd    vga arbiter device.
161  * \param buf   message itself.
162  * \param len   message length.
163  *
164  * \return
165  * Zero on success, 1 if something gets wrong and 2 if fd is busy (only for
166  * 'trylock')
167  */
168 static int
169 vgaarb_write(int fd, char *buf, int len)
170 {
171     int ret;
172
173
174     buf[len] = '\0';
175
176     ret = write(fd, buf, len);
177     if (ret == -1) {
178         /* the user may have called "trylock" and didn't get the lock */
179         if (errno == EBUSY)
180             return 2;
181
182 #ifdef DEBUG
183         fprintf(stderr, "write error");
184 #endif
185         return 1;
186     }
187     else if (ret != len) {
188         /* it's need to receive the exactly amount required. */
189 #ifdef DEBUG
190         fprintf(stderr, "write error: wrote different than expected\n");
191 #endif
192         return 1;
193     }
194
195 #ifdef DEBUG
196     fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf);
197 #endif
198
199     return 0;
200 }
201
202
203 static const char *
204 rsrc_to_str(int iostate)
205 {
206     switch (iostate) {
207     case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM:
208         return "io+mem";
209     case VGA_ARB_RSRC_LEGACY_IO:
210         return "io";
211     case VGA_ARB_RSRC_LEGACY_MEM:
212         return "mem";
213     }
214
215     return "none";
216 }
217
218 int
219 pci_device_vgaarb_set_target(struct pci_device *dev)
220 {
221     int len;
222     char buf[BUFSIZE];
223     int ret;
224
225     if (!dev)
226         dev = pci_sys->vga_default_dev;
227     if (!dev)
228         return -1;
229
230     len = snprintf(buf, BUFSIZE, "target PCI:%04x:%02x:%02x.%x",
231                    dev->domain, dev->bus, dev->dev, dev->func);
232
233     ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
234     if (ret)
235         return ret;
236
237     ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
238     if (ret <= 0)
239         return -1;
240
241     dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL);
242     pci_sys->vga_target = dev;
243     return 0;
244 }
245
246 int
247 pci_device_vgaarb_decodes(int new_vgaarb_rsrc)
248 {
249     int len;
250     char buf[BUFSIZE];
251     int ret;
252     struct pci_device *dev = pci_sys->vga_target;
253
254     if (!dev)
255         return -1;
256     if (dev->vgaarb_rsrc == new_vgaarb_rsrc)
257         return 0;
258
259     len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(dev->vgaarb_rsrc));
260     ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
261     if (ret == 0)
262         dev->vgaarb_rsrc = new_vgaarb_rsrc;
263     return ret;
264 }
265
266 int
267 pci_device_vgaarb_lock(void)
268 {
269     int len;
270     char buf[BUFSIZE];
271     struct pci_device *dev = pci_sys->vga_target;
272
273     if (!dev)
274         return -1;
275
276     if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
277         return 0;
278
279     len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc));
280
281     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
282 }
283
284 int
285 pci_device_vgaarb_trylock(void)
286 {
287     int len;
288     char buf[BUFSIZE];
289     struct pci_device *dev = pci_sys->vga_target;
290
291     if (!dev)
292         return -1;
293
294     if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
295         return 0;
296
297     len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc));
298
299     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
300 }
301
302 int
303 pci_device_vgaarb_unlock(void)
304 {
305     int len;
306     char buf[BUFSIZE];
307     struct pci_device *dev = pci_sys->vga_target;
308
309     if (!dev)
310         return -1;
311
312     if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
313         return 0;
314
315     len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc));
316
317     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
318 }
319
320 int pci_device_vgaarb_get_info(struct pci_device *dev, int *vga_count, int *rsrc_decodes)
321 {
322     *vga_count = pci_sys->vga_count;
323     if (!dev)
324         return 0;
325
326     *rsrc_decodes = dev->vgaarb_rsrc;
327         return 0;
328 }