OSDN Git Service

Strip trailing whitespace
[android-x86/external-libpciaccess.git] / src / common_io.c
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 <ajax@redhat.com>
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 }