File: | common_interface.c |
Location: | line 444, column 26 |
Description: | Call to 'realloc' has an allocation size of 0 bytes |
1 | /* | ||
2 | * (C) Copyright IBM Corporation 2006 | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * on the rights to use, copy, modify, merge, publish, distribute, sub | ||
9 | * license, and/or sell copies of the Software, and to permit persons to whom | ||
10 | * the Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice (including the next | ||
13 | * paragraph) shall be included in all copies or substantial portions of the | ||
14 | * Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
19 | * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
22 | * DEALINGS IN THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | /** | ||
26 | * \file common_interface.c | ||
27 | * Platform independent interface glue. | ||
28 | * | ||
29 | * \author Ian Romanick <idr@us.ibm.com> | ||
30 | */ | ||
31 | |||
32 | #include <stdlib.h> | ||
33 | #include <string.h> | ||
34 | #include <errno(*__errno_location ()).h> | ||
35 | |||
36 | #include "pciaccess.h" | ||
37 | #include "pciaccess_private.h" | ||
38 | |||
39 | #if defined(__linux__1) || defined(__GLIBC__2) | ||
40 | #include <byteswap.h> | ||
41 | |||
42 | #if __BYTE_ORDER4321 == __BIG_ENDIAN4321 | ||
43 | # define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) bswap_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) | ||
44 | # define HTOLE_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) bswap_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) | ||
45 | # define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) bswap_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) | ||
46 | # define HTOLE_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) bswap_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) | ||
47 | #else | ||
48 | # define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) (x) | ||
49 | # define HTOLE_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) (x) | ||
50 | # define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) (x) | ||
51 | # define HTOLE_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) (x) | ||
52 | #endif /* linux */ | ||
53 | |||
54 | #elif defined(__sun) | ||
55 | |||
56 | #include <sys/byteorder.h> | ||
57 | |||
58 | #ifdef _BIG_ENDIAN1 | ||
59 | # define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) BSWAP_16(x) | ||
60 | # define HTOLE_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) BSWAP_16(x) | ||
61 | # define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) BSWAP_32(x) | ||
62 | # define HTOLE_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) BSWAP_32(x) | ||
63 | #else | ||
64 | # define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) (x) | ||
65 | # define HTOLE_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) (x) | ||
66 | # define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) (x) | ||
67 | # define HTOLE_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) (x) | ||
68 | #endif /* Solaris */ | ||
69 | |||
70 | #else | ||
71 | |||
72 | #include <sys/endian.h> | ||
73 | |||
74 | #define HTOLE_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) htole16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) | ||
75 | #define HTOLE_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) htole32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) | ||
76 | |||
77 | #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) | ||
78 | #define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) le16toh(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) | ||
79 | #define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) le32toh(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) | ||
80 | #else | ||
81 | #define LETOH_16(x)(__extension__ ({ unsigned short int __bsx = (x); ((((__bsx) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8)); })) letoh16(x) | ||
82 | #define LETOH_32(x)(__extension__ ({ register unsigned int __bsx = (x); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })) letoh32(x) | ||
83 | #endif | ||
84 | |||
85 | #endif /* others */ | ||
86 | |||
87 | /** | ||
88 | * Read a device's expansion ROM. | ||
89 | * | ||
90 | * Reads the device's expansion ROM and stores the data in the memory pointed | ||
91 | * to by \c buffer. The buffer must be at least \c pci_device::rom_size | ||
92 | * bytes. | ||
93 | * | ||
94 | * \param dev Device whose expansion ROM is to be read. | ||
95 | * \param buffer Memory in which to store the ROM. | ||
96 | * | ||
97 | * \return | ||
98 | * Zero on success or an \c errno value on failure. | ||
99 | */ | ||
100 | int | ||
101 | pci_device_read_rom( struct pci_device * dev, void * buffer ) | ||
102 | { | ||
103 | if ( (dev == NULL((void*)0)) || (buffer == NULL((void*)0)) ) { | ||
104 | return EFAULT14; | ||
105 | } | ||
106 | |||
107 | |||
108 | return (pci_sys->methods->read_rom)( dev, buffer ); | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * Probe a PCI (VGA) device to determine if its the boot VGA device | ||
113 | * | ||
114 | * \param dev Device whose VGA status to query | ||
115 | * \return | ||
116 | * Zero if not the boot VGA, 1 if the boot VGA. | ||
117 | */ | ||
118 | int | ||
119 | pci_device_is_boot_vga( struct pci_device * dev ) | ||
120 | { | ||
121 | if (!pci_sys->methods->boot_vga) | ||
122 | return 0; | ||
123 | return pci_sys->methods->boot_vga( dev ); | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * Probe a PCI device to determine if a kernel driver is attached. | ||
128 | * | ||
129 | * \param dev Device to query | ||
130 | * \return | ||
131 | * Zero if no driver attached, 1 if attached kernel drviver | ||
132 | */ | ||
133 | int | ||
134 | pci_device_has_kernel_driver( struct pci_device * dev ) | ||
135 | { | ||
136 | if (!pci_sys->methods->has_kernel_driver) | ||
137 | return 0; | ||
138 | return pci_sys->methods->has_kernel_driver( dev ); | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * Probe a PCI device to learn information about the device. | ||
143 | * | ||
144 | * Probes a PCI device to learn various information about the device. Before | ||
145 | * calling this function, the only public fields in the \c pci_device | ||
146 | * structure that have valid values are \c pci_device::domain, | ||
147 | * \c pci_device::bus, \c pci_device::dev, and \c pci_device::func. | ||
148 | * | ||
149 | * \param dev Device to be probed. | ||
150 | * | ||
151 | * \return | ||
152 | * Zero on success or an \c errno value on failure. | ||
153 | */ | ||
154 | int | ||
155 | pci_device_probe( struct pci_device * dev ) | ||
156 | { | ||
157 | if ( dev == NULL((void*)0) ) { | ||
158 | return EFAULT14; | ||
159 | } | ||
160 | |||
161 | |||
162 | return (pci_sys->methods->probe)( dev ); | ||
163 | } | ||
164 | |||
165 | |||
166 | /** | ||
167 | * Map the specified BAR so that it can be accessed by the CPU. | ||
168 | * | ||
169 | * Maps the specified BAR for access by the processor. The pointer to the | ||
170 | * mapped region is stored in the \c pci_mem_region::memory pointer for the | ||
171 | * BAR. | ||
172 | * | ||
173 | * \param dev Device whose memory region is to be mapped. | ||
174 | * \param region Region, on the range [0, 5], that is to be mapped. | ||
175 | * \param write_enable Map for writing (non-zero). | ||
176 | * | ||
177 | * \return | ||
178 | * Zero on success or an \c errno value on failure. | ||
179 | * | ||
180 | * \sa pci_device_map_range, pci_device_unmap_range | ||
181 | * \deprecated | ||
182 | */ | ||
183 | int | ||
184 | pci_device_map_region(struct pci_device * dev, unsigned region, | ||
185 | int write_enable) | ||
186 | { | ||
187 | const unsigned map_flags = | ||
188 | (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE(1U<<0) : 0; | ||
189 | |||
190 | if ((region > 5) || (dev->regions[region].size == 0)) { | ||
191 | return ENOENT2; | ||
192 | } | ||
193 | |||
194 | if (dev->regions[region].memory != NULL((void*)0)) { | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | return pci_device_map_range(dev, dev->regions[region].base_addr, | ||
199 | dev->regions[region].size, map_flags, | ||
200 | &dev->regions[region].memory); | ||
201 | } | ||
202 | |||
203 | |||
204 | /** | ||
205 | * Map the specified memory range so that it can be accessed by the CPU. | ||
206 | * | ||
207 | * Maps the specified memory range for access by the processor. The pointer | ||
208 | * to the mapped region is stored in \c addr. In addition, the | ||
209 | * \c pci_mem_region::memory pointer for the BAR will be updated. | ||
210 | * | ||
211 | * \param dev Device whose memory region is to be mapped. | ||
212 | * \param base Base address of the range to be mapped. | ||
213 | * \param size Size of the range to be mapped. | ||
214 | * \param write_enable Map for writing (non-zero). | ||
215 | * \param addr Location to store the mapped address. | ||
216 | * | ||
217 | * \return | ||
218 | * Zero on success or an \c errno value on failure. | ||
219 | * | ||
220 | * \sa pci_device_map_range | ||
221 | */ | ||
222 | int pci_device_map_memory_range(struct pci_device *dev, | ||
223 | pciaddr_t base, pciaddr_t size, | ||
224 | int write_enable, void **addr) | ||
225 | { | ||
226 | return pci_device_map_range(dev, base, size, | ||
227 | (write_enable) ? PCI_DEV_MAP_FLAG_WRITABLE(1U<<0) : 0, | ||
228 | addr); | ||
229 | } | ||
230 | |||
231 | |||
232 | /** | ||
233 | * Map the specified memory range so that it can be accessed by the CPU. | ||
234 | * | ||
235 | * Maps the specified memory range for access by the processor. The pointer | ||
236 | * to the mapped region is stored in \c addr. In addition, the | ||
237 | * \c pci_mem_region::memory pointer for the BAR will be updated. | ||
238 | * | ||
239 | * \param dev Device whose memory region is to be mapped. | ||
240 | * \param base Base address of the range to be mapped. | ||
241 | * \param size Size of the range to be mapped. | ||
242 | * \param map_flags Flag bits controlling how the mapping is accessed. | ||
243 | * \param addr Location to store the mapped address. | ||
244 | * | ||
245 | * \return | ||
246 | * Zero on success or an \c errno value on failure. | ||
247 | * | ||
248 | * \sa pci_device_unmap_range | ||
249 | */ | ||
250 | int | ||
251 | pci_device_map_range(struct pci_device *dev, pciaddr_t base, | ||
252 | pciaddr_t size, unsigned map_flags, | ||
253 | void **addr) | ||
254 | { | ||
255 | struct pci_device_private *const devp = | ||
256 | (struct pci_device_private *) dev; | ||
257 | struct pci_device_mapping *mappings; | ||
258 | unsigned region; | ||
259 | unsigned i; | ||
260 | int err = 0; | ||
261 | |||
262 | |||
263 | *addr = NULL((void*)0); | ||
264 | |||
265 | if (dev == NULL((void*)0)) { | ||
266 | return EFAULT14; | ||
267 | } | ||
268 | |||
269 | |||
270 | for (region = 0; region < 6; region++) { | ||
271 | const struct pci_mem_region const* r = &dev->regions[region]; | ||
272 | |||
273 | if (r->size != 0) { | ||
274 | if ((r->base_addr <= base) && ((r->base_addr + r->size) > base)) { | ||
275 | if ((base + size) > (r->base_addr + r->size)) { | ||
276 | return E2BIG7; | ||
277 | } | ||
278 | |||
279 | break; | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | if (region > 5) { | ||
285 | return ENOENT2; | ||
286 | } | ||
287 | |||
288 | /* Make sure that there isn't already a mapping with the same base and | ||
289 | * size. | ||
290 | */ | ||
291 | for (i = 0; i < devp->num_mappings; i++) { | ||
292 | if ((devp->mappings[i].base == base) | ||
293 | && (devp->mappings[i].size == size)) { | ||
294 | return EINVAL22; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | |||
299 | mappings = realloc(devp->mappings, | ||
300 | (sizeof(devp->mappings[0]) * (devp->num_mappings + 1))); | ||
301 | if (mappings == NULL((void*)0)) { | ||
302 | return ENOMEM12; | ||
303 | } | ||
304 | |||
305 | mappings[devp->num_mappings].base = base; | ||
306 | mappings[devp->num_mappings].size = size; | ||
307 | mappings[devp->num_mappings].region = region; | ||
308 | mappings[devp->num_mappings].flags = map_flags; | ||
309 | mappings[devp->num_mappings].memory = NULL((void*)0); | ||
310 | |||
311 | if (dev->regions[region].memory == NULL((void*)0)) { | ||
312 | err = (*pci_sys->methods->map_range)(dev, | ||
313 | &mappings[devp->num_mappings]); | ||
314 | } | ||
315 | |||
316 | if (err == 0) { | ||
317 | *addr = mappings[devp->num_mappings].memory; | ||
318 | devp->num_mappings++; | ||
319 | } else { | ||
320 | mappings = realloc(mappings, | ||
321 | (sizeof(mappings[0]) * devp->num_mappings)); | ||
322 | } | ||
323 | |||
324 | devp->mappings = mappings; | ||
325 | |||
326 | return err; | ||
327 | } | ||
328 | |||
329 | |||
330 | /** | ||
331 | * Unmap the specified BAR so that it can no longer be accessed by the CPU. | ||
332 | * | ||
333 | * Unmaps the specified BAR that was previously mapped via | ||
334 | * \c pci_device_map_region. | ||
335 | * | ||
336 | * \param dev Device whose memory region is to be mapped. | ||
337 | * \param region Region, on the range [0, 5], that is to be mapped. | ||
338 | * | ||
339 | * \return | ||
340 | * Zero on success or an \c errno value on failure. | ||
341 | * | ||
342 | * \sa pci_device_map_range, pci_device_unmap_range | ||
343 | * \deprecated | ||
344 | */ | ||
345 | int | ||
346 | pci_device_unmap_region( struct pci_device * dev, unsigned region ) | ||
347 | { | ||
348 | int err; | ||
349 | |||
350 | if (dev == NULL((void*)0)) { | ||
351 | return EFAULT14; | ||
352 | } | ||
353 | |||
354 | if ((region > 5) || (dev->regions[region].size == 0)) { | ||
355 | return ENOENT2; | ||
356 | } | ||
357 | |||
358 | err = pci_device_unmap_range(dev, dev->regions[region].memory, | ||
359 | dev->regions[region].size); | ||
360 | if (!err) { | ||
361 | dev->regions[region].memory = NULL((void*)0); | ||
362 | } | ||
363 | |||
364 | return err; | ||
365 | } | ||
366 | |||
367 | |||
368 | /** | ||
369 | * Unmap the specified memory range so that it can no longer be accessed by the CPU. | ||
370 | * | ||
371 | * Unmaps the specified memory range that was previously mapped via | ||
372 | * \c pci_device_map_memory_range. | ||
373 | * | ||
374 | * \param dev Device whose memory is to be unmapped. | ||
375 | * \param memory Pointer to the base of the mapped range. | ||
376 | * \param size Size, in bytes, of the range to be unmapped. | ||
377 | * | ||
378 | * \return | ||
379 | * Zero on success or an \c errno value on failure. | ||
380 | * | ||
381 | * \sa pci_device_map_range, pci_device_unmap_range | ||
382 | * \deprecated | ||
383 | */ | ||
384 | int | ||
385 | pci_device_unmap_memory_range(struct pci_device *dev, void *memory, | ||
386 | pciaddr_t size) | ||
387 | { | ||
388 | return pci_device_unmap_range(dev, memory, size); | ||
389 | } | ||
390 | |||
391 | |||
392 | /** | ||
393 | * Unmap the specified memory range so that it can no longer be accessed by the CPU. | ||
394 | * | ||
395 | * Unmaps the specified memory range that was previously mapped via | ||
396 | * \c pci_device_map_memory_range. | ||
397 | * | ||
398 | * \param dev Device whose memory is to be unmapped. | ||
399 | * \param memory Pointer to the base of the mapped range. | ||
400 | * \param size Size, in bytes, of the range to be unmapped. | ||
401 | * | ||
402 | * \return | ||
403 | * Zero on success or an \c errno value on failure. | ||
404 | * | ||
405 | * \sa pci_device_map_range | ||
406 | */ | ||
407 | int | ||
408 | pci_device_unmap_range(struct pci_device *dev, void *memory, | ||
409 | pciaddr_t size) | ||
410 | { | ||
411 | struct pci_device_private *const devp = | ||
412 | (struct pci_device_private *) dev; | ||
413 | unsigned i; | ||
414 | int err; | ||
415 | |||
416 | |||
417 | if (dev == NULL((void*)0)) { | ||
| |||
| |||
418 | return EFAULT14; | ||
419 | } | ||
420 | |||
421 | for (i = 0; i < devp->num_mappings; i++) { | ||
| |||
422 | if ((devp->mappings[i].memory == memory) | ||
| |||
423 | && (devp->mappings[i].size == size)) { | ||
424 | break; | ||
| |||
425 | } | ||
426 | } | ||
427 | |||
428 | if (i == devp->num_mappings) { | ||
| |||
429 | return ENOENT2; | ||
430 | } | ||
431 | |||
432 | |||
433 | err = (*pci_sys->methods->unmap_range)(dev, &devp->mappings[i]); | ||
434 | if (!err) { | ||
| |||
| |||
435 | const unsigned entries_to_move = (devp->num_mappings - i) - 1; | ||
436 | |||
437 | if (entries_to_move > 0) { | ||
| |||
| |||
438 | (void) memmove(&devp->mappings[i], | ||
439 | &devp->mappings[i + 1], | ||
440 | entries_to_move * sizeof(devp->mappings[0])); | ||
441 | } | ||
442 | |||
443 | devp->num_mappings--; | ||
444 | devp->mappings = realloc(devp->mappings, | ||
| |||
445 | (sizeof(devp->mappings[0]) * devp->num_mappings)); | ||
446 | } | ||
447 | |||
448 | return err; | ||
449 | } | ||
450 | |||
451 | |||
452 | /** | ||
453 | * Read arbitrary bytes from device's PCI config space | ||
454 | * | ||
455 | * Reads data from the device's PCI configuration space. As with the system | ||
456 | * read command, less data may be returned, without an error, than was | ||
457 | * requested. This is particularly the case if a non-root user tries to read | ||
458 | * beyond the first 64-bytes of configuration space. | ||
459 | * | ||
460 | * \param dev Device whose PCI configuration data is to be read. | ||
461 | * \param data Location to store the data | ||
462 | * \param offset Initial byte offset to read | ||
463 | * \param size Total number of bytes to read | ||
464 | * \param bytes_read Location to store the actual number of bytes read. This | ||
465 | * pointer may be \c NULL. | ||
466 | * | ||
467 | * \returns | ||
468 | * Zero on success or an errno value on failure. | ||
469 | * | ||
470 | * \note | ||
471 | * Data read from PCI configuration space using this routine is \b not | ||
472 | * byte-swapped to the host's byte order. PCI configuration data is always | ||
473 | * stored in little-endian order, and that is what this routine returns. | ||
474 | */ | ||
475 | int | ||
476 | pci_device_cfg_read( struct pci_device * dev, void * data, | ||
477 | pciaddr_t offset, pciaddr_t size, | ||
478 | pciaddr_t * bytes_read ) | ||
479 | { | ||
480 | pciaddr_t scratch; | ||
481 | |||
482 | if ( (dev == NULL((void*)0)) || (data == NULL((void*)0)) ) { | ||
483 | return EFAULT14; | ||
484 | } | ||
485 | |||
486 | return pci_sys->methods->read( dev, data, offset, size, | ||
487 | (bytes_read == NULL((void*)0)) | ||
488 | ? & scratch : bytes_read ); | ||
489 | } | ||
490 | |||
491 | |||
492 | int | ||
493 | pci_device_cfg_read_u8( struct pci_device * dev, uint8_t * data, | ||
494 | pciaddr_t offset ) | ||
495 | { | ||
496 | pciaddr_t bytes; | ||
497 | int err = pci_device_cfg_read( dev, data, offset, 1, & bytes ); | ||
498 | |||
499 | if ( (err == 0) && (bytes != 1) ) { | ||
500 | err = ENXIO6; | ||
501 | } | ||
502 | |||
503 | return err; | ||
504 | } | ||
505 | |||
506 | |||
507 | int | ||
508 | pci_device_cfg_read_u16( struct pci_device * dev, uint16_t * data, | ||
509 | pciaddr_t offset ) | ||
510 | { | ||
511 | pciaddr_t bytes; | ||
512 | int err = pci_device_cfg_read( dev, data, offset, 2, & bytes ); | ||
513 | |||
514 | if ( (err == 0) && (bytes != 2) ) { | ||
515 | err = ENXIO6; | ||
516 | } | ||
517 | |||
518 | *data = LETOH_16( *data )(__extension__ ({ unsigned short int __bsx = (*data); ((((__bsx ) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8 )); })); | ||
519 | return err; | ||
520 | } | ||
521 | |||
522 | |||
523 | int | ||
524 | pci_device_cfg_read_u32( struct pci_device * dev, uint32_t * data, | ||
525 | pciaddr_t offset ) | ||
526 | { | ||
527 | pciaddr_t bytes; | ||
528 | int err = pci_device_cfg_read( dev, data, offset, 4, & bytes ); | ||
529 | |||
530 | if ( (err == 0) && (bytes != 4) ) { | ||
531 | err = ENXIO6; | ||
532 | } | ||
533 | |||
534 | *data = LETOH_32( *data )(__extension__ ({ register unsigned int __bsx = (*data); (((( __bsx) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })); | ||
535 | return err; | ||
536 | } | ||
537 | |||
538 | |||
539 | /** | ||
540 | * Write arbitrary bytes to device's PCI config space | ||
541 | * | ||
542 | * Writes data to the device's PCI configuration space. As with the system | ||
543 | * write command, less data may be written, without an error, than was | ||
544 | * requested. | ||
545 | * | ||
546 | * \param dev Device whose PCI configuration data is to be written. | ||
547 | * \param data Location of the source data | ||
548 | * \param offset Initial byte offset to write | ||
549 | * \param size Total number of bytes to write | ||
550 | * \param bytes_read Location to store the actual number of bytes written. | ||
551 | * This pointer may be \c NULL. | ||
552 | * | ||
553 | * \returns | ||
554 | * Zero on success or an errno value on failure. | ||
555 | * | ||
556 | * \note | ||
557 | * Data written to PCI configuration space using this routine is \b not | ||
558 | * byte-swapped from the host's byte order. PCI configuration data is always | ||
559 | * stored in little-endian order, so data written with this routine should be | ||
560 | * put in that order in advance. | ||
561 | */ | ||
562 | int | ||
563 | pci_device_cfg_write( struct pci_device * dev, const void * data, | ||
564 | pciaddr_t offset, pciaddr_t size, | ||
565 | pciaddr_t * bytes_written ) | ||
566 | { | ||
567 | pciaddr_t scratch; | ||
568 | |||
569 | if ( (dev == NULL((void*)0)) || (data == NULL((void*)0)) ) { | ||
570 | return EFAULT14; | ||
571 | } | ||
572 | |||
573 | return pci_sys->methods->write( dev, data, offset, size, | ||
574 | (bytes_written == NULL((void*)0)) | ||
575 | ? & scratch : bytes_written ); | ||
576 | } | ||
577 | |||
578 | |||
579 | int | ||
580 | pci_device_cfg_write_u8(struct pci_device *dev, uint8_t data, | ||
581 | pciaddr_t offset) | ||
582 | { | ||
583 | pciaddr_t bytes; | ||
584 | int err = pci_device_cfg_write(dev, & data, offset, 1, & bytes); | ||
585 | |||
586 | if ( (err == 0) && (bytes != 1) ) { | ||
587 | err = ENOSPC28; | ||
588 | } | ||
589 | |||
590 | |||
591 | return err; | ||
592 | } | ||
593 | |||
594 | |||
595 | int | ||
596 | pci_device_cfg_write_u16(struct pci_device *dev, uint16_t data, | ||
597 | pciaddr_t offset) | ||
598 | { | ||
599 | pciaddr_t bytes; | ||
600 | const uint16_t temp = HTOLE_16(data)(__extension__ ({ unsigned short int __bsx = (data); ((((__bsx ) >> 8) & 0xffu) | (((__bsx) & 0xffu) << 8 )); })); | ||
601 | int err = pci_device_cfg_write( dev, & temp, offset, 2, & bytes ); | ||
602 | |||
603 | if ( (err == 0) && (bytes != 2) ) { | ||
604 | err = ENOSPC28; | ||
605 | } | ||
606 | |||
607 | |||
608 | return err; | ||
609 | } | ||
610 | |||
611 | |||
612 | int | ||
613 | pci_device_cfg_write_u32(struct pci_device *dev, uint32_t data, | ||
614 | pciaddr_t offset) | ||
615 | { | ||
616 | pciaddr_t bytes; | ||
617 | const uint32_t temp = HTOLE_32(data)(__extension__ ({ register unsigned int __bsx = (data); ((((__bsx ) & 0xff000000u) >> 24) | (((__bsx) & 0x00ff0000u ) >> 8) | (((__bsx) & 0x0000ff00u) << 8) | (( (__bsx) & 0x000000ffu) << 24)); })); | ||
618 | int err = pci_device_cfg_write( dev, & temp, offset, 4, & bytes ); | ||
619 | |||
620 | if ( (err == 0) && (bytes != 4) ) { | ||
621 | err = ENOSPC28; | ||
622 | } | ||
623 | |||
624 | |||
625 | return err; | ||
626 | } | ||
627 | |||
628 | |||
629 | int | ||
630 | pci_device_cfg_write_bits( struct pci_device * dev, uint32_t mask, | ||
631 | uint32_t data, pciaddr_t offset ) | ||
632 | { | ||
633 | uint32_t temp; | ||
634 | int err; | ||
635 | |||
636 | err = pci_device_cfg_read_u32( dev, & temp, offset ); | ||
637 | if ( ! err ) { | ||
638 | temp &= ~mask; | ||
639 | temp |= data; | ||
640 | |||
641 | err = pci_device_cfg_write_u32(dev, temp, offset); | ||
642 | } | ||
643 | |||
644 | return err; | ||
645 | } | ||
646 | |||
647 | void | ||
648 | pci_device_enable(struct pci_device *dev) | ||
649 | { | ||
650 | if (dev == NULL((void*)0)) { | ||
651 | return; | ||
652 | } | ||
653 | |||
654 | if (pci_sys->methods->enable) | ||
655 | pci_sys->methods->enable(dev); | ||
656 | } | ||
657 | |||
658 | /** | ||
659 | * Map the legacy memory space for the PCI domain containing \c dev. | ||
660 | * | ||
661 | * \param dev Device whose memory region is to be mapped. | ||
662 | * \param base Base address of the range to be mapped. | ||
663 | * \param size Size of the range to be mapped. | ||
664 | * \param map_flags Flag bits controlling how the mapping is accessed. | ||
665 | * \param addr Location to store the mapped address. | ||
666 | * | ||
667 | * \returns | ||
668 | * Zero on success or an \c errno value on failure. | ||
669 | */ | ||
670 | int | ||
671 | pci_device_map_legacy(struct pci_device *dev, pciaddr_t base, pciaddr_t size, | ||
672 | unsigned map_flags, void **addr) | ||
673 | { | ||
674 | if (base > 0x100000 || base + size > 0x100000) | ||
675 | return EINVAL22; | ||
676 | |||
677 | if (!pci_sys->methods->map_legacy) | ||
678 | return ENOSYS38; | ||
679 | |||
680 | return pci_sys->methods->map_legacy(dev, base, size, map_flags, addr); | ||
681 | } | ||
682 | |||
683 | /** | ||
684 | * Unmap the legacy memory space for the PCI domain containing \c dev. | ||
685 | * | ||
686 | * \param dev Device whose memory region is to be unmapped. | ||
687 | * \param addr Location of the mapped address. | ||
688 | * \param size Size of the range to be unmapped. | ||
689 | * | ||
690 | * \returns | ||
691 | * Zero on success or an \c errno value on failure. | ||
692 | */ | ||
693 | int | ||
694 | pci_device_unmap_legacy(struct pci_device *dev, void *addr, pciaddr_t size) | ||
695 | { | ||
696 | if (!pci_sys->methods->unmap_legacy) | ||
697 | return ENOSYS38; | ||
698 | |||
699 | return pci_sys->methods->unmap_legacy(dev, addr, size); | ||
700 | } |