/*
 * Copyright (C) 2002 Andreas Thiede ( a.thiede@berlin.de )
 * 
 * based on:
 *
 * 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@
 */
/*
 * Copyright (c) 2000 Apple Computer, Inc.  All rights reserved.
 *
 *  DRI: Josh de Cesare
 *
 */

#include <IOKit/IOLib.h>
#include <IOKit/IOCommandGate.h>
#include <vm/vm_kern.h>

#include "Bt8xx.h"
#include "Bt8xxRegs.h"
#include "Bt8xxImpl.h"
#include "Bt8xxUserClient.h"

static Bt8xxImpl * implementationInstance = 0;

#define IOErr IOLog

#define super IOService

OSDefineMetaClassAndStructors( Bt8xx, IOService );

#if 0

WorkLoop *Bt8xx::getWorkLoop(void)
{

    return instance()->getWorkLoop();
}
#endif

/* static */ void Bt8xx::interruptOccurred( OSObject *object, IOInterruptEventSource * eventSource, int count)
{
    //IOLog("Bt8xx::interruptOccurred\n" );

#if 1

    ((Bt8xx *)object)->instance()->handleInterrupt( eventSource, count);
#endif
}


Bt8xxImpl * Bt8xx::instance()
{
    return mImpl;
}

bool Bt8xx::init(OSDictionary *dictionary)
{
    IOLog("Bt8xx::init\n");

    bool res;
  
    res = super::init(dictionary);

#if HAVE_HAVE_PM

    mCurrentPowerState = 1;

#endif

    IOLog("Bt8xx::init done\n");
  
    return res;
}

void Bt8xx::free(void)
{
    IOLog("Bt8xx::free\n");
  
    super::free();

    mImpl->finit();
    
    mImpl->release();
  
    IOLog("Bt8xx::free done\n");

}

bool Bt8xx::attach(IOService *provider)
{
  IOLog("Bt8xx::attach\n");

  bool res;
  
  res = super::attach(provider);
  
  IOLog("Bt8xx::attach done\n");

  return res;
}

void Bt8xx::detach(IOService *provider)
{
    IOLog("Bt8xx::detach\n");

    super::detach(provider);

    IOLog("Bt8xx::detach done\n");
}


IOService *Bt8xx::probe(IOService *provider, SInt32 *score)
{
    IOLog("Bt8xx::probe this(%p)\n", this );
    
    IOService * instance = super::probe(provider, score);

    if( instance ) {

        if( implementationInstance == 0 ) {
        
            implementationInstance = new Bt8xxImpl;
            
            implementationInstance->initWithOwner( this );
        }
        else {
            implementationInstance->retain();
        }
        
        mImpl = implementationInstance;
    }
    
    IOLog("Bt8xx::probe done this(%p) instance(%p) mImpl(%p)\n", this, instance, mImpl );
      
    return instance;
}

bool Bt8xx::start( IOService *provider )
{
    bool ret = kIOReturnError;
    
    IOLog("Bt8xx::start instance(%p) provider(%p)\n", this, provider );

    if (!super::start(provider))  {
        IOErr("Bt8xx::start failed\n");
        return false;
    }
    
    ret = instance()->start( provider );
    
    if( ret == true ) {

        IOLog("Bt8xx::start registerService\n");

        registerService();

#if HAVE_HAVE_PM
        
        PMinit();
        
        provider->joinPMtree( this );
        
        registerWithPolicyMaker( this );
#endif        
    }

    
    IOLog("Bt8xx::start done\n");
  
    return ret;
}

void Bt8xx::stop(IOService *provider)
{
    IOLog("Bt8xx::stop\n");

#if HAVE_HAVE_PM

    PMstop();
#endif

    super::stop(provider);

    instance()->stop( provider );

    IOLog("Bt8xx::stop done\n");
}


IOReturn Bt8xx::newUserClient(task_t owningTask, void *security_id,
				   UInt32 type, IOUserClient **handler)
{
  IOLog("Bt8xx::newUserClient thisThread(%p) workLoopThread(%p)\n", IOThreadSelf() ,
    instance()->getWorkLoop()->getThread() );

  IOUserClient * newUserClient;
  
  if( instance()->mUserClient != 0 ) return kIOReturnExclusiveAccess;
  
  newUserClient = Bt8xxUserClient::withTask(owningTask);

  if( newUserClient ) {

    if( ! newUserClient->attach(this) || ! newUserClient->start(this) ) {

      newUserClient->detach(this);
      newUserClient->release();

    } else {
      instance()->mUserClient = newUserClient;
    }
  }
  
  if ( instance()->mUserClient == 0) return kIOReturnNotOpen;
  
  *handler = instance()->mUserClient;
  
  instance()->clientStart();

  
  IOLog("Bt8xx::newUserClient done\n");
  
  return kIOReturnSuccess;
}

void Bt8xx::close(void)
{
#if 0

    instance()->clientStop();
#endif

    instance()->mUserClient = 0;

}

#if 0

struct IOPMPowerState
{
 unsigned long  version;                // version number of this struct
IOPMPowerFlags  capabilityFlags;        // bits that describe (to interested drivers) the capability of the device in this state 
IOPMPowerFlags  outputPowerCharacter;   // description (to power domain children) of the power provided in this state 
IOPMPowerFlags  inputPowerRequirement;  // description (to power domain parent) of input power required in this state
unsigned long   staticPower;    // average consumption in milliwatts
unsigned long   unbudgetedPower;        // additional consumption from separate power supply (mw)
unsigned long   powerToAttain;  // additional power to attain this state from next lower state (in mw)
unsigned long   timeToAttain;   // time required to enter this state from next lower state (in microseconds)
unsigned long   settleUpTime;   // settle time required after entering this state from next lower state (microseconds)
unsigned long   timeToLower;    // time required to enter next lower state from this one (in microseconds)
unsigned long   settleDownTime; // settle time required after entering next lower state from this state (microseconds)
unsigned long   powerDomainBudget;      // power in mw a domain in this state can deliver to its children
};

#endif

#if HAVE_HAVE_PM

IOReturn Bt8xx::registerWithPolicyMaker( IOService * policyMaker )
{
    IOLog("Bt8xxImpl: registerWithPolicyMaker\n");

#define number_of_power_states 2

    static IOPMPowerState ourPowerStates[number_of_power_states] = {
        {1,0,0,0,0,0,0,0,0,0,0,0},
        {1,IOPMDeviceUsable|IOPMWakeupEnabled,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0}
        };

    mCurrentPowerState = 1;

    return policyMaker->registerPowerDriver( this, ourPowerStates, number_of_power_states );
}

IOReturn Bt8xx::setPowerState( unsigned long powerStateOrdinal, IOService *   whatDevice )
{
    IOReturn ret = IOPMAckImplied;

    IOLog("Bt8xxImpl: setPowerState %ld\n", powerStateOrdinal);

    if ( mCurrentPowerState == powerStateOrdinal )
        return IOPMAckImplied;

    switch ( powerStateOrdinal )     {

        case 0:
            kprintf("Bt8xx: powering off\n");
            mCurrentPowerState = powerStateOrdinal;
            break;

        case 1:
            kprintf("Bt8xx: powering on\n");
            //_powerUp();
            mCurrentPowerState = powerStateOrdinal;
            break;

        default:
            ret = IOPMNoSuchState;
            break;
    }

    IOLog("Bt8xx: setPowerState - returning\n");

    return ret;
}

#endif // HAVE_HAVE_PM
