xref: /libpciaccess/src/common_io.c (revision a798395a)
15e8d4c19SAdam Jackson /*
25e8d4c19SAdam Jackson  * Copyright 2009 Red Hat, Inc.
35e8d4c19SAdam Jackson  *
45e8d4c19SAdam Jackson  * Permission is hereby granted, free of charge, to any person obtaining a
55e8d4c19SAdam Jackson  * copy of this software and associated documentation files (the "Software")
65e8d4c19SAdam Jackson  * to deal in the software without restriction, including without limitation
75e8d4c19SAdam Jackson  * on the rights to use, copy, modify, merge, publish, distribute, sub
85e8d4c19SAdam Jackson  * license, and/or sell copies of the Software, and to permit persons to whom
95e8d4c19SAdam Jackson  * them Software is furnished to do so, subject to the following conditions:
105e8d4c19SAdam Jackson  *
115e8d4c19SAdam Jackson  * The above copyright notice and this permission notice (including the next
125e8d4c19SAdam Jackson  * paragraph) shall be included in all copies or substantial portions of the
135e8d4c19SAdam Jackson  * Software.
145e8d4c19SAdam Jackson  *
155e8d4c19SAdam Jackson  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
165e8d4c19SAdam Jackson  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
175e8d4c19SAdam Jackson  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
185e8d4c19SAdam Jackson  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
195e8d4c19SAdam Jackson  * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
205e8d4c19SAdam Jackson  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
215e8d4c19SAdam Jackson  *
225e8d4c19SAdam Jackson  * Author:
235e8d4c19SAdam Jackson  *	Adam Jackson <[email protected]>
245e8d4c19SAdam Jackson  */
255e8d4c19SAdam Jackson 
265e8d4c19SAdam Jackson #include <stdlib.h>
275e8d4c19SAdam Jackson #include <string.h>
285e8d4c19SAdam Jackson #include "pciaccess.h"
295e8d4c19SAdam Jackson #include "pciaccess_private.h"
305e8d4c19SAdam Jackson 
31947ab16fSAdam Jackson static struct pci_io_handle *ios;
325e8d4c19SAdam Jackson static unsigned int num_ios;
335e8d4c19SAdam Jackson 
345e8d4c19SAdam Jackson static struct pci_io_handle *
new_io_handle(void)355e8d4c19SAdam Jackson new_io_handle(void)
365e8d4c19SAdam Jackson {
37947ab16fSAdam Jackson     struct pci_io_handle *new;
385e8d4c19SAdam Jackson 
395e8d4c19SAdam Jackson     new = realloc(ios, sizeof(struct pci_io_handle) * (num_ios + 1));
405e8d4c19SAdam Jackson     if (!new)
415e8d4c19SAdam Jackson 	return NULL;
425e8d4c19SAdam Jackson 
435e8d4c19SAdam Jackson     ios = new;
445e8d4c19SAdam Jackson     num_ios++;
455e8d4c19SAdam Jackson 
46947ab16fSAdam Jackson     return ios + num_ios - 1;
475e8d4c19SAdam Jackson }
485e8d4c19SAdam Jackson 
495e8d4c19SAdam Jackson static void
delete_io_handle(struct pci_io_handle * handle)505e8d4c19SAdam Jackson delete_io_handle(struct pci_io_handle *handle)
515e8d4c19SAdam Jackson {
52947ab16fSAdam Jackson     struct pci_io_handle *new;
535e8d4c19SAdam Jackson     int i = 0;
545e8d4c19SAdam Jackson 
555e8d4c19SAdam Jackson     if (!handle || !num_ios || (void *)handle < (void *)ios ||
565e8d4c19SAdam Jackson         (void *)handle > (void *)(ios + num_ios - 1))
575e8d4c19SAdam Jackson         return;
585e8d4c19SAdam Jackson 
595e8d4c19SAdam Jackson     for (i = 0; i < num_ios; i++) {
60947ab16fSAdam Jackson         if (ios + i == handle) {
615e8d4c19SAdam Jackson             memmove(&ios[i], &ios[i+1], sizeof(struct pci_io_handle) *
625e8d4c19SAdam Jackson                                         (num_ios - i - 1));
635e8d4c19SAdam Jackson             break;
645e8d4c19SAdam Jackson         }
655e8d4c19SAdam Jackson     }
665e8d4c19SAdam Jackson 
67*a798395aSDaniel Drake     num_ios--;
68*a798395aSDaniel Drake     if (num_ios) {
69*a798395aSDaniel Drake         new = realloc(ios, sizeof(struct pci_io_handle) * num_ios);
705e8d4c19SAdam Jackson         if (new)
715e8d4c19SAdam Jackson             ios = new;
72*a798395aSDaniel Drake     } else {
73*a798395aSDaniel Drake         free(ios);
74*a798395aSDaniel Drake         ios = NULL;
75*a798395aSDaniel Drake     }
765e8d4c19SAdam Jackson }
775e8d4c19SAdam Jackson 
785e8d4c19SAdam Jackson _pci_hidden void
pci_io_cleanup(void)795e8d4c19SAdam Jackson pci_io_cleanup(void)
805e8d4c19SAdam Jackson {
815e8d4c19SAdam Jackson     free(ios);
825e8d4c19SAdam Jackson     ios = NULL;
835e8d4c19SAdam Jackson     num_ios = 0;
845e8d4c19SAdam Jackson }
855e8d4c19SAdam Jackson 
865e8d4c19SAdam Jackson /**
875e8d4c19SAdam Jackson  * Open a handle to a PCI device I/O range.  The \c base and \c size
885e8d4c19SAdam Jackson  * requested must fit entirely within a single I/O BAR on the device.
895e8d4c19SAdam Jackson  * \c size is in bytes.
905e8d4c19SAdam Jackson  *
915e8d4c19SAdam Jackson  * \returns
925e8d4c19SAdam Jackson  * An opaque handle to the I/O BAR, or \c NULL on error.
935e8d4c19SAdam Jackson  */
945e8d4c19SAdam Jackson struct pci_io_handle *
pci_device_open_io(struct pci_device * dev,pciaddr_t base,pciaddr_t size)955e8d4c19SAdam Jackson pci_device_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
965e8d4c19SAdam Jackson {
975e8d4c19SAdam Jackson     struct pci_io_handle *ret;
985e8d4c19SAdam Jackson     int bar;
995e8d4c19SAdam Jackson 
1005e8d4c19SAdam Jackson     if (!pci_sys->methods->open_device_io)
1015e8d4c19SAdam Jackson 	return NULL;
1025e8d4c19SAdam Jackson 
1035e8d4c19SAdam Jackson     for (bar = 0; bar < 6; bar++) {
1045e8d4c19SAdam Jackson 	struct pci_mem_region *region = &(dev->regions[bar]);
1055e8d4c19SAdam Jackson 	if (!region->is_IO)
1065e8d4c19SAdam Jackson 	    continue;
1075e8d4c19SAdam Jackson 
1085e8d4c19SAdam Jackson 	if (base < region->base_addr || base > (region->base_addr+region->size))
1095e8d4c19SAdam Jackson 	    continue;
1105e8d4c19SAdam Jackson 
1115e8d4c19SAdam Jackson 	if ((base + size) > (region->base_addr + region->size))
1125e8d4c19SAdam Jackson 	    continue;
1135e8d4c19SAdam Jackson 
1145e8d4c19SAdam Jackson 	ret = new_io_handle();
1155e8d4c19SAdam Jackson 	if (!ret)
1165e8d4c19SAdam Jackson 	    return NULL;
1175e8d4c19SAdam Jackson 
1185e8d4c19SAdam Jackson 	if (!pci_sys->methods->open_device_io(ret, dev, bar, base, size)) {
1195e8d4c19SAdam Jackson 	    delete_io_handle(ret);
1205e8d4c19SAdam Jackson 	    return NULL;
1215e8d4c19SAdam Jackson 	}
122d4e008eeSAdam Jackson 
123d4e008eeSAdam Jackson         return ret;
1245e8d4c19SAdam Jackson     }
1255e8d4c19SAdam Jackson 
1265e8d4c19SAdam Jackson     return NULL;
1275e8d4c19SAdam Jackson }
1285e8d4c19SAdam Jackson 
1295e8d4c19SAdam Jackson /**
1305e8d4c19SAdam Jackson  * Open a handle to the legacy I/O space for the PCI domain containing
1315e8d4c19SAdam Jackson  * \c dev. \c size is in bytes.
1325e8d4c19SAdam Jackson  *
1335e8d4c19SAdam Jackson  * \returns
1345e8d4c19SAdam Jackson  * An opaque handle to the requested range, or \c NULL on error.
1355e8d4c19SAdam Jackson  */
1365e8d4c19SAdam Jackson struct pci_io_handle *
pci_legacy_open_io(struct pci_device * dev,pciaddr_t base,pciaddr_t size)1375e8d4c19SAdam Jackson pci_legacy_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
1385e8d4c19SAdam Jackson {
1395e8d4c19SAdam Jackson     struct pci_io_handle *ret;
1405e8d4c19SAdam Jackson 
1415e8d4c19SAdam Jackson     if (!pci_sys->methods->open_legacy_io)
1425e8d4c19SAdam Jackson 	return NULL;
1435e8d4c19SAdam Jackson 
1445e8d4c19SAdam Jackson     ret = new_io_handle();
1455e8d4c19SAdam Jackson     if (!ret)
1465e8d4c19SAdam Jackson 	return NULL;
1475e8d4c19SAdam Jackson 
1485e8d4c19SAdam Jackson     if (!pci_sys->methods->open_legacy_io(ret, dev, base, size)) {
1495e8d4c19SAdam Jackson 	delete_io_handle(ret);
1505e8d4c19SAdam Jackson 	return NULL;
1515e8d4c19SAdam Jackson     }
1525e8d4c19SAdam Jackson 
1535e8d4c19SAdam Jackson     return ret;
1545e8d4c19SAdam Jackson }
1555e8d4c19SAdam Jackson 
1565e8d4c19SAdam Jackson /**
1575e8d4c19SAdam Jackson  * Close an I/O handle.
1585e8d4c19SAdam Jackson  */
1595e8d4c19SAdam Jackson void
pci_device_close_io(struct pci_device * dev,struct pci_io_handle * handle)1605e8d4c19SAdam Jackson pci_device_close_io(struct pci_device *dev, struct pci_io_handle *handle)
1615e8d4c19SAdam Jackson {
1625e8d4c19SAdam Jackson     if (dev && handle && pci_sys->methods->close_io)
1635e8d4c19SAdam Jackson 	pci_sys->methods->close_io(dev, handle);
1645e8d4c19SAdam Jackson 
1655e8d4c19SAdam Jackson     delete_io_handle(handle);
1665e8d4c19SAdam Jackson }
1675e8d4c19SAdam Jackson 
1685e8d4c19SAdam Jackson /**
1695e8d4c19SAdam Jackson  * Read a 32-bit value from the I/O space.  \c reg is relative to the
1705e8d4c19SAdam Jackson  * \c base specified when the handle was opened.  Some platforms may
1715e8d4c19SAdam Jackson  * require that \c reg be 32-bit-aligned.
1725e8d4c19SAdam Jackson  *
1735e8d4c19SAdam Jackson  * \returns
1745e8d4c19SAdam Jackson  * The value read from the I/O port, or undefined on any error.
1755e8d4c19SAdam Jackson  */
1765e8d4c19SAdam Jackson uint32_t
pci_io_read32(struct pci_io_handle * handle,uint32_t reg)1775e8d4c19SAdam Jackson pci_io_read32(struct pci_io_handle *handle, uint32_t reg)
1785e8d4c19SAdam Jackson {
1795e8d4c19SAdam Jackson     if (reg + 4 > handle->size)
1805e8d4c19SAdam Jackson 	return UINT32_MAX;
1815e8d4c19SAdam Jackson 
1825e8d4c19SAdam Jackson     return pci_sys->methods->read32(handle, reg);
1835e8d4c19SAdam Jackson }
1845e8d4c19SAdam Jackson 
1855e8d4c19SAdam Jackson /**
1865e8d4c19SAdam Jackson  * Read a 16-bit value from the I/O space.  \c reg is relative to the
1875e8d4c19SAdam Jackson  * \c base specified when the handle was opened.  Some platforms may
1885e8d4c19SAdam Jackson  * require that \c reg be 16-bit-aligned.
1895e8d4c19SAdam Jackson  *
1905e8d4c19SAdam Jackson  * \returns
1915e8d4c19SAdam Jackson  * The value read from the I/O port, or undefined on any error.
1925e8d4c19SAdam Jackson  */
1935e8d4c19SAdam Jackson uint16_t
pci_io_read16(struct pci_io_handle * handle,uint32_t reg)1945e8d4c19SAdam Jackson pci_io_read16(struct pci_io_handle *handle, uint32_t reg)
1955e8d4c19SAdam Jackson {
1965e8d4c19SAdam Jackson     if (reg + 2 > handle->size)
1975e8d4c19SAdam Jackson 	return UINT16_MAX;
1985e8d4c19SAdam Jackson 
1995e8d4c19SAdam Jackson     return pci_sys->methods->read16(handle, reg);
2005e8d4c19SAdam Jackson }
2015e8d4c19SAdam Jackson 
2025e8d4c19SAdam Jackson /**
2035e8d4c19SAdam Jackson  * Read a 8-bit value from the I/O space.  \c reg is relative to the
2045e8d4c19SAdam Jackson  * \c base specified when the handle was opened.
2055e8d4c19SAdam Jackson  *
2065e8d4c19SAdam Jackson  * \returns
2075e8d4c19SAdam Jackson  * The value read from the I/O port, or undefined on any error.
2085e8d4c19SAdam Jackson  */
2095e8d4c19SAdam Jackson uint8_t
pci_io_read8(struct pci_io_handle * handle,uint32_t reg)2105e8d4c19SAdam Jackson pci_io_read8(struct pci_io_handle *handle, uint32_t reg)
2115e8d4c19SAdam Jackson {
2125e8d4c19SAdam Jackson     if (reg + 1 > handle->size)
2135e8d4c19SAdam Jackson 	return UINT8_MAX;
2145e8d4c19SAdam Jackson 
2155e8d4c19SAdam Jackson     return pci_sys->methods->read8(handle, reg);
2165e8d4c19SAdam Jackson }
2175e8d4c19SAdam Jackson 
2185e8d4c19SAdam Jackson /**
2195e8d4c19SAdam Jackson  * Write a 32-bit value to the I/O space.  \c reg is relative to the
2205e8d4c19SAdam Jackson  * \c base specified when the handle was opened.  Some platforms may
2215e8d4c19SAdam Jackson  * require that \c reg be 32-bit-aligned.
2225e8d4c19SAdam Jackson  */
2235e8d4c19SAdam Jackson void
pci_io_write32(struct pci_io_handle * handle,uint32_t reg,uint32_t data)2245e8d4c19SAdam Jackson pci_io_write32(struct pci_io_handle *handle, uint32_t reg, uint32_t data)
2255e8d4c19SAdam Jackson {
2265e8d4c19SAdam Jackson     if (reg + 4 > handle->size)
2275e8d4c19SAdam Jackson 	return;
2285e8d4c19SAdam Jackson 
2295e8d4c19SAdam Jackson     pci_sys->methods->write32(handle, reg, data);
2305e8d4c19SAdam Jackson }
2315e8d4c19SAdam Jackson 
2325e8d4c19SAdam Jackson /**
2335e8d4c19SAdam Jackson  * Write a 16-bit value to the I/O space.  \c reg is relative to the
2345e8d4c19SAdam Jackson  * \c base specified when the handle was opened.  Some platforms may
2355e8d4c19SAdam Jackson  * require that \c reg be 16-bit-aligned.
2365e8d4c19SAdam Jackson  */
2375e8d4c19SAdam Jackson void
pci_io_write16(struct pci_io_handle * handle,uint32_t reg,uint16_t data)2385e8d4c19SAdam Jackson pci_io_write16(struct pci_io_handle *handle, uint32_t reg, uint16_t data)
2395e8d4c19SAdam Jackson {
2405e8d4c19SAdam Jackson     if (reg + 2 > handle->size)
2415e8d4c19SAdam Jackson 	return;
2425e8d4c19SAdam Jackson 
2435e8d4c19SAdam Jackson     pci_sys->methods->write16(handle, reg, data);
2445e8d4c19SAdam Jackson }
2455e8d4c19SAdam Jackson 
2465e8d4c19SAdam Jackson /**
2475e8d4c19SAdam Jackson  * Write a 8-bit value to the I/O space.  \c reg is relative to the
2485e8d4c19SAdam Jackson  * \c base specified when the handle was opened.
2495e8d4c19SAdam Jackson  */
2505e8d4c19SAdam Jackson void
pci_io_write8(struct pci_io_handle * handle,uint32_t reg,uint8_t data)2515e8d4c19SAdam Jackson pci_io_write8(struct pci_io_handle *handle, uint32_t reg, uint8_t data)
2525e8d4c19SAdam Jackson {
2535e8d4c19SAdam Jackson     if (reg + 1 > handle->size)
2545e8d4c19SAdam Jackson 	return;
2555e8d4c19SAdam Jackson 
2565e8d4c19SAdam Jackson     pci_sys->methods->write8(handle, reg, data);
2575e8d4c19SAdam Jackson }
258