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