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    OSWriteBigInt(segment, 0, inSegment.location);
248    OSWriteBigInt(segment, sizeof(IOPhysicalAddress), inSegment.length);
249}
250
251IOBigMemoryCursor *
252IOBigMemoryCursor::withSpecification(IOPhysicalLength inMaxSegmentSize,
253                                     IOPhysicalLength inMaxTransferSize,
254                                     IOPhysicalLength inAlignment)
255{
256    IOBigMemoryCursor * me = new IOBigMemoryCursor;
257
258    if (me && !me->initWithSpecification(inMaxSegmentSize,
259                                         inMaxTransferSize,
260                                         inAlignment))
261    {
262        me->release();
263        return 0;
264    }
265
266    return me;
267}
268
269bool
270IOBigMemoryCursor::initWithSpecification(IOPhysicalLength inMaxSegmentSize,
271                                         IOPhysicalLength inMaxTransferSize,
272                                         IOPhysicalLength inAlignment)
273{
274    return super::initWithSpecification(&IOBigMemoryCursor::outputSegment,
275                                        inMaxSegmentSize,
276                                        inMaxTransferSize,
277                                        inAlignment);
278}
279
280/************************* class IOLittleMemoryCursor ************************/
281
282#undef super
283#define super IOMemoryCursor
284OSDefineMetaClassAndStructors(IOLittleMemoryCursor, IOMemoryCursor)
285
286void
287IOLittleMemoryCursor::outputSegment(PhysicalSegment inSegment,
288                                    void *	    inSegments,
289                                    UInt32	    inSegmentIndex)
290{
291    IOPhysicalAddress * segment;
292
293    segment = &((PhysicalSegment *) inSegments)[inSegmentIndex].location;
294    OSWriteLittleInt(segment, 0, inSegment.location);
295    OSWriteLittleInt(segment, sizeof(IOPhysicalAddress), inSegment.length);
296}
297
298IOLittleMemoryCursor *
299IOLittleMemoryCursor::withSpecification(IOPhysicalLength inMaxSegmentSize,
300                                        IOPhysicalLength inMaxTransferSize,
301                                        IOPhysicalLength inAlignment)
302{
303    IOLittleMemoryCursor * me = new IOLittleMemoryCursor;
304
305    if (me && !me->initWithSpecification(inMaxSegmentSize,
306                                         inMaxTransferSize,
307                                         inAlignment))
308    {
309        me->release();
310        return 0;
311    }
312
313    return me;
314}
315
316/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
317
318bool
319IOLittleMemoryCursor::initWithSpecification(IOPhysicalLength inMaxSegmentSize,
320                                            IOPhysicalLength inMaxTransferSize,
321                                            IOPhysicalLength inAlignment)
322{
323    return super::initWithSpecification(&IOLittleMemoryCursor::outputSegment,
324                                        inMaxSegmentSize,
325                                        inMaxTransferSize,
326                                        inAlignment);
327}
328