1/* 2 * Copyright (c) 2003 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#include "IOFireWireAVCLibUnit.h" 24#include <IOKit/avc/IOFireWireAVCConsts.h> 25#include "IOFireWireAVCLibConsumer.h" 26 27#include <IOKit/IOMessage.h> 28#include <unistd.h> 29 30#define FWLOGGING 0 31#define FWASSERTING 0 32 33#if FWLOGGING 34#define FWLOG(x) printf x 35#else 36#define FWLOG(x) do {} while (0) 37#endif 38 39#if FWASSERTING 40#define FWLOGASSERT(a) { if(!(a)) { printf( "File "__FILE__", line %d: assertion '%s' failed.\n", __LINE__, #a); } } 41#else 42#define FWLOGASSERT(a) do {} while (0) 43#endif 44 45#define kProducerHeartbeatTime 5.0 // 5.0 seconds 46#define kConsumerHeartbeatTime 3.0 // 3.0 seconds 47#define kReconnectTime 10.0 // 10.0 seconds 48 49enum 50{ 51 kFWAVCStatePrivBusSuspended = 0, 52 kFWAVCStatePrivBusResumed = 1, 53 kFWAVCStatePrivPlugSuspended = 3, 54 kFWAVCStatePrivPlugConnected = 4 55}; 56 57enum 58{ 59 kFWAVCConsumerPlugCountMask = 0x00ffffff, 60 kFWAVCConsumerPlugCountPhase = 0, 61 kFWAVCConsumerPlugSCMask = 0x01000000, 62 kFWAVCConsumerPlugSCPhase = 24, 63 kFWAVCConsumerPlugModeMask = 0x0E000000, 64 kFWAVCConsumerPlugModePhase = 25, 65 kFWAVCConsumerPlugHBMask = 0x10000000, 66 kFWAVCConsumerPlugHBPhase = 28 67}; 68 69enum 70{ 71 kFWAVCConsumerMode_FREE = 0, 72 kFWAVCConsumerMode_SUSPENDED = 2 73}; 74 75enum 76{ 77 kFWAVCProducerMode_FREE = 0, 78 kFWAVCProducerMode_SUSPEND = 2, 79 kFWAVCProducerMode_RESUME = 4 80}; 81 82enum 83{ 84 kAVCConcurrentWrites = 0x1, 85 kAVCMulticast = 0x2 86}; 87 88enum 89{ 90 ASYNCHRONOUS_CONNECTION = 0x26, 91 ALLOCATE_ATTACH = 0x03, 92 DETACH_RELEASE = 0x07, 93 RESTORE_PORT = 0x40 94}; 95 96#define AddressHi(poa) ((poa) & 0x0000ffff) 97#define AddressLo_PortBits(poa,pbits) ( ((poa) & 0xfffffffc) | ((pbits) & 0x00000003) ) 98#define AddressLoToMaskedPortID(a) (0xffffffc3 | ((a) & 0x0000003c)) 99#define Ex_ConnectionCount(ex,con) (((ex) << 7) | ((con) & 0x3f)) 100#define WriteInterval_RetryCount(wi,rc) (((wi) << 4) | ((rc) & 0x0000000f)) 101 102enum 103{ 104 kAVCProducerRunBit = 0x00000020, 105 kAVCProducerHBBit = 0x10000000, 106 kAVCProducerSCBit = 0x01000000 107}; 108 109#define oAPR(mode,count,flags,max) ( (flags) | (((mode) & 0x00000007) << 25) | \ 110 ((count) & 0x00ffffc0) | ((max) & 0x0000000f) ) 111 112typedef struct 113{ 114 UInt8 command_type; 115 UInt8 header_address; 116 UInt8 opcode; 117 UInt8 subfunction; 118 UInt8 status; 119 UInt8 plug_id; 120 UInt16 plug_offset_hi; 121 UInt32 plug_offset_lo; 122 UInt16 connected_node_id; 123 UInt16 connected_plug_offset_hi; 124 UInt32 connected_plug_offset_lo; 125 UInt8 connected_plug_id; 126 UInt8 connection_count; 127 UInt8 write_interval_retry_count; 128 UInt8 reserved; 129} ACAVCCommand; 130 131////////////////////////////////////////////////////////////////// 132// static interface table 133// 134 135IOFireWireAVCLibConsumerInterface 136 IOFireWireAVCLibConsumer::sIOFireWireAVCLibConsumerInterface = 137{ 138 0, 139 &IOFireWireAVCLibConsumer::queryInterface, 140 &IOFireWireAVCLibConsumer::comAddRef, 141 &IOFireWireAVCLibConsumer::comRelease, 142 1, 0, // version/revision 143 &IOFireWireAVCLibConsumer::setSubunit, 144 &IOFireWireAVCLibConsumer::setRemotePlug, 145 &IOFireWireAVCLibConsumer::connectToRemotePlug, 146 &IOFireWireAVCLibConsumer::disconnectFromRemotePlug, 147 &IOFireWireAVCLibConsumer::setFrameStatusHandler, 148 &IOFireWireAVCLibConsumer::frameProcessed, 149 &IOFireWireAVCLibConsumer::setMaxPayloadSize, 150 &IOFireWireAVCLibConsumer::setSegmentSize, 151 &IOFireWireAVCLibConsumer::getSegmentSize, 152 &IOFireWireAVCLibConsumer::getSegmentBuffer, 153 &IOFireWireAVCLibConsumer::setPortStateHandler, 154 &IOFireWireAVCLibConsumer::setPortFlags, 155 &IOFireWireAVCLibConsumer::clearPortFlags, 156 &IOFireWireAVCLibConsumer::getPortFlags 157}; 158 159CFArrayCallBacks IOFireWireAVCLibConsumer::sArrayCallbacks = 160{ 161 0, // version 162 &IOFireWireAVCLibConsumer::cfAddRef, // retain 163 &IOFireWireAVCLibConsumer::cfRelease, // release 164 NULL, // copyDescription 165 NULL, // equal 166}; 167 168////////////////////////////////////////////////////////////////// 169// creation and destruction 170// 171 172// ctor 173// 174// 175 176IOFireWireAVCLibConsumer::IOFireWireAVCLibConsumer( void ) 177{ 178 // create driver interface map 179 fIOFireWireAVCLibConsumerInterface.pseudoVTable = (IUnknownVTbl *) &sIOFireWireAVCLibConsumerInterface; 180 fIOFireWireAVCLibConsumerInterface.obj = this; 181 182 // init cf plugin ref counting 183 fRefCount = 0; 184 185 fAVCUnit = NULL; 186 fFWUnit = NULL; 187 fCFRunLoop = NULL; 188 fService = NULL; 189 190 fGeneration = 0; 191 192 fHeartbeatResponseSource = NULL; 193 fHeartbeatResponseSourceInfo = this; 194 fHeartbeatResponseScheduled = false; 195 fConsumerHeartbeatTimer = NULL; 196 fProducerHeartbeatTimer = NULL; 197 fReconnectTimer = NULL; 198 199 fFlags = 0; 200 fSubunit = 0; 201 fLocalPlugNumber = 0; 202 203 fRemotePlugNumber = 0; 204 fRemotePlugAddress = 0; 205 fRemotePlugOptions = 0; 206 207 fMaxPayloadLog = 0x5; // min allowed by spec 208 fSegmentBitState = true; 209 fHeartbeatBitState = false; 210 fMode = 0; 211 212 fInputPlugRegisterBuffer = 0x00000000; 213 fOutputPlugRegisterBuffer = 0x00000000; 214 215 fState = 0; 216 fStateHandlerRefcon = 0; 217 fStateHandler = 0; 218 219 fSegmentSize = 0; 220 fSegmentBuffer = NULL; 221 fPlugAddressSpace = NULL; 222 223 fFrameStatusSource = NULL; 224 fFrameStatusSourceInfo = this; 225 fFrameStatusSourceScheduled = false; 226 fFrameStatusHandler = NULL; 227 fFrameStatusHandlerRefcon = 0; 228 229 fDisconnectResponseSource = NULL; 230 fDisconnectResponseSourceInfo = this; 231 fDisconnectResponseScheduled = false; 232} 233 234// finalize 235// 236// we do the actual clean up in finalize, not in the destructor 237// this gets called before the AVCUnit calls the final CFRelease on us 238 239void IOFireWireAVCLibConsumer::finalize( void ) 240{ 241 // 242 // stop timers 243 // 244 245 stopReconnectTimer(); 246 stopProducerHeartbeatTimer(); 247 stopConsumerHeartbeatTimer(); 248 249 // 250 // free the segment buffer and address space 251 // 252 253 releaseSegment(); 254 255 // 256 // release our runloop sources 257 // 258 259 if( fHeartbeatResponseSource != NULL ) 260 { 261 CFRunLoopSourceInvalidate( fHeartbeatResponseSource ); 262 CFRelease( fHeartbeatResponseSource ); 263 fHeartbeatResponseSource = NULL; 264 } 265 266 if( fFrameStatusSource != NULL ) 267 { 268 CFRunLoopSourceInvalidate( fFrameStatusSource ); 269 CFRelease( fFrameStatusSource ); 270 fFrameStatusSource = NULL; 271 } 272 273 if( fDisconnectResponseSource != NULL ) 274 { 275 CFRunLoopSourceInvalidate( fDisconnectResponseSource ); 276 CFRelease( fDisconnectResponseSource ); 277 fDisconnectResponseSource = NULL; 278 } 279 280 pthread_mutex_destroy( &fLock ); 281 282 // 283 // release our interfaces 284 // 285 286 if( fFWUnit ) 287 { 288 (*fFWUnit)->RemoveCallbackDispatcherFromRunLoop( fFWUnit ); 289 (*fFWUnit)->Close( fFWUnit ); 290 (*fFWUnit)->Release( fFWUnit ); 291 fFWUnit = NULL; 292 } 293} 294 295// dtor 296// 297// clean up has already been done by finalize 298 299IOFireWireAVCLibConsumer::~IOFireWireAVCLibConsumer() 300{ 301 if( fAVCUnit ) 302 { 303 (*fAVCUnit)->Release( fAVCUnit ); 304 fAVCUnit = NULL; 305 } 306} 307 308// alloc 309// 310// static allocator, called by factory method 311 312IUnknownVTbl ** IOFireWireAVCLibConsumer::alloc( IOFireWireAVCLibUnitInterface ** avcUnit, 313 CFRunLoopRef cfRunLoop, 314 UInt8 plugNumber ) 315{ 316 IOReturn status = kIOReturnSuccess; 317 IOFireWireAVCLibConsumer * me; 318 IUnknownVTbl ** interface = NULL; 319 320 if( status == kIOReturnSuccess ) 321 { 322 me = new IOFireWireAVCLibConsumer(); 323 if( me == NULL ) 324 status = kIOReturnError; 325 } 326 327 if( status == kIOReturnSuccess ) 328 { 329 status = me->init( avcUnit, cfRunLoop, plugNumber ); 330 } 331 332 if( status != kIOReturnSuccess ) 333 delete me; 334 335 if( status == kIOReturnSuccess ) 336 { 337 // we return an interface here. 338 // queryInterface is not called in this case, so we call addRef here 339 IOFireWireAVCLibConsumer::addRef(me); 340 interface = (IUnknownVTbl **) &me->fIOFireWireAVCLibConsumerInterface.pseudoVTable; 341 } 342 343 return interface; 344} 345 346// init 347// 348// initialize our object, called by alloc() 349 350IOReturn IOFireWireAVCLibConsumer::init( IOFireWireAVCLibUnitInterface ** avcUnit, 351 CFRunLoopRef cfRunLoop, 352 UInt8 plugNumber ) 353{ 354 IOReturn status = kIOReturnSuccess; 355 356 if( avcUnit == NULL || cfRunLoop == NULL || 357 plugNumber < kFWAVCAsyncPlug0 || plugNumber > kFWAVCAsyncPlug30 ) 358 { 359 status = kIOReturnBadArgument; 360 } 361 362 if( status == kIOReturnSuccess ) 363 { 364 fAVCUnit = avcUnit; 365 (*fAVCUnit)->AddRef( fAVCUnit ); 366 367 fCFRunLoop = cfRunLoop; 368 fLocalPlugNumber = plugNumber; 369 370 pthread_mutex_init( &fLock, NULL ); 371 } 372 373 if( status == kIOReturnSuccess ) 374 { 375 // fDisconnectResponseSourceInfo points to "this" because CF uses the info pointer 376 // to determine if CF runloop sources are the same 377 CFRunLoopSourceContext context = { 0, &fDisconnectResponseSourceInfo, nil, nil, nil, nil, nil, nil, nil, sendDisconnectResponse }; 378 fDisconnectResponseSource = CFRunLoopSourceCreate( kCFAllocatorDefault, 0, &context ); 379 if( fDisconnectResponseSource == NULL ) 380 status = kIOReturnNoMemory; 381 } 382 383 if( status == kIOReturnSuccess ) 384 { 385 CFRunLoopAddSource( fCFRunLoop, fDisconnectResponseSource, kCFRunLoopDefaultMode ); 386 } 387 388 if( status == kIOReturnSuccess ) 389 { 390 // fFrameStatusSourceInfo points to "this" because CF uses the info pointer 391 // to determine if CF runloop sources are the same 392 CFRunLoopSourceContext context = { 0, &fFrameStatusSourceInfo, nil, nil, nil, nil, nil, nil, nil, sendFrameStatusNotification }; 393 fFrameStatusSource = CFRunLoopSourceCreate( kCFAllocatorDefault, 0, &context ); 394 if( fFrameStatusSource == NULL ) 395 status = kIOReturnNoMemory; 396 } 397 398 if( status == kIOReturnSuccess ) 399 { 400 CFRunLoopAddSource( fCFRunLoop, fFrameStatusSource, kCFRunLoopDefaultMode ); 401 } 402 403 if( status == kIOReturnSuccess ) 404 { 405 // fHeartbeatResponseSourceInfo points to "this" because CF uses the info pointer 406 // to determine if CF runloop sources are the same 407 CFRunLoopSourceContext context = { 0, &fHeartbeatResponseSourceInfo, nil, nil, nil, nil, nil, nil, nil, sendHeartbeatResponse }; 408 fHeartbeatResponseSource = CFRunLoopSourceCreate( kCFAllocatorDefault, 0, &context ); 409 if( fHeartbeatResponseSource == NULL ) 410 status = kIOReturnNoMemory; 411 } 412 413 if( status == kIOReturnSuccess ) 414 { 415 CFRunLoopAddSource( fCFRunLoop, fHeartbeatResponseSource, kCFRunLoopDefaultMode ); 416 } 417 418 if( status == kIOReturnSuccess ) 419 { 420 fFWUnit = (IOFireWireDeviceInterface**)(*fAVCUnit)->getAncestorInterface( fAVCUnit, 421 (char*)"IOFireWireUnit", 422 CFUUIDGetUUIDBytes(kIOFireWireLibTypeID), 423 CFUUIDGetUUIDBytes(kIOFireWireDeviceInterfaceID) ); 424 if( fFWUnit == NULL ) 425 status = kIOReturnNoMemory; 426 } 427 428 if( status == kIOReturnSuccess ) 429 { 430 (*fFWUnit)->AddRef( fFWUnit ); 431 } 432 433 IOFireWireSessionRef sessionRef = 0; 434 435 if( status == kIOReturnSuccess ) 436 { 437 sessionRef = (*fAVCUnit)->getSessionRef( fAVCUnit ); 438 if( sessionRef == 0 ) 439 status = kIOReturnError; 440 } 441 442 // open 443 if( status == kIOReturnSuccess ) 444 { 445 status = (*fFWUnit)->OpenWithSessionRef( fFWUnit, sessionRef ); 446 } 447 448 FWLOG(( "IOFireWireAVCLibConsumer::init OpenWithSessionRef return status = 0x%08x\n", status )); 449 450 if( status == kIOReturnSuccess ) 451 { 452 status = (*fFWUnit)->AddCallbackDispatcherToRunLoop( fFWUnit, fCFRunLoop ); 453 } 454 455 if( status == kIOReturnSuccess ) 456 { 457 fService = (*fFWUnit)->GetDevice( fFWUnit ); 458 if( fService == (io_object_t)NULL ) 459 status = kIOReturnError; 460 } 461 462 if( status == kIOReturnSuccess ) 463 { 464 if( isDeviceSuspended( fAVCUnit ) ) 465 { 466 fState = kFWAVCStatePrivBusSuspended; 467 } 468 else 469 { 470 fState = kFWAVCStatePrivBusResumed; 471 } 472 } 473 474 FWLOG(( "IOFireWireAVCLibConsumer::init return status = 0x%08lx\n", (UInt32)status )); 475 476 return status; 477} 478 479// queryInterface 480// 481// 482 483HRESULT IOFireWireAVCLibConsumer::queryInterface( void * self, REFIID iid, void **ppv ) 484{ 485 CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid); 486 HRESULT result = S_OK; 487 IOFireWireAVCLibConsumer * me = getThis(self); 488 489// FWLOG(( "IOFireWireAVCLibConsumer::queryInterface start\n" )); 490 491 if( CFEqual(uuid, IUnknownUUID) || CFEqual(uuid, kIOFireWireAVCLibConsumerInterfaceID) ) 492 { 493 *ppv = &me->fIOFireWireAVCLibConsumerInterface; 494 comAddRef(self); 495 } 496 else 497 *ppv = 0; 498 499 if( !*ppv ) 500 result = E_NOINTERFACE; 501 502 CFRelease( uuid ); 503 504 // FWLOG(( "IOFireWireAVCLibConsumer::queryInterface stop\n" )); 505 506 return result; 507} 508 509////////////////////////////////////////////////////////////////// 510// reference counting 511// 512// cf and com have different reference counting methods 513// we call a shared method to actually do the work 514 515// addRef 516// 517// 518 519const void * IOFireWireAVCLibConsumer::cfAddRef( CFAllocatorRef allocator, const void *value ) 520{ 521 IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)value; 522 IOFireWireAVCLibConsumer::addRef( me ); 523 return value; 524} 525 526UInt32 IOFireWireAVCLibConsumer::comAddRef( void * self ) 527{ 528 IOFireWireAVCLibConsumer * me = getThis(self); 529 return IOFireWireAVCLibConsumer::addRef( me ); 530} 531 532UInt32 IOFireWireAVCLibConsumer::addRef( IOFireWireAVCLibConsumer * me ) 533{ 534 me->fRefCount++; 535 return me->fRefCount; 536} 537 538// release 539// 540// 541 542void IOFireWireAVCLibConsumer::cfRelease( CFAllocatorRef allocator, const void *value ) 543{ 544 IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)value; 545 IOFireWireAVCLibConsumer::release( me ); 546} 547 548UInt32 IOFireWireAVCLibConsumer::comRelease( void * self ) 549{ 550 IOFireWireAVCLibConsumer * me = getThis(self); 551 return IOFireWireAVCLibConsumer::release( me ); 552} 553 554UInt32 IOFireWireAVCLibConsumer::release( IOFireWireAVCLibConsumer * me ) 555{ 556 UInt32 retVal = me->fRefCount; 557 558 me->fRefCount--; 559 560 if( 0 == me->fRefCount ) 561 { 562 delete me; 563 } 564 else if( 1 == me->fRefCount ) 565 { 566 // clean up before we tell the AVCUnit to let us go 567 me->finalize(); 568 569 // unit is last reference, inform it of this fact 570 consumerPlugDestroyed( me->fAVCUnit, me ); 571 } 572 else if( me->fRefCount < 0 ) 573 { 574 me->fRefCount = 0; 575 } 576 577 return retVal; 578} 579 580////////////////////////////////////////////////////////////////// 581// accessors 582// 583 584// getNodeIDsAndGeneration 585// 586// returns the local and remote node ids and the generation for which they are valid 587 588IOReturn IOFireWireAVCLibConsumer::getNodeIDsAndGeneration( UInt16 * local, UInt16 * remote, UInt32 * gen ) 589{ 590 IOReturn status = kIOReturnSuccess; 591 592 UInt16 localNodeID; 593 UInt16 remoteNodeID; 594 UInt32 firstGen, secondGen; 595 596 // these routines only return errors if there is something wrong with the user client's 597 // connection to the kernel 598 599 // 1. get generation and remote nodeID 600 // 2. get local nodeID 601 // 3. get generation again 602 // 4. repeat if the generation has changed 603 604 do 605 { 606 if( status == kIOReturnSuccess ) 607 { 608 status = (*fFWUnit)->GetGenerationAndNodeID( fFWUnit, &firstGen, &remoteNodeID ); 609 } 610 611 if( status == kIOReturnSuccess ) 612 { 613 status = (*fFWUnit)->GetLocalNodeID( fFWUnit, &localNodeID ); 614 } 615 616 if( status == kIOReturnSuccess ) 617 { 618 status = (*fFWUnit)->GetGenerationAndNodeID( fFWUnit, &secondGen, &remoteNodeID ); 619 } 620 621 } while( firstGen != secondGen && status == kIOReturnSuccess ); 622 623 if( status == kIOReturnSuccess ) 624 { 625 *remote = remoteNodeID; 626 *local = localNodeID; 627 *gen = firstGen; 628 } 629 630 return status; 631} 632 633// setSubunit 634// 635// 636 637void IOFireWireAVCLibConsumer::setSubunit( void * self, UInt8 subunit ) 638{ 639 IOFireWireAVCLibConsumer * me = getThis(self); 640 641 me->fSubunit = subunit; 642} 643 644// setRemotePlug 645// 646// 647 648void IOFireWireAVCLibConsumer::setRemotePlug( void * self, UInt8 plugNumber ) 649{ 650 IOFireWireAVCLibConsumer * me = getThis(self); 651 652 me->fRemotePlugNumber = plugNumber; 653} 654 655// setMaxPayloadSize 656// 657// 658 659void IOFireWireAVCLibConsumer::setMaxPayloadSize( void * self, UInt32 size ) 660{ 661 IOFireWireAVCLibConsumer * me = getThis(self); 662 UInt32 sizeBytes = size; 663 664 me->fMaxPayloadLog = 0x0; 665 while( (sizeBytes >= 0x4) && (me->fMaxPayloadLog < 0xa) ) 666 { 667 sizeBytes >>= 1; 668 me->fMaxPayloadLog++; 669 } 670 671 // spec says maxPayloadLog shall not be less than 5 672 if( me->fMaxPayloadLog < 0x5 ) 673 me->fMaxPayloadLog = 0x5; 674} 675 676////////////////////////////////////////////////////////////////// 677// connection management 678// 679 680// connectToRemotePlug 681// 682// public connection method 683 684IOReturn IOFireWireAVCLibConsumer::connectToRemotePlug( void * self ) 685{ 686 IOFireWireAVCLibConsumer * me = getThis(self); 687 IOReturn status = kIOReturnSuccess; 688 689 pthread_mutex_lock( &me->fLock ); 690 691 FWLOG(( "IOFireWireAVCLibConsumer::connectToRemotePlug\n" )); 692 693 if( me->fState != kFWAVCStatePrivBusResumed ) 694 { 695 status = kIOReturnNotReady; 696 } 697 698 if( me->fRemotePlugNumber < kFWAVCAsyncPlug0 || me->fRemotePlugNumber > kFWAVCAsyncPlugAny ) 699 { 700 status = kIOReturnNoResources; 701 } 702 703 if( me->fPlugAddressSpace == NULL ) 704 { 705 status = kIOReturnNoResources; 706 } 707 708 if( status == kIOReturnSuccess ) 709 { 710 FWLOG(( "IOFireWireAVCLibConsumer::connectToRemotePlug attempt to connect to device...\n" )); 711 UInt32 tries = 11; // reconnect timeout is 10 seconds 712 do 713 { 714 status = me->doConnectToRemotePlug(); 715 if( status != kIOReturnSuccess ) 716 { 717 FWLOG(( "IOFireWireLibAVCConsumer::connectToRemotePlug connect to device failed with status = 0x%08lx\n", (UInt32)status )); 718 if( tries > 1 ) 719 { 720 // sleep for 1 second before retrying 721 usleep( 1 * 1000000 ); 722 FWLOG(( "IOFireWireLibAVCConsumer::connectToRemotePlug retrying connect to device...\n" )); 723 } 724 } 725 } 726 while( status != kIOReturnSuccess && --tries ); 727 } 728 729 FWLOG(( "IOFireWireLibAVCConsumer::connectToRemotePlug return status = 0x%08lx\n", (UInt32)status )); 730 731 pthread_mutex_unlock( &me->fLock ); 732 733 return status; 734} 735 736// doConnectToRemotePlug 737// 738// internal connection routine 739 740IOReturn IOFireWireAVCLibConsumer::doConnectToRemotePlug( void ) 741{ 742 IOReturn status = kIOReturnSuccess; 743 744 FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug\n" )); 745 746 FWAddress address; 747 748 if( status == kIOReturnSuccess ) 749 { 750 (*fPlugAddressSpace)->GetFWAddress( fPlugAddressSpace, &address ); 751 } 752 753 UInt16 localNodeID; 754 UInt16 remoteNodeID; 755 UInt32 generation; 756 757 if( status == kIOReturnSuccess ) 758 { 759 status = getNodeIDsAndGeneration( &localNodeID, &remoteNodeID, &generation ); 760 } 761 762 ACAVCCommand cmd; 763 ACAVCCommand response; 764 765 if( status == kIOReturnSuccess ) 766 { 767 // send ALLOCATE_ATTACH to remote subunit 768 769 cmd.command_type = 0x00; // CT/RC = Control command 770 cmd.header_address = kAVCUnitAddress; // HA = unit 771 cmd.opcode = ASYNCHRONOUS_CONNECTION; // Opcode = ASYNCHRONOUS_CONNECTION 772 cmd.subfunction = ALLOCATE_ATTACH; // Subfunction = ALLOCATE_ATTACH 773 cmd.status = 0xff; // status = N/A 774 cmd.plug_id = fRemotePlugNumber; // plugID = plug number 775 cmd.plug_offset_hi = OSSwapHostToBigInt16(0xffff); 776 cmd.plug_offset_lo = OSSwapHostToBigInt32(0xffffffff); // any producer port 777 cmd.connected_node_id = OSSwapHostToBigInt16(0xffc0 | localNodeID); 778 cmd.connected_plug_offset_hi = OSSwapHostToBigInt16(AddressHi(address.addressHi)); 779 cmd.connected_plug_offset_lo = OSSwapHostToBigInt32(AddressLo_PortBits(address.addressLo, kAVCConcurrentWrites | kAVCMulticast )); 780 cmd.connected_plug_id = fLocalPlugNumber; 781 cmd.connection_count = Ex_ConnectionCount(0x1,0x3f); 782 cmd.write_interval_retry_count = WriteInterval_RetryCount(0x00,0x00); 783 cmd.reserved = 0x00; 784 } 785 786 FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug avc command\n" )); 787 788 UInt32 responseLength = sizeof(response); 789 if( status == kIOReturnSuccess ) 790 { 791 status = (*fAVCUnit)->AVCCommandInGeneration( fAVCUnit, generation, (UInt8*)&cmd, sizeof(cmd), (UInt8*)&response, &responseLength ); 792 793 // Fix up endian issues here! 794 if (responseLength >= sizeof(ACAVCCommand)) 795 { 796 response.plug_offset_hi = OSSwapBigToHostInt16(response.plug_offset_hi); 797 response.plug_offset_lo = OSSwapBigToHostInt32(response.plug_offset_lo); 798 response.connected_node_id = OSSwapBigToHostInt16(response.connected_node_id); 799 response.connected_plug_offset_hi = OSSwapBigToHostInt16(response.connected_plug_offset_hi); 800 response.connected_plug_offset_lo = OSSwapBigToHostInt32(response.connected_plug_offset_lo); 801 } 802 } 803 804 if( status == kIOReturnSuccess ) 805 { 806 if( response.status != 0x03 ) 807 status = kIOReturnDeviceError; 808 } 809 810 if( status == kIOReturnSuccess ) 811 { 812 fRemotePlugNumber = response.plug_id; 813 fRemotePlugAddress.addressHi = response.plug_offset_hi; 814 fRemotePlugAddress.addressLo = response.plug_offset_lo & 0xfffffffc; 815 fRemotePlugOptions = response.plug_offset_lo & 0x00000003; 816 } 817 818 // set run bit in producer plug 819 UInt32 newVal = 0; 820 821 if( status == kIOReturnSuccess ) 822 { 823 fOutputPlugRegisterBuffer = 0x00000000; 824 fInputPlugRegisterBuffer = 0x00000000; 825 fSegmentBitState = true; 826 fHeartbeatBitState = false; 827 } 828 829 if( status == kIOReturnSuccess ) 830 { 831 FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug run bit\n" )); 832 // oAPR( mode, count, flags, maxLoad ) 833 UInt32 flags = kAVCProducerRunBit | 834 (fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) | 835 (fSegmentBitState ? kAVCProducerSCBit : 0x00000000); 836 newVal = oAPR( kFWAVCProducerMode_SEND, fSegmentSize, flags, fMaxPayloadLog ); 837 status = updateProducerRegister( newVal, generation ); 838 } 839 840 if( status == kIOReturnSuccess ) 841 { 842 fState = kFWAVCStatePrivPlugConnected; 843 fGeneration = generation; 844 fMode = kFWAVCProducerMode_SEND; 845 startProducerHeartbeatTimer(); 846 } 847 848 FWLOG(( "IOFireWireAVCLibConsumer::doConnectToRemotePlug status = 0x%08lx\n", (UInt32)status )); 849 850 return status; 851} 852 853// disconnectFromRemotePlug 854// 855// 856 857IOReturn IOFireWireAVCLibConsumer::disconnectFromRemotePlug( void * self ) 858{ 859 IOFireWireAVCLibConsumer * me = getThis(self); 860 IOReturn status = kIOReturnSuccess; 861 862 pthread_mutex_lock( &me->fLock ); 863 864 switch( me->fState ) 865 { 866 case kFWAVCStatePrivPlugSuspended: 867 868 // don't reconnect if we get a resume message 869 870 me->stopReconnectTimer(); 871 872 // neither of the heartbeat timers should be running 873 874 if( me->fProducerHeartbeatTimer != NULL || me->fConsumerHeartbeatTimer != NULL ) 875 { 876 printf( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug heartbeat timers set while plug is suspended!\n" ); 877 } 878 879 me->fState = kFWAVCStatePrivBusSuspended; 880 881 break; 882 883 case kFWAVCStatePrivPlugConnected: 884 885 ACAVCCommand cmd; 886 ACAVCCommand response; 887 UInt32 responseLength; 888 889 // the reconnect timer should not be running 890 891 if( me->fReconnectTimer != NULL ) 892 { 893 printf( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug reconnect timer set while plug is resumed!\n" ); 894 } 895 896 me->stopProducerHeartbeatTimer(); 897 me->stopConsumerHeartbeatTimer(); 898 899 if( status == kIOReturnSuccess ) 900 { 901 // send DETACH_RELEASE to remote unit 902 903 cmd.command_type = 0x00; // CT/RC = Control command 904 cmd.header_address = kAVCUnitAddress; // HA = unit 905 cmd.opcode = ASYNCHRONOUS_CONNECTION; // Opcode = ASYNCHRONOUS_CONNECTION 906 cmd.subfunction = DETACH_RELEASE; // Subfunction = DETACH_RELEASE 907 cmd.status = 0xff; // status = N/A 908 cmd.plug_id = me->fRemotePlugNumber; // plugID = plug number 909 cmd.plug_offset_hi = OSSwapHostToBigInt16(0xffff); 910 cmd.plug_offset_lo = OSSwapHostToBigInt32(AddressLoToMaskedPortID(me->fRemotePlugAddress.addressLo)); 911 cmd.connected_node_id = OSSwapHostToBigInt16(0xffff); 912 cmd.connected_plug_offset_hi = OSSwapHostToBigInt16(0xffff); 913 cmd.connected_plug_offset_lo = OSSwapHostToBigInt32(0xffffffff); 914 cmd.connected_plug_id = 0xff; 915 cmd.connection_count = Ex_ConnectionCount(0x1,0x3f); 916 cmd.write_interval_retry_count = WriteInterval_RetryCount(0xf,0xf); 917 cmd.reserved = 0x00; 918 } 919 920 if( status == kIOReturnSuccess ) 921 { 922 responseLength = sizeof(response); 923 status = (*me->fAVCUnit)->AVCCommandInGeneration( me->fAVCUnit, me->fGeneration, (UInt8*)&cmd, sizeof(cmd), (UInt8*)&response, &responseLength ); 924 925 // Fix up endian issues here! 926 if (responseLength >= sizeof(ACAVCCommand)) 927 { 928 response.plug_offset_hi = OSSwapBigToHostInt16(response.plug_offset_hi); 929 response.plug_offset_lo = OSSwapBigToHostInt32(response.plug_offset_lo); 930 response.connected_node_id = OSSwapBigToHostInt16(response.connected_node_id); 931 response.connected_plug_offset_hi = OSSwapBigToHostInt16(response.connected_plug_offset_hi); 932 response.connected_plug_offset_lo = OSSwapBigToHostInt32(response.connected_plug_offset_lo); 933 } 934 } 935 936 if( status == kIOFireWireBusReset ) 937 { 938 // bus reset occured while disconnecting. 939 // as long as we don't reconnect we will be disconnected, so ignore the error 940 941 // this also means we cannot connect until the reconnect period is over 942 943 status = kIOReturnSuccess; 944 } 945 else if( status == kIOReturnSuccess ) 946 { 947 if( response.status != 0x01 ) 948 { 949 // if the device gave us an error on disconnect, it probably 950 // already thinks we're disconnected, so ignore the error 951 952 FWLOG(( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug disconnect AVCCommand returned response.status = 0x%02x\n", response.status )); 953 } 954 } 955 else 956 { 957 FWLOG(( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug disconnect AVCCommand status = 0x%08lx\n", (UInt32)status )); 958 959 // what do we do about this? 960 // figure we're disconnected even if we got an error!? 961 962 status = kIOReturnSuccess; 963 } 964 965 if( status == kIOReturnSuccess ) 966 { 967 me->fState = kFWAVCStatePrivBusResumed; 968 me->fInputPlugRegisterBuffer = 0x00000000; 969 } 970 971 break; 972 973 default: 974 975 // we're in a state we can't disconnect from 976 status = kIOReturnNotPermitted; 977 978 break; 979 980 } 981 982 FWLOG(( "IOFireWireAVCLibConsumer::disconnectFromRemotePlug status = 0x%08lx\n", (UInt32)status )); 983 984 pthread_mutex_unlock( &me->fLock ); 985 986 return status; 987} 988 989// forciblyDisconnected 990// 991// notifies clients of a forced disconnection 992 993void IOFireWireAVCLibConsumer::forciblyDisconnected( void ) 994{ 995 fInputPlugRegisterBuffer = 0x00000000; 996 997 switch( fState ) 998 { 999 case kFWAVCStatePrivPlugSuspended: 1000 1001 fState = kFWAVCStatePrivBusSuspended; 1002 1003 pthread_mutex_unlock( &fLock ); 1004 1005 if( fStateHandler ) 1006 { 1007 (fStateHandler)(fStateHandlerRefcon, kFWAVCStatePlugDisconnected ); 1008 } 1009 1010 break; 1011 1012 case kFWAVCStatePrivPlugConnected: 1013 1014 fState = kFWAVCStatePrivBusResumed; 1015 1016 pthread_mutex_unlock( &fLock ); 1017 1018 if( fStateHandler ) 1019 { 1020 (fStateHandler)(fStateHandlerRefcon, kFWAVCStatePlugDisconnected ); 1021 } 1022 1023 break; 1024 1025 default: 1026 1027 pthread_mutex_unlock( &fLock ); 1028 1029 FWLOG(( "IOFireWireAVCLibConsumer::forciblyDisconnected we're in an unexpected state = 0x%08lx.\n", fState )); 1030 break; 1031 } 1032} 1033 1034// setPortStateHandler 1035// 1036// 1037 1038void IOFireWireAVCLibConsumer::setPortStateHandler( void * self, void * refcon, IOFireWireAVCPortStateHandler handler ) 1039{ 1040 IOFireWireAVCLibConsumer * me = getThis(self); 1041 1042 me->fStateHandlerRefcon = refcon; 1043 me->fStateHandler = handler; 1044} 1045 1046// deviceInterestCallback 1047// 1048// 1049 1050void IOFireWireAVCLibConsumer::deviceInterestCallback( natural_t type, void * arg ) 1051{ 1052 IOReturn status = kIOReturnSuccess; 1053 1054 switch( type ) 1055 { 1056 case kIOMessageServiceIsSuspended: 1057 1058 FWLOG(( "IOFireWireAVCLibConsumer::kIOMessageServiceIsSuspended bus reset start\n" )); 1059 1060 pthread_mutex_lock( &fLock ); 1061 1062 switch ( fState ) 1063 { 1064 case kFWAVCStatePrivBusResumed: 1065 1066 fState = kFWAVCStatePrivBusSuspended; 1067 1068 pthread_mutex_unlock( &fLock ); 1069 1070 if( fStateHandler ) 1071 { 1072 (fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusSuspended ); 1073 } 1074 1075 break; 1076 1077 case kFWAVCStatePrivPlugSuspended: 1078 1079 // restart reconnect timer 1080 startReconnectTimer(); 1081 1082 pthread_mutex_unlock( &fLock ); 1083 1084 break; 1085 1086 case kFWAVCStatePrivPlugConnected: 1087 1088 fState = kFWAVCStatePrivPlugSuspended; 1089 1090 // these values reset on bus resets 1091 fOutputPlugRegisterBuffer &= ~(kAVCProducerRunBit | kAVCProducerHBBit); 1092 fInputPlugRegisterBuffer &= ~kFWAVCConsumerPlugHBMask; 1093 fHeartbeatBitState = false; 1094 1095 stopProducerHeartbeatTimer(); 1096 stopConsumerHeartbeatTimer(); 1097 startReconnectTimer(); 1098 1099 pthread_mutex_unlock( &fLock ); 1100 1101 if( fStateHandler ) 1102 { 1103 (fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusSuspended ); 1104 } 1105 1106 break; 1107 1108 case kFWAVCStatePrivBusSuspended: 1109 default: 1110 pthread_mutex_unlock( &fLock ); 1111 // do nothing 1112 break; 1113 1114 } 1115 1116 break; 1117 1118 case kIOMessageServiceIsResumed: 1119 1120 FWLOG(( "IOFireWireAVCLibConsumer::kIOMessageServiceIsResumed bus reset complete\n" )); 1121 1122 pthread_mutex_lock( &fLock ); 1123 1124 switch ( fState ) 1125 { 1126 case kFWAVCStatePrivBusSuspended: 1127 1128 fState = kFWAVCStatePrivBusResumed; 1129 1130 pthread_mutex_unlock( &fLock ); 1131 1132 if( fStateHandler ) 1133 { 1134 (fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusResumed ); 1135 } 1136 1137 break; 1138 1139 case kFWAVCStatePrivPlugSuspended: 1140 1141 pthread_mutex_unlock( &fLock ); 1142 1143 if( fStateHandler ) 1144 { 1145 (fStateHandler)( fStateHandlerRefcon, kFWAVCStateBusResumed ); 1146 } 1147 1148 pthread_mutex_lock( &fLock ); 1149 1150 stopReconnectTimer(); 1151 1152 UInt16 localNodeID; 1153 UInt16 remoteNodeID; 1154 UInt32 generation; 1155 1156 if( status == kIOReturnSuccess ) 1157 { 1158 status = getNodeIDsAndGeneration( &localNodeID, &remoteNodeID, &generation ); 1159 } 1160 1161 if( status == kIOReturnSuccess ) 1162 { 1163 if( generation == fGeneration ) 1164 { 1165 // we've already connected on this generation, no need to reconnect 1166 // this can happen if we get two (or more) bus rests in a row and 1167 // while handling the first one we latched the generation of the second 1168 } 1169 else 1170 { 1171 ACAVCCommand cmd; 1172 ACAVCCommand response; 1173 1174 if( status == kIOReturnSuccess ) 1175 { 1176 // send RESTORE_PORT to remote unit 1177 1178 cmd.command_type = 0x00; // CT/RC = Control command 1179 cmd.header_address = kAVCUnitAddress; // HA = unit 1180 cmd.opcode = ASYNCHRONOUS_CONNECTION; // Opcode = ASYNCHRONOUS_CONNECTION 1181 cmd.subfunction = RESTORE_PORT; // Subfunction = RESTORE_PORT 1182 cmd.status = 0xff; // status = N/A 1183 cmd.plug_id = fRemotePlugNumber; // plugID = plug number 1184 cmd.plug_offset_hi = OSSwapHostToBigInt16(0xffff); 1185 cmd.plug_offset_lo = OSSwapHostToBigInt32(AddressLoToMaskedPortID(fRemotePlugAddress.addressLo)); 1186 cmd.connected_node_id = OSSwapHostToBigInt16(0xffc0 | localNodeID); 1187 cmd.connected_plug_offset_hi = OSSwapHostToBigInt16(0xffff); 1188 cmd.connected_plug_offset_lo = OSSwapHostToBigInt32(AddressLoToMaskedPortID(0x00000000)); 1189 cmd.connected_plug_id = 0xff; 1190 cmd.connection_count = Ex_ConnectionCount(0x1,0x3f); 1191 cmd.write_interval_retry_count = WriteInterval_RetryCount(0xf,0xf); 1192 cmd.reserved = 0x00; 1193 } 1194 1195 UInt32 responseLength = sizeof(response); 1196 if( status == kIOReturnSuccess ) 1197 { 1198 status = (*fAVCUnit)->AVCCommandInGeneration( fAVCUnit, generation, (UInt8*)&cmd, sizeof(cmd), (UInt8*)&response, &responseLength ); 1199 1200 // Fix up endian issues here! 1201 if (responseLength >= sizeof(ACAVCCommand)) 1202 { 1203 response.plug_offset_hi = OSSwapBigToHostInt16(response.plug_offset_hi); 1204 response.plug_offset_lo = OSSwapBigToHostInt32(response.plug_offset_lo); 1205 response.connected_node_id = OSSwapBigToHostInt16(response.connected_node_id); 1206 response.connected_plug_offset_hi = OSSwapBigToHostInt16(response.connected_plug_offset_hi); 1207 response.connected_plug_offset_lo = OSSwapBigToHostInt32(response.connected_plug_offset_lo); 1208 } 1209 } 1210 1211 if( status == kIOReturnSuccess ) 1212 { 1213 if( response.status != 0x03 ) 1214 status = kIOReturnDeviceError; 1215 } 1216 1217 if( status == kIOReturnSuccess ) 1218 { 1219 fRemotePlugNumber = response.plug_id; 1220 fRemotePlugAddress.addressHi = response.plug_offset_hi; 1221 fRemotePlugAddress.addressLo = response.plug_offset_lo & 0xfffffffc; 1222 fRemotePlugOptions = response.plug_offset_lo & 0x00000003; 1223 } 1224 1225 if( fHeartbeatBitState || 1226 (fOutputPlugRegisterBuffer & (kAVCProducerRunBit | kAVCProducerHBBit)) || 1227 (fInputPlugRegisterBuffer & kFWAVCConsumerPlugHBMask) ) 1228 { 1229 printf( "IOFireWireAVCLibConsumer::deviceInterestCallback register values not reset!\n" ); 1230 } 1231 1232 // set run bit in producer register 1233 1234 UInt32 newVal = 0; 1235 1236 if( status == kIOReturnSuccess ) 1237 { 1238 // oAPR( mode, count, flags, maxLoad ) 1239 UInt32 flags = kAVCProducerRunBit | 1240 (fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) | 1241 (fSegmentBitState ? kAVCProducerSCBit : 0x00000000); 1242 newVal = oAPR( kFWAVCProducerMode_SEND, fSegmentSize, flags, fMaxPayloadLog ); 1243 status = updateProducerRegister( newVal, generation ); 1244 } 1245 1246 if( status == kIOReturnSuccess ) 1247 { 1248 fMode = kFWAVCProducerMode_SEND; 1249 startProducerHeartbeatTimer(); 1250 } 1251 1252 } // generation if 1253 1254 } // status if 1255 1256 if( status == kIOReturnSuccess ) 1257 { 1258 fState = kFWAVCStatePrivPlugConnected; 1259 fGeneration = generation; 1260 1261 } 1262 1263 if( status == kIOReturnSuccess ) 1264 { 1265 pthread_mutex_unlock( &fLock ); 1266 1267 if( fStateHandler ) 1268 { 1269 (fStateHandler)( fStateHandlerRefcon, kFWAVCStatePlugReconnected ); 1270 } 1271 } 1272 else if( status == kIOFireWireBusReset ) 1273 { 1274 // this means our attempt to reconnect was interupted by a bus reset 1275 // that means we will start the reconnect process over and don't need to do anything here 1276 pthread_mutex_unlock( &fLock ); 1277 1278 } 1279 else 1280 { 1281 FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback failed to reconnect - forciblyDisconnecting\n" )); 1282 1283 forciblyDisconnected(); 1284 } 1285 1286 break; 1287 1288 case kIOFWMessageServiceIsRequestingClose: 1289 FWLOG(( "IOFireWireAVCLibConsumer::kIOFWMessageServiceIsRequestingClose (device removed)\n" )); 1290 1291 pthread_mutex_lock( &fLock ); 1292 1293 switch ( fState ) 1294 { 1295 case kFWAVCStatePrivBusSuspended: 1296 1297 pthread_mutex_unlock( &fLock ); 1298 1299 if( fStateHandler ) 1300 { 1301 (fStateHandler)( fStateHandlerRefcon, kFWAVCStateDeviceRemoved ); 1302 } 1303 1304 break; 1305 1306 case kFWAVCStatePrivPlugSuspended: 1307 1308 FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback device unplugged - forciblyDisconnecting\n" )); 1309 1310 forciblyDisconnected(); 1311 1312 if( fStateHandler ) 1313 { 1314 (fStateHandler)( fStateHandlerRefcon, kFWAVCStateDeviceRemoved ); 1315 } 1316 1317 break; 1318 1319 default: 1320 FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback kIOFWMessageServiceIsRequestingClose in odd state, fState = 0x%08lx/n", fState )); 1321 break; 1322 } 1323 1324 1325 break; 1326 1327 case kIOMessageServiceIsTerminated: 1328 FWLOG(( "IOFireWireAVCLibConsumer::kIOMessageServiceIsTerminated (device removed)\n" )); 1329 break; 1330 1331 default: 1332 FWLOG(( "IOFireWireAVCLibConsumer::deviceInterestCallback kIOMessageServiceIsResumed in odd state, fState = 0x%08lx/n", fState )); 1333 break; 1334 } 1335 break; 1336 1337 default: 1338 break; 1339 } 1340} 1341 1342// startReconnectTimer 1343// 1344// 1345 1346void IOFireWireAVCLibConsumer::startReconnectTimer( void ) 1347{ 1348 CFRunLoopTimerContext context; 1349 CFAbsoluteTime time; 1350 1351 // stop if necessary 1352 stopReconnectTimer(); 1353 1354 context.version = 0; 1355 context.info = this; 1356 context.retain = NULL; 1357 context.release = NULL; 1358 context.copyDescription = NULL; 1359 1360 time = CFAbsoluteTimeGetCurrent() + kReconnectTime; 1361 1362 fReconnectTimer = CFRunLoopTimerCreate(NULL, time, 1363 0, 1364 0, 1365 0, 1366 (CFRunLoopTimerCallBack)&IOFireWireAVCLibConsumer::reconnectTimeoutProc, 1367 &context); 1368 1369 if ( fReconnectTimer ) 1370 { 1371 CFRunLoopAddTimer( fCFRunLoop, fReconnectTimer, kCFRunLoopDefaultMode ); 1372 } 1373} 1374 1375// reconnectTimeoutProc 1376// 1377// 1378 1379void IOFireWireAVCLibConsumer::reconnectTimeoutProc( CFRunLoopTimerRef timer, void *data ) 1380{ 1381 IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)data; 1382 1383 pthread_mutex_lock( &me->fLock ); 1384 1385 me->stopReconnectTimer(); 1386 1387 FWLOG(( "IOFireWireAVCLibConsumer::reconnectTimeoutProc reconnect timed out - forciblyDisconnecting\n" )); 1388 1389 me->forciblyDisconnected(); 1390} 1391 1392// stopReconnectTimer 1393// 1394// 1395 1396void IOFireWireAVCLibConsumer::stopReconnectTimer( void ) 1397{ 1398 if ( fReconnectTimer ) 1399 { 1400 CFRunLoopTimerInvalidate( fReconnectTimer ); 1401 CFRelease( fReconnectTimer ); 1402 fReconnectTimer = NULL; 1403 } 1404} 1405 1406////////////////////////////////////////////////////////////////// 1407// segment buffer allocation 1408// 1409 1410// setSegmentSize 1411// 1412// 1413 1414IOReturn IOFireWireAVCLibConsumer::setSegmentSize( void * self, UInt32 size ) 1415{ 1416 IOFireWireAVCLibConsumer * me = getThis(self); 1417 IOReturn status = kIOReturnSuccess; 1418 1419 if( size > 0x00ffffff || (size & 0x0000003f) != 0 ) 1420 { 1421 return kIOReturnBadArgument; 1422 } 1423 1424 // free previous address space 1425 me->releaseSegment(); 1426 1427 // new segment buffer 1428 me->fSegmentBuffer = (char*)malloc( size + 64 ); 1429 if( me->fSegmentBuffer == NULL ) 1430 status = kIOReturnNoMemory; 1431 1432 if( status == kIOReturnSuccess ) 1433 { 1434 me->fSegmentSize = size; 1435 1436 // new psuedo address space 1437 me->fPlugAddressSpace = (*me->fFWUnit)->CreatePseudoAddressSpace( me->fFWUnit, me->fSegmentSize + 64, 1438 me, (me->fSegmentSize + 64) * 2, 1439 me->fSegmentBuffer, 1440 kFWAddressSpaceNoFlags, 1441 CFUUIDGetUUIDBytes(kIOFireWirePseudoAddressSpaceInterfaceID)); 1442 if( me->fPlugAddressSpace == NULL ) 1443 status = kIOReturnNoMemory; 1444 } 1445 1446 if( status == kIOReturnSuccess ) 1447 { 1448 FWAddress address; 1449 (*me->fPlugAddressSpace)->GetFWAddress(me->fPlugAddressSpace, &address); 1450 1451 FWLOG(("IOFireWireAVCLibConsumer::allocated address space at %04X:%08lX\n", address.addressHi, address.addressLo)); 1452 1453 (*me->fPlugAddressSpace)->SetWriteHandler( me->fPlugAddressSpace, 1454 &IOFireWireAVCLibConsumer::packetWriteHandler ); 1455 (*me->fPlugAddressSpace)->SetSkippedPacketHandler( me->fPlugAddressSpace, 1456 &IOFireWireAVCLibConsumer::skippedPacketHandler ); 1457 (*me->fPlugAddressSpace)->SetReadHandler( me->fPlugAddressSpace, &IOFireWireAVCLibConsumer::packetReadHandler ); 1458 1459 if( !(*me->fPlugAddressSpace)->TurnOnNotification( me->fPlugAddressSpace ) ) 1460 status = kIOReturnError ; 1461 1462 } 1463 1464 return status; 1465} 1466 1467// releaseSegment 1468// 1469// 1470 1471void IOFireWireAVCLibConsumer::releaseSegment( void ) 1472{ 1473 // free previous address space 1474 if( fPlugAddressSpace != NULL ) 1475 { 1476 (*fPlugAddressSpace)->TurnOffNotification( fPlugAddressSpace ); 1477 (*fPlugAddressSpace)->Release( fPlugAddressSpace ); 1478 fPlugAddressSpace = NULL; 1479 } 1480 1481 // free previous buffer 1482 if( fSegmentBuffer != NULL ) 1483 { 1484 free( fSegmentBuffer ); 1485 fSegmentBuffer= NULL; 1486 } 1487} 1488 1489// getSegmentSize 1490// 1491// 1492 1493UInt32 IOFireWireAVCLibConsumer::getSegmentSize( void * self ) 1494{ 1495 IOFireWireAVCLibConsumer * me = getThis(self); 1496 1497 return me->fSegmentSize; 1498} 1499 1500// getSegmentBuffer 1501// 1502// 1503 1504char * IOFireWireAVCLibConsumer::getSegmentBuffer( void * self ) 1505{ 1506 IOFireWireAVCLibConsumer * me = getThis(self); 1507 1508 return (me->fSegmentBuffer + 64); 1509} 1510 1511////////////////////////////////////////////////////////////////// 1512// segment buffer transactions 1513// 1514 1515// setFrameStatusHandler 1516// 1517// 1518 1519void IOFireWireAVCLibConsumer::setFrameStatusHandler( void * self, 1520 void * refcon, IOFireWireAVCFrameStatusHandler handler ) 1521{ 1522 IOFireWireAVCLibConsumer * me = getThis(self); 1523 1524 me->fFrameStatusHandler = handler; 1525 me->fFrameStatusHandlerRefcon = refcon; 1526} 1527 1528// updateProducerRegister 1529// 1530// 1531 1532IOReturn IOFireWireAVCLibConsumer::updateProducerRegister( UInt32 newVal, UInt32 generation ) 1533{ 1534 IOReturn status = kIOReturnSuccess; 1535 1536 UInt32 tries = 6; 1537 bool done = false; 1538 do 1539 { 1540 FWLOG(( "IOFireWireAVCLibConsumer::updateProducerRegister sending CompareAndSwap(0x%08lx,0x%08lx) to producer\n", fOutputPlugRegisterBuffer, newVal )); 1541 status = (*fFWUnit)->CompareSwap( fFWUnit, fService, &fRemotePlugAddress, OSSwapHostToBigInt32(fOutputPlugRegisterBuffer), OSSwapHostToBigInt32(newVal), true, generation ); 1542 if( status == kIOFireWireBusReset || status == kIOReturnSuccess) 1543 { 1544 done = true; 1545 } 1546 else 1547 { 1548 FWLOG(( "IOFireWireLibAVCConsumer::updateProducerRegister register update failed with status = 0x%08lx\n", (UInt32)status )); 1549 1550 if( tries > 1 ) 1551 { 1552 // sleep for 25 milliseconds before reading 1553 usleep( 25 * 1000 ); 1554 1555 // perhaps producer register is other than we think 1556 // try reading it 1557 UInt32 producerRegister = 0; 1558 status = (*fFWUnit)->ReadQuadlet( fFWUnit, fService, &fRemotePlugAddress, &producerRegister, true, generation ); 1559 if( status == kIOReturnSuccess ) 1560 { 1561 fOutputPlugRegisterBuffer = OSSwapBigToHostInt32(producerRegister); 1562 } 1563 else if( status == kIOFireWireBusReset ) 1564 { 1565 done = true; 1566 } 1567 1568 if( !done ) 1569 { 1570 // sleep for 25 milliseconds before retrying 1571 usleep( 25 * 1000 ); 1572 FWLOG(( "IOFireWireLibAVCConsumer::updateProducerRegister retrying register update.\n" )); 1573 } 1574 } 1575 } 1576 } 1577 while( !done && --tries ); 1578 1579 if( status == kIOReturnSuccess ) 1580 { 1581 // if it worked store the value away the value for next time. 1582 fOutputPlugRegisterBuffer = newVal; 1583 } 1584 1585 return status; 1586} 1587 1588// packetReadHandler 1589// 1590// 1591 1592UInt32 1593IOFireWireAVCLibConsumer::packetReadHandler( 1594 IOFireWireLibPseudoAddressSpaceRef addressSpace, 1595 FWClientCommandID commandID, 1596 UInt32 packetLen, 1597 UInt32 packetOffset, 1598 UInt16 nodeID, // nodeID of requester 1599 UInt32 destAddressHi, // destination on this node 1600 UInt32 destAddressLo, 1601 void* refcon) 1602{ 1603 1604 IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)refcon; 1605 1606 UInt32 endianFixedPlugVal; 1607 1608 FWLOG(( "IOFireWireAVCLibConsumer::packetReadHandler called - destAddressLo = 0x%08lx\n", destAddressLo )); 1609 1610 UInt8 * buffer = (UInt8 *)(*addressSpace)->GetBuffer( addressSpace ); 1611 1612 if( packetOffset < 4 ) 1613 { 1614 endianFixedPlugVal = OSSwapHostToBigInt32(me->fInputPlugRegisterBuffer); 1615 bcopy( (void*)&endianFixedPlugVal, buffer + packetOffset, sizeof(UInt32)); 1616 } 1617 else if( packetOffset < 64 ) 1618 { 1619 bzero( buffer + packetOffset, packetLen ); 1620 } 1621 else 1622 { 1623 bcopy( me->fSegmentBuffer + packetOffset - 64, buffer + packetOffset, packetLen); 1624 } 1625 1626 (*addressSpace)->ClientCommandIsComplete( addressSpace, commandID, kFWResponseComplete ) ; 1627 1628 return 0; 1629} 1630 1631// packetWriteHandler 1632// 1633// 1634 1635UInt32 IOFireWireAVCLibConsumer::packetWriteHandler( 1636 IOFireWireLibPseudoAddressSpaceRef addressSpace, 1637 FWClientCommandID commandID, 1638 UInt32 packetLen, 1639 void* packet, 1640 UInt16 srcNodeID, // nodeID of sender 1641 UInt32 destAddressHi, // destination on this node 1642 UInt32 destAddressLo, 1643 void* refcon) 1644{ 1645 IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)refcon; 1646 IOReturn status = kIOReturnSuccess; 1647 1648 FWAddress plugAddress; 1649 (*addressSpace)->GetFWAddress(addressSpace, &plugAddress); 1650 1651 FWAddress offsetAddress; 1652 offsetAddress.addressHi = destAddressHi; 1653 offsetAddress.addressLo = destAddressLo; 1654 1655 UInt32 offset = (UInt32)subtractFWAddressFromFWAddress( plugAddress, offsetAddress ); 1656 1657 if( offset < 64 ) 1658 { 1659 // 1660 // in register space 1661 // 1662 1663 if( packetLen > 4 ) 1664 { 1665 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler wrote to register > 4 bytes\n" )); 1666 status = kIOReturnError; 1667 } 1668 1669 if( !((offsetAddress.addressHi == plugAddress.addressHi) && 1670 (offsetAddress.addressLo == plugAddress.addressLo)) ) 1671 { 1672 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler offsetAddress != plugAddress\n" )); 1673 status = kIOReturnError; 1674 } 1675 1676 pthread_mutex_lock( &me->fLock ); 1677 bool workScheduled = false; 1678 1679 if( status == kIOReturnSuccess ) 1680 { 1681 me->fInputPlugRegisterBuffer = OSSwapBigToHostInt32(*((UInt32*)packet)); 1682 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler received packet = 0x%08lx\n", me->fInputPlugRegisterBuffer )); 1683 } 1684 1685 if( status == kIOReturnSuccess && me->fState == kFWAVCStatePrivPlugConnected ) 1686 { 1687 me->stopProducerHeartbeatTimer(); 1688 1689 UInt32 count = (me->fInputPlugRegisterBuffer & kFWAVCConsumerPlugCountMask) >> kFWAVCConsumerPlugCountPhase; 1690 UInt32 mode = (me->fInputPlugRegisterBuffer & kFWAVCConsumerPlugModeMask) >> kFWAVCConsumerPlugModePhase; 1691 1692 bool newHeartbeatState = (me->fInputPlugRegisterBuffer & kFWAVCConsumerPlugHBMask) >> kFWAVCConsumerPlugHBPhase; 1693 1694 if( me->fHeartbeatBitState != newHeartbeatState ) 1695 { 1696 // 1697 // schedule the heartbeat response 1698 // 1699 1700 if( !me->fHeartbeatResponseScheduled ) 1701 { 1702 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler schedule heartbeat response\n" )); 1703 me->fHeartbeatResponseScheduled = true; 1704 workScheduled = true; 1705 CFRunLoopSourceSignal( me->fHeartbeatResponseSource ); 1706 CFRunLoopWakeUp( me->fCFRunLoop ); 1707 } 1708 else 1709 { 1710 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler frame heartbeat response already scheduled!\n" )); 1711 } 1712 } 1713 else 1714 { 1715 switch( mode ) 1716 { 1717 case kFWAVCConsumerMode_FREE: 1718 1719 // producer initiated shutdown request. 1720 1721 switch( me->fState ) 1722 { 1723 case kFWAVCStatePrivPlugConnected: 1724 1725 // 1726 // schedule disconnect response 1727 // 1728 1729 if( !me->fDisconnectResponseScheduled ) 1730 { 1731 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler schedule disconnect response\n" )); 1732 me->fDisconnectResponseScheduled = true; 1733 workScheduled = true; 1734 CFRunLoopSourceSignal( me->fDisconnectResponseSource ); 1735 CFRunLoopWakeUp( me->fCFRunLoop ); 1736 } 1737 else 1738 { 1739 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler disconnect response already scheduled!\n" )); 1740 } 1741 1742 break; 1743 1744 default: 1745 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler FREE received, but we're in an unexpected state = 0x%08lx.\n", me->fState )); 1746 break; 1747 } 1748 1749 break; 1750 1751 case kFWAVCConsumerMode_MORE: 1752 case kFWAVCConsumerMode_LAST: 1753 case kFWAVCConsumerMode_LESS: 1754 case kFWAVCConsumerMode_JUNK: 1755 case kFWAVCConsumerMode_LOST: 1756 1757 // 1758 // schedule frame status handler 1759 // 1760 1761 me->startConsumerHeartbeatTimer(); 1762 1763 me->fFrameStatusMode = mode; 1764 me->fFrameStatusCount = count; 1765 1766 if( !me->fFrameStatusSourceScheduled ) 1767 { 1768 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler schedule frame status handler\n" )); 1769 me->fFrameStatusSourceScheduled = true; 1770 workScheduled = true; 1771 CFRunLoopSourceSignal( me->fFrameStatusSource ); 1772 CFRunLoopWakeUp( me->fCFRunLoop ); 1773 } 1774 else 1775 { 1776 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler frame heartbeat response already scheduled!\n" )); 1777 } 1778 1779 break; 1780 1781 default: 1782 break; 1783 } 1784 } 1785 } 1786 1787 if( !workScheduled ) 1788 { 1789 pthread_mutex_unlock( &me->fLock ); 1790 } 1791 } 1792 else 1793 { 1794 // 1795 // in segment buffer space 1796 // 1797 1798 if( offset + packetLen - 64 > me->fSegmentSize ) 1799 { 1800 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler written packet size > than segment size\n" )); 1801 status = kIOReturnError; 1802 } 1803 1804 if( status == kIOReturnSuccess ) 1805 { 1806 // copy the packet into the segment buffer 1807 bcopy( packet, me->fSegmentBuffer + offset, packetLen ); 1808 } 1809 } 1810 1811 (*addressSpace)->ClientCommandIsComplete(addressSpace, commandID, kIOReturnSuccess) ; 1812 1813 return 0; 1814} 1815 1816// skippedPacketHandler 1817// 1818// 1819 1820void IOFireWireAVCLibConsumer::skippedPacketHandler( 1821 IOFireWireLibPseudoAddressSpaceRef addressSpace, 1822 FWClientCommandID commandID, 1823 UInt32 skippedPacketCount) 1824{ 1825 FWLOG(("IOFireWireAVCLibConsumer::skippedPacketHandler skippedPacketCount = %ld\n", skippedPacketCount)); 1826 1827 //zzz what to do ? 1828 1829 (*addressSpace)->ClientCommandIsComplete(addressSpace, commandID, kIOReturnSuccess); 1830} 1831 1832 1833// sendDisconnectResponse 1834// 1835// 1836 1837void IOFireWireAVCLibConsumer::sendDisconnectResponse( void * info ) 1838{ 1839 IOReturn status = kIOReturnSuccess; 1840 IOFireWireAVCLibConsumer ** meRef = (IOFireWireAVCLibConsumer **)info; 1841 IOFireWireAVCLibConsumer * me = *meRef; 1842 UInt32 newVal = 0; 1843 1844 me->fDisconnectResponseScheduled = false; 1845 1846 FWLOG(( "IOFireWireLibAVCConsumer::sendDisconnectResponse disconnect response handler called\n" )); 1847 1848 UInt32 flags = kAVCProducerRunBit | 1849 (me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) | 1850 (!me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000); 1851 newVal = oAPR( kFWAVCProducerMode_FREE, me->fSegmentSize, flags, me->fMaxPayloadLog ); 1852 status = me->updateProducerRegister( newVal, me->fGeneration ); 1853 if( status == kIOReturnSuccess ) 1854 { 1855 // I guess this is unneeded as we are disconnected 1856 me->fMode = kFWAVCProducerMode_FREE; 1857 me->fState = kFWAVCStatePrivBusResumed; 1858 me->fSegmentBitState = !me->fSegmentBitState; 1859 1860 FWLOG(( "IOFireWireAVCLibConsumer::packetWriteHandler FREE received - forciblyDisconnecting\n" )); 1861 me->forciblyDisconnected(); 1862 } 1863 else 1864 { 1865 pthread_mutex_unlock( &me->fLock ); 1866 } 1867} 1868 1869// sendHeartbeatResponse 1870// 1871// 1872 1873void IOFireWireAVCLibConsumer::sendHeartbeatResponse( void * info ) 1874{ 1875 IOReturn status = kIOReturnSuccess; 1876 IOFireWireAVCLibConsumer ** meRef = (IOFireWireAVCLibConsumer **)info; 1877 IOFireWireAVCLibConsumer * me = *meRef; 1878 UInt32 newVal = 0; 1879 1880 me->fHeartbeatResponseScheduled = false; 1881 FWLOG(( "IOFireWireLibAVCConsumer::sendHeartbeatResponse heartbeat response handler called\n" )); 1882 UInt32 flags = kAVCProducerRunBit | 1883 (!me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) | 1884 (me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000); 1885 newVal = oAPR( kFWAVCProducerMode_SEND, me->fSegmentSize, flags, me->fMaxPayloadLog ); 1886 status = me->updateProducerRegister( newVal, me->fGeneration ); 1887 if( status == kIOReturnSuccess ) 1888 { 1889 me->fHeartbeatBitState = !me->fHeartbeatBitState; 1890 me->startProducerHeartbeatTimer(); 1891 pthread_mutex_unlock( &me->fLock ); 1892 } 1893 else if( status != kIOFireWireBusReset ) 1894 { 1895 FWLOG(( "IOFireWireLibAVCConsumer::sendHeartbeatResponse heartbeat handshake failed with status = 0x%08lx\n", (UInt32)status )); 1896 me->forciblyDisconnected(); 1897 } 1898 else 1899 { 1900 pthread_mutex_unlock( &me->fLock ); 1901 } 1902 1903} 1904 1905// startConsumerHeartbeatTimer 1906// 1907// 1908 1909void IOFireWireAVCLibConsumer::startConsumerHeartbeatTimer( void ) 1910{ 1911 CFRunLoopTimerContext context; 1912 CFAbsoluteTime time; 1913 1914 stopConsumerHeartbeatTimer(); // just in case 1915 1916 context.version = 0; 1917 context.info = this; 1918 context.retain = NULL; 1919 context.release = NULL; 1920 context.copyDescription = NULL; 1921 1922 time = CFAbsoluteTimeGetCurrent() + kConsumerHeartbeatTime; 1923 1924 fConsumerHeartbeatTimer = CFRunLoopTimerCreate(NULL, time, 1925 kConsumerHeartbeatTime, 1926 0, 1927 0, 1928 (CFRunLoopTimerCallBack)&IOFireWireAVCLibConsumer::consumerHeartbeatProc, 1929 &context); 1930 1931 if ( fConsumerHeartbeatTimer ) 1932 { 1933 CFRunLoopAddTimer( fCFRunLoop, fConsumerHeartbeatTimer, kCFRunLoopDefaultMode ); 1934 } 1935} 1936 1937// consumerHeartbeatProc 1938// 1939// 1940 1941void IOFireWireAVCLibConsumer::consumerHeartbeatProc( CFRunLoopTimerRef timer, void *data ) 1942{ 1943 IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)data; 1944 IOReturn status = kIOReturnSuccess; 1945 UInt32 newVal = 0; 1946 1947 pthread_mutex_lock( &me->fLock ); 1948 1949 me->stopConsumerHeartbeatTimer(); // necessary? 1950 1951 // oAPR( mode, count, flags, maxLoad ) 1952 UInt32 flags = kAVCProducerRunBit | 1953 (!me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) | 1954 (me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000); 1955 newVal = oAPR( me->fMode, me->fSegmentSize, flags, me->fMaxPayloadLog ); 1956 status = me->updateProducerRegister( newVal, me->fGeneration ); 1957 if( status == kIOReturnSuccess ) 1958 { 1959 me->fHeartbeatBitState = !me->fHeartbeatBitState; 1960 } 1961 1962 pthread_mutex_unlock( &me->fLock ); 1963} 1964 1965// stopConsumerHeartbeatTimer 1966// 1967// 1968 1969void IOFireWireAVCLibConsumer::stopConsumerHeartbeatTimer( void ) 1970{ 1971 if ( fConsumerHeartbeatTimer ) 1972 { 1973 CFRunLoopTimerInvalidate( fConsumerHeartbeatTimer ); 1974 CFRelease( fConsumerHeartbeatTimer ); 1975 fConsumerHeartbeatTimer = NULL; 1976 } 1977} 1978 1979// sendFrameStatusNotification 1980// 1981// 1982 1983void IOFireWireAVCLibConsumer::sendFrameStatusNotification( void * info ) 1984{ 1985 IOFireWireAVCLibConsumer ** meRef = (IOFireWireAVCLibConsumer **)info; 1986 IOFireWireAVCLibConsumer * me = *meRef; 1987 me->fFrameStatusSourceScheduled = false; 1988 1989 FWLOG(( "IOFireWireLibAVCConsumer::sendFrameStatusNotification frame status handler called\n" )); 1990 1991 pthread_mutex_unlock( &me->fLock ); 1992 1993 if( me->fFrameStatusHandler ) 1994 { 1995 (me->fFrameStatusHandler)(me->fFrameStatusHandlerRefcon, me->fFrameStatusMode, me->fFrameStatusCount); 1996 } 1997} 1998 1999// frameProcessed 2000// 2001// 2002 2003void IOFireWireAVCLibConsumer::frameProcessed( void * self, UInt32 mode ) 2004{ 2005 IOFireWireAVCLibConsumer * me = getThis(self); 2006 IOReturn status = kIOReturnSuccess; 2007 2008 pthread_mutex_lock( &me->fLock ); 2009 2010 me->stopConsumerHeartbeatTimer(); 2011 2012 UInt32 flags = kAVCProducerRunBit | 2013 (me->fHeartbeatBitState ? kAVCProducerHBBit : 0x00000000) | 2014 (!me->fSegmentBitState ? kAVCProducerSCBit : 0x00000000); 2015 2016 // oAPR( mode, count, flags, maxLoad ) 2017 UInt32 newVal = oAPR( mode, me->fSegmentSize, flags, me->fMaxPayloadLog ); 2018 2019 status = me->updateProducerRegister( newVal, me->fGeneration ); 2020 2021 if( status == kIOReturnSuccess ) 2022 { 2023 me->fMode = mode; 2024 me->fSegmentBitState = !me->fSegmentBitState; 2025 me->startProducerHeartbeatTimer(); 2026 } 2027 2028 pthread_mutex_unlock( &me->fLock ); 2029} 2030 2031// startProducerHeartbeatTimer 2032// 2033// 2034 2035void IOFireWireAVCLibConsumer::startProducerHeartbeatTimer( void ) 2036{ 2037 CFRunLoopTimerContext context; 2038 CFAbsoluteTime time; 2039 2040 stopProducerHeartbeatTimer(); // just in case 2041 2042 context.version = 0; 2043 context.info = this; 2044 context.retain = NULL; 2045 context.release = NULL; 2046 context.copyDescription = NULL; 2047 2048 time = CFAbsoluteTimeGetCurrent() + kProducerHeartbeatTime; 2049 2050 fProducerHeartbeatTimer = CFRunLoopTimerCreate( NULL, time, 2051 0, 2052 0, 2053 0, 2054 (CFRunLoopTimerCallBack)&IOFireWireAVCLibConsumer::producerHeartbeatProc, 2055 &context); 2056 2057 if ( fProducerHeartbeatTimer ) 2058 { 2059 CFRunLoopAddTimer( fCFRunLoop, fProducerHeartbeatTimer, kCFRunLoopDefaultMode ); 2060 } 2061} 2062 2063// producerHeartbeatProc 2064// 2065// 2066 2067void IOFireWireAVCLibConsumer::producerHeartbeatProc( CFRunLoopTimerRef timer, void *data ) 2068{ 2069 IOFireWireAVCLibConsumer * me = (IOFireWireAVCLibConsumer*)data; 2070 2071 pthread_mutex_lock( &me->fLock ); 2072 2073 me->stopProducerHeartbeatTimer(); // necessary? 2074 2075 FWLOG(( "IOFireWireAVCLibConsumer::producerHeartbeatProc producer heatbeat timeout - forciblyDisconnecting\n" )); 2076 2077 me->forciblyDisconnected(); 2078} 2079 2080// stopProducerHeartbeatTimer 2081// 2082// 2083 2084void IOFireWireAVCLibConsumer::stopProducerHeartbeatTimer( void ) 2085{ 2086 if( fProducerHeartbeatTimer ) 2087 { 2088 CFRunLoopTimerInvalidate( fProducerHeartbeatTimer ); 2089 CFRelease( fProducerHeartbeatTimer ); 2090 fProducerHeartbeatTimer = NULL; 2091 } 2092} 2093 2094////////////////////////////////////////////////////////////////// 2095// flags 2096// 2097 2098void IOFireWireAVCLibConsumer::setPortFlags( void * self, UInt32 flags ) 2099{ 2100 IOFireWireAVCLibConsumer * me = getThis(self); 2101 2102 me->fFlags |= flags; 2103} 2104 2105void IOFireWireAVCLibConsumer::clearPortFlags( void * self, UInt32 flags ) 2106{ 2107 IOFireWireAVCLibConsumer * me = getThis(self); 2108 2109 me->fFlags &= !flags; 2110} 2111 2112UInt32 IOFireWireAVCLibConsumer::getPortFlags( void * self ) 2113{ 2114 IOFireWireAVCLibConsumer * me = getThis(self); 2115 2116 return me->fFlags; 2117} 2118