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