AppleEHCIitdMemoryBlock*
AppleEHCIitdMemoryBlock::NewMemoryBlock(void)
{
    AppleEHCIitdMemoryBlock 	*me = new AppleEHCIitdMemoryBlock;
    IOByteCount					len;
	IODMACommand				*dmaCommand = NULL;
	UInt64						offset = 0;
	IODMACommand::Segment32		segments;
	UInt32						numSegments = 1;
	IOReturn					status = kIOReturnSuccess;
    
    if (me)
	{
		// Use IODMACommand to get the physical address
		dmaCommand = IODMACommand::withSpecification(kIODMACommandOutputHost32, 32, PAGE_SIZE, (IODMACommand::MappingOptions)(IODMACommand::kMapped | IODMACommand::kIterateOnly));
		if (!dmaCommand)
		{
			USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not create IODMACommand");
			return NULL;
		}
		USBLog(6, "AppleEHCIitdMemoryBlock::NewMemoryBlock - got IODMACommand %p", dmaCommand);
		
		// allocate one page on a page boundary below the 4GB line
		me->_buffer = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, kIOMemoryUnshared | kIODirectionInOut, kEHCIPageSize, kEHCIStructureAllocationPhysicalMask);
		
		// allocate exactly one physical page
		if (me->_buffer) 
		{
			status = me->_buffer->prepare();
			if (status)
			{
				USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not prepare buffer");
				me->_buffer->release();
				me->_buffer = NULL;
				me->release();
				dmaCommand->release();
				return NULL;
			}
			me->_sharedLogical = (EHCIIsochTransferDescriptorSharedPtr)me->_buffer->getBytesNoCopy();
			bzero(me->_sharedLogical, kEHCIPageSize);
			status = dmaCommand->setMemoryDescriptor(me->_buffer);
			if (status)
			{
				USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not set memory descriptor");
				me->_buffer->complete();
				me->_buffer->release();
				me->_buffer = NULL;
				me->release();
				dmaCommand->release();
				return NULL;
			}
			status = dmaCommand->gen32IOVMSegments(&offset, &segments, &numSegments);
			dmaCommand->clearMemoryDescriptor();
			dmaCommand->release();
			if (status || (numSegments != 1) || (segments.fLength != kEHCIPageSize))
			{
				USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock - could not get physical segment");
				me->_buffer->complete();
				me->_buffer->release();
				me->_buffer = NULL;
				me->release();
				return NULL;
			}
			me->_sharedPhysical = segments.fIOVMAddr;
		}
		else
		{
			USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock, could not allocate buffer!");
			me->release();
			me = NULL;
		}
	}
	else
	{
		USBError(1, "AppleEHCIitdMemoryBlock::NewMemoryBlock, constructor failed!");
    }
    return me;
}
Example #2
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);
}