2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * 12 Nov 1998 suurballe Created.
26 #include <IOKit/pwr_mgt/IOPM.h>
27 #include <IOKit/IOSyncer.h>
28 #include "IOPMUADBController.h"
30 #define super IOADBController
31 OSDefineMetaClassAndStructors(IOPMUADBController
, IOADBController
)
33 // **********************************************************************************
36 // **********************************************************************************
37 IOService
* IOPMUADBController::probe( IOService
* provider
, SInt32
* score
)
39 if (super::probe(provider
, score
) == NULL
)
42 // this adb controller must interface with the pmu, so let's check if it is of the right type:
43 // so in any case if this is a powerbook G3 1998 or 1999 it has a pmu so:
44 if (IODTMatchNubWithKeys(getPlatform()->getProvider(), "'AAPL,PowerBook1998'") ||
45 IODTMatchNubWithKeys(getPlatform()->getProvider(), "'PowerBook1,1'"))
48 // If it is a different machine the compatible property will tell us if it is a pmu-driven
50 OSData
*kl
= OSDynamicCast(OSData
, provider
->getProperty("compatible"));
51 if ((kl
!= NULL
) && kl
->isEqualTo("pmu", 3))
54 // In all the other cases we do not handle it:
58 // **********************************************************************************
61 // **********************************************************************************
62 bool IOPMUADBController::start ( IOService
* nub
)
64 // Wait for the PMU to show up:
65 PMUdriver
= waitForService(serviceMatching("ApplePMU"));
67 // All the commands in this file will generate an interrupt.
68 // since the interrupt is the logical conclusion of those commands
69 // we need a syncer to sincronize the begin/end of these functions:
70 waitingForData
= NULL
;
72 // Registers for the two interrupts that needs to handle:
73 if (PMUdriver
->callPlatformFunction("registerForPMUInterrupts", true, (void*) (kPMUADBint
| kPMUenvironmentInt
), (void*)handleADBInterrupt
, (void*)this, NULL
) != kIOReturnSuccess
) {
74 #ifdef VERBOSE_LOGS_ON
75 IOLog("IOPMUADBController::start registerForPMUInterrupts kPMUADBint fails\n");
76 #endif // VERBOSE_LOGS_ON
81 // Creates the mutex lock to protect the clients list:
82 requestMutexLock
= NULL
;
83 requestMutexLock
= IOLockAlloc();
84 if (!requestMutexLock
)
89 // This happens last (while the most common place is the begin) because
90 // trhe superclass may need the services of the functions above.
91 if( !super::start(nub
))
97 // **********************************************************************************
100 // **********************************************************************************
101 void IOPMUADBController::free ( )
103 // Releases the mutex lock used to protect the clients lists:
104 if (requestMutexLock
!= NULL
) {
105 IOLockFree (requestMutexLock
);
106 requestMutexLock
= NULL
;
109 // And removes the interrupt handler:
110 if (PMUdriver
!= NULL
)
111 PMUdriver
->callPlatformFunction("deRegisterClient", true, (void*)this, (void*)(kPMUADBint
| kPMUenvironmentInt
), NULL
, NULL
);
114 // **********************************************************************************
115 // localSendMiscCommand
117 // **********************************************************************************
118 IOReturn
IOPMUADBController::localSendMiscCommand(int command
, IOByteCount sLength
, UInt8
*sBuffer
)
120 IOReturn returnValue
= kIOReturnError
;
121 IOByteCount rLength
= 1;
124 // The poupose of this method is to free us from the pain to create a parameter block each time
125 // we wish to talk to the pmu:
126 SendMiscCommandParameterBlock prmBlock
= {command
, sLength
, sBuffer
, &rLength
, &rBuffer
};
128 #ifdef VERBOSE_LOGS_ON
129 IOLog("ApplePMUInterface::localSendMiscCommand 0x%02x %d 0x%08lx 0x%08lx 0x%08lx\n",
130 command
, sLength
, sBuffer
, rLength
, rBuffer
);
133 if (PMUdriver
!= NULL
) {
134 #ifdef VERBOSE_LOGS_ON
135 IOLog("IOPMUADBController::localSendMiscCommand calling PMUdriver->callPlatformFunction\n");
137 returnValue
= PMUdriver
->callPlatformFunction("sendMiscCommand", true, (void*)&prmBlock
, NULL
, NULL
, NULL
);
140 // If we are here we do not have a dreive to talk to:
141 #ifdef VERBOSE_LOGS_ON
142 IOLog("IOPMUADBController::localSendMiscCommand end 0x%08lx\n", returnValue
);
148 // **********************************************************************************
149 // this is the interrupt handler for all ADB interrupts:
150 // A.W. Added code to check for clamshell status, and block all ADB traffic except
151 // for POWER key scan code from default ADB keyboard or devices that connect
152 // to that keyboard power button.
153 // **********************************************************************************
156 IOPMUADBController::handleADBInterrupt(IOService
*client
, UInt8 interruptMask
, UInt32 length
, UInt8
*buffer
)
158 IOPMUADBController
*myThis
= OSDynamicCast(IOPMUADBController
, client
);
160 // Check if we are the right client for this interrupt:
164 if (interruptMask
& kPMUenvironmentInt
)
168 if (*buffer
& kClamshellClosedEventMask
)
169 myThis
->clamshellOpen
= false;
171 myThis
->clamshellOpen
= true;
173 if ( !(interruptMask
& kPMUautopoll
))
175 return; //Nothing left to do
178 if ((interruptMask
& kPMUautopoll
) && (myThis
->autopollOn
))
180 if (myThis
->clamshellOpen
)
182 autopollHandler(client
, buffer
[0], length
- 1, buffer
+ 1); // yes, call adb input handler
184 else if ( (buffer
[0] == 0x2c) && (buffer
[1] == 0x7f) && (buffer
[2] == 0x7f))
186 autopollHandler(client
, buffer
[0], length
- 1, buffer
+ 1); // POWER down
188 else if ( (buffer
[0] == 0x2c) && (buffer
[1] == 0xff) && (buffer
[2] == 0xff))
190 autopollHandler(client
, buffer
[0], length
- 1, buffer
+ 1); // POWER up
195 if (myThis
->waitingForData
!= NULL
) {
196 // Complets the adb transaction
197 myThis
->dataLen
= length
- 1;
198 bcopy(buffer
+ 1, myThis
->dataBuffer
, myThis
->dataLen
);
199 myThis
->waitingForData
->signal();
205 // **********************************************************************************
208 // **********************************************************************************
209 IOReturn
IOPMUADBController::cancelAllIO ( void )
211 if (waitingForData
!= NULL
) {
212 dataLen
= 0; // read fails with error, write fails quietly
213 waitingForData
->signal();
219 // **********************************************************************************
222 // **********************************************************************************
223 IOReturn
IOPMUADBController::setAutoPollPeriod ( int )
225 return kPMUNotSupported
;
229 // **********************************************************************************
232 // **********************************************************************************
233 IOReturn
IOPMUADBController::getAutoPollPeriod ( int * )
235 return kPMUNotSupported
;
239 // **********************************************************************************
242 // **********************************************************************************
243 IOReturn
IOPMUADBController::setAutoPollList ( UInt16 PollBitField
)
245 pollList
= PollBitField
; // remember the new poll list
250 oBuffer
[0] = 0; // Byte count in the resto of the command
251 oBuffer
[1] = 0x86; // adb Command op.
252 oBuffer
[2] = (UInt8
)(PollBitField
>> 8); // ??
253 oBuffer
[3] = (UInt8
)(PollBitField
& 0xff); // ??
255 localSendMiscCommand (kPMUpMgrADB
, 4, oBuffer
);
261 // **********************************************************************************
264 // **********************************************************************************
265 IOReturn
IOPMUADBController::getAutoPollList ( UInt16
* activeAddressMask
)
267 *activeAddressMask
= pollList
;
272 // **********************************************************************************
275 // **********************************************************************************
276 IOReturn
IOPMUADBController::setAutoPollEnable ( bool enable
)
282 if ( enable
) { // enabling autopoll
285 oBuffer
[2] = (UInt8
)(pollList
>> 8);
286 oBuffer
[3] = (UInt8
)(pollList
& 0xff);
288 localSendMiscCommand (kPMUpMgrADB
, 4, oBuffer
);
290 else { // disabling autopoll;
291 /* Waits one second for the trackpads to be up (this is needed only in old machines)
292 This is placed here because this is the fist call at wake. */
293 if (IODTMatchNubWithKeys(getPlatform()->getProvider(), "'PowerBook1,1'") ||
294 IODTMatchNubWithKeys(getPlatform()->getProvider(), "'AAPL,PowerBook1998'"))
297 localSendMiscCommand (kPMUpMgrADBoff
, 0, NULL
);
304 // **********************************************************************************
307 // **********************************************************************************
308 IOReturn
IOPMUADBController::resetBus ( void )
310 if (requestMutexLock
!= NULL
)
311 IOLockLock(requestMutexLock
);
315 oBuffer
[0] = kPMUResetADBBus
;
319 // Reset bus needs to wait for the interrupt to terminate the transaction:
320 waitingForData
= IOSyncer::create();
321 localSendMiscCommand (kPMUpMgrADB
, 3, oBuffer
);
322 waitingForData
->wait(); // wait till done
325 if (requestMutexLock
!= NULL
)
326 IOLockUnlock(requestMutexLock
);
328 /* Waits one second for the trackpads to be up (this is needed only in old machines) */
329 if (IODTMatchNubWithKeys(getPlatform()->getProvider(), "'PowerBook1,1'") ||
330 IODTMatchNubWithKeys(getPlatform()->getProvider(), "'AAPL,PowerBook1998'"))
337 // **********************************************************************************
340 // **********************************************************************************
341 IOReturn
IOPMUADBController::flushDevice ( IOADBAddress address
)
343 if (requestMutexLock
!= NULL
)
344 IOLockLock(requestMutexLock
);
348 oBuffer
[0] = kPMUFlushADB
| (address
<< kPMUADBAddressField
);
349 oBuffer
[1] = ( autopollOn
? 2 : 0 );
352 // flush device needs to wait for the interrupt to terminate the transaction
353 waitingForData
= IOSyncer::create();
354 localSendMiscCommand (kPMUpMgrADB
, 3, oBuffer
);
355 waitingForData
->wait(); // wait till done
358 if (requestMutexLock
!= NULL
)
359 IOLockUnlock(requestMutexLock
);
365 // **********************************************************************************
368 // The length parameter is ignored on entry. It is set on exit to reflect
369 // the number of bytes read from the device.
370 // **********************************************************************************
371 IOReturn
IOPMUADBController::readFromDevice ( IOADBAddress address
, IOADBRegister adbRegister
,
372 UInt8
* data
, IOByteCount
* length
)
374 if ( (length
== NULL
) || (data
== NULL
) ) {
375 return kPMUParameterError
;
378 if (requestMutexLock
!= NULL
)
379 IOLockLock(requestMutexLock
);
383 oBuffer
[0] = kPMUReadADB
| (address
<< kPMUADBAddressField
) | (adbRegister
);
384 oBuffer
[1] = ( autopollOn
? 2 : 0 );
387 // read from device needs to wait for the interrupt to terminate the transaction
388 // and to obtain the data from the device.
389 waitingForData
= IOSyncer::create();
390 localSendMiscCommand (kPMUpMgrADB
, 3, oBuffer
);
391 waitingForData
->wait(); // wait till done
394 // set caller's length
395 *length
= (dataLen
< *length
? dataLen
: *length
);
396 bcopy(dataBuffer
, data
, *length
);
398 if (requestMutexLock
!= NULL
)
399 IOLockUnlock(requestMutexLock
);
401 if (dataLen
== 0 ) { // nothing read; device isn't there
402 return ADB_RET_NOTPRESENT
;
409 // **********************************************************************************
412 // **********************************************************************************
413 IOReturn
IOPMUADBController::writeToDevice ( IOADBAddress address
, IOADBRegister adbRegister
,
414 UInt8
* data
, IOByteCount
* length
)
416 // Last check on * length > (252): since the pmu registers are 8 bit
417 // and the buffer has the first 3 bytes used for the standard paramters
418 // the max lenght can not be more than 252 bytes.
419 if ( (* length
== 0) || (data
== NULL
) || (* length
> 252) )
421 return kPMUParameterError
;
425 return kPMUNoError
; // for now let's ignore these ...
427 if (requestMutexLock
!= NULL
)
428 IOLockLock(requestMutexLock
);
432 oBuffer
[0] = kPMUWriteADB
| (address
<< kPMUADBAddressField
) | (adbRegister
);
433 oBuffer
[1] = ( autopollOn
? 2 : 0 );
434 oBuffer
[2] = *length
;
435 bcopy(data
, &oBuffer
[3], *length
);
437 // write to the device needs to wait for the interrupt to terminate the transaction
438 waitingForData
= IOSyncer::create();
439 localSendMiscCommand (kPMUpMgrADB
, 3 + *length
, oBuffer
);
440 waitingForData
->wait();
443 if (requestMutexLock
!= NULL
)
444 IOLockUnlock(requestMutexLock
);