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