]> git.saurik.com Git - apple/xnu.git/blame - iokit/Drivers/platform/drvApplePMU/IOPMUADBController.cpp
xnu-344.21.74.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvApplePMU / IOPMUADBController.cpp
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
A
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d7e50217
A
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.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * 12 Nov 1998 suurballe Created.
27 */
28
9bccf70c 29#include <IOKit/pwr_mgt/IOPM.h>
1c79356b
A
30#include <IOKit/IOSyncer.h>
31#include "IOPMUADBController.h"
32
33#define super IOADBController
34OSDefineMetaClassAndStructors(IOPMUADBController, IOADBController)
35
36// **********************************************************************************
37// start
38//
39// **********************************************************************************
40IOService * 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// **********************************************************************************
65bool 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:
9bccf70c 76 if (PMUdriver->callPlatformFunction("registerForPMUInterrupts", true, (void*) (kPMUADBint | kPMUenvironmentInt), (void*)handleADBInterrupt, (void*)this, NULL) != kIOReturnSuccess) {
1c79356b
A
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
9bccf70c
A
90 clamshellOpen = true;
91
1c79356b
A
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// **********************************************************************************
104void 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)
9bccf70c 114 PMUdriver->callPlatformFunction("deRegisterClient", true, (void*)this, (void*)(kPMUADBint | kPMUenvironmentInt), NULL, NULL);
1c79356b
A
115}
116
117// **********************************************************************************
118// localSendMiscCommand
119//
120// **********************************************************************************
0b4e3aa0 121IOReturn IOPMUADBController::localSendMiscCommand(int command, IOByteCount sLength, UInt8 *sBuffer)
1c79356b
A
122{
123 IOReturn returnValue = kIOReturnError;
0b4e3aa0
A
124 IOByteCount rLength = 1;
125 UInt8 rBuffer;
126
1c79356b
A
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:
0b4e3aa0 129 SendMiscCommandParameterBlock prmBlock = {command, sLength, sBuffer, &rLength, &rBuffer};
1c79356b
A
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:
9bccf70c
A
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.
1c79356b
A
156// **********************************************************************************
157
158/* static */ void
159IOPMUADBController::handleADBInterrupt(IOService *client, UInt8 interruptMask, UInt32 length, UInt8 *buffer)
160{
0b4e3aa0
A
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
9bccf70c
A
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 }
0b4e3aa0 181 if ((interruptMask & kPMUautopoll) && (myThis->autopollOn))
9bccf70c
A
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 }
1c79356b 197 else {
0b4e3aa0 198 if (myThis->waitingForData != NULL) {
1c79356b
A
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
0b4e3aa0
A
207
208// **********************************************************************************
209// cancelAllIO
210//
211// **********************************************************************************
212IOReturn 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
1c79356b
A
222// **********************************************************************************
223// setAutoPollPeriod
224//
225// **********************************************************************************
226IOReturn IOPMUADBController::setAutoPollPeriod ( int )
227{
228 return kPMUNotSupported;
229}
230
231
232// **********************************************************************************
233// getAutoPollPeriod
234//
235// **********************************************************************************
236IOReturn IOPMUADBController::getAutoPollPeriod ( int * )
237{
238 return kPMUNotSupported;
239}
240
241
242// **********************************************************************************
243// setAutoPollList
244//
245// **********************************************************************************
246IOReturn 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); // ??
0b4e3aa0
A
257
258 localSendMiscCommand (kPMUpMgrADB, 4, oBuffer);
1c79356b
A
259 }
260 return kPMUNoError;
261}
262
263
264// **********************************************************************************
265// getAutoPollList
266//
267// **********************************************************************************
268IOReturn IOPMUADBController::getAutoPollList ( UInt16 * activeAddressMask )
269{
270 *activeAddressMask = pollList;
271 return kPMUNoError;
272}
273
274
275// **********************************************************************************
276// setAutoPollEnable
277//
278// **********************************************************************************
279IOReturn IOPMUADBController::setAutoPollEnable ( bool enable )
280{
281 UInt8 oBuffer[4];
282
0b4e3aa0
A
283 autopollOn = enable;
284
1c79356b
A
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
0b4e3aa0 291 localSendMiscCommand (kPMUpMgrADB, 4, oBuffer);
1c79356b
A
292 }
293 else { // disabling autopoll;
0b4e3aa0
A
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);
1c79356b
A
301 }
302
303 return kPMUNoError;
304}
305
306
307// **********************************************************************************
308// resetBus
309//
310// **********************************************************************************
311IOReturn IOPMUADBController::resetBus ( void )
312{
313 if (requestMutexLock != NULL)
314 IOLockLock(requestMutexLock);
315
316 UInt8 oBuffer[4];
0b4e3aa0 317
1c79356b
A
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();
0b4e3aa0 324 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
1c79356b
A
325 waitingForData->wait(); // wait till done
326 waitingForData = 0;
327
328 if (requestMutexLock != NULL)
329 IOLockUnlock(requestMutexLock);
0b4e3aa0
A
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
1c79356b
A
336 return kPMUNoError;
337}
338
339
340// **********************************************************************************
341// flushDevice
342//
343// **********************************************************************************
344IOReturn 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();
0b4e3aa0 357 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
1c79356b
A
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// **********************************************************************************
374IOReturn 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();
0b4e3aa0 393 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
1c79356b
A
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// **********************************************************************************
416IOReturn 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();
0b4e3aa0 442 localSendMiscCommand (kPMUpMgrADB, 3 + *length, oBuffer);
1c79356b
A
443 waitingForData->wait();
444 waitingForData = 0;
445
446 if (requestMutexLock != NULL)
447 IOLockUnlock(requestMutexLock);
448
449 return kPMUNoError;
450}
451
452