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 | |
35 | IOInterleavedMemoryDescriptor * IOInterleavedMemoryDescriptor::withCapacity( |
36 | IOByteCount capacity, |
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 | |
58 | bool IOInterleavedMemoryDescriptor::initWithCapacity( |
59 | IOByteCount capacity, |
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 | |
75 | _flags = direction; |
76 | #ifndef __LP64__ |
77 | _direction = (IODirection) (_flags & kIOMemoryDirectionMask); |
78 | #endif /* !__LP64__ */ |
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 | |
95 | void IOInterleavedMemoryDescriptor::clearMemoryDescriptors( IODirection direction ) |
96 | { |
97 | UInt32 index; |
98 | |
99 | for ( index = 0; index < _descriptorCount; index++ ) |
100 | { |
101 | if ( _descriptorPrepared ) |
102 | _descriptors[index]->complete(getDirection()); |
103 | |
104 | _descriptors[index]->release(); |
105 | _descriptors[index] = 0; |
106 | |
107 | _descriptorOffsets[index] = 0; |
108 | _descriptorLengths[index] = 0; |
109 | } |
110 | |
111 | if ( direction != kIODirectionNone ) |
112 | { |
113 | _flags = (_flags & ~kIOMemoryDirectionMask) | direction; |
114 | #ifndef __LP64__ |
115 | _direction = (IODirection) (_flags & kIOMemoryDirectionMask); |
116 | #endif /* !__LP64__ */ |
117 | } |
118 | |
119 | _descriptorCount = 0; |
120 | _length = 0; |
121 | _mappings = 0; |
122 | _tag = 0; |
123 | |
124 | }; |
125 | |
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 | |
137 | // if ( descriptor->getDirection() != getDirection() ) |
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 | |
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 | |
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 | { |
192 | forDirection = getDirection(); |
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 | |
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 | { |
230 | forDirection = getDirection(); |
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 | |
245 | addr64_t IOInterleavedMemoryDescriptor::getPhysicalSegment( |
246 | IOByteCount offset, |
247 | IOByteCount * length, |
248 | IOOptionBits options ) |
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 | |
256 | addr64_t pa; |
257 | |
258 | assert(offset <= _length); |
259 | |
260 | for ( unsigned index = 0; index < _descriptorCount; index++ ) |
261 | { |
262 | if ( offset < _descriptorLengths[index] ) |
263 | { |
264 | pa = _descriptors[index]->getPhysicalSegment(_descriptorOffsets[index] + offset, length, options); |
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 | } |
275 | |