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