add support for finding if something has a kernel driver
[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
34 #include "pciaccess.h"
35 #include "pciaccess_private.h"
36
37 #define BUFSIZE 32
38
39 int
40 pci_device_vgaarb_init(void)
41 {
42     if ((pci_sys->vgaarb_fd = open ("/dev/vga_arbiter", O_RDWR)) < 0) {
43         fprintf(stderr, "device open failed");
44         return errno;
45     }
46
47     return 0;
48 }
49
50 void
51 pci_device_vgaarb_fini(void)
52 {
53     if (close(pci_sys->vgaarb_fd) != 0)
54         fprintf(stderr, "device close failed");
55 }
56
57 /**
58  * Writes message on vga device. The messages are defined by the kernel
59  * implementation.
60  *
61  * \param fd    vga arbiter device.
62  * \param buf   message itself.
63  * \param len   message length.
64  *
65  * \return
66  * Zero on success, 1 if something gets wrong and 2 if fd is busy (only for
67  * 'trylock')
68  */
69 static int
70 vgaarb_write(int fd, char *buf, int len)
71 {
72     int ret;
73
74
75     buf[len] = '\0';
76
77     ret = write(fd, buf, len);
78     if (ret == -1) {
79         /* the user may have called "trylock" and didn't get the lock */
80         if (errno == EBUSY)
81             return 2;
82
83         fprintf(stderr, "write error");
84         return 1;
85     }
86     else if (ret != len) {
87         /* it's need to receive the exactly amount required. */
88         fprintf(stderr, "write error: wrote different than expected\n");
89         return 1;
90     }
91
92 #ifdef DEBUG
93     fprintf(stderr, "%s: successfully wrote: '%s'\n", __FUNCTION__, buf);
94 #endif
95
96     return 0;
97 }
98
99 static int
100 parse_string_to_decodes_rsrc(char *input)
101 {
102     char *tok;
103
104     tok = strtok(input, ",");
105     if (!tok)
106         goto fail;
107
108     tok = strtok(NULL, ",");
109     if (!tok)
110         goto fail;
111     tok = strtok(tok, "=");
112     if (!tok)
113         goto fail;
114     tok = strtok(NULL, "=");
115     if (!tok)
116         goto fail;
117
118     if (!strncmp(tok, "io+mem", 6))
119         return VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM;
120     if (!strncmp(tok, "io", 2))
121         return VGA_ARB_RSRC_LEGACY_IO;
122     if (!strncmp(tok, "mem", 3))
123         return VGA_ARB_RSRC_LEGACY_MEM;
124 fail:
125     return VGA_ARB_RSRC_NONE;
126 }
127
128 static const char *
129 rsrc_to_str(int iostate)
130 {
131     switch (iostate) {
132     case VGA_ARB_RSRC_LEGACY_IO | VGA_ARB_RSRC_LEGACY_MEM:
133         return "io+mem";
134     case VGA_ARB_RSRC_LEGACY_IO:
135         return "io";
136     case VGA_ARB_RSRC_LEGACY_MEM:
137         return "mem";
138     }
139
140     return "none";
141 }
142
143 int
144 pci_device_vgaarb_set_target(struct pci_device *dev)
145 {
146     int len;
147     char buf[BUFSIZE];
148     int ret;
149
150     len = snprintf(buf, BUFSIZE, "target PCI:%d:%d:%d.%d",
151                    dev->domain, dev->bus, dev->dev, dev->func);
152
153     ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
154     if (ret)
155         return ret;
156
157     ret = read(pci_sys->vgaarb_fd, buf, BUFSIZE);
158     if (ret <= 0)
159         return -1;
160
161     dev->vgaarb_rsrc = parse_string_to_decodes_rsrc(buf);
162     return 0;
163 }
164
165 int
166 pci_device_vgaarb_decodes(struct pci_device *dev)
167 {
168     int len;
169     char buf[BUFSIZE];
170
171     len = snprintf(buf, BUFSIZE, "decodes %s", rsrc_to_str(dev->vgaarb_rsrc));
172
173     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
174 }
175
176 int
177 pci_device_vgaarb_lock(struct pci_device *dev)
178 {
179     int len;
180     char buf[BUFSIZE];
181
182     len = snprintf(buf, BUFSIZE, "lock %s", rsrc_to_str(dev->vgaarb_rsrc));
183
184     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
185 }
186
187 int
188 pci_device_vgaarb_trylock(struct pci_device *dev)
189 {
190     int len;
191     char buf[BUFSIZE];
192
193     len = snprintf(buf, BUFSIZE, "trylock %s", rsrc_to_str(dev->vgaarb_rsrc));
194
195     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
196 }
197
198 int
199 pci_device_vgaarb_unlock(struct pci_device *dev)
200 {
201     int len;
202     char buf[BUFSIZE];
203
204     len = snprintf(buf, BUFSIZE, "unlock %s", rsrc_to_str(dev->vgaarb_rsrc));
205
206     return vgaarb_write(pci_sys->vgaarb_fd, buf, len);
207 }