]> git.saurik.com Git - apple/xnu.git/blame - iokit/Drivers/platform/drvApplePMU/IOPMUADBController.cpp
xnu-344.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 *
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
9bccf70c 26#include <IOKit/pwr_mgt/IOPM.h>
1c79356b
A
27#include <IOKit/IOSyncer.h>
28#include "IOPMUADBController.h"
29
30#define super IOADBController
31OSDefineMetaClassAndStructors(IOPMUADBController, IOADBController)
32
33// **********************************************************************************
34// start
35//
36// **********************************************************************************
37IOService * IOPMUADBController::probe( IOService * provider, SInt32 * score )
38{
39 if (super::probe(provider, score) == NULL)
40 return NULL;
41
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'"))
46 return this;
47
48 // If it is a different machine the compatible property will tell us if it is a pmu-driven
49 // adb device:
50 OSData *kl = OSDynamicCast(OSData, provider->getProperty("compatible"));
51 if ((kl != NULL) && kl->isEqualTo("pmu", 3))
52 return this;
53
54 // In all the other cases we do not handle it:
55 return NULL;
56}
57
58// **********************************************************************************
59// start
60//
61// **********************************************************************************
62bool IOPMUADBController::start ( IOService * nub )
63{
64 // Wait for the PMU to show up:
65 PMUdriver = waitForService(serviceMatching("ApplePMU"));
66
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;
71
72 // Registers for the two interrupts that needs to handle:
9bccf70c 73 if (PMUdriver->callPlatformFunction("registerForPMUInterrupts", true, (void*) (kPMUADBint | kPMUenvironmentInt), (void*)handleADBInterrupt, (void*)this, NULL) != kIOReturnSuccess) {
1c79356b
A
74#ifdef VERBOSE_LOGS_ON
75 IOLog("IOPMUADBController::start registerForPMUInterrupts kPMUADBint fails\n");
76#endif // VERBOSE_LOGS_ON
77
78 return false;
79 }
80
81 // Creates the mutex lock to protect the clients list:
82 requestMutexLock = NULL;
83 requestMutexLock = IOLockAlloc();
84 if (!requestMutexLock)
85 return false;
86
9bccf70c
A
87 clamshellOpen = true;
88
1c79356b
A
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))
92 return false;
93
94 return true;
95}
96
97// **********************************************************************************
98// free
99//
100// **********************************************************************************
101void IOPMUADBController::free ( )
102{
103 // Releases the mutex lock used to protect the clients lists:
104 if (requestMutexLock != NULL) {
105 IOLockFree (requestMutexLock);
106 requestMutexLock = NULL;
107 }
108
109 // And removes the interrupt handler:
110 if (PMUdriver != NULL)
9bccf70c 111 PMUdriver->callPlatformFunction("deRegisterClient", true, (void*)this, (void*)(kPMUADBint | kPMUenvironmentInt), NULL, NULL);
1c79356b
A
112}
113
114// **********************************************************************************
115// localSendMiscCommand
116//
117// **********************************************************************************
0b4e3aa0 118IOReturn IOPMUADBController::localSendMiscCommand(int command, IOByteCount sLength, UInt8 *sBuffer)
1c79356b
A
119{
120 IOReturn returnValue = kIOReturnError;
0b4e3aa0
A
121 IOByteCount rLength = 1;
122 UInt8 rBuffer;
123
1c79356b
A
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:
0b4e3aa0 126 SendMiscCommandParameterBlock prmBlock = {command, sLength, sBuffer, &rLength, &rBuffer};
1c79356b
A
127
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);
131#endif
132
133 if (PMUdriver != NULL) {
134#ifdef VERBOSE_LOGS_ON
135 IOLog("IOPMUADBController::localSendMiscCommand calling PMUdriver->callPlatformFunction\n");
136#endif
137 returnValue = PMUdriver->callPlatformFunction("sendMiscCommand", true, (void*)&prmBlock, NULL, NULL, NULL);
138 }
139
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);
143#endif
144
145 return returnValue;
146}
147
148// **********************************************************************************
149// this is the interrupt handler for all ADB interrupts:
9bccf70c
A
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.
1c79356b
A
153// **********************************************************************************
154
155/* static */ void
156IOPMUADBController::handleADBInterrupt(IOService *client, UInt8 interruptMask, UInt32 length, UInt8 *buffer)
157{
0b4e3aa0
A
158 IOPMUADBController *myThis = OSDynamicCast(IOPMUADBController, client);
159
160 // Check if we are the right client for this interrupt:
161 if (myThis == NULL)
162 return;
163
9bccf70c
A
164 if (interruptMask & kPMUenvironmentInt)
165 {
166 if (buffer)
167 {
168 if (*buffer & kClamshellClosedEventMask)
169 myThis->clamshellOpen = false;
170 else
171 myThis->clamshellOpen = true;
172 }
173 if ( !(interruptMask & kPMUautopoll))
174 {
175 return; //Nothing left to do
176 }
177 }
0b4e3aa0 178 if ((interruptMask & kPMUautopoll) && (myThis->autopollOn))
9bccf70c
A
179 {
180 if (myThis->clamshellOpen)
181 {
182 autopollHandler(client, buffer[0], length - 1, buffer + 1); // yes, call adb input handler
183 }
184 else if ( (buffer[0] == 0x2c) && (buffer[1] == 0x7f) && (buffer[2] == 0x7f))
185 {
186 autopollHandler(client, buffer[0], length - 1, buffer + 1); // POWER down
187 }
188 else if ( (buffer[0] == 0x2c) && (buffer[1] == 0xff) && (buffer[2] == 0xff))
189 {
190 autopollHandler(client, buffer[0], length - 1, buffer + 1); // POWER up
191 }
192
193 }
1c79356b 194 else {
0b4e3aa0 195 if (myThis->waitingForData != NULL) {
1c79356b
A
196 // Complets the adb transaction
197 myThis->dataLen = length - 1;
198 bcopy(buffer + 1, myThis->dataBuffer, myThis->dataLen);
199 myThis->waitingForData->signal();
200 }
201 }
202}
203
0b4e3aa0
A
204
205// **********************************************************************************
206// cancelAllIO
207//
208// **********************************************************************************
209IOReturn IOPMUADBController::cancelAllIO ( void )
210{
211 if (waitingForData != NULL) {
212 dataLen = 0; // read fails with error, write fails quietly
213 waitingForData->signal();
214 }
215 return kPMUNoError;
216}
217
218
1c79356b
A
219// **********************************************************************************
220// setAutoPollPeriod
221//
222// **********************************************************************************
223IOReturn IOPMUADBController::setAutoPollPeriod ( int )
224{
225 return kPMUNotSupported;
226}
227
228
229// **********************************************************************************
230// getAutoPollPeriod
231//
232// **********************************************************************************
233IOReturn IOPMUADBController::getAutoPollPeriod ( int * )
234{
235 return kPMUNotSupported;
236}
237
238
239// **********************************************************************************
240// setAutoPollList
241//
242// **********************************************************************************
243IOReturn IOPMUADBController::setAutoPollList ( UInt16 PollBitField )
244{
245 pollList = PollBitField; // remember the new poll list
246
247 if ( autopollOn ) {
248 UInt8 oBuffer[4];
249
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); // ??
0b4e3aa0
A
254
255 localSendMiscCommand (kPMUpMgrADB, 4, oBuffer);
1c79356b
A
256 }
257 return kPMUNoError;
258}
259
260
261// **********************************************************************************
262// getAutoPollList
263//
264// **********************************************************************************
265IOReturn IOPMUADBController::getAutoPollList ( UInt16 * activeAddressMask )
266{
267 *activeAddressMask = pollList;
268 return kPMUNoError;
269}
270
271
272// **********************************************************************************
273// setAutoPollEnable
274//
275// **********************************************************************************
276IOReturn IOPMUADBController::setAutoPollEnable ( bool enable )
277{
278 UInt8 oBuffer[4];
279
0b4e3aa0
A
280 autopollOn = enable;
281
1c79356b
A
282 if ( enable ) { // enabling autopoll
283 oBuffer[0] = 0;
284 oBuffer[1] = 0x86;
285 oBuffer[2] = (UInt8)(pollList >> 8);
286 oBuffer[3] = (UInt8)(pollList & 0xff);
287
0b4e3aa0 288 localSendMiscCommand (kPMUpMgrADB, 4, oBuffer);
1c79356b
A
289 }
290 else { // disabling autopoll;
0b4e3aa0
A
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'"))
295 IOSleep(1500);
296
297 localSendMiscCommand (kPMUpMgrADBoff, 0, NULL);
1c79356b
A
298 }
299
300 return kPMUNoError;
301}
302
303
304// **********************************************************************************
305// resetBus
306//
307// **********************************************************************************
308IOReturn IOPMUADBController::resetBus ( void )
309{
310 if (requestMutexLock != NULL)
311 IOLockLock(requestMutexLock);
312
313 UInt8 oBuffer[4];
0b4e3aa0 314
1c79356b
A
315 oBuffer[0] = kPMUResetADBBus;
316 oBuffer[1] = 0;
317 oBuffer[2] = 0;
318
319 // Reset bus needs to wait for the interrupt to terminate the transaction:
320 waitingForData = IOSyncer::create();
0b4e3aa0 321 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
1c79356b
A
322 waitingForData->wait(); // wait till done
323 waitingForData = 0;
324
325 if (requestMutexLock != NULL)
326 IOLockUnlock(requestMutexLock);
0b4e3aa0
A
327
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'"))
331 IOSleep(1500);
332
1c79356b
A
333 return kPMUNoError;
334}
335
336
337// **********************************************************************************
338// flushDevice
339//
340// **********************************************************************************
341IOReturn IOPMUADBController::flushDevice ( IOADBAddress address )
342{
343 if (requestMutexLock != NULL)
344 IOLockLock(requestMutexLock);
345
346 UInt8 oBuffer[4];
347
348 oBuffer[0] = kPMUFlushADB | (address << kPMUADBAddressField);
349 oBuffer[1] = ( autopollOn ? 2 : 0 );
350 oBuffer[2] = 0;
351
352 // flush device needs to wait for the interrupt to terminate the transaction
353 waitingForData = IOSyncer::create();
0b4e3aa0 354 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
1c79356b
A
355 waitingForData->wait(); // wait till done
356 waitingForData = 0;
357
358 if (requestMutexLock != NULL)
359 IOLockUnlock(requestMutexLock);
360
361 return kPMUNoError;
362}
363
364
365// **********************************************************************************
366// readFromDevice
367//
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// **********************************************************************************
371IOReturn IOPMUADBController::readFromDevice ( IOADBAddress address, IOADBRegister adbRegister,
372 UInt8 * data, IOByteCount * length )
373{
374 if ( (length == NULL) || (data == NULL) ) {
375 return kPMUParameterError;
376 }
377
378 if (requestMutexLock != NULL)
379 IOLockLock(requestMutexLock);
380
381 UInt8 oBuffer[4];
382
383 oBuffer[0] = kPMUReadADB | (address << kPMUADBAddressField) | (adbRegister);
384 oBuffer[1] = ( autopollOn ? 2 : 0 );
385 oBuffer[2] = 0;
386
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();
0b4e3aa0 390 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
1c79356b
A
391 waitingForData->wait(); // wait till done
392 waitingForData = 0;
393
394 // set caller's length
395 *length = (dataLen < *length ? dataLen : *length);
396 bcopy(dataBuffer, data, *length);
397
398 if (requestMutexLock != NULL)
399 IOLockUnlock(requestMutexLock);
400
401 if (dataLen == 0 ) { // nothing read; device isn't there
402 return ADB_RET_NOTPRESENT;
403 }
404
405 return ADB_RET_OK;
406}
407
408
409// **********************************************************************************
410// writeToDevice
411//
412// **********************************************************************************
413IOReturn IOPMUADBController::writeToDevice ( IOADBAddress address, IOADBRegister adbRegister,
414 UInt8 * data, IOByteCount * length )
415{
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) )
420 {
421 return kPMUParameterError;
422 }
423
424 if (address == 0)
425 return kPMUNoError; // for now let's ignore these ...
426
427 if (requestMutexLock != NULL)
428 IOLockLock(requestMutexLock);
429
430 UInt8 oBuffer[256];
431
432 oBuffer[0] = kPMUWriteADB | (address << kPMUADBAddressField) | (adbRegister);
433 oBuffer[1] = ( autopollOn ? 2 : 0 );
434 oBuffer[2] = *length;
435 bcopy(data, &oBuffer[3], *length);
436
437 // write to the device needs to wait for the interrupt to terminate the transaction
438 waitingForData = IOSyncer::create();
0b4e3aa0 439 localSendMiscCommand (kPMUpMgrADB, 3 + *length, oBuffer);
1c79356b
A
440 waitingForData->wait();
441 waitingForData = 0;
442
443 if (requestMutexLock != NULL)
444 IOLockUnlock(requestMutexLock);
445
446 return kPMUNoError;
447}
448
449