]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOMultiMemoryDescriptor.cpp
98eb04d823836892e05aa97abe0cd712cd65abf3
[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 = 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
117 bool 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
175 void 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
195 IOReturn 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
234 IOReturn 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
264 IOPhysicalAddress 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
292 IOPhysicalAddress 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
320 void * IOMultiMemoryDescriptor::getVirtualSegment( IOByteCount /* offset */ ,
321 IOByteCount * /* length */ )
322 {
323 return 0;
324 }
325
326 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
327
328 IOByteCount 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
364 IOByteCount 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 }