Edit

IABSD.fr/xenocara/lib/libpciaccess/src/common_io.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2010-07-10 18:56:27
    Hash : 99887c42
    Message : Update to libpciaccess 0.11, with VGA arbiter support code from kettenis@.

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