]>
Commit | Line | Data |
---|---|---|
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 | |
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: | |
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 | // ********************************************************************************** | |
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) | |
9bccf70c | 111 | PMUdriver->callPlatformFunction("deRegisterClient", true, (void*)this, (void*)(kPMUADBint | kPMUenvironmentInt), NULL, NULL); |
1c79356b A |
112 | } |
113 | ||
114 | // ********************************************************************************** | |
115 | // localSendMiscCommand | |
116 | // | |
117 | // ********************************************************************************** | |
0b4e3aa0 | 118 | IOReturn 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 | |
156 | IOPMUADBController::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 | // ********************************************************************************** | |
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 | ||
1c79356b A |
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); // ?? | |
0b4e3aa0 A |
254 | |
255 | localSendMiscCommand (kPMUpMgrADB, 4, oBuffer); | |
1c79356b A |
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 | ||
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 | // ********************************************************************************** | |
308 | IOReturn 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 | // ********************************************************************************** | |
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(); | |
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 | // ********************************************************************************** | |
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(); | |
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 | // ********************************************************************************** | |
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(); | |
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 |