/*
 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

#include "AppleGenericPCATAController.h"
#include "AppleGenericPCATAKeys.h"

#define super IOService
OSDefineMetaClassAndStructors( AppleGenericPCATAController, IOService )

static bool
getOSNumberValue( const OSDictionary * dict,
                  const char         * key,
                  UInt32             * outValue )
{
    OSNumber * num = OSDynamicCast( OSNumber, dict->getObject( key ) );
    if ( num )
    {
        *outValue = num->unsigned32BitValue();
        return true;
    }
    return false;
}

//---------------------------------------------------------------------------
//
// Create the interrupt properties.
//

bool
AppleGenericPCATAController::setupInterrupt( UInt32 line )
{
	OSArray *         controller = 0;
	OSArray *         specifier  = 0;
	OSData *          tmpData    = 0;
    bool              ret        = false;
	extern OSSymbol * gIntelPICName;

	do {
		// Create the interrupt specifer array.
        // This specifies the interrupt line.

		specifier = OSArray::withCapacity(1);
		if ( !specifier ) break;

        tmpData = OSData::withBytes( &line, sizeof(line) );
        if ( !tmpData ) break;

        specifier->setObject( tmpData );

        // Next the interrupt controller array.

        controller = OSArray::withCapacity(1);
        if ( !controller ) break;

        controller->setObject( gIntelPICName );

        // Put the two arrays into our property table.
        
        ret = setProperty( gIOInterruptControllersKey, controller )
           && setProperty( gIOInterruptSpecifiersKey,  specifier );
    }
    while( false );
    
    if ( controller ) controller->release();
    if ( specifier  ) specifier->release();
    if ( tmpData    ) tmpData->release();
    
    return ret;
}

//---------------------------------------------------------------------------
//
// Initialize the ATA controller object.
//

bool
AppleGenericPCATAController::init( OSDictionary * dictionary )
{
    if ( super::init(dictionary) == false )
        return false;

    // Fetch the port address and interrupt line properties from
    // the dictionary provided.

	if ( !getOSNumberValue( dictionary, kPortAddressKey, &_ioPorts )
      || !getOSNumberValue( dictionary, kInterruptLineKey, &_irq )
      || !getOSNumberValue( dictionary, kPIOModeKey, &_pioMode )
       ) return false;

    if ( !setupInterrupt( _irq ) )
        return false;

    return true;
}

//---------------------------------------------------------------------------
//
// Handle open and close from our client.
//

bool
AppleGenericPCATAController::handleOpen( IOService *  client,
                                         IOOptionBits options,
                                         void *       arg )
{
    bool ret = false;

    if ( _provider && _provider->open( this, 0, arg ) )
    {
        ret = super::handleOpen( client, options, arg );
        if ( ret == false )
            _provider->close( this );
    }
    
    return ret;
}

void
AppleGenericPCATAController::handleClose( IOService *  client,
                                          IOOptionBits options )
{
    super::handleClose( client, options );
	if ( _provider ) _provider->close( this );
}

//---------------------------------------------------------------------------
//
// Set and clear our provider reference when attached and detached
// to a parent in the service plane.
//

bool
AppleGenericPCATAController::attachToParent( IORegistryEntry *       parent,
                                             const IORegistryPlane * plane )
{
	bool ret = super::attachToParent( parent, plane );
	if ( ret && (plane == gIOServicePlane) )
        _provider = (IOService *) parent;
	return ret;
}

void
AppleGenericPCATAController::detachFromParent( IORegistryEntry *       parent,
                                               const IORegistryPlane * plane )
{
    if ( plane == gIOServicePlane ) _provider = 0;
    return super::detachFromParent( parent, plane );
}

//---------------------------------------------------------------------------
//
// Accessor functions to assist our client.
//

UInt32
AppleGenericPCATAController::getIOPorts() const
{
    return _ioPorts;
}

UInt32
AppleGenericPCATAController::getInterruptLine() const
{
    return _irq;
}

UInt32
AppleGenericPCATAController::getPIOMode() const
{
    return _pioMode;
}
