Пример #1
0
IOReturn AppleSamplePCI::generateDMAAddresses( IOMemoryDescriptor * memDesc )
{
    // Get the physical segment list. These could be used to generate a scatter gather
    // list for hardware.

    // This is the old getPhysicalSegment() loop calling IOMemoryDescriptor,
    // it will fail (panic) on new machines with memory above the 4Gb line

    IODMACommand *	cmd;
    IOReturn            err = kIOReturnSuccess;
    IOByteCount		offset = 0;
    IOPhysicalAddress	physicalAddr;
    IOPhysicalLength	segmentLength;
    UInt32              index = 0;

    while( (physicalAddr = memDesc->getPhysicalSegment( offset, &segmentLength ))) {
	IOLog("Physical segment(%ld) %08lx:%08lx\n", index, physicalAddr, segmentLength);
	offset += segmentLength;
	index++;
    }

    // 64 bit physical address generation using IODMACommand
    do
    {
	cmd = IODMACommand::withSpecification(
	    // outSegFunc - Host endian since we read the address data with the cpu
	    // and 64 bit wide quantities
	    kIODMACommandOutputHost64, 
	    // numAddressBits
	    64, 
	    // maxSegmentSize - zero for unrestricted physically contiguous chunks
	    0,
	    // mappingOptions - kMapped for DMA addresses
	    IODMACommand::kMapped,
	    // maxTransferSize - no restriction
	    0,
	    // alignment - no restriction
	    1 );
	if (!cmd)
	{
	    IOLog("IODMACommand::withSpecification failed\n");
	    break;
	}

	// point at the memory descriptor and use the auto prepare option
	// to prepare the entire range
	err = cmd->setMemoryDescriptor(memDesc);
	if (kIOReturnSuccess != err)
	{
	    IOLog("setMemoryDescriptor failed (0x%x)\n", err);
	    break;
	}

	UInt64 offset = 0;
	while ((kIOReturnSuccess == err) && (offset < memDesc->getLength()))
	{
	    // use the 64 bit variant to match outSegFunc
	    IODMACommand::Segment64 segments[1];
	    UInt32 numSeg = 1;

	    // use the 64 bit variant to match outSegFunc
	    err = cmd->gen64IOVMSegments(&offset, &segments[0], &numSeg);
	    IOLog("gen64IOVMSegments(%x) addr 0x%qx, len 0x%qx, nsegs %ld\n",
		    err, segments[0].fIOVMAddr, segments[0].fLength, numSeg);
	}

	// if we had a DMA controller, kick off the DMA here

	// when the DMA has completed,
	
	// clear the memory descriptor and use the auto complete option
	// to complete the transaction
	err = cmd->clearMemoryDescriptor();
	if (kIOReturnSuccess != err)
	{
	    IOLog("clearMemoryDescriptor failed (0x%x)\n", err);
	}
    }
    while (false);
    if (cmd)
	cmd->release();
    // end 64 bit loop


    // 32 bit physical address generation using IODMACommand
    // any memory above 4Gb in the memory descriptor will be buffered
    // to memory below the 4G line, on machines without remapping HW support
    do
    {
	cmd = IODMACommand::withSpecification(
	    // outSegFunc - Host endian since we read the address data with the cpu
	    // and 32 bit wide quantities
	    kIODMACommandOutputHost32, 
	    // numAddressBits
	    32, 
	    // maxSegmentSize - zero for unrestricted physically contiguous chunks
	    0,
	    // mappingOptions - kMapped for DMA addresses
	    IODMACommand::kMapped,
	    // maxTransferSize - no restriction
	    0,
	    // alignment - no restriction
	    1 );
	if (!cmd)
	{
	    IOLog("IODMACommand::withSpecification failed\n");
	    break;
	}

	// point at the memory descriptor and use the auto prepare option
	// to prepare the entire range
	err = cmd->setMemoryDescriptor(memDesc);
	if (kIOReturnSuccess != err)
	{
	    IOLog("setMemoryDescriptor failed (0x%x)\n", err);
	    break;
	}

	UInt64 offset = 0;
	while ((kIOReturnSuccess == err) && (offset < memDesc->getLength()))
	{
	    // use the 32 bit variant to match outSegFunc
	    IODMACommand::Segment32 segments[1];
	    UInt32 numSeg = 1;

	    // use the 32 bit variant to match outSegFunc
	    err = cmd->gen32IOVMSegments(&offset, &segments[0], &numSeg);
	    IOLog("gen32IOVMSegments(%x) addr 0x%lx, len 0x%lx, nsegs %ld\n",
		    err, segments[0].fIOVMAddr, segments[0].fLength, numSeg);
	}

	// if we had a DMA controller, kick off the DMA here

	// when the DMA has completed,
	
	// clear the memory descriptor and use the auto complete option
	// to complete the transaction
	err = cmd->clearMemoryDescriptor();
	if (kIOReturnSuccess != err)
	{
	    IOLog("clearMemoryDescriptor failed (0x%x)\n", err);
	}
    }
    while (false);
    if (cmd)
	cmd->release();
    // end 32 bit loop

    return (err);
}
Пример #2
0
IOReturn
IOUSBController::CheckForDisjointDescriptor(IOUSBCommand *command, UInt16 maxPacketSize)
{
    IOMemoryDescriptor			*buf = command->GetBuffer();
    IOBufferMemoryDescriptor	*newBuf = NULL;
    IOByteCount					length = command->GetReqCount();
	IODMACommand				*dmaCommand = command->GetDMACommand();
    IOByteCount					segLength = 0;
    IOByteCount					offset = 0;
    IOReturn					err;
	UInt64						offset64;
	IODMACommand::Segment64		segment64;
	UInt32						numSegments;
	
	// USBTrace_Start( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this );
	
    // Zero length buffers are valid, but they are surely not disjoint, so just return success.  
    //
    if ( length == 0 )
        return kIOReturnSuccess;
	
	if (!dmaCommand)
	{
		USBLog(1, "%s[%p]::CheckForDisjointDescriptor - no dmaCommand", getName(), this);
		USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnBadArgument, 0, 1 );
		return kIOReturnBadArgument;
	}
	
	if (dmaCommand->getMemoryDescriptor() != buf)
	{
		USBLog(1, "%s[%p]::CheckForDisjointDescriptor - mismatched memory descriptor (%p) and dmaCommand memory descriptor (%p)", getName(), this, buf, dmaCommand->getMemoryDescriptor());
		USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, kIOReturnBadArgument, (uintptr_t)buf, (uintptr_t)dmaCommand->getMemoryDescriptor(), 2 );
		return kIOReturnBadArgument;
	}
	
    while (length)
    {
		offset64 = offset;
		numSegments = 1;
		
		err = dmaCommand->gen64IOVMSegments(&offset64, &segment64, &numSegments);
        if (err || (numSegments != 1))
        {
            USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err (%p) trying to generate segments at offset (%qd), length (%d), segLength (%d), total length (%d), buf (%p), numSegments (%d)", getName(), this, (void*)err, offset64, (int)length, (int)segLength, (int)command->GetReqCount(), buf, (int)numSegments);
			USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, offset64, length, segLength, 3 );
			USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, segLength, command->GetReqCount(), numSegments, 4 );
            return kIOReturnBadArgument;
        }

		
		// 3036056 since length might be less than the length of the descriptor, we are OK if the physical
		// segment is longer than we need
        if (segment64.fLength >= length)
            return kIOReturnSuccess;		// this is the last segment, so we are OK
		
		// since length is a 32 bit quantity, then we know from the above statement that if we are here we are 32 bit only
		segLength = (IOByteCount)segment64.fLength;

        // so the segment is less than the rest of the length - we need to check against maxPacketSize
        if (segLength % maxPacketSize)
        {
            // this is the error case. I need to copy the descriptor to a new descriptor and remember that I did it
            USBLog(6, "%s[%p]::CheckForDisjointDescriptor - found a disjoint segment of length (%d) MPS (%d)", getName(), this, (int)segLength, maxPacketSize);
			length = command->GetReqCount();		// we will not return to the while loop, so don't worry about changing the value of length
													// allocate a new descriptor which is the same total length as the old one
			newBuf = IOBufferMemoryDescriptor::withOptions((command->GetDirection() == kUSBIn) ? kIODirectionIn : kIODirectionOut, length);
			if (!newBuf)
			{
				USBLog(1, "%s[%p]::CheckForDisjointDescriptor - could not allocate new buffer", getName(), this);
				USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnNoMemory, 0, 5 );
				return kIOReturnNoMemory;
			}
			USBLog(7, "%s[%p]::CheckForDisjointDescriptor, obtained buffer %p of length %d", getName(), this, newBuf, (int)length);
			
			// first close out (and complete) the original dma command descriptor
			USBLog(7, "%s[%p]::CheckForDisjointDescriptor, clearing memDec (%p) from dmaCommand (%p)", getName(), this, dmaCommand->getMemoryDescriptor(), dmaCommand);
			dmaCommand->clearMemoryDescriptor();
			
			// copy the bytes to the buffer if necessary
			if (command->GetDirection() == kUSBOut)
			{
				USBLog(7, "%s[%p]::CheckForDisjointDescriptor, copying %d bytes from desc %p to buffer %p", getName(), this, (int)length, buf, newBuf->getBytesNoCopy());
				if (buf->readBytes(0, newBuf->getBytesNoCopy(), length) != length)
				{
					USBLog(1, "%s[%p]::CheckForDisjointDescriptor - bad copy on a write", getName(), this);
					USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, 0, 0, 6 );
					newBuf->release();
					return kIOReturnNoMemory;
				}
			}
			err = newBuf->prepare();
			if (err)
			{
				USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err 0x%x in prepare", getName(), this, err);
				USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, err, 0, 7 );
				newBuf->release();
				return err;
			}
			err = dmaCommand->setMemoryDescriptor(newBuf);
			if (err)
			{
				USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err 0x%x in setMemoryDescriptor", getName(), this, err);
				USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, err, 0, 8 );
				newBuf->complete();
				newBuf->release();
				return err;
			}
			
			command->SetOrigBuffer(command->GetBuffer());
			command->SetDisjointCompletion(command->GetClientCompletion());
			USBLog(7, "%s[%p]::CheckForDisjointDescriptor - changing buffer from (%p) to (%p) and putting new buffer in dmaCommand (%p)", getName(), this, command->GetBuffer(), newBuf, dmaCommand);
			command->SetBuffer(newBuf);
			
			
			IOUSBCompletion completion;
			completion.target = this;
			completion.action = (IOUSBCompletionAction)DisjointCompletion;
			completion.parameter = command;
			command->SetClientCompletion(completion);
			
			command->SetDblBufLength(length);			// for the IOFree - the other buffer may change size
            return kIOReturnSuccess;
		}
        length -= segLength;		// adjust our master length pointer
		offset += segLength;
	}
	
	USBLog(5, "%s[%p]::CheckForDisjointDescriptor - returning kIOReturnBadArgument(0x%x)", getName(), this, kIOReturnBadArgument);
	// USBTrace_End( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnBadArgument);
	
    return kIOReturnBadArgument;
}