1/* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <IOKit/IOLib.h> 30#include <IOKit/IOMultiMemoryDescriptor.h> 31 32#define super IOMemoryDescriptor 33OSDefineMetaClassAndStructors(IOMultiMemoryDescriptor, IOMemoryDescriptor) 34 35IOMultiMemoryDescriptor * IOMultiMemoryDescriptor::withDescriptors( 36 IOMemoryDescriptor ** descriptors, 37 UInt32 withCount, 38 IODirection withDirection, 39 bool asReference ) 40{ 41 // 42 // Create a new IOMultiMemoryDescriptor. The "buffer" is made up of several 43 // memory descriptors, that are to be chained end-to-end to make up a single 44 // memory descriptor. 45 // 46 // Passing the ranges as a reference will avoid an extra allocation. 47 // 48 49 IOMultiMemoryDescriptor * me = new IOMultiMemoryDescriptor; 50 51 if ( me && me->initWithDescriptors( 52 /* descriptors */ descriptors, 53 /* withCount */ withCount, 54 /* withDirection */ withDirection, 55 /* asReference */ asReference ) == false ) 56 { 57 me->release(); 58 me = 0; 59 } 60 61 return me; 62} 63 64bool IOMultiMemoryDescriptor::initWithDescriptors( 65 IOMemoryDescriptor ** descriptors, 66 UInt32 withCount, 67 IODirection withDirection, 68 bool asReference ) 69{ 70 // 71 // Initialize an IOMultiMemoryDescriptor. The "buffer" is made up of several 72 // memory descriptors, that are to be chained end-to-end to make up a single 73 // memory descriptor. 74 // 75 // Passing the ranges as a reference will avoid an extra allocation. 76 // 77 78 assert(descriptors); 79 80 // Release existing descriptors, if any 81 if ( _descriptors ) 82 { 83 for ( unsigned index = 0; index < _descriptorsCount; index++ ) 84 _descriptors[index]->release(); 85 86 if ( _descriptorsIsAllocated ) 87 IODelete(_descriptors, IOMemoryDescriptor *, _descriptorsCount); 88 } else { 89 // Ask our superclass' opinion. 90 if ( super::init() == false ) return false; 91 } 92 93 // Initialize our minimal state. 94 95 _descriptors = 0; 96 _descriptorsCount = withCount; 97 _descriptorsIsAllocated = asReference ? false : true; 98 _flags = withDirection; 99#ifndef __LP64__ 100 _direction = (IODirection) (_flags & kIOMemoryDirectionMask); 101#endif /* !__LP64__ */ 102 _length = 0; 103 _mappings = 0; 104 _tag = 0; 105 106 if ( asReference ) 107 { 108 _descriptors = descriptors; 109 } 110 else 111 { 112 _descriptors = IONew(IOMemoryDescriptor *, withCount); 113 if ( _descriptors == 0 ) return false; 114 115 bcopy( /* from */ descriptors, 116 /* to */ _descriptors, 117 /* bytes */ withCount * sizeof(IOMemoryDescriptor *) ); 118 } 119 120 for ( unsigned index = 0; index < withCount; index++ ) 121 { 122 descriptors[index]->retain(); 123 _length += descriptors[index]->getLength(); 124 if ( _tag == 0 ) _tag = descriptors[index]->getTag(); 125 assert(descriptors[index]->getDirection() == 126 (withDirection & kIOMemoryDirectionMask)); 127 } 128 129 return true; 130} 131 132void IOMultiMemoryDescriptor::free() 133{ 134 // 135 // Free all of this object's outstanding resources. 136 // 137 138 if ( _descriptors ) 139 { 140 for ( unsigned index = 0; index < _descriptorsCount; index++ ) 141 _descriptors[index]->release(); 142 143 if ( _descriptorsIsAllocated ) 144 IODelete(_descriptors, IOMemoryDescriptor *, _descriptorsCount); 145 } 146 147 super::free(); 148} 149 150IOReturn IOMultiMemoryDescriptor::prepare(IODirection forDirection) 151{ 152 // 153 // Prepare the memory for an I/O transfer. 154 // 155 // This involves paging in the memory and wiring it down for the duration 156 // of the transfer. The complete() method finishes the processing of the 157 // memory after the I/O transfer finishes. 158 // 159 160 unsigned index; 161 IOReturn status = kIOReturnInternalError; 162 IOReturn statusUndo; 163 164 if ( forDirection == kIODirectionNone ) 165 { 166 forDirection = getDirection(); 167 } 168 169 for ( index = 0; index < _descriptorsCount; index++ ) 170 { 171 status = _descriptors[index]->prepare(forDirection); 172 if ( status != kIOReturnSuccess ) break; 173 } 174 175 if ( status != kIOReturnSuccess ) 176 { 177 for ( unsigned indexUndo = 0; indexUndo <= index; indexUndo++ ) 178 { 179 statusUndo = _descriptors[index]->complete(forDirection); 180 assert(statusUndo == kIOReturnSuccess); 181 } 182 } 183 184 return status; 185} 186 187IOReturn IOMultiMemoryDescriptor::complete(IODirection forDirection) 188{ 189 // 190 // Complete processing of the memory after an I/O transfer finishes. 191 // 192 // This method shouldn't be called unless a prepare() was previously issued; 193 // the prepare() and complete() must occur in pairs, before and after an I/O 194 // transfer. 195 // 196 197 IOReturn status; 198 IOReturn statusFinal = kIOReturnSuccess; 199 200 if ( forDirection == kIODirectionNone ) 201 { 202 forDirection = getDirection(); 203 } 204 205 for ( unsigned index = 0; index < _descriptorsCount; index++ ) 206 { 207 status = _descriptors[index]->complete(forDirection); 208 if ( status != kIOReturnSuccess ) statusFinal = status; 209 assert(status == kIOReturnSuccess); 210 } 211 212 return statusFinal; 213} 214 215addr64_t IOMultiMemoryDescriptor::getPhysicalSegment( 216 IOByteCount offset, 217 IOByteCount * length, 218 IOOptionBits options ) 219{ 220 // 221 // This method returns the physical address of the byte at the given offset 222 // into the memory, and optionally the length of the physically contiguous 223 // segment from that offset. 224 // 225 226 assert(offset <= _length); 227 228 for ( unsigned index = 0; index < _descriptorsCount; index++ ) 229 { 230 if ( offset < _descriptors[index]->getLength() ) 231 { 232 return _descriptors[index]->getPhysicalSegment(offset, length, options); 233 } 234 offset -= _descriptors[index]->getLength(); 235 } 236 237 if ( length ) *length = 0; 238 239 return 0; 240} 241