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/* IOMemoryCursor.cpp created by wgulland on 1999-3-02 */
29
30#include <IOKit/assert.h>
31#include <IOKit/IOLib.h>
32#include <IOKit/IOMemoryCursor.h>
33#include <IOKit/IOMemoryDescriptor.h>
34#include <libkern/OSByteOrder.h>
35
36/**************************** class IOMemoryCursor ***************************/
37
38#undef super
39#define super OSObject
40OSDefineMetaClassAndStructors(IOMemoryCursor, OSObject)
41
42IOMemoryCursor *
43IOMemoryCursor::withSpecification(SegmentFunction inSegFunc,
44 IOPhysicalLength inMaxSegmentSize,
45 IOPhysicalLength inMaxTransferSize,
46 IOPhysicalLength inAlignment)
47{
48 IOMemoryCursor * me = new IOMemoryCursor;
49
50 if (me && !me->initWithSpecification(inSegFunc,
51 inMaxSegmentSize,
52 inMaxTransferSize,
53 inAlignment))
54 {
55 me->release();
56 return 0;
57 }
58
59 return me;
60}
61
62/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
63
64bool
65IOMemoryCursor::initWithSpecification(SegmentFunction inSegFunc,
66 IOPhysicalLength inMaxSegmentSize,
67 IOPhysicalLength inMaxTransferSize,
68 IOPhysicalLength inAlignment)
69{
70// @@@ gvdl: Remove me
71#if 1
72static UInt sMaxDBDMASegment;
73if (!sMaxDBDMASegment) {
74 sMaxDBDMASegment = (UInt) -1;
75 if (PE_parse_boot_argn("mseg", &sMaxDBDMASegment, sizeof (sMaxDBDMASegment)))
76 IOLog("Setting MaxDBDMASegment to %d\n", sMaxDBDMASegment);
77}
78
79if (inMaxSegmentSize > sMaxDBDMASegment) inMaxSegmentSize = sMaxDBDMASegment;
80#endif
81
82 if (!super::init())
83 return false;
84
85 if (!inSegFunc)
86 return false;
87
88 outSeg = inSegFunc;
89 maxSegmentSize = inMaxSegmentSize;
90 if (inMaxTransferSize)
91 maxTransferSize = inMaxTransferSize;
92 else
93 maxTransferSize = (IOPhysicalLength) -1;
94 alignMask = inAlignment - 1;
95 assert(alignMask == 0); // No alignment code yet!
96
97 return true;
98}
99
100/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
101
102UInt32
103IOMemoryCursor::genPhysicalSegments(IOMemoryDescriptor *inDescriptor,
104 IOByteCount fromPosition,
105 void * inSegments,
106 UInt32 inMaxSegments,
107 UInt32 inMaxTransferSize,
108 IOByteCount *outTransferSize)
109{
110 if (!inDescriptor)
111 return 0;
112
113 if (!inMaxSegments)
114 return 0;
115
116 if (!inMaxTransferSize)
117 inMaxTransferSize = maxTransferSize;
118
119 /*
120 * Iterate over the packet, translating segments where allowed
121 *
122 * If we finished cleanly return number of segments found
123 * and update the position in the descriptor.
124 */
125 PhysicalSegment curSeg = { 0, 0 };
126 UInt curSegIndex = 0;
127 UInt curTransferSize = 0;
128 IOByteCount inDescriptorLength = inDescriptor->getLength();
129 PhysicalSegment seg = { 0, 0 };
130
131 while ((seg.location) || (fromPosition < inDescriptorLength))
132 {
133 if (!seg.location)
134 {
135 seg.location = inDescriptor->getPhysicalSegment(
136 fromPosition, (IOByteCount*)&seg.length);
137 assert(seg.location);
138 assert(seg.length);
139 fromPosition += seg.length;
140 }
141
142 if (!curSeg.location)
143 {
144 curTransferSize += seg.length;
145 curSeg = seg;
146 seg.location = 0;
147 }
148 else if ((curSeg.location + curSeg.length == seg.location))
149 {
150 curTransferSize += seg.length;
151 curSeg.length += seg.length;
152 seg.location = 0;
153 }
154
155 if (!seg.location)
156 {
157 if ((curSeg.length > maxSegmentSize))
158 {
159 seg.location = curSeg.location + maxSegmentSize;
160 seg.length = curSeg.length - maxSegmentSize;
161 curTransferSize -= seg.length;
162 curSeg.length -= seg.length;
163 }
164
165 if ((curTransferSize >= inMaxTransferSize))
166 {
167 curSeg.length -= curTransferSize - inMaxTransferSize;
168 curTransferSize = inMaxTransferSize;
169 break;
170 }
171 }
172
173 if (seg.location)
174 {
175 if ((curSegIndex + 1 == inMaxSegments))
176 break;
177 (*outSeg)(curSeg, inSegments, curSegIndex++);
178 curSeg.location = 0;
179 }
180 }
181
182 if (curSeg.location)
183 (*outSeg)(curSeg, inSegments, curSegIndex++);
184
185 if (outTransferSize)
186 *outTransferSize = curTransferSize;
187
188 return curSegIndex;
189}
190
191/************************ class IONaturalMemoryCursor ************************/
192
193#undef super
194#define super IOMemoryCursor
195OSDefineMetaClassAndStructors(IONaturalMemoryCursor, IOMemoryCursor)
196
197void IONaturalMemoryCursor::outputSegment(PhysicalSegment segment,
198 void * outSegments,
199 UInt32 outSegmentIndex)
200{
201 ((PhysicalSegment *) outSegments)[outSegmentIndex] = segment;
202}
203
204IONaturalMemoryCursor *
205IONaturalMemoryCursor::withSpecification(IOPhysicalLength inMaxSegmentSize,
206 IOPhysicalLength inMaxTransferSize,
207 IOPhysicalLength inAlignment)
208{
209 IONaturalMemoryCursor *me = new IONaturalMemoryCursor;
210
211 if (me && !me->initWithSpecification(inMaxSegmentSize,
212 inMaxTransferSize,
213 inAlignment))
214 {
215 me->release();
216 return 0;
217 }
218
219 return me;
220}
221
222bool
223IONaturalMemoryCursor::initWithSpecification(IOPhysicalLength inMaxSegmentSize,
224 IOPhysicalLength inMaxTransferSize,
225 IOPhysicalLength inAlignment)
226{
227 return super::initWithSpecification(&IONaturalMemoryCursor::outputSegment,
228 inMaxSegmentSize,
229 inMaxTransferSize,
230 inAlignment);
231}
232
233/************************** class IOBigMemoryCursor **************************/
234
235#undef super
236#define super IOMemoryCursor
237OSDefineMetaClassAndStructors(IOBigMemoryCursor, IOMemoryCursor)
238
239void
240IOBigMemoryCursor::outputSegment(PhysicalSegment inSegment,
241 void * inSegments,
242 UInt32 inSegmentIndex)
243{
244 IOPhysicalAddress * segment;
245
246 segment = &((PhysicalSegment *) inSegments)[inSegmentIndex].location;
247#if IOPhysSize == 64
248 OSWriteBigInt64(segment, 0, inSegment.location);
249 OSWriteBigInt64(segment, sizeof(IOPhysicalAddress), inSegment.length);
250#else
251 OSWriteBigInt(segment, 0, inSegment.location);
252 OSWriteBigInt(segment, sizeof(IOPhysicalAddress), inSegment.length);
253#endif
254}
255
256IOBigMemoryCursor *
257IOBigMemoryCursor::withSpecification(IOPhysicalLength inMaxSegmentSize,
258 IOPhysicalLength inMaxTransferSize,
259 IOPhysicalLength inAlignment)
260{
261 IOBigMemoryCursor * me = new IOBigMemoryCursor;
262
263 if (me && !me->initWithSpecification(inMaxSegmentSize,
264 inMaxTransferSize,
265 inAlignment))
266 {
267 me->release();
268 return 0;
269 }
270
271 return me;
272}
273
274bool
275IOBigMemoryCursor::initWithSpecification(IOPhysicalLength inMaxSegmentSize,
276 IOPhysicalLength inMaxTransferSize,
277 IOPhysicalLength inAlignment)
278{
279 return super::initWithSpecification(&IOBigMemoryCursor::outputSegment,
280 inMaxSegmentSize,
281 inMaxTransferSize,
282 inAlignment);
283}
284
285/************************* class IOLittleMemoryCursor ************************/
286
287#undef super
288#define super IOMemoryCursor
289OSDefineMetaClassAndStructors(IOLittleMemoryCursor, IOMemoryCursor)
290
291void
292IOLittleMemoryCursor::outputSegment(PhysicalSegment inSegment,
293 void * inSegments,
294 UInt32 inSegmentIndex)
295{
296 IOPhysicalAddress * segment;
297
298 segment = &((PhysicalSegment *) inSegments)[inSegmentIndex].location;
299#if IOPhysSize == 64
300 OSWriteLittleInt64(segment, 0, inSegment.location);
301 OSWriteLittleInt64(segment, sizeof(IOPhysicalAddress), inSegment.length);
302#else
303 OSWriteLittleInt(segment, 0, inSegment.location);
304 OSWriteLittleInt(segment, sizeof(IOPhysicalAddress), inSegment.length);
305#endif
306}
307
308IOLittleMemoryCursor *
309IOLittleMemoryCursor::withSpecification(IOPhysicalLength inMaxSegmentSize,
310 IOPhysicalLength inMaxTransferSize,
311 IOPhysicalLength inAlignment)
312{
313 IOLittleMemoryCursor * me = new IOLittleMemoryCursor;
314
315 if (me && !me->initWithSpecification(inMaxSegmentSize,
316 inMaxTransferSize,
317 inAlignment))
318 {
319 me->release();
320 return 0;
321 }
322
323 return me;
324}
325
326/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
327
328bool
329IOLittleMemoryCursor::initWithSpecification(IOPhysicalLength inMaxSegmentSize,
330 IOPhysicalLength inMaxTransferSize,
331 IOPhysicalLength inAlignment)
332{
333 return super::initWithSpecification(&IOLittleMemoryCursor::outputSegment,
334 inMaxSegmentSize,
335 inMaxTransferSize,
336 inAlignment);
337}
338