1e432255dSmrg/*
2e432255dSmrg * Copyright 2009 Red Hat, Inc.
3e432255dSmrg *
4e432255dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5e432255dSmrg * copy of this software and associated documentation files (the "Software")
6e432255dSmrg * to deal in the software without restriction, including without limitation
7e432255dSmrg * on the rights to use, copy, modify, merge, publish, distribute, sub
8e432255dSmrg * license, and/or sell copies of the Software, and to permit persons to whom
9e432255dSmrg * them Software is furnished to do so, subject to the following conditions:
10e432255dSmrg *
11e432255dSmrg * The above copyright notice and this permission notice (including the next
12e432255dSmrg * paragraph) shall be included in all copies or substantial portions of the
13e432255dSmrg * Software.
14e432255dSmrg *
15e432255dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1648becaf0Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17e432255dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
18e432255dSmrg * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
19e432255dSmrg * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
20e432255dSmrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21e432255dSmrg *
22e432255dSmrg * Author:
23e432255dSmrg *	Adam Jackson <ajax@redhat.com>
24e432255dSmrg */
2549310723Smrg#ifdef HAVE_CONFIG_H
2649310723Smrg#include "config.h"
2749310723Smrg#endif
28e432255dSmrg
29e432255dSmrg#include <stdlib.h>
30e432255dSmrg#include <string.h>
31e432255dSmrg#include "pciaccess.h"
32e432255dSmrg#include "pciaccess_private.h"
33e432255dSmrg
34e432255dSmrgstatic struct pci_io_handle *
35e432255dSmrgnew_io_handle(void)
36e432255dSmrg{
37e432255dSmrg    struct pci_io_handle *new;
38e432255dSmrg
39cad31331Smrg    new = malloc(sizeof(struct pci_io_handle));
40e432255dSmrg    if (!new)
41e432255dSmrg	return NULL;
42e432255dSmrg
43cad31331Smrg    return new;
44e432255dSmrg}
45e432255dSmrg
46e432255dSmrgstatic void
47e432255dSmrgdelete_io_handle(struct pci_io_handle *handle)
48e432255dSmrg{
49cad31331Smrg    free(handle);
50cad31331Smrg    return;
51e432255dSmrg}
52e432255dSmrg
53e432255dSmrg_pci_hidden void
54e432255dSmrgpci_io_cleanup(void)
55e432255dSmrg{
56e432255dSmrg}
57e432255dSmrg
58e432255dSmrg/**
59e432255dSmrg * Open a handle to a PCI device I/O range.  The \c base and \c size
60e432255dSmrg * requested must fit entirely within a single I/O BAR on the device.
61e432255dSmrg * \c size is in bytes.
62e432255dSmrg *
63e432255dSmrg * \returns
64e432255dSmrg * An opaque handle to the I/O BAR, or \c NULL on error.
65e432255dSmrg */
66e432255dSmrgstruct pci_io_handle *
67e432255dSmrgpci_device_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
68e432255dSmrg{
69e432255dSmrg    struct pci_io_handle *ret;
70e432255dSmrg    int bar;
71e432255dSmrg
72e432255dSmrg    if (!pci_sys->methods->open_device_io)
73e432255dSmrg	return NULL;
74e432255dSmrg
75e432255dSmrg    for (bar = 0; bar < 6; bar++) {
76e432255dSmrg	struct pci_mem_region *region = &(dev->regions[bar]);
77e432255dSmrg	if (!region->is_IO)
78e432255dSmrg	    continue;
79e432255dSmrg
80e432255dSmrg	if (base < region->base_addr || base > (region->base_addr+region->size))
81e432255dSmrg	    continue;
82e432255dSmrg
83e432255dSmrg	if ((base + size) > (region->base_addr + region->size))
84e432255dSmrg	    continue;
85e432255dSmrg
86e432255dSmrg	ret = new_io_handle();
87e432255dSmrg	if (!ret)
88e432255dSmrg	    return NULL;
89cad31331Smrg
90e432255dSmrg	if (!pci_sys->methods->open_device_io(ret, dev, bar, base, size)) {
91e432255dSmrg	    delete_io_handle(ret);
92e432255dSmrg	    return NULL;
93e432255dSmrg	}
94e432255dSmrg
95e432255dSmrg        return ret;
96e432255dSmrg    }
97e432255dSmrg
98e432255dSmrg    return NULL;
99e432255dSmrg}
100e432255dSmrg
101e432255dSmrg/**
102e432255dSmrg * Open a handle to the legacy I/O space for the PCI domain containing
103e432255dSmrg * \c dev. \c size is in bytes.
104e432255dSmrg *
105e432255dSmrg * \returns
106e432255dSmrg * An opaque handle to the requested range, or \c NULL on error.
107e432255dSmrg */
108e432255dSmrgstruct pci_io_handle *
109e432255dSmrgpci_legacy_open_io(struct pci_device *dev, pciaddr_t base, pciaddr_t size)
110e432255dSmrg{
111e432255dSmrg    struct pci_io_handle *ret;
112e432255dSmrg
113e432255dSmrg    if (!pci_sys->methods->open_legacy_io)
114e432255dSmrg	return NULL;
115e432255dSmrg
116e432255dSmrg    ret = new_io_handle();
117e432255dSmrg    if (!ret)
118e432255dSmrg	return NULL;
119e432255dSmrg
120e432255dSmrg    if (!pci_sys->methods->open_legacy_io(ret, dev, base, size)) {
121e432255dSmrg	delete_io_handle(ret);
122e432255dSmrg	return NULL;
123e432255dSmrg    }
124e432255dSmrg
125e432255dSmrg    return ret;
126e432255dSmrg}
127e432255dSmrg
128e432255dSmrg/**
129e432255dSmrg * Close an I/O handle.
130e432255dSmrg */
131e432255dSmrgvoid
132e432255dSmrgpci_device_close_io(struct pci_device *dev, struct pci_io_handle *handle)
133e432255dSmrg{
134e432255dSmrg    if (dev && handle && pci_sys->methods->close_io)
135e432255dSmrg	pci_sys->methods->close_io(dev, handle);
136e432255dSmrg
137e432255dSmrg    delete_io_handle(handle);
138e432255dSmrg}
139e432255dSmrg
140e432255dSmrg/**
141e432255dSmrg * Read a 32-bit value from the I/O space.  \c reg is relative to the
142e432255dSmrg * \c base specified when the handle was opened.  Some platforms may
143e432255dSmrg * require that \c reg be 32-bit-aligned.
144e432255dSmrg *
145e432255dSmrg * \returns
146e432255dSmrg * The value read from the I/O port, or undefined on any error.
147e432255dSmrg */
148e432255dSmrguint32_t
149e432255dSmrgpci_io_read32(struct pci_io_handle *handle, uint32_t reg)
150e432255dSmrg{
151e432255dSmrg    if (reg + 4 > handle->size)
152e432255dSmrg	return UINT32_MAX;
153e432255dSmrg
154e432255dSmrg    return pci_sys->methods->read32(handle, reg);
155e432255dSmrg}
156e432255dSmrg
157e432255dSmrg/**
158e432255dSmrg * Read a 16-bit value from the I/O space.  \c reg is relative to the
159e432255dSmrg * \c base specified when the handle was opened.  Some platforms may
160e432255dSmrg * require that \c reg be 16-bit-aligned.
161e432255dSmrg *
162e432255dSmrg * \returns
163e432255dSmrg * The value read from the I/O port, or undefined on any error.
164e432255dSmrg */
165e432255dSmrguint16_t
166e432255dSmrgpci_io_read16(struct pci_io_handle *handle, uint32_t reg)
167e432255dSmrg{
168e432255dSmrg    if (reg + 2 > handle->size)
169e432255dSmrg	return UINT16_MAX;
170e432255dSmrg
171e432255dSmrg    return pci_sys->methods->read16(handle, reg);
172e432255dSmrg}
173e432255dSmrg
174e432255dSmrg/**
175e432255dSmrg * Read a 8-bit value from the I/O space.  \c reg is relative to the
176e432255dSmrg * \c base specified when the handle was opened.
177e432255dSmrg *
178e432255dSmrg * \returns
179e432255dSmrg * The value read from the I/O port, or undefined on any error.
180e432255dSmrg */
181e432255dSmrguint8_t
182e432255dSmrgpci_io_read8(struct pci_io_handle *handle, uint32_t reg)
183e432255dSmrg{
184e432255dSmrg    if (reg + 1 > handle->size)
185e432255dSmrg	return UINT8_MAX;
186e432255dSmrg
187e432255dSmrg    return pci_sys->methods->read8(handle, reg);
188e432255dSmrg}
189e432255dSmrg
190e432255dSmrg/**
191e432255dSmrg * Write a 32-bit value to the I/O space.  \c reg is relative to the
192e432255dSmrg * \c base specified when the handle was opened.  Some platforms may
193e432255dSmrg * require that \c reg be 32-bit-aligned.
194e432255dSmrg */
195e432255dSmrgvoid
196e432255dSmrgpci_io_write32(struct pci_io_handle *handle, uint32_t reg, uint32_t data)
197e432255dSmrg{
198e432255dSmrg    if (reg + 4 > handle->size)
199e432255dSmrg	return;
200e432255dSmrg
201e432255dSmrg    pci_sys->methods->write32(handle, reg, data);
202e432255dSmrg}
203e432255dSmrg
204e432255dSmrg/**
205e432255dSmrg * Write a 16-bit value to the I/O space.  \c reg is relative to the
206e432255dSmrg * \c base specified when the handle was opened.  Some platforms may
207e432255dSmrg * require that \c reg be 16-bit-aligned.
208e432255dSmrg */
209e432255dSmrgvoid
210e432255dSmrgpci_io_write16(struct pci_io_handle *handle, uint32_t reg, uint16_t data)
211e432255dSmrg{
212e432255dSmrg    if (reg + 2 > handle->size)
213e432255dSmrg	return;
214e432255dSmrg
215e432255dSmrg    pci_sys->methods->write16(handle, reg, data);
216e432255dSmrg}
217e432255dSmrg
218e432255dSmrg/**
219e432255dSmrg * Write a 8-bit value to the I/O space.  \c reg is relative to the
220e432255dSmrg * \c base specified when the handle was opened.
221e432255dSmrg */
222e432255dSmrgvoid
223e432255dSmrgpci_io_write8(struct pci_io_handle *handle, uint32_t reg, uint8_t data)
224e432255dSmrg{
225e432255dSmrg    if (reg + 1 > handle->size)
226e432255dSmrg	return;
227e432255dSmrg
228e432255dSmrg    pci_sys->methods->write8(handle, reg, data);
229e432255dSmrg}
230