]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMPowerStateQueue.cpp
xnu-792.25.20.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMPowerStateQueue.cpp
1 /*
2 * Copyright (c) 2001-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 #include "IOPMPowerStateQueue.h"
24 #include "IOKit/IOLocks.h"
25 #undef super
26 #define super IOEventSource
27 OSDefineMetaClassAndStructors(IOPMPowerStateQueue, IOEventSource);
28
29 #ifdef __i386__ /* ppc does this right and doesn't need these routines */
30 static
31 void * OSDequeueAtomic(void ** inList, SInt32 inOffset)
32 {
33 void * oldListHead;
34 void * newListHead;
35
36 do {
37 oldListHead = *inList;
38 if (oldListHead == NULL) {
39 break;
40 }
41
42 newListHead = *(void **) (((char *) oldListHead) + inOffset);
43 } while (! OSCompareAndSwap((UInt32)oldListHead,
44 (UInt32)newListHead, (UInt32 *)inList));
45 return oldListHead;
46 }
47
48 static
49 void OSEnqueueAtomic(void ** inList, void * inNewLink, SInt32 inOffset)
50 {
51 void * oldListHead;
52 void * newListHead = inNewLink;
53 void ** newLinkNextPtr = (void **) (((char *) inNewLink) + inOffset);
54
55 do {
56 oldListHead = *inList;
57 *newLinkNextPtr = oldListHead;
58 } while (! OSCompareAndSwap((UInt32)oldListHead, (UInt32)newListHead,
59 (UInt32 *)inList));
60 }
61 #endif /* __i386__ */
62
63
64 IOPMPowerStateQueue *IOPMPowerStateQueue::PMPowerStateQueue(OSObject *inOwner)
65 {
66 IOPMPowerStateQueue *me = new IOPMPowerStateQueue;
67
68 if(me && !me->init(inOwner, 0) )
69 {
70 me->release();
71 return NULL;
72 }
73
74 return me;
75 }
76
77 bool IOPMPowerStateQueue::init(OSObject *owner, Action action)
78 {
79 if(!(super::init(owner, (IOEventSource::Action) action))) return false;
80
81 // Queue of powerstate changes
82 changes = NULL;
83 #ifdef __i386__
84 if (!(tmpLock = IOLockAlloc())) panic("IOPMPowerStateQueue::init can't alloc lock");
85 #endif
86 return true;
87 }
88
89
90 bool IOPMPowerStateQueue::unIdleOccurred(IOService *inTarget, unsigned long inState)
91 {
92 PowerChangeEntry *new_one = NULL;
93
94 new_one = (PowerChangeEntry *)IOMalloc(sizeof(PowerChangeEntry));
95 if(!new_one) return false;
96
97 new_one->actionType = IOPMPowerStateQueue::kUnIdle;
98 new_one->state = inState;
99 new_one->target = inTarget;
100
101 // Change to queue
102 #ifdef __i386__
103 IOLockLock(tmpLock);
104 #endif
105 OSEnqueueAtomic((void **)&changes, (void *)new_one, 0);
106 #ifdef __i386__
107 IOLockUnlock(tmpLock);
108 #endif
109 signalWorkAvailable();
110
111 return true;
112 }
113
114 // checkForWork() is called in a gated context
115 bool IOPMPowerStateQueue::checkForWork()
116 {
117 PowerChangeEntry *theNode;
118 int theState;
119 IOService *theTarget;
120 UInt16 theAction;
121
122 // Dequeue and process the state change request
123 #ifdef __i386__
124 IOLockLock(tmpLock);
125 #endif
126 if((theNode = (PowerChangeEntry *)OSDequeueAtomic((void **)&changes, 0)))
127 {
128 #ifdef __i386__
129 IOLockUnlock(tmpLock);
130 #endif
131 theState = theNode->state;
132 theTarget = theNode->target;
133 theAction = theNode->actionType;
134 IOFree((void *)theNode, sizeof(PowerChangeEntry));
135
136 switch (theAction)
137 {
138 case kUnIdle:
139 theTarget->command_received((void *)theState, 0, 0, 0);
140 break;
141 }
142 }
143 #ifdef __i386__
144 else {
145 IOLockUnlock(tmpLock);
146 }
147 #endif
148 // Return true if there's more work to be done
149 if(changes) return true;
150 else return false;
151 }