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/IOInterleavedMemoryDescriptor.h> 31 32#define super IOMemoryDescriptor 33OSDefineMetaClassAndStructors(IOInterleavedMemoryDescriptor, IOMemoryDescriptor) 34 35IOInterleavedMemoryDescriptor * IOInterleavedMemoryDescriptor::withCapacity( 36 IOByteCount capacity, 37 IODirection direction ) 38{ 39 // 40 // Create a new IOInterleavedMemoryDescriptor. The "buffer" will be made up 41 // of several memory descriptors, that are to be chained end-to-end to make up 42 // a single memory descriptor. 43 // 44 45 IOInterleavedMemoryDescriptor * me = new IOInterleavedMemoryDescriptor; 46 47 if ( me && !me->initWithCapacity( 48 /* capacity */ capacity, 49 /* direction */ direction )) 50 { 51 me->release(); 52 me = 0; 53 } 54 55 return me; 56} 57 58bool IOInterleavedMemoryDescriptor::initWithCapacity( 59 IOByteCount capacity, 60 IODirection direction ) 61{ 62 // 63 // Initialize an IOInterleavedMemoryDescriptor. The "buffer" will be made up 64 // of several memory descriptors, that are to be chained end-to-end to make up 65 // a single memory descriptor. 66 // 67 68 assert(capacity); 69 70 // Ask our superclass' opinion. 71 if ( super::init() == false ) return false; 72 73 // Initialize our minimal state. 74 75 _flags = direction; 76#ifndef __LP64__ 77 _direction = (IODirection) (_flags & kIOMemoryDirectionMask); 78#endif /* !__LP64__ */ 79 _length = 0; 80 _mappings = 0; 81 _tag = 0; 82 _descriptorCount = 0; 83 _descriptors = IONew(IOMemoryDescriptor *, capacity); 84 _descriptorOffsets = IONew(IOByteCount, capacity); 85 _descriptorLengths = IONew(IOByteCount, capacity); 86 87 if ( (_descriptors == 0) || (_descriptorOffsets == 0) || (_descriptorLengths == 0) ) 88 return false; 89 90 _descriptorCapacity = capacity; 91 92 return true; 93} 94 95void IOInterleavedMemoryDescriptor::clearMemoryDescriptors( IODirection direction ) 96{ 97 UInt32 index; 98 99 for ( index = 0; index < _descriptorCount; index++ ) 100 { 101 if ( _descriptorPrepared ) 102 _descriptors[index]->complete(getDirection()); 103 104 _descriptors[index]->release(); 105 _descriptors[index] = 0; 106 107 _descriptorOffsets[index] = 0; 108 _descriptorLengths[index] = 0; 109 } 110 111 if ( direction != kIODirectionNone ) 112 { 113 _flags = (_flags & ~kIOMemoryDirectionMask) | direction; 114#ifndef __LP64__ 115 _direction = (IODirection) (_flags & kIOMemoryDirectionMask); 116#endif /* !__LP64__ */ 117 } 118 119 _descriptorCount = 0; 120 _length = 0; 121 _mappings = 0; 122 _tag = 0; 123 124}; 125 126bool IOInterleavedMemoryDescriptor::setMemoryDescriptor( 127 IOMemoryDescriptor * descriptor, 128 IOByteCount offset, 129 IOByteCount length ) 130{ 131 if ( _descriptorPrepared || (_descriptorCount == _descriptorCapacity) ) 132 return false; 133 134 if ( (offset + length) > descriptor->getLength() ) 135 return false; 136 137// if ( descriptor->getDirection() != getDirection() ) 138// return false; 139 140 descriptor->retain(); 141 _descriptors[_descriptorCount] = descriptor; 142 _descriptorOffsets[_descriptorCount] = offset; 143 _descriptorLengths[_descriptorCount] = length; 144 145 _descriptorCount++; 146 147 _length += length; 148 149 return true; 150} 151 152void IOInterleavedMemoryDescriptor::free() 153{ 154 // 155 // Free all of this object's outstanding resources. 156 // 157 158 if ( _descriptors ) 159 { 160 for ( unsigned index = 0; index < _descriptorCount; index++ ) 161 _descriptors[index]->release(); 162 163 if ( _descriptors != 0 ) 164 IODelete(_descriptors, IOMemoryDescriptor *, _descriptorCapacity); 165 166 if ( _descriptorOffsets != 0 ) 167 IODelete(_descriptorOffsets, IOMemoryDescriptor *, _descriptorCapacity); 168 169 if ( _descriptorLengths != 0 ) 170 IODelete(_descriptorLengths, IOMemoryDescriptor *, _descriptorCapacity); 171 } 172 173 super::free(); 174} 175 176IOReturn IOInterleavedMemoryDescriptor::prepare(IODirection forDirection) 177{ 178 // 179 // Prepare the memory for an I/O transfer. 180 // 181 // This involves paging in the memory and wiring it down for the duration 182 // of the transfer. The complete() method finishes the processing of the 183 // memory after the I/O transfer finishes. 184 // 185 186 unsigned index; 187 IOReturn status = kIOReturnSuccess; 188 IOReturn statusUndo; 189 190 if ( forDirection == kIODirectionNone ) 191 { 192 forDirection = getDirection(); 193 } 194 195 for ( index = 0; index < _descriptorCount; index++ ) 196 { 197 status = _descriptors[index]->prepare(forDirection); 198 if ( status != kIOReturnSuccess ) break; 199 } 200 201 if ( status != kIOReturnSuccess ) 202 { 203 for ( unsigned indexUndo = 0; indexUndo < index; indexUndo++ ) 204 { 205 statusUndo = _descriptors[index]->complete(forDirection); 206 assert(statusUndo == kIOReturnSuccess); 207 } 208 } 209 210 if ( status == kIOReturnSuccess ) _descriptorPrepared = true; 211 212 return status; 213} 214 215IOReturn IOInterleavedMemoryDescriptor::complete(IODirection forDirection) 216{ 217 // 218 // Complete processing of the memory after an I/O transfer finishes. 219 // 220 // This method shouldn't be called unless a prepare() was previously issued; 221 // the prepare() and complete() must occur in pairs, before and after an I/O 222 // transfer. 223 // 224 225 IOReturn status; 226 IOReturn statusFinal = kIOReturnSuccess; 227 228 if ( forDirection == kIODirectionNone ) 229 { 230 forDirection = getDirection(); 231 } 232 233 for ( unsigned index = 0; index < _descriptorCount; index++ ) 234 { 235 status = _descriptors[index]->complete(forDirection); 236 if ( status != kIOReturnSuccess ) statusFinal = status; 237 assert(status == kIOReturnSuccess); 238 } 239 240 _descriptorPrepared = false; 241 242 return statusFinal; 243} 244 245addr64_t IOInterleavedMemoryDescriptor::getPhysicalSegment( 246 IOByteCount offset, 247 IOByteCount * length, 248 IOOptionBits options ) 249{ 250 // 251 // This method returns the physical address of the byte at the given offset 252 // into the memory, and optionally the length of the physically contiguous 253 // segment from that offset. 254 // 255 256 addr64_t pa; 257 258 assert(offset <= _length); 259 260 for ( unsigned index = 0; index < _descriptorCount; index++ ) 261 { 262 if ( offset < _descriptorLengths[index] ) 263 { 264 pa = _descriptors[index]->getPhysicalSegment(_descriptorOffsets[index] + offset, length, options); 265 if ((_descriptorLengths[index] - offset) < *length) *length = _descriptorLengths[index] - offset; 266 return pa; 267 } 268 offset -= _descriptorLengths[index]; 269 } 270 271 if ( length ) *length = 0; 272 273 return 0; 274} 275