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