]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/platform/drvApplePMU/IOPMUADBController.cpp
xnu-123.5.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvApplePMU / IOPMUADBController.cpp
1 /*
2 * Copyright (c) 1998-2000 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 * 12 Nov 1998 suurballe Created.
24 */
25
26 #include <IOKit/IOSyncer.h>
27 #include "IOPMUADBController.h"
28
29 #define super IOADBController
30 OSDefineMetaClassAndStructors(IOPMUADBController, IOADBController)
31
32 // **********************************************************************************
33 // start
34 //
35 // **********************************************************************************
36 IOService * IOPMUADBController::probe( IOService * provider, SInt32 * score )
37 {
38 if (super::probe(provider, score) == NULL)
39 return NULL;
40
41 // this adb controller must interface with the pmu, so let's check if it is of the right type:
42 // so in any case if this is a powerbook G3 1998 or 1999 it has a pmu so:
43 if (IODTMatchNubWithKeys(getPlatform()->getProvider(), "'AAPL,PowerBook1998'") ||
44 IODTMatchNubWithKeys(getPlatform()->getProvider(), "'PowerBook1,1'"))
45 return this;
46
47 // If it is a different machine the compatible property will tell us if it is a pmu-driven
48 // adb device:
49 OSData *kl = OSDynamicCast(OSData, provider->getProperty("compatible"));
50 if ((kl != NULL) && kl->isEqualTo("pmu", 3))
51 return this;
52
53 // In all the other cases we do not handle it:
54 return NULL;
55 }
56
57 // **********************************************************************************
58 // start
59 //
60 // **********************************************************************************
61 bool IOPMUADBController::start ( IOService * nub )
62 {
63 // Wait for the PMU to show up:
64 PMUdriver = waitForService(serviceMatching("ApplePMU"));
65
66 // All the commands in this file will generate an interrupt.
67 // since the interrupt is the logical conclusion of those commands
68 // we need a syncer to sincronize the begin/end of these functions:
69 waitingForData = NULL;
70
71 // Registers for the two interrupts that needs to handle:
72 if (PMUdriver->callPlatformFunction("registerForPMUInterrupts", true, (void*)kPMUADBint, (void*)handleADBInterrupt, (void*)this, NULL) != kIOReturnSuccess) {
73 #ifdef VERBOSE_LOGS_ON
74 IOLog("IOPMUADBController::start registerForPMUInterrupts kPMUADBint fails\n");
75 #endif // VERBOSE_LOGS_ON
76
77 return false;
78 }
79
80 // Creates the mutex lock to protect the clients list:
81 requestMutexLock = NULL;
82 requestMutexLock = IOLockAlloc();
83 if (!requestMutexLock)
84 return false;
85
86 // This happens last (while the most common place is the begin) because
87 // trhe superclass may need the services of the functions above.
88 if( !super::start(nub))
89 return false;
90
91 return true;
92 }
93
94 // **********************************************************************************
95 // free
96 //
97 // **********************************************************************************
98 void IOPMUADBController::free ( )
99 {
100 // Releases the mutex lock used to protect the clients lists:
101 if (requestMutexLock != NULL) {
102 IOLockFree (requestMutexLock);
103 requestMutexLock = NULL;
104 }
105
106 // And removes the interrupt handler:
107 if (PMUdriver != NULL)
108 PMUdriver->callPlatformFunction("deRegisterClient", true, (void*)this, (void*)kPMUADBint, NULL, NULL);
109 }
110
111 // **********************************************************************************
112 // localSendMiscCommand
113 //
114 // **********************************************************************************
115 IOReturn IOPMUADBController::localSendMiscCommand(int command, IOByteCount sLength, UInt8 *sBuffer, IOByteCount *rLength, UInt8 *rBuffer)
116 {
117 IOReturn returnValue = kIOReturnError;
118
119 // The poupose of this method is to free us from the pain to create a parameter block each time
120 // we wish to talk to the pmu:
121 SendMiscCommandParameterBlock prmBlock = {command, sLength, sBuffer, rLength, rBuffer};
122
123 #ifdef VERBOSE_LOGS_ON
124 IOLog("ApplePMUInterface::localSendMiscCommand 0x%02x %d 0x%08lx 0x%08lx 0x%08lx\n",
125 command, sLength, sBuffer, rLength, rBuffer);
126 #endif
127
128 if (PMUdriver != NULL) {
129 #ifdef VERBOSE_LOGS_ON
130 IOLog("IOPMUADBController::localSendMiscCommand calling PMUdriver->callPlatformFunction\n");
131 #endif
132 returnValue = PMUdriver->callPlatformFunction("sendMiscCommand", true, (void*)&prmBlock, NULL, NULL, NULL);
133 }
134
135 // If we are here we do not have a dreive to talk to:
136 #ifdef VERBOSE_LOGS_ON
137 IOLog("IOPMUADBController::localSendMiscCommand end 0x%08lx\n", returnValue);
138 #endif
139
140 return returnValue;
141 }
142
143 // **********************************************************************************
144 // this is the interrupt handler for all ADB interrupts:
145 //
146 // **********************************************************************************
147
148 /* static */ void
149 IOPMUADBController::handleADBInterrupt(IOService *client, UInt8 interruptMask, UInt32 length, UInt8 *buffer)
150 {
151 if (interruptMask & kPMUautopoll)
152 autopollHandler(client, buffer[0], length - 1, buffer + 1); // yes, call adb input handler
153 else {
154 IOPMUADBController *myThis = OSDynamicCast(IOPMUADBController, client);
155
156 if ((myThis != NULL) && (myThis->waitingForData != NULL)) {
157 // Complets the adb transaction
158 myThis->dataLen = length - 1;
159 bcopy(buffer + 1, myThis->dataBuffer, myThis->dataLen);
160 myThis->waitingForData->signal();
161 }
162 }
163 }
164
165 // **********************************************************************************
166 // setAutoPollPeriod
167 //
168 // **********************************************************************************
169 IOReturn IOPMUADBController::setAutoPollPeriod ( int )
170 {
171 return kPMUNotSupported;
172 }
173
174
175 // **********************************************************************************
176 // getAutoPollPeriod
177 //
178 // **********************************************************************************
179 IOReturn IOPMUADBController::getAutoPollPeriod ( int * )
180 {
181 return kPMUNotSupported;
182 }
183
184
185 // **********************************************************************************
186 // setAutoPollList
187 //
188 // **********************************************************************************
189 IOReturn IOPMUADBController::setAutoPollList ( UInt16 PollBitField )
190 {
191 pollList = PollBitField; // remember the new poll list
192
193 if ( autopollOn ) {
194 UInt8 oBuffer[4];
195
196 oBuffer[0] = 0; // Byte count in the resto of the command
197 oBuffer[1] = 0x86; // adb Command op.
198 oBuffer[2] = (UInt8)(PollBitField >> 8); // ??
199 oBuffer[3] = (UInt8)(PollBitField & 0xff); // ??
200
201 localSendMiscCommand (kPMUpMgrADB, 4, oBuffer, NULL, NULL);
202 }
203 return kPMUNoError;
204 }
205
206
207 // **********************************************************************************
208 // getAutoPollList
209 //
210 // **********************************************************************************
211 IOReturn IOPMUADBController::getAutoPollList ( UInt16 * activeAddressMask )
212 {
213 *activeAddressMask = pollList;
214 return kPMUNoError;
215 }
216
217
218 // **********************************************************************************
219 // setAutoPollEnable
220 //
221 // **********************************************************************************
222 IOReturn IOPMUADBController::setAutoPollEnable ( bool enable )
223 {
224 UInt8 oBuffer[4];
225
226 if ( enable ) { // enabling autopoll
227 oBuffer[0] = 0;
228 oBuffer[1] = 0x86;
229 oBuffer[2] = (UInt8)(pollList >> 8);
230 oBuffer[3] = (UInt8)(pollList & 0xff);
231
232 localSendMiscCommand (kPMUpMgrADB, 4, oBuffer, NULL,NULL);
233 autopollOn = true;
234 }
235 else { // disabling autopoll;
236 localSendMiscCommand (kPMUpMgrADBoff, 0, NULL, NULL, NULL);
237 }
238
239 return kPMUNoError;
240 }
241
242
243 // **********************************************************************************
244 // resetBus
245 //
246 // **********************************************************************************
247 IOReturn IOPMUADBController::resetBus ( void )
248 {
249 if (requestMutexLock != NULL)
250 IOLockLock(requestMutexLock);
251
252 UInt8 oBuffer[4];
253
254 oBuffer[0] = kPMUResetADBBus;
255 oBuffer[1] = 0;
256 oBuffer[2] = 0;
257
258 // Reset bus needs to wait for the interrupt to terminate the transaction:
259 waitingForData = IOSyncer::create();
260 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer, NULL, NULL);
261 waitingForData->wait(); // wait till done
262 waitingForData = 0;
263
264 if (requestMutexLock != NULL)
265 IOLockUnlock(requestMutexLock);
266
267 return kPMUNoError;
268 }
269
270
271 // **********************************************************************************
272 // flushDevice
273 //
274 // **********************************************************************************
275 IOReturn IOPMUADBController::flushDevice ( IOADBAddress address )
276 {
277 if (requestMutexLock != NULL)
278 IOLockLock(requestMutexLock);
279
280 UInt8 oBuffer[4];
281
282 oBuffer[0] = kPMUFlushADB | (address << kPMUADBAddressField);
283 oBuffer[1] = ( autopollOn ? 2 : 0 );
284 oBuffer[2] = 0;
285
286 // flush device needs to wait for the interrupt to terminate the transaction
287 waitingForData = IOSyncer::create();
288 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer, NULL, NULL);
289 waitingForData->wait(); // wait till done
290 waitingForData = 0;
291
292 if (requestMutexLock != NULL)
293 IOLockUnlock(requestMutexLock);
294
295 return kPMUNoError;
296 }
297
298
299 // **********************************************************************************
300 // readFromDevice
301 //
302 // The length parameter is ignored on entry. It is set on exit to reflect
303 // the number of bytes read from the device.
304 // **********************************************************************************
305 IOReturn IOPMUADBController::readFromDevice ( IOADBAddress address, IOADBRegister adbRegister,
306 UInt8 * data, IOByteCount * length )
307 {
308 if ( (length == NULL) || (data == NULL) ) {
309 return kPMUParameterError;
310 }
311
312 if (requestMutexLock != NULL)
313 IOLockLock(requestMutexLock);
314
315 UInt8 oBuffer[4];
316
317 oBuffer[0] = kPMUReadADB | (address << kPMUADBAddressField) | (adbRegister);
318 oBuffer[1] = ( autopollOn ? 2 : 0 );
319 oBuffer[2] = 0;
320
321 // read from device needs to wait for the interrupt to terminate the transaction
322 // and to obtain the data from the device.
323 waitingForData = IOSyncer::create();
324 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer, NULL, NULL);
325 waitingForData->wait(); // wait till done
326 waitingForData = 0;
327
328 // set caller's length
329 *length = (dataLen < *length ? dataLen : *length);
330 bcopy(dataBuffer, data, *length);
331
332 if (requestMutexLock != NULL)
333 IOLockUnlock(requestMutexLock);
334
335 if (dataLen == 0 ) { // nothing read; device isn't there
336 return ADB_RET_NOTPRESENT;
337 }
338
339 return ADB_RET_OK;
340 }
341
342
343 // **********************************************************************************
344 // writeToDevice
345 //
346 // **********************************************************************************
347 IOReturn IOPMUADBController::writeToDevice ( IOADBAddress address, IOADBRegister adbRegister,
348 UInt8 * data, IOByteCount * length )
349 {
350 // Last check on * length > (252): since the pmu registers are 8 bit
351 // and the buffer has the first 3 bytes used for the standard paramters
352 // the max lenght can not be more than 252 bytes.
353 if ( (* length == 0) || (data == NULL) || (* length > 252) )
354 {
355 return kPMUParameterError;
356 }
357
358 if (address == 0)
359 return kPMUNoError; // for now let's ignore these ...
360
361 if (requestMutexLock != NULL)
362 IOLockLock(requestMutexLock);
363
364 UInt8 oBuffer[256];
365
366 oBuffer[0] = kPMUWriteADB | (address << kPMUADBAddressField) | (adbRegister);
367 oBuffer[1] = ( autopollOn ? 2 : 0 );
368 oBuffer[2] = *length;
369 bcopy(data, &oBuffer[3], *length);
370
371 // write to the device needs to wait for the interrupt to terminate the transaction
372 waitingForData = IOSyncer::create();
373 localSendMiscCommand (kPMUpMgrADB, 3 + *length, oBuffer, NULL, NULL);
374 waitingForData->wait();
375 waitingForData = 0;
376
377 if (requestMutexLock != NULL)
378 IOLockUnlock(requestMutexLock);
379
380 return kPMUNoError;
381 }
382
383