]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOMultiMemoryDescriptor.cpp
xnu-792.6.61.tar.gz
[apple/xnu.git] / iokit / Kernel / IOMultiMemoryDescriptor.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
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.
1c79356b 11 *
37839358
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
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.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <IOKit/IOLib.h>
24#include <IOKit/IOMultiMemoryDescriptor.h>
25
26#define super IOMemoryDescriptor
27OSDefineMetaClassAndStructors(IOMultiMemoryDescriptor, IOMemoryDescriptor)
28
29// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
30
31bool IOMultiMemoryDescriptor::initWithAddress(
32 void * /* address */ ,
33 IOByteCount /* withLength */ ,
34 IODirection /* withDirection */ )
35{
36 return false;
37}
38
39// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
40
41bool 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
52bool IOMultiMemoryDescriptor::initWithPhysicalAddress(
53 IOPhysicalAddress /* address */ ,
54 IOByteCount /* withLength */ ,
55 IODirection /* withDirection */ )
56{
57 return false;
58}
59
60
61// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62
63bool IOMultiMemoryDescriptor::initWithPhysicalRanges(
64 IOPhysicalRange * /* ranges */ ,
65 UInt32 /* withCount */ ,
66 IODirection /* withDirection */ ,
67 bool /* asReference */ )
68{
69 return false;
70}
71
72// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
73
74bool 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
86IOMultiMemoryDescriptor * IOMultiMemoryDescriptor::withDescriptors(
87 IOMemoryDescriptor ** descriptors,
88 UInt32 withCount,
89 IODirection withDirection,
55e303ae 90 bool asReference )
1c79356b
A
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
117bool IOMultiMemoryDescriptor::initWithDescriptors(
118 IOMemoryDescriptor ** descriptors,
119 UInt32 withCount,
120 IODirection withDirection,
55e303ae 121 bool asReference )
1c79356b
A
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
55e303ae
A
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
1c79356b
A
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
184void 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
204IOReturn 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
243IOReturn 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
273IOPhysicalAddress IOMultiMemoryDescriptor::getPhysicalSegment(
274 IOByteCount offset,
275 IOByteCount * length )
276{
277 //
278 // This method returns the physical address of the byte at the given offset
279 // into the memory, and optionally the length of the physically contiguous
280 // segment from that offset.
281 //
282
283 assert(offset <= _length);
284
285 for ( unsigned index = 0; index < _descriptorsCount; index++ )
286 {
287 if ( offset < _descriptors[index]->getLength() )
288 {
289 return _descriptors[index]->getPhysicalSegment(offset, length);
290 }
291 offset -= _descriptors[index]->getLength();
292 }
293
294 if ( length ) *length = 0;
295
296 return 0;
297}
298
299// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
300
0b4e3aa0
A
301IOPhysicalAddress IOMultiMemoryDescriptor::getSourceSegment(
302 IOByteCount offset,
303 IOByteCount * length )
304{
305 //
306 // This method returns the physical address of the byte at the given offset
307 // into the memory, and optionally the length of the physically contiguous
308 // segment from that offset.
309 //
310
311 assert(offset <= _length);
312
313 for ( unsigned index = 0; index < _descriptorsCount; index++ )
314 {
315 if ( offset < _descriptors[index]->getLength() )
316 {
317 return _descriptors[index]->getSourceSegment(offset, length);
318 }
319 offset -= _descriptors[index]->getLength();
320 }
321
322 if ( length ) *length = 0;
323
324 return 0;
325}
326
327// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
328
1c79356b
A
329void * IOMultiMemoryDescriptor::getVirtualSegment( IOByteCount /* offset */ ,
330 IOByteCount * /* length */ )
331{
332 return 0;
333}
334
335// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
336
337IOByteCount IOMultiMemoryDescriptor::readBytes( IOByteCount offset,
338 void * bytes,
339 IOByteCount withLength )
340{
341 //
342 // Copies data from the memory descriptor's buffer at the given offset, to
343 // the specified buffer. Returns the number of bytes copied.
344 //
345
346 IOByteCount bytesCopied = 0;
347 unsigned index;
348
349 for ( index = 0; index < _descriptorsCount; index++ )
350 {
351 if ( offset < _descriptors[index]->getLength() ) break;
352 offset -= _descriptors[index]->getLength();
353 }
354
355 for ( ; index < _descriptorsCount && withLength; index++)
356 {
357 IOByteCount copy = min(_descriptors[index]->getLength(), withLength);
358 IOByteCount copied = _descriptors[index]->readBytes(offset,bytes,copy);
359
360 bytesCopied += copied;
361 if ( copied != copy ) break;
362
363 bytes = ((UInt8 *) bytes) + copied;
364 withLength -= copied;
365 offset = 0;
366 }
367
368 return bytesCopied;
369}
370
371// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
372
373IOByteCount IOMultiMemoryDescriptor::writeBytes( IOByteCount offset,
374 const void * bytes,
375 IOByteCount withLength )
376{
377 //
378 // Copies data to the memory descriptor's buffer at the given offset, from
379 // the specified buffer. Returns the number of bytes copied.
380 //
381
382 IOByteCount bytesCopied = 0;
383 unsigned index;
384
385 for ( index = 0; index < _descriptorsCount; index++ )
386 {
387 if ( offset < _descriptors[index]->getLength() ) break;
388 offset -= _descriptors[index]->getLength();
389 }
390
391 for ( ; index < _descriptorsCount && withLength; index++)
392 {
393 IOByteCount copy = min(_descriptors[index]->getLength(), withLength);
394 IOByteCount copied = _descriptors[index]->writeBytes(offset,bytes,copy);
395
396 bytesCopied += copied;
397 if ( copied != copy ) break;
398
399 bytes = ((UInt8 *) bytes) + copied;
400 withLength -= copied;
401 offset = 0;
402 }
403
404 return bytesCopied;
405}