1 /*
2  * Copyright (c) 1998-2000 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 #include <IOKit/pwr_mgt/IOPM.h>
29 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
30 #include <IOKit/pwr_mgt/IOPMinformee.h>
31 
32 #define super OSObject
OSDefineMetaClassAndStructors(IOPMinformeeList,OSObject)33 OSDefineMetaClassAndStructors(IOPMinformeeList, OSObject)
34 
35 //*********************************************************************************
36 // init
37 //
38 //*********************************************************************************
39 void
40 IOPMinformeeList::initialize( void )
41 {
42 	firstItem = NULL;
43 	length = 0;
44 }
45 
46 //******************************************************************************
47 // getSharedRecursiveLock
48 //
49 //******************************************************************************
50 IORecursiveLock *
getSharedRecursiveLock(void)51 IOPMinformeeList::getSharedRecursiveLock( void )
52 {
53 	static IORecursiveLock *sharedListLock = NULL;
54 
55 	/* A running system could have 50-60+ instances of IOPMInformeeList.
56 	 * They'll share this lock, since list insertion and removal is relatively
57 	 * rare, and generally tied to major events like device discovery.
58 	 *
59 	 * getSharedRecursiveLock() is called from IOStartIOKit to initialize
60 	 * the sharedListLock before any IOPMinformeeLists are instantiated.
61 	 *
62 	 * The IOPMinformeeList class will be around for the lifetime of the system,
63 	 * we don't worry about freeing this lock.
64 	 */
65 
66 	if (NULL == sharedListLock) {
67 		sharedListLock = IORecursiveLockAlloc();
68 	}
69 	return sharedListLock;
70 }
71 
72 //*********************************************************************************
73 // appendNewInformee
74 //
75 //*********************************************************************************
76 IOPMinformee *
appendNewInformee(IOService * newObject)77 IOPMinformeeList::appendNewInformee( IOService * newObject )
78 {
79 	IOPMinformee * newInformee;
80 
81 	if (!newObject) {
82 		return NULL;
83 	}
84 
85 	newInformee = IOPMinformee::withObject(newObject);
86 
87 	if (!newInformee) {
88 		return NULL;
89 	}
90 
91 	if (IOPMNoErr == addToList(newInformee)) {
92 		return newInformee;
93 	} else {
94 		newInformee->release();
95 		return NULL;
96 	}
97 }
98 
99 
100 //*********************************************************************************
101 // addToList
102 // *OBSOLETE* do not call from outside of this file.
103 // Try appendNewInformee() instead
104 //*********************************************************************************
105 IOReturn
addToList(IOPMinformee * newInformee)106 IOPMinformeeList::addToList( IOPMinformee * newInformee )
107 {
108 	IORecursiveLock *listLock = getSharedRecursiveLock();
109 	IOReturn        ret = kIOReturnError;
110 
111 	if (!listLock) {
112 		return ret;
113 	}
114 
115 	IORecursiveLockLock(listLock);
116 
117 	// Is new object already in the list?
118 	if (findItem(newInformee->whatObject) != NULL) {
119 		// object is present; just exit
120 		goto unlock_and_exit;
121 	}
122 
123 	// add it to the front of the list
124 	newInformee->nextInList = firstItem;
125 	firstItem = newInformee;
126 	length++;
127 	ret = IOPMNoErr;
128 
129 unlock_and_exit:
130 	IORecursiveLockUnlock(listLock);
131 	return ret;
132 }
133 
134 
135 //*********************************************************************************
136 // removeFromList
137 //
138 // Find the item in the list, unlink it, and free it.
139 //*********************************************************************************
140 
141 IOReturn
removeFromList(IOService * theItem)142 IOPMinformeeList::removeFromList( IOService * theItem )
143 {
144 	IOPMinformee * item = firstItem;
145 	IOPMinformee * temp;
146 	IORecursiveLock    *listLock = getSharedRecursiveLock();
147 
148 	if (NULL == item) {
149 		return IOPMNoErr;
150 	}
151 	if (!listLock) {
152 		return kIOReturnError;
153 	}
154 
155 	IORecursiveLockLock( listLock );
156 
157 	if (item->whatObject == theItem) {
158 		firstItem = item->nextInList;
159 		length--;
160 		item->release();
161 		goto unlock_and_exit;
162 	}
163 
164 	while (item->nextInList != NULL) {
165 		if (item->nextInList->whatObject == theItem) {
166 			temp = item->nextInList;
167 			item->nextInList = temp->nextInList;
168 			length--;
169 			temp->release();
170 			goto unlock_and_exit;
171 		}
172 		item = item->nextInList;
173 	}
174 
175 unlock_and_exit:
176 	IORecursiveLockUnlock(listLock);
177 	return IOPMNoErr;
178 }
179 
180 
181 //*********************************************************************************
182 // firstInList
183 //
184 //*********************************************************************************
185 
186 IOPMinformee *
firstInList(void)187 IOPMinformeeList::firstInList( void )
188 {
189 	return firstItem;
190 }
191 
192 //*********************************************************************************
193 // nextInList
194 //
195 //*********************************************************************************
196 
197 IOPMinformee *
nextInList(IOPMinformee * currentItem)198 IOPMinformeeList::nextInList( IOPMinformee * currentItem )
199 {
200 	if (currentItem != NULL) {
201 		return currentItem->nextInList;
202 	}
203 	return NULL;
204 }
205 
206 //*********************************************************************************
207 // numberOfItems
208 //
209 //*********************************************************************************
210 
211 unsigned long
numberOfItems(void)212 IOPMinformeeList::numberOfItems( void )
213 {
214 	return length;
215 }
216 
217 //*********************************************************************************
218 // findItem
219 //
220 // Look through the list for the one which points to the object identified
221 // by the parameter.  Return a pointer to the list item or NULL.
222 //*********************************************************************************
223 
224 IOPMinformee *
findItem(IOService * driverOrChild)225 IOPMinformeeList::findItem( IOService * driverOrChild )
226 {
227 	IOPMinformee * nextObject;
228 
229 	nextObject = firstInList();
230 	while (nextObject != NULL) {
231 		if (nextObject->whatObject == driverOrChild) {
232 			return nextObject;
233 		}
234 		nextObject = nextInList(nextObject);
235 	}
236 	return NULL;
237 }
238 
239 
240 
241 //*********************************************************************************
242 // free
243 //
244 // Free all items in the list, and then free the list itself
245 //*********************************************************************************
246 
247 void
free(void)248 IOPMinformeeList::free(void )
249 {
250 	IOPMinformee * next = firstItem;
251 
252 	while (next != NULL) {
253 		firstItem = next->nextInList;
254 		length--;
255 		next->release();
256 		next = firstItem;
257 	}
258 	super::free();
259 }
260