xref: /libpciaccess/src/common_io.c (revision d4e008ee)
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         return ret;
119     }
120 
121     return NULL;
122 }
123 
124 /**
125  * Open a handle to the legacy I/O space for the PCI domain containing
126  * \c dev. \c size is in bytes.
127  *
128  * \returns
129  * An opaque handle to the requested range, or \c NULL on error.
130  */
131 struct pci_io_handle *
132 pci_legacy_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
133 {
134     struct pci_io_handle *ret;
135 
136     if (!pci_sys->methods->open_legacy_io)
137 	return NULL;
138 
139     ret = new_io_handle();
140     if (!ret)
141 	return NULL;
142 
143     if (!pci_sys->methods->open_legacy_io(ret, dev, base, size)) {
144 	delete_io_handle(ret);
145 	return NULL;
146     }
147 
148     return ret;
149 }
150 
151 /**
152  * Close an I/O handle.
153  */
154 void
155 pci_device_close_io(struct pci_device *dev, struct pci_io_handle *handle)
156 {
157     if (dev && handle && pci_sys->methods->close_io)
158 	pci_sys->methods->close_io(dev, handle);
159 
160     delete_io_handle(handle);
161 }
162 
163 /**
164  * Read a 32-bit value from the I/O space.  \c reg is relative to the
165  * \c base specified when the handle was opened.  Some platforms may
166  * require that \c reg be 32-bit-aligned.
167  *
168  * \returns
169  * The value read from the I/O port, or undefined on any error.
170  */
171 uint32_t
172 pci_io_read32(struct pci_io_handle *handle, uint32_t reg)
173 {
174     if (reg + 4 > handle->size)
175 	return UINT32_MAX;
176 
177     return pci_sys->methods->read32(handle, reg);
178 }
179 
180 /**
181  * Read a 16-bit value from the I/O space.  \c reg is relative to the
182  * \c base specified when the handle was opened.  Some platforms may
183  * require that \c reg be 16-bit-aligned.
184  *
185  * \returns
186  * The value read from the I/O port, or undefined on any error.
187  */
188 uint16_t
189 pci_io_read16(struct pci_io_handle *handle, uint32_t reg)
190 {
191     if (reg + 2 > handle->size)
192 	return UINT16_MAX;
193 
194     return pci_sys->methods->read16(handle, reg);
195 }
196 
197 /**
198  * Read a 8-bit value from the I/O space.  \c reg is relative to the
199  * \c base specified when the handle was opened.
200  *
201  * \returns
202  * The value read from the I/O port, or undefined on any error.
203  */
204 uint8_t
205 pci_io_read8(struct pci_io_handle *handle, uint32_t reg)
206 {
207     if (reg + 1 > handle->size)
208 	return UINT8_MAX;
209 
210     return pci_sys->methods->read8(handle, reg);
211 }
212 
213 /**
214  * Write a 32-bit value to the I/O space.  \c reg is relative to the
215  * \c base specified when the handle was opened.  Some platforms may
216  * require that \c reg be 32-bit-aligned.
217  */
218 void
219 pci_io_write32(struct pci_io_handle *handle, uint32_t reg, uint32_t data)
220 {
221     if (reg + 4 > handle->size)
222 	return;
223 
224     pci_sys->methods->write32(handle, reg, data);
225 }
226 
227 /**
228  * Write a 16-bit value to the I/O space.  \c reg is relative to the
229  * \c base specified when the handle was opened.  Some platforms may
230  * require that \c reg be 16-bit-aligned.
231  */
232 void
233 pci_io_write16(struct pci_io_handle *handle, uint32_t reg, uint16_t data)
234 {
235     if (reg + 2 > handle->size)
236 	return;
237 
238     pci_sys->methods->write16(handle, reg, data);
239 }
240 
241 /**
242  * Write a 8-bit value to the I/O space.  \c reg is relative to the
243  * \c base specified when the handle was opened.
244  */
245 void
246 pci_io_write8(struct pci_io_handle *handle, uint32_t reg, uint8_t data)
247 {
248     if (reg + 1 > handle->size)
249 	return;
250 
251     pci_sys->methods->write8(handle, reg, data);
252 }
253