/*
 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code 
 * as defined in and that are subject to the Apple Public Source License 
 * Version 2.0 (the 'License'). You may not use this file except in 
 * compliance with the License.  The rights granted to you under the 
 * License may not be used to create, or enable the creation or 
 * redistribution of, unlawful or unlicensed copies of an Apple operating 
 * system, or to circumvent, violate, or enable the circumvention or 
 * violation of, any terms of an Apple operating system software license 
 * agreement.
 *
 * Please obtain a copy of the License at 
 * http://www.opensource.apple.com/apsl/ and read it before using this 
 * file.
 *
 * The 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
 * Please see the License for the specific language governing rights and 
 * limitations under the License.
 *
 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
 */
#include <IOKit/pwr_mgt/IOPM.h>
#include <IOKit/pwr_mgt/IOPMchangeNoteList.h>
#include <IOKit/pwr_mgt/IOPowerConnection.h>

#define super OSObject
OSDefineMetaClassAndStructors(IOPMchangeNoteList,OSObject)

//*********************************************************************************
// init
//
//*********************************************************************************
void IOPMchangeNoteList::initialize ( void )
{
    long i;

    firstInList = 0;
    firstUnused = 0;
    for ( i = 0; i < IOPMMaxChangeNotes; i++ ) {
        changeNote[i].flags = IOPMNotInUse;
    }
}

//*********************************************************************************
// createChangeNote
//
//*********************************************************************************

long IOPMchangeNoteList::createChangeNote ( void )
{
    unsigned long i, j;

    i = increment(firstUnused);
    if ( firstInList == i ) {
        return -1;
    }
    j = firstUnused;
    firstUnused = i;

    return j;
}

//*********************************************************************************
// currentChange
//
// Return the ordinal of the first change note in the list.
// If the list is empty, return -1.
//*********************************************************************************

long IOPMchangeNoteList::currentChange ( void )
{
    if ( firstUnused == firstInList ) {
        return -1;
    }
    else {
        return firstInList;
    }
}

//*********************************************************************************
// latestChange
//
// Return the ordinal of the last change note in the list.
// If the list is empty, return -1.
//*********************************************************************************

long IOPMchangeNoteList::latestChange ( void )
{
    if ( firstUnused == firstInList ) {
        return -1;
    }
    else {
        return decrement(firstUnused);
    }
}

//*********************************************************************************
// releaseHeadChangeNote
//
// Mark the head node unused.
// This happens when the first change in the list is completely processed.
// That is, all interested parties have acknowledged it, and power is settled
// at the new level.
//*********************************************************************************

IOReturn IOPMchangeNoteList::releaseHeadChangeNote ( void )
{
    IOPowerConnection *tmp;

    if((tmp = changeNote[firstInList].parent)) {
       changeNote[firstInList].parent = 0;
       tmp->release();
    }

    changeNote[firstInList].flags = IOPMNotInUse;
    firstInList = increment(firstInList);
    return IOPMNoErr;
}

//*********************************************************************************
// releaseTailChangeNote
//
// Mark the tail node unused.
// This happens when a power change is queued up after another which has
// not yet been started, and the second one supercedes the first.  The data in
// the second is copied into the first and the the second is released.  This
// collapses the first change out of the list.
//*********************************************************************************

IOReturn IOPMchangeNoteList::releaseTailChangeNote ( void )
{
    IOPowerConnection *tmp;
    
    if((tmp = changeNote[firstInList].parent)) {
       changeNote[firstInList].parent = 0;
       tmp->release();
    }

    firstUnused = decrement(firstUnused);
    changeNote[firstUnused].flags = IOPMNotInUse;
    return IOPMNoErr;
}

//*********************************************************************************
// changeNoteInUse
//
//*********************************************************************************

bool IOPMchangeNoteList::changeNoteInUse ( unsigned long ordinal )
{
    if ( changeNote[ordinal].flags == IOPMNotInUse ) {
        return false;
    }
    else {
        return true;
    }
}

//*********************************************************************************
// nextChangeNote
//
// If the parameter corresponds to the most recent power change notification
// passed to drivers and children, return -1.  Otherwise, return the array
// position of the next notification in the circular list.
//*********************************************************************************

long IOPMchangeNoteList::nextChangeNote ( unsigned long ordinal )
{
    unsigned long i;

    i = increment(ordinal);
    if ( i == firstUnused)  {
        return -1;
    }
    return ( i );
}

//*********************************************************************************
// increment
//
// Increment the parameter mod the circular list size and return it.
//*********************************************************************************

unsigned long IOPMchangeNoteList::increment ( unsigned long ordinal )
{
    if ( ordinal == (IOPMMaxChangeNotes - 1) ) {
        return 0;
    }
    else {
        return ordinal + 1;
    }
}

//*********************************************************************************
// decrement
//
// Decrement the parameter mod the circular list size and return it.
//*********************************************************************************

unsigned long IOPMchangeNoteList::decrement ( unsigned long  ordinal )
{
    if ( ordinal == 0 ) {
        return IOPMMaxChangeNotes - 1;
    }
    else {
        return ordinal - 1;
    }
}

//*********************************************************************************
// previousChangeNote
//
// If the parameter corresponds to the oldest power change notification
// passed to drivers and children, return -1.  Otherwise, return the array
// position of the previous notification in the circular list.
//*********************************************************************************

long IOPMchangeNoteList::previousChangeNote ( unsigned long ordinal )
{
    if ( ordinal == firstInList )  {
        return -1;
    }
    return decrement(ordinal);
}

//*********************************************************************************
// listEmpty
//
//*********************************************************************************

bool IOPMchangeNoteList::listEmpty ( void )
{
    return ( firstInList == firstUnused ) ;
}
