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