]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/platform/drvApplePMU/IOPMUADBController.cpp
xnu-344.21.74.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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * 12 Nov 1998 suurballe Created.
27 */
28
29 #include <IOKit/pwr_mgt/IOPM.h>
30 #include <IOKit/IOSyncer.h>
31 #include "IOPMUADBController.h"
32
33 #define super IOADBController
34 OSDefineMetaClassAndStructors(IOPMUADBController, IOADBController)
35
36 // **********************************************************************************
37 // start
38 //
39 // **********************************************************************************
40 IOService * IOPMUADBController::probe( IOService * provider, SInt32 * score )
41 {
42 if (super::probe(provider, score) == NULL)
43 return NULL;
44
45 // this adb controller must interface with the pmu, so let's check if it is of the right type:
46 // so in any case if this is a powerbook G3 1998 or 1999 it has a pmu so:
47 if (IODTMatchNubWithKeys(getPlatform()->getProvider(), "'AAPL,PowerBook1998'") ||
48 IODTMatchNubWithKeys(getPlatform()->getProvider(), "'PowerBook1,1'"))
49 return this;
50
51 // If it is a different machine the compatible property will tell us if it is a pmu-driven
52 // adb device:
53 OSData *kl = OSDynamicCast(OSData, provider->getProperty("compatible"));
54 if ((kl != NULL) && kl->isEqualTo("pmu", 3))
55 return this;
56
57 // In all the other cases we do not handle it:
58 return NULL;
59 }
60
61 // **********************************************************************************
62 // start
63 //
64 // **********************************************************************************
65 bool IOPMUADBController::start ( IOService * nub )
66 {
67 // Wait for the PMU to show up:
68 PMUdriver = waitForService(serviceMatching("ApplePMU"));
69
70 // All the commands in this file will generate an interrupt.
71 // since the interrupt is the logical conclusion of those commands
72 // we need a syncer to sincronize the begin/end of these functions:
73 waitingForData = NULL;
74
75 // Registers for the two interrupts that needs to handle:
76 if (PMUdriver->callPlatformFunction("registerForPMUInterrupts", true, (void*) (kPMUADBint | kPMUenvironmentInt), (void*)handleADBInterrupt, (void*)this, NULL) != kIOReturnSuccess) {
77 #ifdef VERBOSE_LOGS_ON
78 IOLog("IOPMUADBController::start registerForPMUInterrupts kPMUADBint fails\n");
79 #endif // VERBOSE_LOGS_ON
80
81 return false;
82 }
83
84 // Creates the mutex lock to protect the clients list:
85 requestMutexLock = NULL;
86 requestMutexLock = IOLockAlloc();
87 if (!requestMutexLock)
88 return false;
89
90 clamshellOpen = true;
91
92 // This happens last (while the most common place is the begin) because
93 // trhe superclass may need the services of the functions above.
94 if( !super::start(nub))
95 return false;
96
97 return true;
98 }
99
100 // **********************************************************************************
101 // free
102 //
103 // **********************************************************************************
104 void IOPMUADBController::free ( )
105 {
106 // Releases the mutex lock used to protect the clients lists:
107 if (requestMutexLock != NULL) {
108 IOLockFree (requestMutexLock);
109 requestMutexLock = NULL;
110 }
111
112 // And removes the interrupt handler:
113 if (PMUdriver != NULL)
114 PMUdriver->callPlatformFunction("deRegisterClient", true, (void*)this, (void*)(kPMUADBint | kPMUenvironmentInt), NULL, NULL);
115 }
116
117 // **********************************************************************************
118 // localSendMiscCommand
119 //
120 // **********************************************************************************
121 IOReturn IOPMUADBController::localSendMiscCommand(int command, IOByteCount sLength, UInt8 *sBuffer)
122 {
123 IOReturn returnValue = kIOReturnError;
124 IOByteCount rLength = 1;
125 UInt8 rBuffer;
126
127 // The poupose of this method is to free us from the pain to create a parameter block each time
128 // we wish to talk to the pmu:
129 SendMiscCommandParameterBlock prmBlock = {command, sLength, sBuffer, &rLength, &rBuffer};
130
131 #ifdef VERBOSE_LOGS_ON
132 IOLog("ApplePMUInterface::localSendMiscCommand 0x%02x %d 0x%08lx 0x%08lx 0x%08lx\n",
133 command, sLength, sBuffer, rLength, rBuffer);
134 #endif
135
136 if (PMUdriver != NULL) {
137 #ifdef VERBOSE_LOGS_ON
138 IOLog("IOPMUADBController::localSendMiscCommand calling PMUdriver->callPlatformFunction\n");
139 #endif
140 returnValue = PMUdriver->callPlatformFunction("sendMiscCommand", true, (void*)&prmBlock, NULL, NULL, NULL);
141 }
142
143 // If we are here we do not have a dreive to talk to:
144 #ifdef VERBOSE_LOGS_ON
145 IOLog("IOPMUADBController::localSendMiscCommand end 0x%08lx\n", returnValue);
146 #endif
147
148 return returnValue;
149 }
150
151 // **********************************************************************************
152 // this is the interrupt handler for all ADB interrupts:
153 // A.W. Added code to check for clamshell status, and block all ADB traffic except
154 // for POWER key scan code from default ADB keyboard or devices that connect
155 // to that keyboard power button.
156 // **********************************************************************************
157
158 /* static */ void
159 IOPMUADBController::handleADBInterrupt(IOService *client, UInt8 interruptMask, UInt32 length, UInt8 *buffer)
160 {
161 IOPMUADBController *myThis = OSDynamicCast(IOPMUADBController, client);
162
163 // Check if we are the right client for this interrupt:
164 if (myThis == NULL)
165 return;
166
167 if (interruptMask & kPMUenvironmentInt)
168 {
169 if (buffer)
170 {
171 if (*buffer & kClamshellClosedEventMask)
172 myThis->clamshellOpen = false;
173 else
174 myThis->clamshellOpen = true;
175 }
176 if ( !(interruptMask & kPMUautopoll))
177 {
178 return; //Nothing left to do
179 }
180 }
181 if ((interruptMask & kPMUautopoll) && (myThis->autopollOn))
182 {
183 if (myThis->clamshellOpen)
184 {
185 autopollHandler(client, buffer[0], length - 1, buffer + 1); // yes, call adb input handler
186 }
187 else if ( (buffer[0] == 0x2c) && (buffer[1] == 0x7f) && (buffer[2] == 0x7f))
188 {
189 autopollHandler(client, buffer[0], length - 1, buffer + 1); // POWER down
190 }
191 else if ( (buffer[0] == 0x2c) && (buffer[1] == 0xff) && (buffer[2] == 0xff))
192 {
193 autopollHandler(client, buffer[0], length - 1, buffer + 1); // POWER up
194 }
195
196 }
197 else {
198 if (myThis->waitingForData != NULL) {
199 // Complets the adb transaction
200 myThis->dataLen = length - 1;
201 bcopy(buffer + 1, myThis->dataBuffer, myThis->dataLen);
202 myThis->waitingForData->signal();
203 }
204 }
205 }
206
207
208 // **********************************************************************************
209 // cancelAllIO
210 //
211 // **********************************************************************************
212 IOReturn IOPMUADBController::cancelAllIO ( void )
213 {
214 if (waitingForData != NULL) {
215 dataLen = 0; // read fails with error, write fails quietly
216 waitingForData->signal();
217 }
218 return kPMUNoError;
219 }
220
221
222 // **********************************************************************************
223 // setAutoPollPeriod
224 //
225 // **********************************************************************************
226 IOReturn IOPMUADBController::setAutoPollPeriod ( int )
227 {
228 return kPMUNotSupported;
229 }
230
231
232 // **********************************************************************************
233 // getAutoPollPeriod
234 //
235 // **********************************************************************************
236 IOReturn IOPMUADBController::getAutoPollPeriod ( int * )
237 {
238 return kPMUNotSupported;
239 }
240
241
242 // **********************************************************************************
243 // setAutoPollList
244 //
245 // **********************************************************************************
246 IOReturn IOPMUADBController::setAutoPollList ( UInt16 PollBitField )
247 {
248 pollList = PollBitField; // remember the new poll list
249
250 if ( autopollOn ) {
251 UInt8 oBuffer[4];
252
253 oBuffer[0] = 0; // Byte count in the resto of the command
254 oBuffer[1] = 0x86; // adb Command op.
255 oBuffer[2] = (UInt8)(PollBitField >> 8); // ??
256 oBuffer[3] = (UInt8)(PollBitField & 0xff); // ??
257
258 localSendMiscCommand (kPMUpMgrADB, 4, oBuffer);
259 }
260 return kPMUNoError;
261 }
262
263
264 // **********************************************************************************
265 // getAutoPollList
266 //
267 // **********************************************************************************
268 IOReturn IOPMUADBController::getAutoPollList ( UInt16 * activeAddressMask )
269 {
270 *activeAddressMask = pollList;
271 return kPMUNoError;
272 }
273
274
275 // **********************************************************************************
276 // setAutoPollEnable
277 //
278 // **********************************************************************************
279 IOReturn IOPMUADBController::setAutoPollEnable ( bool enable )
280 {
281 UInt8 oBuffer[4];
282
283 autopollOn = enable;
284
285 if ( enable ) { // enabling autopoll
286 oBuffer[0] = 0;
287 oBuffer[1] = 0x86;
288 oBuffer[2] = (UInt8)(pollList >> 8);
289 oBuffer[3] = (UInt8)(pollList & 0xff);
290
291 localSendMiscCommand (kPMUpMgrADB, 4, oBuffer);
292 }
293 else { // disabling autopoll;
294 /* Waits one second for the trackpads to be up (this is needed only in old machines)
295 This is placed here because this is the fist call at wake. */
296 if (IODTMatchNubWithKeys(getPlatform()->getProvider(), "'PowerBook1,1'") ||
297 IODTMatchNubWithKeys(getPlatform()->getProvider(), "'AAPL,PowerBook1998'"))
298 IOSleep(1500);
299
300 localSendMiscCommand (kPMUpMgrADBoff, 0, NULL);
301 }
302
303 return kPMUNoError;
304 }
305
306
307 // **********************************************************************************
308 // resetBus
309 //
310 // **********************************************************************************
311 IOReturn IOPMUADBController::resetBus ( void )
312 {
313 if (requestMutexLock != NULL)
314 IOLockLock(requestMutexLock);
315
316 UInt8 oBuffer[4];
317
318 oBuffer[0] = kPMUResetADBBus;
319 oBuffer[1] = 0;
320 oBuffer[2] = 0;
321
322 // Reset bus needs to wait for the interrupt to terminate the transaction:
323 waitingForData = IOSyncer::create();
324 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
325 waitingForData->wait(); // wait till done
326 waitingForData = 0;
327
328 if (requestMutexLock != NULL)
329 IOLockUnlock(requestMutexLock);
330
331 /* Waits one second for the trackpads to be up (this is needed only in old machines) */
332 if (IODTMatchNubWithKeys(getPlatform()->getProvider(), "'PowerBook1,1'") ||
333 IODTMatchNubWithKeys(getPlatform()->getProvider(), "'AAPL,PowerBook1998'"))
334 IOSleep(1500);
335
336 return kPMUNoError;
337 }
338
339
340 // **********************************************************************************
341 // flushDevice
342 //
343 // **********************************************************************************
344 IOReturn IOPMUADBController::flushDevice ( IOADBAddress address )
345 {
346 if (requestMutexLock != NULL)
347 IOLockLock(requestMutexLock);
348
349 UInt8 oBuffer[4];
350
351 oBuffer[0] = kPMUFlushADB | (address << kPMUADBAddressField);
352 oBuffer[1] = ( autopollOn ? 2 : 0 );
353 oBuffer[2] = 0;
354
355 // flush device needs to wait for the interrupt to terminate the transaction
356 waitingForData = IOSyncer::create();
357 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
358 waitingForData->wait(); // wait till done
359 waitingForData = 0;
360
361 if (requestMutexLock != NULL)
362 IOLockUnlock(requestMutexLock);
363
364 return kPMUNoError;
365 }
366
367
368 // **********************************************************************************
369 // readFromDevice
370 //
371 // The length parameter is ignored on entry. It is set on exit to reflect
372 // the number of bytes read from the device.
373 // **********************************************************************************
374 IOReturn IOPMUADBController::readFromDevice ( IOADBAddress address, IOADBRegister adbRegister,
375 UInt8 * data, IOByteCount * length )
376 {
377 if ( (length == NULL) || (data == NULL) ) {
378 return kPMUParameterError;
379 }
380
381 if (requestMutexLock != NULL)
382 IOLockLock(requestMutexLock);
383
384 UInt8 oBuffer[4];
385
386 oBuffer[0] = kPMUReadADB | (address << kPMUADBAddressField) | (adbRegister);
387 oBuffer[1] = ( autopollOn ? 2 : 0 );
388 oBuffer[2] = 0;
389
390 // read from device needs to wait for the interrupt to terminate the transaction
391 // and to obtain the data from the device.
392 waitingForData = IOSyncer::create();
393 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
394 waitingForData->wait(); // wait till done
395 waitingForData = 0;
396
397 // set caller's length
398 *length = (dataLen < *length ? dataLen : *length);
399 bcopy(dataBuffer, data, *length);
400
401 if (requestMutexLock != NULL)
402 IOLockUnlock(requestMutexLock);
403
404 if (dataLen == 0 ) { // nothing read; device isn't there
405 return ADB_RET_NOTPRESENT;
406 }
407
408 return ADB_RET_OK;
409 }
410
411
412 // **********************************************************************************
413 // writeToDevice
414 //
415 // **********************************************************************************
416 IOReturn IOPMUADBController::writeToDevice ( IOADBAddress address, IOADBRegister adbRegister,
417 UInt8 * data, IOByteCount * length )
418 {
419 // Last check on * length > (252): since the pmu registers are 8 bit
420 // and the buffer has the first 3 bytes used for the standard paramters
421 // the max lenght can not be more than 252 bytes.
422 if ( (* length == 0) || (data == NULL) || (* length > 252) )
423 {
424 return kPMUParameterError;
425 }
426
427 if (address == 0)
428 return kPMUNoError; // for now let's ignore these ...
429
430 if (requestMutexLock != NULL)
431 IOLockLock(requestMutexLock);
432
433 UInt8 oBuffer[256];
434
435 oBuffer[0] = kPMUWriteADB | (address << kPMUADBAddressField) | (adbRegister);
436 oBuffer[1] = ( autopollOn ? 2 : 0 );
437 oBuffer[2] = *length;
438 bcopy(data, &oBuffer[3], *length);
439
440 // write to the device needs to wait for the interrupt to terminate the transaction
441 waitingForData = IOSyncer::create();
442 localSendMiscCommand (kPMUpMgrADB, 3 + *length, oBuffer);
443 waitingForData->wait();
444 waitingForData = 0;
445
446 if (requestMutexLock != NULL)
447 IOLockUnlock(requestMutexLock);
448
449 return kPMUNoError;
450 }
451
452