1/* IrDAComm.h - Start up IrDA and the IrComm client */ 2 3#include <IOKit/IOTimerEventSource.h> 4#include <IOKit/IOCommandGate.h> 5#include "IrDAComm.h" 6#include "IrGlue.h" 7#include "IrComm.h" 8#include "CTimer.h" 9#include "IrDALog.h" 10 11#if (hasTracing > 0 && hasIrDACommTracing > 0) 12 13enum tracecodes 14{ 15 kLogNew = 1, 16 kLogFree, 17 kLogInit, 18 kLogStop, 19 kLogStop1, 20 kLogStopThread, 21 22 kLogTxBufferAvailable, 23 kLogWrite, 24 kLogReadComplete, 25 kLogReturnCredit, 26 kLogConnectionStatus, 27 kLogTransmitComplete, 28 kLogSetSpeedComplete, 29 kLogBackEnable, 30 31 kLogTimer, 32 kLogTimerFinished, 33 34 kLogXmitCompleteErr, 35 kLogReturnCreditErr, 36 37 kLogDoSomething, 38 kLogStateChange 39}; 40 41static 42EventTraceCauseDesc gTraceEvents[] = { 43 {kLogNew, "IrDAComm: new, obj="}, 44 {kLogFree, "IrDAComm: free, obj="}, 45 {kLogInit, "IrDAComm: init, obj="}, 46 {kLogStop, "IrDAComm: stop, obj="}, 47 {kLogStop1, "IrDAComm: stop waiting for disconnect"}, 48 {kLogStopThread, "IrDAComm: stop thread"}, 49 50 {kLogTxBufferAvailable, "IrDAComm: tx buffer available"}, 51 {kLogWrite, "IrDAComm: write, state=,length="}, 52 {kLogReadComplete, "IrDAComm: pkt read complete, length="}, 53 {kLogReturnCredit, "IrDAComm: return credit, bytecount="}, 54 {kLogConnectionStatus, "IrDAComm: new connection status, state=, connected="}, 55 {kLogTransmitComplete, "IrDAComm: pkt transmit complete, worked="}, 56 {kLogSetSpeedComplete, "IrDAComm: set speed complete"}, 57 {kLogBackEnable, "IrDAComm: back enable, write active="}, 58 59 {kLogTimer, "IrDAComm: timer routine entry, state="}, 60 {kLogTimerFinished, "IrDAComm: timer routine exit"}, 61 62 {kLogXmitCompleteErr, "IrDAComm: ERROR. transmit complete while stack is active"}, 63 {kLogReturnCreditErr, "IrDAComm: ERROR. return credit while stack is active"}, 64 65 {kLogDoSomething, "IrDAComm: run command in gate, cmd code="}, 66 {kLogStateChange, "IrDAComm: state change entry, event=, current state="} 67}; 68 69#define XTRACE(x, y, z) IrDALogAdd ( x, y, (uintptr_t)z & 0xffff, gTraceEvents, true) 70#else 71#define XTRACE(x, y, z) ((void)0) 72#endif 73 74extern "C" void timeoutRoutine(OSObject *owner, IOTimerEventSource *sender); 75 76enum { // command codes for DoSomething 77 cmdTxBufferAvailable, 78 cmdWrite, 79 cmdReturnCredit, 80 cmdStop, 81 cmdStopEvent, 82 cmdReadComplete, 83 cmdXmitComplete, 84 cmdSetSpeedComplete 85}; 86 87/****************************************************************************************************/ 88#define super OSObject 89 90 OSDefineMetaClassAndStructors(IrDAComm, OSObject); 91 92 93// 94// factory create 95// 96/*static*/ 97IrDAComm * 98IrDAComm::irDAComm(AppleIrDASerial *driver, AppleIrDA *appleirda) 99{ 100 IrDAComm *obj = new IrDAComm; // create an IrDAComm object 101 102 XTRACE(kLogNew, 0, obj); 103 104 if (obj && !obj->init(driver, appleirda)) { 105 obj->release(); 106 obj = nil; 107 } 108 109 return obj; 110} 111 112 113void IrDAComm::free() 114{ 115 IOWorkLoop *workloop; 116 117 XTRACE(kLogFree, 0, this); 118 119 this->Stop(); // make sure we're stopped before releasing memory 120 121 if (fDriver) { 122 workloop = fDriver->getWorkLoop(); 123 if (workloop) { 124 if (fGate) 125 workloop->removeEventSource(fGate); 126 //if (fTimerSrc) 127 // workloop->removeEventSource(fTimerSrc); 128 } 129 } 130 131#define FREE(x) { if (x) { (x)->release(); x = nil; }} 132 133 FREE(fGate); 134 FREE(fTimer); 135 FREE(fIrComm); // free the ircomm object before the rest of irda ... 136 FREE(fIrDA); 137 138#undef FREE 139 140#define THREAD_FREE(x) do { if (x) { \ 141 thread_call_cancel(x); \ 142 thread_call_free(x); \ 143 x = NULL; } } while(0) 144 145 THREAD_FREE(fStop_thread); 146#undef THREAD_FREE 147 148 super::free(); // we're done, call super 149} 150 151 152/****************************************************************************************************/ 153// 154// Method: IrDAComm::Init 155// 156// Inputs: pointer to the usb irda driver 157// 158// Outputs: return code - true (initialized ok), false (it didn't) 159// 160// Desc: Initialize the IrDAComm class 161// 162/****************************************************************************************************/ 163 164bool IrDAComm::init(AppleIrDASerial *driver, AppleIrDA *appleirda) 165{ 166 IOReturn rc; 167 IOWorkLoop *workloop; 168 169 XTRACE(kLogInit, 0, this); 170#if (hasTracing > 0) 171 DebugLog("log info at 0x%lx", (uintptr_t)IrDALogGetInfo()); 172#endif 173 require(driver, Fail); 174 175 fState = kIrDACommStateStart; 176 fDriver = driver; 177 //fTimerSrc = nil; 178 fTimer = nil; 179 fQoS = nil; 180 fIrDA = nil; 181 fIrComm = nil; 182 fWriteBusy = false; 183 fGate = nil; 184 fStartCounter = 0; // counter for initial connection attempts 185 fStop_thread = nil; 186 187 if (!super::init()) 188 return false; 189 190 fQoS = driver->GetIrDAQoS(); 191 require(fQoS, Fail); 192 193 workloop = fDriver->getWorkLoop(); 194 require(workloop, Fail); 195 196 fStop_thread = thread_call_allocate(stop_thread, this); 197 require(fStop_thread, Fail); 198 199 fIrDA = TIrGlue::tIrGlue(fDriver, appleirda, workloop, fQoS); // create irda stack 200 require(fIrDA, Fail); 201 202 fIrComm = IrComm::irComm(fIrDA, this); // create an ircomm object 203 require(fIrComm, Fail); 204 205 fGate = IOCommandGate::commandGate(this, 0); // create a new command gate for our access to IrDA 206 require(fGate, Fail); 207 208 rc = workloop->addEventSource(fGate); // add it to the usb workloop 209 require(rc == kIOReturnSuccess, Fail); 210 211 fTimer = CTimer::cTimer(workloop, this, &IrDAComm::TimerRoutine); 212 require(fTimer, Fail); 213 214 fTimer->StartTimer(100, 0); // 100ms delay after init and then startup 215 216 //fTimerSrc = IOTimerEventSource::timerEventSource ( driver, &::timeoutRoutine); // create an io timer 217 //require(fTimerSrc, Fail); 218 // 219 //rc = workloop->addEventSource(fTimerSrc); 220 //require(rc == kIOReturnSuccess, Fail); 221 // 222 //rc = fTimerSrc->setTimeoutMS(100); // 100 ms delay after init'ing 223 //require(rc == kIOReturnSuccess, Fail); 224 225 return true; 226 227Fail: 228 return false; 229 230} /* end Initialize */ 231 232 233/****************************************************************************************************/ 234// 235// Method: IrDAComm::Stop 236// 237// Inputs: 238// 239// Outputs: return code - kIOReturnSuccess 240// 241// Desc: Stops the class (clean up etc.) 242// 243/****************************************************************************************************/ 244 245IOReturn IrDAComm::Stop(void) 246{ 247 int i; 248 IOReturn rc = kIOReturnSuccess; 249 250 XTRACE(kLogStop, 0, this); 251 require(fGate, Fail); 252 require(fIrDA, Fail); // sanity 253 require(fDriver, Fail); // sanity 254 255 if (fState != kIrDACommStateStopped) { // if not already stopped 256 boolean_t bt; 257 258 if (fDriver->getWorkLoop()->inGate()) { // if we have the gate, just call it 259 rc = fGate->runAction(&DoSomething, (void *)cmdStopEvent, nil, nil, nil); 260 check(rc == kIOReturnSuccess); 261 } 262 else { // we don't have the gate, run stop in another thread and wait for it 263 bt = thread_call_enter(fStop_thread); // run stop logic in another thread 264 check(bt == false); // true here means it was already running and we're confused 265 266 for (i = 0 ; i < 10; i++) { // max wait of a second (should be more than enough) 267 XTRACE(kLogStop1, i, fState); 268 if (fState == kIrDACommStateStopped && // if ircomm is stopped and the irlap link is down 269 fIrDA->IsLAPConnected() == false) break; // then we're really stopped 270 IOSleep(100); // wait 1/10 of a second per state poll 271 } 272 } 273 check(fState == kIrDACommStateStopped); // this will fail if in broken-beam, just debugging 274 275 rc = fGate->runAction(&DoSomething, (void *)cmdStop, nil, nil, nil); 276 check(rc == kIOReturnSuccess); 277 } 278 279Fail: 280 fState = kIrDACommStateStopped; // it's really stopped now, regardless of above 281 XTRACE(kLogStop, 0xffff, 0xffff); 282 283 return rc; 284} 285 286/****************************************************************************************************/ 287// 288// Method: IrDAComm::TXBufferAvailable 289// 290// Inputs: 291// 292// Outputs: size - number of bytes available for a write 293// 294// Desc: Returns the number of bytes IrDA can currently accept for a write 295// 296/****************************************************************************************************/ 297 298size_t IrDAComm::TXBufferAvailable() 299{ 300 IOReturn rc; 301 size_t result = 0; 302 303 XTRACE(kLogTxBufferAvailable, 0, 0); 304 305 // we're getting called from outside the usb workloop, so run through our command gate 306 307 if (fIrComm && fGate) { 308 rc = fGate->runAction(&DoSomething, (void *)cmdTxBufferAvailable, &result); 309 check(rc == kIOReturnSuccess); 310 } 311 312 XTRACE(kLogTxBufferAvailable, 0xffff, result); 313 return result; 314 315} /* end TXBufferAvailable */ 316 317/****************************************************************************************************/ 318// 319// Method: IrDAComm::Write 320// 321// Inputs: Buf - the data to be written, Length - the size of the data 322// 323// Outputs: size - number of bytes written 324// 325// Desc: Queue the data to be written by IrComm 326// 327/****************************************************************************************************/ 328 329size_t IrDAComm::Write(UInt8 *buf, size_t length) 330{ 331 UInt32 result = length; 332 IOReturn rc; 333 334 XTRACE(kLogWrite, fState, length); 335 336 // this is coming from outside our workloop, send through our gate 337 338 if (fState == kIrDACommStateConnected && fIrComm && fGate) { 339 rc = fGate->runAction(&DoSomething, (void *)cmdWrite, buf, (void *)length, &result); 340 check(rc == kIOReturnSuccess); 341 } 342 343 return result; // pretend it worked if no connection (i.e. sink to /dev/null) 344 345} /* end Write */ 346 347/****************************************************************************************************/ 348// 349// Method: IrDAComm::ReadComplete 350// 351// Inputs: Frame - Incoming IrDA frame 352// 353// Outputs: Return code - kIOReturnSuccess or 354// 355// Desc: Process an incoming frame 356// 357/****************************************************************************************************/ 358 359IOReturn IrDAComm::ReadComplete(UInt8 *buf, size_t length) 360{ 361 IOReturn rc = -1; 362 363 XTRACE(kLogReadComplete, length >> 16, length); 364 365 if (fGate && fIrComm && fIrDA) { 366 rc = fGate->runAction(&DoSomething, (void *)cmdReadComplete, buf, (void *)length, nil); 367 } 368 369 return rc; 370 371} /* end ReadComplete */ 372 373// 374// Sending back flow-control to the peer 375// 376void 377IrDAComm::ReturnCredit(size_t byte_count) // serial client has consumed count bytes of data 378{ 379 IOReturn rc; 380 381 XTRACE(kLogReturnCredit, byte_count >> 16, byte_count); 382 383 // this is coming from outside our workloop, send to irda via our command gate 384 385 if (fState == kIrDACommStateConnected && fIrComm && fGate) { 386 rc = fGate->runAction(&DoSomething, (void *)cmdReturnCredit, (void *)byte_count); 387 check(rc == kIOReturnSuccess); 388 } 389 390 return; 391} 392 393 394void 395IrDAComm::Transmit_Complete(Boolean worked) 396{ 397 IOReturn rc; 398 399 XTRACE(kLogTransmitComplete, 0, worked); 400 401 if (fGate && fIrDA) { 402 rc = fGate->runAction(&DoSomething, (void *)cmdXmitComplete, (void *)worked); 403 } 404 405 XTRACE(kLogTransmitComplete, 0xffff, 0xffff); 406} 407 408void 409IrDAComm::SetSpeedComplete(Boolean worked) 410{ 411 IOReturn rc; 412 413 XTRACE(kLogSetSpeedComplete, 0, worked); 414 415 if (fGate && fIrDA) { 416 rc = fGate->runAction(&DoSomething, (void *)cmdSetSpeedComplete, (void *)worked); 417 } 418 419 XTRACE(kLogSetSpeedComplete, 0xffff, 0xffff); 420} 421 422 423 424// 425// Called by IrCOMM to send data back to the pseudo tty 426// 427void 428IrDAComm::IrCommDataRead(UInt8 *buf, UInt32 length) // ircomm data to pass back to the tty 429{ 430 if (fDriver) // if we're not stopped 431 fDriver->Add_RXBytes(buf, length); // error return? 432 else 433 DebugLog("IrDAComm data read but no driver"); 434} 435 436// 437// IrComm calls this when our tinytp peer has extended more credit 438// to us .. i.e. previously blocked writes may now work. 439// 440void 441IrDAComm::BackEnable(void) 442{ 443 XTRACE(kLogBackEnable, 0, fWriteBusy); 444 445 if (fDriver // if we're alive and ... 446 /* && fWriteBusy */ ) // last time they asked we were busy, then 447 // above 'optimization' test stopped the tx queue wheneveer we break up a too-big 448 // write into several small writes. radar 2890966 449 fDriver->SetUpTransmit(); // ask driver code to try to transmit again 450} 451 452// 453// The state engine for keeping irda in a connect/listen loop. 454// 455 456void 457IrDAComm::StateChange(int event) 458{ 459 XTRACE(kLogStateChange, event, fState); 460 461 require(fIrComm, Fail); 462 require(fIrDA, Fail); 463 464 switch (fState) { 465 466 case kIrDACommStateStart: // Starting up and doing initial discovery/connect attempts 467 switch (event) { 468 469 case kIrDACommEventTimer: // start off the state engine. 470 check(fStartCounter == 0); // sanity 471 if (fStartCounter == 0) { 472 fIrDA->Start(); // start irda stack up 473 fIrComm->TryConnect(1); // and do the first discovery 474 } 475 break; 476 477 case kIrDACommEventConnected: // we're connected! 478 fState = kIrDACommStateConnected; 479 break; 480 481 case kIrDACommEventDisconnected: // initial discover/connect failed. Try again 3 times 482 if (fStartCounter++ < 3) 483 fIrComm->TryConnect(1); 484 else 485 fState = kIrDACommStateIdle; // could listen here, but main timer is about to fire soon 486 break; 487 488 case kIrDACommEventStop: 489 if (fStartCounter == 0) // if stopped before we really started 490 fState = kIrDACommStateStopped; // then we're done w/out doing anything 491 else { // else we have a connect pending 492 fState = kIrDACommStateStopping2; // wait for two callbacks 493 fIrComm->Disconnect(); // abort the connect attempt 494 } 495 break; 496 } 497 break; 498 499 case kIrDACommStateIdle: // not doing much 500 switch (event) { 501 502 case kIrDACommEventTimer: // time to wake up. Let's try a discover/connect 503 fState = kIrDACommStateConnecting; 504 fIrComm->TryConnect(6); 505 break; 506 507 case kIrDACommEventConnected: // connected w/out my doing anything? 508 DebugLog("logic error event=%d, state=%d", event, fState); 509 break; 510 511 case kIrDACommEventDisconnected: // disconnect when idle? seems unlikley 512 DebugLog("logic error event=%d, state=%d", event, fState); 513 break; 514 515 case kIrDACommEventStop: // stopped when we're idle 516 fState = kIrDACommStateStopped; // then we're done w/out doing anything 517 break; 518 519 } 520 break; 521 522 case kIrDACommStateConnecting: // trying to connect 523 switch (event) { 524 525 case kIrDACommEventTimer: // connect is stuck, likely in broken beam 526 DebugLog("connect timing out"); 527 break; 528 529 case kIrDACommEventConnected: 530 fState = kIrDACommStateConnected; // we've connected! 531 break; 532 533 case kIrDACommEventDisconnected: // connect failed, switch to listen 534 fState = kIrDACommStateListening; 535 fIrComm->Listen(); 536 break; 537 538 case kIrDACommEventStop: // stop request with connect pending 539 fState = kIrDACommStateStopping2; // wait for two callbacks 540 fIrComm->Disconnect(); // abort the connect attempt 541 break; 542 } 543 break; 544 545 case kIrDACommStateListening: // listening for a peer to discover and connect to us 546 switch (event) { 547 548 case kIrDACommEventTimer: // Time to stop listening and try a connect again. 549 fState = kIrDACommStateStoppingListen; // Issue a disconnect to abort listen. We'll get two 550 fIrComm->Disconnect(); // completes, one for listen stopped, and one for disconnect done. 551 break; 552 553 case kIrDACommEventConnected: // the listen worked, we've got a peer! 554 fState = kIrDACommStateConnected; 555 break; 556 557 case kIrDACommEventDisconnected: // we can get a disconnect if the link bounces, just 558 fIrComm->Listen(); // just keep the listen going 559 break; 560 561 case kIrDACommEventStop: // stop request when listen pending 562 fState = kIrDACommStateStopping2; // wait for two callbacks 563 fIrComm->Disconnect(); // abort the listen 564 break; 565 } 566 break; 567 568 case kIrDACommStateStoppingListen: // waiting for listen abort to finish it's disconnect 569 switch (event) { 570 571 case kIrDACommEventTimer: // stuck waiting for listen abort. likely in broken beam 572 DebugLog("stopping listen timer fired, are we stuck?"); 573 break; 574 575 case kIrDACommEventConnected: // connected? have a disconnect pending. wait for it. 576 DebugLog("listen disconnect race condition"); 577 break; 578 579 case kIrDACommEventDisconnected: // listen aborted. Now wait for the disconnect complete 580 fState = kIrDACommStateDisconnecting; 581 break; 582 583 case kIrDACommEventStop: // stopped after issuing disconnect to stop listen 584 fState = kIrDACommStateStopping2; // wait for two callbacks 585 break; 586 } 587 break; 588 589 case kIrDACommStateDisconnecting: // waiting for a disconnect request to finish 590 switch (event) { 591 592 case kIrDACommEventTimer: // stuck doing disconnect, most likely in broken beam 593 DebugLog("disconnect timing out?"); 594 break; 595 596 case kIrDACommEventConnected: // connected? race condition. Expect a disconnect soon. 597 DebugLog("disconnect race condition"); 598 break; 599 600 case kIrDACommEventDisconnected: // listen abort finished, let's try a connect 601 fState = kIrDACommStateConnecting; // switch from listen to connect 602 fIrComm->TryConnect(6); // a reasonable number of discover slots after quick start 603 break; 604 605 case kIrDACommEventStop: // stopped after issuing disconnect 606 fState = kIrDACommStateStopping; // wait for one more callback 607 break; 608 609 } 610 break; 611 612 case kIrDACommStateConnected: // ircomm channel open, data can flow 613 switch (event) { 614 615 case kIrDACommEventTimer: // nothing to do, we're a happy camper 616 break; 617 618 case kIrDACommEventConnected: // connected again? logic error 619 DebugLog("logic error event=%d, state=%d", event, fState); 620 break; 621 622 case kIrDACommEventDisconnected: // lost our connection 623 fState = kIrDACommStateIdle; // wait for timer before trying to connect again 624 break; 625 626 case kIrDACommEventStop: // stopped when we're up and running 627 fState = kIrDACommStateStopping; // wait for one callback 628 fIrComm->Disconnect(); // disconnect 629 break; 630 } 631 break; 632 633 case kIrDACommStateStopping2: 634 switch (event) { 635 case kIrDACommEventTimer: // timer should be stopped 636 DebugLog("logic error event=%d, state=%d", event, fState); 637 break; 638 639 case kIrDACommEventConnected: // race condition 640 fState = kIrDACommStateStopping; // should disconnect "real soon" now 641 break; 642 643 case kIrDACommEventDisconnected: 644 fState = kIrDACommStateStopping; // normal, listen/connect has aborted 645 break; 646 647 case kIrDACommEventStop: 648 DebugLog("logic error event=%d, state=%d", event, fState); 649 break; 650 } 651 break; 652 653 case kIrDACommStateStopping: 654 switch (event) { 655 case kIrDACommEventTimer: 656 DebugLog("logic error event=%d, state=%d", event, fState); 657 break; 658 659 case kIrDACommEventConnected: 660 DebugLog("logic error event=%d, state=%d", event, fState); 661 break; 662 663 case kIrDACommEventDisconnected: 664 fState = kIrDACommStateStopped; // stop completed 665 if (fIrDA->IsLAPConnected()) // if lap is connected, then 666 fIrDA->DoIdleDisconnect(); // don't wait 1 second, disconnect now 667 break; 668 669 case kIrDACommEventStop: 670 DebugLog("logic error event=%d, state=%d", event, fState); 671 break; 672 } 673 break; 674 675 case kIrDACommStateStopped: // we're stopped, shouldn't be getting requests 676 DebugLog("logic error event=%d, state=%d", event, fState); 677 break; 678 679 } 680Fail: 681 return; 682} 683 684// 685// called by IrComm to let us know of major connection state changes 686// 687void 688IrDAComm::ConnectionStatus(Boolean connected) 689{ 690 static Boolean last_connected = false; // cut down on the debug log noise 691 692 XTRACE(kLogConnectionStatus, fState, connected); 693 if (connected != last_connected) { 694 DebugLog("connection status %d", connected); 695 last_connected = connected; 696 } 697 check(fState != kIrDACommStateIdle); 698 699 if (connected) StateChange(kIrDACommEventConnected); 700 else StateChange(kIrDACommEventDisconnected); 701} 702 703// 704// 5 second timer, keep connection attempts going. 705// 706/* static */ 707void 708IrDAComm::TimerRoutine(OSObject *owner, IrDATimerEventSource *iotimer) 709{ 710 IrDAComm *obj; 711 712 XTRACE(kLogTimer, 0, 0); 713 714 obj = OSDynamicCast(IrDAComm, owner); 715 require(obj, Fail); 716 717 XTRACE(kLogTimer, 0x1111, obj->fState); 718 719 obj->StateChange(kIrDACommEventTimer); 720 721 if (obj->fIrDA) { // now run the irda event queue until it's done 722 obj->fIrDA->RunQueue(); 723 } 724 725 require(obj->fTimer, Fail); 726 obj->fTimer->StartTimer(5 * 1000, 0); // wake up again in 5 seconds 727 728 XTRACE(kLogTimerFinished, 0, 0); 729 return; 730 731Fail: 732 XTRACE(kLogTimerFinished, 0xdead, 0xbeef); 733 return; 734} 735 736/****************************************************************************************************/ 737// 738// Method: timeoutRoutine 739// 740// Inputs: object handle, timer source 741// 742// Outputs: none 743// 744// Desc: call the real C++ method to handle the timeout 745// 746/****************************************************************************************************/ 747/* 748extern "C" 749void 750timeoutRoutine(OSObject *owner, IOTimerEventSource *sender) 751{ 752 AppleIrDASerial *driver = (AppleIrDASerial *)owner; 753 IrDAComm *me = driver->GetIrDAComm(); 754 755 me->TimerRoutine(sender); 756} 757*/ 758 759// 760// 761//static 762IOReturn 763IrDAComm::DoSomething(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 764{ 765 IrDAComm *obj; 766 uintptr_t cmd = (uintptr_t)arg1; 767 768 XTRACE(kLogDoSomething, 0, (uintptr_t)arg1); // log the command code 769 770 obj = OSDynamicCast(IrDAComm, owner); 771 require(obj, Fail); 772 773 switch (cmd) { 774 case cmdTxBufferAvailable: 775 { 776 UInt32 count = 0; 777 UInt32 *result = (UInt32 *)arg2; 778 if (obj->fIrComm) 779 count = obj->fIrComm->TxBufferAvailable(); 780 obj->fWriteBusy = (count == 0); 781 if (result) 782 *result = count; 783 } 784 break; 785 786 case cmdWrite: 787 { 788 UInt8 *buf = (UInt8 *)arg2; 789 uintptr_t length = (uintptr_t)arg3; 790 UInt32 *result = (UInt32 *)arg4; 791 792 if (result) 793 *result = obj->fIrComm->Write(buf, length); 794 } 795 break; 796 797 case cmdReturnCredit: 798 { 799 uintptr_t byte_count = (uintptr_t)arg2; 800 if (obj->fIrComm) 801 obj->fIrComm->ReturnCredit(byte_count); 802 } 803 break; 804 805 case cmdStop: 806 { 807 if (obj->fTimer) { 808 obj->fTimer->StopTimer(); 809 obj->fTimer->release(); 810 obj->fTimer = nil; 811 } 812 813 if (obj->fIrDA) { 814 obj->fIrDA->Stop(); // tell irda not to use the driver anymore 815 } 816 } 817 break; 818 819 case cmdStopEvent: 820 check(obj->fTimer); 821 if (obj->fTimer) { 822 obj->fTimer->StopTimer(); // stop the timer 823 obj->StateChange(kIrDACommEventStop); // get the state engine to stop 824 } 825 if (obj->fIrDA) { // now run the irda event queue until it's done 826 obj->fIrDA->RunQueue(); 827 } 828 break; 829 830 case cmdReadComplete: 831 { 832 UInt8 *buf = (UInt8 *)arg2; 833 uintptr_t length = (uintptr_t)arg3; 834 if (obj->fIrDA) { 835 obj->fIrDA->ReadComplete(buf, length); 836 obj->fIrDA->RunQueue(); 837 } 838 } 839 break; 840 841 case cmdXmitComplete: 842 { 843 bool worked = (bool)arg2; 844 if (obj->fIrDA) { 845 obj->fIrDA->TransmitComplete(worked); 846 XTRACE(kLogTransmitComplete, 0x1111, 0x1111); 847 obj->fIrDA->RunQueue(); 848 XTRACE(kLogTransmitComplete, 0x2222, 0x2222); 849 } 850 } 851 break; 852 853 case cmdSetSpeedComplete: 854 { 855 bool worked = (bool)arg2; 856 if (obj->fIrDA) { 857 obj->fIrDA->SetSpeedComplete(worked); 858 XTRACE(kLogSetSpeedComplete, 0x1111, 0x1111); 859 obj->fIrDA->RunQueue(); 860 XTRACE(kLogSetSpeedComplete, 0x2222, 0x2222); 861 } 862 } 863 break; 864 865 default: 866 check(0); 867 break; 868 } 869 870 return kIOReturnSuccess; 871 872Fail: 873 return kIOReturnBadArgument; 874} 875 876// 877// return irda status to user-client 878// 879void 880IrDAComm::GetIrDAStatus(IrDAStatus *status) 881{ 882 if (fIrDA && status) 883 fIrDA->GetIrDAStatus(status); 884} 885 886// 887// return true if starting up (initial connection attempt) 888// 889bool 890IrDAComm::Starting() 891{ 892 return fState == kIrDACommStateStart; 893} 894 895 896void IrDAComm::stop_thread(thread_call_param_t param0, thread_call_param_t param1) 897{ 898 IrDAComm *obj; 899 IOReturn rc; 900 901 XTRACE(kLogStopThread, 0, 0); 902 903 require(param0, Fail); 904 obj = OSDynamicCast(IrDAComm, (OSObject *)param0); 905 require(obj, Fail); 906 907 rc = obj->fGate->runAction(&DoSomething, (void *)cmdStopEvent, nil, nil, nil); 908 check(rc == kIOReturnSuccess); 909 910Fail: 911 return; 912} 913