]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOInterleavedMemoryDescriptor.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOInterleavedMemoryDescriptor.cpp
CommitLineData
2d21ac55
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <IOKit/IOLib.h>
30#include <IOKit/IOInterleavedMemoryDescriptor.h>
31
32#define super IOMemoryDescriptor
33OSDefineMetaClassAndStructors(IOInterleavedMemoryDescriptor, IOMemoryDescriptor)
34
2d21ac55 35IOInterleavedMemoryDescriptor * IOInterleavedMemoryDescriptor::withCapacity(
0a7de745
A
36 IOByteCount capacity,
37 IODirection direction )
2d21ac55 38{
0a7de745
A
39 //
40 // Create a new IOInterleavedMemoryDescriptor. The "buffer" will be made up
41 // of several memory descriptors, that are to be chained end-to-end to make up
42 // a single memory descriptor.
43 //
44
45 IOInterleavedMemoryDescriptor * me = new IOInterleavedMemoryDescriptor;
46
47 if (me && !me->initWithCapacity(
48 /* capacity */ capacity,
49 /* direction */ direction )) {
50 me->release();
cb323159 51 me = NULL;
0a7de745
A
52 }
53
54 return me;
2d21ac55
A
55}
56
0a7de745
A
57bool
58IOInterleavedMemoryDescriptor::initWithCapacity(
59 IOByteCount capacity,
60 IODirection direction )
2d21ac55 61{
0a7de745
A
62 //
63 // Initialize an IOInterleavedMemoryDescriptor. The "buffer" will be made up
64 // of several memory descriptors, that are to be chained end-to-end to make up
65 // a single memory descriptor.
66 //
67
68 assert(capacity);
2d21ac55 69
0a7de745
A
70 // Ask our superclass' opinion.
71 if (super::init() == false) {
72 return false;
73 }
2d21ac55 74
0a7de745 75 // Initialize our minimal state.
2d21ac55 76
0a7de745 77 _flags = direction;
b0d623f7 78#ifndef __LP64__
0a7de745 79 _direction = (IODirection) (_flags & kIOMemoryDirectionMask);
b0d623f7 80#endif /* !__LP64__ */
0a7de745 81 _length = 0;
cb323159 82 _mappings = NULL;
0a7de745
A
83 _tag = 0;
84 _descriptorCount = 0;
85 _descriptors = IONew(IOMemoryDescriptor *, capacity);
86 _descriptorOffsets = IONew(IOByteCount, capacity);
87 _descriptorLengths = IONew(IOByteCount, capacity);
2d21ac55 88
cb323159 89 if ((_descriptors == NULL) || (_descriptorOffsets == NULL) || (_descriptorLengths == NULL)) {
0a7de745
A
90 return false;
91 }
2d21ac55 92
0a7de745 93 _descriptorCapacity = capacity;
2d21ac55 94
0a7de745 95 return true;
2d21ac55
A
96}
97
0a7de745
A
98void
99IOInterleavedMemoryDescriptor::clearMemoryDescriptors( IODirection direction )
2d21ac55 100{
0a7de745 101 UInt32 index;
2d21ac55 102
0a7de745
A
103 for (index = 0; index < _descriptorCount; index++) {
104 if (_descriptorPrepared) {
105 _descriptors[index]->complete(getDirection());
106 }
2d21ac55 107
0a7de745 108 _descriptors[index]->release();
cb323159 109 _descriptors[index] = NULL;
2d21ac55 110
0a7de745
A
111 _descriptorOffsets[index] = 0;
112 _descriptorLengths[index] = 0;
113 }
2d21ac55 114
0a7de745
A
115 if (direction != kIODirectionNone) {
116 _flags = (_flags & ~kIOMemoryDirectionMask) | direction;
b0d623f7 117#ifndef __LP64__
0a7de745 118 _direction = (IODirection) (_flags & kIOMemoryDirectionMask);
b0d623f7 119#endif /* !__LP64__ */
0a7de745 120 }
2d21ac55 121
0a7de745
A
122 _descriptorCount = 0;
123 _length = 0;
cb323159 124 _mappings = NULL;
0a7de745 125 _tag = 0;
2d21ac55
A
126};
127
0a7de745
A
128bool
129IOInterleavedMemoryDescriptor::setMemoryDescriptor(
130 IOMemoryDescriptor * descriptor,
131 IOByteCount offset,
132 IOByteCount length )
2d21ac55 133{
0a7de745
A
134 if (_descriptorPrepared || (_descriptorCount == _descriptorCapacity)) {
135 return false;
136 }
2d21ac55 137
0a7de745
A
138 if ((offset + length) > descriptor->getLength()) {
139 return false;
140 }
2d21ac55 141
b0d623f7 142// if ( descriptor->getDirection() != getDirection() )
2d21ac55
A
143// return false;
144
0a7de745
A
145 descriptor->retain();
146 _descriptors[_descriptorCount] = descriptor;
147 _descriptorOffsets[_descriptorCount] = offset;
148 _descriptorLengths[_descriptorCount] = length;
2d21ac55 149
0a7de745 150 _descriptorCount++;
2d21ac55 151
0a7de745 152 _length += length;
2d21ac55 153
0a7de745 154 return true;
2d21ac55
A
155}
156
0a7de745
A
157void
158IOInterleavedMemoryDescriptor::free()
2d21ac55 159{
0a7de745
A
160 //
161 // Free all of this object's outstanding resources.
162 //
2d21ac55 163
0a7de745
A
164 if (_descriptors) {
165 for (unsigned index = 0; index < _descriptorCount; index++) {
166 _descriptors[index]->release();
167 }
2d21ac55 168
cb323159 169 if (_descriptors != NULL) {
0a7de745
A
170 IODelete(_descriptors, IOMemoryDescriptor *, _descriptorCapacity);
171 }
2d21ac55 172
cb323159 173 if (_descriptorOffsets != NULL) {
0a7de745
A
174 IODelete(_descriptorOffsets, IOMemoryDescriptor *, _descriptorCapacity);
175 }
2d21ac55 176
cb323159 177 if (_descriptorLengths != NULL) {
0a7de745
A
178 IODelete(_descriptorLengths, IOMemoryDescriptor *, _descriptorCapacity);
179 }
180 }
2d21ac55 181
0a7de745 182 super::free();
2d21ac55
A
183}
184
0a7de745
A
185IOReturn
186IOInterleavedMemoryDescriptor::prepare(IODirection forDirection)
2d21ac55 187{
0a7de745
A
188 //
189 // Prepare the memory for an I/O transfer.
190 //
191 // This involves paging in the memory and wiring it down for the duration
192 // of the transfer. The complete() method finishes the processing of the
193 // memory after the I/O transfer finishes.
194 //
195
196 unsigned index;
197 IOReturn status = kIOReturnSuccess;
198 IOReturn statusUndo;
199
200 if (forDirection == kIODirectionNone) {
201 forDirection = getDirection();
202 }
203
204 for (index = 0; index < _descriptorCount; index++) {
205 status = _descriptors[index]->prepare(forDirection);
206 if (status != kIOReturnSuccess) {
207 break;
208 }
209 }
210
211 if (status != kIOReturnSuccess) {
212 for (unsigned indexUndo = 0; indexUndo < index; indexUndo++) {
213 statusUndo = _descriptors[index]->complete(forDirection);
214 assert(statusUndo == kIOReturnSuccess);
215 }
216 }
217
218 if (status == kIOReturnSuccess) {
219 _descriptorPrepared = true;
220 }
221
222 return status;
2d21ac55
A
223}
224
0a7de745
A
225IOReturn
226IOInterleavedMemoryDescriptor::complete(IODirection forDirection)
2d21ac55 227{
0a7de745
A
228 //
229 // Complete processing of the memory after an I/O transfer finishes.
230 //
231 // This method shouldn't be called unless a prepare() was previously issued;
232 // the prepare() and complete() must occur in pairs, before and after an I/O
233 // transfer.
234 //
235
236 IOReturn status;
237 IOReturn statusFinal = kIOReturnSuccess;
238
239 if (forDirection == kIODirectionNone) {
240 forDirection = getDirection();
241 }
242
243 for (unsigned index = 0; index < _descriptorCount; index++) {
244 status = _descriptors[index]->complete(forDirection);
245 if (status != kIOReturnSuccess) {
246 statusFinal = status;
247 }
248 assert(status == kIOReturnSuccess);
249 }
250
251 _descriptorPrepared = false;
252
253 return statusFinal;
2d21ac55
A
254}
255
0a7de745
A
256addr64_t
257IOInterleavedMemoryDescriptor::getPhysicalSegment(
258 IOByteCount offset,
259 IOByteCount * length,
260 IOOptionBits options )
2d21ac55 261{
0a7de745
A
262 //
263 // This method returns the physical address of the byte at the given offset
264 // into the memory, and optionally the length of the physically contiguous
265 // segment from that offset.
266 //
267
268 addr64_t pa;
269
270 assert(offset <= _length);
271
272 for (unsigned index = 0; index < _descriptorCount; index++) {
273 if (offset < _descriptorLengths[index]) {
274 pa = _descriptors[index]->getPhysicalSegment(_descriptorOffsets[index] + offset, length, options);
275 if ((_descriptorLengths[index] - offset) < *length) {
276 *length = _descriptorLengths[index] - offset;
277 }
278 return pa;
279 }
280 offset -= _descriptorLengths[index];
281 }
282
283 if (length) {
284 *length = 0;
285 }
286
287 return 0;
2d21ac55 288}