]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOMultiMemoryDescriptor.cpp
3e31f16b8560d8d83cec5b7004d078a40dcede7d
[apple/xnu.git] / iokit / Kernel / IOMultiMemoryDescriptor.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 #include <IOKit/IOLib.h>
27 #include <IOKit/IOMultiMemoryDescriptor.h>
28
29 #define super IOMemoryDescriptor
30 OSDefineMetaClassAndStructors(IOMultiMemoryDescriptor, IOMemoryDescriptor)
31
32 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33
34 bool IOMultiMemoryDescriptor::initWithAddress(
35 void * /* address */ ,
36 IOByteCount /* withLength */ ,
37 IODirection /* withDirection */ )
38 {
39 return false;
40 }
41
42 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
43
44 bool IOMultiMemoryDescriptor::initWithAddress(
45 vm_address_t /* address */ ,
46 IOByteCount /* withLength */ ,
47 IODirection /* withDirection */ ,
48 task_t /* withTask */ )
49 {
50 return false;
51 }
52
53 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
54
55 bool IOMultiMemoryDescriptor::initWithPhysicalAddress(
56 IOPhysicalAddress /* address */ ,
57 IOByteCount /* withLength */ ,
58 IODirection /* withDirection */ )
59 {
60 return false;
61 }
62
63
64 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
65
66 bool IOMultiMemoryDescriptor::initWithPhysicalRanges(
67 IOPhysicalRange * /* ranges */ ,
68 UInt32 /* withCount */ ,
69 IODirection /* withDirection */ ,
70 bool /* asReference */ )
71 {
72 return false;
73 }
74
75 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
76
77 bool IOMultiMemoryDescriptor::initWithRanges(
78 IOVirtualRange * /* ranges */ ,
79 UInt32 /* withCount */ ,
80 IODirection /* withDirection */ ,
81 task_t /* withTask */ ,
82 bool /* asReference */ )
83 {
84 return false;
85 }
86
87 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
88
89 IOMultiMemoryDescriptor * IOMultiMemoryDescriptor::withDescriptors(
90 IOMemoryDescriptor ** descriptors,
91 UInt32 withCount,
92 IODirection withDirection,
93 bool asReference = false )
94 {
95 //
96 // Create a new IOMultiMemoryDescriptor. The "buffer" is made up of several
97 // memory descriptors, that are to be chained end-to-end to make up a single
98 // memory descriptor.
99 //
100 // Passing the ranges as a reference will avoid an extra allocation.
101 //
102
103 IOMultiMemoryDescriptor * me = new IOMultiMemoryDescriptor;
104
105 if ( me && me->initWithDescriptors(
106 /* descriptors */ descriptors,
107 /* withCount */ withCount,
108 /* withDirection */ withDirection,
109 /* asReference */ asReference ) == false )
110 {
111 me->release();
112 me = 0;
113 }
114
115 return me;
116 }
117
118 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
119
120 bool IOMultiMemoryDescriptor::initWithDescriptors(
121 IOMemoryDescriptor ** descriptors,
122 UInt32 withCount,
123 IODirection withDirection,
124 bool asReference = false )
125 {
126 //
127 // Initialize an IOMultiMemoryDescriptor. The "buffer" is made up of several
128 // memory descriptors, that are to be chained end-to-end to make up a single
129 // memory descriptor.
130 //
131 // Passing the ranges as a reference will avoid an extra allocation.
132 //
133
134 assert(descriptors);
135 assert(withCount);
136
137 // Ask our superclass' opinion.
138
139 if ( super::init() == false ) return false;
140
141 // Initialize our minimal state.
142
143 _descriptors = 0;
144 _descriptorsCount = withCount;
145 _descriptorsIsAllocated = asReference ? false : true;
146 _direction = withDirection;
147 _length = 0;
148 _mappings = 0;
149 _tag = 0;
150
151 if ( asReference )
152 {
153 _descriptors = descriptors;
154 }
155 else
156 {
157 _descriptors = IONew(IOMemoryDescriptor *, withCount);
158 if ( _descriptors == 0 ) return false;
159
160 bcopy( /* from */ descriptors,
161 /* to */ _descriptors,
162 /* bytes */ withCount * sizeof(IOMemoryDescriptor *) );
163 }
164
165 for ( unsigned index = 0; index < withCount; index++ )
166 {
167 descriptors[index]->retain();
168 _length += descriptors[index]->getLength();
169 if ( _tag == 0 ) _tag = descriptors[index]->getTag();
170 assert(descriptors[index]->getDirection() == withDirection);
171 }
172
173 return true;
174 }
175
176 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
177
178 void IOMultiMemoryDescriptor::free()
179 {
180 //
181 // Free all of this object's outstanding resources.
182 //
183
184 if ( _descriptors )
185 {
186 for ( unsigned index = 0; index < _descriptorsCount; index++ )
187 _descriptors[index]->release();
188
189 if ( _descriptorsIsAllocated )
190 IODelete(_descriptors, IOMemoryDescriptor *, _descriptorsCount);
191 }
192
193 super::free();
194 }
195
196 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
197
198 IOReturn IOMultiMemoryDescriptor::prepare(IODirection forDirection)
199 {
200 //
201 // Prepare the memory for an I/O transfer.
202 //
203 // This involves paging in the memory and wiring it down for the duration
204 // of the transfer. The complete() method finishes the processing of the
205 // memory after the I/O transfer finishes.
206 //
207
208 unsigned index;
209 IOReturn status = kIOReturnInternalError;
210 IOReturn statusUndo;
211
212 if ( forDirection == kIODirectionNone )
213 {
214 forDirection = _direction;
215 }
216
217 for ( index = 0; index < _descriptorsCount; index++ )
218 {
219 status = _descriptors[index]->prepare(forDirection);
220 if ( status != kIOReturnSuccess ) break;
221 }
222
223 if ( status != kIOReturnSuccess )
224 {
225 for ( unsigned indexUndo = 0; indexUndo <= index; indexUndo++ )
226 {
227 statusUndo = _descriptors[index]->complete(forDirection);
228 assert(statusUndo == kIOReturnSuccess);
229 }
230 }
231
232 return status;
233 }
234
235 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
236
237 IOReturn IOMultiMemoryDescriptor::complete(IODirection forDirection)
238 {
239 //
240 // Complete processing of the memory after an I/O transfer finishes.
241 //
242 // This method shouldn't be called unless a prepare() was previously issued;
243 // the prepare() and complete() must occur in pairs, before and after an I/O
244 // transfer.
245 //
246
247 IOReturn status;
248 IOReturn statusFinal = kIOReturnSuccess;
249
250 if ( forDirection == kIODirectionNone )
251 {
252 forDirection = _direction;
253 }
254
255 for ( unsigned index = 0; index < _descriptorsCount; index++ )
256 {
257 status = _descriptors[index]->complete(forDirection);
258 if ( status != kIOReturnSuccess ) statusFinal = status;
259 assert(status == kIOReturnSuccess);
260 }
261
262 return statusFinal;
263 }
264
265 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
266
267 IOPhysicalAddress IOMultiMemoryDescriptor::getPhysicalSegment(
268 IOByteCount offset,
269 IOByteCount * length )
270 {
271 //
272 // This method returns the physical address of the byte at the given offset
273 // into the memory, and optionally the length of the physically contiguous
274 // segment from that offset.
275 //
276
277 assert(offset <= _length);
278
279 for ( unsigned index = 0; index < _descriptorsCount; index++ )
280 {
281 if ( offset < _descriptors[index]->getLength() )
282 {
283 return _descriptors[index]->getPhysicalSegment(offset, length);
284 }
285 offset -= _descriptors[index]->getLength();
286 }
287
288 if ( length ) *length = 0;
289
290 return 0;
291 }
292
293 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
294
295 IOPhysicalAddress IOMultiMemoryDescriptor::getSourceSegment(
296 IOByteCount offset,
297 IOByteCount * length )
298 {
299 //
300 // This method returns the physical address of the byte at the given offset
301 // into the memory, and optionally the length of the physically contiguous
302 // segment from that offset.
303 //
304
305 assert(offset <= _length);
306
307 for ( unsigned index = 0; index < _descriptorsCount; index++ )
308 {
309 if ( offset < _descriptors[index]->getLength() )
310 {
311 return _descriptors[index]->getSourceSegment(offset, length);
312 }
313 offset -= _descriptors[index]->getLength();
314 }
315
316 if ( length ) *length = 0;
317
318 return 0;
319 }
320
321 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
322
323 void * IOMultiMemoryDescriptor::getVirtualSegment( IOByteCount /* offset */ ,
324 IOByteCount * /* length */ )
325 {
326 return 0;
327 }
328
329 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
330
331 IOByteCount IOMultiMemoryDescriptor::readBytes( IOByteCount offset,
332 void * bytes,
333 IOByteCount withLength )
334 {
335 //
336 // Copies data from the memory descriptor's buffer at the given offset, to
337 // the specified buffer. Returns the number of bytes copied.
338 //
339
340 IOByteCount bytesCopied = 0;
341 unsigned index;
342
343 for ( index = 0; index < _descriptorsCount; index++ )
344 {
345 if ( offset < _descriptors[index]->getLength() ) break;
346 offset -= _descriptors[index]->getLength();
347 }
348
349 for ( ; index < _descriptorsCount && withLength; index++)
350 {
351 IOByteCount copy = min(_descriptors[index]->getLength(), withLength);
352 IOByteCount copied = _descriptors[index]->readBytes(offset,bytes,copy);
353
354 bytesCopied += copied;
355 if ( copied != copy ) break;
356
357 bytes = ((UInt8 *) bytes) + copied;
358 withLength -= copied;
359 offset = 0;
360 }
361
362 return bytesCopied;
363 }
364
365 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
366
367 IOByteCount IOMultiMemoryDescriptor::writeBytes( IOByteCount offset,
368 const void * bytes,
369 IOByteCount withLength )
370 {
371 //
372 // Copies data to the memory descriptor's buffer at the given offset, from
373 // the specified buffer. Returns the number of bytes copied.
374 //
375
376 IOByteCount bytesCopied = 0;
377 unsigned index;
378
379 for ( index = 0; index < _descriptorsCount; index++ )
380 {
381 if ( offset < _descriptors[index]->getLength() ) break;
382 offset -= _descriptors[index]->getLength();
383 }
384
385 for ( ; index < _descriptorsCount && withLength; index++)
386 {
387 IOByteCount copy = min(_descriptors[index]->getLength(), withLength);
388 IOByteCount copied = _descriptors[index]->writeBytes(offset,bytes,copy);
389
390 bytesCopied += copied;
391 if ( copied != copy ) break;
392
393 bytes = ((UInt8 *) bytes) + copied;
394 withLength -= copied;
395 offset = 0;
396 }
397
398 return bytesCopied;
399 }