void pci_free_consistent(void *pdev, size_t size, void *vaddr, dma_addr_t dma_handle)
{
	// free a hw dma scatter/gather list located in host memory
	int                             index;
	OSArray                         *dma_info_array;
	IOBufferMemoryDescriptor        *memDesc;
	IOVirtualAddress                virt_address;

	// search for the correct dma_info by checking against passed virtual address
	dma_info_array = g_bcm_dma_info;
	for(index = 0; index < (int)dma_info_array->getCount(); index++) {
		memDesc = (IOBufferMemoryDescriptor*)dma_info_array->getObject(index);
		virt_address = (IOVirtualAddress)memDesc->getBytesNoCopy();
		if ((IOVirtualAddress)vaddr == virt_address) {
			//IOLog("pci_free_consistent padd(%p), size(0x%X)\n", dma_handle, size);
			// found it, now complete. removeObject will release it
			memDesc->complete();
			dma_info_array->removeObject(index);
			// should be able to just call memDesc->release() after memDesc->complete()
			// but on atv, there's something holding a ref to memDesc and so we leak memory
			// everytime the crystalhs driver closes. Doing the release this way fixes the mem
			// leak on atv and is fine under real 10.4/10.5 boxes.
			SAFE_RELEASE(memDesc);
			break;
		}
	}
}
void *pci_alloc_consistent(void *pdev, size_t size, dma_addr_t *dma_handle)
{
	IOBufferMemoryDescriptor    *memDesc;
	IOVirtualAddress            virt_address;
	IOPhysicalAddress           phys_address;

	// construct a memory descriptor for a buffer below the 4Gb line,
	// addressable by 32 bit DMA and page aligned.
	memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task,
		kIOMemoryPhysicallyContiguous, size, PAGE_SIZE);
	if (memDesc) {
		IOByteCount		offset = 0;
		IOByteCount		length;

		memDesc->prepare();
		virt_address = (IOVirtualAddress)memDesc->getBytesNoCopy();
		phys_address = memDesc->getPhysicalSegment(offset, &length);

		g_bcm_dma_info->setObject(memDesc);
	} else {
		virt_address = NULL;
		phys_address = NULL;
		IOLog("pci_alloc_consistent:IOBufferMemoryDescriptor::inTaskWithOptions failed\n");
	}

	//IOLog("pci_alloc_consistent paddr(0x%X), size(0x%X)\n", (unsigned int)phys_address, size);
	*dma_handle = phys_address;
	return (void*)virt_address;
}
IOReturn XboxOneControllerClass::handleReport(IOMemoryDescriptor * descriptor, IOHIDReportType reportType, IOOptionBits options)
{
    if (descriptor->getLength() >= sizeof(XBOXONE_IN_GUIDE_REPORT)) {
        IOBufferMemoryDescriptor *desc = OSDynamicCast(IOBufferMemoryDescriptor, descriptor);
        if (desc != NULL) {
            XBOXONE_ELITE_IN_REPORT *report=(XBOXONE_ELITE_IN_REPORT*)desc->getBytesNoCopy();
            if ((report->header.command==0x07) && (report->header.size==(sizeof(XBOXONE_IN_GUIDE_REPORT)-4)))
            {
                XBOXONE_IN_GUIDE_REPORT *guideReport=(XBOXONE_IN_GUIDE_REPORT*)report;
                isXboxOneGuideButtonPressed = (bool)guideReport->state;
                XBOX360_IN_REPORT *oldReport = (XBOX360_IN_REPORT*)lastData;
                oldReport->buttons ^= (-isXboxOneGuideButtonPressed ^ oldReport->buttons) & (1 << GetOwner(this)->mapping[10]);
                memcpy(report, lastData, sizeof(XBOX360_IN_REPORT));
            }
            else if (report->header.command==0x20)
            {
                if (report->header.size==0x0e || report->header.size==0x1d || report->header.size==0x1a)
                {
                    convertFromXboxOne(report, report->header.size);
                    XBOX360_IN_REPORT *report360=(XBOX360_IN_REPORT*)report;
                    if (!(GetOwner(this)->noMapping))
                        remapButtons(report360);
                    GetOwner(this)->fiddleReport(report360->left, report360->right);

                    if (GetOwner(this)->swapSticks)
                        remapAxes(report360);

                    memcpy(lastData, report360, sizeof(XBOX360_IN_REPORT));
                }
            }
        }
    }
    IOReturn ret = IOHIDDevice::handleReport(descriptor, reportType, options);
    return ret;
}
// Queue an asynchronous write on a controller
bool WirelessGamingReceiver::QueueWrite(int index, const void *bytes, UInt32 length)
{
    IOBufferMemoryDescriptor *outBuffer;
    IOUSBCompletion complete;
    IOReturn err;
    
    outBuffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, length);
    if (outBuffer == NULL)
    {
//        IOLog("send - unable to allocate buffer\n");
        return false;
    }
    outBuffer->writeBytes(0, bytes, length);
    
    complete.target = this;
    complete.action = _WriteComplete;
    complete.parameter = outBuffer;
    
    err = connections[index].controllerOut->Write(outBuffer, 0, 0, length, &complete);
    if (err == kIOReturnSuccess)
        return true;
    else
    {
//        IOLog("send - failed to start (0x%.8x)\n",err);
        return false;
    }
}
// Returns the HID descriptor for this device
IOReturn Xbox360ControllerClass::newReportDescriptor(IOMemoryDescriptor **descriptor) const
{
    IOBufferMemoryDescriptor *buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task,0,sizeof(HID_360::ReportDescriptor));

    if (buffer == NULL) return kIOReturnNoResources;
    buffer->writeBytes(0,HID_360::ReportDescriptor,sizeof(HID_360::ReportDescriptor));
    *descriptor=buffer;
    return kIOReturnSuccess;
}
Exemple #6
0
void * IOMallocContiguous(vm_size_t size, vm_size_t alignment,
			   IOPhysicalAddress * physicalAddress)
{
    mach_vm_address_t	address = 0;

    if (size == 0)
	return 0;
    if (alignment == 0) 
	alignment = 1;

    /* Do we want a physical address? */
    if (!physicalAddress)
    {
	address = IOKernelAllocateWithPhysicalRestrict(size, 0 /*maxPhys*/, alignment, true);
    }
    else do
    {
	IOBufferMemoryDescriptor * bmd;
	mach_vm_address_t          physicalMask;
	vm_offset_t		   alignMask;

	alignMask = alignment - 1;
	physicalMask = (0xFFFFFFFF ^ alignMask);

	bmd = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
		kernel_task, kIOMemoryPhysicallyContiguous, size, physicalMask);
	if (!bmd)
	    break;
	
	_IOMallocContiguousEntry *
	entry = IONew(_IOMallocContiguousEntry, 1);
	if (!entry)
	{
	    bmd->release();
	    break;
	}
	entry->virtualAddr = (mach_vm_address_t) bmd->getBytesNoCopy();
	entry->md          = bmd;
	lck_mtx_lock(gIOMallocContiguousEntriesLock);
	queue_enter( &gIOMallocContiguousEntries, entry, 
		    _IOMallocContiguousEntry *, link );
	lck_mtx_unlock(gIOMallocContiguousEntriesLock);

	address          = (mach_vm_address_t) entry->virtualAddr;
	*physicalAddress = bmd->getPhysicalAddress();
    }
    while (false);

	if (address) {
	    IOStatisticsAlloc(kIOStatisticsMallocContiguous, size);
    }

    return (void *) address;
}
IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::withOptions(
                                            IOOptionBits options,
                                            vm_size_t    capacity,
                                            vm_offset_t  alignment)
{
    IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
    
    if (me && !me->initWithPhysicalMask(kernel_task, options, capacity, alignment, 0)) {
	me->release();
	me = 0;
    }
    return me;
}
/*
 * withBytes:
 *
 * Returns a new IOBufferMemoryDescriptor preloaded with bytes (copied).
 * The descriptor's length and capacity are set to the input buffer's size.
 */
IOBufferMemoryDescriptor *
IOBufferMemoryDescriptor::withBytes(const void * inBytes,
                                    vm_size_t    inLength,
                                    IODirection  inDirection,
                                    bool         inContiguous)
{
    IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;

    if (me && !me->initWithBytes(inBytes, inLength, inDirection, inContiguous)) {
        me->release();
        me = 0;
    }
    return me;
}
IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::inTaskWithOptions(
    task_t       inTask,
    IOOptionBits options,
    vm_size_t    capacity,
    vm_offset_t  alignment)
{
    IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;

    if (me && !me->initWithOptions(options, capacity, alignment, inTask)) {
        me->release();
        me = 0;
    }
    return me;
}
IOReturn Xbox360ControllerClass::handleReport(IOMemoryDescriptor * descriptor, IOHIDReportType reportType, IOOptionBits options) {
    if (descriptor->getLength() >= sizeof(XBOX360_IN_REPORT)) {
        IOBufferMemoryDescriptor *desc = OSDynamicCast(IOBufferMemoryDescriptor, descriptor);
        if (desc != NULL) {
            XBOX360_IN_REPORT *report=(XBOX360_IN_REPORT*)desc->getBytesNoCopy();
            if ((report->header.command==inReport) && (report->header.size==sizeof(XBOX360_IN_REPORT))) {
                GetOwner(this)->fiddleReport(desc);
                remapButtons(report);
            }
        }
    }
    IOReturn ret = IOHIDDevice::handleReport(descriptor, reportType, options);
    return ret;
}
Exemple #11
0
IOReturn it_unbit_foohid_device::newReportDescriptor(IOMemoryDescriptor **descriptor) const {
    IOLog("it_unbit_foohid_device::newReportDescriptor()\n");
    IOBufferMemoryDescriptor *buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, reportDescriptor_len);
    if (buffer == NULL) {
        IOLog("OOOOPS");
        return kIOReturnNoResources;
    }
    
    buffer->writeBytes(0, reportDescriptor, reportDescriptor_len);
    *descriptor = buffer;
    
    IOLog("all fine\n");
    
    return kIOReturnSuccess;
}
IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
					    task_t	      inTask,
                                            IOOptionBits      options,
                                            mach_vm_size_t    capacity,
                                            mach_vm_address_t physicalMask)
{
    IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;
    
    if (me && !me->initWithPhysicalMask(inTask, options, capacity, 1, physicalMask))
    {
	me->release();
	me = 0;
    }
    return me;
}
Exemple #13
0
IOBufferMemoryDescriptor* MemoryDmaAlloc(UInt32 buf_size, dma_addr_t *phys_add, void *virt_add)
{
	IOBufferMemoryDescriptor *memBuffer;
	void *virt_address;
	dma_addr_t phys_address;
	IOMemoryMap *memMap;
	
	memBuffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task,
						kIODirectionOutIn | kIOMemoryPhysicallyContiguous | \
						kIOMemoryAutoPrepare | kIOMapInhibitCache, buf_size, \
						PAGE_SIZE);

	if (memBuffer == NULL) {
		//IOLog("Memory Allocation failed - RLC");

		return NULL;
	}

	memMap = memBuffer->map();

	if (memMap == NULL) {
		//IOLog("mapping failed\n");
		memBuffer->release();
		memBuffer = NULL;
		
		return NULL;	
	}

	phys_address = memMap->getPhysicalAddress();

	virt_address = (void *)memMap->getVirtualAddress();

	if (virt_address == NULL || phys_address == NULL) {
		memMap->release();
		memBuffer->release();
		memBuffer = NULL;
		
		return NULL;
	}

	*phys_add = phys_address;
	*(IOVirtualAddress*)virt_add = (IOVirtualAddress)virt_address;
	memMap->release();

	return memBuffer;
}
Exemple #14
0
/* read the <partition#> sector on the root address for label and size */
void net_habitue_device_SC101::partitionCompletion(void *parameter, IOReturn status, UInt64 actualByteCount)
{
  if (status != kIOReturnSuccess || actualByteCount != sizeof(psan_get_response_partition_t))
  {
    KINFO("partition lookup on %s failed", getID()->getCStringNoCopy());
    return;
  }
  
  IOBufferMemoryDescriptor *buffer = (IOBufferMemoryDescriptor *)parameter;
  
  psan_get_response_partition_t *part = (psan_get_response_partition_t *)buffer->getBytesNoCopy();
  OSString *id = getID();

  for (UInt32 i = 0; i < actualByteCount / sizeof(psan_get_response_partition_t); i++, part++)
  {
    KDEBUG("cmp %s", part->id);
    
    if (strncmp(part->id, id->getCStringNoCopy(), id->getLength() + 1) != 0)
      continue;
    
    KDEBUG("Matched!");
    
    OSString *label = OSString::withCString(part->label);
    if (label)
    {
      setProperty(gSC101DeviceLabelKey, label);
      label->release();
    }
    
    OSNumber *size = OSNumber::withNumber(getUInt48(part->sector_size) << 9, 64);
    if (size)
    {
      setProperty(gSC101DeviceSizeKey, size);
      size->release();
    }
 
    if (1) // TODO(iwade) determine minimum fields needed
    {
      _mediaStateAttached = true;
      _mediaStateChanged = true;
    }

    break;
  }
}
void VoodooI2CHIDDevice::i2c_hid_get_input(OSObject* owner, IOTimerEventSource* sender) {
//    IOLog("getting input\n");
    if (hid_device->reading)
        return;

    UInt rsize;
    int ret;

    rsize = UInt16(ihid->hdesc.wMaxInputLength);
    
    unsigned char* rdesc = (unsigned char *)IOMalloc(rsize);
    
    ret = i2c_hid_command(ihid, &hid_input_cmd, rdesc, rsize);

//    IOLog("===Input (%d)===\n", rsize);
//    for (int i = 0; i < rsize; i++)
//        IOLog("0x%02x ", (UInt8) rdesc[i]);
//    IOLog("\n");

    int return_size = rdesc[0] | rdesc[1] << 8;
    if (return_size == 0) {
        /* host or device initiated RESET completed */
        // test/clear bit?
        hid_device->timerSource->setTimeoutMS(10);
        return;
    }

    if (return_size > rsize) {
        IOLog("%s: Incomplete report %d/%d\n", __func__, rsize, return_size);
    }

    IOBufferMemoryDescriptor *buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, return_size);
    buffer->writeBytes(0, rdesc + 2, return_size - 2);

    IOReturn err = _wrapper->handleReport(buffer, kIOHIDReportTypeInput);
    if (err != kIOReturnSuccess)
        IOLog("Error handling report: 0x%.8x\n", err);

    buffer->release();

    IOFree(rdesc, rsize);
    
    hid_device->timerSource->setTimeoutMS(10);
}
IOBufferMemoryDescriptor *kXAudioEngine::my_alloc_contiguous(mach_vm_size_t size, void **addr, dword *phys)
{
    if(size<PAGE_SIZE)
		size=PAGE_SIZE;
    
#ifdef DEBUGGING
    size += 2 * PAGE_SIZE;
#endif	
		//void *addr=IOMallocContiguous(size+PAGE_SIZE+PAGE_SIZE,alignment,phys);	
    
    mach_vm_address_t mask = 0x000000007FFFFFFFULL & ~(PAGE_SIZE - 1);
    
    IOBufferMemoryDescriptor *desc =
    IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
													 kernel_task,
													 kIODirectionInOut | kIOMemoryPhysicallyContiguous,
													 size,
													 mask);
    
    if(desc)
    {
		desc->prepare();
		
		IOPhysicalAddress pa = desc->getPhysicalAddress();
		
		if (pa & ~mask)
			debug("kXAudioEngine[%p]::my_alloc_contiguous() - memory misaligned or beyond 2GB limit (%p)\n", this, (void *)pa);
		
		*phys = (dword)pa;
		*addr = desc->getBytesNoCopy();
		
#ifdef DEBUGGING
		memset(addr,0x11,PAGE_SIZE);
		memset((UInt8 *)addr+PAGE_SIZE+size,0x22,PAGE_SIZE);
		
		*((UInt8 *)addr) += PAGE_SIZE;
		*phys += PAGE_SIZE;
#endif
    }
    else
		debug("kXAudioEngine[%p]::my_alloc_contiguous() - allocation failed\n",this);
    
    return desc;
}
IOReturn org_litio_OzoneStrikeBattle::newReportDescriptor(IOMemoryDescriptor** descriptor) const {
    // TODO: Define new device descriptor struct for the keyboard.
    // Assigning current descriptor.
    IOLog("OzoneStrike::%s[%p] - Setting HID report descriptor.\n", getName(), this);
    OSData *reportDescriptor = OSData::withBytes(Ozone::HIDReportDescriptor, sizeof(Ozone::HIDReportDescriptor));
    OSData *reportDescriptorNew = OSDynamicCast(OSData, getProperty("ReportDescriptorOverride"));
    
    if (reportDescriptor == NULL) {
        IOLog("OzoneStrike::%s[%p] - reportDescriptor OSData not set.\n", getName(), this);
        return kIOReturnNoResources;
    }
    
    printBytes(reportDescriptorNew);
    printBytes(reportDescriptor);
    
    IOLog("OzoneStrike::%s[%p] - reportDescriptor OSData set (size: %d, data: %s).\n", getName(), this, reportDescriptor->getLength(), reportDescriptor->getBytesNoCopy());

    //OSData *reportDescriptor = OSDynamicCast(OSData, Ozone::HIDReportDescriptor);
    IOBufferMemoryDescriptor *bufferDescriptor = IOBufferMemoryDescriptor::withBytes(reportDescriptor->getBytesNoCopy(),
                                                                               reportDescriptor->getLength(),
                                                                               kIODirectionOutIn);
    //IOBufferMemoryDescriptor *bufferDescriptor = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task,
     //                                                                                        0,
     //                                                                                        sizeof(Ozone::HIDReportDescriptor));
/*
    if (bufferDescriptor == NULL) {
        return kIOReturnNoResources;
    }

    bufferDescriptor->writeBytes(0, Ozone::HIDReportDescriptor,sizeof(Ozone::HIDReportDescriptor));
*/
    if (bufferDescriptor) {
        *descriptor = bufferDescriptor;
        return kIOReturnSuccess;
    } else {
        bufferDescriptor->release();
        *descriptor = NULL;
        return kIOReturnNoMemory;
    }

    //return IOUSBHostHIDDevice::newReportDescriptor(descriptor);
}
Exemple #18
0
void net_habitue_device_SC101::diskCompletion(void *parameter, IOReturn status, UInt64 actualByteCount)
{
  if (status != kIOReturnSuccess || actualByteCount != sizeof(psan_get_response_disk_t))
  {
    KINFO("disk query on %s failed", getID()->getCStringNoCopy());
    return;
  }
  
  IOBufferMemoryDescriptor *buffer = (IOBufferMemoryDescriptor *)parameter;
  
  psan_get_response_disk_t *disk = (psan_get_response_disk_t *)buffer->getBytesNoCopy();
  
  OSData *partNumber = OSData::withBytes(disk->part_number, sizeof(disk->part_number));
  if (partNumber)
  {
    OSString *resourceFile = NULL;

    if (partNumber->isEqualTo(kSC101PartNumber, sizeof(kSC101PartNumber)))
      resourceFile = OSString::withCString("SC101.icns");
    else if (partNumber->isEqualTo(kSC101TPartNumber, sizeof(kSC101TPartNumber)))
      resourceFile = OSString::withCString("SC101T.icns");
    
    if (resourceFile)
    {
      setIcon(resourceFile);
      resourceFile->release();
    }
    
    setProperty(gSC101DevicePartNumberKey, partNumber);    
    partNumber->release();
  }
  
  OSString *version = OSString::withCString(disk->version);
  if (version)
  {
    setProperty(gSC101DeviceVersionKey, version);
    version->release();
  }
  
  partition(disk->partitions);
}
/*
 * withBytes:
 *
 * Returns a new IOBufferMemoryDescriptor preloaded with bytes (copied).
 * The descriptor's length and capacity are set to the input buffer's size.
 */
IOBufferMemoryDescriptor *
IOBufferMemoryDescriptor::withBytes(const void * inBytes,
                                    vm_size_t    inLength,
                                    IODirection  inDirection,
                                    bool         inContiguous)
{
    IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor;

    if (me && !me->initWithPhysicalMask(
               kernel_task, inDirection | kIOMemoryUnshared
                | (inContiguous ? kIOMemoryPhysicallyContiguous : 0),
               inLength, inLength, 0 ))
    {
	me->release();
	me = 0;
    }

    if (me)
    {
	// start out with no data
	me->setLength(0);

	if (!me->appendBytes(inBytes, inLength))
	{
	    me->release();
	    me = 0;
	}
    }
    return me;
}
Exemple #20
0
IOReturn com_veltrop_taylor_driver_virtualhid::newReportDescriptor(IOMemoryDescriptor ** desc) const
{
	//	IOLog("newReportDescriptor\n");

	IOBufferMemoryDescriptor * bufferDesc = NULL;
	UInt32 inOutSize = myReportDescSize;
	
	bufferDesc = IOBufferMemoryDescriptor::withCapacity(inOutSize, kIODirectionOutIn);
	
	if (bufferDesc) {
		UInt8* buff = (UInt8*)(bufferDesc->getBytesNoCopy());
		memcpy(buff, myHIDReportDescriptor, inOutSize);
	} 
	else
		return kIOReturnError;

	*desc = bufferDesc;
	
	// Note: I do not need to free bufferDesc, the caller will!

	return kIOReturnSuccess;
}
// Set up an asynchronous write
bool Xbox360Peripheral::QueueWrite(const void *bytes,UInt32 length)
{
    IOBufferMemoryDescriptor *outBuffer;
    IOUSBCompletion complete;
    IOReturn err;
    
    outBuffer=IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task,0,length);
    if(outBuffer==NULL) {
        IOLog("send - unable to allocate buffer\n");
        return false;
    }
    outBuffer->writeBytes(0,bytes,length);
    complete.target=this;
    complete.action=WriteCompleteInternal;
    complete.parameter=outBuffer;
    err=outPipe->Write(outBuffer,0,0,length,&complete);
    if(err==kIOReturnSuccess) return true;
    else {
        IOLog("send - failed to start (0x%.8x)\n",err);
        return false;
    }
}
IOReturn IOUSBHIDDriverDescriptorOverride::newReportDescriptor(IOMemoryDescriptor **desc) const {
	
	OSData *reportDescriptor = OSDynamicCast(OSData, getProperty(REPORT_DESCRIPTOR_OVERRIDE_KEY));
	
	if(reportDescriptor) {		
		IOBufferMemoryDescriptor *bufferDesc = IOBufferMemoryDescriptor::withBytes(reportDescriptor->getBytesNoCopy(),
																				   reportDescriptor->getLength(),
																				   kIODirectionOutIn);
		if(bufferDesc) {
			*desc = bufferDesc;
			return kIOReturnSuccess;
		} else {
			bufferDesc->release();
			*desc = NULL;
			return kIOReturnNoMemory;
		}
	} else {
		//IOLog("IOUSBHIDDriverDescriptorOverride(%s)[%p]::newReportDescriptor - "
		//	  "No %s data in personality, calling IOUSBHIDDriver::newReportDescriptor\n",
		//	  getName(), this, REPORT_DESCRIPTOR_OVERRIDE_KEY);
		return IOUSBHIDDriver::newReportDescriptor(desc);
	}
}
OSSet * IOFDiskPartitionScheme::scan(SInt32 * score)
{
    //
    // Scan the provider media for an FDisk partition map.  Returns the set
    // of media objects representing each of the partitions (the retain for
    // the set is passed to the caller), or null should no partition map be
    // found.  The default probe score can be adjusted up or down, based on
    // the confidence of the scan.
    //

    IOBufferMemoryDescriptor * buffer         = 0;
    UInt32                     bufferSize     = 0;
    UInt32                     fdiskBlock     = 0;
    UInt32                     fdiskBlockExtn = 0;
    UInt32                     fdiskBlockNext = 0;
    UInt32                     fdiskID        = 0;
    disk_blk0 *                fdiskMap       = 0;
    IOMedia *                  media          = getProvider();
    UInt64                     mediaBlockSize = media->getPreferredBlockSize();
    bool                       mediaIsOpen    = false;
    OSSet *                    partitions     = 0;
    IOReturn                   status         = kIOReturnError;

    // Determine whether this media is formatted.

    if ( media->isFormatted() == false )  goto scanErr;

    // Determine whether this media has an appropriate block size.

    if ( (mediaBlockSize % sizeof(disk_blk0)) )  goto scanErr;

    // Allocate a buffer large enough to hold one map, rounded to a media block.

    bufferSize = IORound(sizeof(disk_blk0), mediaBlockSize);
    buffer     = IOBufferMemoryDescriptor::withCapacity(
                                           /* capacity      */ bufferSize,
                                           /* withDirection */ kIODirectionIn );
    if ( buffer == 0 )  goto scanErr;

    // Allocate a set to hold the set of media objects representing partitions.

    partitions = OSSet::withCapacity(4);
    if ( partitions == 0 )  goto scanErr;

    // Open the media with read access.

    mediaIsOpen = open(this, 0, kIOStorageAccessReader);
    if ( mediaIsOpen == false )  goto scanErr;

    // Scan the media for FDisk partition map(s).

    do
    {
        // Read the next FDisk map into our buffer.

        status = media->read(this, fdiskBlock * mediaBlockSize, buffer);
        if ( status != kIOReturnSuccess )  goto scanErr;

        fdiskMap = (disk_blk0 *) buffer->getBytesNoCopy();

        // Determine whether the partition map signature is present.

        if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
        {
            goto scanErr;
        }

        // Scan for valid partition entries in the partition map.

        fdiskBlockNext = 0;

        for ( unsigned index = 0; index < DISK_NPART; index++ )
        {
            // Determine whether this is an extended (vs. data) partition.

            if ( isPartitionExtended(fdiskMap->parts + index) )    // (extended)
            {
                // If peer extended partitions exist, we accept only the first.

                if ( fdiskBlockNext == 0 )      // (no peer extended partition)
                {
                    fdiskBlockNext = fdiskBlockExtn +
                                     OSSwapLittleToHostInt32(
                                    /* data */ fdiskMap->parts[index].relsect );

                    if ( fdiskBlockNext * mediaBlockSize >= media->getSize() )
                    {
                        fdiskBlockNext = 0;       // (exceeds confines of media)
                    }
                }
            }
            else if ( isPartitionUsed(fdiskMap->parts + index) )       // (data)
            {
                // Prepare this partition's ID.

                fdiskID = ( fdiskBlock == 0 ) ? (index + 1) : (fdiskID + 1);

                // Determine whether the partition is corrupt (fatal).

                if ( isPartitionCorrupt(
                                   /* partition   */ fdiskMap->parts + index,
                                   /* partitionID */ fdiskID,
                                   /* fdiskBlock  */ fdiskBlock ) )
                {
                    goto scanErr;
                }

                // Determine whether the partition is invalid (skipped).

                if ( isPartitionInvalid(
                                   /* partition   */ fdiskMap->parts + index,
                                   /* partitionID */ fdiskID,
                                   /* fdiskBlock  */ fdiskBlock ) )
                {
                    continue;
                }

                // Create a media object to represent this partition.

                IOMedia * newMedia = instantiateMediaObject(
                                   /* partition   */ fdiskMap->parts + index,
                                   /* partitionID */ fdiskID,
                                   /* fdiskBlock  */ fdiskBlock );

                if ( newMedia )
                {
                    partitions->setObject(newMedia);
                    newMedia->release();
                }
            }
        }

        // Prepare for first extended partition, if any.

        if ( fdiskBlock == 0 )
        {
            fdiskID        = DISK_NPART;
            fdiskBlockExtn = fdiskBlockNext;
        }

    } while ( (fdiskBlock = fdiskBlockNext) );

    // Release our resources.

    close(this);
    buffer->release();

    return partitions;

scanErr:

    // Release our resources.

    if ( mediaIsOpen )  close(this);
    if ( partitions )  partitions->release();
    if ( buffer )  buffer->release();

    return 0;
}
Exemple #24
0
int HoRNDIS::rndisCommand(struct rndis_msg_hdr *buf, int buflen) {
	int count;
	int rc = kIOReturnSuccess;
	IOUSBDevRequestDesc rq;
	IOBufferMemoryDescriptor *txdsc = IOBufferMemoryDescriptor::withCapacity(le32_to_cpu(buf->msg_len), kIODirectionOut);
	IOBufferMemoryDescriptor *rxdsc = IOBufferMemoryDescriptor::withCapacity(RNDIS_CMD_BUF_SZ, kIODirectionIn);

	if (buf->msg_type != RNDIS_MSG_HALT && buf->msg_type != RNDIS_MSG_RESET) {
		/* lock? */
		buf->request_id = cpu_to_le32(xid++);
		if (!buf->request_id)
			buf->request_id = cpu_to_le32(xid++);
	}
		
	memcpy(txdsc->getBytesNoCopy(), buf, le32_to_cpu(buf->msg_len));
	rq.bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
	rq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface);
	rq.wValue = 0;
	rq.wIndex = fCommInterface->GetInterfaceNumber();
	rq.pData = txdsc;
	rq.wLength = cpu_to_le32(buf->msg_len);
		
	if ((rc = fCommInterface->DeviceRequest(&rq)) != kIOReturnSuccess)
		goto bailout;
	
	/* Linux polls on the status channel, too; hopefully this shouldn't be needed if we're just talking to Android. */
	
	/* Now we wait around a while for the device to get back to us. */
	for (count = 0; count < 10; count++) {
		struct rndis_msg_hdr *inbuf = (struct rndis_msg_hdr *) rxdsc->getBytesNoCopy();
		IOUSBDevRequestDesc rxrq;
		
		memset(inbuf, 0, RNDIS_CMD_BUF_SZ);
		rxrq.bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
		rxrq.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface);
		rxrq.wValue = 0;
		rxrq.wIndex = fCommInterface->GetInterfaceNumber();
		rxrq.pData = rxdsc;
		rxrq.wLength = RNDIS_CMD_BUF_SZ;
				
		if ((rc = fCommInterface->DeviceRequest(&rxrq)) != kIOReturnSuccess)
			goto bailout;
		
		if (rxrq.wLenDone < 8) {
			LOG(V_ERROR, "short read on control request?");
			IOSleep(20);
			continue;
		}
		
		if (inbuf->msg_type == (buf->msg_type | RNDIS_MSG_COMPLETION)) {
			if (inbuf->request_id == buf->request_id) {
				if (inbuf->msg_type == RNDIS_MSG_RESET_C)
					break;
				if (inbuf->status == RNDIS_STATUS_SUCCESS) {
					/* ...and copy it out! */
					LOG(V_DEBUG, "RNDIS command completed");
					memcpy(buf, inbuf, le32_to_cpu(rxrq.wLenDone));
					break;
				}
				LOG(V_ERROR, "RNDIS command returned status %08x", inbuf->status);
				rc = -1;
				break;
			} else {
				LOG(V_ERROR, "RNDIS return had incorrect xid?");
			}
		} else {
			switch (inbuf->msg_type) {
				case RNDIS_MSG_INDICATE:
					LOG(V_ERROR, "unsupported: RNDIS_MSG_INDICATE");
					break;
				case RNDIS_MSG_KEEPALIVE:
					LOG(V_ERROR, "unsupported: RNDIS_MSG_KEEPALIVE");
					break;
				default:
					LOG(V_ERROR, "unexpected msg type %08x, msg_len %08x", inbuf->msg_type, inbuf->msg_len);
					break;
			}
		}
		
		IOSleep(20);
	}
	if (count == 10) {
		LOG(V_ERROR, "command timed out?");
		rc = kIOReturnTimeout;
	}
	
bailout:
	txdsc->complete();
	txdsc->release();
	rxdsc->complete();
	rxdsc->release();
	
	return rc;
}
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;
}
IOReturn
AppleFileSystemDriver::readHFSUUID(IOMedia *media, void **uuidPtr)
{
    bool                       mediaIsOpen    = false;
    UInt64                     mediaBlockSize = 0;
    IOBufferMemoryDescriptor * buffer         = 0;
    uint8_t *                  bytes          = 0;
    UInt64                     bytesAt        = 0;
    UInt64                     bufferReadAt   = 0;
    vm_size_t                  bufferSize     = 0;
    IOReturn                   status         = kIOReturnError;
    HFSMasterDirectoryBlock *  mdbPtr         = 0;
    HFSPlusVolumeHeader *      volHdrPtr      = 0;
    VolumeUUID *               volumeUUIDPtr  = (VolumeUUID *)uuidPtr;


    DEBUG_LOG("%s::%s\n", kClassName, __func__);
	
    do {
		
        mediaBlockSize = media->getPreferredBlockSize();
		
        bufferSize = IORound(sizeof(HFSMasterDirectoryBlock), mediaBlockSize);
        buffer     = IOBufferMemoryDescriptor::withCapacity(bufferSize, kIODirectionIn);
        if ( buffer == 0 ) break;
		
        bytes = (uint8_t *) buffer->getBytesNoCopy();
		
        // Open the media with read access.
		
        mediaIsOpen = media->open(media, 0, kIOStorageAccessReader);
        if ( mediaIsOpen == false ) break;
		
        bytesAt = 2 * kHFSBlockSize;
        bufferReadAt = IOTrunc( bytesAt, mediaBlockSize );
        bytesAt -= bufferReadAt;

        mdbPtr = (HFSMasterDirectoryBlock *)&bytes[bytesAt];
        volHdrPtr = (HFSPlusVolumeHeader *)&bytes[bytesAt];
		
        status = media->read(media, bufferReadAt, buffer);
        if ( status != kIOReturnSuccess )  break;
		
        /*
         * If this is a wrapped HFS Plus volume, read the Volume Header from
         * sector 2 of the embedded volume.
         */
        if ( OSSwapBigToHostInt16(mdbPtr->drSigWord) == kHFSSigWord &&
             OSSwapBigToHostInt16(mdbPtr->drEmbedSigWord) == kHFSPlusSigWord) {
			
            u_int32_t   allocationBlockSize, firstAllocationBlock, startBlock, blockCount;
			
            if (OSSwapBigToHostInt16(mdbPtr->drSigWord) != kHFSSigWord) {
                break;
            }
			
            allocationBlockSize = OSSwapBigToHostInt32(mdbPtr->drAlBlkSiz);
            firstAllocationBlock = OSSwapBigToHostInt16(mdbPtr->drAlBlSt);
			
            if (OSSwapBigToHostInt16(mdbPtr->drEmbedSigWord) != kHFSPlusSigWord) {
                break;
            }
			
            startBlock = OSSwapBigToHostInt16(mdbPtr->drEmbedExtent.startBlock);
            blockCount = OSSwapBigToHostInt16(mdbPtr->drEmbedExtent.blockCount);
			
            bytesAt = ((u_int64_t)startBlock * (u_int64_t)allocationBlockSize) +
                ((u_int64_t)firstAllocationBlock * (u_int64_t)kHFSBlockSize) +
                (u_int64_t)(2 * kHFSBlockSize);
			
            bufferReadAt = IOTrunc( bytesAt, mediaBlockSize );
            bytesAt -= bufferReadAt;

            mdbPtr = (HFSMasterDirectoryBlock *)&bytes[bytesAt];
            volHdrPtr = (HFSPlusVolumeHeader *)&bytes[bytesAt];

            status = media->read(media, bufferReadAt, buffer);
            if ( status != kIOReturnSuccess )  break;
        }
		
        /*
         * At this point, we have the MDB for plain HFS, or VHB for HFS Plus and HFSX
         * volumes (including wrapped HFS Plus).  Verify the signature and grab the
         * UUID from the Finder Info.
         */
        if (OSSwapBigToHostInt16(mdbPtr->drSigWord) == kHFSSigWord) {
            bcopy((void *)&mdbPtr->drFndrInfo[6], volumeUUIDPtr->bytes, kVolumeUUIDValueLength);
            status = kIOReturnSuccess;
			
        } else if (OSSwapBigToHostInt16(volHdrPtr->signature) == kHFSPlusSigWord ||
                   OSSwapBigToHostInt16(volHdrPtr->signature) == kHFSXSigWord) {
            bcopy((void *)&volHdrPtr->finderInfo[24], volumeUUIDPtr->bytes, kVolumeUUIDValueLength);
            status = kIOReturnSuccess;
        } else {
	    // status = 0 from earlier successful media->read()
	    status = kIOReturnBadMedia;
	}

    } while (false);
	
    if ( mediaIsOpen )  media->close(media);
    if ( buffer )  buffer->release();

    DEBUG_LOG("%s::%s finishes with status %d\n", kClassName, __func__, status);

    return status;
}
Exemple #27
0
IOReturn
IOCDBlockStorageDriver::cacheTocInfo(void)
{
    IOBufferMemoryDescriptor *buffer;
    IOReturn result;
    CDTOC *toc;
    UInt16 tocSize;

    assert(sizeof(CDTOC) == 4);		/* (compiler/platform check) */
    assert(sizeof(CDTOCDescriptor) == 11);		/* (compiler/platform check) */

    assert(_toc == NULL);

    /* Read the TOC header: */

    buffer = IOBufferMemoryDescriptor::withCapacity(sizeof(CDTOC),kIODirectionIn);
    if (buffer == NULL) {
        return(kIOReturnNoMemory);
    }

    result = getProvider()->readTOC(buffer);
    if (result != kIOReturnSuccess) {
        buffer->release();
        return(result);
    }

    toc = (CDTOC *) buffer->getBytesNoCopy();
    tocSize = OSSwapBigToHostInt16(toc->length) + sizeof(toc->length);

    buffer->release();

    /* Reject the TOC if its size is too small: */

    if (tocSize <= sizeof(CDTOC)) {
        return(kIOReturnNotFound);
    }

    /* Read the TOC in full: */

    buffer = IOBufferMemoryDescriptor::withCapacity(tocSize,kIODirectionIn);
    if (buffer == NULL) {
        return(kIOReturnNoMemory);
    }

    result = getProvider()->readTOC(buffer);
    if (result != kIOReturnSuccess) {
        buffer->release();
        return(result);
    }

    toc = (CDTOC *) IOMalloc(tocSize);
    if (toc == NULL) {
        buffer->release();
        return(kIOReturnNoMemory);
    }

    if (buffer->readBytes(0,toc,tocSize) != tocSize) {
        buffer->release();
        IOFree(toc,tocSize);
        return(kIOReturnNoMemory);
    }

    _toc = toc;
    _tocSize = tocSize;

    buffer->release();

    return(result);
}
OSSet * IOGUIDPartitionScheme::scan(SInt32 * score)
{
    //
    // Scan the provider media for a GUID partition map.    Returns the set
    // of media objects representing each of the partitions (the retain for
    // the set is passed to the caller), or null should no partition map be
    // found.  The default probe score can be adjusted up or down, based on
    // the confidence of the scan.
    //

    IOBufferMemoryDescriptor * buffer         = 0;
    IOByteCount                bufferSize     = 0;
    UInt32                     fdiskID        = 0;
    disk_blk0 *                fdiskMap       = 0;
    UInt64                     gptBlock       = 0;
    UInt32                     gptCheck       = 0;
    UInt32                     gptCount       = 0;
    UInt32                     gptID          = 0;
    gpt_ent *                  gptMap         = 0;
    UInt32                     gptSize        = 0;
    UInt32                     headerCheck    = 0;
    gpt_hdr *                  headerMap      = 0;
    UInt32                     headerSize     = 0;
    IOMedia *                  media          = getProvider();
    UInt64                     mediaBlockSize = media->getPreferredBlockSize();
    bool                       mediaIsOpen    = false;
    OSSet *                    partitions     = 0;
    IOReturn                   status         = kIOReturnError;

    // Determine whether this media is formatted.

    if ( media->isFormatted() == false )  goto scanErr;

    // Determine whether this media has an appropriate block size.

    if ( (mediaBlockSize % sizeof(disk_blk0)) )  goto scanErr;

    // Allocate a buffer large enough to hold one map, rounded to a media block.

    bufferSize = IORound(sizeof(disk_blk0), mediaBlockSize);
    buffer     = IOBufferMemoryDescriptor::withCapacity(
                                           /* capacity      */ bufferSize,
                                           /* withDirection */ kIODirectionIn );
    if ( buffer == 0 )  goto scanErr;

    // Allocate a set to hold the set of media objects representing partitions.

    partitions = OSSet::withCapacity(8);
    if ( partitions == 0 )  goto scanErr;

    // Open the media with read access.

    mediaIsOpen = open(this, 0, kIOStorageAccessReader);
    if ( mediaIsOpen == false )  goto scanErr;

    // Read the protective map into our buffer.

    status = media->read(this, 0, buffer);
    if ( status != kIOReturnSuccess )  goto scanErr;

    fdiskMap = (disk_blk0 *) buffer->getBytesNoCopy();

    // Determine whether the protective map signature is present.

    if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
    {
         goto scanErr;
    }

    // Scan for valid partition entries in the protective map.

    for ( unsigned index = 0; index < DISK_NPART; index++ )
    {
        if ( fdiskMap->parts[index].systid )
        {
            if ( fdiskMap->parts[index].systid == 0xEE )
            {
                if ( fdiskID )  goto scanErr;

                fdiskID = index + 1;
            }
        }
    }

    if ( fdiskID == 0 )  goto scanErr;

    // Read the partition header into our buffer.

    status = media->read(this, mediaBlockSize, buffer);
    if ( status != kIOReturnSuccess )  goto scanErr;

    headerMap = (gpt_hdr *) buffer->getBytesNoCopy();

    // Determine whether the partition header signature is present.

    if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
    {
        goto scanErr;
    }

    // Determine whether the partition header size is valid.

    headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
    headerSize  = OSSwapLittleToHostInt32(headerMap->hdr_size);

    if ( headerSize < offsetof(gpt_hdr, padding) )
    {
        goto scanErr;
    }

    if ( headerSize > mediaBlockSize )
    {
        goto scanErr;
    }

    // Determine whether the partition header checksum is valid.

    headerMap->hdr_crc_self = 0;

    if ( crc32(0, headerMap, headerSize) != headerCheck )
    {
        goto scanErr;
    }

    // Determine whether the partition entry size is valid.

    gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
    gptSize  = OSSwapLittleToHostInt32(headerMap->hdr_entsz);

    if ( gptSize < sizeof(gpt_ent) )
    {
        goto scanErr;
    }

    if ( gptSize > UINT16_MAX )
    {
        goto scanErr;
    }

    // Determine whether the partition entry count is valid.

    gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
    gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);

    if ( gptCount > UINT16_MAX )
    {
        goto scanErr;
    }

    // Allocate a buffer large enough to hold one map, rounded to a media block.

    buffer->release();

    bufferSize = IORound(gptCount * gptSize, mediaBlockSize);
    buffer     = IOBufferMemoryDescriptor::withCapacity(
                                           /* capacity      */ bufferSize,
                                           /* withDirection */ kIODirectionIn );
    if ( buffer == 0 )  goto scanErr;

    // Read the partition header into our buffer.

    status = media->read(this, gptBlock * mediaBlockSize, buffer);
    if ( status != kIOReturnSuccess )  goto scanErr;

    gptMap = (gpt_ent *) buffer->getBytesNoCopy();

    // Determine whether the partition entry checksum is valid.

    if ( crc32(0, gptMap, gptCount * gptSize) != gptCheck )
    {
        goto scanErr;
    }

    // Scan for valid partition entries in the partition map.

    for ( gptID = 1; gptID <= gptCount; gptID++ )
    {
        gptMap = (gpt_ent *) ( ((UInt8 *) buffer->getBytesNoCopy()) +
                               (gptID * gptSize) - gptSize );

        uuid_unswap( gptMap->ent_type );
        uuid_unswap( gptMap->ent_uuid );
 
        if ( isPartitionUsed( gptMap ) )
        {
            // Determine whether the partition is corrupt (fatal).

            if ( isPartitionCorrupt( gptMap, gptID ) )
            {
                goto scanErr;
            }

            // Determine whether the partition is invalid (skipped).

            if ( isPartitionInvalid( gptMap, gptID ) )
            {
                continue;
            }

            // Create a media object to represent this partition.

            IOMedia * newMedia = instantiateMediaObject( gptMap, gptID );

            if ( newMedia )
            {
                partitions->setObject(newMedia);
                newMedia->release();
            }
        }
    }

    // Release our resources.

    close(this);
    buffer->release();

    return partitions;

scanErr:

    // Release our resources.

    if ( mediaIsOpen )  close(this);
    if ( partitions )  partitions->release();
    if ( buffer )  buffer->release();

    return 0;
}
static void 
DisjointCompletion(IOUSBController *me, IOUSBCommand *command, IOReturn status, UInt32 bufferSizeRemaining)
{
    IOBufferMemoryDescriptor	*buf = NULL;
	IODMACommand				*dmaCommand = NULL;

	USBTrace_Start( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)command, status, bufferSizeRemaining );
	
    if (!me || !command)
    {
		USBError(1, "DisjointCompletion sanity check failed - me(%p) command (%p)", me, command);
		return;
    }
	
	buf = OSDynamicCast(IOBufferMemoryDescriptor, command->GetBuffer());
	dmaCommand = command->GetDMACommand();
	
	if (!dmaCommand || !buf)
	{
		USBLog(1, "%s[%p]::DisjointCompletion - no dmaCommand, or buf(%p) is not an IOBMD", me->getName(), me, command->GetBuffer());
		USBTrace( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)command->GetBuffer(), 0, 1 );
		return;
	}
	
	if (dmaCommand->getMemoryDescriptor())
	{
		if (dmaCommand->getMemoryDescriptor() != buf)
		{
			USBLog(1, "%s[%p]::DisjointCompletion - buf(%p) doesn't match getMemoryDescriptor(%p)", me->getName(), me, buf, dmaCommand->getMemoryDescriptor());
			USBTrace( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)buf, (uintptr_t)dmaCommand->getMemoryDescriptor(), 2 );
		}
		
		// need to complete the dma command
		USBLog(6, "%s[%p]::DisjointCompletion - clearing memory descriptor (%p) from dmaCommand (%p)", me->getName(), me, dmaCommand->getMemoryDescriptor(), dmaCommand);
		dmaCommand->clearMemoryDescriptor();
	}
	
    if (command->GetDirection() == kUSBIn)
    {
		USBLog(5, "%s[%p]::DisjointCompletion, copying %d out of %d bytes to desc %p from buffer %p", me->getName(), me, (int)(command->GetDblBufLength()-bufferSizeRemaining), (int)command->GetDblBufLength(), command->GetOrigBuffer(), buf);
		command->GetOrigBuffer()->writeBytes(0, buf->getBytesNoCopy(), (command->GetDblBufLength()-bufferSizeRemaining));
    }
	
    buf->complete();
	buf->release();								// done with this buffer
	command->SetBuffer(NULL);
	
    // now call through to the original completion routine
    IOUSBCompletion completion = command->GetDisjointCompletion();
	
	if ( !command->GetIsSyncTransfer() )
	{
		// Free our command now that we have the completion and we are not going to use it anymore
		me->ReturnUSBCommand(command);
	}
	
   	if (completion.action)
	{
		USBLog(status == kIOReturnSuccess ? 7 : 3, "%s[%p]::DisjointCompletion calling through to %p - status 0x%x!", me->getName(), me, completion.action, (uint32_t)status);
		(*completion.action)(completion.target, completion.parameter, status, bufferSizeRemaining);
	}
	
	USBTrace_End( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)completion.target, (uintptr_t)completion.parameter, status, bufferSizeRemaining);
}
void VoodooI2CHIDDevice::i2c_hid_get_input(OSObject* owner, IOTimerEventSource* sender) {
//    IOLog("getting input\n");
    UInt rsize;
    int ret;
    static unsigned char* rdesc_prev = NULL;
    static UInt rsize_prev = 0;
    bool new_report = true;
    
    rsize = UInt16(ihid->hdesc.wMaxInputLength);
    
    unsigned char* rdesc = (unsigned char *)IOMalloc(rsize);
    
    ret = i2c_hid_command(ihid, &hid_input_cmd, rdesc, rsize);

//    IOLog("===Input (%d)===\n", rsize);
//    for (int i = 0; i < rsize; i++)
//        IOLog("0x%02x ", (UInt8) rdesc[i]);
//    IOLog("\n");

    int return_size = rdesc[0] | rdesc[1] << 8;
    if (return_size == 0) {
        /* host or device initiated RESET completed */
        // test/clear bit?
        hid_device->timerSource->setTimeoutMS(10);
        return;
    }

    if (return_size > rsize) {
        IOLog("%s: Incomplete report %d/%d\n", __func__, rsize, return_size);
    }

    IOBufferMemoryDescriptor *buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, return_size);
    buffer->writeBytes(0, rdesc + 2, return_size - 2);

#define FILTER_REPEATED_REPORTS /* Needed on my ASUS/Skylake ELAN1000 */

#ifdef FILTER_REPEATED_REPORTS
    /* Compare to previous report */
    if (rdesc_prev)
    {
        /* See if they're different! */
        if (rsize == rsize_prev)
        {
            if (memcmp(rdesc_prev, rdesc, rsize))
            {
                new_report = true;
            } else {
                new_report = false;
            }
        } else {
            new_report = true;
        }

        /* We don't need the previous report anymore */
        IOFree(rdesc_prev, rsize_prev);
    }
    else
    {
        new_report = true;
    }

    /* Keep for next comparison */
    rdesc_prev = rdesc;
    rsize_prev = rsize;

    if (new_report)
    {
        IOReturn err = _wrapper->handleReport(buffer, kIOHIDReportTypeInput);
        if (err != kIOReturnSuccess)
            IOLog("Error handling report: 0x%.8x\n", err);
    }

#else /* non filtered for repeating reports */
    IOReturn err = _wrapper->handleReport(buffer, kIOHIDReportTypeInput);
    if (err != kIOReturnSuccess)
        IOLog("Error handling report: 0x%.8x\n", err);
#endif

    buffer->release();

#ifndef FILTER_REPEATED_REPORTS
    IOFree(rdesc, rsize);
#endif

    hid_device->timerSource->setTimeoutMS(10);
}