1/* 2 * Copyright (c) 1998-2001 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#include <IOKit/avc/IOFireWireAVCUnit.h> 23#include <IOKit/avc/IOFireWireAVCCommand.h> 24#include <IOKit/avc/IOFireWireAVCConsts.h> 25#include <IOKit/IOMessage.h> 26#include <IOKit/IOKitKeys.h> 27#include <IOKit/firewire/IOFireWireUnit.h> 28#include <IOKit/firewire/IOFireWireBus.h> 29#include <IOKit/firewire/IOFWAddressSpace.h> 30#include <IOKit/firewire/IOFireWireController.h> 31#include <IOKit/avc/IOFireWirePCRSpace.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 40const OSSymbol *gIOFireWireAVCUnitType; 41const OSSymbol *gIOFireWireAVCSubUnitType; 42const OSSymbol *gIOFireWireAVCSubUnitCount[kAVCNumSubUnitTypes]; 43 44OSDefineMetaClassAndStructors(IOFireWireAVCAsynchronousCommand, IOCommand) 45OSMetaClassDefineReservedUnused(IOFireWireAVCAsynchronousCommand, 0); 46OSMetaClassDefineReservedUnused(IOFireWireAVCAsynchronousCommand, 1); 47OSMetaClassDefineReservedUnused(IOFireWireAVCAsynchronousCommand, 2); 48OSMetaClassDefineReservedUnused(IOFireWireAVCAsynchronousCommand, 3); 49 50OSDefineMetaClass(IOFireWireAVCNub, IOService) 51OSDefineAbstractStructors(IOFireWireAVCNub, IOService) 52//OSMetaClassDefineReservedUnused(IOFireWireAVCNub, 0); 53OSMetaClassDefineReservedUnused(IOFireWireAVCNub, 1); 54OSMetaClassDefineReservedUnused(IOFireWireAVCNub, 2); 55OSMetaClassDefineReservedUnused(IOFireWireAVCNub, 3); 56 57OSDefineMetaClassAndStructors(IOFireWireAVCUnit, IOFireWireAVCNub) 58OSMetaClassDefineReservedUnused(IOFireWireAVCUnit, 0); 59OSMetaClassDefineReservedUnused(IOFireWireAVCUnit, 1); 60OSMetaClassDefineReservedUnused(IOFireWireAVCUnit, 2); 61OSMetaClassDefineReservedUnused(IOFireWireAVCUnit, 3); 62 63////////////////////////////////////////////////////// 64// IOFireWireAVCAsynchronousCommand::isPending 65////////////////////////////////////////////////////// 66bool IOFireWireAVCAsynchronousCommand::isPending(void) 67{ 68 bool res; 69 70 switch (cmdState) 71 { 72 case kAVCAsyncCommandStateRequestSent: // Command has been submitted, but no write done yet 73 case kAVCAsyncCommandStateWaitingForResponse: // Received write done, but no first response 74 case kAVCAsyncCommandStateReceivedInterimResponse: // Received interim response, but no final response 75 res = true; 76 break; 77 78 case kAVCAsyncCommandStatePendingRequest: // Command created, but not yet submitted 79 case kAVCAsyncCommandStateRequestFailed: // Submitting the request failed 80 case kAVCAsyncCommandStateReceivedFinalResponse: // Received a final response 81 case kAVCAsyncCommandStateTimeOutBeforeResponse: // Timeout before first response 82 case kAVCAsyncCommandStateBusReset: // Bus reset before first response 83 case kAVCAsyncCommandStateOutOfMemory: // Ran out of memory 84 case kAVCAsyncCommandStateCanceled: // Command cancled 85 default: 86 res = false; 87 break; 88 }; 89 90 return res; 91} 92 93////////////////////////////////////////////////////// 94// IOFireWireAVCAsynchronousCommand::free 95////////////////////////////////////////////////////// 96void IOFireWireAVCAsynchronousCommand::free() 97{ 98 FIRELOG_MSG(("IOFireWireAVCAsynchronousCommand::free (this=0x%08X)\n",this)); 99 100 // Only allow a free if we're not pending. 101 if ( isPending() ) 102 { 103 cancel(); 104 } 105 106 fWriteNodeID = kIOFWAVCAsyncCmdFreed; // Special flag to indicate this command was cancled in this unit's free routine. 107 // The command is now canceled 108 cmdState = kAVCAsyncCommandStateCanceled; 109 110 if ( fWriteCmd->Busy() ) 111 { 112 fWriteCmd->cancel(kIOReturnOffline); 113 } 114 115 if ( fWriteCmd ) 116 { 117 fWriteCmd->release(); 118 fWriteCmd = NULL; 119 } 120 121 if( fDelayCmd->Busy() ) 122 { 123 fDelayCmd->cancel(kIOReturnOffline); 124 } 125 126 if (fDelayCmd) 127 { 128 fDelayCmd->release(); 129 fDelayCmd = NULL; 130 } 131 132 if (fMem) 133 { 134 fMem->release(); 135 fMem = NULL; 136 } 137 138 if (pCommandBuf) 139 { 140 delete[] pCommandBuf; 141 pCommandBuf = NULL; 142 } 143 144 if (pInterimResponseBuf) 145 { 146 delete[] pInterimResponseBuf; 147 pInterimResponseBuf = NULL; 148 } 149 150 if (pFinalResponseBuf) 151 { 152 delete[] pFinalResponseBuf; 153 pFinalResponseBuf = NULL; 154 } 155 156 OSObject::free(); 157} 158 159////////////////////////////////////////////////////// 160// IOFireWireAVCAsynchronousCommand::init 161////////////////////////////////////////////////////// 162IOReturn IOFireWireAVCAsynchronousCommand::init(const UInt8 * command, 163 UInt32 len, 164 IOFireWireAVCAsynchronousCommandCallback completionCallback, 165 void *pClientRefCon) 166{ 167 FIRELOG_MSG(("IOFireWireAVCAsynchronousCommand::init (this=0x%08X, opCode=0x%02X)\n",this,command[kAVCOpcode])); 168 169 // Validate the length of the command buffer 170 if(len == 0 || len > 512) 171 return kIOReturnBadArgument; 172 173 // Initialize async command object 174 pCommandBuf = new UInt8[len]; 175 if (!pCommandBuf) 176 return kIOReturnNoMemory; 177 bcopy(command, pCommandBuf, len); 178 cmdLen = len; 179 cmdState = kAVCAsyncCommandStatePendingRequest; 180 fCallback = completionCallback; 181 pRefCon = pClientRefCon; 182 pInterimResponseBuf = NULL; 183 interimResponseLen = 0; 184 pFinalResponseBuf = NULL; 185 finalResponseLen = 0; 186 fAVCUnit = NULL; 187 fMem = NULL; 188 fWriteCmd = NULL; 189 fDelayCmd = NULL; 190 fWriteNodeID = kFWBadNodeID; 191 fWriteGen = 0xFFFFFFFF; 192 193 return kIOReturnSuccess; 194} 195 196////////////////////////////////////////////////////// 197// IOFireWireAVCAsynchronousCommand::submit 198////////////////////////////////////////////////////// 199IOReturn IOFireWireAVCAsynchronousCommand::submit(IOFireWireAVCNub *pAVCNub) 200{ 201 IOReturn res; 202 FWAddress addr; 203 IOFireWireAVCUnit *pAVCUnit; 204 IOFireWireAVCSubUnit *pAVCSubunit; 205 206 FIRELOG_MSG(("IOFireWireAVCAsynchronousCommand::submit (this=0x%08X, opCode=0x%02X)\n",this,pCommandBuf[kAVCOpcode])); 207 208 retain(); 209 210 // If fWriteNodeID is kIOFWAVCAsyncCmdFreed, this command was cancled in the AVCUnit's free routine, 211 // so, we will not let this command be reinited or submitted again! 212 if (fWriteNodeID == kIOFWAVCAsyncCmdFreed) 213 { 214 release(); 215 return kIOReturnNotPermitted; 216 } 217 218 // Figure out if the nub is a unit or subunit 219 if (OSDynamicCast(IOFireWireAVCUnit, pAVCNub) != NULL) 220 { 221 pAVCUnit = (IOFireWireAVCUnit*) pAVCNub; 222 } 223 else if (OSDynamicCast(IOFireWireAVCSubUnit, pAVCNub) != NULL) 224 { 225 pAVCSubunit = (IOFireWireAVCSubUnit*) pAVCNub; 226 pAVCUnit = pAVCSubunit->fAVCUnit; 227 } 228 else 229 { 230 release(); 231 return kIOReturnBadArgument; 232 } 233 234 // setup AVC Request address 235 addr.addressHi = kCSRRegisterSpaceBaseAddressHi; 236 addr.addressLo = kFCPCommandAddress; 237 238 // Only submit the write command, if we are pending request 239 if (cmdState != kAVCAsyncCommandStatePendingRequest) 240 { 241 release(); 242 return kIOReturnNotPermitted; 243 } 244 245 // Save a pointer to the unit 246 fAVCUnit = pAVCUnit; 247 248 if ( not fAVCUnit->available() ) 249 { 250 release(); 251 return kIOReturnNotPermitted; 252 } 253 254 // Create a memory descriptor for the request bytes 255 fMem = IOMemoryDescriptor::withAddress((void *)pCommandBuf, 256 cmdLen, 257 kIODirectionOutIn); 258 if(!fMem) 259 { 260 release(); 261 return kIOReturnNoMemory; 262 } 263 264 // Prepare the memory descriptor 265 IOReturn err = fMem->prepare(); 266 if( err != kIOReturnSuccess ) 267 { 268 release(); 269 return kIOReturnNoMemory; 270 } 271 272 // Create a write command 273 fWriteCmd = fAVCUnit->fDevice->createWriteCommand(addr, 274 fMem, 275 IOFireWireAVCUnit::AVCAsynchRequestWriteDone, 276 this); 277 if(!fWriteCmd) 278 { 279 release(); 280 return kIOReturnNoMemory; 281 } 282 283 // Create a delay command for providing a timeout when waiting for AVC response 284 fDelayCmd = fAVCUnit->fIOFireWireAVCUnitExpansion->fControl->createDelayedCmd(250000, 285 IOFireWireAVCUnit::AVCAsynchDelayDone, 286 this); 287 if (!fDelayCmd) 288 { 289 release(); 290 return kIOReturnNoMemory; 291 } 292 293 // Get the async command lock 294 fAVCUnit->lockAVCAsynchronousCommandLock(); 295 296 // Add this command to the unit's array of pending async commands 297 // Try to add the new command to our array of outstanding commands 298 if(!fAVCUnit->fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->setObject(this)) 299 { 300 res = kIOReturnNoMemory; 301 } 302 else 303 { 304 // Submit the write command 305 res = fWriteCmd->submit(); 306 // Note that the write done routine may have already been called during the submit 307 // Only change the command state here if it hasn't already changed 308 if (cmdState == kAVCAsyncCommandStatePendingRequest) 309 { 310 if (res == kIOReturnSuccess) 311 cmdState = kAVCAsyncCommandStateRequestSent; 312 else 313 cmdState = kAVCAsyncCommandStateRequestFailed; 314 } 315 } 316 317 // Free the async command lock 318 fAVCUnit->unlockAVCAsynchronousCommandLock(); 319 320 release(); 321 322 return res; 323} 324 325////////////////////////////////////////////////////// 326// IOFireWireAVCAsynchronousCommand::reinit 327////////////////////////////////////////////////////// 328IOReturn IOFireWireAVCAsynchronousCommand::reinit(const UInt8 * command, UInt32 len) 329{ 330 FIRELOG_MSG(("IOFireWireAVCAsynchronousCommand::reinit (this=0x%08X)\n",this)); 331 332 // If fWriteNodeID is kIOFWAVCAsyncCmdFreed, this command was cancled in the AVCUnit's free routine, 333 // so, we will not let this command be reinited or submitted again! 334 if (fWriteNodeID == kIOFWAVCAsyncCmdFreed) 335 return kIOReturnNotPermitted; 336 337 // Only allow a reinit if we're not pending. 338 if (isPending()) 339 return kIOReturnNotPermitted; 340 341 // Validate the length of the command buffer 342 if(len == 0 || len > 512) 343 return kIOReturnBadArgument; 344 345 if (fWriteCmd) 346 fWriteCmd->release(); 347 348 if (fDelayCmd) 349 fDelayCmd->release(); 350 351 if (fMem) 352 fMem->release(); 353 354 if (pCommandBuf) 355 delete pCommandBuf; 356 357 if (pInterimResponseBuf) 358 delete pInterimResponseBuf; 359 360 if (pFinalResponseBuf) 361 delete pFinalResponseBuf; 362 363 // Initialize async command object 364 pCommandBuf = new UInt8[len]; 365 if (!pCommandBuf) 366 return kIOReturnNoMemory; 367 bcopy(command, pCommandBuf, len); 368 369 cmdLen = len; 370 cmdState = kAVCAsyncCommandStatePendingRequest; 371 pInterimResponseBuf = NULL; 372 interimResponseLen = 0; 373 pFinalResponseBuf = NULL; 374 finalResponseLen = 0; 375 fAVCUnit = NULL; 376 fMem = NULL; 377 fWriteCmd = NULL; 378 fDelayCmd = NULL; 379 fWriteNodeID = kFWBadNodeID; 380 fWriteGen = 0xFFFFFFFF; 381 382 return kIOReturnSuccess; 383} 384 385////////////////////////////////////////////////////// 386// IOFireWireAVCAsynchronousCommand::cancel 387////////////////////////////////////////////////////// 388IOReturn IOFireWireAVCAsynchronousCommand::cancel(void) 389{ 390 // Local Vars 391 UInt32 cmdIndex; 392 393 FIRELOG_MSG(("IOFireWireAVCAsynchronousCommand::cancel (this=0x%08X)\n",this)); 394 395 // TODO: What if the AVCUnit is already been freed? 396 397 // TODO: Do some state checking before continuing 398 399 // Get the async command lock 400 fAVCUnit->lockAVCAsynchronousCommandLock(); 401 402 // Cancel the delay command, and write command (if needed?) 403 if ((cmdState == kAVCAsyncCommandStateRequestSent) && (fWriteCmd)) 404 fWriteCmd->cancel(kIOReturnAborted); 405 else if ((cmdState == kAVCAsyncCommandStateWaitingForResponse) && (fDelayCmd)) 406 fDelayCmd->cancel(kIOReturnAborted); 407 408 // The command is now canceled 409 cmdState = kAVCAsyncCommandStateCanceled; 410 411 // Remove this object from the unit's array 412 cmdIndex = fAVCUnit->indexOfAVCAsynchronousCommandObject(this); 413 if (cmdIndex != 0xFFFFFFFF) 414 { 415 fAVCUnit->removeAVCAsynchronousCommandObjectAtIndex(cmdIndex); 416 } 417 418 // Free the async command lock 419 fAVCUnit->unlockAVCAsynchronousCommandLock(); 420 421 // We do a client callback here 422 if (fCallback != NULL) 423 fCallback(pRefCon,this); 424 425 return kIOReturnSuccess; 426} 427 428////////////////////////////////////////////////////// 429// IOFireWireAVCUnit::setProperties 430////////////////////////////////////////////////////// 431IOReturn IOFireWireAVCUnit::setProperties (OSObject * properties ) 432{ 433 IOReturn result = kIOReturnSuccess ; 434 435 //IOLog(IOFireWireAVCUnit::setProperties\n"); 436 437 OSDictionary* dict = OSDynamicCast( OSDictionary, properties ) ; 438 439 if ( dict ) 440 { 441 OSObject* value = dict->getObject( "RobustAVCResponseMatching" ) ; 442 443 if ( value ) 444 { 445 // Disable robust AV/C command/response matching 446 //IOLog("Disabling RobustAVCResponseMatching for AV/C device 0x%08X\n",(unsigned int) this); 447 fIOFireWireAVCUnitExpansion->enableRobustAVCCommandResponseMatching = false; 448 } 449 else 450 { 451 result = IOFireWireAVCNub::setProperties ( properties ) ; 452 } 453 } 454 else 455 result = IOFireWireAVCNub::setProperties ( properties ) ; 456 457 return result ; 458} 459 460////////////////////////////////////////////////////// 461// IOFireWireAVCUnit::AVCResponse 462////////////////////////////////////////////////////// 463UInt32 IOFireWireAVCUnit::AVCResponse(void *refcon, UInt16 nodeID, IOFWSpeed &speed, 464 FWAddress addr, UInt32 len, const void *buf, IOFWRequestRefCon requestRefcon) 465{ 466 // Local Vars 467 IOFireWireAVCUnit *me = (IOFireWireAVCUnit *)refcon; 468 UInt8 *pResponseBytes = (UInt8*) buf; 469 UInt32 res = kFWResponseAddressError; 470 UInt32 i; 471 IOFireWireAVCAsynchronousCommand *pCmd; 472 bool foundOutstandingAVCAsynchCommandForNode = false; 473 bool matchFound = false; 474 UInt32 matchedCommandIndex; 475 bool doCallback = false; 476 477 FIRELOG_MSG(("IOFireWireAVCUnit::AVCResponse (this=0x%08X)\n",me)); 478 FIRELOG_MSG(("AVCResponse Info: nodeID=0x%04X, opCode=0x%02X, avcAddress=0x%02X respLen=0x%08X\n",nodeID, pResponseBytes[kAVCOpcode], pResponseBytes[kAVCAddress],len)); 479 480 // Check this packet for validity 481 if ((addr.addressLo != kFCPResponseAddress) || (len < 3)) 482 return res; 483 484 // Get the async command lock 485 me->lockAVCAsynchronousCommandLock(); 486 487 // Look through all the pending AVCAsynch commands to find a match 488 for (i = 0; i < me->fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getCount(); i++) 489 { 490 pCmd = (IOFireWireAVCAsynchronousCommand*) me->fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getObject(i); 491 FIRELOG_MSG(("Evaluating outstanding AVC async cmd %d (%d total): cmd = 0x%08X, nodeID = 0x%04X, opCode=0x%02X, avcAddress=0x%02X pending=%s\n", 492 i, 493 me->fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getCount(), 494 pCmd, 495 pCmd->fWriteNodeID, 496 pCmd->pCommandBuf[kAVCOpcode] , 497 pCmd->pCommandBuf[kAVCAddress], 498 (pCmd->isPending() ? "YES" : "NO") 499 )); 500 501 // Does the nodeID match? 502 if (pCmd->fWriteNodeID == nodeID) 503 { 504 // Mark that we found at least one pending AVCAsync command for this node 505 foundOutstandingAVCAsynchCommandForNode = true; 506 507 // Evaluate the AVCAddress, and Opcode, looking for a match 508 if ((pCmd->pCommandBuf[kAVCAddress] == pResponseBytes[kAVCAddress]) && (pCmd->pCommandBuf[kAVCOpcode] == pResponseBytes[kAVCOpcode])) 509 { 510 if ((pCmd->pCommandBuf[kAVCCommandResponse] == kAVCNotifyCommand) && 511 ((pResponseBytes[kAVCCommandResponse] == kAVCAcceptedStatus) || (pResponseBytes[kAVCCommandResponse] == kAVCInTransitionStatus) || (pResponseBytes[kAVCCommandResponse] == kAVCImplementedStatus))) 512 { 513 // This is not a match because notify commands cannot have this type of response! 514 } 515 else 516 { 517 // This is a match 518 matchFound = true; 519 matchedCommandIndex = i; 520 break; 521 } 522 } 523 } 524 } 525 526 // If we didn't match, yet we have an oustanding command for this node, and the response is from a tape-subunit, 527 // see if this is the special-case of the tape-subunit transport-state command, which overwrites the opcode 528 // in the response packet. 529 if ((!matchFound) && (foundOutstandingAVCAsynchCommandForNode) && ((pResponseBytes[kAVCAddress] & 0xF8) == 0x20)) 530 { 531 // Look again through all the pending AVCAsynch commands to find a match 532 for (i = 0; i < me->fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getCount(); i++) 533 { 534 pCmd = (IOFireWireAVCAsynchronousCommand*) me->fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getObject(i); 535 536 // Does the nodeID match? 537 if (pCmd->fWriteNodeID == nodeID) 538 { 539 // Evaluate the AVCAddress for a match, and see if this command is the tape subunit transport-state opcode 540 if ((pCmd->pCommandBuf[kAVCAddress] == pResponseBytes[kAVCAddress]) && (pCmd->pCommandBuf[kAVCOpcode] == 0xD0)) 541 { 542 // It is a tape-subunit transport state command. See if the response packet look like it could indeed 543 // be the one we're looking for 544 if (((pResponseBytes[kAVCOpcode] == 0xC1) || 545 (pResponseBytes[kAVCOpcode] == 0xC2) || 546 (pResponseBytes[kAVCOpcode] == 0xC3) || 547 (pResponseBytes[kAVCOpcode] == 0xC4)) && (len == 4)) 548 { 549 if ((pCmd->pCommandBuf[kAVCCommandResponse] == kAVCNotifyCommand) && 550 ((pResponseBytes[kAVCCommandResponse] == kAVCAcceptedStatus) || (pResponseBytes[kAVCCommandResponse] == kAVCInTransitionStatus) || (pResponseBytes[kAVCCommandResponse] == kAVCImplementedStatus))) 551 { 552 // This is not a match because notify commands cannot have this type of response! 553 } 554 else 555 { 556 // This is a match 557 matchFound = true; 558 matchedCommandIndex = i; 559 break; 560 } 561 } 562 } 563 } 564 } 565 } 566 567 // We found a match, so deal with it 568 if (matchFound) 569 { 570 FIRELOG_MSG(("AVC Async Request/Response Match Found: %d\n",matchedCommandIndex)); 571 572 // At this point, if the interim response buffer is NULL, then this is the 573 // first response for this command, so now is the time to cancle the timer 574 if (pCmd->pInterimResponseBuf == NULL) 575 { 576 // Abort the timeOut delay command 577 if (pCmd->fDelayCmd) 578 pCmd->fDelayCmd->cancel(kIOReturnAborted); 579 } 580 581 // Is this an Interim, or Final Response 582 if (pResponseBytes[kAVCCommandResponse] == 0x0F) 583 { 584 // Interim Response 585 586 // Allocate the command's interim response buffer, and copy response bytes 587 pCmd->pInterimResponseBuf = new UInt8[len]; 588 if (pCmd->pInterimResponseBuf) 589 { 590 pCmd->interimResponseLen = len; 591 bcopy(pResponseBytes, pCmd->pInterimResponseBuf, len); 592 593 // Set the command' state 594 pCmd->cmdState = kAVCAsyncCommandStateReceivedInterimResponse; 595 } 596 else 597 { 598 pCmd->cmdState = kAVCAsyncCommandStateOutOfMemory; 599 600 // Remove this command from the unit's pending async command list 601 me->removeAVCAsynchronousCommandObjectAtIndex(matchedCommandIndex); 602 } 603 } 604 else 605 { 606 // Final Response 607 608 // Allocate the command's final response buffer, and copy response bytes 609 pCmd->pFinalResponseBuf = new UInt8[len]; 610 if (pCmd->pFinalResponseBuf) 611 { 612 pCmd->finalResponseLen = len; 613 bcopy(pResponseBytes, pCmd->pFinalResponseBuf, len); 614 615 // Set the command' state 616 pCmd->cmdState = kAVCAsyncCommandStateReceivedFinalResponse; 617 } 618 else 619 pCmd->cmdState = kAVCAsyncCommandStateOutOfMemory; 620 621 // Remove this command from the unit's pending async command list 622 me->removeAVCAsynchronousCommandObjectAtIndex(matchedCommandIndex); 623 } 624 625 // We need to do a callback after we release the lock 626 doCallback = true; 627 628 res = kFWResponseComplete; 629 } 630 631 // Free the async command lock 632 me->unlockAVCAsynchronousCommandLock(); 633 634 // Se if we need to do a callback to the client 635 if (doCallback == true) 636 { 637 // Notify the client 638 if (pCmd->fCallback != NULL) 639 pCmd->fCallback(pCmd->pRefCon,pCmd); 640 } 641 642 // If we don't have a match, see if there is a pending blocking-AVC command for this node 643 if (!matchFound) 644 { 645 // if this is for us, copy the status bytes from fPseudoSpace 646 if(me->fCommand) 647 { 648 if (me->fIOFireWireAVCUnitExpansion->enableRobustAVCCommandResponseMatching) 649 res = me->fCommand->handleResponse(nodeID, len, buf); 650 else 651 res = me->fCommand->handleResponseWithSimpleMatching(nodeID, len, buf); 652 } 653 } 654 655 return res; 656} 657 658////////////////////////////////////////////////////// 659// IOFireWireAVCUnit::rescanSubUnits 660////////////////////////////////////////////////////// 661void IOFireWireAVCUnit::rescanSubUnits(void *arg) 662{ 663 664 IOFireWireAVCUnit *me = (IOFireWireAVCUnit *)arg; 665 666 FIRELOG_MSG(("IOFireWireAVCUnit::rescanSubUnits (this=0x%08X)\n",me)); 667 668 me->updateSubUnits(false); 669} 670 671////////////////////////////////////////////////////// 672// IOFireWireAVCUnit::updateSubUnits 673////////////////////////////////////////////////////// 674void IOFireWireAVCUnit::updateSubUnits(bool firstTime) 675{ 676 FIRELOG_MSG(("IOFireWireAVCUnit::updateSubUnits (this=0x%08X)\n",this)); 677 678 IOReturn res; 679 UInt32 size; 680 UInt8 cmd[8],response[8]; 681 OSObject *prop; 682 bool hasFCP = true; 683// Get SubUnit info 684 cmd[kAVCCommandResponse] = kAVCStatusInquiryCommand; 685 cmd[kAVCAddress] = kAVCUnitAddress; 686 cmd[kAVCOpcode] = kAVCSubunitInfoOpcode; 687 cmd[kAVCOperand0] = 7; 688 cmd[4] = cmd[5] = cmd[6] = cmd[7] = 0xff; 689 size = 8; 690 691 for(int i = 0; i<10; i++) { 692 res = AVCCommand(cmd, 8, response, &size); 693 if(res == (kIOFireWireResponseBase + kFWResponseConflictError)) { 694 IOSleep(10); 695 continue; // Try again 696 } 697 else if(res == kIOReturnSuccess && response[kAVCOperand1] == 0xff) { 698 // Some devices initially say they have no subunits. 699 IOSleep(10); 700 continue; // Try again 701 } 702 else if(res == kIOReturnOffline){ 703 // Bus-reset occurred. 704 FIRELOG_MSG(("IOFireWireAVCUnit %p, bus-reset during subunit scan! firstTime=%s\n",this,firstTime == true ? "true" : "false")); 705 IOSleep(10); 706 continue; // Try again 707 } 708 else 709 break; // Got a final result code 710 } 711 if(res != kIOReturnSuccess || response[kAVCCommandResponse] != kAVCImplementedStatus) { 712 if(firstTime) { 713 // Sony convertor box doesn't do AVC, make it look like a camcorder. 714 // Panasonic NV-C5 doesn't support SubunitInfo query but does support VCR commands 715 if(res != kIOReturnSuccess) 716 hasFCP = false; 717 718 response[kAVCOperand1] = 0x20; // One VCR 719 response[kAVCOperand2] = 0xff; 720 response[kAVCOperand3] = 0xff; 721 response[kAVCOperand4] = 0xff; 722 } 723 else 724 { 725 this->release(); // If this is not the first-time we need to release before returning 726 return; // No update necessary 727 } 728 } 729 else if(size == 5) { 730 // some mLAN devices don't report their subunit info correctly, 731 // set it up here 732 size = 8; 733 response[kAVCOperand1] = 0x08; // One Audio subunit 734 response[kAVCOperand2] = 0xff; 735 response[kAVCOperand3] = 0xff; 736 response[kAVCOperand4] = 0xff; 737 } 738 if(firstTime) 739 setProperty("supportsFCP", hasFCP); 740 741 // Zero count of subunits before updating with new counts 742 bzero(fSubUnitCount, sizeof(fSubUnitCount)); 743 for(int i=0; i<kAVCNumSubUnitTypes; i++) { 744 removeProperty(gIOFireWireAVCSubUnitCount[i]); 745 } 746 747 for(int i=0; i<4; i++) { 748 UInt8 val = response[kAVCOperand1+i]; 749 if(val != 0xff) { 750 UInt8 type, num; 751 type = val >> 3; 752 num = (val & 0x7)+1; 753 fSubUnitCount[type] = num; 754 //IOLog("Subunit type %x, num %d\n", type, num); 755 setProperty(gIOFireWireAVCSubUnitCount[type]->getCStringNoCopy(), num, 8); 756 757 // Create sub unit nub if it doesn't exist 758 IOFireWireAVCSubUnit *sub = NULL; 759 OSDictionary * propTable = 0; 760 do { 761 propTable = OSDictionary::withCapacity(6); 762 if(!propTable) 763 break; 764 prop = OSNumber::withNumber(type, 32); 765 propTable->setObject(gIOFireWireAVCSubUnitType, prop); 766 prop->release(); 767 if(!firstTime) { 768 OSIterator *childIterator; 769 IOFireWireAVCSubUnit * found = NULL; 770 childIterator = getClientIterator(); 771 if(childIterator) { 772 OSObject *child; 773 while( (child = childIterator->getNextObject())) { 774 found = OSDynamicCast(IOFireWireAVCSubUnit, child); 775 if(found && found->matchPropertyTable(propTable)) { 776 break; 777 } 778 else 779 found = NULL; 780 } 781 childIterator->release(); 782 if(found) { 783 break; 784 } 785 } 786 } 787 sub = new IOFireWireAVCSubUnit; 788 if(!sub) 789 break; 790 791 if (!sub->init(propTable, this)) 792 break; 793 if (!sub->attach(this)) 794 break; 795 sub->setProperty("supportsFCP", hasFCP); 796 797 sub->registerService(); 798 799 // Special handling for Sony TVs - make them root! 800 if (type == 0) 801 { 802 OSObject *prop; 803 OSNumber *deviceGUID; 804 unsigned long long guidVal; 805 806 prop = getProperty(gFireWire_GUID); 807 deviceGUID = OSDynamicCast( OSNumber, prop ); 808 guidVal = deviceGUID->unsigned64BitValue(); 809 810 if ((guidVal & 0xFFFFFF0000000000LL) == 0x0800460000000000LL) // Sony 811 { 812 fDevice->setNodeFlags(kIOFWMustBeRoot); 813 } 814 } 815 816 } while (0); 817 if(sub) 818 sub->release(); 819 if(propTable) 820 propTable->release(); 821 } 822 } 823 824 // Prune sub units that have gone away. 825 if(!firstTime) { 826 OSIterator *childIterator; 827 IOFireWireAVCSubUnit * sub = NULL; 828 childIterator = getClientIterator(); 829 if(childIterator) { 830 OSObject *child; 831 while( (child = childIterator->getNextObject())) { 832 sub = OSDynamicCast(IOFireWireAVCSubUnit, child); 833 if(sub) { 834 OSNumber *type; 835 type = OSDynamicCast(OSNumber, sub->getProperty(gIOFireWireAVCSubUnitType)); 836 if(type && !fSubUnitCount[type->unsigned32BitValue()]) 837 sub->terminate(); 838 } 839 } 840 childIterator->release(); 841 } 842 } 843 844 if (!firstTime) 845 this->release(); // If this is not the first-time we need to release before returning 846} 847 848////////////////////////////////////////////////////// 849// IOFireWireAVCUnit::start 850////////////////////////////////////////////////////// 851bool IOFireWireAVCUnit::start(IOService *provider) 852{ 853 FIRELOG_MSG(("IOFireWireAVCUnit::start (this=0x%08X)\n",this)); 854 855 OSObject *prop; 856 UInt32 type; 857 OSNumber *deviceGUID; 858 unsigned long long guidVal; 859 UInt8 series; 860 861 fDevice = OSDynamicCast(IOFireWireNub, provider); 862 if(!fDevice) 863 return false; 864 865 // Retain our provider, the IOFireWireUnit object 866 fDevice->retain(); 867 868 // create/clear expansion data 869 fIOFireWireAVCUnitExpansion = (ExpansionData*) IOMalloc( sizeof(ExpansionData) ); 870 if( fIOFireWireAVCUnitExpansion == NULL ) 871 return false; 872 else 873 bzero( fIOFireWireAVCUnitExpansion, sizeof(ExpansionData) ); 874 875 // Get the controller 876 fIOFireWireAVCUnitExpansion->fControl = fDevice->getController(); 877 if(!fIOFireWireAVCUnitExpansion->fControl) 878 return false; 879 880 // Enable robust AV/C Command/Response Matching 881 fIOFireWireAVCUnitExpansion->enableRobustAVCCommandResponseMatching = true; 882 883 // Create array to hold outstanding async AVC commands 884 fIOFireWireAVCUnitExpansion->fAVCAsyncCommands = OSArray::withCapacity(1); 885 886 if(!gIOFireWireAVCUnitType) 887 gIOFireWireAVCUnitType = OSSymbol::withCString("Unit_Type"); 888 if(!gIOFireWireAVCUnitType) 889 return false; 890 891 if(!gIOFireWireAVCSubUnitType) 892 gIOFireWireAVCSubUnitType = OSSymbol::withCString("SubUnit_Type"); 893 if(!gIOFireWireAVCSubUnitType) 894 return false; 895 896 for(int i=0; i<kAVCNumSubUnitTypes; i++) { 897 char buff[16]; 898 if(!gIOFireWireAVCSubUnitCount[i]) { 899 snprintf(buff, sizeof(buff), "AVCSubUnit_%x", i); 900 gIOFireWireAVCSubUnitCount[i] = OSSymbol::withCString(buff); 901 if(!gIOFireWireAVCSubUnitCount[i]) 902 return false; 903 } 904 } 905 906 if( !IOService::start(provider)) 907 return false; 908 909 fFCPResponseSpace = fDevice->getBus()->createInitialAddressSpace(kFCPResponseAddress, 512, 910 NULL, AVCResponse, this); 911 if(!fFCPResponseSpace) 912 return false; 913 914 fFCPResponseSpace->activate(); 915 916 avcLock = IOLockAlloc(); 917 if (avcLock == NULL) { 918 IOLog("IOAVCUnit::start avcLock failed\n"); 919 return false; 920 } 921 922 cmdLock = IOLockAlloc(); 923 if (cmdLock == NULL) { 924 IOLog("IOAVCUnit::start cmdLock failed\n"); 925 return false; 926 } 927 928// Get Unit type 929 IOReturn res; 930 UInt32 size; 931 UInt8 cmd[8],response[8]; 932 UInt32 unitInfoRetryCount = 0; 933 934 cmd[kAVCCommandResponse] = kAVCStatusInquiryCommand; 935 cmd[kAVCAddress] = kAVCUnitAddress; 936 cmd[kAVCOpcode] = kAVCUnitInfoOpcode; 937 cmd[3] = cmd[4] = cmd[5] = cmd[6] = cmd[7] = 0xff; 938 size = 8; 939 res = AVCCommand(cmd, 8, response, &size); 940 if(kIOReturnSuccess != res) 941 { 942 do 943 { 944 unitInfoRetryCount++; 945 IOSleep(2000); // two seconds, give device time to get it's act together 946 size = 8; 947 res = AVCCommand(cmd, 8, response, &size); 948 }while((kIOReturnSuccess != res) && (unitInfoRetryCount <= 4)); 949 } 950 951 if(kIOReturnSuccess != res || response[kAVCCommandResponse] != kAVCImplementedStatus) 952 type = kAVCVideoCamera; // Anything that doesn't implement AVC properly is probably a camcorder! 953 else 954 type = IOAVCType(response[kAVCOperand1]); 955 956 // Copy over matching properties from FireWire Unit 957 prop = provider->getProperty(gFireWireVendor_ID); 958 if(prop) 959 setProperty(gFireWireVendor_ID, prop); 960 961 962 prop = provider->getProperty(gFireWire_GUID); 963 if(prop) 964 { 965 setProperty(gFireWire_GUID, prop); 966 967 // Check the guid to see if this device requires special asynch throttling 968 deviceGUID = OSDynamicCast( OSNumber, prop ); 969 guidVal = deviceGUID->unsigned64BitValue(); 970 if ((guidVal & 0xFFFFFFFFFF000000LL) == 0x0000850000000000LL) 971 { 972 series = (UInt8) ((guidVal & 0x0000000000FF0000LL) >> 16); 973 if ((series <= 0x13) || ((series >= 0x18) && (series <= 0x23))) 974 fDevice->setNodeFlags( kIOFWLimitAsyncPacketSize ); 975 976 series = (UInt8) (((guidVal & 0x00000000FFFFFFFFLL) >> 18) & 0x3f); // GL-2 977 if(series == 0x19) // GL-2 978 fDevice->setNodeFlags(kIOFWMustNotBeRoot); 979 } 980 981 if ((guidVal & 0xFFFFFF0000000000LL) == 0x0080450000000000LL) // panasonic 982 { 983 series = (UInt8) ((guidVal & 0x0000000000FF0000LL) >> 16); 984 985 prop = provider->getProperty(gFireWireProduct_Name); 986 if(prop) 987 { 988 OSString * string = OSDynamicCast ( OSString, prop ) ; 989 if (string->isEqualTo("PV-GS15")) 990 { 991 fDevice->setNodeFlags(kIOFWMustNotBeRoot); 992 fDevice->setNodeFlags(kIOFWMustHaveGap63); 993 IOLog("Panasonic guid=%lld series=%x model=%s\n", guidVal, series, string->getCStringNoCopy()); // node flags happens here 994 } 995 else if (string->isEqualTo("PV-GS120 ")) 996 { 997 fDevice->setNodeFlags(kIOFWMustBeRoot); 998 IOLog("Panasonic guid=%lld series=%x model=%s\n", guidVal, series, string->getCStringNoCopy()); // node flags happens here 999 } 1000 else 1001 { 1002 FIRELOG_MSG(( "Unknown Panasonic series\n" )); 1003 } 1004 } 1005 } 1006 } 1007 1008 prop = provider->getProperty(gFireWireProduct_Name); 1009 if(prop) 1010 setProperty(gFireWireProduct_Name, prop); 1011 1012 setProperty("Unit_Type", type, 32); 1013 1014 // mark ourselves as started, this allows us to service resumed messages 1015 // resumed messages after this point should be safe. 1016 fStarted = true; 1017 1018 updateSubUnits(true); 1019 1020 // Finally enable matching on this object. 1021 registerService(); 1022 1023 return true; 1024} 1025 1026bool IOFireWireAVCUnit::available() 1027{ 1028 return fStarted; 1029} 1030 1031////////////////////////////////////////////////////// 1032// IOFireWireAVCUnit::free 1033////////////////////////////////////////////////////// 1034void IOFireWireAVCUnit::free(void) 1035{ 1036 // Local Vars 1037 IOFireWireAVCAsynchronousCommand *pCmd; 1038 1039 FIRELOG_MSG(("IOFireWireAVCUnit::free (this=0x%08X)\n",this)); 1040 1041 if ((fIOFireWireAVCUnitExpansion) && (fIOFireWireAVCUnitExpansion->fControl)) 1042 { 1043 lockAVCAsynchronousCommandLock(); 1044 1045 fStarted = false; 1046 1047 unlockAVCAsynchronousCommandLock(); 1048 } 1049 1050 if (fFCPResponseSpace) { 1051 fFCPResponseSpace->deactivate(); 1052 fFCPResponseSpace->release(); 1053 fFCPResponseSpace = NULL; 1054 } 1055 if (avcLock) { 1056 IOLockFree(avcLock); 1057 avcLock = NULL; 1058 } 1059 1060 if ((fIOFireWireAVCUnitExpansion) && (fIOFireWireAVCUnitExpansion->fControl) && (fIOFireWireAVCUnitExpansion->fAVCAsyncCommands)) 1061 { 1062 // Get the unit's async command lock 1063 lockAVCAsynchronousCommandLock(); 1064 1065 // Cancel any remaining pending AVC async commands in the AVC command array 1066 while (fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getCount()) 1067 { 1068 pCmd = (IOFireWireAVCAsynchronousCommand*) fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getObject(0); 1069 pCmd->fWriteNodeID = kIOFWAVCAsyncCmdFreed; // Special flag to indicate this command was cancled in this unit's free routine. 1070 pCmd->cancel(); 1071 } 1072 1073 // Free the async command lock 1074 unlockAVCAsynchronousCommandLock(); 1075 1076 // Release the async AVC command array 1077 fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->release(); 1078 } 1079 1080 if (cmdLock) 1081 { 1082 IOLockFree(cmdLock); 1083 cmdLock = NULL; 1084 } 1085 1086 // Release our provider, the IOFireWireUnit object 1087 if( fDevice ) 1088 { 1089 fDevice->release(); 1090 fDevice = NULL; 1091 } 1092 1093 // free expansion data 1094 if (fIOFireWireAVCUnitExpansion) 1095 { 1096 IOFree ( fIOFireWireAVCUnitExpansion, sizeof(ExpansionData) ); 1097 fIOFireWireAVCUnitExpansion = NULL; 1098 } 1099 1100 IOService::free(); 1101} 1102 1103////////////////////////////////////////////////////// 1104// IOFireWireAVCUnit::matchPropertyTable 1105////////////////////////////////////////////////////// 1106bool IOFireWireAVCUnit::matchPropertyTable(OSDictionary * table) 1107{ 1108 //FIRELOG_MSG(("IOFireWireAVCUnit::matchPropertyTable (this=0x%08X)\n",this)); 1109 1110 // 1111 // If the service object wishes to compare some of its properties in its 1112 // property table against the supplied matching dictionary, 1113 // it should do so in this method and return truth on success. 1114 // 1115 if (!IOService::matchPropertyTable(table)) return false; 1116 1117 // We return success if the following expression is true -- individual 1118 // comparisions evaluate to truth if the named property is not present 1119 // in the supplied matching dictionary. 1120 1121 1122 bool res = compareProperty(table, gIOFireWireAVCUnitType) && 1123 compareProperty(table, gFireWireVendor_ID) && 1124 compareProperty(table, gFireWire_GUID); 1125 1126 if(res) { 1127 // Also see if requested subunits are available. 1128 int i; 1129 //OLog("Checking subunit foo\n"); 1130 for(i=0; i<kAVCNumSubUnitTypes; i++) { 1131 OSNumber * value; 1132 value = OSDynamicCast(OSNumber, table->getObject( gIOFireWireAVCSubUnitCount[i] )); 1133 if(value) { 1134 // make sure we have at least the requested number of subunits of the requested type 1135 //IOLog("Want %d AVCSubUnit_%x, got %d\n", value->unsigned8BitValue(), i, fSubUnitCount[i]); 1136 res = value->unsigned8BitValue() <= fSubUnitCount[i]; 1137 if(!res) 1138 break; 1139 } 1140 } 1141 //IOLog("After Checking subunit foo, match is %d\n", res); 1142 } 1143 return res; 1144} 1145 1146////////////////////////////////////////////////////// 1147// IOFireWireAVCUnit::AVCCommand 1148////////////////////////////////////////////////////// 1149IOReturn IOFireWireAVCUnit::AVCCommand(const UInt8 * in, UInt32 len, UInt8 * out, UInt32 *size) 1150{ 1151 FIRELOG_MSG(("IOFireWireAVCUnit::AVCCommand (this=0x%08X, opCode=0x%02X)\n",this,in[2])); 1152 1153 IOReturn res; 1154 IOFireWireAVCCommand *cmd; 1155 if(len == 0 || len > 512) { 1156 IOLog("Loopy AVCCmd, len %d, respLen %d\n", (uint32_t)len, (uint32_t)*size); 1157 return kIOReturnBadArgument; 1158 } 1159 1160 // Retain the AVCUnit object while processing the command 1161 this->retain(); 1162 1163 cmd = IOFireWireAVCCommand::withNub(fDevice, in, len, out, size); 1164 if(!cmd) 1165 { 1166 // Remove the extra retain we made above. 1167 this->release(); 1168 1169 return kIOReturnNoMemory; 1170 } 1171 1172 // lock avc space 1173 IOTakeLock(avcLock); 1174 1175 fCommand = cmd; 1176 1177 res = fCommand->submit(); 1178 if(res != kIOReturnSuccess) { 1179 //IOLog("AVCCommand returning 0x%x\n", res); 1180 //IOLog("command %x\n", *(UInt32 *)in); 1181 } 1182 IOTakeLock(cmdLock); 1183 fCommand = NULL; 1184 IOUnlock(cmdLock); 1185 cmd->release(); 1186 IOUnlock(avcLock); 1187 1188 // Remove the extra retain we made above. 1189 this->release(); 1190 1191 return res; 1192} 1193 1194////////////////////////////////////////////////////// 1195// IOFireWireAVCUnit::AVCCommandInGeneration 1196////////////////////////////////////////////////////// 1197IOReturn IOFireWireAVCUnit::AVCCommandInGeneration(UInt32 generation, const UInt8 * in, UInt32 len, UInt8 * out, UInt32 *size) 1198{ 1199 FIRELOG_MSG(("IOFireWireAVCUnit::AVCCommandInGeneration (this=0x%08X)\n",this)); 1200 1201 IOReturn res; 1202 IOFireWireAVCCommand *cmd; 1203 if(len == 0 || len > 512) { 1204 IOLog("Loopy AVCCmd, len %d, respLen %d\n", (uint32_t)len, (uint32_t)*size); 1205 return kIOReturnBadArgument; 1206 } 1207 1208 cmd = IOFireWireAVCCommand::withNub(fDevice, generation, in, len, out, size); 1209 if(!cmd) 1210 return kIOReturnNoMemory; 1211 1212 // lock avc space 1213 IOTakeLock(avcLock); 1214 fCommand = cmd; 1215 1216 res = fCommand->submit(); 1217 if(res != kIOReturnSuccess) { 1218 //IOLog("AVCCommand returning 0x%x\n", res); 1219 //IOLog("command %x\n", *(UInt32 *)in); 1220 } 1221 IOTakeLock(cmdLock); 1222 fCommand = NULL; 1223 IOUnlock(cmdLock); 1224 cmd->release(); 1225 IOUnlock(avcLock); 1226 1227 return res; 1228} 1229 1230////////////////////////////////////////////////////// 1231// IOFireWireAVCUnit::AVCAsynchRequestWriteDone 1232////////////////////////////////////////////////////// 1233void IOFireWireAVCUnit::AVCAsynchRequestWriteDone(void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd) 1234{ 1235 IOFireWireAVCAsynchronousCommand *pCmdObject = OSDynamicCast(IOFireWireAVCAsynchronousCommand, (IOFireWireAVCAsynchronousCommand*)refcon); 1236 1237 if(!pCmdObject) 1238 return; 1239 1240 IOFireWireAVCUnit *pAVCUnit = OSDynamicCast(IOFireWireAVCUnit, pCmdObject->fAVCUnit); 1241 1242 if(!pAVCUnit) 1243 return; 1244 1245 UInt32 cmdIndex; 1246 bool doCallback = false; 1247 1248 FIRELOG_MSG(("IOFireWireAVCUnit::AVCAsynchRequestWriteDone (cmd=0x%08X, status=0x%08X)\n",pCmdObject,status)); 1249 1250 // Get the async command lock 1251 pAVCUnit->lockAVCAsynchronousCommandLock(); 1252 1253 // If this is due to a cancel, don't process further 1254 if(status == kIOReturnAborted) 1255 { 1256 pAVCUnit->unlockAVCAsynchronousCommandLock(); 1257 return; 1258 } 1259 1260 // Verify the async command object is still on our list of pending commands 1261 cmdIndex = pAVCUnit->indexOfAVCAsynchronousCommandObject(pCmdObject); 1262 if (cmdIndex == 0xFFFFFFFF) 1263 { 1264 // The AVC async command must have already been terminated. Free the lock, and return. 1265 pAVCUnit->unlockAVCAsynchronousCommandLock(); 1266 return; 1267 } 1268 1269 if(status == kIOReturnSuccess) 1270 { 1271 // Store current node and generation 1272 if(device) 1273 device->getNodeIDGeneration(pCmdObject->fWriteGen, pCmdObject->fWriteNodeID); 1274 1275 // Start the delay 1276 pCmdObject->fDelayCmd->submit(); 1277 1278 // Change the state of this command 1279 pCmdObject->cmdState = kAVCAsyncCommandStateWaitingForResponse; 1280 } 1281 else 1282 { 1283 // Change the state of this command 1284 pCmdObject->cmdState = kAVCAsyncCommandStateRequestFailed; 1285 1286 // We need to do a callback after we release the lock 1287 doCallback = true; 1288 1289 // Remove this command from the unit's pending async command list 1290 pAVCUnit->removeAVCAsynchronousCommandObjectAtIndex(cmdIndex); 1291 } 1292 1293 // Free the async command lock 1294 pAVCUnit->unlockAVCAsynchronousCommandLock(); 1295 1296 // Se if we need to do a callback to the client 1297 if (doCallback == true) 1298 { 1299 // Notify the client 1300 if (pCmdObject->fCallback != NULL) 1301 pCmdObject->fCallback(pCmdObject->pRefCon,pCmdObject); 1302 } 1303} 1304 1305////////////////////////////////////////////////////// 1306// IOFireWireAVCUnit::AVCAsynchDelayDone 1307////////////////////////////////////////////////////// 1308void IOFireWireAVCUnit::AVCAsynchDelayDone(void *refcon, IOReturn status, IOFireWireBus *bus, IOFWBusCommand *fwCmd) 1309{ 1310 IOFireWireAVCAsynchronousCommand *pCmdObject = OSDynamicCast( IOFireWireAVCAsynchronousCommand, (IOFireWireAVCAsynchronousCommand*)refcon ); 1311 1312 if(!pCmdObject) 1313 return; 1314 1315 IOFireWireAVCUnit *pAVCUnit = OSDynamicCast(IOFireWireAVCUnit, (IOFireWireAVCUnit*)pCmdObject->fAVCUnit); 1316 1317 if(!pAVCUnit) 1318 return; 1319 1320 UInt32 cmdIndex; 1321 1322 FIRELOG_MSG(("IOFireWireAVCUnit::AVCAsynchDelayDone, cmd=0x%08X, status = 0x%08X\n",pCmdObject,status)); 1323 1324 // only proceed if status is time-out! 1325 if (status != kIOReturnTimeout) 1326 return; 1327 1328 // Get the async command lock 1329 pAVCUnit->lockAVCAsynchronousCommandLock(); 1330 1331 // Verify the async command object is still on our list of pending commands 1332 cmdIndex = pAVCUnit->indexOfAVCAsynchronousCommandObject(pCmdObject); 1333 if (cmdIndex == 0xFFFFFFFF) 1334 { 1335 // The AVC async command must have already been terminated. Free the lock, and return. 1336 pAVCUnit->unlockAVCAsynchronousCommandLock(); 1337 return; 1338 } 1339 1340 // Change the state of this command 1341 pCmdObject->cmdState = kAVCAsyncCommandStateTimeOutBeforeResponse; 1342 1343 // Remove this command from the unit's pending async command list 1344 pAVCUnit->removeAVCAsynchronousCommandObjectAtIndex(cmdIndex); 1345 1346 // Free the async command lock 1347 pAVCUnit->unlockAVCAsynchronousCommandLock(); 1348 1349 // Notify the client 1350 if (pCmdObject->fCallback != NULL) 1351 pCmdObject->fCallback(pCmdObject->pRefCon,pCmdObject); 1352} 1353 1354////////////////////////////////////////////////////// 1355// IOFireWireAVCUnit::indexOfAVCAsynchronousCommandObject 1356////////////////////////////////////////////////////// 1357UInt32 IOFireWireAVCUnit::indexOfAVCAsynchronousCommandObject(IOFireWireAVCAsynchronousCommand *pCommandObject) 1358{ 1359 UInt32 res = 0xFFFFFFFF; 1360 int i; 1361 1362 // NOTE: Assume that the AVCAsynchronousCommandLock has already 1363 // been taken before this function was called! 1364 1365 for (i=(fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getCount()-1);i>=0;i--) 1366 { 1367 IOFireWireAVCAsynchronousCommand *pCmd; 1368 pCmd = (IOFireWireAVCAsynchronousCommand*) fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getObject(i); 1369 if(pCommandObject == pCmd) 1370 { 1371 res = i; 1372 break; 1373 } 1374 } 1375 1376 return res; 1377} 1378 1379////////////////////////////////////////////////////// 1380// IOFireWireAVCUnit::removeAVCAsynchronousCommandObjectAtIndex 1381////////////////////////////////////////////////////// 1382void IOFireWireAVCUnit::removeAVCAsynchronousCommandObjectAtIndex(UInt32 index) 1383{ 1384 // NOTE: Assume that the AVCAsynchronousCommandLock has already 1385 // been taken before this function was called! 1386 1387 fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->removeObject(index); 1388} 1389 1390////////////////////////////////////////////////////// 1391// IOFireWireAVCUnit::lockAVCAsynchronousCommandLock 1392////////////////////////////////////////////////////// 1393void IOFireWireAVCUnit::lockAVCAsynchronousCommandLock() 1394{ 1395 FIRELOG_MSG(("IOFireWireAVCUnit::lockAVCAsynchronousCommandLock (this=0x%08X)\n",this)); 1396 fIOFireWireAVCUnitExpansion->fControl->closeGate(); 1397} 1398 1399////////////////////////////////////////////////////// 1400// IOFireWireAVCUnit::unlockAVCAsynchronousCommandLock 1401////////////////////////////////////////////////////// 1402void IOFireWireAVCUnit::unlockAVCAsynchronousCommandLock() 1403{ 1404 FIRELOG_MSG(("IOFireWireAVCUnit::unlockAVCAsynchronousCommandLock (this=0x%08X)\n",this)); 1405 fIOFireWireAVCUnitExpansion->fControl->openGate(); 1406} 1407 1408////////////////////////////////////////////////////// 1409// IOFireWireAVCUnit::handleOpen 1410////////////////////////////////////////////////////// 1411bool IOFireWireAVCUnit::handleOpen( IOService * forClient, IOOptionBits options, void * arg ) 1412{ 1413 FIRELOG_MSG(("IOFireWireAVCUnit::handleOpen (this=0x%08X)\n",this)); 1414 1415 bool ok = false; 1416 1417 if( !isOpen() ) 1418 { 1419 ok = fDevice->open(this, options, arg); 1420 if(ok) 1421 ok = IOService::handleOpen(forClient, options, arg); 1422 } 1423 1424 return ok; 1425} 1426 1427////////////////////////////////////////////////////// 1428// IOFireWireAVCUnit::handleClose 1429////////////////////////////////////////////////////// 1430void IOFireWireAVCUnit::handleClose( IOService * forClient, IOOptionBits options ) 1431{ 1432 FIRELOG_MSG(("IOFireWireAVCUnit::handleClose (this=0x%08X)\n",this)); 1433 1434 if( isOpen( forClient ) ) 1435 { 1436 IOService::handleClose(forClient, options); 1437 fDevice->close(this, options); 1438 } 1439} 1440 1441////////////////////////////////////////////////////// 1442// IOFireWireAVCUnit::message 1443////////////////////////////////////////////////////// 1444IOReturn IOFireWireAVCUnit::message(UInt32 type, IOService *provider, void *argument) 1445{ 1446 // Local Vars 1447 UInt32 i; 1448 IOFireWireAVCAsynchronousCommand *pCmd; 1449 OSArray *pTerminatedCommandsArray = NULL; 1450 1451 FIRELOG_MSG(("IOFireWireAVCUnit::message (type = 0x%08X, this=0x%08X)\n",type,this)); 1452 1453 // If we have outstanding Async AVC commands, process them here for bus-reset command termination. 1454 if( fStarted == true && 1455 type == kIOMessageServiceIsSuspended && 1456 (fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getCount() > 0)) 1457 { 1458 // Get the unit's async command lock 1459 lockAVCAsynchronousCommandLock(); 1460 1461 for (i = 0; i < fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getCount(); i++) 1462 { 1463 pCmd = (IOFireWireAVCAsynchronousCommand*) fIOFireWireAVCUnitExpansion->fAVCAsyncCommands->getObject(i); 1464 1465 // If the write command has been submitted, but no write done yet, cancel it now 1466 if (pCmd->cmdState == kAVCAsyncCommandStateRequestSent) 1467 pCmd->fWriteCmd->cancel(kIOReturnAborted); 1468 1469 // If the delay command has been submitted, but not completed, cancel it now 1470 if (pCmd->cmdState == kAVCAsyncCommandStateWaitingForResponse) 1471 pCmd->fDelayCmd->cancel(kIOReturnAborted); 1472 1473 FIRELOG_MSG(("IOFireWireAVCUnit::message setting pending async AVC command (0x%08X) to bus-reset state\n",pCmd)); 1474 pCmd->cmdState = kAVCAsyncCommandStateBusReset; 1475 1476 // Remove this command from the unit's pending async command list 1477 removeAVCAsynchronousCommandObjectAtIndex(i); 1478 1479 // Add this command to the array of commands which we need to do client callbacks for 1480 // Note - this will add an extra retain to the command, which will be released when the array is released 1481 if (pTerminatedCommandsArray == NULL) 1482 pTerminatedCommandsArray = OSArray::withCapacity(1); 1483 if (pTerminatedCommandsArray != NULL) 1484 pTerminatedCommandsArray->setObject(pCmd); 1485 } 1486 1487 // Free the async command lock 1488 unlockAVCAsynchronousCommandLock(); 1489 1490 // Do we have any terminated commands which we should do client callbacks for? 1491 if (pTerminatedCommandsArray != NULL) 1492 { 1493 for (i = 0; i < pTerminatedCommandsArray->getCount(); i++) 1494 { 1495 pCmd = (IOFireWireAVCAsynchronousCommand*) pTerminatedCommandsArray->getObject(i); 1496 1497 // Notify the client 1498 if (pCmd->fCallback != NULL) 1499 pCmd->fCallback(pCmd->pRefCon,pCmd); 1500 } 1501 1502 // Release the array - note that this will release all the objects from the array 1503 // to remove the extra retain that was done when the command was added to the array 1504 pTerminatedCommandsArray->release(); 1505 } 1506 } 1507 1508 // If this is a bus-reset complete, then rescan subunits on the device 1509 // on another thread 1510 if( fStarted == true && type == kIOMessageServiceIsResumed ) 1511 { 1512 this->retain(); // Retain this object before starting the rescan thread! 1513 thread_t thread; 1514 if( kernel_thread_start((thread_continue_t)rescanSubUnits, this, &thread ) == KERN_SUCCESS ) 1515 { 1516 thread_deallocate(thread); 1517 } 1518 } 1519 messageClients(type); 1520 1521 return kIOReturnSuccess; 1522} 1523 1524////////////////////////////////////////////////////// 1525// IOFireWireAVCUnit::updateAVCCommandTimeout 1526////////////////////////////////////////////////////// 1527IOReturn IOFireWireAVCUnit::updateAVCCommandTimeout() 1528{ 1529 FIRELOG_MSG(("IOFireWireAVCUnit::updateAVCCommandTimeout (this=0x%08X)\n",this)); 1530 1531 IOTakeLock(cmdLock); 1532 if(fCommand != NULL) 1533 fCommand->resetInterimTimeout(); 1534 IOUnlock(cmdLock); 1535 1536 return kIOReturnSuccess; 1537} 1538 1539/* -------------------------------------------- AVC SubUnit -------------------------------------------- */ 1540 1541OSDefineMetaClassAndStructors(IOFireWireAVCSubUnit, IOFireWireAVCNub) 1542OSMetaClassDefineReservedUnused(IOFireWireAVCSubUnit, 0); 1543OSMetaClassDefineReservedUnused(IOFireWireAVCSubUnit, 1); 1544OSMetaClassDefineReservedUnused(IOFireWireAVCSubUnit, 2); 1545OSMetaClassDefineReservedUnused(IOFireWireAVCSubUnit, 3); 1546 1547////////////////////////////////////////////////////// 1548// IOFireWireAVCSubUnit::init 1549////////////////////////////////////////////////////// 1550bool IOFireWireAVCSubUnit::init(OSDictionary *propTable, IOFireWireAVCUnit *provider) 1551{ 1552 FIRELOG_MSG(("IOFireWireAVCSubUnit::init (this=0x%08X)\n",this)); 1553 1554 OSObject *prop; 1555 1556 if(!IOFireWireAVCNub::init(propTable)) 1557 return false; 1558 fAVCUnit = provider; 1559 if(!fAVCUnit) 1560 return false; 1561 fDevice = fAVCUnit->getDevice(); 1562 if(!fDevice) 1563 return false; 1564 1565 // Copy over matching properties from AVC Unit 1566 prop = provider->getProperty(gFireWireVendor_ID); 1567 if(prop) 1568 setProperty(gFireWireVendor_ID, prop); 1569 prop = provider->getProperty(gFireWire_GUID); 1570 if(prop) 1571 setProperty(gFireWire_GUID, prop); 1572 prop = provider->getProperty(gFireWireProduct_Name); 1573 if(prop) 1574 setProperty(gFireWireProduct_Name, prop); 1575 1576 // Copy over user client properties 1577 prop = provider->getProperty(gIOUserClientClassKey); 1578 if(prop) 1579 setProperty(gIOUserClientClassKey, prop); 1580 prop = provider->getProperty(kIOCFPlugInTypesKey); 1581 if(prop) 1582 setProperty(kIOCFPlugInTypesKey, prop); 1583 1584 return true; 1585} 1586 1587/** 1588 ** Matching methods 1589 **/ 1590////////////////////////////////////////////////////// 1591// IOFireWireAVCSubUnit::matchPropertyTable 1592////////////////////////////////////////////////////// 1593bool IOFireWireAVCSubUnit::matchPropertyTable(OSDictionary * table) 1594{ 1595 //FIRELOG_MSG(("IOFireWireAVCSubUnit::matchPropertyTable (this=0x%08X)\n",this)); 1596 1597 // 1598 // If the service object wishes to compare some of its properties in its 1599 // property table against the supplied matching dictionary, 1600 // it should do so in this method and return truth on success. 1601 // 1602 if (!IOService::matchPropertyTable(table)) return false; 1603 1604 // We return success if the following expression is true -- individual 1605 // comparisions evaluate to truth if the named property is not present 1606 // in the supplied matching dictionary. 1607 1608 1609 return compareProperty(table, gIOFireWireAVCSubUnitType) && 1610 compareProperty(table, gFireWireVendor_ID) && 1611 compareProperty(table, gFireWire_GUID); 1612} 1613 1614////////////////////////////////////////////////////// 1615// IOFireWireAVCSubUnit::AVCCommand 1616////////////////////////////////////////////////////// 1617IOReturn IOFireWireAVCSubUnit::AVCCommand(const UInt8 * in, UInt32 len, UInt8 * out, UInt32 *size) 1618{ 1619 FIRELOG_MSG(("IOFireWireAVCSubUnit::AVCCommand (this=0x%08X)\n",this)); 1620 1621 return fAVCUnit->AVCCommand(in, len, out, size); 1622} 1623 1624////////////////////////////////////////////////////// 1625// IOFireWireAVCSubUnit::AVCCommandInGeneration 1626////////////////////////////////////////////////////// 1627IOReturn IOFireWireAVCSubUnit::AVCCommandInGeneration(UInt32 generation, const UInt8 * in, UInt32 len, UInt8 * out, UInt32 *size) 1628{ 1629 FIRELOG_MSG(("IOFireWireAVCSubUnit::AVCCommandInGeneration (this=0x%08X)\n",this)); 1630 1631 return fAVCUnit->AVCCommandInGeneration(generation, in, len, out, size); 1632} 1633 1634////////////////////////////////////////////////////// 1635// IOFireWireAVCSubUnit::updateAVCCommandTimeout 1636////////////////////////////////////////////////////// 1637IOReturn IOFireWireAVCSubUnit::updateAVCCommandTimeout() 1638{ 1639 FIRELOG_MSG(("IOFireWireAVCSubUnit::updateAVCCommandTimeout (this=0x%08X)\n",this)); 1640 1641 return fAVCUnit->updateAVCCommandTimeout(); 1642} 1643 1644////////////////////////////////////////////////////// 1645// IOFireWireAVCSubUnit::handleOpen 1646////////////////////////////////////////////////////// 1647bool IOFireWireAVCSubUnit::handleOpen( IOService * forClient, IOOptionBits options, void * arg ) 1648{ 1649 FIRELOG_MSG(("IOFireWireAVCSubUnit::handleOpen (this=0x%08X)\n",this)); 1650 1651 bool ok = false; 1652 1653 if( !isOpen() ) 1654 { 1655 ok = fAVCUnit->open(this, options, arg); 1656 if(ok) 1657 ok = IOService::handleOpen(forClient, options, arg); 1658 } 1659 1660 return ok; 1661} 1662 1663////////////////////////////////////////////////////// 1664// IOFireWireAVCSubUnit::handleClose 1665////////////////////////////////////////////////////// 1666void IOFireWireAVCSubUnit::handleClose( IOService * forClient, IOOptionBits options ) 1667{ 1668 FIRELOG_MSG(("IOFireWireAVCSubUnit::handleClose (this=0x%08X)\n",this)); 1669 1670 if( isOpen( forClient ) ) 1671 { 1672 IOService::handleClose(forClient, options); 1673 fAVCUnit->close(this, options); 1674 } 1675} 1676 1677////////////////////////////////////////////////////// 1678// IOFireWireAVCSubUnit::message 1679////////////////////////////////////////////////////// 1680IOReturn IOFireWireAVCSubUnit::message(UInt32 type, IOService *provider, void *argument) 1681{ 1682 //FIRELOG_MSG(("IOFireWireAVCSubUnit::message (this=0x%08X)\n",this)); 1683 1684 messageClients(type); 1685 1686 return kIOReturnSuccess; 1687} 1688 1689