vgaarb: change API to target taking a device + lock/unlock not taking one
[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 count[16];
46
47     strncpy(count, input, 10);
48     count[11] = 0;
49
50     tok = strtok(count,":");
51     if (!tok)
52         goto fail;
53     tok = strtok(NULL, "");
54     if (!tok)
55         goto fail;
56
57     *vga_count = strtoul(tok, NULL, 10);
58     if (*vga_count == LONG_MAX)
59         goto fail;
60
61 #ifdef DEBUG
62     fprintf(stderr,"vga count is %d\n", *vga_count);
63 #endif
64
65     tok = strtok(input, ",");
66     if (!tok)
67         goto fail;
68
69     if (match) {
70         tok = strtok(NULL, ":");
71         if (!tok)
72             goto fail;
73         match->domain = strtoul(tok, NULL, 16);
74
75         tok = strtok(NULL, ":");
76         if (!tok)
77             goto fail;
78         match->bus = strtoul(tok, NULL, 16);
79
80         tok = strtok(NULL, ".");
81         if (!tok)
82             goto fail;
83         match->dev = strtoul(tok, NULL, 16);
84
85         tok = strtok(NULL, ".");
86         if (!tok)
87             goto fail;
88         match->func = strtoul(tok, NULL, 16);
89     }
90
91     tok = strtok(NULL, ",");
92     if (!tok)
93         goto fail;
94     tok = strtok(tok, "=");
95     if (!tok)
96         goto fail;
97     tok = strtok(NULL, "=");
98     if (!tok)
99         goto fail;
100
101     if (!strncmp(tok, "io+mem", 6))
102         return VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM;
103     if (!strncmp(tok, "io", 2))
104         return VGA_ARB_RSRC_LEGACY_IO;
105     if (!strncmp(tok, "mem", 3))
106         return VGA_ARB_RSRC_LEGACY_MEM;
107 fail:
108     return VGA_ARB_RSRC_NONE;
109 }
110
111 int
112 pci_device_vgaarb_init(void)
113 {
114     struct pci_slot_match match;
115     char buf[BUFSIZE];
116     int ret, rsrc;
117     if ((pci_sys->vgaarb_fd = open ("/dev/vga_arbiter", O_RDWR)) < 0) {
118         return errno;
119     }
120
121     ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
122     if (ret <= 0)
123         return -1;
124
125     memset(&match, 0xff, sizeof(match));
126     /* need to find the device to go back to and what it was decoding */
127     rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, &match);
128     
129     pci_sys->vga_default_dev = pci_device_find_by_slot(match.domain, match.bus, match.dev, match.func);
130     
131     if (pci_sys->vga_default_dev)
132         pci_sys->vga_default_dev->vgaarb_rsrc = rsrc;
133     return 0;
134 }
135
136 void
137 pci_device_vgaarb_fini(void)
138 {
139     close(pci_sys->vgaarb_fd);
140 }
141
142 /**
143  * Writes message on vga device. The messages are defined by the kernel
144  * implementation.
145  *
146  * \param fd    vga arbiter device.
147  * \param buf   message itself.
148  * \param len   message length.
149  *
150  * \return
151  * Zero on success, 1 if something gets wrong and 2 if fd is busy (only for
152  * 'trylock')
153  */
154 static int
155 vgaarb_write(int fd, char *buf, int len)
156 {
157     int ret;
158
159
160     buf[len] = '\0';
161
162     ret = write(fd, buf, len);
163     if (ret == -1) {
164         /* the user may have called "trylock" and didn't get the lock */
165         if (errno == EBUSY)
166             return 2;
167
168 #ifdef DEBUG
169         fprintf(stderr, "write error");
170 #endif
171         return 1;
172     }
173     else if (ret != len) {
174         /* it's need to receive the exactly amount required. */
175 #ifdef DEBUG
176         fprintf(stderr, "write error: wrote different than expected\n");
177 #endif
178         return 1;
179     }
180
181 #ifdef DEBUG
182     fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf);
183 #endif
184
185     return 0;
186 }
187
188
189 static const char *
190 rsrc_to_str(int iostate)
191 {
192     switch (iostate) {
193     case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM:
194         return "io+mem";
195     case VGA_ARB_RSRC_LEGACY_IO:
196         return "io";
197     case VGA_ARB_RSRC_LEGACY_MEM:
198         return "mem";
199     }
200
201     return "none";
202 }
203
204 int
205 pci_device_vgaarb_set_target(struct pci_device *dev)
206 {
207     int len;
208     char buf[BUFSIZE];
209     int ret;
210
211     if (!dev)
212         dev = pci_sys->vga_default_dev;
213     if (!dev)
214         return -1;
215
216     len = snprintf(buf, BUFSIZE, "target PCI:%d:%d:%d.%d",
217                    dev->domain, dev->bus, dev->dev, dev->func);
218
219     ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
220     if (ret)
221         return ret;
222
223     ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
224     if (ret <= 0)
225         return -1;
226
227     dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf, &pci_sys->vga_count, NULL);
228     pci_sys->vga_target = dev;
229     return 0;
230 }
231
232 int
233 pci_device_vgaarb_decodes(int new_vgaarb_rsrc)
234 {
235     int len;
236     char buf[BUFSIZE];
237     int ret;
238     struct pci_device *dev = pci_sys->vga_target;
239
240     if (!dev)
241         return -1;
242     if (dev->vgaarb_rsrc == new_vgaarb_rsrc)
243         return 0;
244
245     len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(dev->vgaarb_rsrc));
246     ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
247     if (ret == 0)
248         dev->vgaarb_rsrc = new_vgaarb_rsrc;
249     return ret;
250 }
251
252 int
253 pci_device_vgaarb_lock(void)
254 {
255     int len;
256     char buf[BUFSIZE];
257     struct pci_device *dev = pci_sys->vga_target;
258
259     if (!dev)
260         return -1;
261
262     if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
263         return 0;
264
265     len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc));
266
267     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
268 }
269
270 int
271 pci_device_vgaarb_trylock(void)
272 {
273     int len;
274     char buf[BUFSIZE];
275     struct pci_device *dev = pci_sys->vga_target;
276
277     if (!dev)
278         return -1;
279
280     if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
281         return 0;
282
283     len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc));
284
285     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
286 }
287
288 int
289 pci_device_vgaarb_unlock(void)
290 {
291     int len;
292     char buf[BUFSIZE];
293     struct pci_device *dev = pci_sys->vga_target;
294
295     if (!dev)
296         return -1;
297
298     if (dev->vgaarb_rsrc == 0 || pci_sys->vga_count == 1)
299         return 0;
300
301     len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc));
302
303     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
304 }