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// This is for testing of the new async AVC command kernel stuff 24//#define kUseAsyncAVCCommandForBlockingAVCCommand 1 25 26#include "IOFireWireAVCUserClient.h" 27#include <IOKit/IOLib.h> 28#include <IOKit/IOMessage.h> 29#include <IOKit/IOSyncer.h> 30#include <IOKit/firewire/IOFireWireUnit.h> 31#include <IOKit/firewire/IOFireWireController.h> 32 33#if FIRELOG 34#import <IOKit/firewire/FireLog.h> 35#define FIRELOG_MSG(x) FireLog x 36#else 37#define FIRELOG_MSG(x) do {} while (0) 38#endif 39 40OSDefineMetaClassAndStructors(IOFireWireAVCConnection, OSObject) 41OSDefineMetaClassAndStructors(IOFireWireAVCUserClientAsyncCommand, OSObject) 42OSDefineMetaClassAndStructors(IOFireWireAVCUserClient, IOUserClient) 43 44void AVCUserClientAsyncCommandCallback(void *pRefCon, IOFireWireAVCAsynchronousCommand *pCommandObject); 45 46////////////////////////////////////////////////////// 47// IOFireWireAVCUserClient::externalMethod 48////////////////////////////////////////////////////// 49IOReturn IOFireWireAVCUserClient::externalMethod( uint32_t selector, 50 IOExternalMethodArguments * arguments, 51 IOExternalMethodDispatch * dispatch, 52 OSObject * target, 53 void * reference) 54{ 55 IOReturn result = kIOReturnBadArgument; 56 57 FIRELOG_MSG(("IOFireWireAVCUserClient::externalMethod (this=0x%08X), selector=0x%08X\n",this,selector)); 58 59 // Dispatch the method call 60 switch (selector) 61 { 62 case kIOFWAVCUserClientOpen: 63 result = open(NULL,NULL,NULL,NULL,NULL,NULL); 64 break; 65 66 case kIOFWAVCUserClientClose: 67 result = close(NULL,NULL,NULL,NULL,NULL,NULL); 68 break; 69 70 case kIOFWAVCUserClientGetSessionRef: 71 result = getSessionRef( arguments->scalarOutput,NULL,NULL,NULL,NULL,NULL); 72 break; 73 74 case kIOFWAVCUserClientAVCCommand: 75 result = AVCCommand((UInt8*)arguments->structureInput, 76 (UInt8*)arguments->structureOutput, 77 arguments->structureInputSize, 78 (UInt32*)&arguments->structureOutputSize); 79 break; 80 81 case kIOFWAVCUserClientOpenWithSessionRef: 82 result = openWithSessionRef((IOFireWireLib::UserObjectHandle) arguments->scalarInput[0],NULL,NULL,NULL,NULL,NULL); 83 break; 84 85 case kIOFWAVCUserClientAVCCommandInGen: 86 result = AVCCommandInGen((UInt8*) arguments->structureInput, 87 (UInt8*)arguments->structureOutput, 88 arguments->structureInputSize, 89 (UInt32*)&arguments->structureOutputSize); 90 break; 91 92 case kIOFWAVCUserClientUpdateAVCCommandTimeout: 93 result = updateAVCCommandTimeout(NULL,NULL,NULL,NULL,NULL,NULL); 94 break; 95 96 case kIOFWAVCUserClientMakeP2PInputConnection: 97 result = makeP2PInputConnection(arguments->scalarInput[0],arguments->scalarInput[1],NULL,NULL,NULL,NULL); 98 break; 99 100 case kIOFWAVCUserClientBreakP2PInputConnection: 101 result = breakP2PInputConnection(arguments->scalarInput[0],NULL,NULL,NULL,NULL,NULL); 102 break; 103 104 case kIOFWAVCUserClientMakeP2POutputConnection: 105 result = makeP2POutputConnection(arguments->scalarInput[0],arguments->scalarInput[1],(IOFWSpeed)arguments->scalarInput[2],NULL,NULL,NULL); 106 break; 107 108 case kIOFWAVCUserClientBreakP2POutputConnection: 109 result = breakP2POutputConnection(arguments->scalarInput[0],NULL,NULL,NULL,NULL,NULL); 110 break; 111 112 case kIOFWAVCUserClientCreateAsyncAVCCommand: 113 result = CreateAVCAsyncCommand((UInt8*)arguments->structureInput, 114 (UInt8*)arguments->structureOutput, 115 arguments->structureInputSize, 116 (UInt32*)&arguments->structureOutputSize); 117 break; 118 119 case kIOFWAVCUserClientSubmitAsyncAVCCommand: 120 result = SubmitAVCAsyncCommand(arguments->scalarInput[0]); 121 break; 122 123 case kIOFWAVCUserClientCancelAsyncAVCCommand: 124 result = CancelAVCAsyncCommand(arguments->scalarInput[0]); 125 break; 126 127 case kIOFWAVCUserClientReleaseAsyncAVCCommand: 128 result = ReleaseAVCAsyncCommand(arguments->scalarInput[0]); 129 break; 130 131 case kIOFWAVCUserClientReinitAsyncAVCCommand: 132 result = ReinitAVCAsyncCommand(arguments->scalarInput[0], (const UInt8*) arguments->structureInput, arguments->structureInputSize); 133 break; 134 135 case kIOFWAVCUserClientInstallAsyncAVCCommandCallback: 136 result = installUserLibAsyncAVCCommandCallback(arguments->asyncReference,arguments->scalarInput[0], arguments->scalarOutput); 137 break; 138 139 default: 140 // None of the above! 141 break; 142 }; 143 144 return result; 145} 146 147////////////////////////////////////////////////////// 148// IOFireWireAVCUserClient::initWithTask 149////////////////////////////////////////////////////// 150bool IOFireWireAVCUserClient::initWithTask( 151 task_t owningTask, void * securityToken, UInt32 type, 152 OSDictionary * properties) 153{ 154 FIRELOG_MSG(("IOFireWireAVCUserClient::initWithTask (this=0x%08X)\n",this)); 155 156 fTask = owningTask; 157 158 // Allow Rosetta based apps access to this user-client 159 if (properties) 160 properties->setObject("IOUserClientCrossEndianCompatible", kOSBooleanTrue); 161 162 return IOUserClient::initWithTask(owningTask, securityToken, type,properties); 163} 164 165////////////////////////////////////////////////////// 166// IOFireWireAVCUserClient::free 167////////////////////////////////////////////////////// 168void IOFireWireAVCUserClient::free() 169{ 170 FIRELOG_MSG(("IOFireWireAVCUserClient::free (this=0x%08X)\n",this)); 171 172 if(fConnections) { 173 UInt32 i; 174 175 if(fUnit) { 176 for(i=0; i<fConnections->getCount(); i++) { 177 IOFireWireAVCConnection *connection; 178 connection = (IOFireWireAVCConnection *)fConnections->getObject(i); 179 //IOLog("Cleaning up connection %d %p\n", i, connection); 180 updateP2PCount(connection->fPlugAddr, -1, false, 0xFFFFFFFF, kFWSpeedInvalid); 181 } 182 } 183 fConnections->release(); 184 } 185 186 // Free the async cmd lock 187 if (fAsyncAVCCmdLock) 188 IOLockFree(fAsyncAVCCmdLock); 189 190#ifdef kUseAsyncAVCCommandForBlockingAVCCommand 191 if (avcCmdLock) 192 { 193 if (IOLockTryLock(avcCmdLock) == false) 194 { 195 // The avcCmdLock is currently locked, meaning we are in the process of 196 // running IOFireWireAVCUserClient::AVCCommand on another thread. Cancel 197 // that command now. 198 if (pCommandObject) 199 pCommandObject->cancel(); 200 IOTakeLock(avcCmdLock); 201 } 202 IOLockFree(avcCmdLock); 203 } 204#endif 205 206 // Release our retain on the IOFireWireAVCUnit! 207 if (fUnit) 208 fUnit->release(); 209 210 IOService::free(); 211} 212 213////////////////////////////////////////////////////// 214// IOFireWireAVCUserClient::stop 215////////////////////////////////////////////////////// 216void IOFireWireAVCUserClient::stop( IOService * provider ) 217{ 218 IOFireWireAVCUserClientAsyncCommand *pUCAsyncCommand; 219 220 FIRELOG_MSG(("IOFireWireAVCUserClient::stop (this=0x%08X)\n",this)); 221 222 fStarted = false; 223 224 // Deal with the fUCAsyncCommands array, deal with any outstanding commands and release it 225 IOTakeLock(fAsyncAVCCmdLock); 226 while (fUCAsyncCommands->getCount()) 227 { 228 pUCAsyncCommand = (IOFireWireAVCUserClientAsyncCommand *)fUCAsyncCommands->getObject(0); 229 if (pUCAsyncCommand) 230 { 231 pUCAsyncCommand->pAsyncCommand->cancel(); // Cancel, just in case it's still pending! 232 pUCAsyncCommand->pAsyncCommand->release(); 233 234 // Get rid of the memory descriptor for the shared buf 235 pUCAsyncCommand->fMem->complete(); 236 pUCAsyncCommand->fMem->release() ; 237 238 // Remove this object from our array. This will release it. 239 fUCAsyncCommands->removeObject(0); 240 } 241 } 242 243 IOUnlock(fAsyncAVCCmdLock); 244 245 IOService::stop(provider); 246} 247 248 249////////////////////////////////////////////////////// 250// IOFireWireAVCUserClient::start 251////////////////////////////////////////////////////// 252bool IOFireWireAVCUserClient::start( IOService * provider ) 253{ 254 FIRELOG_MSG(("IOFireWireAVCUserClient::start (this=0x%08X)\n",this)); 255 256 if( fStarted ) 257 return false; 258 259 fUnit = OSDynamicCast(IOFireWireAVCNub, provider); 260 if (fUnit == NULL) 261 return false; 262 263 fConnections = OSArray::withCapacity(1); 264 265 // Create array to hold outstanding async AVC commands for this UC, and a lock for protecting it 266 fUCAsyncCommands = OSArray::withCapacity(1); 267 fAsyncAVCCmdLock = IOLockAlloc(); 268 if (fAsyncAVCCmdLock == NULL) 269 return false; 270 271#ifdef kUseAsyncAVCCommandForBlockingAVCCommand 272 pCommandObject = NULL; 273 avcCmdLock = IOLockAlloc(); 274 if (avcCmdLock == NULL) { 275 return false; 276 } 277#endif 278 279 if( !IOUserClient::start(provider) ) 280 return false; 281 282 fStarted = true; 283 284 // Retain the IOFireWireAVCUnit to prevent it from being terminated 285 fUnit->retain(); 286 287 return true; 288} 289 290////////////////////////////////////////////////////// 291// IOFireWireAVCUserClient::clientClose 292////////////////////////////////////////////////////// 293IOReturn IOFireWireAVCUserClient::clientClose( void ) 294{ 295 FIRELOG_MSG(("IOFireWireAVCUserClient::clientClose (this=0x%08X)\n",this)); 296 297 if( fOpened ) 298 { 299 fOpened = false; 300 fUnit->close(this); 301 } 302 303 fStarted = false; 304 305 terminate( kIOServiceRequired ); 306 307 return kIOReturnSuccess; 308} 309 310////////////////////////////////////////////////////// 311// IOFireWireAVCUserClient::clientDied 312////////////////////////////////////////////////////// 313IOReturn IOFireWireAVCUserClient::clientDied( void ) 314{ 315 FIRELOG_MSG(("IOFireWireAVCUserClient::clientDied (this=0x%08X)\n",this)); 316 317 return clientClose(); 318} 319 320////////////////////////////////////////////////////// 321// IOFireWireAVCUserClient::open 322////////////////////////////////////////////////////// 323IOReturn IOFireWireAVCUserClient::open 324 ( void *, void *, void *, void *, void *, void * ) 325{ 326 FIRELOG_MSG(("IOFireWireAVCUserClient::open (this=0x%08X)\n",this)); 327 328 IOReturn status = kIOReturnSuccess; 329 330 if( fOpened ) 331 status = kIOReturnError; 332 333 if( status == kIOReturnSuccess ) 334 { 335 if( fUnit->open(this) ) 336 { 337 IOFWUserObjectExporter * exporter = fUnit->getDevice()->getBus()->getSessionRefExporter(); 338 status = exporter->addObject( this, NULL, &fSessionRef ); 339 if( status == kIOReturnSuccess ) 340 { 341 fOpened = true; 342 } 343 else 344 { 345 fUnit->close(this); 346 } 347 } 348 else 349 status = kIOReturnExclusiveAccess; 350 } 351 352 return status; 353} 354 355////////////////////////////////////////////////////// 356// IOFireWireAVCUserClient::openWithSessionRef 357////////////////////////////////////////////////////// 358IOReturn IOFireWireAVCUserClient::openWithSessionRef( IOFireWireLib::UserObjectHandle sessionRef, void *, void *, void *, void *, void * ) 359{ 360 FIRELOG_MSG(("IOFireWireAVCUserClient::openWithSessionRef (this=0x%08X)\n",this)); 361 362 IOReturn status = kIOReturnSuccess; 363 IOService * service = NULL; 364 IOService * original_service = NULL; 365 366 if( fOpened || !fUnit->isOpen() ) 367 status = kIOReturnError; 368 369 if( status == kIOReturnSuccess ) 370 { 371 IOFWUserObjectExporter * exporter = fUnit->getDevice()->getBus()->getSessionRefExporter(); 372 original_service = (IOService*) exporter->lookupObjectForType( sessionRef, OSTypeID(IOService) ); 373 if( original_service == NULL ) 374 status = kIOReturnBadArgument; 375 } 376 377 if( status == kIOReturnSuccess ) 378 { 379 // look for us in provider chain 380 service = original_service; 381 while( fUnit != service && service != NULL ) 382 service = service->getProvider(); 383 384 // were we found 385 if( service == NULL ) 386 status = kIOReturnBadArgument; 387 } 388 389 if( original_service ) 390 { 391 original_service->release(); 392 original_service = NULL; 393 } 394 395 return status; 396} 397 398////////////////////////////////////////////////////// 399// IOFireWireAVCUserClient::getSessionRef 400////////////////////////////////////////////////////// 401IOReturn IOFireWireAVCUserClient::getSessionRef( uint64_t * sessionRef, void *, void *, void *, void *, void * ) 402{ 403 FIRELOG_MSG(("IOFireWireAVCUserClient::getSessionRef (this=0x%08X)\n",this)); 404 405 IOReturn status = kIOReturnSuccess; 406 407 if( !fOpened ) 408 status = kIOReturnError; 409 410 if( status == kIOReturnSuccess ) 411 { 412 *sessionRef = (uint64_t) fSessionRef; 413 } 414 415 return status; 416} 417 418////////////////////////////////////////////////////// 419// IOFireWireAVCUserClient::close 420////////////////////////////////////////////////////// 421IOReturn IOFireWireAVCUserClient::close 422 ( void *, void *, void *, void *, void *, void * ) 423{ 424 FIRELOG_MSG(("IOFireWireAVCUserClient::close (this=0x%08X)\n",this)); 425 426 if( fOpened ) 427 { 428 IOFWUserObjectExporter * exporter = fUnit->getDevice()->getBus()->getSessionRefExporter(); 429 exporter->removeObject( fSessionRef ); 430 fSessionRef = 0; 431 432 fUnit->close(this); 433 fOpened = false; 434 } 435 436 return kIOReturnSuccess; 437} 438 439#ifdef kUseAsyncAVCCommandForBlockingAVCCommand 440////////////////////////////////////////////////////// 441// AVCAsyncCommandCallback 442////////////////////////////////////////////////////// 443void AVCAsyncCommandCallback(void *pRefCon, IOFireWireAVCAsynchronousCommand *pCommandObject) 444{ 445 IOSyncer *fSyncWakeup = (IOSyncer*) pRefCon; 446 447 FIRELOG_MSG(("IOFireWireAVCUserClient::AVCAsyncCommandCallback (cmd=0x%08X, state=%d)\n",pCommandObject,pCommandObject->cmdState)); 448 449 // If this command is no longer pending, release the blocking lock 450 if (!pCommandObject->isPending()) 451 fSyncWakeup->signal(pCommandObject->cmdState); 452} 453#endif 454 455////////////////////////////////////////////////////// 456// IOFireWireAVCUserClient::AVCCommand 457////////////////////////////////////////////////////// 458IOReturn IOFireWireAVCUserClient::AVCCommand(UInt8 * cmd, UInt8 * response, 459 UInt32 len, UInt32 *size) 460{ 461 FIRELOG_MSG(("IOFireWireAVCUserClient::AVCCommand (this=0x%08X)\n",this)); 462 463 IOReturn res; 464 465 if(!fStarted ) 466 return kIOReturnNoDevice; 467 468#ifndef kUseAsyncAVCCommandForBlockingAVCCommand 469 470 res = fUnit->AVCCommand(cmd,len,response,size); 471 return res; 472 473#else 474 475 // Local Vars 476 IOSyncer *fSyncWakeup; 477 UInt32 responseLen; 478 479 IOTakeLock(avcCmdLock); 480 481 // TODO: Remove (Just a sanity check. This should never happen!) 482 if (pCommandObject) 483 { 484 FIRELOG_MSG(("IOFireWireAVCUserClient::AVCCommand ERROR: pCommandObject is not NULL!\n")); 485 return kIOReturnError; 486 } 487 488 // Allocate a syncer 489 fSyncWakeup = IOSyncer::create(); 490 if(!fSyncWakeup) 491 { 492 IOUnlock(avcCmdLock); 493 return kIOReturnNoMemory; 494 } 495 496 pCommandObject = new IOFireWireAVCAsynchronousCommand; 497 if (pCommandObject) 498 { 499 res = pCommandObject->init(cmd,len,AVCAsyncCommandCallback,fSyncWakeup); 500 if (res == kIOReturnSuccess) 501 { 502 FIRELOG_MSG(("IOFireWireAVCUserClient::AVCCommand createAVCAsynchronousCommand successful, cmd=0x%08X\n",pCommandObject)); 503 504 // Submit it 505 res = pCommandObject->submit(fUnit); 506 if (res == kIOReturnSuccess) 507 { 508 // Wait for the async command callback to signal us. 509 res = fSyncWakeup->wait(); 510 FIRELOG_MSG(("IOFireWireAVCUserClient::AVCCommand continuing after receiving async command complete notification(this=0x%08X)\n",this)); 511 512 // Copy the async command final response, if it exists 513 if ((pCommandObject->cmdState == kAVCAsyncCommandStateReceivedFinalResponse) && 514 (pCommandObject->pFinalResponseBuf != NULL)) 515 { 516 // Copy as much of the response as will fit into the caller's response buf 517 if (pCommandObject->finalResponseLen > *size) 518 responseLen = *size; 519 else 520 responseLen = pCommandObject->finalResponseLen; 521 bcopy(pCommandObject->pFinalResponseBuf, response, responseLen); 522 *size = responseLen; 523 524 // Set the return value to success 525 res = kIOReturnSuccess; 526 } 527 else 528 { 529 // This is a failure, set the return value correctly 530 res = kIOReturnError; // TODO: further refine error codes based on command state 531 } 532 } 533 } 534 else 535 { 536 // TODO: Since the init failed, we need to manually release the syncer 537 } 538 539 // Release the command object 540 pCommandObject->release(); 541 pCommandObject = NULL; 542 } 543 544 // Release the syncer 545 //fSyncWakeup->release(); 546 547 IOUnlock(avcCmdLock); 548 549 return res; 550#endif 551} 552 553////////////////////////////////////////////////////// 554// IOFireWireAVCUserClient::AVCCommandInGen 555////////////////////////////////////////////////////// 556IOReturn IOFireWireAVCUserClient::AVCCommandInGen(UInt8 * cmd, UInt8 * response, 557 UInt32 len, UInt32 *size) 558{ 559 FIRELOG_MSG(("IOFireWireAVCUserClient::AVCCommandInGen (this=0x%08X)\n",this)); 560 561 IOReturn res; 562 UInt32 generation; 563 generation = *(UInt32 *)cmd; 564 cmd += sizeof(UInt32); 565 len -= sizeof(UInt32); 566 567 if(!fStarted ) 568 return kIOReturnNoDevice; 569 570 res = fUnit->AVCCommandInGeneration(generation,cmd,len,response,size); 571 572 return res; 573} 574 575////////////////////////////////////////////////////// 576// IOFireWireAVCUserClient::updateAVCCommandTimeout 577////////////////////////////////////////////////////// 578IOReturn IOFireWireAVCUserClient::updateAVCCommandTimeout 579 ( void *, void *, void *, void *, void *, void * ) 580{ 581 FIRELOG_MSG(("IOFireWireAVCUserClient::updateAVCCommandTimeout (this=0x%08X)\n",this)); 582 583 if(!fStarted ) 584 return kIOReturnNoDevice; 585 586 fUnit->updateAVCCommandTimeout(); 587 588 return kIOReturnSuccess; 589} 590 591////////////////////////////////////////////////////// 592// IOFireWireAVCUserClient::updateP2PCount 593////////////////////////////////////////////////////// 594IOReturn IOFireWireAVCUserClient::updateP2PCount(UInt32 addr, SInt32 inc, bool failOnBusReset, UInt32 chan, IOFWSpeed speed) 595{ 596 FIRELOG_MSG(("IOFireWireAVCUserClient::updateP2PCount (this=0x%08X)\n",this)); 597 598 if(!fStarted ) 599 return kIOReturnNoDevice; 600 601 IOFireWireNub *device = fUnit->getDevice(); 602 FWAddress plugAddr(kCSRRegisterSpaceBaseAddressHi, addr); 603 IOFWReadQuadCommand *readCmd; 604 IOFWCompareAndSwapCommand *lockCmd; 605 UInt32 plugVal, newVal; 606 UInt32 plugValHost, newValHost; 607 UInt32 curCount; 608 UInt32 curChan; 609 IOFWSpeed curSpeed; 610 IOReturn res; 611 612 readCmd = device->createReadQuadCommand(plugAddr, &plugVal, 1, NULL, NULL, failOnBusReset); 613 res = readCmd->submit(); 614 readCmd->release(); 615 if(res != kIOReturnSuccess) 616 return res; 617 618 plugValHost = OSSwapBigToHostInt32( plugVal ); 619 620 for(int i=0; i<4; i++) { 621 bool success; 622 623 // Parse current plug value 624 curCount = ((plugValHost & kIOFWPCRP2PCount) >> 24); 625 curChan = ((plugValHost & kIOFWPCRChannel) >> 16); 626 curSpeed = (IOFWSpeed)((plugValHost & kIOFWPCROutputDataRate) >> 14); 627 newValHost = plugValHost; 628 629 // If requested, modify channel 630 if (chan != 0xFFFFFFFF) 631 { 632 if ((curCount != 0) && (chan != curChan)) 633 return kIOReturnError; 634 635 newValHost &= ~kIOFWPCRChannel; 636 newValHost |= ((chan & 0x3F) << 16); 637 } 638 639 // If requested, modify speed 640 if (speed != kFWSpeedInvalid) 641 { 642 if ((curCount != 0) && (speed != curSpeed)) 643 return kIOReturnError; 644 645 newValHost &= ~kIOFWPCROutputDataRate; 646 newValHost |= ((speed & 0x03) << 14); 647 } 648 649 // Modify P2P count 650 newValHost &= ~kIOFWPCRP2PCount; 651 if (inc > 0) 652 { 653 if (curCount == 0x3F) 654 return kIOReturnError; 655 newValHost |= ((curCount+1) << 24); 656 } 657 else 658 { 659 if (curCount == 0) 660 return kIOReturnError; 661 newValHost |= ((curCount-1) << 24); 662 } 663 664 newVal = OSSwapHostToBigInt32( newValHost ); 665 lockCmd = device->createCompareAndSwapCommand(plugAddr, &plugVal, &newVal, 1); 666 res = lockCmd->submit(); 667 success = lockCmd->locked(&plugVal); 668 plugValHost = OSSwapBigToHostInt32( plugVal ); 669 lockCmd->release(); 670 if(res != kIOReturnSuccess) 671 break; 672 if(success) 673 break; 674 } 675 return res; 676} 677 678////////////////////////////////////////////////////// 679// IOFireWireAVCUserClient::makeConnection 680////////////////////////////////////////////////////// 681IOReturn IOFireWireAVCUserClient::makeConnection(UInt32 addr, UInt32 chan, IOFWSpeed speed) 682{ 683 FIRELOG_MSG(("IOFireWireAVCUserClient::makeConnection (this=0x%08X)\n",this)); 684 685 IOReturn err; 686 IOFireWireAVCConnection *connection; 687 connection = new IOFireWireAVCConnection; 688 if(!connection) 689 return kIOReturnNoMemory; 690 691 err = updateP2PCount(addr, 1, false, chan, speed); 692 if(kIOReturnSuccess == err) { 693 connection->fPlugAddr = addr; 694 connection->fChannel = chan; 695 fConnections->setObject(connection); 696 } 697 connection->release(); 698 return err; 699} 700 701////////////////////////////////////////////////////// 702// IOFireWireAVCUserClient::breakConnection 703////////////////////////////////////////////////////// 704void IOFireWireAVCUserClient::breakConnection(UInt32 addr) 705{ 706 FIRELOG_MSG(("IOFireWireAVCUserClient::breakConnection (this=0x%08X)\n",this)); 707 708 UInt32 i; 709 710 for(i=0; i<fConnections->getCount(); i++) { 711 IOFireWireAVCConnection *connection; 712 connection = (IOFireWireAVCConnection *)fConnections->getObject(i); 713 if(connection->fPlugAddr == addr) { 714 updateP2PCount(addr, -1, false, 0xFFFFFFFF, kFWSpeedInvalid); 715 fConnections->removeObject(i); 716 break; 717 } 718 } 719} 720 721////////////////////////////////////////////////////// 722// IOFireWireAVCUserClient::makeP2PInputConnection 723////////////////////////////////////////////////////// 724IOReturn IOFireWireAVCUserClient::makeP2PInputConnection( UInt32 plugNo, UInt32 chan, void *, void *, void *, void *) 725{ 726 FIRELOG_MSG(("IOFireWireAVCUserClient::makeP2PInputConnection (this=0x%08X)\n",this)); 727 728 return makeConnection(kPCRBaseAddress+0x84+4*plugNo, chan, kFWSpeedInvalid); 729} 730 731////////////////////////////////////////////////////// 732// IOFireWireAVCUserClient::breakP2PInputConnection 733////////////////////////////////////////////////////// 734IOReturn IOFireWireAVCUserClient::breakP2PInputConnection( UInt32 plugNo, void *, void *, void *, void *, void *) 735{ 736 FIRELOG_MSG(("IOFireWireAVCUserClient::breakP2PInputConnection (this=0x%08X)\n",this)); 737 738 breakConnection(kPCRBaseAddress+0x84+4*plugNo); 739 return kIOReturnSuccess; 740} 741 742////////////////////////////////////////////////////// 743// IOFireWireAVCUserClient::makeP2POutputConnection 744////////////////////////////////////////////////////// 745IOReturn IOFireWireAVCUserClient::makeP2POutputConnection( UInt32 plugNo, UInt32 chan, IOFWSpeed speed, void *, void *, void *) 746{ 747 FIRELOG_MSG(("IOFireWireAVCUserClient::makeP2POutputConnection (this=0x%08X)\n",this)); 748 749 return makeConnection(kPCRBaseAddress+4+4*plugNo, chan, speed); 750} 751 752////////////////////////////////////////////////////// 753// IOFireWireAVCUserClient::breakP2POutputConnection 754////////////////////////////////////////////////////// 755IOReturn IOFireWireAVCUserClient::breakP2POutputConnection( UInt32 plugNo, void *, void *, void *, void *, void *) 756{ 757 FIRELOG_MSG(("IOFireWireAVCUserClient::breakP2POutputConnection (this=0x%08X)\n",this)); 758 759 breakConnection(kPCRBaseAddress+4+4*plugNo); 760 return kIOReturnSuccess; 761} 762 763////////////////////////////////////////////////////// 764// IOFireWireAVCUserClient::message 765////////////////////////////////////////////////////// 766IOReturn IOFireWireAVCUserClient::message(UInt32 type, IOService *provider, void *argument) 767{ 768 //FIRELOG_MSG(("IOFireWireAVCUserClient::message (this=0x%08X)\n",this)); 769 770 if( fStarted == true && type == kIOMessageServiceIsResumed ) { 771 retain(); // Make sure we don't get deleted with the thread running 772 thread_t thread; 773 if( kernel_thread_start((thread_continue_t)remakeConnections, this, &thread ) == KERN_SUCCESS ) 774 { 775 thread_deallocate(thread); 776 } 777 } 778 779 return kIOReturnSuccess; 780} 781 782////////////////////////////////////////////////////// 783// IOFireWireAVCUserClient::remakeConnections 784////////////////////////////////////////////////////// 785void IOFireWireAVCUserClient::remakeConnections(void *arg) 786{ 787 IOFireWireAVCUserClient *me = (IOFireWireAVCUserClient *)arg; 788 789 FIRELOG_MSG(("IOFireWireAVCUserClient::remakeConnections (this=0x%08X)\n",me)); 790 791 UInt32 i; 792 IOReturn res; 793 for(i=0; i<me->fConnections->getCount(); i++) { 794 IOFireWireAVCConnection *connection; 795 connection = (IOFireWireAVCConnection *)me->fConnections->getObject(i); 796 //IOLog("Remaking connection %d %p\n", i, connection); 797 res = me->updateP2PCount(connection->fPlugAddr, 1, true, connection->fChannel, kFWSpeedInvalid); 798 if(res == kIOFireWireBusReset) 799 break; 800 } 801 802 me->release(); 803} 804 805////////////////////////////////////////////////////// 806// IOFireWireAVCUserClient::installUserLibAsyncAVCCommandCallback 807////////////////////////////////////////////////////// 808IOReturn IOFireWireAVCUserClient::installUserLibAsyncAVCCommandCallback(io_user_reference_t *asyncRef, uint64_t userRefcon, uint64_t *returnParam) 809{ 810 FIRELOG_MSG(("IOFireWireAVCUserClient::installUserLibAsyncAVCCommandCallback (this=0x%08X, userRefcon=0x%08X)\n",this,userRefcon)); 811 812 bcopy(asyncRef,fAsyncAVCCmdCallbackInfo,sizeof(OSAsyncReference64)); 813 *returnParam = 0x12345678; 814 815 return kIOReturnSuccess; 816} 817 818////////////////////////////////////////////////////// 819// IOFireWireAVCUserClient::CreateAVCAsyncCommand 820////////////////////////////////////////////////////// 821IOReturn IOFireWireAVCUserClient::CreateAVCAsyncCommand(UInt8 * cmd, UInt8 * asyncAVCCommandHandle, UInt32 len, UInt32 *refSize) 822{ 823 IOReturn res = kIOReturnNoMemory; 824 UInt32 *pReturnedCommandHandle = (UInt32*) asyncAVCCommandHandle; 825 UInt32 cmdLen = len - sizeof(mach_vm_address_t); 826 mach_vm_address_t *ppSharedBufAddress = (mach_vm_address_t*) &cmd[cmdLen]; 827 IOFireWireAVCUserClientAsyncCommand *pUCAsyncCommand; 828 bool memDescPrepared = false; 829 830 FIRELOG_MSG(("IOFireWireAVCUserClient::CreateAVCAsyncCommand (this=0x%08X)\n",this)); 831 832 if(!fStarted ) 833 return kIOReturnNoDevice; 834 835 do 836 { 837 // Create the wrapper object for the async command 838 pUCAsyncCommand = new IOFireWireAVCUserClientAsyncCommand; 839 if (!pUCAsyncCommand) 840 break; 841 842 // Initialize the wrapper object 843 pUCAsyncCommand->pUserClient = this; 844 845 // Create the memory descriptor for the user/kernel shared response buffer 846 pUCAsyncCommand->fMem = IOMemoryDescriptor::withAddressRange( *ppSharedBufAddress, 1024, kIODirectionInOut, fTask ) ; 847 if (!pUCAsyncCommand->fMem) 848 break; 849 850 // Prepare the memory descriptor 851 res = pUCAsyncCommand->fMem->prepare() ; 852 if (res != kIOReturnSuccess) 853 break; 854 else 855 memDescPrepared = true; 856 857 // Create the Async command object 858 pUCAsyncCommand->pAsyncCommand = new IOFireWireAVCAsynchronousCommand; 859 if (!pUCAsyncCommand->pAsyncCommand) 860 { 861 res = kIOReturnNoMemory; 862 break; 863 } 864 865 // Init the async command object 866 res = pUCAsyncCommand->pAsyncCommand->init(cmd,cmdLen,AVCUserClientAsyncCommandCallback,pUCAsyncCommand); 867 if (res != kIOReturnSuccess) 868 break; 869 870 }while(0); 871 872 if (res == kIOReturnSuccess) 873 { 874 // Everything created successfully. Add this to the array of created async commands 875 IOTakeLock(fAsyncAVCCmdLock); 876 pUCAsyncCommand->commandIdentifierHandle = fNextAVCAsyncCommandHandle++; 877 fUCAsyncCommands->setObject(pUCAsyncCommand); 878 IOUnlock(fAsyncAVCCmdLock); 879 880 // Now that it's retained by the array, remove the extra retain count 881 pUCAsyncCommand->release(); 882 883 // Set the return handle for this new command to the user-side lib 884 *pReturnedCommandHandle = pUCAsyncCommand->commandIdentifierHandle; 885 } 886 else 887 { 888 // Something went wrong. Cleanup the mess. 889 *pReturnedCommandHandle = 0xFFFFFFFF; 890 if (pUCAsyncCommand) 891 { 892 if (pUCAsyncCommand->fMem) 893 { 894 if (memDescPrepared == true) 895 pUCAsyncCommand->fMem->complete(); 896 pUCAsyncCommand->fMem->release() ; 897 } 898 899 if (pUCAsyncCommand->pAsyncCommand) 900 pUCAsyncCommand->pAsyncCommand->release(); 901 902 pUCAsyncCommand->release(); 903 } 904 } 905 906 return res; 907} 908 909////////////////////////////////////////////////////// 910// IOFireWireAVCUserClient::SubmitAVCAsyncCommand 911////////////////////////////////////////////////////// 912IOReturn IOFireWireAVCUserClient::SubmitAVCAsyncCommand(UInt32 commandHandle) 913{ 914 IOReturn res = kIOReturnBadArgument; 915 IOFireWireAVCUserClientAsyncCommand *pUCAsyncCommand; 916 917 FIRELOG_MSG(("IOFireWireAVCUserClient::SubmitAVCAsyncCommand (this=0x%08X)\n",this)); 918 919 pUCAsyncCommand = FindUCAsyncCommandWithHandle(commandHandle); 920 921 if (pUCAsyncCommand) 922 { 923 // Submit it 924 res = pUCAsyncCommand->pAsyncCommand->submit(fUnit); 925 } 926 return res; 927} 928 929////////////////////////////////////////////////////// 930// IOFireWireAVCUserClient::CancelAVCAsyncCommand 931////////////////////////////////////////////////////// 932IOReturn IOFireWireAVCUserClient::CancelAVCAsyncCommand(UInt32 commandHandle) 933{ 934 IOReturn res = kIOReturnBadArgument; 935 IOFireWireAVCUserClientAsyncCommand *pUCAsyncCommand; 936 937 FIRELOG_MSG(("IOFireWireAVCUserClient::CancelAVCAsyncCommand (this=0x%08X)\n",this)); 938 939 pUCAsyncCommand = FindUCAsyncCommandWithHandle(commandHandle); 940 941 if (pUCAsyncCommand) 942 res = pUCAsyncCommand->pAsyncCommand->cancel(); 943 944 return res; 945} 946 947////////////////////////////////////////////////////// 948// IOFireWireAVCUserClient::ReleaseAVCAsyncCommand 949////////////////////////////////////////////////////// 950IOReturn IOFireWireAVCUserClient::ReleaseAVCAsyncCommand(UInt32 commandHandle) 951{ 952 IOReturn res = kIOReturnBadArgument; 953 IOFireWireAVCUserClientAsyncCommand *pUCAsyncCommand; 954 bool found = false; 955 UInt32 i; 956 957 FIRELOG_MSG(("IOFireWireAVCUserClient::ReleaseAVCAsyncCommand (this=0x%08X)\n",this)); 958 959 // Look for an command in our array with the specified command handle 960 IOTakeLock(fAsyncAVCCmdLock); 961 for(i=0; i<fUCAsyncCommands->getCount(); i++) 962 { 963 pUCAsyncCommand = (IOFireWireAVCUserClientAsyncCommand *)fUCAsyncCommands->getObject(i); 964 if (pUCAsyncCommand->commandIdentifierHandle == commandHandle) 965 { 966 found = true; 967 break; 968 } 969 } 970 971 if (found == true) 972 { 973 pUCAsyncCommand->pAsyncCommand->cancel(); // Cancel, just in case it's still pending! 974 pUCAsyncCommand->pAsyncCommand->release(); 975 976 // Get rid of the memory descriptor for the shared buf 977 pUCAsyncCommand->fMem->complete(); 978 pUCAsyncCommand->fMem->release() ; 979 980 // Remove this object from our array. This will release it. 981 fUCAsyncCommands->removeObject(i); 982 983 res = kIOReturnSuccess; 984 } 985 986 IOUnlock(fAsyncAVCCmdLock); 987 return res; 988} 989 990////////////////////////////////////////////////////// 991// IOFireWireAVCUserClient::ReinitAVCAsyncCommand 992////////////////////////////////////////////////////// 993IOReturn IOFireWireAVCUserClient::ReinitAVCAsyncCommand(UInt32 commandHandle, const UInt8 *pCommandBytes, UInt32 len) 994{ 995 IOReturn res = kIOReturnBadArgument; 996 IOFireWireAVCUserClientAsyncCommand *pUCAsyncCommand; 997 998 FIRELOG_MSG(("IOFireWireAVCUserClient::CancelAVCAsyncCommand (this=0x%08X)\n",this)); 999 1000 pUCAsyncCommand = FindUCAsyncCommandWithHandle(commandHandle); 1001 1002 if (pUCAsyncCommand) 1003 res = pUCAsyncCommand->pAsyncCommand->reinit(pCommandBytes, len); 1004 1005 return res; 1006} 1007 1008////////////////////////////////////////////////////// 1009// IOFireWireAVCUserClient::FindUCAsyncCommandWithHandle 1010////////////////////////////////////////////////////// 1011IOFireWireAVCUserClientAsyncCommand *IOFireWireAVCUserClient::FindUCAsyncCommandWithHandle(UInt32 commandHandle) 1012{ 1013 IOFireWireAVCUserClientAsyncCommand *pUCAsyncCommand; 1014 bool found = false; 1015 UInt32 i; 1016 1017 FIRELOG_MSG(("IOFireWireAVCUserClient::FindUCAsyncCommandWithHandle (this=0x%08X)\n",this)); 1018 1019 // Look for an command in our array with the specified command handle 1020 IOTakeLock(fAsyncAVCCmdLock); 1021 for(i=0; i<fUCAsyncCommands->getCount(); i++) 1022 { 1023 pUCAsyncCommand = (IOFireWireAVCUserClientAsyncCommand *)fUCAsyncCommands->getObject(i); 1024 if (pUCAsyncCommand->commandIdentifierHandle == commandHandle) 1025 { 1026 found = true; 1027 break; 1028 } 1029 } 1030 IOUnlock(fAsyncAVCCmdLock); 1031 1032 if (found == true) 1033 return pUCAsyncCommand; 1034 else 1035 return NULL; 1036} 1037 1038////////////////////////////////////////////////////// 1039// IOFireWireAVCUserClient::HandleUCAsyncCommandCallback 1040////////////////////////////////////////////////////// 1041void IOFireWireAVCUserClient::HandleUCAsyncCommandCallback(IOFireWireAVCUserClientAsyncCommand *pUCAsyncCommand) 1042{ 1043 UInt32 respLen; 1044 //void * args[kMaxAsyncArgs]; 1045 io_user_reference_t args[kMaxAsyncArgs]; 1046 OSAsyncReference64 asyncRef; 1047 1048 FIRELOG_MSG(("IOFireWireAVCUserClient::HandleUCAsyncCommandCallback (this=0x%08X)\n",this)); 1049 1050 bcopy(fAsyncAVCCmdCallbackInfo, asyncRef, kOSAsyncRef64Size); 1051 1052 // If we just got a response, copy it into the shared user/kernel response memory buffer for this command 1053 switch(pUCAsyncCommand->pAsyncCommand->cmdState) 1054 { 1055 case kAVCAsyncCommandStateReceivedInterimResponse: 1056 pUCAsyncCommand->fMem->writeBytes(kAsyncCmdSharedBufInterimRespOffset, 1057 pUCAsyncCommand->pAsyncCommand->pInterimResponseBuf, 1058 pUCAsyncCommand->pAsyncCommand->interimResponseLen); 1059 respLen = pUCAsyncCommand->pAsyncCommand->interimResponseLen; 1060 break; 1061 1062 case kAVCAsyncCommandStateReceivedFinalResponse: 1063 pUCAsyncCommand->fMem->writeBytes(kAsyncCmdSharedBufFinalRespOffset, 1064 pUCAsyncCommand->pAsyncCommand->pFinalResponseBuf, 1065 pUCAsyncCommand->pAsyncCommand->finalResponseLen); 1066 respLen = pUCAsyncCommand->pAsyncCommand->finalResponseLen; 1067 break; 1068 1069 case kAVCAsyncCommandStatePendingRequest: 1070 case kAVCAsyncCommandStateRequestSent: 1071 case kAVCAsyncCommandStateRequestFailed: 1072 case kAVCAsyncCommandStateWaitingForResponse: 1073 case kAVCAsyncCommandStateTimeOutBeforeResponse: 1074 case kAVCAsyncCommandStateBusReset: 1075 case kAVCAsyncCommandStateOutOfMemory: 1076 case kAVCAsyncCommandStateCanceled: 1077 default: 1078 respLen = 0; 1079 break; 1080 } 1081 1082 // Send the results to user space 1083 args[0] = (io_user_reference_t) pUCAsyncCommand->commandIdentifierHandle; 1084 args[1] = (io_user_reference_t) pUCAsyncCommand->pAsyncCommand->cmdState; 1085 args[2] = (io_user_reference_t) respLen; 1086 sendAsyncResult64(asyncRef, kIOReturnSuccess, args, 3); 1087} 1088 1089////////////////////////////////////////////////////// 1090// AVCUserClientAsyncCommandCallback 1091////////////////////////////////////////////////////// 1092void AVCUserClientAsyncCommandCallback(void *pRefCon, IOFireWireAVCAsynchronousCommand *pCommandObject) 1093{ 1094 IOFireWireAVCUserClientAsyncCommand *pUCAsyncCommand = (IOFireWireAVCUserClientAsyncCommand*) pRefCon; 1095 1096 FIRELOG_MSG(("AVCUserClientAsyncCommandCallback (pCommandObject=0x%08X)\n",pCommandObject)); 1097 1098 pUCAsyncCommand->pUserClient->HandleUCAsyncCommandCallback(pUCAsyncCommand); 1099} 1100 1101// requestTerminate 1102// 1103// 1104 1105bool IOFireWireAVCUserClient::requestTerminate( IOService * provider, IOOptionBits options ) 1106{ 1107 // don't let this go inactive while its open, else the close can't be sent from the user app 1108 1109// kprintf( "IOFireWireAVCUserClient::requestTerminate\n" ); 1110 if( fOpened ) 1111 { 1112 return false; 1113 } 1114 else 1115 { 1116 return IOService::requestTerminate(provider, options); 1117 } 1118} 1119