|
Packit |
7d1034 |
/*
|
|
Packit |
7d1034 |
* Copyright 2009 Red Hat, Inc.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
Packit |
7d1034 |
* copy of this software and associated documentation files (the "Software")
|
|
Packit |
7d1034 |
* to deal in the software without restriction, including without limitation
|
|
Packit |
7d1034 |
* on the rights to use, copy, modify, merge, publish, distribute, sub
|
|
Packit |
7d1034 |
* license, and/or sell copies of the Software, and to permit persons to whom
|
|
Packit |
7d1034 |
* them Software is furnished to do so, subject to the following conditions:
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* The above copyright notice and this permission notice (including the next
|
|
Packit |
7d1034 |
* paragraph) shall be included in all copies or substantial portions of the
|
|
Packit |
7d1034 |
* Software.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
Packit |
7d1034 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
|
|
Packit |
7d1034 |
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
|
Packit |
7d1034 |
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
|
|
Packit |
7d1034 |
* IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
Packit |
7d1034 |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* Author:
|
|
Packit |
7d1034 |
* Adam Jackson <ajax@redhat.com>
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
7d1034 |
#include "config.h"
|
|
Packit |
7d1034 |
#endif
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#include <stdlib.h>
|
|
Packit |
7d1034 |
#include <string.h>
|
|
Packit |
7d1034 |
#include "pciaccess.h"
|
|
Packit |
7d1034 |
#include "pciaccess_private.h"
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static struct pci_io_handle *
|
|
Packit |
7d1034 |
new_io_handle(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
struct pci_io_handle *new;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
new = malloc(sizeof(struct pci_io_handle));
|
|
Packit |
7d1034 |
if (!new)
|
|
Packit |
7d1034 |
return NULL;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return new;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static void
|
|
Packit |
7d1034 |
delete_io_handle(struct pci_io_handle *handle)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
free(handle);
|
|
Packit |
7d1034 |
return;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
_pci_hidden void
|
|
Packit |
7d1034 |
pci_io_cleanup(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Open a handle to a PCI device I/O range. The \c base and \c size
|
|
Packit |
7d1034 |
* requested must fit entirely within a single I/O BAR on the device.
|
|
Packit |
7d1034 |
* \c size is in bytes.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* \returns
|
|
Packit |
7d1034 |
* An opaque handle to the I/O BAR, or \c NULL on error.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
struct pci_io_handle *
|
|
Packit |
7d1034 |
pci_device_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
struct pci_io_handle *ret;
|
|
Packit |
7d1034 |
int bar;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!pci_sys->methods->open_device_io)
|
|
Packit |
7d1034 |
return NULL;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
for (bar = 0; bar < 6; bar++) {
|
|
Packit |
7d1034 |
struct pci_mem_region *region = &(dev->regions[bar]);
|
|
Packit |
7d1034 |
if (!region->is_IO)
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (base < region->base_addr || base > (region->base_addr+region->size))
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if ((base + size) > (region->base_addr + region->size))
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ret = new_io_handle();
|
|
Packit |
7d1034 |
if (!ret)
|
|
Packit |
7d1034 |
return NULL;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!pci_sys->methods->open_device_io(ret, dev, bar, base, size)) {
|
|
Packit |
7d1034 |
delete_io_handle(ret);
|
|
Packit |
7d1034 |
return NULL;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return NULL;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Open a handle to the legacy I/O space for the PCI domain containing
|
|
Packit |
7d1034 |
* \c dev. \c size is in bytes.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* \returns
|
|
Packit |
7d1034 |
* An opaque handle to the requested range, or \c NULL on error.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
struct pci_io_handle *
|
|
Packit |
7d1034 |
pci_legacy_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
struct pci_io_handle *ret;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!pci_sys->methods->open_legacy_io)
|
|
Packit |
7d1034 |
return NULL;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ret = new_io_handle();
|
|
Packit |
7d1034 |
if (!ret)
|
|
Packit |
7d1034 |
return NULL;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!pci_sys->methods->open_legacy_io(ret, dev, base, size)) {
|
|
Packit |
7d1034 |
delete_io_handle(ret);
|
|
Packit |
7d1034 |
return NULL;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Close an I/O handle.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
void
|
|
Packit |
7d1034 |
pci_device_close_io(struct pci_device *dev, struct pci_io_handle *handle)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (dev && handle && pci_sys->methods->close_io)
|
|
Packit |
7d1034 |
pci_sys->methods->close_io(dev, handle);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
delete_io_handle(handle);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Read a 32-bit value from the I/O space. \c reg is relative to the
|
|
Packit |
7d1034 |
* \c base specified when the handle was opened. Some platforms may
|
|
Packit |
7d1034 |
* require that \c reg be 32-bit-aligned.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* \returns
|
|
Packit |
7d1034 |
* The value read from the I/O port, or undefined on any error.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
uint32_t
|
|
Packit |
7d1034 |
pci_io_read32(struct pci_io_handle *handle, uint32_t reg)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (reg + 4 > handle->size)
|
|
Packit |
7d1034 |
return UINT32_MAX;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return pci_sys->methods->read32(handle, reg);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Read a 16-bit value from the I/O space. \c reg is relative to the
|
|
Packit |
7d1034 |
* \c base specified when the handle was opened. Some platforms may
|
|
Packit |
7d1034 |
* require that \c reg be 16-bit-aligned.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* \returns
|
|
Packit |
7d1034 |
* The value read from the I/O port, or undefined on any error.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
uint16_t
|
|
Packit |
7d1034 |
pci_io_read16(struct pci_io_handle *handle, uint32_t reg)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (reg + 2 > handle->size)
|
|
Packit |
7d1034 |
return UINT16_MAX;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return pci_sys->methods->read16(handle, reg);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Read a 8-bit value from the I/O space. \c reg is relative to the
|
|
Packit |
7d1034 |
* \c base specified when the handle was opened.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* \returns
|
|
Packit |
7d1034 |
* The value read from the I/O port, or undefined on any error.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
uint8_t
|
|
Packit |
7d1034 |
pci_io_read8(struct pci_io_handle *handle, uint32_t reg)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (reg + 1 > handle->size)
|
|
Packit |
7d1034 |
return UINT8_MAX;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return pci_sys->methods->read8(handle, reg);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Write a 32-bit value to the I/O space. \c reg is relative to the
|
|
Packit |
7d1034 |
* \c base specified when the handle was opened. Some platforms may
|
|
Packit |
7d1034 |
* require that \c reg be 32-bit-aligned.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
void
|
|
Packit |
7d1034 |
pci_io_write32(struct pci_io_handle *handle, uint32_t reg, uint32_t data)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (reg + 4 > handle->size)
|
|
Packit |
7d1034 |
return;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
pci_sys->methods->write32(handle, reg, data);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Write a 16-bit value to the I/O space. \c reg is relative to the
|
|
Packit |
7d1034 |
* \c base specified when the handle was opened. Some platforms may
|
|
Packit |
7d1034 |
* require that \c reg be 16-bit-aligned.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
void
|
|
Packit |
7d1034 |
pci_io_write16(struct pci_io_handle *handle, uint32_t reg, uint16_t data)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (reg + 2 > handle->size)
|
|
Packit |
7d1034 |
return;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
pci_sys->methods->write16(handle, reg, data);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Write a 8-bit value to the I/O space. \c reg is relative to the
|
|
Packit |
7d1034 |
* \c base specified when the handle was opened.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
void
|
|
Packit |
7d1034 |
pci_io_write8(struct pci_io_handle *handle, uint32_t reg, uint8_t data)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (reg + 1 > handle->size)
|
|
Packit |
7d1034 |
return;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
pci_sys->methods->write8(handle, reg, data);
|
|
Packit |
7d1034 |
}
|