]>
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 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
24 | * | |
25 | * IOKernelDebugger.cpp | |
26 | * | |
27 | * HISTORY | |
28 | */ | |
29 | ||
30 | #include <IOKit/assert.h> | |
31 | #include <IOKit/IOLib.h> | |
32 | #include <IOKit/IOMessage.h> | |
33 | #include <IOKit/IOLocks.h> | |
34 | #include <IOKit/network/IONetworkController.h> | |
35 | #include <IOKit/network/IOKernelDebugger.h> | |
36 | #include <libkern/OSAtomic.h> | |
37 | ||
38 | //--------------------------------------------------------------------------- | |
39 | // IOKDP | |
40 | ||
41 | #define kIOKDPEnableKDP "IOEnableKDP" | |
42 | #define kIOKDPDriverMatch "IODriverMatch" | |
43 | #define kIOKDPDriverNubMatch "IODriverNubMatch" | |
44 | ||
45 | class IOKDP : public IOService | |
46 | { | |
47 | OSDeclareDefaultStructors( IOKDP ) | |
48 | ||
49 | public: | |
50 | static void initialize(); | |
51 | ||
52 | virtual bool start( IOService * provider ); | |
53 | ||
54 | virtual void stop( IOService * provider ); | |
55 | ||
56 | virtual bool matchProvider( IOService * provider ); | |
57 | ||
58 | virtual bool matchServiceWithDictionary( IOService * service, | |
59 | OSDictionary * match ); | |
60 | ||
61 | virtual IOReturn message( UInt32 type, | |
62 | IOService * provider, | |
63 | void * argument = 0 ); | |
64 | }; | |
65 | ||
66 | //--------------------------------------------------------------------------- | |
67 | // IOKDP defined globals. | |
68 | ||
69 | static IOLock * gIOKDPLock = 0; | |
70 | static IOKDP * gIOKDP = 0; | |
71 | ||
72 | #define super IOService | |
73 | OSDefineMetaClassAndStructorsWithInit( IOKDP, IOService, | |
74 | IOKDP::initialize() ) | |
75 | ||
76 | //--------------------------------------------------------------------------- | |
77 | // Match the provider with the matching dictionary in our property table. | |
78 | ||
79 | bool IOKDP::matchProvider(IOService * provider) | |
80 | { | |
81 | IOService * driver = 0; | |
82 | IOService * driverNub = 0; | |
83 | OSBoolean * aBool; | |
84 | ||
85 | if ( provider ) driver = provider->getProvider(); | |
86 | if ( driver ) driverNub = driver->getProvider(); | |
87 | ||
88 | if ( (driver == 0) || (driverNub == 0) ) | |
89 | return false; | |
90 | ||
91 | if ( ( aBool = OSDynamicCast(OSBoolean, getProperty(kIOKDPEnableKDP)) ) && | |
92 | ( aBool->isTrue() == false ) ) | |
93 | return false; | |
94 | ||
95 | if ( matchServiceWithDictionary( driver, (OSDictionary *) | |
96 | getProperty(kIOKDPDriverMatch)) ) | |
97 | { | |
98 | // IOLog("IOKDP: %s\n", kIOKDPDriverMatch); | |
99 | return true; | |
100 | } | |
101 | ||
102 | if ( matchServiceWithDictionary( driverNub, (OSDictionary *) | |
103 | getProperty(kIOKDPDriverNubMatch)) ) | |
104 | { | |
105 | // IOLog("IOKDP: %s\n", kIOKDPDriverNubMatch); | |
106 | return true; | |
107 | } | |
108 | ||
109 | return false; | |
110 | } | |
111 | ||
112 | //--------------------------------------------------------------------------- | |
113 | // Match an IOService with a matching dictionary. | |
114 | ||
115 | bool IOKDP::matchServiceWithDictionary(IOService * service, | |
116 | OSDictionary * match) | |
117 | { | |
118 | OSCollectionIterator * matchIter; | |
119 | OSCollectionIterator * arrayIter = 0; | |
120 | OSCollection * array; | |
121 | OSObject * objM; | |
122 | OSObject * objP; | |
123 | OSSymbol * sym; | |
124 | bool isMatch = false; | |
125 | ||
126 | if ( ( OSDynamicCast(OSDictionary, match) == 0 ) || | |
127 | ( match->getCount() == 0 ) || | |
128 | ( (matchIter = OSCollectionIterator::withCollection(match)) == 0 ) ) | |
129 | return false; | |
130 | ||
131 | while ( ( sym = OSDynamicCast(OSSymbol, matchIter->getNextObject()) ) ) | |
132 | { | |
133 | objM = match->getObject(sym); | |
134 | objP = service->getProperty(sym); | |
135 | ||
136 | isMatch = false; | |
137 | ||
138 | if ( arrayIter ) | |
139 | { | |
140 | arrayIter->release(); | |
141 | arrayIter = 0; | |
142 | } | |
143 | ||
144 | if ( (array = OSDynamicCast( OSCollection, objM )) ) | |
145 | { | |
146 | arrayIter = OSCollectionIterator::withCollection( array ); | |
147 | if ( arrayIter == 0 ) break; | |
148 | } | |
149 | ||
150 | do { | |
151 | if ( arrayIter && ((objM = arrayIter->getNextObject()) == 0) ) | |
152 | break; | |
153 | ||
154 | if ( objM && objP && objM->isEqualTo(objP) ) | |
155 | { | |
156 | isMatch = true; | |
157 | break; | |
158 | } | |
159 | } | |
160 | while ( arrayIter ); | |
161 | ||
162 | if ( isMatch == false ) break; | |
163 | } | |
164 | ||
165 | if ( arrayIter ) arrayIter->release(); | |
166 | matchIter->release(); | |
167 | ||
168 | return isMatch; | |
169 | } | |
170 | ||
171 | //--------------------------------------------------------------------------- | |
172 | // IOKDP class initializer. | |
173 | ||
174 | void IOKDP::initialize() | |
175 | { | |
176 | gIOKDPLock = IOLockAlloc(); | |
177 | assert( gIOKDPLock ); | |
178 | } | |
179 | ||
180 | //--------------------------------------------------------------------------- | |
181 | // start/stop/message. | |
182 | ||
183 | bool IOKDP::start( IOService * provider ) | |
184 | { | |
185 | bool ret = false; | |
186 | ||
187 | if ( super::start(provider) == false ) | |
188 | return false; | |
189 | ||
190 | IOLockLock( gIOKDPLock ); | |
191 | ||
192 | do { | |
193 | if ( gIOKDP ) | |
194 | break; | |
195 | ||
196 | if ( matchProvider(provider) == false ) | |
197 | break; | |
198 | ||
199 | if ( provider->open(this) == false ) | |
200 | break; | |
201 | ||
202 | publishResource("kdp"); | |
203 | ||
204 | gIOKDP = this; | |
205 | ret = true; | |
206 | } | |
207 | while ( false ); | |
208 | ||
209 | IOLockUnlock( gIOKDPLock ); | |
210 | ||
211 | return ret; | |
212 | } | |
213 | ||
214 | void IOKDP::stop( IOService * provider ) | |
215 | { | |
216 | provider->close(this); | |
217 | ||
218 | IOLockLock( gIOKDPLock ); | |
219 | ||
220 | if ( gIOKDP == this ) gIOKDP = 0; | |
221 | ||
222 | IOLockUnlock( gIOKDPLock ); | |
223 | ||
224 | super::stop(provider); | |
225 | } | |
226 | ||
227 | IOReturn IOKDP::message( UInt32 type, | |
228 | IOService * provider, | |
229 | void * argument ) | |
230 | { | |
231 | if ( type == kIOMessageServiceIsTerminated ) | |
232 | { | |
233 | provider->close(this); | |
234 | } | |
235 | return kIOReturnSuccess; | |
236 | } | |
237 | ||
238 | ||
239 | //--------------------------------------------------------------------------- | |
240 | // IOKernelDebugger | |
241 | ||
242 | extern "C" { | |
243 | // | |
244 | // Defined in osfmk/kdp/kdp_en_debugger.h, but the header file is not | |
245 | // exported, thus the definition is replicated here. | |
246 | // | |
247 | typedef void (*kdp_send_t)( void * pkt, UInt pkt_len ); | |
248 | typedef void (*kdp_receive_t)( void * pkt, UInt * pkt_len, UInt timeout ); | |
249 | void kdp_register_send_receive( kdp_send_t send, kdp_receive_t receive ); | |
250 | } | |
251 | ||
252 | #undef super | |
253 | #define super IOService | |
254 | OSDefineMetaClassAndStructors( IOKernelDebugger, IOService ) | |
255 | OSMetaClassDefineReservedUnused( IOKernelDebugger, 0); | |
256 | OSMetaClassDefineReservedUnused( IOKernelDebugger, 1); | |
257 | OSMetaClassDefineReservedUnused( IOKernelDebugger, 2); | |
258 | OSMetaClassDefineReservedUnused( IOKernelDebugger, 3); | |
259 | ||
260 | // IOKernelDebugger global variables. | |
261 | // | |
262 | IOService * gIODebuggerDevice = 0; | |
263 | IODebuggerTxHandler gIODebuggerTxHandler = 0; | |
264 | IODebuggerRxHandler gIODebuggerRxHandler = 0; | |
265 | UInt32 gIODebuggerTxBytes = 0; | |
266 | UInt32 gIODebuggerRxBytes = 0; | |
267 | SInt32 gIODebuggerSemaphore = 0; | |
268 | UInt32 gIODebuggerFlag = 0; | |
269 | ||
270 | // Global debugger flags. | |
271 | // | |
272 | enum { | |
273 | kIODebuggerFlagRegistered = 0x01, | |
274 | kIODebuggerFlagWarnNullHandler = 0x02 | |
275 | }; | |
276 | ||
277 | //--------------------------------------------------------------------------- | |
278 | // The KDP receive dispatch function. Dispatches KDP receive requests to the | |
279 | // registered receive handler. This function is registered with KDP via | |
280 | // kdp_register_send_receive(). | |
281 | ||
282 | void IOKernelDebugger::kdpReceiveDispatcher( void * buffer, | |
283 | UInt32 * length, | |
284 | UInt32 timeout ) | |
285 | { | |
286 | *length = 0; // return a zero length field by default. | |
287 | ||
288 | if ( gIODebuggerSemaphore ) return; // FIXME - Driver is busy! | |
289 | ||
290 | (*gIODebuggerRxHandler)( gIODebuggerDevice, buffer, length, timeout ); | |
291 | ||
292 | gIODebuggerRxBytes += *length; | |
293 | } | |
294 | ||
295 | //--------------------------------------------------------------------------- | |
296 | // The KDP transmit dispatch function. Dispatches KDP receive requests to the | |
297 | // registered transmit handler. This function is registered with KDP via | |
298 | // kdp_register_send_receive(). | |
299 | ||
300 | void IOKernelDebugger::kdpTransmitDispatcher( void * buffer, UInt32 length ) | |
301 | { | |
302 | if ( gIODebuggerSemaphore ) return; // FIXME - Driver is busy! | |
303 | ||
304 | (*gIODebuggerTxHandler)( gIODebuggerDevice, buffer, length ); | |
305 | ||
306 | gIODebuggerTxBytes += length; | |
307 | } | |
308 | ||
309 | //--------------------------------------------------------------------------- | |
310 | // Null debugger handlers. | |
311 | ||
312 | void IOKernelDebugger::nullTxHandler( IOService * target, | |
313 | void * buffer, | |
314 | UInt32 length ) | |
315 | { | |
316 | } | |
317 | ||
318 | void IOKernelDebugger::nullRxHandler( IOService * target, | |
319 | void * buffer, | |
320 | UInt32 * length, | |
321 | UInt32 timeout ) | |
322 | { | |
323 | if ( gIODebuggerFlag & kIODebuggerFlagWarnNullHandler ) | |
324 | { | |
325 | IOLog("IOKernelDebugger::%s no debugger device\n", __FUNCTION__); | |
326 | gIODebuggerFlag &= ~kIODebuggerFlagWarnNullHandler; | |
327 | } | |
328 | } | |
329 | ||
330 | //--------------------------------------------------------------------------- | |
331 | // Take the debugger lock conditionally. | |
332 | ||
333 | IODebuggerLockState IOKernelDebugger::lock( IOService * object ) | |
334 | { | |
335 | if ( gIODebuggerDevice == object ) | |
336 | { | |
337 | OSIncrementAtomic( &gIODebuggerSemaphore ); | |
338 | return kIODebuggerLockTaken; | |
339 | } | |
340 | return (IODebuggerLockState) 0; | |
341 | } | |
342 | ||
343 | //--------------------------------------------------------------------------- | |
344 | // Release the debugger lock if the kIODebuggerLockTaken flag is set. | |
345 | ||
346 | void IOKernelDebugger::unlock( IODebuggerLockState state ) | |
347 | { | |
348 | if ( state & kIODebuggerLockTaken ) | |
349 | OSDecrementAtomic( &gIODebuggerSemaphore ); | |
350 | } | |
351 | ||
352 | //--------------------------------------------------------------------------- | |
353 | // Initialize an IOKernelDebugger instance. | |
354 | ||
355 | bool IOKernelDebugger::init( IOService * target, | |
356 | IODebuggerTxHandler txHandler, | |
357 | IODebuggerRxHandler rxHandler ) | |
358 | { | |
359 | if ( ( super::init() == false ) || | |
360 | ( OSDynamicCast(IOService, target) == 0 ) || | |
361 | ( txHandler == 0 ) || | |
362 | ( rxHandler == 0 ) ) | |
363 | { | |
364 | return false; | |
365 | } | |
366 | ||
367 | // Cache the target and handlers provided. | |
368 | ||
369 | _target = target; | |
370 | _txHandler = txHandler; | |
371 | _rxHandler = rxHandler; | |
372 | ||
373 | return true; | |
374 | } | |
375 | ||
376 | //--------------------------------------------------------------------------- | |
377 | // Factory method which performs allocation and initialization of an | |
378 | // IOKernelDebugger instance. | |
379 | ||
380 | IOKernelDebugger * IOKernelDebugger::debugger( IOService * target, | |
381 | IODebuggerTxHandler txHandler, | |
382 | IODebuggerRxHandler rxHandler ) | |
383 | { | |
384 | IOKernelDebugger * debugger = new IOKernelDebugger; | |
385 | ||
386 | if (debugger && (debugger->init( target, txHandler, rxHandler ) == false)) | |
387 | { | |
388 | debugger->release(); | |
389 | debugger = 0; | |
390 | } | |
391 | ||
392 | return debugger; | |
393 | } | |
394 | ||
395 | //--------------------------------------------------------------------------- | |
396 | // Register the debugger handlers. | |
397 | ||
398 | void IOKernelDebugger::registerHandler( IOService * target, | |
399 | IODebuggerTxHandler txHandler, | |
400 | IODebuggerRxHandler rxHandler ) | |
401 | { | |
402 | bool doRegister; | |
403 | ||
404 | assert( ( target == gIODebuggerDevice ) || | |
405 | ( target == 0 ) || | |
406 | ( gIODebuggerDevice == 0 ) ); | |
407 | ||
408 | doRegister = ( target && ( txHandler != 0 ) && ( rxHandler != 0 ) ); | |
409 | ||
410 | if ( txHandler == 0 ) txHandler = &IOKernelDebugger::nullTxHandler; | |
411 | if ( rxHandler == 0 ) rxHandler = &IOKernelDebugger::nullRxHandler; | |
412 | ||
413 | OSIncrementAtomic( &gIODebuggerSemaphore ); | |
414 | ||
415 | gIODebuggerDevice = target; | |
416 | gIODebuggerTxHandler = txHandler; | |
417 | gIODebuggerRxHandler = rxHandler; | |
418 | gIODebuggerFlag |= kIODebuggerFlagWarnNullHandler; | |
419 | ||
420 | OSDecrementAtomic( &gIODebuggerSemaphore ); | |
421 | ||
422 | if ( doRegister && (( gIODebuggerFlag & kIODebuggerFlagRegistered ) == 0) ) | |
423 | { | |
424 | // Register dispatch function, these in turn will call the | |
425 | // handlers when the debugger is active. | |
426 | // | |
427 | // Note: The following call may trigger an immediate break | |
428 | // to the debugger. | |
429 | ||
430 | kdp_register_send_receive( (kdp_send_t) kdpTransmitDispatcher, | |
431 | (kdp_receive_t) kdpReceiveDispatcher ); | |
432 | ||
433 | // Limit ourself to a single real KDP registration. | |
434 | ||
435 | gIODebuggerFlag |= kIODebuggerFlagRegistered; | |
436 | } | |
437 | } | |
438 | ||
439 | //--------------------------------------------------------------------------- | |
440 | // Called by open() with the arbitration lock held. | |
441 | ||
442 | bool IOKernelDebugger::handleOpen( IOService * forClient, | |
443 | IOOptionBits options, | |
444 | void * arg ) | |
445 | { | |
446 | IONetworkController * ctr = OSDynamicCast(IONetworkController, _target); | |
447 | bool ret = false; | |
448 | ||
449 | do { | |
450 | // Only a single client at a time. | |
451 | ||
452 | if ( _client ) break; | |
453 | ||
454 | // Register the target to prime the lock()/unlock() functionality | |
455 | // before opening the target. | |
456 | ||
457 | registerHandler( _target ); | |
458 | ||
459 | // While the target is opened/enabled, it must block any thread | |
460 | // which may acquire the debugger lock in its execution path. | |
461 | ||
462 | if ( _target->open( this ) == false ) | |
463 | break; | |
464 | ||
465 | // Register interest in receiving notifications about controller | |
466 | // power state changes. | |
467 | // | |
468 | // We are making an assumption that the controller is 'usable' and | |
469 | // the next notification will inform this object that the controller | |
470 | // has become unusable, there is no support for cases when the | |
471 | // controller is already in an 'unusable' state. | |
472 | ||
473 | _pmDisabled = false; | |
474 | ||
475 | if ( ctr ) | |
476 | { | |
477 | // Register to receive PM notifications for controller power | |
478 | // state changes. | |
479 | ||
480 | ctr->registerInterestedDriver( this ); | |
481 | ||
482 | if ( ctr->doEnable( this ) != kIOReturnSuccess ) | |
483 | { | |
484 | ctr->deRegisterInterestedDriver( this ); | |
485 | break; | |
486 | } | |
487 | } | |
488 | ||
489 | // After the target has been opened, complete the registration. | |
490 | ||
491 | IOLog("%s: Debugger attached\n", getName()); | |
492 | registerHandler( _target, _txHandler, _rxHandler ); | |
493 | ||
494 | // Remember the client. | |
495 | ||
496 | _client = forClient; | |
497 | ||
498 | ret = true; | |
499 | } | |
500 | while (0); | |
501 | ||
502 | if ( ret == false ) | |
503 | { | |
504 | registerHandler( 0 ); | |
505 | _target->close( this ); | |
506 | } | |
507 | ||
508 | return ret; | |
509 | } | |
510 | ||
511 | //--------------------------------------------------------------------------- | |
512 | // Called by IOService::close() with the arbitration lock held. | |
513 | ||
514 | void IOKernelDebugger::handleClose( IOService * forClient, | |
515 | IOOptionBits options ) | |
516 | { | |
517 | IONetworkController * ctr = OSDynamicCast(IONetworkController, _target); | |
518 | ||
519 | if ( _client && ( _client == forClient ) ) | |
520 | { | |
521 | // There is no KDP un-registration. The best we can do is to | |
522 | // register dummy handlers. | |
523 | ||
524 | registerHandler( 0 ); | |
525 | ||
526 | if ( ctr ) | |
527 | { | |
528 | // Disable controller if it is not already disabled. | |
529 | ||
530 | if ( _pmDisabled == false ) | |
531 | { | |
532 | ctr->doDisable( this ); | |
533 | } | |
534 | ||
535 | // Before closing the controller, remove interest in receiving | |
536 | // notifications about controller power state changes. | |
537 | ||
538 | ctr->deRegisterInterestedDriver( this ); | |
539 | } | |
540 | ||
541 | _client = 0; | |
542 | ||
543 | _target->close( this ); | |
544 | } | |
545 | } | |
546 | ||
547 | //--------------------------------------------------------------------------- | |
548 | // Called by IOService::isOpen() with the arbitration lock held. | |
549 | ||
550 | bool IOKernelDebugger::handleIsOpen( const IOService * forClient ) const | |
551 | { | |
552 | if ( forClient == 0 ) | |
553 | return ( forClient != _client ); | |
554 | else | |
555 | return ( forClient == _client ); | |
556 | } | |
557 | ||
558 | //--------------------------------------------------------------------------- | |
559 | // Free the IOKernelDebugger object. | |
560 | ||
561 | void IOKernelDebugger::free() | |
562 | { | |
563 | // IOLog("IOKernelDebugger::%s %p\n", __FUNCTION__, this); | |
564 | super::free(); | |
565 | } | |
566 | ||
567 | #define PM_SECS(x) ((x) * 1000 * 1000) | |
568 | ||
569 | //--------------------------------------------------------------------------- | |
570 | // Handle controller's power state change notitifications. | |
571 | ||
572 | IOReturn | |
573 | IOKernelDebugger::powerStateWillChangeTo( IOPMPowerFlags flags, | |
574 | unsigned long stateNumber, | |
575 | IOService * policyMaker ) | |
576 | { | |
577 | IOReturn ret = IOPMAckImplied; | |
578 | ||
579 | if ( ( flags & IOPMDeviceUsable ) == 0 ) | |
580 | { | |
581 | // Controller is about to transition to an un-usable state. | |
582 | // The debugger nub should be disabled. | |
583 | ||
584 | this->retain(); | |
585 | ||
586 | thread_call_func( (thread_call_func_t) pmDisableDebugger, | |
587 | this, /* parameter */ | |
588 | FALSE ); /* disable unique call filter */ | |
589 | ||
590 | ret = PM_SECS(3); /* Must ACK within 3 seconds */ | |
591 | } | |
592 | ||
593 | return ret; | |
594 | } | |
595 | ||
596 | IOReturn | |
597 | IOKernelDebugger::powerStateDidChangeTo( IOPMPowerFlags flags, | |
598 | unsigned long stateNumber, | |
599 | IOService * policyMaker ) | |
600 | { | |
601 | IOReturn ret = IOPMAckImplied; | |
602 | ||
603 | if ( flags & IOPMDeviceUsable ) | |
604 | { | |
605 | // Controller has transitioned to an usable state. | |
606 | // The debugger nub should be enabled if necessary. | |
607 | ||
608 | this->retain(); | |
609 | ||
610 | thread_call_func( (thread_call_func_t) pmEnableDebugger, | |
611 | this, /* parameter */ | |
612 | FALSE ); /* disable unique call filter */ | |
613 | ||
614 | ret = PM_SECS(3); /* Must ACK within 3 seconds */ | |
615 | } | |
616 | ||
617 | return ret; | |
618 | } | |
619 | ||
620 | //--------------------------------------------------------------------------- | |
621 | // Static member function: Enable the debugger nub after the controller | |
622 | // transitions into an usable state. | |
623 | ||
624 | void IOKernelDebugger::pmEnableDebugger( IOKernelDebugger * debugger ) | |
625 | { | |
626 | IONetworkController * ctr; | |
627 | assert( debugger ); | |
628 | ||
629 | ctr = OSDynamicCast( IONetworkController, debugger->_target ); | |
630 | ||
631 | debugger->lockForArbitration(); | |
632 | ||
633 | if ( debugger->_client && ( debugger->_pmDisabled == true ) ) | |
634 | { | |
635 | if ( ctr && ( ctr->doEnable( debugger ) != kIOReturnSuccess ) ) | |
636 | { | |
637 | // This is bad, unable to re-enable the controller after sleep. | |
638 | IOLog("IOKernelDebugger: Unable to re-enable controller\n"); | |
639 | } | |
640 | else | |
641 | { | |
642 | registerHandler( debugger->_target, debugger->_txHandler, | |
643 | debugger->_rxHandler ); | |
644 | ||
645 | debugger->_pmDisabled = false; | |
646 | } | |
647 | } | |
648 | ||
649 | debugger->unlockForArbitration(); | |
650 | ||
651 | // Ack the power state change. | |
652 | debugger->_target->acknowledgePowerChange( debugger ); | |
653 | ||
654 | debugger->release(); | |
655 | } | |
656 | ||
657 | //--------------------------------------------------------------------------- | |
658 | // Static member function: Disable the debugger nub before the controller | |
659 | // transitions into an unusable state. | |
660 | ||
661 | void IOKernelDebugger::pmDisableDebugger( IOKernelDebugger * debugger ) | |
662 | { | |
663 | IONetworkController * ctr; | |
664 | assert( debugger ); | |
665 | ||
666 | ctr = OSDynamicCast( IONetworkController, debugger->_target ); | |
667 | ||
668 | debugger->lockForArbitration(); | |
669 | ||
670 | if ( debugger->_client && ( debugger->_pmDisabled == false ) ) | |
671 | { | |
672 | // Keep an open on the controller, but inhibit access to the | |
673 | // controller's debugger handlers, and disable controller's | |
674 | // hardware support for the debugger. | |
675 | ||
676 | registerHandler( 0 ); | |
677 | if ( ctr ) ctr->doDisable( debugger ); | |
678 | ||
679 | debugger->_pmDisabled = true; | |
680 | } | |
681 | ||
682 | debugger->unlockForArbitration(); | |
683 | ||
684 | // Ack the power state change. | |
685 | debugger->_target->acknowledgePowerChange( debugger ); | |
686 | ||
687 | debugger->release(); | |
688 | } |