]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/platform/drvApplePMU/IOPMUADBController.cpp
978cedac413604c0d86ac02677fa74ef794e6661
[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 * 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
26 #include <IOKit/pwr_mgt/IOPM.h>
27 #include <IOKit/IOSyncer.h>
28 #include "IOPMUADBController.h"
29
30 #define super IOADBController
31 OSDefineMetaClassAndStructors(IOPMUADBController, IOADBController)
32
33 // **********************************************************************************
34 // start
35 //
36 // **********************************************************************************
37 IOService * 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 // **********************************************************************************
62 bool 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:
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
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
87 clamshellOpen = true;
88
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 // **********************************************************************************
101 void 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)
111 PMUdriver->callPlatformFunction("deRegisterClient", true, (void*)this, (void*)(kPMUADBint | kPMUenvironmentInt), NULL, NULL);
112 }
113
114 // **********************************************************************************
115 // localSendMiscCommand
116 //
117 // **********************************************************************************
118 IOReturn IOPMUADBController::localSendMiscCommand(int command, IOByteCount sLength, UInt8 *sBuffer)
119 {
120 IOReturn returnValue = kIOReturnError;
121 IOByteCount rLength = 1;
122 UInt8 rBuffer;
123
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};
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:
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 // **********************************************************************************
154
155 /* static */ void
156 IOPMUADBController::handleADBInterrupt(IOService *client, UInt8 interruptMask, UInt32 length, UInt8 *buffer)
157 {
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
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 }
178 if ((interruptMask & kPMUautopoll) && (myThis->autopollOn))
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 }
194 else {
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();
200 }
201 }
202 }
203
204
205 // **********************************************************************************
206 // cancelAllIO
207 //
208 // **********************************************************************************
209 IOReturn 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
219 // **********************************************************************************
220 // setAutoPollPeriod
221 //
222 // **********************************************************************************
223 IOReturn IOPMUADBController::setAutoPollPeriod ( int )
224 {
225 return kPMUNotSupported;
226 }
227
228
229 // **********************************************************************************
230 // getAutoPollPeriod
231 //
232 // **********************************************************************************
233 IOReturn IOPMUADBController::getAutoPollPeriod ( int * )
234 {
235 return kPMUNotSupported;
236 }
237
238
239 // **********************************************************************************
240 // setAutoPollList
241 //
242 // **********************************************************************************
243 IOReturn 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); // ??
254
255 localSendMiscCommand (kPMUpMgrADB, 4, oBuffer);
256 }
257 return kPMUNoError;
258 }
259
260
261 // **********************************************************************************
262 // getAutoPollList
263 //
264 // **********************************************************************************
265 IOReturn IOPMUADBController::getAutoPollList ( UInt16 * activeAddressMask )
266 {
267 *activeAddressMask = pollList;
268 return kPMUNoError;
269 }
270
271
272 // **********************************************************************************
273 // setAutoPollEnable
274 //
275 // **********************************************************************************
276 IOReturn IOPMUADBController::setAutoPollEnable ( bool enable )
277 {
278 UInt8 oBuffer[4];
279
280 autopollOn = enable;
281
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
288 localSendMiscCommand (kPMUpMgrADB, 4, oBuffer);
289 }
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'"))
295 IOSleep(1500);
296
297 localSendMiscCommand (kPMUpMgrADBoff, 0, NULL);
298 }
299
300 return kPMUNoError;
301 }
302
303
304 // **********************************************************************************
305 // resetBus
306 //
307 // **********************************************************************************
308 IOReturn IOPMUADBController::resetBus ( void )
309 {
310 if (requestMutexLock != NULL)
311 IOLockLock(requestMutexLock);
312
313 UInt8 oBuffer[4];
314
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();
321 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
322 waitingForData->wait(); // wait till done
323 waitingForData = 0;
324
325 if (requestMutexLock != NULL)
326 IOLockUnlock(requestMutexLock);
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
333 return kPMUNoError;
334 }
335
336
337 // **********************************************************************************
338 // flushDevice
339 //
340 // **********************************************************************************
341 IOReturn 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();
354 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
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 // **********************************************************************************
371 IOReturn 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();
390 localSendMiscCommand (kPMUpMgrADB, 3, oBuffer);
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 // **********************************************************************************
413 IOReturn 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();
439 localSendMiscCommand (kPMUpMgrADB, 3 + *length, oBuffer);
440 waitingForData->wait();
441 waitingForData = 0;
442
443 if (requestMutexLock != NULL)
444 IOLockUnlock(requestMutexLock);
445
446 return kPMUNoError;
447 }
448
449