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