IOReturn SoftU2FUserClient::sendFrame(U2FHID_FRAME *frame, size_t frameSize) {
  SoftU2FDevice *device = nullptr;
  IOMemoryDescriptor *report = nullptr;

  if (isInactive())
    return kIOReturnOffline;

  if (frameSize != HID_RPT_SIZE)
    return kIOReturnBadArgument;

  device = OSDynamicCast(SoftU2FDevice, getClient());
  if (!device)
    return kIOReturnNotAttached;

  report = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, HID_RPT_SIZE);
  if (!report)
    return kIOReturnNoResources;

  report->writeBytes(0, frame, frameSize);

  if (device->handleReport(report) != kIOReturnSuccess) {
    report->release();
    return kIOReturnError;
  }

  report->release();

  return kIOReturnSuccess;
}
Beispiel #2
0
/*
 *  GetSenseInformation
 *
 *  Attempt to get SCSI sense information either from the Auto sense
 *  mechanism or by querying manually.
 */
void
IOSCSITape::GetSense(SCSITaskIdentifier request)
{
	SCSI_Sense_Data		senseBuffer = { 0 };
	bool				validSense = false;
	SCSIServiceResponse	serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
	
	IOMemoryDescriptor *bufferDesc = IOMemoryDescriptor::withAddress((void *)&senseBuffer, 
																	 sizeof(senseBuffer), 
																	 kIODirectionIn);
	
	if (GetTaskStatus(request) == kSCSITaskStatus_CHECK_CONDITION)
	{
		validSense = GetAutoSenseData(request, &senseBuffer);
		
		if (validSense == false)
		{
			if (REQUEST_SENSE(request, bufferDesc, kSenseDefaultSize, 0) == true)
				serviceResponse = SendCommand(request, kTenSecondTimeoutInMS);
			
			if (serviceResponse == kSCSIServiceResponse_TASK_COMPLETE)
				validSense = true;
		}
		
		if (validSense == true)
			InterpretSense(&senseBuffer);
		else
			STATUS_LOG("invalid or unretrievable SCSI SENSE");
	}
	
	bufferDesc->release();
}
void IOHIDTestDriver::issueFakeReport()
{
    UInt8 report[][7] = {
    { 0x44, 0x3B, 0x49, 0x43, 0x80, 0x00, 0x00 },
    { 0x44, 0x3B, 0x49, 0x43, 0x00, 0x00, 0x00 },
    { 0x44, 0x3B, 0x49, 0x43, 0x20, 0x00, 0x00 },
    { 0x44, 0x3B, 0x49, 0x43, 0x00, 0x00, 0x00 },
    { 0x44, 0x3B, 0x49, 0x43, 0x10, 0x00, 0x00 },
    { 0x44, 0x3B, 0x49, 0x43, 0x00, 0x00, 0x00 },
    { 0x44, 0x3B, 0x49, 0x43, 0x00, 0x80, 0x00 },
    { 0x44, 0x3B, 0x49, 0x43, 0x00, 0x00, 0x00 },
    { 0x44, 0x36, 0x49, 0x43, 0x00, 0x00, 0x00 },
    { 0x48, 0x19, 0x49, 0x43, 0x00, 0x00, 0x00 },
    { 0x48, 0x15, 0x49, 0x43, 0x00, 0x00, 0x00 },
    { 0x4C, 0x11, 0x49, 0x43, 0x00, 0x00, 0x00 } };

    const  UInt32 reportCount = sizeof(report)/sizeof(report[0]);
    static UInt32 reportIndex = 0;

    IOMemoryDescriptor * desc = IOMemoryDescriptor::withAddress(
                                        report[reportIndex],
                                        sizeof(report[0]),
                                        kIODirectionNone );

    if (desc)
    {
        handleReport( desc );
        desc->release();
    }

    if ( ++reportIndex >= reportCount )
        reportIndex = 0;
}
// Received a normal HID update from the device
void WirelessHIDDevice::receivedHIDupdate(unsigned char *data, int length)
{
    IOReturn err;
    IOMemoryDescriptor *report;
    
    report = IOMemoryDescriptor::withAddress(data, length, kIODirectionNone);
    err = handleReport(report, kIOHIDReportTypeInput);
    report->release();
    if (err != kIOReturnSuccess)
        IOLog("handleReport return: 0x%.8x\n", err);
}
// Handle new data from the device
void WirelessHIDDevice::receivedData(void)
{
    IOMemoryDescriptor *data;
    WirelessDevice *device = OSDynamicCast(WirelessDevice, getProvider());
    if (device == NULL)
        return;
    
    while ((data = device->NextPacket()) != NULL)
    {
        receivedMessage(data);
        data->release();
    }
}
Beispiel #6
0
IOReturn
IOSCSITape::GetDeviceBlockLimits(void)
{
	SCSITaskIdentifier		task			= NULL;
	IOReturn				status			= kIOReturnError;
	UInt8					blockLimitsData[6]	= { 0 };
	SCSITaskStatus			taskStatus		= kSCSITaskStatus_DeliveryFailure;
	IOMemoryDescriptor *	dataBuffer		= NULL;
	
	dataBuffer = IOMemoryDescriptor::withAddress(&blockLimitsData, 
												 sizeof(blockLimitsData), 
												 kIODirectionIn);

	require ((dataBuffer != 0), ErrorExit);
	
	task = GetSCSITask();
	
	require ((task != 0), ErrorExit);
	
	if (READ_BLOCK_LIMITS(task, dataBuffer, 0x00) == true)
		taskStatus = DoSCSICommand(task, SCSI_NOMOTION_TIMEOUT);
	
	if (taskStatus == kSCSITaskStatus_GOOD)
	{
		// blkgran = blockLimitsData[0] & 0x1F;
		
		blkmin =
			(blockLimitsData[4] <<  8) |
			 blockLimitsData[5];
		
		blkmax =
			(blockLimitsData[1] << 16) |
			(blockLimitsData[2] <<  8) |
			 blockLimitsData[3];
		
		STATUS_LOG("min/max block size: %d/%d", blkmin, blkmax);
		
		status = kIOReturnSuccess;
	}

	ReleaseSCSITask(task);
	dataBuffer->release();
	
ErrorExit:
	
	return status;
}
IOReturn XboxOneControllerDriver::sendHello()
{
	IOReturn ior = kIOReturnSuccess;
	IOMemoryDescriptor* hello = nullptr;
	IOByteCount bytesWritten = 0;
	constexpr size_t helloSize = sizeof XboxOneControllerHelloMessage;
	
	if (_interruptPipe == nullptr) // paranoid check
	{
		IO_LOG_DEBUG("_interruptPipe is null");
		ior = kIOReturnInternalError;
		goto cleanup;
	}
	
	// Create the hello message that we're about to send to the controller.
	hello = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, helloSize);
	if (hello == nullptr)
	{
		IO_LOG_DEBUG("Could not allocate buffer for hello message.");
		ior = kIOReturnNoMemory;
		goto cleanup;
	}
	
	bytesWritten = hello->writeBytes(0, XboxOneControllerHelloMessage, helloSize);
	if (bytesWritten != helloSize) // paranoid check
	{
		ior = kIOReturnOverrun;
		goto cleanup;
	}
	
	// Now send the message
	ior = _interruptPipe->Write(hello, 0, 0, hello->getLength());
	if (ior != kIOReturnSuccess)
	{
		IO_LOG_DEBUG("Couldn't send hello message to controller: %08x\n", ior);
		goto cleanup;
	}
	
cleanup:
	if (hello != nullptr)
	{
		hello->release();
	}
	
	return ior;
}
static inline bool hpetIsInvalid()
{
    hpetInfo_t hpetInfo;
    hpet_get_info(&hpetInfo);
    // The AppleIntelCPUPowerManagement will crash if rcbaArea and/or HPET is NULL
    // Ordinarily this can never happen but modified xnu can allow for this.
    if(hpetInfo.rcbaArea == 0)
    {
        IOLog("Forcing takeover of AppleIntelCPUPowerManagement resource due to lack of RCBA (no LPC?)\n");
        return true;
    }
    // Another case is that the LPC exists but the HPET isn't really valid.
    // That is to say that virtual hardware provides enough to get past xnu startup
    // but not enough to really make the HPET work.

    uint32_t hptc = *(uint32_t*)(hpetInfo.rcbaArea + 0x3404);
    if(!(hptc & hptcAE))
    {
        IOLog("Forcing takeover of AppleIntelCPUPowerManagement resource because HPET is not enabled\n");
        return true;
    }
    // Use the RCBA's HPTC to determine which of the four possible HPET physical addresses is used
    uint32_t hpetAreap = hpetAddr | ((hptc & 3) << 12);
    IOMemoryDescriptor *hpetMemDesc = IOMemoryDescriptor::withPhysicalAddress(hpetAreap, sizeof(hpetReg_t), kIODirectionIn);

    // grab the GCAP_ID (note offset is actually 0)
    uint64_t GCAP_ID;
    hpetMemDesc->readBytes(offsetof(hpetReg_t, GCAP_ID), &GCAP_ID, sizeof(GCAP_ID));

    // We're done with the memory descriptor now, so release it
    hpetMemDesc->release();
    hpetMemDesc = NULL;

    // Extract the VENDOR_ID_CAP field from the GCAP_ID and test it
    uint16_t vendorId = bitfield(GCAP_ID, 31, 16);
    if( (vendorId == 0x0000) || (vendorId == 0xffff))
    {
        IOLog("Forcing takeover of AppleIntelCPUPowerManagement resource due to bad HPET VENDOR_ID_CAP\n");
        return true;
    }
    else if(vendorId != 0x8086)
    {
        IOLog("WARNING: HPET is not Intel.  Going ahead and allowing AppleIntelCPUPowerManagement to start but beware it may behave strangely\n");
    }
    return false;
}
Beispiel #9
0
int st_readwrite(dev_t dev, struct uio *uio, int ioflag)
{
	IOSCSITape			*st			= IOSCSITape::devices[minor(dev)];
	IOMemoryDescriptor	*dataBuffer	= IOMemoryDescriptorFromUIO(uio);
	int					status		= ENOSYS;
	IOReturn			opStatus	= kIOReturnError;
	int					lastRealizedBytes = 0;
	
	if (dataBuffer == 0)
		return ENOMEM;
	
	dataBuffer->prepare();
	
	opStatus = st->ReadWrite(dataBuffer, &lastRealizedBytes);
	
	dataBuffer->complete();
	dataBuffer->release();
	
	if (opStatus == kIOReturnSuccess)
	{
		uio_setresid(uio, uio_resid(uio) - lastRealizedBytes);
		
		if (st->blkno != -1)
		{
			if (st->IsFixedBlockSize())
				st->blkno += (lastRealizedBytes / st->blksize);
			else
				st->blkno++;
		}

		status = KERN_SUCCESS;
	}
	else if (st->sense_flags & SENSE_FILEMARK)
	{
		if (st->fileno != -1)
		{
			st->fileno++;
			st->blkno = 0;
		}
		
		status = KERN_SUCCESS;
	}
	
	return status;
}
Beispiel #10
0
IOReturn
IOSCSITape::SetDeviceDetails(SCSI_ModeSense_Default *modeData)
{
	IOReturn				status		= kIOReturnError;
	IOMemoryDescriptor *	dataBuffer	= NULL;
	SCSITaskIdentifier		task		= NULL;
	SCSITaskStatus			taskStatus	= kSCSITaskStatus_DeviceNotResponding;
	
	dataBuffer = IOMemoryDescriptor::withAddress(modeData,
												 sizeof(SCSI_ModeSense_Default),
												 kIODirectionOut);
	
	require((dataBuffer != 0), ErrorExit);
	
	task = GetSCSITask();
	
	require((task != 0), ErrorExit);
	
	if (MODE_SELECT_6(task, 
					  dataBuffer, 
					  0x0, // PF
					  0x0, // SP
					  sizeof(SCSI_ModeSense_Default), 
					  0x00) == true)
	{
		taskStatus = DoSCSICommand(task, SCSI_NOMOTION_TIMEOUT);
	}
	
	if (taskStatus == kSCSITaskStatus_GOOD)
	{
		status = kIOReturnSuccess;
	}
	
	ReleaseSCSITask(task);
	dataBuffer->release();
	
ErrorExit:
	
	return status;
}
IOReturn XboxOneControllerDriver::newReportDescriptor(IOMemoryDescriptor **descriptor) const
{
	if (descriptor == nullptr)
	{
		return kIOReturnBadArgument;
	}
	
	constexpr size_t descriptorSize = sizeof XboxOneControllerReportDescriptor;
	IOMemoryDescriptor* buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, descriptorSize);
	if (buffer == nullptr)
	{
		return kIOReturnNoMemory;
	}
	
	IOByteCount written = buffer->writeBytes(0, XboxOneControllerReportDescriptor, descriptorSize);
	if (written != sizeof XboxOneControllerReportDescriptor) // paranoid check
	{
		buffer->release();
		return kIOReturnNoSpace;
	}
	
	*descriptor = buffer;
	return kIOReturnSuccess;
}
Beispiel #12
0
IOReturn
IrDAUserClient::getIrDALog(void *pIn, void *pOut, IOByteCount inputSize, IOByteCount *outPutSize)
{
#if (hasTracing > 0)

    IOMemoryDescriptor *md;         // make a memory descriptor for the client's big buffer
    unsigned char *input = (unsigned char *)pIn;
    mach_vm_address_t bigaddr;
    IOByteCount   biglen;
    IrDALogInfo *info;

    require(inputSize == 9, Fail);
    require(outPutSize, Fail);
    require(*outPutSize == sizeof(IrDALogInfo), Fail);
	
    //bigaddr = input[1] << 24 | input[2] << 16 | input[3] << 8 | input[4];
    //biglen  = input[5] << 24 | input[6] << 16 | input[7] << 8 | input[8];
    bcopy(&input[1], &bigaddr, sizeof(bigaddr));
    bcopy(&input[5], &biglen, sizeof(biglen));
    
    //IOLog("biglen is %d\n", biglen);
    
    // create and init the memory descriptor
    //md = IOMemoryDescriptor::withAddress(bigaddr, biglen, kIODirectionOutIn, fTask);        // REVIEW direction
    //use withAddressRange() and prepare() instead
    md = IOMemoryDescriptor::withAddressRange(bigaddr, biglen, kIODirectionOutIn, fTask);        // REVIEW direction
    md->prepare(kIODirectionOutIn);

    require(md, Fail);
    
    info = IrDALogGetInfo();        // get the info block
		    
    //ELG(info->hdr,       info->hdrSize,       'irda', "info hdr");
    //ELG(info->eventLog,  info->eventLogSize,  'irda', "info events");
    //ELG(info->msgBuffer, info->msgBufferSize, 'irda', "info msg buf");
		    
    bcopy(info, pOut, sizeof(*info));       // copy the info record back to the client
    *outPutSize = sizeof(*info);            // set the output size (nop, it already is)
    
    // copy the buffer over now if there is room
    if (biglen >= info->hdrSize + info->eventLogSize + info->msgBufferSize) {
	IOByteCount ct;
	IOReturn rc;
	
	rc = md->prepare(kIODirectionNone);
	if (rc)  {ELG(-1, rc, 'irda', "prepare failed"); }
	
	ct = md->writeBytes(0,                              info->hdr,       info->hdrSize);
	if (ct != info->hdrSize) ELG(-1, rc, 'irda', "write of hdr failed");
	
	ct = md->writeBytes(info->hdrSize,                   info->eventLog,  info->eventLogSize);
	if (ct != info->eventLogSize) ELG(-1, rc, 'irda', "write of events failed");
	
	ct = md->writeBytes(info->hdrSize+info->eventLogSize, info->msgBuffer, info->msgBufferSize);
	if (ct != info->msgBufferSize) ELG(-1, rc, 'irda', "write of msgs failed");
	
	ELG(0, info->hdrSize+info->eventLogSize, 'irda', "wrote msgs at offset");
	
	rc = md->complete(kIODirectionNone);
	if (!rc) { ELG(0, 0, 'irda', "complete worked"); }
	else    { ELG(-1, rc, 'irda', "complete failed"); }

	// todo check return code of above before resetting the buffer
	IrDALogReset();     // reset the buffer now
    }
    md->release();  // free it

    return kIOReturnSuccess;


Fail:

#endif          // hasTracing > 0

    return kIOReturnBadArgument;
}
IOReturn
SATSMARTUserClient::GetIdentifyData (UInt32 * dataOut,
				     IOByteCount * outputSize)
{
    
    IOReturn status                  = kIOReturnSuccess;
    IOSATCommand *                          command                 = NULL;
    IOMemoryDescriptor *      buffer                  = NULL;
    DEBUG_LOG("%s[%p]::%s %p(%ld)\n", getClassName(), this, __FUNCTION__, dataOut, (long)(outputSize));
    
    if (!dataOut || !outputSize || *outputSize < kATADefaultSectorSize ) {
        return kIOReturnBadArgument;
    }
    
    fOutstandingCommands++;
    
    if ( isInactive ( ) )
    {
        
        status = kIOReturnNoDevice;
        goto ErrorExit;
        
    }
    
    fProvider->retain ( );
    
    command = AllocateCommand ( );
    if ( command == NULL )
    {
        
        status = kIOReturnNoResources;
        goto ReleaseProvider;
        
    }
    
    buffer = IOMemoryDescriptor::withAddress(dataOut, kATADefaultSectorSize, kIODirectionIn);
    if ( buffer == NULL )
    {
        
        status = kIOReturnNoResources;
        goto ReleaseCommand;
        
    }
    
    status = buffer->prepare ( );
    if ( status != kIOReturnSuccess )
    {
        
        goto ReleaseBuffer;
        
    }
    
    command->setBuffer                              ( buffer );
    command->setByteCount                   ( kATADefaultSectorSize );
    command->setTransferChunkSize   ( kATADefaultSectorSize );
    command->setOpcode                              ( kATAFnExecIO );
    command->setTimeoutMS                   ( kATAThirtySecondTimeoutInMS );
    command->setCommand                             ( kATAcmdDriveIdentify );
    command->setFlags                               ( mATAFlagIORead );
    command->setRegMask                             ( ( ataRegMask ) ( mATAErrFeaturesValid | mATAStatusCmdValid ) );
    
    status = SendSMARTCommand ( command );
    if ( status == kIOReturnSuccess )
    {
        
#if defined(__BIG_ENDIAN__)
        UInt8 *         bufferToCopy = identifyDataPtr;
        
        // The identify device info needs to be byte-swapped on big-endian (ppc)
        // systems becuase it is data that is produced by the drive, read across a
        // 16-bit little-endian PCI interface, directly into a big-endian system.
        // Regular data doesn't need to be byte-swapped because it is written and
        // read from the host and is intrinsically byte-order correct.
        
        IOByteCount index;
        UInt8 temp;
        UInt8 *                 firstBytePtr;
        UInt8 *                 identifyDataPtr = ( UInt8 * )dataOut;
        
        for ( index = 0; index < buffer->getLength ( ); index += 2 )
        {
            
            firstBytePtr            = identifyDataPtr;                          // save pointer
            temp                            = *identifyDataPtr++;               // Save Byte0, point to Byte1
            *firstBytePtr           = *identifyDataPtr;                         // Byte0 = Byte1
            *identifyDataPtr++      = temp;                                             // Byte1 = Byte0
            
        }
        
#endif
        
        *outputSize = buffer->getLength ( );
        DEBUG_LOG("%s[%p]::%s cpy %p %p\n", getClassName(), this,  __FUNCTION__, (void*)*outputSize, (void*)buffer->getLength());
    }
    
    
ReleaseBufferPrepared:
    
    buffer->complete ( );
    
    
ReleaseBuffer:
    
    
    buffer->release ( );
    buffer = NULL;
    
    
ReleaseCommand:
    
    
    DeallocateCommand ( command );
    command = NULL;
    
    
ReleaseProvider:
    
    
    fProvider->release ( );
    
    
ErrorExit:
    
    
    fOutstandingCommands--;
    
    DEBUG_LOG("%s[%p]::%s result %x\n", getClassName(), this,  __FUNCTION__, status);
    return status;
    
}
Beispiel #14
0
/*
 *  GetDeviceDetails()
 *  Get mode sense details and set device parameters.
 *
 *  Would have ideally liked to use super::GetModeSense() but it appears
 *  to set the DBD bit and we need the descriptor values for density,
 *  etc.
 */
IOReturn
IOSCSITape::GetDeviceDetails(void)
{
	IOReturn				status		= kIOReturnError;
	SCSITaskIdentifier		task		= NULL;
	SCSITaskStatus			taskStatus	= kSCSITaskStatus_DeviceNotResponding;
	IOMemoryDescriptor *	dataBuffer	= NULL;
	SCSI_ModeSense_Default	modeData	= { 0 };

	dataBuffer = IOMemoryDescriptor::withAddress(&modeData,
												 sizeof(modeData),
												 kIODirectionIn);
	
	require((dataBuffer != 0), ErrorExit);
	
	task = GetSCSITask();
	
	require((task != 0), ErrorExit);

	if (MODE_SENSE_6(task, 
					 dataBuffer, 
					 0x0,
					 0x0,
					 0x00,
					 sizeof(SCSI_ModeSense_Default), 
					 0x00) == true)
	{
		taskStatus = DoSCSICommand(task, SCSI_NOMOTION_TIMEOUT);
	}
	
	if (taskStatus == kSCSITaskStatus_GOOD)
	{
		/* copy mode data for next MODE SELECT */
		bcopy(&modeData, &lastModeData, sizeof(SCSI_ModeSense_Default));
		
		blksize = 
			(modeData.descriptor.BLOCK_LENGTH[0] << 16) |
			(modeData.descriptor.BLOCK_LENGTH[1] <<  8) |
			 modeData.descriptor.BLOCK_LENGTH[2];
		
		density = modeData.descriptor.DENSITY_CODE;
		flags &= ~(ST_READONLY | ST_BUFF_MODE);
		
		if (modeData.header.DEVICE_SPECIFIC_PARAMETER & SMH_DSP_WRITE_PROT)
			flags |= ST_READONLY;
		
		if (modeData.header.DEVICE_SPECIFIC_PARAMETER & SMH_DSP_BUFF_MODE)
			flags |= ST_BUFF_MODE;

		STATUS_LOG("density code: %d, %d-byte blocks, write-%s, %sbuffered",
				   density, blksize,
				   flags & ST_READONLY ? "protected" : "enabled",
				   flags & ST_BUFF_MODE ? "" : "un");
		
		status = kIOReturnSuccess;
	}
	
	ReleaseSCSITask(task);
	dataBuffer->release();
	
ErrorExit:
	
	return status;
}
IOReturn
SATSMARTUserClient::ReadDataThresholds (UInt32 * dataOut,
                                        IOByteCount * outputSize)
{
    
    IOReturn status  = kIOReturnSuccess;
    IOSATCommand *                  command = NULL;
    IOMemoryDescriptor *    buffer  = NULL;
    DEBUG_LOG("%s[%p]::%s\n", getClassName(), this, __FUNCTION__);
    
    if (!dataOut || !outputSize || *outputSize != sizeof ( ATASMARTDataThresholds ) ) {
        return kIOReturnBadArgument;
    }
    
    fOutstandingCommands++;
    
    if ( isInactive ( ) )
    {
        
        status = kIOReturnNoDevice;
        goto ErrorExit;
        
    }
    
    fProvider->retain ( );
    
    command = AllocateCommand ( );
    if ( command == NULL )
    {
        
        status = kIOReturnNoResources;
        goto ReleaseProvider;
        
    }
    
    buffer = IOMemoryDescriptor::withAddress(dataOut, sizeof ( ATASMARTDataThresholds ), kIODirectionIn);
    
    if ( buffer == NULL )
    {
        
        status = kIOReturnNoResources;
        goto ReleaseCommand;
        
    }
    
    status = buffer->prepare ( );
    if ( status != kIOReturnSuccess )
    {
        
        goto ReleaseBuffer;
        
    }
    
    command->setBuffer                      ( buffer );
    command->setByteCount           ( sizeof ( ATASMARTDataThresholds ) );
    command->setFeatures            ( kFeaturesRegisterReadDataThresholds );
    command->setOpcode                      ( kATAFnExecIO );
    command->setTimeoutMS           ( kATAThirtySecondTimeoutInMS );
    command->setCylLo                       ( kSMARTMagicCylinderLoValue );
    command->setCylHi                       ( kSMARTMagicCylinderHiValue );
    command->setCommand                     ( kATAcmdSMART );
    command->setFlags                       ( mATAFlagIORead );
    
    status = SendSMARTCommand ( command );
    if ( status == kIOReturnIOError )
    {
        
        if ( command->getEndErrorReg ( ) & 0x04 )
        {
            
            ERROR_LOG ( "ReadDataThresholds unsupported\n" );
            status = kIOReturnUnsupported;
            
        }
        
        if ( command->getEndErrorReg ( ) & 0x10 )
        {
            
            ERROR_LOG ( "ReadDataThresholds Not readable\n" );
            status = kIOReturnNotReadable;
            
        }
        
    }
    
    *outputSize = buffer->getLength();
    
    buffer->complete ( );
    
    
ReleaseBuffer:
    
    
    buffer->release ( );
    buffer = NULL;
    
    
ReleaseCommand:
    
    
    DeallocateCommand ( command );
    command = NULL;
    
    
ReleaseProvider:
    
    
    fProvider->release ( );
    
    
ErrorExit:
    
    
    fOutstandingCommands--;
    
    DEBUG_LOG("%s[%p]::%s result %d\n", getClassName(), this,  __FUNCTION__, status);
    return status;
    
}
IOReturn
SATSMARTUserClient::WriteLogAtAddress ( ATASMARTWriteLogStruct *        writeLogData,
                                       UInt32 inStructSize )
{
    
    IOReturn status                  = kIOReturnSuccess;
    IOSATCommand *                  command                 = NULL;
    IOMemoryDescriptor *    buffer                  = NULL;
    DEBUG_LOG("%s[%p]::%s\n", getClassName(), this, __FUNCTION__);
    
    if ( inStructSize != sizeof ( ATASMARTWriteLogStruct ) || writeLogData->numSectors > 16 || writeLogData->data_length > kSATMaxDataSize) {
        return kIOReturnBadArgument;
    }
    
    fOutstandingCommands++;
    
    if ( isInactive ( ) )
    {
        
        status = kIOReturnNoDevice;
        goto ErrorExit;
        
    }
    
    fProvider->retain ( );
    
    command = AllocateCommand ( );
    if ( command == NULL )
    {
        status = kIOReturnNoResources;
        goto ReleaseProvider;
    }
    
    //buffer = IOMemoryDescriptor::withAddress(writeLogData->buffer, writeLogData->bufferSize, kIODirectionOut);
    buffer = IOMemoryDescriptor::withAddressRange(writeLogData->data_pointer, writeLogData->data_length, kIODirectionOut, fTask);
    
    if ( buffer == NULL )
    {
        status = kIOReturnVMError;
        goto ReleaseCommand;
    }
    
    status = buffer->prepare ( );
    if ( status != kIOReturnSuccess )
    {
        goto ReleaseBuffer;
    }
    
    command->setBuffer                      ( buffer );
    command->setByteCount           ( writeLogData->data_length );
    command->setFeatures            ( kFeaturesRegisterWriteLogAtAddress );
    command->setOpcode                      ( kATAFnExecIO );
    command->setTimeoutMS           ( kATAThirtySecondTimeoutInMS );
    command->setSectorCount         ( writeLogData->numSectors );
    command->setSectorNumber        ( writeLogData->logAddress );
    command->setCylLo                       ( kSMARTMagicCylinderLoValue );
    command->setCylHi                       ( kSMARTMagicCylinderHiValue );
    command->setCommand                     ( kATAcmdSMART );
    command->setFlags                       ( mATAFlagIOWrite );
    
    status = SendSMARTCommand ( command );
    if ( status == kIOReturnIOError )
    {
        
        if ( command->getEndErrorReg ( ) & 0x04 )
        {
            
            ERROR_LOG ( "WriteLogAtAddress %d unsupported\n", writeLogData->logAddress );
            status = kIOReturnUnsupported;
            
        }
        
        if ( command->getEndErrorReg ( ) & 0x10 )
        {
            
            ERROR_LOG ( "WriteLogAtAddress %d unwriteable\n", writeLogData->logAddress );
            status = kIOReturnNotWritable;
            
        }
        
    }
    
    buffer->complete ( );
    
    
ReleaseBuffer:
    
    
    buffer->release ( );
    buffer = NULL;
    
    
ReleaseCommand:
    
    
    DeallocateCommand ( command );
    command = NULL;
    
    
ReleaseProvider:
    
    
    fProvider->release ( );
    
    
ErrorExit:
    
    
    fOutstandingCommands--;
    
    DEBUG_LOG("%s[%p]::%s result %d\n", getClassName(), this,  __FUNCTION__, status);
    return status;
    
}
// Processes a message for a controller
void WirelessGamingReceiver::ProcessMessage(int index, const unsigned char *data, int length)
{
/*
    char s[1024];
    int i;
    
    for (i = 0; i < length; i++)
    {
        s[(i * 2) + 0] = "0123456789ABCDEF"[(data[i] & 0xF0) >> 4];
        s[(i * 2) + 1] = "0123456789ABCDEF"[data[i] & 0x0F];
    }
    s[i * 2] = '\0';
    IOLog("Got data (%d, %d bytes): %s\n", index, length, s);
*/
    // Handle device connections
    if ((length == 2) && (data[0] == 0x08))
    {
        if (data[1] == 0x00)
        {
            // Device disconnected
//            IOLog("process: Device detached\n");
            if (connections[index].service != NULL)
            {
                connections[index].service->SetIndex(-1);
                if (connections[index].controllerStarted)
                    connections[index].service->terminate(kIOServiceRequired | kIOServiceSynchronous);
                connections[index].service->detach(this);
                connections[index].service->release();
                connections[index].service = NULL;
                connections[index].controllerStarted = false;
            }
        }
        else
        {
            // Device connected
//            IOLog("process: Attempting to add new device\n");
            if (connections[index].service == NULL)
            {
                bool ready;
                int i, j;
                IOMemoryDescriptor *data;
                char c;
                
                ready = false;
                j = connections[index].inputArray->getCount();
                for (i = 0; !ready && (i < j); i++)
                {
                    data = OSDynamicCast(IOMemoryDescriptor, connections[index].inputArray->getObject(i));
                    data->readBytes(1, &c, 1);
                    if (c == 0x0f)
                        ready = true;
                }
                InstantiateService(index);
                if (ready)
                {
//                    IOLog("Registering wireless device");
                    connections[index].controllerStarted = true;
                    connections[index].service->registerService();
                }
            }
        }
        return;
    }
    
    // Add anything else to the queue
    IOMemoryDescriptor *copy = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, length);
    copy->writeBytes(0, data, length);
    connections[index].inputArray->setObject(copy);
    if (connections[index].service == NULL)
        InstantiateService(index);
    if (connections[index].service != NULL)
    {
        connections[index].service->NewData();
        if (!connections[index].controllerStarted)
        {
            char c;
            
            copy->readBytes(1, &c, 1);
            if (c == 0x0f)
            {
//                IOLog("Registering wireless device");
                connections[index].controllerStarted = true;
                connections[index].service->registerService();
            }
        }
    }
    copy->release();
}
IOReturn SamplePCIUserClientClassName::method2( SampleStructForMethod2 * structIn,
        SampleResultsForMethod2 * structOut,
        IOByteCount inputSize, IOByteCount * outputSize )

{
    IOReturn err;
    IOMemoryDescriptor * memDesc = 0;
    UInt32 param1 = structIn->parameter1;

    uint64_t clientAddr = structIn->data_pointer;
    uint64_t size = structIn->data_length;

    // Rosetta
    if (fCrossEndian) {
        param1 = OSSwapInt32(param1);
    }

    IOLog("SamplePCIUserClient::method2(" UInt32_x_FORMAT ")\n", param1);
    IOLog( "fClientShared->string == \"%s\"\n", fClientShared->string );

    structOut->results1 = 0x87654321;
    // Rosetta
    if (fCrossEndian) {
        structOut->results1 = OSSwapInt64(structOut->results1);
        clientAddr = OSSwapInt64(clientAddr);
        size = OSSwapInt64(size);
    }

    do
    {

#if defined(__ppc__) && (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4)
        // construct a memory descriptor for the out of line client memory
        // old 32 bit API - this will fail and log a backtrace if the task is 64 bit
        IOLog("The Pre-Leopard way to construct a memory descriptor\n");
        memDesc = IOMemoryDescriptor::withAddress( (vm_address_t) clientAddr, (IOByteCount) size, kIODirectionNone, fTask );
        if (memDesc == NULL) {
            IOLog("IOMemoryDescriptor::withAddress failed\n");
            err = kIOReturnVMError;
            continue;
        }
#else
        // 64 bit API - works on all tasks, whether 64 bit or 32 bit
        IOLog("The Leopard and later way to construct a memory descriptor\n");
        memDesc = IOMemoryDescriptor::withAddressRange( clientAddr, size, kIODirectionNone, fTask );
        if (memDesc == NULL) {
            IOLog("IOMemoryDescriptor::withAddresswithAddressRange failed\n");
            err = kIOReturnVMError;
            continue;
        }
#endif
        // Wire it and make sure we can write it
        err = memDesc->prepare( kIODirectionOutIn );
        if (kIOReturnSuccess != err) {
            IOLog("IOMemoryDescriptor::prepare failed(0x%08x)\n", err);
            continue;
        }

        // Generate a DMA list for the client memory
        err = fDriver->generateDMAAddresses(memDesc);

        // Other methods to access client memory:

        // readBytes/writeBytes allow programmed I/O to/from an offset in the buffer
        char pioBuffer[ 200 ];
        memDesc->readBytes(32, &pioBuffer, sizeof(pioBuffer));
        IOLog("readBytes: \"%s\"\n", pioBuffer);

        // map() will create a mapping in the kernel address space.
        IOMemoryMap* memMap = memDesc->map();
        if (memMap) {
            char* address = (char *) memMap->getVirtualAddress();
            IOLog("kernel mapped: \"%s\"\n", address + 32);
            memMap->release();
        } else {
            IOLog("memDesc map(kernel) failed\n");
        }

        // this map() will create a mapping in the users (the client of this IOUserClient) address space.
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
        memMap = memDesc->map(fTask, 0, kIOMapAnywhere);
#else
        memMap = memDesc->createMappingInTask(fTask, 0, kIOMapAnywhere);
#endif
        if (memMap) {
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
            IOLog("The pre-Leopard way to construct a memory descriptor\n");
            // old 32 bit API - this will truncate and log a backtrace if the task is 64 bit
            IOVirtualAddress address32 = memMap->getVirtualAddress();
            IOLog("user32 mapped: " VirtAddr_FORMAT "\n", address32);
#else
            IOLog("The Leopard and later way to construct a memory descriptor\n");
            // new 64 bit API - same for 32 bit and 64 bit client tasks
            mach_vm_address_t address64 = memMap->getAddress();
            IOLog("user64 mapped: 0x%016llx\n", address64);
            memMap->release();
#endif
        } else {
            IOLog("memDesc map(user) failed\n");
        }

        // Done with the I/O now.
        memDesc->complete( kIODirectionOutIn );

    } while ( false );

    if (memDesc)
        memDesc->release();

    return err;
}
IOReturn
org_pqrs_driver_KeyRemap4MacBook_UserClient_kext::callback_synchronized_communication(const BridgeUserClientStruct* inputdata, uint64_t* outputdata)
{
  IOReturn result = kIOReturnSuccess;
  IOMemoryDescriptor* memorydescriptor = NULL;

  if (! inputdata || ! outputdata) {
    result = kIOReturnBadArgument;
    IOLOG_ERROR("UserClient_kext::callback_synchronized_communication kIOReturnBadArgument\n");
    goto finish;
  }

  if (provider_ == NULL || isInactive()) {
    // Return an error if we don't have a provider. This could happen if the user process
    // called callback_synchronized_communication without calling IOServiceOpen first.
    // Or, the user client could be in the process of being terminated and is thus inactive.
    result = kIOReturnNotAttached;
    IOLOG_ERROR("UserClient_kext::callback_synchronized_communication kIOReturnNotAttached\n");
    goto finish;
  }

  if (! provider_->isOpen(this)) {
    // Return an error if we do not have the driver open. This could happen if the user process
    // did not call callback_open before calling this function.
    result = kIOReturnNotOpen;
    IOLOG_ERROR("UserClient_kext::callback_synchronized_communication kIOReturnNotOpen\n");
    goto finish;
  }

  memorydescriptor = IOMemoryDescriptor::withAddressRange(inputdata->data, inputdata->size, kIODirectionNone, task_);
  if (! memorydescriptor) {
    result = kIOReturnVMError;
    IOLOG_ERROR("UserClient_kext::callback_synchronized_communication kIOReturnVMError\n");
    goto finish;
  }

  // wire it and make sure we can write it
  result = memorydescriptor->prepare(kIODirectionOutIn);
  if (kIOReturnSuccess != result) {
    IOLOG_ERROR("UserClient_kext::callback_synchronized_communication IOMemoryDescriptor::prepare failed(0x%x)\n", result);
    goto finish;
  }

  {
    // this map() will create a mapping in the users (the client of this IOUserClient) address space.
    IOMemoryMap* memorymap = memorydescriptor->map();
    if (! memorymap) {
      result = kIOReturnVMError;
      IOLOG_ERROR("UserClient_kext::callback_synchronized_communication IOMemoryDescriptor::map failed\n");

    } else {
      mach_vm_address_t address = memorymap->getAddress();
      handle_synchronized_communication(inputdata->type, inputdata->option, address, inputdata->size, outputdata);
      memorymap->release();
    }
  }

  // Done with the I/O now.
  memorydescriptor->complete(kIODirectionOutIn);

finish:
  if (memorydescriptor) {
    memorydescriptor->release();
  }

  return result;
}
Beispiel #20
0
IOReturn
IOSCSITape::ReadPosition(SCSI_ReadPositionShortForm *readPos, bool vendor)
{
	SCSITaskIdentifier		task			= NULL;
	IOReturn				status			= kIOReturnError;
	SCSITaskStatus			taskStatus		= kSCSITaskStatus_DeviceNotResponding;
	IOMemoryDescriptor *	dataBuffer		= NULL;
	UInt8					readPosData[20] = { 0 };
	
	dataBuffer = IOMemoryDescriptor::withAddress(&readPosData, 
												 sizeof(readPosData), 
												 kIODirectionIn);
	
	require((dataBuffer != 0), ErrorExit);
	
	task = GetSCSITask();
	
	require((task != 0), ErrorExit);
	
	if (READ_POSITION(task, 
					  dataBuffer, 
					  (vendor ? kSCSIReadPositionServiceAction_ShortFormVendorSpecific : kSCSIReadPositionServiceAction_ShortFormBlockID), 
					  0x0, 
					  0x00) == true)
	{
		taskStatus = DoSCSICommand(task, SCSI_NOMOTION_TIMEOUT);
	}
	
	if (taskStatus == kSCSITaskStatus_GOOD)
	{
		readPos->flags = readPosData[0];
		readPos->partitionNumber = readPosData[1];
		
		readPos->firstLogicalObjectLocation =
			(readPosData[4]  << 24) |
			(readPosData[5]  << 16) |
			(readPosData[6]  <<  8) |
			 readPosData[7];
		
		readPos->lastLogicalObjectLocation =
			(readPosData[8]  << 24) |
			(readPosData[9]  << 16) |
			(readPosData[10] <<  8) |
			 readPosData[11];
		
		readPos->logicalObjectsInObjectBuffer =
			(readPosData[13] << 16) |
			(readPosData[14] <<  8) |
			 readPosData[15];
		
		readPos->bytesInObjectBuffer =
			(readPosData[16] << 24) |
			(readPosData[17] << 16) |
			(readPosData[18] <<  8) |
			 readPosData[19];
		
		status = kIOReturnSuccess;
	}
	
	ReleaseSCSITask(task);
	dataBuffer->release();
	
ErrorExit:
	
	return status;
}
bool
IOFWUserLocalIsochPort::initWithUserDCLProgram ( 
		AllocateParams * 			params,
		IOFireWireUserClient & 		userclient,
		IOFireWireController &		controller )
{
	// sanity checking
	if ( params->programExportBytes == 0 )
	{
		ErrorLog ( "No program!" ) ;
		return false ;
	}
	
	fLock = IORecursiveLockAlloc () ;
	if ( ! fLock )
	{
		ErrorLog ( "Couldn't allocate recursive lock\n" ) ;
		return false ;
	}

// init easy params

	fUserObj = params->userObj ;
	fUserClient = & userclient ;
	fDCLPool = NULL ;
	fProgramCount = 0;
	fStarted = false ;

	IOReturn error = kIOReturnSuccess ;
	
// get user program ranges:

	IOAddressRange * bufferRanges = new IOAddressRange[ params->bufferRangeCount ] ;
	if ( !bufferRanges )
	{
		error = kIOReturnNoMemory ;
	}
	
	if ( !error )
	{
		error = fUserClient->copyUserData(params->bufferRanges,(mach_vm_address_t)bufferRanges, sizeof ( IOAddressRange ) * params->bufferRangeCount ) ;
	}

// create descriptor for program buffers

	IOMemoryDescriptor * bufferDesc = NULL ;
	if ( ! error )
	{
		IOByteCount length = 0 ;
		for ( unsigned index = 0; index < params->bufferRangeCount; ++index )
		{
			length += bufferRanges[ index ].length ;
		}			
	
		bufferDesc = IOMemoryDescriptor::withAddressRanges (	bufferRanges, params->bufferRangeCount, kIODirectionOutIn, 
															fUserClient->getOwningTask() ) ;
		if ( ! bufferDesc )
		{
			error = kIOReturnNoMemory ;
		}
		else
		{
		
			// IOLog( "IOFWUserLocalIsochPort::initWithUserDCLProgram - checkMemoryInRange status 0x%08lx\n", checkMemoryInRange( bufferDesc, 0x000000001FFFFFFF ) );
		
			error = bufferDesc->prepare( kIODirectionPrepareToPhys32 ) ;
			
			FWTrace( kFWTIsoch, kTPIsochPortUserInitWithUserDCLProgram, (uintptr_t)(fUserClient->getOwner()->getController()->getLink()), error, length, 0 );
			
			// IOLog( "IOFWUserLocalIsochPort::initWithUserDCLProgram - prep 32 checkMemoryInRange status 0x%08lx\n", checkMemoryInRange( bufferDesc, 0x000000001FFFFFFF ) );
			
		}
	}
	
// create map for buffers; we will need to get a virtual address for them

	IOMemoryMap * bufferMap = NULL ;
	if ( !error )
	{
		bufferMap = bufferDesc->map() ;
		if ( !bufferMap )
		{
			DebugLog( "Couldn't map program buffers\n" ) ;
			error = kIOReturnVMError ;
		}
		
		bufferDesc->release() ;
	}
	
	IOMemoryDescriptor * userProgramExportDesc = NULL ;
	if ( !error )
	{
		userProgramExportDesc = IOMemoryDescriptor::withAddressRange( 
																	 params->programData, 
																	 params->programExportBytes, 
																	 kIODirectionOut, 
																	 fUserClient->getOwningTask() ) ;
	
	}

	// get map of program export data
	if ( userProgramExportDesc )
	{
		error = userProgramExportDesc->prepare() ;
	}
	
	if ( !error )	
	{
		DCLCommand * opcodes = NULL ;
		switch ( params->version )
		{
			case kDCLExportDataLegacyVersion :

				error = importUserProgram( userProgramExportDesc, params->bufferRangeCount, bufferRanges, bufferMap ) ;
				ErrorLogCond( error, "importUserProgram returned %x\n", error ) ;

				if ( ! error )
				{
					opcodes = (DCLCommand*)fProgramBuffer ;
				}
				
				break ;

			case kDCLExportDataNuDCLRosettaVersion :

				fDCLPool = fUserClient->getOwner()->getBus()->createDCLPool() ;
				
				if ( ! fDCLPool )
				{
					error = kIOReturnNoMemory ;
				}

				if ( !error )
				{
					error = fDCLPool->importUserProgram( userProgramExportDesc, params->bufferRangeCount, bufferRanges, bufferMap ) ;
				}
				
				fProgramBuffer = new UInt8[ sizeof( DCLNuDCLLeader ) ] ;
				{
					DCLNuDCLLeader * leader = (DCLNuDCLLeader*)fProgramBuffer ;
					{
						leader->pNextDCLCommand = NULL ;	// unused - always NULL
						leader->opcode = kDCLNuDCLLeaderOp ;
						leader->program = fDCLPool ;
					}
					
					opcodes = (DCLCommand*)leader ;
				}
				
				break ;
			
			default :
			
				ErrorLog ( "unsupported DCL program type\n" ) ;
				error = kIOReturnBadArgument ;
				
				break ;
		}
		
		ErrorLogCond( !opcodes, "Couldn't get opcodes\n" ) ;
		
		IODCLProgram * program = NULL ;
		
		if ( opcodes )
		{
//			IOFWLocalIsochPort::printDCLProgram( opcodes ) ;
		
			IOFireWireBus::DCLTaskInfoAux	infoAux ;
			{
				infoAux.version = 2 ;

				infoAux.u.v2.bufferMemoryMap = bufferMap ;
				infoAux.u.v2.workloop = params->options & kFWIsochPortUseSeparateKernelThread ? createRealtimeThread() : NULL ;
				infoAux.u.v2.options = (IOFWIsochPortOptions)params->options ;
			}
						
			IOFireWireBus::DCLTaskInfo info = { 0, 0, 0, 0, 0, 0, & infoAux } ;
			
			program = fUserClient->getOwner()->getController()->getLink()->createDCLProgram(	params->talking,
																								opcodes,
																								& info,
																								params->startEvent, 
																								params->startState,
																								params->startMask ) ;

			bufferMap->release() ;		// retained by DCL program
			bufferMap = NULL ;
			
			if (  infoAux.u.v2.workloop )
			{
				// If we created a custom workloop, it will be retained by the program...
				// We can release our reference...
				infoAux.u.v2.workloop->release() ;
			}
			
			DebugLogCond( !program, "createDCLProgram returned nil\n" ) ;
		}

		if ( program )
		{
			if ( ! super::init( program, & controller ) )
			{
				ErrorLog ( "IOFWUserIsochPort::init failed\n" ) ;
				error = kIOReturnError ;
			}
		}
		else
		{
			DebugLog ( "Couldn't create DCL program\n" ) ;
			error = kIOReturnNoMemory ;
		}
		
		userProgramExportDesc->complete() ;
		userProgramExportDesc->release() ;
		userProgramExportDesc = NULL ;
	}
	
	delete [] bufferRanges ;
	
	InfoLog( "-IOFWUserLocalIsochPort::initWithUserDCLProgram error=%x (build date "__TIME__" "__DATE__")\n", error ) ;

	return ( ! error ) ;
}
IOReturn
SATSMARTUserClient::ReadLogAtAddress ( ATASMARTReadLogStruct * structIn,
                                      void * structOut,
                                      IOByteCount inStructSize,
                                      IOByteCount *outStructSize)
{
    
    IOReturn status                  = kIOReturnSuccess;
    IOSATCommand *                  command                 = NULL;
    IOMemoryDescriptor *    buffer                  = NULL;
    DEBUG_LOG("%s[%p]::%s %p(%ld) %p(%ld)\n", getClassName(), this, __FUNCTION__, structIn, (long)inStructSize, structOut, (long)(outStructSize));
    
    if ( inStructSize != sizeof ( ATASMARTReadLogStruct )  || !outStructSize || *outStructSize < 1) {
        return kIOReturnBadArgument;
    }
    
    fOutstandingCommands++;
    
    if ( isInactive ( ) )
    {
        
        status = kIOReturnNoDevice;
        goto ErrorExit;
        
    }
    
    fProvider->retain ( );
    
    command = AllocateCommand ( );
    if ( command == NULL )
    {
        
        status = kIOReturnNoResources;
        goto ReleaseProvider;
        
    }
    
    buffer = IOMemoryDescriptor::withAddress (structOut,  *outStructSize, kIODirectionIn);
    if ( buffer == NULL )
    {
        
        status = kIOReturnNoResources;
        goto ReleaseCommand;
        
    }
    
    status = buffer->prepare ( );
    DEBUG_LOG("%s[%p]::%s status %x\n", getClassName(), this, __FUNCTION__, status);
    if ( status != kIOReturnSuccess )
    {
        
        goto ReleaseBuffer;
        
    }
    
    command->setBuffer                      ( buffer );
    command->setByteCount           ( buffer->getLength());
    command->setFeatures            ( kFeaturesRegisterReadLogAtAddress );
    command->setOpcode                      ( kATAFnExecIO );
    command->setTimeoutMS           ( kATAThirtySecondTimeoutInMS );
    command->setSectorCount         ( structIn->numSectors );
    command->setSectorNumber        ( structIn->logAddress );
    command->setCylLo                       ( kSMARTMagicCylinderLoValue );
    command->setCylHi                       ( kSMARTMagicCylinderHiValue );
    command->setCommand                     ( kATAcmdSMART );
    command->setFlags                       ( mATAFlagIORead );
    
    status = SendSMARTCommand ( command );
    if ( status == kIOReturnIOError )
    {
        
        if ( command->getEndErrorReg ( ) & 0x04 )
        {
            
            ERROR_LOG ( "ReadLogAtAddress %d unsupported\n", structIn->logAddress );
            status = kIOReturnUnsupported;
            
        }
        
        if ( command->getEndErrorReg ( ) & 0x10 )
        {
            
            ERROR_LOG ( "ReadLogAtAddress %d unreadable\n", structIn->logAddress );
            status = kIOReturnNotReadable;
            
        }
        
    }
    
    *outStructSize = buffer->getLength();
    
    buffer->complete ( );
    
    
    
ReleaseBuffer:
    
    
    buffer->release ( );
    buffer = NULL;
    
    
ReleaseCommand:
    
    
    DeallocateCommand ( command );
    command = NULL;
    
    
ReleaseProvider:
    
    
    fProvider->release ( );
    
    
ErrorExit:
    
    
    fOutstandingCommands--;
    
    DEBUG_LOG("%s[%p]::%s result %d\n", getClassName(), this,  __FUNCTION__, status);
    return status;
    
}