]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOMultiMemoryDescriptor.cpp
ff981beb8ea18816eb0ea7a0374b5ce97f06c63d
[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 )
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 )
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 // Release existing descriptors, if any
138 if ( _descriptors )
139 {
140 for ( unsigned index = 0; index < _descriptorsCount; index++ )
141 _descriptors[index]->release();
142
143 if ( _descriptorsIsAllocated )
144 IODelete(_descriptors, IOMemoryDescriptor *, _descriptorsCount);
145 } else {
146 // Ask our superclass' opinion.
147 if ( super::init() == false ) return false;
148 }
149
150 // Initialize our minimal state.
151
152 _descriptors = 0;
153 _descriptorsCount = withCount;
154 _descriptorsIsAllocated = asReference ? false : true;
155 _direction = withDirection;
156 _length = 0;
157 _mappings = 0;
158 _tag = 0;
159
160 if ( asReference )
161 {
162 _descriptors = descriptors;
163 }
164 else
165 {
166 _descriptors = IONew(IOMemoryDescriptor *, withCount);
167 if ( _descriptors == 0 ) return false;
168
169 bcopy( /* from */ descriptors,
170 /* to */ _descriptors,
171 /* bytes */ withCount * sizeof(IOMemoryDescriptor *) );
172 }
173
174 for ( unsigned index = 0; index < withCount; index++ )
175 {
176 descriptors[index]->retain();
177 _length += descriptors[index]->getLength();
178 if ( _tag == 0 ) _tag = descriptors[index]->getTag();
179 assert(descriptors[index]->getDirection() == withDirection);
180 }
181
182 return true;
183 }
184
185 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
186
187 void IOMultiMemoryDescriptor::free()
188 {
189 //
190 // Free all of this object's outstanding resources.
191 //
192
193 if ( _descriptors )
194 {
195 for ( unsigned index = 0; index < _descriptorsCount; index++ )
196 _descriptors[index]->release();
197
198 if ( _descriptorsIsAllocated )
199 IODelete(_descriptors, IOMemoryDescriptor *, _descriptorsCount);
200 }
201
202 super::free();
203 }
204
205 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
206
207 IOReturn IOMultiMemoryDescriptor::prepare(IODirection forDirection)
208 {
209 //
210 // Prepare the memory for an I/O transfer.
211 //
212 // This involves paging in the memory and wiring it down for the duration
213 // of the transfer. The complete() method finishes the processing of the
214 // memory after the I/O transfer finishes.
215 //
216
217 unsigned index;
218 IOReturn status = kIOReturnInternalError;
219 IOReturn statusUndo;
220
221 if ( forDirection == kIODirectionNone )
222 {
223 forDirection = _direction;
224 }
225
226 for ( index = 0; index < _descriptorsCount; index++ )
227 {
228 status = _descriptors[index]->prepare(forDirection);
229 if ( status != kIOReturnSuccess ) break;
230 }
231
232 if ( status != kIOReturnSuccess )
233 {
234 for ( unsigned indexUndo = 0; indexUndo <= index; indexUndo++ )
235 {
236 statusUndo = _descriptors[index]->complete(forDirection);
237 assert(statusUndo == kIOReturnSuccess);
238 }
239 }
240
241 return status;
242 }
243
244 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
245
246 IOReturn IOMultiMemoryDescriptor::complete(IODirection forDirection)
247 {
248 //
249 // Complete processing of the memory after an I/O transfer finishes.
250 //
251 // This method shouldn't be called unless a prepare() was previously issued;
252 // the prepare() and complete() must occur in pairs, before and after an I/O
253 // transfer.
254 //
255
256 IOReturn status;
257 IOReturn statusFinal = kIOReturnSuccess;
258
259 if ( forDirection == kIODirectionNone )
260 {
261 forDirection = _direction;
262 }
263
264 for ( unsigned index = 0; index < _descriptorsCount; index++ )
265 {
266 status = _descriptors[index]->complete(forDirection);
267 if ( status != kIOReturnSuccess ) statusFinal = status;
268 assert(status == kIOReturnSuccess);
269 }
270
271 return statusFinal;
272 }
273
274 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
275
276 IOPhysicalAddress IOMultiMemoryDescriptor::getPhysicalSegment(
277 IOByteCount offset,
278 IOByteCount * length )
279 {
280 //
281 // This method returns the physical address of the byte at the given offset
282 // into the memory, and optionally the length of the physically contiguous
283 // segment from that offset.
284 //
285
286 assert(offset <= _length);
287
288 for ( unsigned index = 0; index < _descriptorsCount; index++ )
289 {
290 if ( offset < _descriptors[index]->getLength() )
291 {
292 return _descriptors[index]->getPhysicalSegment(offset, length);
293 }
294 offset -= _descriptors[index]->getLength();
295 }
296
297 if ( length ) *length = 0;
298
299 return 0;
300 }
301
302 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
303
304 IOPhysicalAddress IOMultiMemoryDescriptor::getSourceSegment(
305 IOByteCount offset,
306 IOByteCount * length )
307 {
308 //
309 // This method returns the physical address of the byte at the given offset
310 // into the memory, and optionally the length of the physically contiguous
311 // segment from that offset.
312 //
313
314 assert(offset <= _length);
315
316 for ( unsigned index = 0; index < _descriptorsCount; index++ )
317 {
318 if ( offset < _descriptors[index]->getLength() )
319 {
320 return _descriptors[index]->getSourceSegment(offset, length);
321 }
322 offset -= _descriptors[index]->getLength();
323 }
324
325 if ( length ) *length = 0;
326
327 return 0;
328 }
329
330 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
331
332 void * IOMultiMemoryDescriptor::getVirtualSegment( IOByteCount /* offset */ ,
333 IOByteCount * /* length */ )
334 {
335 return 0;
336 }
337
338 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
339
340 IOByteCount IOMultiMemoryDescriptor::readBytes( IOByteCount offset,
341 void * bytes,
342 IOByteCount withLength )
343 {
344 //
345 // Copies data from the memory descriptor's buffer at the given offset, to
346 // the specified buffer. Returns the number of bytes copied.
347 //
348
349 IOByteCount bytesCopied = 0;
350 unsigned index;
351
352 for ( index = 0; index < _descriptorsCount; index++ )
353 {
354 if ( offset < _descriptors[index]->getLength() ) break;
355 offset -= _descriptors[index]->getLength();
356 }
357
358 for ( ; index < _descriptorsCount && withLength; index++)
359 {
360 IOByteCount copy = min(_descriptors[index]->getLength(), withLength);
361 IOByteCount copied = _descriptors[index]->readBytes(offset,bytes,copy);
362
363 bytesCopied += copied;
364 if ( copied != copy ) break;
365
366 bytes = ((UInt8 *) bytes) + copied;
367 withLength -= copied;
368 offset = 0;
369 }
370
371 return bytesCopied;
372 }
373
374 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
375
376 IOByteCount IOMultiMemoryDescriptor::writeBytes( IOByteCount offset,
377 const void * bytes,
378 IOByteCount withLength )
379 {
380 //
381 // Copies data to the memory descriptor's buffer at the given offset, from
382 // the specified buffer. Returns the number of bytes copied.
383 //
384
385 IOByteCount bytesCopied = 0;
386 unsigned index;
387
388 for ( index = 0; index < _descriptorsCount; index++ )
389 {
390 if ( offset < _descriptors[index]->getLength() ) break;
391 offset -= _descriptors[index]->getLength();
392 }
393
394 for ( ; index < _descriptorsCount && withLength; index++)
395 {
396 IOByteCount copy = min(_descriptors[index]->getLength(), withLength);
397 IOByteCount copied = _descriptors[index]->writeBytes(offset,bytes,copy);
398
399 bytesCopied += copied;
400 if ( copied != copy ) break;
401
402 bytes = ((UInt8 *) bytes) + copied;
403 withLength -= copied;
404 offset = 0;
405 }
406
407 return bytesCopied;
408 }