]>
Commit | Line | Data |
---|---|---|
2d21ac55 A |
1 | /* |
2 | * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
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. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
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. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | #include <IOKit/IOLib.h> | |
30 | #include <IOKit/IOInterleavedMemoryDescriptor.h> | |
31 | ||
32 | #define super IOMemoryDescriptor | |
33 | OSDefineMetaClassAndStructors(IOInterleavedMemoryDescriptor, IOMemoryDescriptor) | |
34 | ||
2d21ac55 | 35 | IOInterleavedMemoryDescriptor * IOInterleavedMemoryDescriptor::withCapacity( |
b0d623f7 | 36 | IOByteCount capacity, |
2d21ac55 A |
37 | IODirection direction ) |
38 | { | |
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 | { | |
51 | me->release(); | |
52 | me = 0; | |
53 | } | |
54 | ||
55 | return me; | |
56 | } | |
57 | ||
2d21ac55 | 58 | bool IOInterleavedMemoryDescriptor::initWithCapacity( |
b0d623f7 | 59 | IOByteCount capacity, |
2d21ac55 A |
60 | IODirection direction ) |
61 | { | |
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); | |
69 | ||
70 | // Ask our superclass' opinion. | |
71 | if ( super::init() == false ) return false; | |
72 | ||
73 | // Initialize our minimal state. | |
74 | ||
b0d623f7 A |
75 | _flags = direction; |
76 | #ifndef __LP64__ | |
77 | _direction = (IODirection) (_flags & kIOMemoryDirectionMask); | |
78 | #endif /* !__LP64__ */ | |
2d21ac55 A |
79 | _length = 0; |
80 | _mappings = 0; | |
81 | _tag = 0; | |
82 | _descriptorCount = 0; | |
83 | _descriptors = IONew(IOMemoryDescriptor *, capacity); | |
84 | _descriptorOffsets = IONew(IOByteCount, capacity); | |
85 | _descriptorLengths = IONew(IOByteCount, capacity); | |
86 | ||
87 | if ( (_descriptors == 0) || (_descriptorOffsets == 0) || (_descriptorLengths == 0) ) | |
88 | return false; | |
89 | ||
90 | _descriptorCapacity = capacity; | |
91 | ||
92 | return true; | |
93 | } | |
94 | ||
2d21ac55 A |
95 | void IOInterleavedMemoryDescriptor::clearMemoryDescriptors( IODirection direction ) |
96 | { | |
97 | UInt32 index; | |
98 | ||
99 | for ( index = 0; index < _descriptorCount; index++ ) | |
100 | { | |
101 | if ( _descriptorPrepared ) | |
b0d623f7 | 102 | _descriptors[index]->complete(getDirection()); |
2d21ac55 A |
103 | |
104 | _descriptors[index]->release(); | |
105 | _descriptors[index] = 0; | |
106 | ||
107 | _descriptorOffsets[index] = 0; | |
108 | _descriptorLengths[index] = 0; | |
109 | } | |
110 | ||
111 | if ( direction != kIODirectionNone ) | |
b0d623f7 A |
112 | { |
113 | _flags = (_flags & ~kIOMemoryDirectionMask) | direction; | |
114 | #ifndef __LP64__ | |
115 | _direction = (IODirection) (_flags & kIOMemoryDirectionMask); | |
116 | #endif /* !__LP64__ */ | |
117 | } | |
2d21ac55 A |
118 | |
119 | _descriptorCount = 0; | |
120 | _length = 0; | |
121 | _mappings = 0; | |
122 | _tag = 0; | |
123 | ||
124 | }; | |
125 | ||
2d21ac55 A |
126 | bool IOInterleavedMemoryDescriptor::setMemoryDescriptor( |
127 | IOMemoryDescriptor * descriptor, | |
128 | IOByteCount offset, | |
129 | IOByteCount length ) | |
130 | { | |
131 | if ( _descriptorPrepared || (_descriptorCount == _descriptorCapacity) ) | |
132 | return false; | |
133 | ||
134 | if ( (offset + length) > descriptor->getLength() ) | |
135 | return false; | |
136 | ||
b0d623f7 | 137 | // if ( descriptor->getDirection() != getDirection() ) |
2d21ac55 A |
138 | // return false; |
139 | ||
140 | descriptor->retain(); | |
141 | _descriptors[_descriptorCount] = descriptor; | |
142 | _descriptorOffsets[_descriptorCount] = offset; | |
143 | _descriptorLengths[_descriptorCount] = length; | |
144 | ||
145 | _descriptorCount++; | |
146 | ||
147 | _length += length; | |
148 | ||
149 | return true; | |
150 | } | |
151 | ||
2d21ac55 A |
152 | void IOInterleavedMemoryDescriptor::free() |
153 | { | |
154 | // | |
155 | // Free all of this object's outstanding resources. | |
156 | // | |
157 | ||
158 | if ( _descriptors ) | |
159 | { | |
160 | for ( unsigned index = 0; index < _descriptorCount; index++ ) | |
161 | _descriptors[index]->release(); | |
162 | ||
163 | if ( _descriptors != 0 ) | |
164 | IODelete(_descriptors, IOMemoryDescriptor *, _descriptorCapacity); | |
165 | ||
166 | if ( _descriptorOffsets != 0 ) | |
167 | IODelete(_descriptorOffsets, IOMemoryDescriptor *, _descriptorCapacity); | |
168 | ||
169 | if ( _descriptorLengths != 0 ) | |
170 | IODelete(_descriptorLengths, IOMemoryDescriptor *, _descriptorCapacity); | |
171 | } | |
172 | ||
173 | super::free(); | |
174 | } | |
175 | ||
2d21ac55 A |
176 | IOReturn IOInterleavedMemoryDescriptor::prepare(IODirection forDirection) |
177 | { | |
178 | // | |
179 | // Prepare the memory for an I/O transfer. | |
180 | // | |
181 | // This involves paging in the memory and wiring it down for the duration | |
182 | // of the transfer. The complete() method finishes the processing of the | |
183 | // memory after the I/O transfer finishes. | |
184 | // | |
185 | ||
186 | unsigned index; | |
187 | IOReturn status = kIOReturnSuccess; | |
188 | IOReturn statusUndo; | |
189 | ||
190 | if ( forDirection == kIODirectionNone ) | |
191 | { | |
b0d623f7 | 192 | forDirection = getDirection(); |
2d21ac55 A |
193 | } |
194 | ||
195 | for ( index = 0; index < _descriptorCount; index++ ) | |
196 | { | |
197 | status = _descriptors[index]->prepare(forDirection); | |
198 | if ( status != kIOReturnSuccess ) break; | |
199 | } | |
200 | ||
201 | if ( status != kIOReturnSuccess ) | |
202 | { | |
203 | for ( unsigned indexUndo = 0; indexUndo < index; indexUndo++ ) | |
204 | { | |
205 | statusUndo = _descriptors[index]->complete(forDirection); | |
206 | assert(statusUndo == kIOReturnSuccess); | |
207 | } | |
208 | } | |
209 | ||
210 | if ( status == kIOReturnSuccess ) _descriptorPrepared = true; | |
211 | ||
212 | return status; | |
213 | } | |
214 | ||
2d21ac55 A |
215 | IOReturn IOInterleavedMemoryDescriptor::complete(IODirection forDirection) |
216 | { | |
217 | // | |
218 | // Complete processing of the memory after an I/O transfer finishes. | |
219 | // | |
220 | // This method shouldn't be called unless a prepare() was previously issued; | |
221 | // the prepare() and complete() must occur in pairs, before and after an I/O | |
222 | // transfer. | |
223 | // | |
224 | ||
225 | IOReturn status; | |
226 | IOReturn statusFinal = kIOReturnSuccess; | |
227 | ||
228 | if ( forDirection == kIODirectionNone ) | |
229 | { | |
b0d623f7 | 230 | forDirection = getDirection(); |
2d21ac55 A |
231 | } |
232 | ||
233 | for ( unsigned index = 0; index < _descriptorCount; index++ ) | |
234 | { | |
235 | status = _descriptors[index]->complete(forDirection); | |
236 | if ( status != kIOReturnSuccess ) statusFinal = status; | |
237 | assert(status == kIOReturnSuccess); | |
238 | } | |
239 | ||
240 | _descriptorPrepared = false; | |
241 | ||
242 | return statusFinal; | |
243 | } | |
244 | ||
b0d623f7 | 245 | addr64_t IOInterleavedMemoryDescriptor::getPhysicalSegment( |
2d21ac55 | 246 | IOByteCount offset, |
b0d623f7 A |
247 | IOByteCount * length, |
248 | IOOptionBits options ) | |
2d21ac55 A |
249 | { |
250 | // | |
251 | // This method returns the physical address of the byte at the given offset | |
252 | // into the memory, and optionally the length of the physically contiguous | |
253 | // segment from that offset. | |
254 | // | |
255 | ||
b0d623f7 | 256 | addr64_t pa; |
2d21ac55 A |
257 | |
258 | assert(offset <= _length); | |
259 | ||
260 | for ( unsigned index = 0; index < _descriptorCount; index++ ) | |
261 | { | |
262 | if ( offset < _descriptorLengths[index] ) | |
263 | { | |
b0d623f7 | 264 | pa = _descriptors[index]->getPhysicalSegment(_descriptorOffsets[index] + offset, length, options); |
2d21ac55 A |
265 | if ((_descriptorLengths[index] - offset) < *length) *length = _descriptorLengths[index] - offset; |
266 | return pa; | |
267 | } | |
268 | offset -= _descriptorLengths[index]; | |
269 | } | |
270 | ||
271 | if ( length ) *length = 0; | |
272 | ||
273 | return 0; | |
274 | } |