]>
Commit | Line | Data |
---|---|---|
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 | |
34 | OSDefineMetaClassAndStructors(IOPMUADBController, IOADBController) | |
35 | ||
36 | // ********************************************************************************** | |
37 | // start | |
38 | // | |
39 | // ********************************************************************************** | |
40 | IOService * 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 | // ********************************************************************************** | |
65 | bool 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 | // ********************************************************************************** | |
104 | void 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 | 121 | IOReturn 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 | |
159 | IOPMUADBController::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 | // ********************************************************************************** | |
212 | IOReturn 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 | // ********************************************************************************** | |
226 | IOReturn IOPMUADBController::setAutoPollPeriod ( int ) | |
227 | { | |
228 | return kPMUNotSupported; | |
229 | } | |
230 | ||
231 | ||
232 | // ********************************************************************************** | |
233 | // getAutoPollPeriod | |
234 | // | |
235 | // ********************************************************************************** | |
236 | IOReturn IOPMUADBController::getAutoPollPeriod ( int * ) | |
237 | { | |
238 | return kPMUNotSupported; | |
239 | } | |
240 | ||
241 | ||
242 | // ********************************************************************************** | |
243 | // setAutoPollList | |
244 | // | |
245 | // ********************************************************************************** | |
246 | IOReturn 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 | // ********************************************************************************** | |
268 | IOReturn IOPMUADBController::getAutoPollList ( UInt16 * activeAddressMask ) | |
269 | { | |
270 | *activeAddressMask = pollList; | |
271 | return kPMUNoError; | |
272 | } | |
273 | ||
274 | ||
275 | // ********************************************************************************** | |
276 | // setAutoPollEnable | |
277 | // | |
278 | // ********************************************************************************** | |
279 | IOReturn 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 | // ********************************************************************************** | |
311 | IOReturn 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 | // ********************************************************************************** | |
344 | IOReturn 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 | // ********************************************************************************** | |
374 | IOReturn 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 | // ********************************************************************************** | |
416 | IOReturn 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 |