/*
* Copyright (c) 1998-2019 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef _IOMEMORYCURSOR_H
#define _IOMEMORYCURSOR_H
#include <libkern/c++/OSObject.h>
#include <libkern/c++/OSPtr.h>
#include <IOKit/IOTypes.h>
class IOMemoryDescriptor;
/**************************** class IOMemoryCursor ***************************/
/*!
* @class IOMemoryCursor
* @abstract A mechanism to convert memory references to physical addresses.
* @discussion The IOMemoryCursor declares the super class that all
* specific memory cursors must inherit from, but a memory cursor can be created without a specific format subclass by just providing a segment function to the initializers. This class does the difficult stuff of dividing a memory descriptor into a physical scatter/gather list appropriate for the target hardware.
* <br><br>
* A driver is expected to create a memory cursor and configure it to the limitations of its DMA hardware; for instance the memory cursor used by the FireWire SBP-2 protocol has a maximum physical segment size of 2^16 - 1 but the actual transfer size is unlimited. Thus it would create a cursor with a maxSegmentSize of 65535 and a maxTransfer size of UINT_MAX. It would also provide a SegmentFunction that can output a pagelist entry.
* <br><br>
* Below is the simplest example of a SegmentFunction:<br>
* void IONaturalMemoryCursor::outputSegment(PhysicalSegment segment,<br>
* void * outSegments,<br>
* UInt32 outSegmentIndex)<br>
* {<br>
* ((PhysicalSegment *) outSegments)[outSegmentIndex] = segment;<br>
* }
*
*/
class IOMemoryCursor : public OSObject
{
OSDeclareDefaultStructors(IOMemoryCursor);
public:
/*!
* @typedef PhysicalSegment
* @discussion A physical address/length pair.
*/
struct PhysicalSegment {
IOPhysicalAddress location;
IOPhysicalLength length;
};
/*! @defined IOPhysicalSegment
* @discussion Backward compatibility define for the old non-class scoped type definition. See IOMemoryCursor::PhysicalSegment
*/
#define IOPhysicalSegment IOMemoryCursor::PhysicalSegment
/*!
* @typedef SegmentFunction
* @discussion Pointer to a C function that outputs a single physical segment to an element in the array as defined by the segments and segmentIndex parameters.
* @param segment The physical address and length that is next to be output.
* @param segments Base of the output vector of DMA address length pairs.
* @param segmentIndex Index to output 'segment' in the 'segments' array.
*/
typedef void (*SegmentFunction)(PhysicalSegment segment,
void * segments,
UInt32 segmentIndex);
/*! @defined OutputSegmentFunc
* @discussion Backward compatibility define for the old non-class scoped type definition. See IOMemoryCursor::SegmentFunction */
#define OutputSegmentFunc IOMemoryCursor::SegmentFunction
protected:
/*! @var outSeg The action method called when an event has been delivered */
SegmentFunction outSeg;
/*! @var maxSegmentSize Maximum size of one segment in a scatter/gather list */
IOPhysicalLength maxSegmentSize;
/*! @var maxTransferSize
* Maximum size of a transfer that this memory cursor is allowed to generate */
IOPhysicalLength maxTransferSize;
/*! @var alignMask
* Currently unused. Reserved for automated aligment restriction code. */
IOPhysicalLength alignMask;
public:
/*! @function withSpecification
* @abstract Creates and initializes an IOMemoryCursor in one operation.
* @discussion Factory function to create and initialize an IOMemoryCursor in one operation. For more information, see IOMemoryCursor::initWithSpecification.
* @param outSegFunc SegmentFunction to call to output one physical segment.
* @param maxSegmentSize Maximum allowable size for one segment. Defaults to 0.
* @param maxTransferSize Maximum size of an entire transfer. Defaults to 0 indicating no maximum.
* @param alignment Alignment restrictions on output physical addresses. Not currently implemented. Defaults to single byte alignment.
* @result Returns a new memory cursor if successfully created and initialized, 0 otherwise.
*/
static OSPtr<IOMemoryCursor>
withSpecification(SegmentFunction outSegFunc,
IOPhysicalLength maxSegmentSize = 0,
IOPhysicalLength maxTransferSize = 0,
IOPhysicalLength alignment = 1);
/*! @function initWithSpecification
* @abstract Primary initializer for the IOMemoryCursor class.
* @param outSegFunc SegmentFunction to call to output one physical segment.
* @param maxSegmentSize Maximum allowable size for one segment. Defaults to 0.
* @param maxTransferSize Maximum size of an entire transfer. Defaults to 0 indicating no maximum.
* @param alignment Alignment restrictions on output physical addresses. Not currently implemented. Defaults to single byte alignment.
* @result Returns true if the inherited classes and this instance initialize
* successfully.
*/
virtual bool initWithSpecification(SegmentFunction outSegFunc,
IOPhysicalLength maxSegmentSize = 0,
IOPhysicalLength maxTransferSize = 0,
IOPhysicalLength alignment = 1);
/*! @function genPhysicalSegments
* @abstract Generates a physical scatter/gather list given a memory descriptor.
* @discussion Generates a list of physical segments from the given memory descriptor, relative to the current position of the descriptor.
* @param descriptor IOMemoryDescriptor that describes the data associated with an I/O request.
* @param fromPosition Starting location of the I/O within a memory descriptor.
* @param segments Void pointer to base of output physical scatter/gather list. Always passed directly onto the SegmentFunction without interpretation by the cursor.
* @param maxSegments Maximum number of segments that can be written to segments array.
* @param maxTransferSize Maximum transfer size is limited to that many bytes, otherwise it defaults to the maximum transfer size specified when the memory cursor was initialized.
* @param transferSize Pointer to an IOByteCount variable that can contain the total size of the transfer being described. Defaults to 0 indicating that no transfer size need be returned.
* @result If the descriptor is exhausted of memory, a zero is returned, otherwise the number of segments that were filled in is returned.
*/
virtual UInt32 genPhysicalSegments(
IOMemoryDescriptor *descriptor,
IOByteCount fromPosition,
void * segments,
UInt32 maxSegments,
UInt32 maxTransferSize = 0,
IOByteCount *transferSize = NULL);
};
/************************ class IONaturalMemoryCursor ************************/
/*!
* @class IONaturalMemoryCursor
* @abstract An IOMemoryCursor subclass that outputs a vector of PhysicalSegments in the natural byte orientation for the CPU.
* @discussion The IONaturalMemoryCursor would be used when it is too difficult to safely describe a SegmentFunction that is more appropriate for your hardware. This cursor just outputs an array of PhysicalSegments.
*/
class IONaturalMemoryCursor : public IOMemoryCursor
{
OSDeclareDefaultStructors(IONaturalMemoryCursor);
public:
/*! @function outputSegment
* @abstract Outputs the given segment into the output segments array in natural byte order.
* @param segment The physical address and length that is next to be output.
* @param segments Base of the output vector of DMA address length pairs.
* @param segmentIndex Index to output 'segment' in the 'segments' array.
*/
static void outputSegment(PhysicalSegment segment,
void * segments,
UInt32 segmentIndex);
/*! @defined naturalOutputSegment
* @discussion Backward compatibility define for the old global function definition. See IONaturalMemoryCursor::outputSegment.
*/
#define naturalOutputSegment IONaturalMemoryCursor::outputSegment
/*! @function withSpecification
* @abstract Creates and initializes an IONaturalMemoryCursor in one operation.
* @discussion Factory function to create and initialize an IONaturalMemoryCursor in one operation. For more information, see IONaturalMemoryCursor::initWithSpecification.
* @param maxSegmentSize Maximum allowable size for one segment. Defaults to 0.
* @param maxTransferSize Maximum size of an entire transfer. Defaults to 0 indicating no maximum.
* @param alignment Alignment restrictions on output physical addresses. Not currently implemented. Defaults to single byte alignment.
* @result Returns a new memory cursor if successfully created and initialized, 0 otherwise.
*/
static OSPtr<IONaturalMemoryCursor>
withSpecification(IOPhysicalLength maxSegmentSize,
IOPhysicalLength maxTransferSize,
IOPhysicalLength alignment = 1);
/*! @function initWithSpecification
* @abstract Primary initializer for the IONaturalMemoryCursor class.
* @param maxSegmentSize Maximum allowable size for one segment. Defaults to 0.
* @param maxTransferSize Maximum size of an entire transfer. Defaults to 0 indicating no maximum.
* @param alignment Alignment restrictions on output physical addresses. Not currently implemented. Defaults to single byte alignment.
* @result Returns true if the inherited classes and this instance initialize successfully.
*/
virtual bool initWithSpecification(IOPhysicalLength maxSegmentSize,
IOPhysicalLength maxTransferSize,
IOPhysicalLength alignment = 1);
/*! @function getPhysicalSegments
* @abstract Generates a CPU natural physical scatter/gather list given a memory descriptor.
* @discussion Generates a list of physical segments from the given memory descriptor, relative to the current position of the descriptor. Wraps IOMemoryCursor::genPhysicalSegments.
* @param descriptor IOMemoryDescriptor that describes the data associated with an I/O request.
* @param fromPosition Starting location of the I/O within a memory descriptor.
* @param segments Pointer to an array of IOMemoryCursor::PhysicalSegments for the output physical scatter/gather list.
* @param maxSegments Maximum number of segments that can be written to segments array.
* @param inMaxTransferSize Maximum transfer size is limited to that many bytes, otherwise it defaults to the maximum transfer size specified when the memory cursor was initialized.
* @param transferSize Pointer to an IOByteCount variable that can contain the total size of the transfer being described. Defaults to 0 indicating that no transfer size need be returned.
* @result If the descriptor is exhausted of memory, a zero is returned, otherwise the number of segments that were filled in is returned.
*/
virtual UInt32
getPhysicalSegments(IOMemoryDescriptor *descriptor,
IOByteCount fromPosition,
PhysicalSegment *segments,
UInt32 maxSegments,
UInt32 inMaxTransferSize = 0,
IOByteCount *transferSize = NULL)
{
return genPhysicalSegments(descriptor, fromPosition, segments,
maxSegments, inMaxTransferSize, transferSize);
}
};
/************************** class IOBigMemoryCursor **************************/
/*!
* @class IOBigMemoryCursor
* @abstract An IOMemoryCursor subclass that outputs a vector of PhysicalSegments in the big endian byte order.
* @discussion The IOBigMemoryCursor would be used when the DMA hardware requires a big endian address and length pair. This cursor outputs an array of PhysicalSegments that are encoded in big-endian format.
*/
class IOBigMemoryCursor : public IOMemoryCursor
{
OSDeclareDefaultStructors(IOBigMemoryCursor);
public:
/*! @function outputSegment
* @abstract Outputs the given segment into the output segments array in big endian byte order.
* @param segment The physical address and length that is next to be output.
* @param segments Base of the output vector of DMA address length pairs.
* @param segmentIndex Index to output 'segment' in the 'segments' array.
*/
static void outputSegment(PhysicalSegment segment,
void * segments,
UInt32 segmentIndex);
/*! @defined bigOutputSegment
* @discussion Backward compatibility define for the old global function definition. See IOBigMemoryCursor::outputSegment
*/
#define bigOutputSegment IOBigMemoryCursor::outputSegment
/*! @function withSpecification
* @abstract Creates and initializes an IOBigMemoryCursor in one operation.
* @discussion Factory function to create and initialize an IOBigMemoryCursor in one operation. See also IOBigMemoryCursor::initWithSpecification.
* @param maxSegmentSize Maximum allowable size for one segment. Defaults to 0.
* @param maxTransferSize Maximum size of an entire transfer. Defaults to 0 indicating no maximum.
* @param alignment Alignment restrictions on output physical addresses. Not currently implemented. Defaults to single byte alignment.
* @result Returns a new memory cursor if successfully created and initialized, 0 otherwise.
*/
static OSPtr<IOBigMemoryCursor>
withSpecification(IOPhysicalLength maxSegmentSize,
IOPhysicalLength maxTransferSize,
IOPhysicalLength alignment = 1);
/*! @function initWithSpecification
* @abstract Primary initializer for the IOBigMemoryCursor class.
* @param maxSegmentSize Maximum allowable size for one segment. Defaults to 0.
* @param maxTransferSize Maximum size of an entire transfer. Defaults to 0 indicating no maximum.
* @param alignment Alignment restrictions on output physical addresses. Not currently implemented. Defaults to single byte alignment.
* @result Returns true if the inherited classes and this instance initialize
* successfully.
*/
virtual bool initWithSpecification(IOPhysicalLength maxSegmentSize,
IOPhysicalLength maxTransferSize,
IOPhysicalLength alignment = 1);
/*! @function getPhysicalSegments
* @abstract Generates a big endian physical scatter/gather list given a memory descriptor.
* @discussion Generates a list of physical segments from the given memory descriptor, relative to the current position of the descriptor. Wraps IOMemoryCursor::genPhysicalSegments.
* @param descriptor IOMemoryDescriptor that describes the data associated with an I/O request.
* @param fromPosition Starting location of the I/O within a memory descriptor.
* @param segments Pointer to an array of IOMemoryCursor::PhysicalSegments for the output physical scatter/gather list.
* @param maxSegments Maximum number of segments that can be written to segments array.
* @param inMaxTransferSize Maximum transfer size is limited to that many bytes, otherwise it defaults to the maximum transfer size specified when the memory cursor was initialized.
* @param transferSize Pointer to an IOByteCount variable that can contain the total size of the transfer being described. Defaults to 0 indicating that no transfer size need be returned.
* @result If the descriptor is exhausted of memory, a zero is returned, otherwise the number of segments that were filled in is returned.
*/
virtual UInt32
getPhysicalSegments(IOMemoryDescriptor * descriptor,
IOByteCount fromPosition,
PhysicalSegment * segments,
UInt32 maxSegments,
UInt32 inMaxTransferSize = 0,
IOByteCount * transferSize = NULL)
{
return genPhysicalSegments(descriptor, fromPosition, segments,
maxSegments, inMaxTransferSize, transferSize);
}
};
/************************* class IOLittleMemoryCursor ************************/
/*!
* @class IOLittleMemoryCursor
* @abstract An IOMemoryCursor subclass that outputs a vector of PhysicalSegments in the little endian byte order.
* @discussion The IOLittleMemoryCursor would be used when the DMA hardware requires a little endian address and length pair. This cursor outputs an array of PhysicalSegments that are encoded in little endian format.
*/
class IOLittleMemoryCursor : public IOMemoryCursor
{
OSDeclareDefaultStructors(IOLittleMemoryCursor);
public:
/*! @function outputSegment
* @abstract Outputs the given segment into the output segments array in little endian byte order.
* @param segment The physical address and length that is next to be output.
* @param segments Base of the output vector of DMA address length pairs.
* @param segmentIndex Index to output 'segment' in the 'segments' array.
*/
static void outputSegment(PhysicalSegment segment,
void * segments,
UInt32 segmentIndex);
/*! @defined littleOutputSegment
* @discussion Backward compatibility define for the old global function definition. See also IOLittleMemoryCursor::outputSegment. */
#define littleOutputSegment IOLittleMemoryCursor::outputSegment
/*! @function withSpecification
* @abstract Creates and initializes an IOLittleMemoryCursor in one operation.
* @discussion Factory function to create and initialize an IOLittleMemoryCursor in one operation. See also IOLittleMemoryCursor::initWithSpecification.
* @param maxSegmentSize Maximum allowable size for one segment. Defaults to 0.
* @param maxTransferSize Maximum size of an entire transfer. Defaults to 0 indicating no maximum.
* @param alignment Alignment restrictions on output physical addresses. Not currently implemented. Defaults to single byte alignment.
* @result Returns a new memory cursor if successfully created and initialized, 0 otherwise.
*/
static OSPtr<IOLittleMemoryCursor>
withSpecification(IOPhysicalLength maxSegmentSize,
IOPhysicalLength maxTransferSize,
IOPhysicalLength alignment = 1);
/*! @function initWithSpecification
* @abstract Primary initializer for the IOLittleMemoryCursor class.
* @param maxSegmentSize Maximum allowable size for one segment. Defaults to 0.
* @param maxTransferSize Maximum size of an entire transfer. Defaults to 0 indicating no maximum.
* @param alignment Alignment restrictions on output physical addresses. Not currently implemented. Defaults to single byte alignment.
* @result Returns true if the inherited classes and this instance initialize successfully.
*/
virtual bool initWithSpecification(IOPhysicalLength maxSegmentSize,
IOPhysicalLength maxTransferSize,
IOPhysicalLength alignment = 1);
/*! @function getPhysicalSegments
* @abstract Generates a little endian physical scatter/gather list given a memory descriptor.
* @discussion Generates a list of physical segments from the given memory descriptor, relative to the current position of the descriptor. Wraps IOMemoryCursor::genPhysicalSegments.
* @param descriptor IOMemoryDescriptor that describes the data associated with an I/O request.
* @param fromPosition Starting location of the I/O within a memory descriptor.
* @param segments Pointer to an array of IOMemoryCursor::PhysicalSegments for the output physical scatter/gather list.
* @param maxSegments Maximum number of segments that can be written to segments array.
* @param inMaxTransferSize Maximum transfer size is limited to that many bytes, otherwise it defaults to the maximum transfer size specified when the memory cursor was initialized.
* @param transferSize Pointer to an IOByteCount variable that can contain the total size of the transfer being described. Defaults to 0 indicating that no transfer size need be returned.
* @result If the descriptor is exhausted of memory, a zero is returned, otherwise the number of segments that were filled in is returned.
*/
virtual UInt32
getPhysicalSegments(IOMemoryDescriptor * descriptor,
IOByteCount fromPosition,
PhysicalSegment * segments,
UInt32 maxSegments,
UInt32 inMaxTransferSize = 0,
IOByteCount * transferSize = NULL)
{
return genPhysicalSegments(descriptor, fromPosition, segments,
maxSegments, inMaxTransferSize, transferSize);
}
};
#endif /* !_IOMEMORYCURSOR_H */