]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOMultiMemoryDescriptor.cpp
xnu-792.6.70.tar.gz
[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 * 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
27 OSDefineMetaClassAndStructors(IOMultiMemoryDescriptor, IOMemoryDescriptor)
28
29 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
30
31 bool IOMultiMemoryDescriptor::initWithAddress(
32 void * /* address */ ,
33 IOByteCount /* withLength */ ,
34 IODirection /* withDirection */ )
35 {
36 return false;
37 }
38
39 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
40
41 bool 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
52 bool IOMultiMemoryDescriptor::initWithPhysicalAddress(
53 IOPhysicalAddress /* address */ ,
54 IOByteCount /* withLength */ ,
55 IODirection /* withDirection */ )
56 {
57 return false;
58 }
59
60
61 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62
63 bool IOMultiMemoryDescriptor::initWithPhysicalRanges(
64 IOPhysicalRange * /* ranges */ ,
65 UInt32 /* withCount */ ,
66 IODirection /* withDirection */ ,
67 bool /* asReference */ )
68 {
69 return false;
70 }
71
72 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
73
74 bool 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
86 IOMultiMemoryDescriptor * IOMultiMemoryDescriptor::withDescriptors(
87 IOMemoryDescriptor ** descriptors,
88 UInt32 withCount,
89 IODirection withDirection,
90 bool asReference )
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
117 bool IOMultiMemoryDescriptor::initWithDescriptors(
118 IOMemoryDescriptor ** descriptors,
119 UInt32 withCount,
120 IODirection withDirection,
121 bool asReference )
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 // 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
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
184 void 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
204 IOReturn 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
243 IOReturn 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
273 IOPhysicalAddress 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
301 IOPhysicalAddress 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
329 void * IOMultiMemoryDescriptor::getVirtualSegment( IOByteCount /* offset */ ,
330 IOByteCount * /* length */ )
331 {
332 return 0;
333 }
334
335 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
336
337 IOByteCount 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
373 IOByteCount 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 }