2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
26 * 12 Nov 1998 suurballe Created.
29 #include <IOKit/pwr_mgt/IOPM.h>
30 #include <IOKit/IOSyncer.h>
31 #include "IOPMUADBController.h"
33 #define super IOADBController
34 OSDefineMetaClassAndStructors(IOPMUADBController
, IOADBController
)
36 // **********************************************************************************
39 // **********************************************************************************
40 IOService
* IOPMUADBController::probe( IOService
* provider
, SInt32
* score
)
42 if (super::probe(provider
, score
) == NULL
)
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'"))
51 // If it is a different machine the compatible property will tell us if it is a pmu-driven
53 OSData
*kl
= OSDynamicCast(OSData
, provider
->getProperty("compatible"));
54 if ((kl
!= NULL
) && kl
->isEqualTo("pmu", 3))
57 // In all the other cases we do not handle it:
61 // **********************************************************************************
64 // **********************************************************************************
65 bool IOPMUADBController::start ( IOService
* nub
)
67 // Wait for the PMU to show up:
68 PMUdriver
= waitForService(serviceMatching("ApplePMU"));
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
;
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
84 // Creates the mutex lock to protect the clients list:
85 requestMutexLock
= NULL
;
86 requestMutexLock
= IOLockAlloc();
87 if (!requestMutexLock
)
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
))
100 // **********************************************************************************
103 // **********************************************************************************
104 void IOPMUADBController::free ( )
106 // Releases the mutex lock used to protect the clients lists:
107 if (requestMutexLock
!= NULL
) {
108 IOLockFree (requestMutexLock
);
109 requestMutexLock
= NULL
;
112 // And removes the interrupt handler:
113 if (PMUdriver
!= NULL
)
114 PMUdriver
->callPlatformFunction("deRegisterClient", true, (void*)this, (void*)(kPMUADBint
| kPMUenvironmentInt
), NULL
, NULL
);
117 // **********************************************************************************
118 // localSendMiscCommand
120 // **********************************************************************************
121 IOReturn
IOPMUADBController::localSendMiscCommand(int command
, IOByteCount sLength
, UInt8
*sBuffer
)
123 IOReturn returnValue
= kIOReturnError
;
124 IOByteCount rLength
= 1;
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
};
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
);
136 if (PMUdriver
!= NULL
) {
137 #ifdef VERBOSE_LOGS_ON
138 IOLog("IOPMUADBController::localSendMiscCommand calling PMUdriver->callPlatformFunction\n");
140 returnValue
= PMUdriver
->callPlatformFunction("sendMiscCommand", true, (void*)&prmBlock
, NULL
, NULL
, NULL
);
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
);
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 // **********************************************************************************
159 IOPMUADBController::handleADBInterrupt(IOService
*client
, UInt8 interruptMask
, UInt32 length
, UInt8
*buffer
)
161 IOPMUADBController
*myThis
= OSDynamicCast(IOPMUADBController
, client
);
163 // Check if we are the right client for this interrupt:
167 if (interruptMask
& kPMUenvironmentInt
)
171 if (*buffer
& kClamshellClosedEventMask
)
172 myThis
->clamshellOpen
= false;
174 myThis
->clamshellOpen
= true;
176 if ( !(interruptMask
& kPMUautopoll
))
178 return; //Nothing left to do
181 if ((interruptMask
& kPMUautopoll
) && (myThis
->autopollOn
))
183 if (myThis
->clamshellOpen
)
185 autopollHandler(client
, buffer
[0], length
- 1, buffer
+ 1); // yes, call adb input handler
187 else if ( (buffer
[0] == 0x2c) && (buffer
[1] == 0x7f) && (buffer
[2] == 0x7f))
189 autopollHandler(client
, buffer
[0], length
- 1, buffer
+ 1); // POWER down
191 else if ( (buffer
[0] == 0x2c) && (buffer
[1] == 0xff) && (buffer
[2] == 0xff))
193 autopollHandler(client
, buffer
[0], length
- 1, buffer
+ 1); // POWER up
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();
208 // **********************************************************************************
211 // **********************************************************************************
212 IOReturn
IOPMUADBController::cancelAllIO ( void )
214 if (waitingForData
!= NULL
) {
215 dataLen
= 0; // read fails with error, write fails quietly
216 waitingForData
->signal();
222 // **********************************************************************************
225 // **********************************************************************************
226 IOReturn
IOPMUADBController::setAutoPollPeriod ( int )
228 return kPMUNotSupported
;
232 // **********************************************************************************
235 // **********************************************************************************
236 IOReturn
IOPMUADBController::getAutoPollPeriod ( int * )
238 return kPMUNotSupported
;
242 // **********************************************************************************
245 // **********************************************************************************
246 IOReturn
IOPMUADBController::setAutoPollList ( UInt16 PollBitField
)
248 pollList
= PollBitField
; // remember the new poll list
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); // ??
258 localSendMiscCommand (kPMUpMgrADB
, 4, oBuffer
);
264 // **********************************************************************************
267 // **********************************************************************************
268 IOReturn
IOPMUADBController::getAutoPollList ( UInt16
* activeAddressMask
)
270 *activeAddressMask
= pollList
;
275 // **********************************************************************************
278 // **********************************************************************************
279 IOReturn
IOPMUADBController::setAutoPollEnable ( bool enable
)
285 if ( enable
) { // enabling autopoll
288 oBuffer
[2] = (UInt8
)(pollList
>> 8);
289 oBuffer
[3] = (UInt8
)(pollList
& 0xff);
291 localSendMiscCommand (kPMUpMgrADB
, 4, oBuffer
);
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'"))
300 localSendMiscCommand (kPMUpMgrADBoff
, 0, NULL
);
307 // **********************************************************************************
310 // **********************************************************************************
311 IOReturn
IOPMUADBController::resetBus ( void )
313 if (requestMutexLock
!= NULL
)
314 IOLockLock(requestMutexLock
);
318 oBuffer
[0] = kPMUResetADBBus
;
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
328 if (requestMutexLock
!= NULL
)
329 IOLockUnlock(requestMutexLock
);
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'"))
340 // **********************************************************************************
343 // **********************************************************************************
344 IOReturn
IOPMUADBController::flushDevice ( IOADBAddress address
)
346 if (requestMutexLock
!= NULL
)
347 IOLockLock(requestMutexLock
);
351 oBuffer
[0] = kPMUFlushADB
| (address
<< kPMUADBAddressField
);
352 oBuffer
[1] = ( autopollOn
? 2 : 0 );
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
361 if (requestMutexLock
!= NULL
)
362 IOLockUnlock(requestMutexLock
);
368 // **********************************************************************************
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
)
377 if ( (length
== NULL
) || (data
== NULL
) ) {
378 return kPMUParameterError
;
381 if (requestMutexLock
!= NULL
)
382 IOLockLock(requestMutexLock
);
386 oBuffer
[0] = kPMUReadADB
| (address
<< kPMUADBAddressField
) | (adbRegister
);
387 oBuffer
[1] = ( autopollOn
? 2 : 0 );
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
397 // set caller's length
398 *length
= (dataLen
< *length
? dataLen
: *length
);
399 bcopy(dataBuffer
, data
, *length
);
401 if (requestMutexLock
!= NULL
)
402 IOLockUnlock(requestMutexLock
);
404 if (dataLen
== 0 ) { // nothing read; device isn't there
405 return ADB_RET_NOTPRESENT
;
412 // **********************************************************************************
415 // **********************************************************************************
416 IOReturn
IOPMUADBController::writeToDevice ( IOADBAddress address
, IOADBRegister adbRegister
,
417 UInt8
* data
, IOByteCount
* length
)
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) )
424 return kPMUParameterError
;
428 return kPMUNoError
; // for now let's ignore these ...
430 if (requestMutexLock
!= NULL
)
431 IOLockLock(requestMutexLock
);
435 oBuffer
[0] = kPMUWriteADB
| (address
<< kPMUADBAddressField
) | (adbRegister
);
436 oBuffer
[1] = ( autopollOn
? 2 : 0 );
437 oBuffer
[2] = *length
;
438 bcopy(data
, &oBuffer
[3], *length
);
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();
446 if (requestMutexLock
!= NULL
)
447 IOLockUnlock(requestMutexLock
);