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