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