AppleGenericPCATADriver.cpp [plain text]
#include <IOKit/IOMessage.h>
#include <IOKit/ata/IOATATypes.h>
#include <IOKit/ata/IOATAController.h>
#include <IOKit/ata/ATADeviceNub.h>
#include "AppleGenericPCATAController.h"
#include "AppleGenericPCATADriver.h"
#define super IOATAController
OSDefineMetaClassAndStructors( AppleGenericPCATADriver, IOATAController )
#ifdef DEBUG
#define DLOG(fmt, args...) IOLog(fmt, ## args)
#else
#define DLOG(fmt, args...)
#endif
bool
AppleGenericPCATADriver::start( IOService * provider )
{
DLOG("%s::%s( %p )\n", getName(), __FUNCTION__, provider);
_provider = OSDynamicCast( AppleGenericPCATAController, provider );
if ( _provider == 0 )
goto fail;
_provider->retain();
if ( _provider->open( this ) != true )
{
IOLog("%s: provider open failed\n", getName());
goto fail;
}
_ioPorts = _provider->getIOPorts();
if ( super::start(_provider) == false )
{
IOLog("%s: super start failed\n", getName());
goto fail;
}
_intSrc = IOInterruptEventSource::interruptEventSource(
(OSObject *) this,
(IOInterruptEventAction) &interruptOccurred,
_provider, 0 );
if ( !_intSrc || !_workLoop ||
(_workLoop->addEventSource(_intSrc) != kIOReturnSuccess) )
{
IOLog("%s: interrupt event source error\n", getName());
goto fail;
}
_intSrc->enable();
for ( UInt32 i = 0; i < 2; i++ )
{
if ( _devInfo[i].type != kUnknownATADeviceType )
{
ATADeviceNub * nub;
nub = ATADeviceNub::ataDeviceNub( (IOATAController*) this,
(ataUnitID) i,
_devInfo[i].type );
if ( nub )
{
if ( nub->attach( this ) )
{
_nub[i] = (IOATADevice *) nub;
_nub[i]->retain();
_nub[i]->registerService();
}
nub->release();
}
}
}
IOLog("%s: Port 0x%x, IRQ %ld\n", getName(),
_ioPorts, _provider->getInterruptLine());
return true;
fail:
if ( _provider )
{
_provider->close( this );
}
return false;
}
void
AppleGenericPCATADriver::free()
{
#define RELEASE(x) do { if(x) { (x)->release(); (x) = 0; } } while(0)
DLOG("%s::%s()\n", getName(), __FUNCTION__);
RELEASE( _intSrc );
RELEASE( _nub[0] );
RELEASE( _nub[1] );
RELEASE( _provider );
RELEASE( _tfDataReg );
RELEASE( _tfFeatureReg );
RELEASE( _tfSCountReg );
RELEASE( _tfSectorNReg );
RELEASE( _tfCylLoReg );
RELEASE( _tfCylHiReg );
RELEASE( _tfSDHReg );
RELEASE( _tfStatusCmdReg );
RELEASE( _tfAltSDevCReg );
if ( _doubleBuffer.logicalBuffer )
{
IOFree( (void *) _doubleBuffer.logicalBuffer,
_doubleBuffer.bufferSize );
_doubleBuffer.bufferSize = 0;
_doubleBuffer.logicalBuffer = 0;
_doubleBuffer.physicalBuffer = 0;
}
super::free();
}
IOWorkLoop *
AppleGenericPCATADriver::getWorkLoop() const
{
DLOG("%s::%s()\n", getName(), __FUNCTION__);
return ( _workLoop ) ? _workLoop :
IOWorkLoop::workLoop();
}
bool
AppleGenericPCATADriver::configureTFPointers()
{
DLOG("%s::%s()\n", getName(), __FUNCTION__);
_tfDataReg = IOATAIOReg16::withAddress( _ioPorts + 0 );
_tfFeatureReg = IOATAIOReg8::withAddress( _ioPorts + 1 );
_tfSCountReg = IOATAIOReg8::withAddress( _ioPorts + 2 );
_tfSectorNReg = IOATAIOReg8::withAddress( _ioPorts + 3 );
_tfCylLoReg = IOATAIOReg8::withAddress( _ioPorts + 4 );
_tfCylHiReg = IOATAIOReg8::withAddress( _ioPorts + 5 );
_tfSDHReg = IOATAIOReg8::withAddress( _ioPorts + 6 );
_tfStatusCmdReg = IOATAIOReg8::withAddress( _ioPorts + 7 );
_tfAltSDevCReg = IOATAIOReg8::withAddress( _ioPorts + 0x206 );
if ( !_tfDataReg || !_tfFeatureReg || !_tfSCountReg ||
!_tfSectorNReg || !_tfCylLoReg || !_tfCylHiReg ||
!_tfSDHReg || !_tfStatusCmdReg || !_tfAltSDevCReg )
{
return false;
}
return true;
}
void
AppleGenericPCATADriver::interruptOccurred( OSObject * owner,
IOInterruptEventSource * evtSrc,
int count )
{
AppleGenericPCATADriver * self = (AppleGenericPCATADriver *) owner;
self->handleDeviceInterrupt();
}
UInt32
AppleGenericPCATADriver::scanForDrives()
{
DLOG("%s::%s()\n", getName(), __FUNCTION__);
*_tfAltSDevCReg = mATADCRReset;
IODelay( 100 );
*_tfAltSDevCReg = 0x0;
IOSleep( 10 );
return super::scanForDrives();
}
IOReturn AppleGenericPCATADriver::provideBusInfo( IOATABusInfo * infoOut )
{
UInt32 pioModes;
DLOG("%s::%s( %p )\n", getName(), __FUNCTION__, infoOut);
if ( infoOut == 0 )
{
IOLog("%s::provideBusInfo bad argument\n", getName());
return -1;
}
pioModes = (1 << (_provider->getPIOMode() + 1)) - 1;
infoOut->zeroData();
infoOut->setSocketType( kInternalATASocket );
infoOut->setPIOModes( pioModes );
infoOut->setDMAModes( 0x00 ); infoOut->setUltraModes( 0x00 );
UInt8 units = 0;
if ( _devInfo[0].type != kUnknownATADeviceType ) units++;
if ( _devInfo[1].type != kUnknownATADeviceType ) units++;
infoOut->setUnits( units );
return kATANoErr;
}
IOReturn
AppleGenericPCATADriver::getConfig( IOATADevConfig * configOut,
UInt32 unitNumber )
{
const UInt16 cycleTimes[5] = { 600, 383, 240, 180, 120 };
UInt32 pioMode;
DLOG("%s::%s( %p, %ld )\n", getName(), __FUNCTION__,
configOut, unitNumber);
if ( (configOut == 0) || (unitNumber > kATADevice1DeviceID) )
{
IOLog("%s::getConfig bad argument\n", getName());
return -1;
}
pioMode = _provider->getPIOMode();
configOut->setPIOMode( 1 << pioMode );
configOut->setDMAMode( 0x00 );
configOut->setUltraMode( 0x00 );
if ( pioMode >= (sizeof(cycleTimes) / sizeof(cycleTimes[0])) )
pioMode = sizeof(cycleTimes) / sizeof(cycleTimes[0]) - 1;
configOut->setPIOCycleTime( cycleTimes[pioMode] );
configOut->setPacketConfig( _devInfo[unitNumber].packetSend );
return kATANoErr;
}
IOReturn
AppleGenericPCATADriver::selectConfig( IOATADevConfig * configRequest,
UInt32 unitNumber )
{
DLOG("%s::%s( %p, %ld )\n", getName(), __FUNCTION__,
configRequest, unitNumber);
if ( (configRequest == 0) || (unitNumber > kATADevice1DeviceID) )
{
DLOG("%s::selectConfig bad argument\n", getName());
return -1;
}
_devInfo[unitNumber].packetSend = configRequest->getPacketConfig();
return kATANoErr;
}
IOReturn
AppleGenericPCATADriver::handleQueueFlush()
{
UInt32 savedQstate = _queueState;
DLOG("%s::%s()\n", getName(), __FUNCTION__);
_queueState = IOATAController::kQueueLocked;
IOATABusCommand * cmdPtr = 0;
while ( cmdPtr = dequeueFirstCommand() )
{
cmdPtr->setResult( kIOReturnError );
cmdPtr->executeCallback();
}
_queueState = savedQstate;
return kATANoErr;
}
IOReturn
AppleGenericPCATADriver::message( UInt32 type,
IOService * provider,
void * argument )
{
if ( ( provider == _provider ) &&
( type == kIOMessageServiceIsTerminated ) )
{
_provider->close( this );
return kIOReturnSuccess;
}
return super::message( type, provider, argument );
}