IOATAPIHDDrive.cpp [plain text]
#include <IOKit/assert.h>
#include <IOKit/storage/ata/IOATAPIHDDrive.h>
#include <IOKit/storage/ata/IOATAPIHDDriveNub.h>
#define super IOATAHDDrive
OSDefineMetaClassAndStructors( IOATAPIHDDrive, IOATAHDDrive )
bool
IOATAPIHDDrive::init(OSDictionary * properties)
{
_mediaPresent = false;
_isRemovable = false;
return super::init(properties);
}
IOService *
IOATAPIHDDrive::probe(IOService * provider, SInt32 * score)
{
UInt8 deviceType;
IOService * ret = 0;
bool wasOpened = false;
if (!super::probe(provider, score))
return 0;
_ataDevice = OSDynamicCast(IOATADevice, provider);
if (_ataDevice == 0)
return 0;
do {
if (_ataDevice->open(this) == false)
break;
wasOpened = true;
if (!_ataDevice->getInquiryData(1, (ATAPIInquiry *) &deviceType) ||
!matchATAPIDeviceType(deviceType & 0x1f, score))
break;
ret = this;
}
while (false);
if (wasOpened)
_ataDevice->close(this);
_ataDevice = 0;
return ret;
}
ATADeviceType
IOATAPIHDDrive::reportATADeviceType() const
{
return kATADeviceATAPI;
}
bool
IOATAPIHDDrive::matchATAPIDeviceType(UInt8 type, SInt32 * score)
{
if (type == kIOATAPIDeviceTypeDirectAccess)
return true;
return false;
}
bool
IOATAPIHDDrive::inspectDevice(IOATADevice * device)
{
OSString * string;
string = OSDynamicCast(OSString,
device->getProperty(kATAPropertyVendorName));
if (string) {
strncpy(_vendor, string->getCStringNoCopy(), 8);
_vendor[8] = '\0';
}
string = OSDynamicCast(OSString,
device->getProperty(kATAPropertyProductName));
if (string) {
strncpy(_product, string->getCStringNoCopy(), 16);
_product[16] = '\0';
}
string = OSDynamicCast(OSString,
device->getProperty(kATAPropertyProductRevision));
if (string) {
strncpy(_revision, string->getCStringNoCopy(), 4);
_revision[4] = '\0';
}
_supportedFeatures |= kIOATAFeaturePowerManagement;
return true;
}
IOReturn
IOATAPIHDDrive::doAsyncReadWrite(IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks,
IOStorageCompletion completion)
{
IOReturn ret;
IOATACommand * cmd = atapiCommandReadWrite(buffer, block, nblks);
if (!cmd)
return kIOReturnNoMemory;
ret = asyncExecute(cmd, completion);
cmd->release();
return ret;
}
IOReturn
IOATAPIHDDrive::doSyncReadWrite(IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks)
{
IOReturn ret;
IOATACommand * cmd = atapiCommandReadWrite(buffer, block, nblks);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
cmd->release();
return ret;
}
IOReturn
IOATAPIHDDrive::doEjectMedia()
{
IOReturn ret;
IOATACommand * cmd = atapiCommandStartStopUnit(false,
true,
false);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
cmd->release();
return ret;
}
IOReturn
IOATAPIHDDrive::doFormatMedia(UInt64 byteCapacity,
IOMemoryDescriptor * formatData = 0)
{
IOReturn ret;
IOATACommand * cmd = atapiCommandFormatUnit(0, 0, 0, formatData);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd, 15 * 60 * 1000);
cmd->release();
return ret;
}
IOReturn
IOATAPIHDDrive::doLockUnlockMedia(bool doLock)
{
IOReturn ret;
IOATACommand * cmd = atapiCommandPreventAllowRemoval(doLock);
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
cmd->release();
_isLocked = doLock;
return ret;
}
IOReturn
IOATAPIHDDrive::doSynchronizeCache()
{
IOReturn ret;
IOATACommand * cmd = atapiCommandSynchronizeCache();
if (!cmd)
return kIOReturnNoMemory;
ret = syncExecute(cmd);
cmd->release();
return ret;
}
IOReturn
IOATAPIHDDrive::doStart()
{
return doStartStop(true);
}
IOReturn
IOATAPIHDDrive::doStop()
{
return doStartStop(false);
}
IOReturn
IOATAPIHDDrive::doStartStop(bool doStart)
{
IOReturn ret;
IOATACommand * cmd;
cmd = atapiCommandStartStopUnit(doStart,
false,
false);
if (!cmd) return kIOReturnNoMemory;
ret = syncExecute(cmd);
cmd->release();
return ret;
}
char * IOATAPIHDDrive::getVendorString()
{
return _vendor;
}
char * IOATAPIHDDrive::getProductString()
{
return _product;
}
char * IOATAPIHDDrive::getRevisionString()
{
return _revision;
}
char * IOATAPIHDDrive::getAdditionalDeviceInfoString()
{
return ("[ATAPI]");
}
IOReturn
IOATAPIHDDrive::reportEjectability(bool * isEjectable)
{
*isEjectable = true;
return kIOReturnSuccess;
}
IOReturn
IOATAPIHDDrive::reportLockability(bool * isLockable)
{
*isLockable = true;
return kIOReturnSuccess;
}
IOReturn
IOATAPIHDDrive::reportPollRequirements(bool * pollRequired,
bool * pollIsExpensive)
{
*pollIsExpensive = false;
*pollRequired = _isRemovable;
return kIOReturnSuccess;
}
IOReturn
IOATAPIHDDrive::reportMediaState(bool * mediaPresent,
bool * changed)
{
IOATACommand * cmd = 0;
IOMemoryDescriptor * senseData = 0;
UInt8 senseBuf[18];
ATAResults results;
IOReturn ret;
assert(mediaPresent && changed);
do {
ret = kIOReturnNoMemory;
bzero((void *) senseBuf, sizeof(senseBuf));
senseData = IOMemoryDescriptor::withAddress(senseBuf,
sizeof(senseBuf),
kIODirectionIn);
if (!senseData)
break;
cmd = atapiCommandTestUnitReady();
if (!cmd)
break;
syncExecute(cmd, kATADefaultTimeout, kATAZeroRetry, senseData);
ret = kIOReturnSuccess;
if (cmd->getResults(&results) == kIOReturnSuccess)
{
*mediaPresent = true;
*changed = (*mediaPresent != _mediaPresent);
_mediaPresent = true;
}
else
{
UInt8 errorCode = senseBuf[0];
UInt8 senseKey = senseBuf[2];
#ifdef DEBUG_LOG
UInt8 senseCode = senseBuf[12];
UInt8 senseQualifier = senseBuf[13];
IOLog("-- IOATAPIHDDrive::reportMediaState --\n");
IOLog("Error code: %02x\n", errorCode);
IOLog("Sense Key : %02x\n", senseKey);
IOLog("ASC : %02x\n", senseCode);
IOLog("ASCQ : %02x\n", senseQualifier);
#endif
*mediaPresent = false;
*changed = (*mediaPresent != _mediaPresent);
_mediaPresent = false;
if ((errorCode == 0x70) || (errorCode == 0x71))
{
switch (senseKey) {
case 5:
ret = kIOReturnIOError;
break;
case 2:
break;
default:
break;
}
}
}
}
while (false);
if (cmd)
cmd->release();
if (senseData)
senseData->release();
#if 0
IOLog("%s: media present %s, changed %s\n", getName(),
*mediaPresent ? "Y" : "N",
*changed ? "Y" : "N"
);
#endif
return ret;
}
IOReturn
IOATAPIHDDrive::reportRemovability(bool * isRemovable)
{
UInt8 inqBuf[2];
*isRemovable = false;
if (_ataDevice->getInquiryData(sizeof(inqBuf), (ATAPIInquiry *) inqBuf))
{
if (inqBuf[1] & 0x80)
*isRemovable = _isRemovable = true;
else
*isRemovable = _isRemovable = false;
}
return kIOReturnSuccess;
}
IOReturn
IOATAPIHDDrive::reportWriteProtection(bool * isWriteProtected)
{
*isWriteProtected = false; return kIOReturnSuccess;
}
IOService *
IOATAPIHDDrive::instantiateNub()
{
IOService * nub = new IOATAPIHDDriveNub;
return nub;
}
void
IOATAPIHDDrive::handleActiveStateTransition( UInt32 stage, IOReturn status )
{
if ( ( stage == kIOATAActiveStage0 ) && _isLocked )
{
IOStorageCompletion completion;
IOReturn ret;
IOATACommand * cmd = atapiCommandPreventAllowRemoval( true );
completion.target = this;
completion.action = sHandleActiveStateTransition;
completion.parameter = (void *) kIOATAActiveStage1;
if ( cmd )
{
cmd->setQueueInfo( kATAQTypeBypassQ );
ret = asyncExecute( cmd, completion );
cmd->release();
}
}
else
{
super::handleActiveStateTransition( stage, status );
}
}