]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMWorkArbiter.cpp
xnu-792.18.15.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMWorkArbiter.cpp
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 "IOPMWorkArbiter.h"
30 #include "IOKit/IOLocks.h"
31 #undef super
32 #define super IOEventSource
33 OSDefineMetaClassAndStructors(IOPMWorkArbiter, IOEventSource);
34
35 /*************************************************************************/
36 static
37 void * _dequeue(void ** inList, SInt32 inOffset)
38 {
39 void * oldListHead;
40 void * newListHead;
41
42 do {
43 oldListHead = *inList;
44 if (oldListHead == NULL) {
45 break;
46 }
47
48 newListHead = *(void **) (((char *) oldListHead) + inOffset);
49 } while (! OSCompareAndSwap((UInt32)oldListHead,
50 (UInt32)newListHead, (UInt32 *)inList));
51 return oldListHead;
52 }
53
54 /*************************************************************************/
55 static
56 void _enqueue(void ** inList, void * inNewLink, SInt32 inOffset)
57 {
58 void * oldListHead;
59 void * newListHead = inNewLink;
60 void ** newLinkNextPtr = (void **) (((char *) inNewLink) + inOffset);
61
62 do {
63 oldListHead = *inList;
64 *newLinkNextPtr = oldListHead;
65 } while (! OSCompareAndSwap((UInt32)oldListHead, (UInt32)newListHead,
66 (UInt32 *)inList));
67 }
68
69 /*************************************************************************/
70 IOPMWorkArbiter *IOPMWorkArbiter::pmWorkArbiter(
71 IOPMrootDomain *inOwner)
72 {
73 IOPMWorkArbiter *me = new IOPMWorkArbiter;
74
75 if(me && !me->init((OSObject *)inOwner, 0) )
76 {
77 me->release();
78 return NULL;
79 }
80
81 return me;
82 }
83
84 /*************************************************************************/
85 bool IOPMWorkArbiter::init(OSObject *owner, Action action)
86 {
87 if(!(super::init(owner, (IOEventSource::Action) action)))
88 return false;
89
90 events = NULL;
91 fRootDomain = (IOPMrootDomain *)owner;
92
93 if (!(tmpLock = IOLockAlloc())) {
94 panic("IOPMWorkArbiter::init can't alloc lock");
95 }
96 return true;
97 }
98
99
100 /*************************************************************************/
101 bool IOPMWorkArbiter::clamshellStateChangeOccurred(uint32_t messageValue)
102 {
103 PMEventEntry *new_one = NULL;
104
105 new_one = (PMEventEntry *)IOMalloc(sizeof(PMEventEntry));
106 if(!new_one) return false;
107
108 new_one->actionType = IOPMWorkArbiter::kRootDomainClamshellChanged;
109 new_one->target = (IOService *)fRootDomain;
110 new_one->intArgument = messageValue;
111 new_one->target->retain();
112
113 IOLockLock(tmpLock);
114 _enqueue((void **)&events, (void *)new_one, 0);
115 IOLockUnlock(tmpLock);
116 signalWorkAvailable();
117
118 return true;
119 }
120
121
122 /*************************************************************************/
123 // checkForWork() is called in a gated context
124 bool IOPMWorkArbiter::checkForWork()
125 {
126 PMEventEntry *theNode;
127 IOService *theTarget;
128 UInt16 theAction;
129
130 // Dequeue and process the state change request
131 IOLockLock(tmpLock);
132 if((theNode = (PMEventEntry *)_dequeue((void **)&events, 0)))
133 {
134 IOLockUnlock(tmpLock);
135 theTarget = theNode->target;
136 theAction = theNode->actionType;
137
138 switch (theAction)
139 {
140 case kRootDomainClamshellChanged:
141 theTarget->messageClients(
142 kIOPMMessageClamshellStateChange,
143 (void *)theNode->intArgument);
144 break;
145 }
146
147 if (theTarget)
148 theTarget->release();
149 IOFree((void *)theNode, sizeof(PMEventEntry));
150 }
151 else {
152 IOLockUnlock(tmpLock);
153 }
154 // Return true if there's more work to be done
155 if(events) return true;
156 else return false;
157 }
158
159