xref: /libpciaccess/src/common_io.c (revision 5e8d4c19)
1 /*
2  * Copyright 2009 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software")
6  * to deal in the software without restriction, including without limitation
7  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * them Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Author:
23  *	Adam Jackson <[email protected]>
24  */
25 
26 #include <stdlib.h>
27 #include <string.h>
28 #include "pciaccess.h"
29 #include "pciaccess_private.h"
30 
31 static struct pci_io_handle **ios;
32 static unsigned int num_ios;
33 
34 static struct pci_io_handle *
35 new_io_handle(void)
36 {
37     struct pci_io_handle **new;
38 
39     new = realloc(ios, sizeof(struct pci_io_handle) * (num_ios + 1));
40     if (!new)
41 	return NULL;
42 
43     ios = new;
44     num_ios++;
45 
46     return ios[num_ios - 1];
47 }
48 
49 static void
50 delete_io_handle(struct pci_io_handle *handle)
51 {
52     struct pci_io_handle **new;
53     int i = 0;
54 
55     if (!handle || !num_ios || (void *)handle < (void *)ios ||
56         (void *)handle > (void *)(ios + num_ios - 1))
57         return;
58 
59     for (i = 0; i < num_ios; i++) {
60         if (ios[i] == handle) {
61             memmove(&ios[i], &ios[i+1], sizeof(struct pci_io_handle) *
62                                         (num_ios - i - 1));
63             break;
64         }
65     }
66 
67     new = realloc(ios, sizeof(struct pci_io_handle) * (num_ios - 1));
68     if (new)
69         ios = new;
70     num_ios--;
71 }
72 
73 _pci_hidden void
74 pci_io_cleanup(void)
75 {
76     free(ios);
77     ios = NULL;
78     num_ios = 0;
79 }
80 
81 /**
82  * Open a handle to a PCI device I/O range.  The \c base and \c size
83  * requested must fit entirely within a single I/O BAR on the device.
84  * \c size is in bytes.
85  *
86  * \returns
87  * An opaque handle to the I/O BAR, or \c NULL on error.
88  */
89 struct pci_io_handle *
90 pci_device_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
91 {
92     struct pci_io_handle *ret;
93     int bar;
94 
95     if (!pci_sys->methods->open_device_io)
96 	return NULL;
97 
98     for (bar = 0; bar < 6; bar++) {
99 	struct pci_mem_region *region = &(dev->regions[bar]);
100 	if (!region->is_IO)
101 	    continue;
102 
103 	if (base < region->base_addr || base > (region->base_addr+region->size))
104 	    continue;
105 
106 	if ((base + size) > (region->base_addr + region->size))
107 	    continue;
108 
109 	ret = new_io_handle();
110 	if (!ret)
111 	    return NULL;
112 
113 	if (!pci_sys->methods->open_device_io(ret, dev, bar, base, size)) {
114 	    delete_io_handle(ret);
115 	    return NULL;
116 	}
117     }
118 
119     return NULL;
120 }
121 
122 /**
123  * Open a handle to the legacy I/O space for the PCI domain containing
124  * \c dev. \c size is in bytes.
125  *
126  * \returns
127  * An opaque handle to the requested range, or \c NULL on error.
128  */
129 struct pci_io_handle *
130 pci_legacy_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
131 {
132     struct pci_io_handle *ret;
133 
134     if (!pci_sys->methods->open_legacy_io)
135 	return NULL;
136 
137     ret = new_io_handle();
138     if (!ret)
139 	return NULL;
140 
141     if (!pci_sys->methods->open_legacy_io(ret, dev, base, size)) {
142 	delete_io_handle(ret);
143 	return NULL;
144     }
145 
146     return ret;
147 }
148 
149 /**
150  * Close an I/O handle.
151  */
152 void
153 pci_device_close_io(struct pci_device *dev, struct pci_io_handle *handle)
154 {
155     if (dev && handle && pci_sys->methods->close_io)
156 	pci_sys->methods->close_io(dev, handle);
157 
158     delete_io_handle(handle);
159 }
160 
161 /**
162  * Read a 32-bit value from the I/O space.  \c reg is relative to the
163  * \c base specified when the handle was opened.  Some platforms may
164  * require that \c reg be 32-bit-aligned.
165  *
166  * \returns
167  * The value read from the I/O port, or undefined on any error.
168  */
169 uint32_t
170 pci_io_read32(struct pci_io_handle *handle, uint32_t reg)
171 {
172     if (reg + 4 > handle->size)
173 	return UINT32_MAX;
174 
175     return pci_sys->methods->read32(handle, reg);
176 }
177 
178 /**
179  * Read a 16-bit value from the I/O space.  \c reg is relative to the
180  * \c base specified when the handle was opened.  Some platforms may
181  * require that \c reg be 16-bit-aligned.
182  *
183  * \returns
184  * The value read from the I/O port, or undefined on any error.
185  */
186 uint16_t
187 pci_io_read16(struct pci_io_handle *handle, uint32_t reg)
188 {
189     if (reg + 2 > handle->size)
190 	return UINT16_MAX;
191 
192     return pci_sys->methods->read16(handle, reg);
193 }
194 
195 /**
196  * Read a 8-bit value from the I/O space.  \c reg is relative to the
197  * \c base specified when the handle was opened.
198  *
199  * \returns
200  * The value read from the I/O port, or undefined on any error.
201  */
202 uint8_t
203 pci_io_read8(struct pci_io_handle *handle, uint32_t reg)
204 {
205     if (reg + 1 > handle->size)
206 	return UINT8_MAX;
207 
208     return pci_sys->methods->read8(handle, reg);
209 }
210 
211 /**
212  * Write a 32-bit value to the I/O space.  \c reg is relative to the
213  * \c base specified when the handle was opened.  Some platforms may
214  * require that \c reg be 32-bit-aligned.
215  */
216 void
217 pci_io_write32(struct pci_io_handle *handle, uint32_t reg, uint32_t data)
218 {
219     if (reg + 4 > handle->size)
220 	return;
221 
222     pci_sys->methods->write32(handle, reg, data);
223 }
224 
225 /**
226  * Write a 16-bit value to the I/O space.  \c reg is relative to the
227  * \c base specified when the handle was opened.  Some platforms may
228  * require that \c reg be 16-bit-aligned.
229  */
230 void
231 pci_io_write16(struct pci_io_handle *handle, uint32_t reg, uint16_t data)
232 {
233     if (reg + 2 > handle->size)
234 	return;
235 
236     pci_sys->methods->write16(handle, reg, data);
237 }
238 
239 /**
240  * Write a 8-bit value to the I/O space.  \c reg is relative to the
241  * \c base specified when the handle was opened.
242  */
243 void
244 pci_io_write8(struct pci_io_handle *handle, uint32_t reg, uint8_t data)
245 {
246     if (reg + 1 > handle->size)
247 	return;
248 
249     pci_sys->methods->write8(handle, reg, data);
250 }
251