+struct IODMACommandTransferContext
+{
+ void * buffer;
+ UInt64 bufferOffset;
+ UInt64 remaining;
+ UInt32 op;
+};
+enum
+{
+ kIODMACommandTransferOpReadBytes = 1,
+ kIODMACommandTransferOpWriteBytes = 2
+};
+
+IOReturn
+IODMACommand::transferSegment(void *reference,
+ IODMACommand *target,
+ Segment64 segment,
+ void *segments,
+ UInt32 segmentIndex)
+{
+ IODMACommandTransferContext * context = (IODMACommandTransferContext *) reference;
+ UInt64 length = min(segment.fLength, context->remaining);
+ addr64_t ioAddr = segment.fIOVMAddr;
+ addr64_t cpuAddr = ioAddr;
+
+ context->remaining -= length;
+
+ while (length)
+ {
+ UInt64 copyLen = length;
+ if ((kMapped == MAPTYPE(target->fMappingOptions))
+ && target->fMapper)
+ {
+ cpuAddr = target->fMapper->mapToPhysicalAddress(ioAddr);
+ copyLen = min(copyLen, page_size - (ioAddr & (page_size - 1)));
+ ioAddr += copyLen;
+ }
+
+ switch (context->op)
+ {
+ case kIODMACommandTransferOpReadBytes:
+ copypv(cpuAddr, context->bufferOffset + (addr64_t) context->buffer, copyLen,
+ cppvPsrc | cppvNoRefSrc | cppvFsnk | cppvKmap);
+ break;
+ case kIODMACommandTransferOpWriteBytes:
+ copypv(context->bufferOffset + (addr64_t) context->buffer, cpuAddr, copyLen,
+ cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
+ break;
+ }
+ length -= copyLen;
+ context->bufferOffset += copyLen;
+ }
+
+ return (context->remaining ? kIOReturnSuccess : kIOReturnOverrun);
+}
+
+UInt64
+IODMACommand::transfer(IOOptionBits transferOp, UInt64 offset, void * buffer, UInt64 length)
+{
+ IODMACommandInternal * state = fInternalState;
+ IODMACommandTransferContext context;
+ Segment64 segments[1];
+ UInt32 numSegments = 0-1;
+
+ if (fActive < 1)
+ return (0);
+
+ if (offset >= state->fPreparedLength)
+ return (0);
+ length = min(length, state->fPreparedLength - offset);
+
+ context.buffer = buffer;
+ context.bufferOffset = 0;
+ context.remaining = length;
+ context.op = transferOp;
+ (void) genIOVMSegments(kWalkClient, transferSegment, &context, &offset, &segments[0], &numSegments);
+
+ return (length - context.remaining);
+}
+
+UInt64
+IODMACommand::readBytes(UInt64 offset, void *bytes, UInt64 length)
+{
+ return (transfer(kIODMACommandTransferOpReadBytes, offset, bytes, length));
+}
+
+UInt64
+IODMACommand::writeBytes(UInt64 offset, const void *bytes, UInt64 length)
+{
+ return (transfer(kIODMACommandTransferOpWriteBytes, offset, const_cast<void *>(bytes), length));
+}
+