1/* 2 * Copyright (c) 2001-2002 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include "IOPMPowerStateQueue.h" 30#include "IOKit/IOLocks.h" 31#undef super 32#define super IOEventSource 33OSDefineMetaClassAndStructors(IOPMPowerStateQueue, IOEventSource); 34 35#ifndef __ppc__ /* ppc does this right and doesn't need these routines */ 36static 37void * OSDequeueAtomic(void * volatile * inList, SInt32 inOffset) 38{ 39 /* The _pointer_ is volatile, not the listhead itself */ 40 void * volatile oldListHead; 41 void * volatile newListHead; 42 43 do { 44 oldListHead = *inList; 45 if (oldListHead == NULL) { 46 break; 47 } 48 49 newListHead = *(void * volatile *) (((char *) oldListHead) + inOffset); 50 } while (! OSCompareAndSwap((UInt32)oldListHead, 51 (UInt32)newListHead, (volatile UInt32 *)inList)); 52 return oldListHead; 53} 54 55static 56void OSEnqueueAtomic(void * volatile * inList, void * inNewLink, SInt32 inOffset) 57{ 58 /* The _pointer_ is volatile, not the listhead itself */ 59 void * volatile oldListHead; 60 void * volatile newListHead = inNewLink; 61 void * volatile * newLinkNextPtr = (void * volatile *) (((char *) inNewLink) + inOffset); 62 63 do { 64 oldListHead = *inList; 65 *newLinkNextPtr = oldListHead; 66 } while (! OSCompareAndSwap((UInt32)oldListHead, (UInt32)newListHead, 67 (volatile UInt32 *)inList)); 68} 69#endif /* ! __ppc__ */ 70 71 72IOPMPowerStateQueue *IOPMPowerStateQueue::PMPowerStateQueue(OSObject *inOwner) 73{ 74 IOPMPowerStateQueue *me = new IOPMPowerStateQueue; 75 76 if(me && !me->init(inOwner, 0) ) 77 { 78 me->release(); 79 return NULL; 80 } 81 82 return me; 83} 84 85bool IOPMPowerStateQueue::init(OSObject *owner, Action action) 86{ 87 if(!(super::init(owner, (IOEventSource::Action) action))) return false; 88 89 // Queue of powerstate changes 90 changes = NULL; 91#ifndef __ppc__ 92 if (!(tmpLock = IOLockAlloc())) panic("IOPMPowerStateQueue::init can't alloc lock"); 93#endif 94 return true; 95} 96 97 98bool IOPMPowerStateQueue::unIdleOccurred(IOService *inTarget, unsigned long inState) 99{ 100 PowerChangeEntry *new_one = NULL; 101 102 new_one = (PowerChangeEntry *)IOMalloc(sizeof(PowerChangeEntry)); 103 if(!new_one) return false; 104 105 new_one->actionType = IOPMPowerStateQueue::kUnIdle; 106 new_one->state = inState; 107 new_one->target = inTarget; 108 109 // Change to queue 110#ifndef __ppc__ 111 IOLockLock(tmpLock); 112#endif 113 OSEnqueueAtomic((void **)&changes, (void *)new_one, 0); 114#ifndef __ppc__ 115 IOLockUnlock(tmpLock); 116#endif 117 signalWorkAvailable(); 118 119 return true; 120} 121 122bool IOPMPowerStateQueue::featureChangeOccurred( 123 uint32_t inState, 124 IOService *inTarget) 125{ 126 PowerChangeEntry *new_one = NULL; 127 128 new_one = (PowerChangeEntry *)IOMalloc(sizeof(PowerChangeEntry)); 129 if(!new_one) return false; 130 131 new_one->actionType = IOPMPowerStateQueue::kPMFeatureChange; 132 new_one->state = inState; 133 new_one->target = inTarget; 134 135 // Change to queue 136#ifdef __i386__ 137 IOLockLock(tmpLock); 138#endif 139 OSEnqueueAtomic((void **)&changes, (void *)new_one, 0); 140#ifdef __i386__ 141 IOLockUnlock(tmpLock); 142#endif 143 signalWorkAvailable(); 144 145 return true; 146} 147 148 149// checkForWork() is called in a gated context 150bool IOPMPowerStateQueue::checkForWork() 151{ 152 PowerChangeEntry *theNode; 153 uint32_t theState; 154 IOService *theTarget; 155 uint16_t theAction; 156 157 // Dequeue and process the state change request 158#ifndef __ppc__ 159 IOLockLock(tmpLock); 160#endif 161 if((theNode = (PowerChangeEntry *)OSDequeueAtomic((void **)&changes, 0))) 162 { 163#ifndef __ppc__ 164 IOLockUnlock(tmpLock); 165#endif 166 theState = theNode->state; 167 theTarget = theNode->target; 168 theAction = theNode->actionType; 169 IOFree((void *)theNode, sizeof(PowerChangeEntry)); 170 171 switch (theAction) 172 { 173 case kUnIdle: 174 theTarget->command_received((void *)theState, 0, 0, 0); 175 break; 176 177 case kPMFeatureChange: 178 theTarget->messageClients(theState, theTarget); 179 break; 180 } 181 } 182#ifndef __ppc__ 183 else { 184 IOLockUnlock(tmpLock); 185 } 186#endif 187 // Return true if there's more work to be done 188 if(changes) return true; 189 else return false; 190} 191