1/* 2 * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include "DVLib.h" 25#include <pthread.h> 26#include <mach/mach_port.h> 27#include <mach/thread_act.h> 28#include <mach/vm_map.h> 29#include <mach/mach_time.h> 30 31#include <syslog.h> // Debug messages 32 33#include <IOKit/IOMessage.h> 34 35#include <IOKit/firewire/IOFireWireLibIsoch.h> 36#include <IOKit/avc/IOFireWireAVCConsts.h> 37 38#include <IOKit/pwr_mgt/IOPMLib.h> 39 40#include "IsochronousDataHandler.h" 41 42#define kDVRequestID 0 43 44#define ALT_TIMING 1 45 46//#define USE_P2P_CONNECTIONS_FOR_DV_READ 1 47 48#define PAGE_SIZE 4096; 49#define kNoPlug 0xdeadbeef 50 51// Use Channel 62 to send DV, and 63 to receive (because camcorders love to send on 63). 52#define kWriteChannel 62 53#define kReadChannel 61 54 55enum { 56 kNoP2PConnection = 0, 57 kWriteP2PConnection = 1, 58 kReadP2PConnection = 2 59}; 60 61// AY_TODO: Move the following to IOFireWireAVCConsts.h 62#define kAVCSignalModeDVCPro50_525_60 0x74 63#define kAVCSignalModeDVCPro50_625_50 0xF4 64#define kAVCSignalModeDVCPro100_525_60 0x70 65#define kAVCSignalModeDVCPro100_625_50 0xF0 66#define kAVCSignalModeMask_DVCPro50 0x74 67#define kAVCSignalModeMask_DVCPro100 0x70 68#define kAVCSignalModeMask_HD 0x08 69 70enum { 71 kDVRunning = 0, 72 kDVStopped = 1, 73 kDVWriteOverrun = 2, 74 kDVReadOverrun = 3, 75 kDVStopping = 4 76}; 77 78// Isoc packet header, 2nd quad 79enum { 80 kPALBit = 0x800000, // 1 bit 81 kSTypeMask = 0x7c0000, // 5 bits 82 kSTypeSD = 0x00000, 83 kSTypeSDL = 0x40000, 84 kSTypeHD = 0x80000 85}; 86 87enum { 88 89 // DVRead 90 kNumPacketsPerInputBuffer = 100, 91 kDVSDPayloadPacketSize = 480, 92 kDVSDLPayloadPacketSize = 240, 93 kDVHDPayloadPacketSize = 960, 94 kDVCPro50PayloadPacketSize = 960, 95 kDVCPro100PayloadPacketSize = 1920, 96 97 kNumPingPongs = 8, // Number of DCL blocks in read program 98 kNumPacketsPerPingPong = 100, 99 kNumDCLsPerPingPongPacket = 1, 100 kRecordNumDCLs = 101 kNumPingPongs * (kNumPacketsPerPingPong * kNumDCLsPerPingPongPacket+3)+6, 102 kMaxDCLSize = 32, 103 kRecordDCLProgramSize = kMaxDCLSize * kRecordNumDCLs, 104}; 105 106enum { 107 kNTSCFrameRateNumerator = 2997, 108 kNTSCFrameRateDenominator = 100, 109 kNTSCPlayFramePeriodNumerator = kNTSCFrameRateDenominator, 110 kNTSCPlayFramePeriodDenominator = kNTSCFrameRateNumerator, 111 kNTSCNumDataPacketsPerDVFrame = 250, 112 kNTSCNumDataPacketsPerGroup = 125, 113 114 kPALFrameRateNumerator = 25, 115 kPALFrameRateDenominator = 1, 116 kPALPlayFramePeriodNumerator = kPALFrameRateDenominator, 117 kPALPlayFramePeriodDenominator = kPALFrameRateNumerator, 118 kPALNumDataPacketsPerDVFrame = 300, 119 kPALNumDataPacketsPerGroup = 150, 120 121 kDVPacketAlignSlop = 8, // add 8 bytes to 122 kDVPacketCIPSize = 8, 123 kPlaySYTDelay = 3, // Sony camcorders send a delay of 2, but VX2000 wants 3 from us... 124}; 125 126// Frame Sizes 127enum { 128 kFrameSize_SD525_60 = 120000, 129 kFrameSize_DVCPro525_60 = 120000, 130 kFrameSize_SD625_50 = 144000, 131 kFrameSize_DVCPro625_50 = 144000, 132 kFrameSize_SDL525_60 = 60000, 133 kFrameSize_SDL625_50 = 72000, 134 kFrameSize_DVCPro50_525_60 = 240000, 135 kFrameSize_HD1125_60 = 240000, 136 kFrameSize_DVCPro50_625_50 = 288000, 137 kFrameSize_HD1250_50 = 288000, 138 kFrameSize_DVCPro100_525_60 = 480000, 139 kFrameSize_DVCPro100_625_50 = 576000 140}; 141 142typedef struct { 143 UInt32 fRequest; 144 void * fParams; 145} DVReq; 146 147typedef struct { 148 mach_msg_header_t msgHdr; 149 DVReq dvRequest; 150} SendMsg; 151 152typedef struct { 153 mach_msg_header_t msgHdr; 154 DVReq dvRequest; 155 mach_msg_trailer_t trailer; 156} ReceiveMsg; 157 158 159struct DVLocalOutStruct; 160typedef struct DVLocalOutStruct DVLocalOut, *DVLocalOutPtr; 161 162typedef struct _DVStreamStruct { 163 IOFireWireLibDeviceRef pFWDevice; 164 IOFireWireAVCLibProtocolInterface **fAVCProtoInterface; 165 IOFireWireLibLocalIsochPortRef pFWLocalIsochPort; 166 IOFireWireLibRemoteIsochPortRef pFWRemoteIsochPort; 167 IOFireWireLibIsochChannelRef fIsochChannelRef; 168 UInt32 fPlug; // PCR plug register of local node 169 DVThread * fThread; 170 DVFrameVars fFrames; 171 DCLCommandPtr pDCLList; // DCLs used for playing. 172 UInt8 * fDCLBuffers; // Buffers to use to transfer packet data. 173 UInt32 fDCLBufferSize; // Total allocation for output buffers 174 UInt64 fChannelMask; // Legal channels to use 175 UInt8 fSignalMode; // signal type 176 UInt8 fIsocChannel; // Channel to use 177 UInt8 fMaxSpeed; // Max bus speed for isoc channel 178 DVDevice *pDVDevice; 179 UInt32 fDVFrameSize; // Frame size based on current signal mode 180} DVStream; 181 182// structs 183 184struct DVLocalOutStruct 185{ 186 DVLocalOutPtr pNextLocalData; 187 DVLocalOutPtr pPrevLocalData; 188 DVGlobalOutPtr pGlobalData; 189 // Pointer to jump command to end of buffer group. 190 DCLJumpPtr pEndOfBufferGroupDCLJump; 191 // Pointer to label command at start of buffer group. 192 DCLLabelPtr pStartOfBufferGroupDCLLabel; 193 // Pointer to jump command to use to skip an empty packet. 194 DCLJumpPtr pBufferGroupSkipEmptyPacketDCLJump; 195 // Label to jump to to skip an empty packet. 196 DCLLabelPtr pBufferGroupSkipEmptyPacketDCLLabel; 197 // Label to jump to to not skip an empty packet. 198 DCLLabelPtr pBufferGroupDontSkipEmptyPacketDCLLabel; 199 // Pointer to buffer group's time stamp. 200 UInt32 * pBufferGroupTimeStampPtr; 201 // Pointer to first DCL command in buffer group. 202 DCLCommandPtr pFirstBufferGroupDCLCommand; 203 // Pointer to last DCL command in buffer group. 204 DCLCommandPtr pLastBufferGroupDCLCommand; 205 206 // DCL update list with just the buffer group's time stamp DCL. 207 DCLCommandPtr timeStampUpdateDCLList; 208 // List of DCL commands that need updating for each run through buffer group. 209 DCLCommandPtr * bufferGroupUpdateDCLList; 210 // Number of DCL commands in above list. 211 UInt32 updateListSize; 212 213 // Number of packets in this buffer group. 214 UInt32 numPackets; 215 UInt32 fBlockNum; 216 // True if pBufferGroupSkipEmptyPacketDCLJump is set to skip an empty packet. 217 bool skippingEmptyPacket; 218}; 219 220// DVGlobalOut 221 222struct DVGlobalOutStruct { 223 DVStream fStreamVars; 224 UInt8 * fDCLCommandPool; 225 UInt32 fTotalPool; 226 UInt32 fAllocatedPool; 227 DVSharedVars fSharedDCLVars; 228 229 // output structures 230 DVLocalOut fLocalDataArray[kNumPlayBufferGroups]; // List of buffer group data records. 231 UInt8 * pEmptyTransmitBuffers; // Buffer to use for empty transmit packet data. 232 DCLLabelPtr pUnderrunDCLLabel; // Pointer to underrun label. 233 UInt32 totalPackets; // Total number of packets for playing. 234 UInt32 activePackets; // Total number of active packets for playing. 235 UInt32 nominalFrameCycleTime; // Nominal cycle time between frames. 236 UInt32 nextSYT; // Next SYT to use on frame boundary. 237 UInt32 nextDBC; // Next DBC to use for first packet of next buffer group. 238 UInt32 numDataPacketsPerFrame; // number of data packets per frame (different for NTSC or PAL) 239 UInt32 numDataPacketsPerGroup; // Number of data packets in each group (different for NTSC or PAL) 240 UInt32 playFramePeriodNumerator; 241 UInt32 playFramePeriodDenominator; 242 UInt32 playFrameRateNumerator, playFrameRateDenominator; 243 UInt32 fDataPacketSize; // Data portion, in bytes 244 UInt32 fDataQuadSize; // Data portion, in quads 245 UInt32 fAlignQuadSize; // Packet size in quads, padded to 16 byte boundary. 246 UInt32 fHeader0; // First quad - sourceID, data size, seq. no. 247 UInt32 fHeader1; // Second quad - format, PAL/NTSC, SType, rsv, SYT 248 // channel buffer structures 249 UInt32 nextDataPacketNum; // Data packet number for first data packet of next buffer group. 250 UInt32 * pImageBuffer; // Buffer to hold image in. 251 bool fUpdateBuffers; // Our job to copy image data? 252 bool pendingDVWriteUnderrunHandler; 253 bool deferredDVWriteFree; 254 bool dvWriteStopInProgress; 255}; 256 257typedef struct DVLocalInStruct 258{ 259 DVGlobalInPtr pGlobalData; 260 DCLCommandPtr fFirstCmd; 261 DCLLabelPtr fStateLabel; 262 DCLJumpPtr fStateJmp; 263 UInt32 fBlockNum; 264 UInt32 * fTimeStampPtr; 265} DVLocalIn, *DVLocalInPtr; 266 267struct DVGlobalInStruct 268{ 269 DVStream fStreamVars; 270 DCLCommandPtr *ppUpdateDCLList; 271 UInt32 packetCount; 272 UInt32 fLastFrameTime; 273 DVLocalIn fLocalDataArray[kNumPingPongs]; 274 DCLLabelPtr fTerminal; 275 UInt8 *pImageBuffer; 276 UInt8 lastSequenceCount; 277 UInt8 fState; // Current DCL block 278 UInt8 fSynced; 279 UInt8 fRestarted; 280 bool pendingDVReadUnderrunHandler; 281 bool deferredDVReadFree; 282 bool dvReadStopInProgress; 283}; 284 285static IOReturn buildWriteProgram(DVGlobalOutPtr pGlobalData); 286static IOReturn allocateBuffers(DVGlobalOutPtr pGlobalData); 287static void DVWritePoll(DVGlobalOutPtr globs); 288static void DVReadPoll(DVGlobalInPtr globs); 289static void closeStream(DVStream *stream); 290static void doDVReadHandleInputUnderrun( DVGlobalInPtr pGlobalData ); 291static void doDVHandleOutputUnderrun( DVGlobalOutPtr pGlobalData ); 292 293#include <CoreFoundation/CFRuntime.h> 294 295#if ( MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 ) && defined(CF_USING_COLLECTABLE_MEMORY) 296#define REGISTER_THREADS_WITH_GC 1 297#else // MAC_OS_X_VERSION_MIN_REQUIRED < 1060 298#define REGISTER_THREADS_WITH_GC 0 299#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1060 300 301#if REGISTER_THREADS_WITH_GC 302#include <dlfcn.h> 303typedef void (*ObjCRegisterThreadWithCollectorPtr)(void); 304#endif REGISTER_THREADS_WITH_GC 305 306UInt32 AddFWCycleTimeToFWCycleTime( UInt32 cycleTime1, UInt32 cycleTime2 ) 307{ 308 UInt32 secondCount, 309 cycleCount, 310 cycleOffset; 311 UInt32 cycleTime; 312 313 // Add cycle offsets. 314 cycleOffset = (cycleTime1 & 0x0FFF) + (cycleTime2 & 0x0FFF); 315 316 // Add cycle counts. 317 cycleCount = (cycleTime1 & 0x01FFF000) + (cycleTime2 & 0x01FFF000); 318 319 // Add any carry over from cycle offset to cycle count. 320 if (cycleOffset > 3071) 321 { 322 cycleCount += 0x1000; 323 cycleOffset -= 3072; 324 } 325 326 // Add secondCounts. 327 secondCount = (cycleTime1 & 0xFE000000) + (cycleTime2 & 0xFE000000); 328 329 // Add any carry over from cycle count to secondCount. 330 if (cycleCount > (7999 << 12)) 331 { 332 secondCount += 0x02000000; 333 cycleCount -= (8000 << 12); 334 } 335 336 // Put everything together into cycle time. 337 cycleTime = secondCount | cycleCount | cycleOffset; 338 339 return (cycleTime); 340} 341 342UInt32 SubtractFWCycleTimeFromFWCycleTime( UInt32 cycleTime1, UInt32 cycleTime2) 343{ 344 SInt32 secondCount, 345 cycleCount, 346 cycleOffset; 347 UInt32 cycleTime; 348 349 // Subtract cycle offsets. 350 cycleOffset = (cycleTime1 & 0x0FFF) - (cycleTime2 & 0x0FFF); 351 352 // Subtract cycle counts. 353 cycleCount = (cycleTime1 & 0x01FFF000) - (cycleTime2 & 0x01FFF000); 354 355 // Subtract any borrow over from cycle offset to cycle count. 356 357 if (cycleOffset < 0) 358 { 359 cycleCount -= 0x1000; 360 cycleOffset += 3072; 361 } 362 363 // Subtract secondCounts. 364 secondCount = (cycleTime1 & 0xFE000000) - (cycleTime2 & 0xFE000000); 365 366 // Subtract any borrow over from cycle count to secondCount. 367 if (cycleCount < 0) 368 { 369 secondCount -= 0x02000000; 370 cycleCount += (8000 << 12); 371 } 372 373 // Put everything together into cycle time. 374 cycleTime = secondCount | cycleCount | cycleOffset; 375 376 return (cycleTime); 377} 378 379static UInt32 ConvertFractionalSecondsToFWCycleTime( UInt32 secondsNumerator, UInt32 secondsDenominator ) 380{ 381 // float fSecondCount; 382 // float fCycleCount; 383 // float fCycleOffset; 384 // UInt32 iSecondsCount; 385 // UInt32 iCycleCount; 386 // UInt32 iCycleOffset; 387 // UInt32 secondsCycleTime; 388 389 UInt32 iSecondsCount2; 390 UInt32 iCycleCount2; 391 UInt32 iCycleOffset2; 392 UInt32 mSecondCount; 393 UInt32 mCycleCount; 394 UInt32 secondsCycleTime2; 395 396 // Convert fractional seconds into floating point and compute seconds count. 397 // fSecondCount = ((float) secondsNumerator) / ((float) secondsDenominator); 398 // iSecondsCount = (UInt32) fSecondCount; 399 iSecondsCount2 = secondsNumerator / secondsDenominator; 400 mSecondCount = secondsNumerator % secondsDenominator; 401 402 // Subtract whole seconds out of fSecondCount and convert to cycle count. 403 // fCycleCount = (fSecondCount - ((float) iSecondsCount)) * 8000.0; 404 // iCycleCount = (UInt32) fCycleCount; 405 iCycleCount2 = (mSecondCount * 8000) / secondsDenominator; 406 mCycleCount = (mSecondCount * 8000) % secondsDenominator; 407 408 // Subtract whole cycles out of fCycleCount and convert to cycle offset. 409 // fCycleOffset = (fCycleCount - ((float) iCycleCount)) * 3072.0; 410 // iCycleOffset = (UInt32) fCycleOffset; 411 iCycleOffset2 = (mCycleCount * 3072) / secondsDenominator; 412 413 // Convert to cycle timer format. 414 // secondsCycleTime = (iSecondsCount << 25) | (iCycleCount << 12) | iCycleOffset; 415 secondsCycleTime2 = (iSecondsCount2 << 25) | (iCycleCount2 << 12) | iCycleOffset2; 416 417 return (secondsCycleTime2); 418} 419 420static IOReturn writePlug(IOFireWireAVCLibProtocolInterface **interface, UInt32 plug, UInt32 val) 421{ 422 return (*interface)->updateOutputPlug(interface, plug, 423 (*interface)->readOutputPlug(interface, plug), val); 424} 425 426static void handlePCRLock(void *refcon, UInt32 generation, UInt16 nodeID, UInt32 plug, 427 UInt32 oldVal, UInt32 newVal) 428{ 429 //syslog(LOG_INFO, "Plug %d written to, old val 0x%x new val 0x%x\n", plug, oldVal, newVal); 430} 431 432static IOReturn writeDeviceOutputMCR(IOFireWireLibDeviceRef interface, UInt32 mask, UInt32 val) 433{ 434 UInt32 oldVal, newVal; 435 UInt32 oldValHost, newValHost; 436 IOReturn err; 437 FWAddress addr; 438 io_object_t obj; 439 440 addr.nodeID = 0; 441 addr.addressHi = 0xffff; 442 addr.addressLo = 0xf0000900; 443 obj = (*interface)->GetDevice(interface); 444 err = (*interface)->ReadQuadlet(interface, obj, &addr, &oldVal, false, 0); 445 oldValHost = EndianU32_BtoN( oldVal ); 446 447 if(err == kIOReturnSuccess) { 448 if( (oldValHost & mask) != val) { 449 newValHost = (oldValHost & ~mask) | val; 450 newVal = EndianU32_NtoB( newValHost ); 451 err = (*interface)->CompareSwap(interface, obj, &addr, oldVal, newVal, false, 0); 452 } 453 } 454 return err; 455} 456 457static IOReturn MakeP2PConnectionForWrite(DVDevice *pDVDevice,UInt32 plug, UInt32 chan) 458{ 459 IOReturn err; 460 461#ifdef kIDH_Verbose_Debug_Logging 462 syslog(LOG_INFO, "DVLib: MakeP2PConnectionForWrite begin\n"); 463#endif 464 465 err = (*pDVDevice->fAVCInterface)->makeP2PInputConnection(pDVDevice->fAVCInterface, plug, chan); 466 if (err == kIOReturnSuccess) 467 { 468 pDVDevice->p2pConnected = kWriteP2PConnection; 469 pDVDevice->p2pPlug = plug; 470 pDVDevice->p2pChan = chan; 471 } 472 473#ifdef kIDH_Verbose_Debug_Logging 474 syslog(LOG_INFO, "DVLib: MakeP2PConnectionForWrite end\n"); 475#endif 476 477 return err; 478} 479 480static IOReturn BreakP2PConnectionForWrite(DVDevice *pDVDevice,UInt32 plug, UInt32 chan) 481{ 482 IOReturn err; 483 484#ifdef kIDH_Verbose_Debug_Logging 485 syslog(LOG_INFO, "DVLib: BreakP2PConnectionForWrite begin\n"); 486#endif 487 488 err = (*pDVDevice->fAVCInterface)->breakP2PInputConnection(pDVDevice->fAVCInterface, plug); 489 490 // Always clear the connected flag, even if there was an error. 491 pDVDevice->p2pConnected = kNoP2PConnection; 492 493#ifdef kIDH_Verbose_Debug_Logging 494 syslog(LOG_INFO, "DVLib: BreakP2PConnectionForWrite end\n"); 495#endif 496 497 return err; 498} 499 500static IOReturn MakeP2PConnectionForRead(DVDevice *pDVDevice,UInt32 plug, UInt32 chan) 501{ 502 IOReturn err; 503 504#ifdef kIDH_Verbose_Debug_Logging 505 syslog(LOG_INFO, "DVLib: MakeP2PConnectionForRead begin\n"); 506#endif 507 508 err = (*pDVDevice->fAVCInterface)->makeP2POutputConnection(pDVDevice->fAVCInterface, plug,chan,kFWSpeedInvalid); 509 if (err == kIOReturnSuccess) 510 { 511 pDVDevice->p2pConnected = kReadP2PConnection; 512 pDVDevice->p2pPlug = plug; 513 pDVDevice->p2pChan = chan; 514 } 515 516#ifdef kIDH_Verbose_Debug_Logging 517 syslog(LOG_INFO, "DVLib: MakeP2PConnectionForRead end\n"); 518#endif 519 520 return err; 521} 522 523static IOReturn BreakP2PConnectionForRead(DVDevice *pDVDevice,UInt32 plug, UInt32 chan) 524{ 525 IOReturn err; 526 527#ifdef kIDH_Verbose_Debug_Logging 528 syslog(LOG_INFO, "DVLib: BreakP2PConnectionForRead begin\n"); 529#endif 530 531 err = (*pDVDevice->fAVCInterface)->breakP2POutputConnection(pDVDevice->fAVCInterface, plug); 532 533 // Always clear the connected flag, even if there was an error. 534 pDVDevice->p2pConnected = kNoP2PConnection; 535 536#ifdef kIDH_Verbose_Debug_Logging 537 syslog(LOG_INFO, "DVLib: BreakP2PConnectionForRead end\n"); 538#endif 539 540 return err; 541} 542 543void AVCUnitMessageCallback(void * refCon, UInt32 type, void * arg ) 544{ 545 DVDevice *pDVDevice = (DVDevice*) refCon; 546 547#ifdef kIDH_Verbose_Debug_Logging 548 syslog(LOG_INFO, "DVLib: AVCUnitMessageCallback begin, type = 0x%08X\n",type); 549#endif 550 551 // If this is a bus-reset notification, see if we have a p2p connection. 552 // If so, restore the P2P connection, do on real time thread for safety. 553 // Done by kernel now. 554 // Callback the client's message notification handler 555 if (pDVDevice->fThread->fDeviceMessage != NULL) 556 pDVDevice->fThread->fDeviceMessage((void*)pDVDevice->deviceIndex,type,arg); 557 558#ifdef kIDH_Verbose_Debug_Logging 559 syslog(LOG_INFO, "DVLib: AVCUnitMessageCallback end\n"); 560#endif 561 562 return; 563} 564 565static IOReturn getSignalMode(IOFireWireAVCLibUnitInterface **avc, UInt8 *mode) 566{ 567 UInt32 size; 568 UInt8 cmd[4],response[4]; 569 IOReturn res; 570 571#ifdef kIDH_Verbose_Debug_Logging 572 syslog(LOG_INFO, "DVLib: getSignalMode begin\n"); 573#endif 574 575 // build query Output Signal Mode command 576 cmd[0] = kAVCStatusInquiryCommand; 577 cmd[1] = IOAVCAddress(kAVCTapeRecorder, 0); 578 cmd[2] = kAVCOutputSignalModeOpcode; 579 cmd[3] = kAVCSignalModeDummyOperand; 580 size = 4; 581 res = (*avc)->AVCCommand(avc, cmd, 4, response, &size); 582 if(res == kIOReturnSuccess) { 583 *mode = response[3]; 584 } 585 586#ifdef kIDH_Verbose_Debug_Logging 587 syslog(LOG_INFO, "DVLib: getSignalMode end\n"); 588#endif 589 590 return res; 591} 592 593static bool isDVCPro(IOFireWireAVCLibUnitInterface **avc, UInt8 *pMode) 594{ 595 UInt32 size; 596 UInt8 cmd[10],response[10]; 597 IOReturn res; 598 599#ifdef kIDH_Verbose_Debug_Logging 600 syslog(LOG_INFO, "DVLib: isDVCPro begin\n"); 601#endif 602 603 // build query vender-dependent command (is DVCPro?). 604 cmd[0] = kAVCStatusInquiryCommand; 605 cmd[1] = kAVCUnitAddress; 606 cmd[2] = kAVCVendorDependentOpcode; 607 cmd[3] = 0; 608 cmd[4] = 0x80; 609 cmd[5] = 0x45; 610 cmd[6] = 0x82; 611 cmd[7] = 0x48; 612 cmd[8] = 0xff; 613 cmd[9] = 0xff; 614 size = 10; 615 res = (*avc)->AVCCommand(avc, cmd, 10, response, &size); 616 617 // If it is DVCPro50, see if its 25 or 50 618 if ((res == kIOReturnSuccess) && (response[0] == kAVCImplementedStatus)) 619 { 620 cmd[0] = kAVCStatusInquiryCommand; 621 cmd[1] = kAVCUnitAddress; 622 cmd[2] = kAVCOutputPlugSignalFormatOpcode; 623 cmd[3] = 0; 624 cmd[4] = 0xFF; 625 cmd[5] = 0xFF; 626 cmd[6] = 0xFF; 627 cmd[7] = 0xFF; 628 size = 8; 629 630 res = (*avc)->AVCCommand(avc, cmd, 8, response, &size); 631 632 if (res == kIOReturnSuccess && response[0] == kAVCImplementedStatus) 633 *pMode = response[5]; 634 else 635 *pMode = 0x00; 636 637#ifdef kIDH_Verbose_Debug_Logging 638 syslog(LOG_INFO, "DVLib: isDVCPro end:true\n"); 639#endif 640 641 return true; 642 } 643 else 644 { 645 646#ifdef kIDH_Verbose_Debug_Logging 647 syslog(LOG_INFO, "DVLib: isDVCPro end:false\n"); 648#endif 649 return false; 650 } 651} 652 653static bool isSDL(IOFireWireAVCLibUnitInterface **avc, UInt8 signalMode) 654{ 655 // Try setting input mode to SDL 656 IOReturn res; 657 bool hasSDL; 658 659 UInt32 size; 660 UInt8 cmd[4],response[4]; 661 662#ifdef kIDH_Verbose_Debug_Logging 663 syslog(LOG_INFO, "DVLib: isSDL begin\n"); 664#endif 665 666 cmd[0] = kAVCControlCommand; 667 cmd[1] = IOAVCAddress(kAVCTapeRecorder, 0); 668 cmd[2] = kAVCInputSignalModeOpcode; 669 cmd[3] = (signalMode & ~kAVCSignalModeMask_STYPE) | kAVCSignalModeMask_SDL; 670 size = 4; 671 res = (*avc)->AVCCommand(avc, cmd, 4, response, &size); 672 if(res != kIOReturnSuccess || response[0] != kAVCAcceptedStatus) 673 { 674#ifdef kIDH_Verbose_Debug_Logging 675 syslog(LOG_INFO, "DVLib: isSDL end:false\n"); 676#endif 677 return false; // Failed to set to SDL 678 } 679 680 cmd[0] = kAVCStatusInquiryCommand; 681 cmd[1] = IOAVCAddress(kAVCTapeRecorder, 0); 682 cmd[2] = kAVCInputSignalModeOpcode; 683 cmd[3] = kAVCSignalModeDummyOperand; 684 size = 4; 685 res = (*avc)->AVCCommand(avc, cmd, 4, response, &size); 686 hasSDL = (response[3] & kAVCSignalModeMask_STYPE) == kAVCSignalModeMask_SDL; 687 688 // Set back to original value 689 cmd[0] = kAVCControlCommand; 690 cmd[1] = IOAVCAddress(kAVCTapeRecorder, 0); 691 cmd[2] = kAVCInputSignalModeOpcode; 692 cmd[3] = signalMode; 693 size = 4; 694 res = (*avc)->AVCCommand(avc, cmd, 4, response, &size); 695 696#ifdef kIDH_Verbose_Debug_Logging 697 syslog(LOG_INFO, "DVLib: isSDL end:%s\n",(hasSDL==true ? "true" : "false")); 698#endif 699 700 return hasSDL; 701} 702 703static bool isMPEG(IOFireWireAVCLibUnitInterface **avc) 704{ 705 UInt32 size; 706 UInt8 cmd[8],response[8]; 707 IOReturn res; 708 709 cmd[0] = kAVCStatusInquiryCommand; 710 cmd[1] = kAVCUnitAddress; 711 cmd[2] = kAVCOutputPlugSignalFormatOpcode; 712 cmd[3] = 0; 713 cmd[4] = 0xFF; 714 cmd[5] = 0xFF; 715 cmd[6] = 0xFF; 716 cmd[7] = 0xFF; 717 size = 8; 718 719 res = (*avc)->AVCCommand(avc, cmd, 8, response, &size); 720 721 if ((res == kIOReturnSuccess) && 722 (response[0] == kAVCImplementedStatus) && 723 (response[4] == 0xA0)) 724 return true; 725 else 726 return false; 727} 728 729static void deviceArrived(void *refcon, io_iterator_t iterator ) 730{ 731 io_object_t obj; 732 DVThread * dvThread = (DVThread *)refcon; 733 UInt8 dvcProMode; 734 735#ifdef kIDH_Verbose_Debug_Logging 736 syslog(LOG_INFO, "DVLib: deviceArrived begin\n"); 737#endif 738 739 //syslog(LOG_INFO,"deviceArrived(0x%x, 0x%x)\n", refcon, iterator); 740 while(obj = IOIteratorNext(iterator)) { 741 CFMutableDictionaryRef properties; 742 CFNumberRef dataDesc; 743 CFStringRef strDesc; 744 kern_return_t err; 745 UInt64 GUID; 746 int refound = 0; 747 int device; 748 DVDevice *dev = NULL; 749 750 //syslog(LOG_INFO, "object 0x%x arrived!\n", obj); 751 err = IORegistryEntryCreateCFProperties(obj, &properties, kCFAllocatorDefault, kNilOptions); 752 753 dataDesc = (CFNumberRef)CFDictionaryGetValue(properties, CFSTR("GUID")); 754 CFNumberGetValue(dataDesc, kCFNumberSInt64Type, &GUID); 755 for(device=0; device<dvThread->fNumDevices; device++) { 756 if(GUID == dvThread->fDevices[device].fGUID) { 757 refound = 1; 758 dev = &dvThread->fDevices[device]; 759 break; 760 } 761 } 762 if(!refound) { 763 CFBooleanRef hasFCP; 764 device = dvThread->fNumDevices; 765 dvThread->fNumDevices++; 766 dev = &dvThread->fDevices[device]; 767 strDesc = (CFStringRef)CFDictionaryGetValue(properties, CFSTR("FireWire Product Name")); 768 if(strDesc) { 769 dev->fName[0] = 0; 770 CFStringGetCString(strDesc, dev->fName, sizeof(dev->fName), kCFStringEncodingMacRoman); 771 } 772 hasFCP = (CFBooleanRef)CFDictionaryGetValue(properties, CFSTR("supportsFCP")); 773 dev->fSupportsFCP = true; 774 if(hasFCP) 775 dev->fSupportsFCP = CFBooleanGetValue(hasFCP); 776 777 dev->fGUID = GUID; 778 dev->fMaxSpeed = kFWSpeed100MBit; 779 dev->fWriteChan = kWriteChannel; 780 dev->fReadChan = kReadChannel; 781 } 782 CFRelease(properties); 783 784 dev->fObject = obj; 785 dev->fThread = dvThread; 786 787 // Request notification of messages via AVC user client 788 err = openAVCUnit(dev->fObject, &dev->fAVCInterface, dvThread); 789 if(err == kIOReturnSuccess) 790 { 791 UInt8 mode, stype; 792 793 // Exclude DVCProHD and MPEG devices from the IDH device list! 794 if (dev->fSupportsFCP) 795 { 796 if(isDVCPro(dev->fAVCInterface,&dvcProMode)) 797 { 798 if ((dvcProMode == kAVCSignalModeDVCPro100_525_60) || (dvcProMode == kAVCSignalModeDVCPro100_625_50)) 799 { 800 // Terminate this device 801 DVDeviceTerminate(dev); 802 803 // Remove this device from the device list 804 dvThread->fNumDevices--; 805 806 continue; // continue to next device! 807 } 808 } 809 else if (isMPEG(dev->fAVCInterface)) 810 { 811 // Terminate this device 812 DVDeviceTerminate(dev); 813 814 // Remove this device from the device list 815 dvThread->fNumDevices--; 816 817 continue; // continue to next device! 818 } 819 } 820 821 dev->deviceIndex = device+1; 822 (*dev->fAVCInterface)->setMessageCallback(dev->fAVCInterface, (void *) dev, AVCUnitMessageCallback); 823 824 // Determine mode(s) supported 825 if(dev->fSupportsFCP) 826 { 827 err = getSignalMode(dev->fAVCInterface, &mode); 828 if(err == kIOReturnSuccess) 829 { 830 if(mode & kAVCSignalModeMask_50) 831 dev->standard = palIn; 832 else 833 dev->standard = ntscIn; 834 835 // See if DVCPro25 type device 836 stype = mode & kAVCSignalModeMask_STYPE; 837 if(stype == kAVCSignalModeMask_DVCPro25) 838 { 839 dev->fDVFormats |= 1 << kIDHDVCPro_25; 840 } 841 else if(stype == kAVCSignalModeMask_DVCPro50) 842 { 843 dev->fDVFormats |= 1 << kIDHDVCPro_50; 844 dev->fMaxSpeed = kFWSpeed400MBit; // Default to 400 for DVCPro-50 845 } 846 else 847 { 848 // Ask device via vender-dependent command if it's a DVCPro device. 849 if(isDVCPro(dev->fAVCInterface,&dvcProMode)) 850 { 851 if((dvcProMode & kAVCSignalModeMask_STYPE) == kAVCSignalModeMask_DVCPro50) 852 { 853 dev->fDVFormats |= 1 << kIDHDVCPro_50; 854 dev->fMaxSpeed = kFWSpeed400MBit; // Default to 400 for DVCPro-50 855 } 856 else 857 dev->fDVFormats |= 1 << kIDHDVCPro_25; 858 } 859 } 860 861 // See if SDL type device 862 if(stype == kAVCSignalModeMask_SDL) 863 dev->fDVFormats |= 1 << kIDHDV_SDL; 864 else 865 { 866 // Ask camera if it's SDL. 867 if(isSDL(dev->fAVCInterface, mode)) 868 dev->fDVFormats |= 1 << kIDHDV_SDL; 869 } 870 } 871 else 872 { 873 // Failed the signal mode command. Assume standard NTSC DV 874 dev->fDVFormats = 1 << kIDHDV_SD; // Standard DV 875 dev->standard = ntscIn; 876 } 877 } 878 else 879 { 880 // Assume NTSC, standard DV if device doesn't support AVC. 881 dev->fDVFormats = 1 << kIDHDV_SD; // Standard DV 882 dev->standard = ntscIn; // device standard - NTSC/PAL 883 } 884 885 // Notify client 886 (dvThread->fAddedFunc)(dvThread->fAddedRefCon, dev, device+1, refound); 887 } 888 } 889 890#ifdef kIDH_Verbose_Debug_Logging 891 syslog(LOG_INFO, "DVLib: deviceArrived end\n"); 892#endif 893 894} 895 896static OSStatus DVthreadExit(DVThread *dvThread, UInt32 params) 897{ 898 899#ifdef kIDH_Verbose_Debug_Logging 900 syslog(LOG_INFO, "DVLib: DVthreadExit begin\n"); 901#endif 902 903 if(dvThread->fNotifySource) 904 CFRunLoopSourceInvalidate(dvThread->fNotifySource); 905 906 if(dvThread->fPowerNotifySource) 907 CFRunLoopSourceInvalidate(dvThread->fPowerNotifySource); 908 909 // we have to do this because CF sometimes adds it's own source to our run loop (?!) 910 // which we don't (can't?) invalidate 911 // this makes sure our thread will really exit.. 912 CFRunLoopStop(dvThread->fWorkLoop) ; 913 dvThread->fTimerFunc = NULL; 914 915#ifdef kIDH_Verbose_Debug_Logging 916 syslog(LOG_INFO, "DVLib: DVthreadExit end\n"); 917#endif 918 919 return noErr; 920} 921 922static void *DVRTThreadStart(DVThread *dvThread) 923{ 924 925#if REGISTER_THREADS_WITH_GC 926 if (CF_USING_COLLECTABLE_MEMORY) 927 { 928 void *dlhandle = dlopen("/usr/lib/libobjc.dylib", RTLD_LAZY | RTLD_LOCAL); 929 if( dlhandle != NULL ) { 930 ObjCRegisterThreadWithCollectorPtr objcRegisterThreadWithCollector = dlsym( dlhandle, "objc_registerThreadWithCollector" ); 931 if( objcRegisterThreadWithCollector != NULL ) 932 objcRegisterThreadWithCollector(); 933 else syslog(LOG_INFO, "dlsym(objc_registerThreadWithCollector) failed"); 934 dlclose( dlhandle ); 935 } 936 else syslog(LOG_INFO, "dlopen(/usr/lib/libobjc.dylib) failed"); 937 } 938#endif // REGISTER_THREADS_WITH_GC 939 940 ReceiveMsg msg; 941 kern_return_t err; 942 int delay; 943 int run = true; 944 int i; 945 946#ifdef kIDH_Verbose_Debug_Logging 947 syslog(LOG_INFO, "DVLib: DVRTThreadStart begin\n"); 948#endif 949 950 deviceArrived(dvThread, dvThread->fMatchEnumer); 951 // signal that we're about to start the mach loop 952 DVSignalSync(&dvThread->fRequestSyncer, &dvThread->fSyncRequest, 1); 953 954 delay = 12; // DCL block size 955 while(run) { 956 int nextTick; 957#if TIMING 958 CFAbsoluteTime start; 959 start = CFAbsoluteTimeGetCurrent(); 960#endif 961 err = mach_msg(&msg.msgHdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 962 //err = mach_msg(&msg.msgHdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_LARGE, 963 0, sizeof(msg), dvThread->fRequestMachPort, delay, MACH_PORT_NULL); 964 965#if TIMING 966 DVLog(dvThread, 'mmsg', start, CFAbsoluteTimeGetCurrent()); 967#endif 968 if(err == MACH_MSG_SUCCESS) { 969 switch (msg.msgHdr.msgh_id) { 970 case kDVRequestID: 971 dvThread->fRequestResult = (dvThread->fRequestFunc)(dvThread->fRequestArg, dvThread->fRequestParam); 972 if(dvThread->fRequestFunc == DVthreadExit) 973 run = false; 974 DVSignalSync(&dvThread->fRequestSyncer, &dvThread->fSyncRequest, (UInt32)dvThread->fRequestFunc); 975 } 976 } 977 for(i=0; i<kDVMaxStreamsActive; i++) { 978 if(dvThread->fInStreams[i]) 979 DVReadPoll(dvThread->fInStreams[i]); 980 if(dvThread->fOutStreams[i]) 981 DVWritePoll(dvThread->fOutStreams[i]); 982 } 983 if(dvThread->fTimerFunc) { 984 dvThread->fTimerFunc(NULL, dvThread->fTimerRefCon); 985 delay = 12; // DCL block size in milliseconds 986 nextTick = (int)((dvThread->requestTimeoutTime-CFAbsoluteTimeGetCurrent())*1000.0); 987 if(nextTick <= 0) 988 nextTick = 1; 989 if(nextTick < delay) 990 delay = nextTick; 991 } 992 993 } 994 995#ifdef kIDH_Verbose_Debug_Logging 996 syslog(LOG_INFO, "DVLib: DVRTThreadStart end\n"); 997#endif 998 999 return NULL; 1000} 1001 1002static void *DVRLThreadStart(DVThread *thread) 1003{ 1004#if REGISTER_THREADS_WITH_GC 1005 if (CF_USING_COLLECTABLE_MEMORY) 1006 { 1007 void *dlhandle = dlopen("/usr/lib/libobjc.dylib", RTLD_LAZY | RTLD_LOCAL); 1008 if( dlhandle != NULL ) { 1009 ObjCRegisterThreadWithCollectorPtr objcRegisterThreadWithCollector = dlsym( dlhandle, "objc_registerThreadWithCollector" ); 1010 if( objcRegisterThreadWithCollector != NULL ) 1011 objcRegisterThreadWithCollector(); 1012 else syslog(LOG_INFO, "dlsym(objc_registerThreadWithCollector) failed"); 1013 dlclose( dlhandle ); 1014 } 1015 else syslog(LOG_INFO, "dlopen(/usr/lib/libobjc.dylib) failed"); 1016 } 1017#endif // REGISTER_THREADS_WITH_GC 1018 1019 CFRunLoopRef loop; 1020 //syslog(LOG_INFO, "Starting thread: %p\n", thread); 1021 1022#ifdef kIDH_Verbose_Debug_Logging 1023 syslog(LOG_INFO, "DVLib: DVRLThreadStart begin\n"); 1024#endif 1025 1026 loop = CFRunLoopGetCurrent(); 1027 //printf("Starting thread: %p, loop %p, notify retain %d, notify %p ioport %p, info %x\n", 1028 // thread, loop, retain, thread->fNotifySource, thread->fNotifyPort, *((UInt32 *)thread->fNotifySource + 1)); 1029 if(thread->fNotifySource) 1030 CFRunLoopAddSource(loop, thread->fNotifySource, kCFRunLoopDefaultMode); 1031 1032 if(thread->fPowerNotifySource) 1033 CFRunLoopAddSource(loop, thread->fPowerNotifySource, kCFRunLoopDefaultMode); 1034 1035 1036 CFRetain(loop); 1037 thread->fWorkLoop = loop; 1038 1039 thread->fRunLoopIsRunning = true; 1040 1041 // signal that we're about to start the runloop 1042 DVSignalSync(&thread->fRequestSyncer, &thread->fSyncRequest, 1); 1043 1044 CFRunLoopRun(); 1045 1046 thread->fRunLoopIsRunning = false; 1047 1048 //printf("Exiting thread: %p, loop %p\n", thread, loop); 1049 1050#ifdef kIDH_Verbose_Debug_Logging 1051 syslog(LOG_INFO, "DVLib: DVRLThreadStart end\n"); 1052#endif 1053 1054 return NULL; 1055} 1056 1057void 1058PowerManagementNotificationCallback(void * refcon, 1059 io_service_t service, 1060 natural_t messageType, 1061 void * messageArgument ) 1062{ 1063 DVThread *dvThread = (DVThread*) refcon; 1064 UInt32 i; 1065 1066#ifdef kIDH_Verbose_Debug_Logging 1067 syslog(LOG_INFO, "DVLib: PowerManagementNotificationCallback begin\n"); 1068#endif 1069 1070 // If we are waking from sleep, restart any running streams 1071 if (messageType == kIOMessageSystemHasPoweredOn) 1072 { 1073 // Find all active streams, and restart them 1074 for(i=0; i<kDVMaxStreamsActive; i++) 1075 { 1076 if(dvThread->fInStreams[i]) 1077 { 1078 syslog(LOG_INFO, "DV PowerManagementNotificationCallback, Restarting input stream %d\n",i); 1079 if (dvThread->fInStreams[i]->dvReadStopInProgress == false) 1080 { 1081 dvThread->fInStreams[i]->pendingDVReadUnderrunHandler = true; 1082 DVRequest(dvThread->fInStreams[i]->fStreamVars.fThread, 1083 doDVReadHandleInputUnderrun, 1084 dvThread->fInStreams[i], 1085 0); 1086 } 1087 } 1088 1089 if(dvThread->fOutStreams[i]) 1090 { 1091 syslog(LOG_INFO, "DV PowerManagementNotificationCallback, Restarting output stream %d\n",i); 1092 if (dvThread->fOutStreams[i]->dvWriteStopInProgress == false) 1093 { 1094 dvThread->fOutStreams[i]->pendingDVWriteUnderrunHandler = true; 1095 DVRequest(dvThread->fOutStreams[i]->fStreamVars.fThread, 1096 doDVHandleOutputUnderrun, 1097 dvThread->fOutStreams[i], 1098 0); 1099 } 1100 } 1101 } 1102 } 1103 1104 // Acknowledge the message 1105 IOAllowPowerChange (dvThread->fPowerNotifyConnect, (long) messageArgument); 1106 1107#ifdef kIDH_Verbose_Debug_Logging 1108 syslog(LOG_INFO, "DVLib: PowerManagementNotificationCallback end\n"); 1109#endif 1110 1111} 1112 1113DVThread * DVCreateThread(DVDeviceArrivedFunc deviceAdded, void * addedRefCon, 1114 CFRunLoopTimerCallBack timerTick, void *timerRefCon, IOFWAVCMessageCallback deviceMessage) 1115{ 1116 UInt32 i; 1117 IOReturn err; 1118 mach_port_t masterDevicePort; 1119 DVThread *dvThread; 1120 1121 const UInt8 num = kAVCTapeRecorder; 1122 CFMutableDictionaryRef dict = 0; 1123 CFNumberRef tape; 1124 1125#ifdef kIDH_Verbose_Debug_Logging 1126 syslog(LOG_INFO, "DVLib: DVCreateThread begin\n"); 1127#endif 1128 1129 dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, 1130 &kCFTypeDictionaryKeyCallBacks, 1131 &kCFTypeDictionaryValueCallBacks); 1132 1133 if(!dict) 1134 return nil; 1135 1136 tape = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type, &num); 1137 if(!tape) 1138 return nil; 1139 1140 CFDictionarySetValue( dict, CFSTR(kIOProviderClassKey), CFSTR("IOFireWireAVCSubUnit") ); 1141 CFDictionarySetValue( dict, CFSTR("SubUnit_Type"), tape); 1142 CFRelease(tape); 1143 1144 if ((err = IOMasterPort(bootstrap_port, &masterDevicePort)) != KERN_SUCCESS) { 1145 1146#ifdef kIDH_Verbose_Debug_Logging 1147 syslog(LOG_INFO, "DVLib: DVCreateThread end:failed to get master port\n"); 1148#endif 1149 return NULL; 1150 } 1151 1152 dvThread = malloc(sizeof(DVThread)); 1153 bzero(dvThread, sizeof(DVThread)); 1154 for(i = 0 ; i < kDVMaxDevicesActive ; i++){ 1155 dvThread->fDevices[i].fOutPlug = kNoPlug; 1156 } 1157 pthread_mutex_init(&dvThread->fRequestSyncer.fMutex, NULL); 1158 pthread_cond_init(&dvThread->fRequestSyncer.fSyncCond, NULL); 1159 pthread_mutex_init(&dvThread->fRequestMutex, NULL); 1160 1161 dvThread->fNotifyPort = IONotificationPortCreate(masterDevicePort); 1162 dvThread->fNotifySource = IONotificationPortGetRunLoopSource(dvThread->fNotifyPort); 1163 1164 err = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &dvThread->fRequestMachPort); 1165 err = mach_port_insert_right(mach_task_self(), dvThread->fRequestMachPort, dvThread->fRequestMachPort, 1166 MACH_MSG_TYPE_MAKE_SEND); 1167 1168 if(timerTick) { 1169 dvThread->fTimerFunc = timerTick; 1170 dvThread->fTimerRefCon = timerRefCon; 1171 } 1172 1173 dvThread->fAddedRefCon = addedRefCon; 1174 dvThread->fAddedFunc = deviceAdded; 1175 dvThread->fDeviceMessage = deviceMessage; 1176 1177 err = IOServiceAddMatchingNotification( dvThread->fNotifyPort, 1178 kIOMatchedNotification, dict, 1179 deviceArrived, dvThread, &dvThread->fMatchEnumer ); 1180 1181 // Register for system power notifications 1182 dvThread->fPowerNotifyConnect = IORegisterForSystemPower ( dvThread, 1183 &dvThread->fPowerNotifyPort, 1184 PowerManagementNotificationCallback, 1185 &dvThread->fPowerManagementNotifier); 1186 dvThread->fPowerNotifySource = IONotificationPortGetRunLoopSource(dvThread->fPowerNotifyPort); 1187 1188#ifdef kIDH_Verbose_Debug_Logging 1189 syslog(LOG_INFO, "DVLib: DVCreateThread end\n"); 1190#endif 1191 1192 return dvThread; 1193} 1194 1195static void setThreadPriority(pthread_t thread) 1196{ 1197 double mult; 1198 thread_time_constraint_policy_data_t constraints; 1199 kern_return_t result; 1200 1201#ifdef kIDH_Verbose_Debug_Logging 1202 syslog(LOG_INFO, "DVLib: setThreadPriority begin\n"); 1203#endif 1204 1205 // use mach_timebase_info to get abs to ns conversion parameters 1206 mach_timebase_info_data_t tTBI; 1207 mach_timebase_info(&tTBI); 1208 1209 // Set thread to Real Time 1210 mult = ((double)tTBI.denom / (double)tTBI.numer) * 1000000; 1211 constraints.period = 12*mult; 1212 constraints.computation = 2*mult; 1213 constraints.constraint = 24*mult; 1214 constraints.preemptible = TRUE; 1215 result = thread_policy_set(pthread_mach_thread_np(thread), THREAD_TIME_CONSTRAINT_POLICY, 1216 (thread_policy_t)&constraints, THREAD_TIME_CONSTRAINT_POLICY_COUNT); 1217 1218#ifdef kIDH_Verbose_Debug_Logging 1219 syslog(LOG_INFO, "DVLib: setThreadPriority end\n"); 1220#endif 1221 1222} 1223 1224void DVSetTimeoutTime(DVThread * dvThread, CFAbsoluteTime fireDate) 1225{ 1226 dvThread->setTimeoutTime = CFAbsoluteTimeGetCurrent(); 1227 dvThread->requestTimeoutTime = fireDate; 1228} 1229 1230void DVRunThread(DVThread * dvThread) 1231{ 1232 pthread_attr_t threadAttr; // Attributes of work thread 1233 pthread_t thread; 1234 1235#ifdef kIDH_Verbose_Debug_Logging 1236 syslog(LOG_INFO, "DVLib: DVRunThread begin\n"); 1237#endif 1238 1239 // Start each thread, wait for first to start before setting up second. 1240 dvThread->fSyncRequest = 0; 1241 pthread_attr_init(&threadAttr); 1242 //pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED); 1243 pthread_create(&thread, &threadAttr, DVRLThreadStart, dvThread); 1244 dvThread->fRLThread = thread; 1245 DVWaitSync(&dvThread->fRequestSyncer, &dvThread->fSyncRequest); 1246 1247 dvThread->fSyncRequest = 0; 1248 pthread_create(&thread, &threadAttr, DVRTThreadStart, dvThread); 1249 dvThread->fRTThread = thread; 1250 setThreadPriority(thread); 1251 DVWaitSync(&dvThread->fRequestSyncer, &dvThread->fSyncRequest); 1252 1253#ifdef kIDH_Verbose_Debug_Logging 1254 syslog(LOG_INFO, "DVLib: DVRunThread end\n"); 1255#endif 1256 1257} 1258 1259void DVFreeThread(DVThread * dvThread) 1260{ 1261 1262#ifdef kIDH_Verbose_Debug_Logging 1263 syslog(LOG_INFO, "DVLib: DVFreeThread begin\n"); 1264#endif 1265 1266 DVRequest(dvThread, DVthreadExit, dvThread, 0); 1267 pthread_join(dvThread->fRTThread, NULL); 1268 pthread_join(dvThread->fRLThread, NULL); 1269 1270 //printf("Workloop retain %d\n", CFGetRetainCount(dvThread->fWorkLoop)); 1271 CFRelease(dvThread->fWorkLoop); 1272 1273 //CFRunLoopRemoveSource(dvThread->fWorkLoop, dvThread->fNotifySource, kCFRunLoopDefaultMode); 1274 //CFRunLoopRemoveSource(dvThread->fWorkLoop, dvThread->fRequestSource, kCFRunLoopDefaultMode); 1275 //printf("after thread exit, notify , request retains are %d, %d\n", 1276 // CFGetRetainCount(dvThread->fNotifySource), CFGetRetainCount(dvThread->fRequestSource)); 1277 if(dvThread->fMatchEnumer) 1278 IOObjectRelease(dvThread->fMatchEnumer); 1279 if(dvThread->fNotifyPort) { 1280 CFMachPortRef hack; 1281 CFMachPortContext context; 1282 Boolean shouldFreeInfo; 1283 1284 context.version = 1; 1285 context.info = (void *) dvThread->fNotifyPort; 1286 context.retain = NULL; 1287 context.release = NULL; 1288 context.copyDescription = NULL; 1289 1290 1291 hack = CFMachPortCreateWithPort(NULL, IONotificationPortGetMachPort(dvThread->fNotifyPort), 1292 NULL, &context, &shouldFreeInfo); 1293 CFMachPortInvalidate(hack); 1294 IONotificationPortDestroy(dvThread->fNotifyPort); 1295 //printf("hack port retain %d\n", CFGetRetainCount(hack)); 1296 CFRelease(hack); 1297 1298 1299 } 1300 1301 if(dvThread->fPowerNotifyPort) { 1302 CFMachPortRef hack; 1303 CFMachPortContext context; 1304 Boolean shouldFreeInfo; 1305 1306 context.version = 1; 1307 context.info = (void *) dvThread->fPowerNotifyPort; 1308 context.retain = NULL; 1309 context.release = NULL; 1310 context.copyDescription = NULL; 1311 1312 1313 hack = CFMachPortCreateWithPort(NULL, IONotificationPortGetMachPort(dvThread->fPowerNotifyPort), 1314 NULL, &context, &shouldFreeInfo); 1315 printf( "DVFreeThread - CFMachPortCreateWithPort hack = %p, fPowerNotifyPort= %p\n", hack, dvThread->fPowerNotifyPort ); 1316 1317 CFMachPortInvalidate(hack); 1318 IONotificationPortDestroy(dvThread->fPowerNotifyPort); 1319 //printf("hack port retain %d\n", CFGetRetainCount(hack)); 1320 CFRelease(hack); 1321 1322 1323 } 1324 1325 //IONotificationPortDestroy(dvThread->fPowerNotifyPort); 1326 1327 mach_port_destroy(mach_task_self(), dvThread->fRequestMachPort); 1328 1329 //printf("after IONotificationPortDestroy, notify retain is %d\n", CFGetRetainCount(dvThread->fNotifySource)); 1330 1331 pthread_mutex_destroy(&dvThread->fRequestSyncer.fMutex); 1332 pthread_cond_destroy(&dvThread->fRequestSyncer.fSyncCond); 1333 pthread_mutex_destroy(&dvThread->fRequestMutex); 1334 1335 IODeregisterForSystemPower(&dvThread->fPowerManagementNotifier); 1336 IOServiceClose(dvThread->fPowerNotifyConnect); 1337 memset(dvThread, 0xde, sizeof(DVThread)); 1338 free(dvThread); 1339 1340#ifdef kIDH_Verbose_Debug_Logging 1341 syslog(LOG_INFO, "DVLib: DVFreeThread end\n"); 1342#endif 1343 1344} 1345 1346void DVSignalSync(ThreadSyncer *sync, UInt32 *var, UInt32 val) 1347{ 1348#ifdef kIDH_Verbose_Debug_Logging 1349 syslog(LOG_INFO, "DVLib: DVSignalSync begin\n"); 1350#endif 1351 1352 pthread_mutex_lock(&sync->fMutex); 1353 *var = val; 1354 pthread_mutex_unlock(&sync->fMutex); 1355 pthread_cond_broadcast(&sync->fSyncCond); 1356 1357#ifdef kIDH_Verbose_Debug_Logging 1358 syslog(LOG_INFO, "DVLib: DVSignalSync end\n"); 1359#endif 1360} 1361 1362void DVWaitSync(ThreadSyncer *sync, UInt32 *var) 1363{ 1364 1365#ifdef kIDH_Verbose_Debug_Logging 1366 syslog(LOG_INFO, "DVLib: DVWaitSync begin\n"); 1367#endif 1368 1369 //if(!*var) 1370 { 1371 pthread_mutex_lock(&sync->fMutex); 1372 while(!*var) { 1373 pthread_cond_wait(&sync->fSyncCond, &sync->fMutex); 1374 } 1375 pthread_mutex_unlock(&sync->fMutex); 1376 } 1377 1378#ifdef kIDH_Verbose_Debug_Logging 1379 syslog(LOG_INFO, "DVLib: DVWaitSync end\n"); 1380#endif 1381 1382} 1383 1384void DVLock(ThreadSyncer *sync) 1385{ 1386 1387#ifdef kIDH_Verbose_Debug_Logging 1388 syslog(LOG_INFO, "DVLib: DVLock begin\n"); 1389#endif 1390 1391 pthread_mutex_lock(&sync->fMutex); 1392 1393#ifdef kIDH_Verbose_Debug_Logging 1394 syslog(LOG_INFO, "DVLib: DVLock end\n"); 1395#endif 1396} 1397 1398void DVUnlock(ThreadSyncer *sync) 1399{ 1400 1401#ifdef kIDH_Verbose_Debug_Logging 1402 syslog(LOG_INFO, "DVLib: DVUnlock begin\n"); 1403#endif 1404 1405 pthread_mutex_unlock(&sync->fMutex); 1406 1407#ifdef kIDH_Verbose_Debug_Logging 1408 syslog(LOG_INFO, "DVLib: DVUnlock end\n"); 1409#endif 1410} 1411 1412static IOReturn isochPortGetSupported( 1413 IOFireWireLibIsochPortRef interface, 1414 IOFWSpeed* outMaxSpeed, 1415 UInt64* outChanSupported) 1416{ 1417 DVStream *stream; 1418 1419#ifdef kIDH_Verbose_Debug_Logging 1420 syslog(LOG_INFO, "DVLib: isochPortGetSupported begin\n"); 1421#endif 1422 1423 stream = (DVStream *)((*interface)->GetRefCon(interface)); 1424 1425 if(*outMaxSpeed > stream->fMaxSpeed) 1426 *outMaxSpeed = stream->fMaxSpeed; 1427 *outChanSupported = stream->fChannelMask; 1428 1429#ifdef kIDH_Verbose_Debug_Logging 1430 syslog(LOG_INFO, "DVLib: isochPortGetSupported end\n"); 1431#endif 1432 1433 return kIOReturnSuccess; 1434} 1435 1436static IOReturn isochPortAllocate( 1437 IOFireWireLibIsochPortRef interface, 1438 IOFWSpeed maxSpeed, 1439 UInt32 channel) 1440{ 1441 DVStream *stream; 1442 1443#ifdef kIDH_Verbose_Debug_Logging 1444 syslog(LOG_INFO, "DVLib: isochPortAllocate begin\n"); 1445#endif 1446 1447 stream = (DVStream *)((*interface)->GetRefCon(interface)); 1448 //printf("using channel %d\n", channel); 1449 stream->fIsocChannel = channel; 1450 1451#ifdef kIDH_Verbose_Debug_Logging 1452 syslog(LOG_INFO, "DVLib: isochPortAllocate end\n"); 1453#endif 1454 1455 return kIOReturnSuccess; 1456} 1457 1458IOReturn openFireWireUnit(IOFireWireAVCLibUnitInterface **avcInterface, IOFireWireSessionRef session, IOFireWireLibDeviceRef *retInterface, DVThread *thread) 1459{ 1460 IOFireWireLibDeviceRef resultInterface; 1461 IOReturn err = kIOReturnNoMemory; 1462 int opened = false; 1463 1464#ifdef kIDH_Verbose_Debug_Logging 1465 syslog(LOG_INFO, "DVLib: openFireWireUnit begin\n"); 1466#endif 1467 1468 do { 1469 resultInterface = (*avcInterface)->getAncestorInterface(avcInterface, "IOFireWireUnit", 1470 CFUUIDGetUUIDBytes(kIOFireWireLibTypeID), CFUUIDGetUUIDBytes(kIOFireWireUnitInterfaceID_v3)); 1471 if(!resultInterface) 1472 break; 1473 1474 if(session) 1475 err = (*resultInterface)->OpenWithSessionRef(resultInterface, session); 1476 else 1477 err = (*resultInterface)->Open(resultInterface); 1478 if(err) 1479 break; 1480 opened = true; 1481 //err = (*resultInterface)->AddCallbackDispatcherToRunLoop(resultInterface, workLoop ); 1482 err = (*resultInterface)->AddIsochCallbackDispatcherToRunLoop(resultInterface, thread->fWorkLoop); 1483 } while (false); 1484 1485 if(!err) 1486 *retInterface = resultInterface; 1487 else { 1488 if(opened) 1489 (*resultInterface)->Close(resultInterface); 1490 if(resultInterface) 1491 (*resultInterface)->Release(resultInterface); 1492 } 1493 1494#ifdef kIDH_Verbose_Debug_Logging 1495 syslog(LOG_INFO, "DVLib: openFireWireUnit end\n"); 1496#endif 1497 1498 return err; 1499} 1500 1501IOReturn openAVCUnit(io_object_t obj, IOFireWireAVCLibUnitInterface ***retInterface, DVThread *thread) 1502{ 1503 IOCFPlugInInterface** theCFPlugInInterface; 1504 IOFireWireAVCLibUnitInterface **resultInterface = 0 ; 1505 SInt32 theScore ; 1506 IOReturn err; 1507 1508#ifdef kIDH_Verbose_Debug_Logging 1509 syslog(LOG_INFO, "DVLib: openAVCUnit begin\n"); 1510#endif 1511 1512 err = IOCreatePlugInInterfaceForService( 1513 obj, 1514 kIOFireWireAVCLibUnitTypeID, 1515 kIOCFPlugInInterfaceID, //interfaceType, 1516 & theCFPlugInInterface, 1517 & theScore); 1518 if (!err) { 1519 HRESULT comErr; 1520 comErr = (*theCFPlugInInterface)->QueryInterface( 1521 theCFPlugInInterface, 1522 CFUUIDGetUUIDBytes(kIOFireWireAVCLibUnitInterfaceID), 1523 (void**) & resultInterface); 1524 if (comErr == S_OK) { 1525 err = (*resultInterface)->addCallbackDispatcherToRunLoop(resultInterface, thread->fWorkLoop ); 1526 } 1527 else 1528 err = comErr; 1529 (*theCFPlugInInterface)->Release(theCFPlugInInterface); // Leave just one reference. 1530 } 1531 1532 if(!err) 1533 *retInterface = resultInterface; 1534 1535#ifdef kIDH_Verbose_Debug_Logging 1536 syslog(LOG_INFO, "DVLib: openAVCUnit end\n"); 1537#endif 1538 1539 return err; 1540} 1541 1542IOReturn openAVCProto(IOFireWireAVCLibUnitInterface **avcInterface, IOFireWireAVCLibProtocolInterface ***retInterface, DVThread *thread) 1543{ 1544 IOFireWireAVCLibProtocolInterface **resultInterface; 1545 IOReturn err = noErr; 1546 1547#ifdef kIDH_Verbose_Debug_Logging 1548 syslog(LOG_INFO, "DVLib: openAVCProto begin\n"); 1549#endif 1550 1551 do { 1552 resultInterface = (*avcInterface)->getProtocolInterface(avcInterface, 1553 CFUUIDGetUUIDBytes(kIOFireWireAVCLibProtocolTypeID), 1554 CFUUIDGetUUIDBytes(kIOFireWireAVCLibProtocolInterfaceID)); 1555 if(!resultInterface) 1556 break; 1557 err = (*resultInterface)->addCallbackDispatcherToRunLoop(resultInterface, thread->fWorkLoop); 1558 } while (false); 1559 1560 if(!err) 1561 *retInterface = resultInterface; 1562 else { 1563 if(resultInterface) 1564 (*resultInterface)->Release(resultInterface); 1565 } 1566 1567 1568#ifdef kIDH_Verbose_Debug_Logging 1569 syslog(LOG_INFO, "DVLib: openAVCProto end\n"); 1570#endif 1571 1572 return err; 1573} 1574 1575void DVDeviceTerminate(DVDevice *dev) 1576{ 1577 1578#ifdef kIDH_Verbose_Debug_Logging 1579 syslog(LOG_INFO, "DVLib: DVDeviceTerminate begin\n"); 1580#endif 1581 1582 DVDeviceClose(dev); 1583 if(dev->fAVCInterface) 1584 { 1585 // Remove runloop source for this interface 1586 (*dev->fAVCInterface)->removeCallbackDispatcherFromRunLoop(dev->fAVCInterface); 1587 1588 // Crasher Fix: If we are on a thread other than the RL thread, 1589 // we need to make sure the RL thread is idle before 1590 // releasing the AVC interface 1591 if (dev->fThread->fWorkLoop != CFRunLoopGetCurrent()) 1592 { 1593 // Endless loop here until the run-loop thread is idle 1594 while ((CFRunLoopIsWaiting(dev->fThread->fWorkLoop) == false ) && (dev->fThread->fRunLoopIsRunning == true)) 1595 usleep(1000); // sleep for a millisecond 1596 } 1597 1598 (*dev->fAVCInterface)->Release(dev->fAVCInterface); 1599 dev->fAVCInterface = NULL; 1600 } 1601 if(dev->fObject) { 1602 IOObjectRelease(dev->fObject); 1603 dev->fObject = NULL; 1604 } 1605 1606#ifdef kIDH_Verbose_Debug_Logging 1607 syslog(LOG_INFO, "DVLib: DVDeviceTerminate end\n"); 1608#endif 1609 1610} 1611 1612IOReturn DVDeviceOpen(DVThread *dvThread, DVDevice *device) 1613{ 1614 IOReturn err = noErr; 1615 1616#ifdef kIDH_Verbose_Debug_Logging 1617 syslog(LOG_INFO, "DVLib: DVDeviceOpen begin\n"); 1618#endif 1619 1620 if(!device->fAVCInterface) 1621 return kIOReturnNoMemory; 1622 1623 do { 1624 err = (*device->fAVCInterface)->open(device->fAVCInterface); 1625 1626 if(err != kIOReturnSuccess) break; 1627 err = openFireWireUnit(device->fAVCInterface, (*device->fAVCInterface)->getSessionRef(device->fAVCInterface), 1628 &device->fDevInterface, dvThread); 1629 if(err != kIOReturnSuccess) break; 1630 1631 err = openAVCProto(device->fAVCInterface, &device->fAVCProtoInterface, dvThread); 1632 if(err != kIOReturnSuccess) break; 1633 err = (*device->fAVCProtoInterface)->allocateOutputPlug(device->fAVCProtoInterface, 1634 device, handlePCRLock, &device->fOutPlug); 1635 if(err != kIOReturnSuccess) break; 1636 1637 err = writePlug(device->fAVCProtoInterface, device->fOutPlug, 122 << kIOFWPCROutputPayloadPhase); 1638 if(err != kIOReturnSuccess) break; 1639 } while (0); 1640 if(err != kIOReturnSuccess) 1641 DVDeviceClose(device); 1642 1643#ifdef kIDH_Verbose_Debug_Logging 1644 syslog(LOG_INFO, "DVLib: DVDeviceOpen end\n"); 1645#endif 1646 1647 return err; 1648} 1649 1650static IOReturn doDVDeviceClose(DVDevice *dev) 1651{ 1652 1653#ifdef kIDH_Verbose_Debug_Logging 1654 syslog(LOG_INFO, "DVLib: doDVDeviceClose begin\n"); 1655#endif 1656 1657 if(dev->fDevInterface) { 1658 UInt32 ref; 1659 (*dev->fDevInterface)->Close(dev->fDevInterface); 1660 1661 // Remove isoch callback runloop source 1662 (*dev->fDevInterface)->RemoveIsochCallbackDispatcherFromRunLoop(dev->fDevInterface); 1663 1664 ref = (*dev->fDevInterface)->Release(dev->fDevInterface); 1665 //syslog(LOG_INFO, "DVCloseDriver FW refcount was %d\n", ref); 1666 dev->fDevInterface = NULL; 1667 } 1668 1669 if(dev->fAVCProtoInterface) 1670 { 1671 UInt32 ref; 1672 if(dev->fOutPlug != kNoPlug) { 1673 (*dev->fAVCProtoInterface)->freeOutputPlug(dev->fAVCProtoInterface, dev->fOutPlug); 1674 dev->fOutPlug = kNoPlug; 1675 } 1676 1677 // Remove callback runloop source 1678 (*dev->fAVCProtoInterface)->removeCallbackDispatcherFromRunLoop(dev->fAVCProtoInterface); 1679 1680 ref = (*dev->fAVCProtoInterface)->Release(dev->fAVCProtoInterface); 1681 //syslog(LOG_INFO, "DVCloseDriver AVCproto refcount was %d\n", ref); 1682 dev->fAVCProtoInterface = NULL; 1683 } 1684 1685 if(dev->fAVCInterface) { 1686 (*dev->fAVCInterface)->close(dev->fAVCInterface); 1687 } 1688 1689#ifdef kIDH_Verbose_Debug_Logging 1690 syslog(LOG_INFO, "DVLib: doDVDeviceClose end\n"); 1691#endif 1692 1693 return kIOReturnSuccess; 1694} 1695 1696void DVDeviceClose(DVDevice *dev) 1697{ 1698 1699#ifdef kIDH_Verbose_Debug_Logging 1700 syslog(LOG_INFO, "DVLib: DVDeviceClose begin\n"); 1701#endif 1702 1703 DVRequest(dev->fThread, doDVDeviceClose, dev, 0); 1704 1705#ifdef kIDH_Verbose_Debug_Logging 1706 syslog(LOG_INFO, "DVLib: DVDeviceClose end\n"); 1707#endif 1708 1709} 1710 1711IOReturn DVRequest(DVThread *thread, IOReturn (*func)(void *arg, UInt32 param), void *arg, UInt32 param) 1712{ 1713 IOReturn result; 1714 1715 //printf("Doing request %p\n", func); 1716 if(thread->fRTThread != pthread_self()) { 1717 1718 pthread_mutex_lock(&thread->fRequestMutex); 1719 thread->fSyncRequest = 0; 1720 thread->fRequestFunc = func; 1721 thread->fRequestArg = arg; 1722 thread->fRequestParam = param; 1723 1724 { 1725 SendMsg msg; 1726 bzero( &msg, sizeof(msg)); 1727 1728 msg.msgHdr.msgh_remote_port = thread->fRequestMachPort; 1729 msg.msgHdr.msgh_bits = MACH_MSGH_BITS( 1730 MACH_MSG_TYPE_COPY_SEND, 1731 MACH_MSG_TYPE_COPY_SEND ); 1732 msg.msgHdr.msgh_size = sizeof(msg); 1733 msg.msgHdr.msgh_id = kDVRequestID; 1734 1735 mach_msg(&msg.msgHdr, MACH_SEND_MSG, 1736 msg.msgHdr.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); 1737 } 1738 1739 DVWaitSync(&thread->fRequestSyncer, &thread->fSyncRequest); 1740 result = thread->fRequestResult; 1741 pthread_mutex_unlock(&thread->fRequestMutex); 1742 } 1743 else 1744 result = (*func)(arg, param); 1745 1746 return result; 1747} 1748 1749static void initStream(DVStream *stream, DVDevice *device, UInt32 plug, UInt32 channel, DVThread *thread) 1750{ 1751 1752#ifdef kIDH_Verbose_Debug_Logging 1753 syslog(LOG_INFO, "DVLib: initStream begin\n"); 1754#endif 1755 1756 stream->pFWDevice = device->fDevInterface; 1757 stream->pDVDevice = device; 1758 stream->fAVCProtoInterface = device->fAVCProtoInterface; 1759 stream->fPlug = plug; 1760 stream->fIsocChannel = channel; 1761 stream->fMaxSpeed = device->fMaxSpeed; 1762 stream->fThread = thread; 1763 1764#ifdef kIDH_Verbose_Debug_Logging 1765 syslog(LOG_INFO, "DVLib: initStream end\n"); 1766#endif 1767 1768} 1769 1770static IOReturn openStream(DVStream *stream, bool forWrite, UInt32 packetSize) 1771{ 1772 IOReturn err; 1773 IOFireWireLibIsochPortRef talker, listener; 1774 IOVirtualRange bufRange; 1775 bool allocBandwidth; 1776 1777#ifdef kIDH_Verbose_Debug_Logging 1778 syslog(LOG_INFO, "DVLib: openStream begin\n"); 1779#endif 1780 1781 do { 1782 1783 if(forWrite) { 1784 // always allocate bandwidth 1785 allocBandwidth = true; 1786 } 1787 else { 1788 // Figure out if the device is already tranmitting, in which case use that channel and don't 1789 // allocate bandwidth 1790 UInt32 plugVal, plugValHost; 1791 io_object_t obj; 1792 FWAddress addr; 1793 UInt32 size; 1794 // Use any channel not already in use, or the channel that the camcorder is already using 1795 addr.nodeID = 0; 1796 addr.addressHi = 0xffff; 1797 addr.addressLo = 0xf0000904; 1798 size = 4; 1799 obj = (*stream->pFWDevice)->GetDevice(stream->pFWDevice); 1800 err = (*stream->pFWDevice)->ReadQuadlet(stream->pFWDevice, obj, &addr, &plugVal, false, 0); 1801 plugValHost = EndianU32_BtoN( plugVal ); 1802 1803 if(plugValHost & (kIOFWPCRBroadcast | kIOFWPCRP2PCount)) { 1804 UInt32 chan = (plugValHost & kIOFWPCRChannel)>>kIOFWPCRChannelPhase; 1805 //printf("Already transmitting on channel %x\n", chan); 1806 stream->fChannelMask = 1ULL << (63-chan); 1807 allocBandwidth = false; 1808 } 1809 else { 1810#ifdef USE_P2P_CONNECTIONS_FOR_DV_READ 1811 stream->fChannelMask = ~1ULL; 1812 allocBandwidth = true; 1813#else 1814 stream->fChannelMask = 1ULL; // Assume the camera will use channel 63 1815 allocBandwidth = false; 1816#endif 1817 } 1818 } 1819 stream->fIsochChannelRef = (*stream->pFWDevice)->CreateIsochChannel(stream->pFWDevice, allocBandwidth, packetSize, 1820 stream->fMaxSpeed, CFUUIDGetUUIDBytes(kIOFireWireIsochChannelInterfaceID)); 1821 if (NULL == stream->fIsochChannelRef) { 1822 err = memFullErr; 1823 break; 1824 } 1825 1826 bufRange.address = (IOVirtualAddress)stream->fDCLBuffers; 1827 bufRange.length = stream->fDCLBufferSize; 1828 1829 // Add local node as talker or listener 1830 if(forWrite) { 1831 stream->pFWLocalIsochPort = (*stream->pFWDevice)->CreateLocalIsochPort(stream->pFWDevice, 1 /*inTalking*/, 1832 stream->pDCLList, kFWDCLCycleEvent, 0, 0x0000f000, nil, 0, &bufRange, 1, 1833 CFUUIDGetUUIDBytes(kIOFireWireLocalIsochPortInterfaceID)); 1834 1835 // Use any available channel 1836 stream->fChannelMask = ~1ULL; 1837 } 1838 else { 1839 stream->pFWLocalIsochPort = (*stream->pFWDevice)->CreateLocalIsochPort(stream->pFWDevice, 0 /*inTalking*/, 1840 stream->pDCLList, 0, 0, 0, nil, 0, &bufRange, 1, 1841 CFUUIDGetUUIDBytes(kIOFireWireLocalIsochPortInterfaceID)); 1842 } 1843 if (!stream->pFWLocalIsochPort) { 1844 err = memFullErr; 1845 break; 1846 } 1847 1848 stream->pFWRemoteIsochPort = (*stream->pFWDevice)->CreateRemoteIsochPort(stream->pFWDevice, 0, CFUUIDGetUUIDBytes(kIOFireWireRemoteIsochPortInterfaceID) ); 1849 1850 (*stream->pFWRemoteIsochPort)->SetRefCon( stream->pFWRemoteIsochPort, stream); 1851 (*stream->pFWRemoteIsochPort)->SetGetSupportedHandler( stream->pFWRemoteIsochPort, &isochPortGetSupported); 1852 (*stream->pFWRemoteIsochPort)->SetAllocatePortHandler( stream->pFWRemoteIsochPort, &isochPortAllocate); 1853 1854 if(forWrite) { 1855 talker = (IOFireWireLibIsochPortRef) stream->pFWLocalIsochPort; 1856 listener = (IOFireWireLibIsochPortRef)stream->pFWRemoteIsochPort; 1857 } 1858 else { 1859 listener = (IOFireWireLibIsochPortRef) stream->pFWLocalIsochPort; 1860 talker = (IOFireWireLibIsochPortRef)stream->pFWRemoteIsochPort; 1861 } 1862 err = (*stream->fIsochChannelRef)->SetTalker( stream->fIsochChannelRef, talker); 1863 if(err) 1864 break; 1865 err = (*stream->fIsochChannelRef)->AddListener( stream->fIsochChannelRef, listener); 1866 if(err) 1867 break; 1868 1869 1870 // Initialize isochronous channel. 1871 1872 (*stream->fIsochChannelRef)->TurnOnNotification(stream->fIsochChannelRef); 1873 err = (*stream->fIsochChannelRef)->AllocateChannel(stream->fIsochChannelRef); 1874 if(err) 1875 break; 1876 if(forWrite) { 1877 // set our output plug broadcast bit, channel number and bandwidth usage. 1878 err = writePlug(stream->fAVCProtoInterface, stream->fPlug, 1879 kIOFWPCROnline | kIOFWPCRBroadcast | (1 << kIOFWPCRP2PCountPhase) | 1880 (stream->fIsocChannel<<kIOFWPCRChannelPhase) | 1881 (15 << kIOFWPCROutputOverheadPhase) | (122 << kIOFWPCROutputPayloadPhase)); 1882 1883 if(err) 1884 break; 1885 err = MakeP2PConnectionForWrite(stream->pDVDevice,0,stream->fIsocChannel); 1886 } 1887 else 1888 { 1889#ifdef USE_P2P_CONNECTIONS_FOR_DV_READ 1890 err = MakeP2PConnectionForRead(stream->pDVDevice,0,stream->fIsocChannel); 1891#endif 1892 } 1893 1894 err = (*stream->fIsochChannelRef)->Start(stream->fIsochChannelRef); 1895 if(err) 1896 break; 1897 1898 stream->fFrames.fStatus = kDVRunning; 1899 1900 } while (false); 1901 1902 // If we got any errors, call closeStream now to cleanup 1903 if(err) 1904 closeStream(stream); 1905 1906#ifdef kIDH_Verbose_Debug_Logging 1907 syslog(LOG_INFO, "DVLib: openStream end\n"); 1908#endif 1909 1910 return err; 1911} 1912 1913static void closeStream(DVStream *stream) 1914{ 1915 IOReturn err; 1916 1917#ifdef kIDH_Verbose_Debug_Logging 1918 syslog(LOG_INFO, "DVLib: closeStream begin\n"); 1919#endif 1920 1921 stream->fFrames.fStatus = kDVStopped; 1922 if(stream->fIsochChannelRef) { 1923 (*stream->fIsochChannelRef)->TurnOffNotification(stream->fIsochChannelRef); 1924 //syslog(LOG_INFO, "Stopping stream %p\n", stream); 1925 err = (*stream->fIsochChannelRef)->Stop(stream->fIsochChannelRef); 1926 //syslog(LOG_INFO, "Stopped stream, err %x\n", err); 1927 //syslog(LOG_INFO, "ReleaseChannel of stream %p\n", stream); 1928 err = (*stream->fIsochChannelRef)->ReleaseChannel(stream->fIsochChannelRef); 1929 //syslog(LOG_INFO, "releaseChannelled, err %x\n", err); 1930 //syslog(LOG_INFO, "Releaseing channel of stream %p\n", stream); 1931 (*stream->fIsochChannelRef)->Release(stream->fIsochChannelRef); 1932 stream->fIsochChannelRef = NULL; 1933 } 1934 if(stream->pFWLocalIsochPort) { 1935 (*stream->pFWLocalIsochPort)->Release(stream->pFWLocalIsochPort); 1936 stream->pFWLocalIsochPort = NULL; 1937 } 1938 if(stream->pFWRemoteIsochPort) { 1939 (*stream->pFWRemoteIsochPort)->Release(stream->pFWRemoteIsochPort); 1940 stream->pFWRemoteIsochPort = NULL; 1941 } 1942 1943 // Run the runloop for .1 secs to pick up stray DCL callbacks 1944 // But we don't want to run the other runloop sources... 1945 //CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); 1946 1947#ifdef kIDH_Verbose_Debug_Logging 1948 syslog(LOG_INFO, "DVLib: closeStream end\n"); 1949#endif 1950 1951} 1952 1953static IOReturn DVAllocFrames(DVFrameVars *pFrameData, UInt32 numFrames, UInt32 frameSize, 1954 DVFrameVars **frameVars, UInt8 **frames) 1955{ 1956 int i; 1957 1958#ifdef kIDH_Verbose_Debug_Logging 1959 syslog(LOG_INFO, "DVLib: DVAllocFrames begin\n"); 1960#endif 1961 1962 pFrameData->fNumFrames = numFrames; 1963 pFrameData->fFrames = malloc(numFrames*frameSize); 1964 pFrameData->fReader = 0; 1965 pFrameData->fWriter = 0; 1966 pFrameData->fDroppedFrames = 0; 1967 pFrameData->fStatus = 0; 1968 for(i=0; i<numFrames; i++) { 1969 frames[i] = pFrameData->fFrames + i*frameSize; 1970 } 1971 *frameVars = pFrameData; 1972 1973#ifdef kIDH_Verbose_Debug_Logging 1974 syslog(LOG_INFO, "DVLib: DVAllocFrames end\n"); 1975#endif 1976 1977 return kIOReturnSuccess; 1978} 1979 1980static void DVFreeFrames(DVFrameVars *pFrameData) 1981{ 1982 1983#ifdef kIDH_Verbose_Debug_Logging 1984 syslog(LOG_INFO, "DVLib: DVFreeFrames begin\n"); 1985#endif 1986 1987 if(!pFrameData->fFrames) 1988 { 1989#ifdef kIDH_Verbose_Debug_Logging 1990 syslog(LOG_INFO, "DVLib: DVFreeFrames end:no frames\n"); 1991#endif 1992 return; 1993 } 1994 1995 free(pFrameData->fFrames); 1996 pFrameData->fFrames = NULL; 1997 1998#ifdef kIDH_Verbose_Debug_Logging 1999 syslog(LOG_INFO, "DVLib: DVFreeFrames end\n"); 2000#endif 2001} 2002 2003static void DVGetNextFullOutputFrame(DVFrameVars *pFrameData, UInt8** ppFrame, UInt32 frameSize ) 2004{ 2005 if(NULL == *ppFrame) { 2006 *ppFrame = pFrameData->fFrames; 2007 } 2008 else { 2009 if (pFrameData->fReader + 1 < pFrameData->fWriter) { 2010 pFrameData->fReader++; 2011 } 2012 else { 2013 //syslog(LOG_INFO, "DVGetNextFullOutputFrame: dropping frame: reader %d writer %d dropped %d\n", 2014 //pFrameData->fReader, pFrameData->fWriter, 2015 //pFrameData->fDroppedFrames); 2016 pFrameData->fDroppedFrames++; 2017 } 2018 *ppFrame = pFrameData->fFrames + 2019 frameSize*(pFrameData->fReader % pFrameData->fNumFrames); 2020 } 2021} 2022 2023void DVSetInputFrameSizeAndMode(DVFrameVars *pFrameData, UInt32 bytes, UInt8 mode, UInt32 frameTime ) 2024{ 2025 int index = pFrameData->fWriter % pFrameData->fNumFrames; 2026 int i; 2027 pFrameData->fFrameSize[index] = bytes; 2028 pFrameData->fFrameStandard[index] = mode; 2029 pFrameData->fFrameTime[index] = frameTime; 2030 pFrameData->fFrameStatus[index] = kReady; 2031 2032 // find next free frame 2033 for(i=pFrameData->fWriter + 1; i < pFrameData->fReader + pFrameData->fNumFrames; i++) { 2034 if(pFrameData->fFrameStatus[i % pFrameData->fNumFrames] != kReading) 2035 break; 2036 //syslog(LOG_INFO, "Skipping frame %d (%d) state %d\n", 2037 // i, i % pFrameData->fNumFrames, pFrameData->fFrameStatus[i % pFrameData->fNumFrames]); 2038 } 2039 if (i< pFrameData->fReader + pFrameData->fNumFrames) 2040 pFrameData->fWriter = i; 2041 else { 2042 pFrameData->fDroppedFrames++; 2043 //(LOG_INFO, "Dropping frame on input, dropped %d @ %d\n", 2044 // pFrameData->fDroppedFrames, pFrameData->fWriter); 2045 } 2046} 2047 2048void DVGetNextEmptyInputFrame(DVFrameVars *pFrameData, UInt8** ppFrame, UInt32 frameSize ) 2049{ 2050 int index = pFrameData->fWriter % pFrameData->fNumFrames; 2051 *ppFrame = pFrameData->fFrames + frameSize*index; 2052 pFrameData->fFrameStatus[index] = kWriting; 2053} 2054 2055static UInt32 getEmptyPacketsPerGroup(DVGlobalOutPtr pGlobalData, UInt32 numDataPacketsPerPlayBufferGroup) 2056{ 2057 // Compute the number of data packets per empty packet. 2058 // If the frame rate is expressed as n/d, the number of data packets per buffer group 2059 // expressed as A, and the number of data packets per frame as C, then the number of 2060 // empty packets per buffer group B should be 2061 // 2062 // B = int (8000*d/n*A/C - A + 1) 2063 // B = A*((8000*d)/(n*c) - 1) + 1 2064 2065 // 2066 // in order to ensure that the frame rate may be maintained by periodically reducing 2067 // the number of empty packets in a buffer group by 1. 2068 // 2069 2070 UInt32 numEmptyPacketsPerPlayBufferGroup; 2071 UInt32 A1, C1, d1, n1; 2072 2073 A1 = numDataPacketsPerPlayBufferGroup; 2074 C1 = pGlobalData->numDataPacketsPerFrame; 2075 n1 = pGlobalData->playFrameRateNumerator; 2076 d1 = pGlobalData->playFrameRateDenominator; 2077#if ALT_TIMING 2078 { 2079 UInt32 d2 = C1*n1; 2080 UInt32 n2 = (8000 * d1 * A1) - (d2 * A1) + d2; 2081 numEmptyPacketsPerPlayBufferGroup = n2 / d2; 2082 } 2083#else 2084 numEmptyPacketsPerPlayBufferGroup = (8000 * d1 * A1 + (n1 * C1)/2) / (n1 * C1) - A1; 2085#endif 2086 2087 return numEmptyPacketsPerPlayBufferGroup; 2088} 2089 2090static void FreeDCLCommandPool(DVGlobalOutPtr pGlobalData) 2091{ 2092 2093#ifdef kIDH_Verbose_Debug_Logging 2094 syslog(LOG_INFO, "DVLib: FreeDCLCommandPool begin\n"); 2095#endif 2096 2097 if( pGlobalData->fDCLCommandPool != NULL ) { 2098 free(pGlobalData->fDCLCommandPool); 2099 pGlobalData->fDCLCommandPool = NULL; 2100 } 2101 2102#ifdef kIDH_Verbose_Debug_Logging 2103 syslog(LOG_INFO, "DVLib: FreeDCLCommandPool end\n"); 2104#endif 2105 2106} 2107 2108static IOReturn AllocateDCLCommandPool(DVGlobalOutPtr pGlobalData, UInt32 total ) 2109{ 2110 UInt8 * pDCLCommandPool; 2111 2112#ifdef kIDH_Verbose_Debug_Logging 2113 syslog(LOG_INFO, "DVLib: AllocateDCLCommandPool begin\n"); 2114#endif 2115 2116 // Allocate DCL command pool record. 2117 pDCLCommandPool = malloc(total); 2118 if (pDCLCommandPool == NULL) 2119 { 2120 // syslog(LOG_INFO, "AllocateDCLCommandPool: IOMalloc: pDCLCommandPool failed\n"); 2121#ifdef kIDH_Verbose_Debug_Logging 2122 syslog(LOG_INFO, "DVLib: AllocateDCLCommandPool end:no pool\n"); 2123#endif 2124 return kIOReturnNoMemory; 2125 } 2126 else 2127 { 2128 pGlobalData->fTotalPool = total; 2129 pGlobalData->fAllocatedPool = 0; 2130 pGlobalData->fDCLCommandPool = pDCLCommandPool; 2131 } 2132 2133#ifdef kIDH_Verbose_Debug_Logging 2134 syslog(LOG_INFO, "DVLib: AllocateDCLCommandPool end\n"); 2135#endif 2136 2137 return kIOReturnSuccess; 2138} 2139 2140static DCLCommandPtr AllocateDCLCommand(DVGlobalOutPtr pGlobalData, UInt32 dclSize ) 2141{ 2142 DCLCommandPtr pDCLCommand; 2143 2144 if(pGlobalData->fAllocatedPool + dclSize <= pGlobalData->fTotalPool) { 2145 pDCLCommand = (DCLCommandPtr)(pGlobalData->fDCLCommandPool + pGlobalData->fAllocatedPool); 2146 pGlobalData->fAllocatedPool += dclSize; 2147 } 2148 else { 2149 syslog(LOG_INFO, "Trying to allocated DCL command size %d, no space left\n", dclSize); 2150 pDCLCommand = NULL; 2151 } 2152 2153 return (pDCLCommand); 2154} 2155 2156static DVLocalOutPtr DVAllocatePlayBufferGroup(DVGlobalOutPtr pGlobalData, int num) 2157{ 2158 DVLocalOutPtr pLocalData, 2159 pPrevLocalData, 2160 pNextLocalData; 2161 2162 // Allocate buffer group data record. 2163 pLocalData = &pGlobalData->fLocalDataArray[num]; 2164 pLocalData->pGlobalData = pGlobalData; 2165 pLocalData->fBlockNum = num; 2166 2167 // Insert buffer group data record into list. 2168 if(num == 0) { 2169 pPrevLocalData = &pGlobalData->fLocalDataArray[kNumPlayBufferGroups-1]; 2170 } 2171 else 2172 pPrevLocalData = &pGlobalData->fLocalDataArray[num-1]; 2173 2174 if(num == kNumPlayBufferGroups-1) 2175 pNextLocalData = &pGlobalData->fLocalDataArray[0]; 2176 else 2177 pNextLocalData = &pGlobalData->fLocalDataArray[num+1]; 2178 2179 pLocalData->pNextLocalData = pNextLocalData; 2180 pLocalData->pPrevLocalData = pPrevLocalData; 2181 return (pLocalData); 2182} 2183 2184static void DVDeallocatePlayBufferGroup( DVLocalOutPtr pLocalData ) 2185{ 2186 if ( pLocalData != NULL ) 2187 { 2188 if ( pLocalData->bufferGroupUpdateDCLList != NULL ) 2189 free(pLocalData->bufferGroupUpdateDCLList); 2190 } 2191} 2192 2193static IOReturn DVCreatePlayBufferGroupUpdateList( DVLocalOutPtr pLocalData) 2194{ 2195 DCLCommandPtr pDCLCommand, 2196 pLastDCLCommand; 2197 DCLCommandPtr *updateDCLList, 2198 *pUpdateDCLListEntry; 2199 UInt32 opcode; 2200 UInt32 updateListSize; 2201 IOReturn error = 0; 2202 2203 // Loop through all DCL commands in buffer group and count all send packet DCL 2204 // commands. 2205 pDCLCommand = pLocalData->pFirstBufferGroupDCLCommand; 2206 pLastDCLCommand = pLocalData->pLastBufferGroupDCLCommand; 2207 updateListSize = 0; 2208 while (pDCLCommand != pLastDCLCommand) 2209 { 2210 opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask; 2211 if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp)) 2212 updateListSize++; 2213 2214 pDCLCommand = pDCLCommand->pNextDCLCommand; 2215 } 2216 opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask; 2217 if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp)) 2218 updateListSize++; 2219 2220 // Allocate update list. 2221 updateDCLList = (DCLCommandPtr *)malloc( updateListSize * sizeof (DCLCommandPtr) ); 2222 if (updateDCLList == NULL) 2223 { 2224 // syslog(LOG_INFO, "DVCreatePlayBufferGroupUpdateList: IOMalloc: updateDCLList\n"); 2225 error = kIOReturnNoMemory; 2226 } 2227 else 2228 { 2229 bzero( updateDCLList, updateListSize * sizeof (DCLCommandPtr) ); 2230 } 2231 2232 // Loop through all DCL commands in buffer group and add all send packet DCL 2233 // commands to update list. 2234 if (error == 0) 2235 { 2236 pDCLCommand = pLocalData->pFirstBufferGroupDCLCommand; 2237 pLastDCLCommand = pLocalData->pLastBufferGroupDCLCommand; 2238 pUpdateDCLListEntry = updateDCLList; 2239 2240 while (pDCLCommand != pLastDCLCommand) 2241 { 2242 opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask; 2243 if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp)) 2244 *pUpdateDCLListEntry++ = pDCLCommand; 2245 2246 pDCLCommand = pDCLCommand->pNextDCLCommand; 2247 } 2248 2249 opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask; 2250 if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp)) 2251 *pUpdateDCLListEntry++ = pDCLCommand; 2252 } 2253 2254 // Save update list. 2255 if (error == 0) 2256 { 2257 pLocalData->bufferGroupUpdateDCLList = updateDCLList; 2258 pLocalData->updateListSize = updateListSize; 2259 } 2260 else 2261 { 2262 pLocalData->bufferGroupUpdateDCLList = NULL; 2263 pLocalData->updateListSize = 0; 2264 } 2265 2266 return ( error ); 2267} 2268 2269static void ModifyDCLJump(IOFireWireLibLocalIsochPortRef port, DCLJumpPtr pDCLJump, DCLLabelPtr pDCLLabel) 2270{ 2271 // Send notification to DCL compiler. 2272 if (port) { 2273 (*port)->ModifyJumpDCL( port, pDCLJump, pDCLLabel); 2274 } 2275} 2276 2277void DVSilenceFrame(UInt8 mode, UInt8* frame) 2278{ 2279 UInt32 i,j,k,n; 2280 UInt8 *tPtr; 2281 UInt8 sType = ((mode & 0x7C) >> 2); 2282 2283 //syslog(LOG_INFO, "silencing frame %p\n", frame); 2284 2285 // Get DSF flag in byte 3 of header (Blue Book p. 113) 2286 tPtr = frame; 2287 if ((tPtr[3] & 0x80) == 0) 2288 n=10; // ntsc 2289 else 2290 n=12; // pal 2291 2292 if (sType == 1) 2293 n /= 2; // SDL 2294 else if (sType == 0x1D) 2295 n *= 2; // DVCPro-50 2296 2297 // Mute all the audio samples 2298 2299 for (i=0;i<n;i++) 2300 { 2301 for (j=0;j<9;j++) 2302 { 2303 tPtr = frame + (i * 12000) + ((j * 16 + 6) * 80) + 8; 2304 for (k=0;k<72;k++) 2305 *tPtr++ = 0x0; 2306 } 2307 } 2308} 2309 2310 2311static void DVUpdateOutputBuffers( DVLocalOutPtr pLocalData ) 2312{ 2313 DCLCommandPtr pCurrentDCLCommand; 2314 DCLTransferPacketPtr pDCLTransferPacket; 2315 DVLocalOutPtr pPrevLocalData; 2316 DVGlobalOutPtr pGlobalData; 2317 UInt16 localNodeID; 2318 UInt32 shiftedNodeID; // Poistioned for ORing into header0 2319 UInt32 nominalFrameCycleTime; 2320 UInt32 syt; 2321 UInt32 *pBuffer, *pImageBuffer, *pLastImageBuffer; 2322 UInt32 packetNum, dataPacketNum, numPackets; 2323 UInt32 dbc; 2324// static UInt16 lastFrameSequence = 0; 2325// UInt16 currentFrameSequence; 2326 UInt8 stype; 2327 2328 // Get driver data and first DCL command. 2329 pGlobalData = pLocalData->pGlobalData; 2330 2331 pCurrentDCLCommand = pLocalData->pFirstBufferGroupDCLCommand; 2332 nominalFrameCycleTime = pGlobalData->nominalFrameCycleTime; 2333 2334 // Get data for previous buffer group. 2335 pPrevLocalData = pLocalData->pPrevLocalData; 2336 syt = pGlobalData->nextSYT; 2337 dbc = pGlobalData->nextDBC; 2338 dataPacketNum = pGlobalData->nextDataPacketNum; 2339 2340 // Get local node ID. 2341 2342 (*pGlobalData->fStreamVars.pFWDevice)->GetLocalNodeID(pGlobalData->fStreamVars.pFWDevice, &localNodeID); 2343 localNodeID &= 0x3f; 2344 shiftedNodeID = (UInt32)localNodeID << 24; 2345 2346 // Get first send packet command for this buffer group. 2347 while (pCurrentDCLCommand->opcode != kDCLSendPacketStartOp) 2348 pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; 2349 pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentDCLCommand; 2350 2351 // Update the packet buffers. 2352 numPackets = pLocalData->numPackets; 2353 2354 if(pGlobalData->fUpdateBuffers) { 2355 // Get the next frame to output 2356 if( pGlobalData->pImageBuffer == NULL ) { 2357 DVGetNextFullOutputFrame(&pGlobalData->fStreamVars.fFrames, 2358 (UInt8 **)&(pGlobalData->pImageBuffer), 2359 pGlobalData->fStreamVars.fDVFrameSize); 2360 } 2361 } 2362 pImageBuffer = ( pGlobalData->pImageBuffer + (pGlobalData->fDataQuadSize * dataPacketNum) ); 2363 for( packetNum = 0; packetNum < numPackets; packetNum++) 2364 { 2365 // Set up packet header. 2366 pBuffer = (UInt32 *) pDCLTransferPacket->buffer; 2367 2368 pBuffer[0] = EndianU32_NtoB( pGlobalData->fHeader0 | (dbc & 0xFF) | shiftedNodeID ); 2369 pBuffer[1] = EndianU32_NtoB( pGlobalData->fHeader1 | 0xFFFF ); 2370 2371 // if not an empty packet 2372 if (pDCLTransferPacket->size > kDVPacketCIPSize) 2373 { 2374 // Set SYT field if this is the first data packet in the frame. 2375 if (dataPacketNum == 0) 2376 { 2377 pBuffer[1] = EndianU32_NtoB( pGlobalData->fHeader1 | (syt & 0xFFFF) ); 2378 syt = AddFWCycleTimeToFWCycleTime(syt, pGlobalData->nominalFrameCycleTime); 2379 } 2380 2381 // Copy data into packet. 2382 if(pGlobalData->fUpdateBuffers) { 2383 bcopy(pImageBuffer, (void *)((UInt32)(pDCLTransferPacket->buffer) + kDVPacketCIPSize), 2384 pGlobalData->fDataPacketSize); 2385 pImageBuffer += pGlobalData->fDataQuadSize; 2386 } 2387 2388 // Increment dbc based on stream type 2389 // TODO: This will need to change to support 2x,4x modes on some signal types 2390 stype = pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_STYPE; 2391 switch (stype) 2392 { 2393 case kAVCSignalModeMask_DVCPro50: 2394 dbc += 2; // DBC increments by two for each packet 2395 break; 2396 2397 case kAVCSignalModeMask_DVCPro100: 2398 dbc += 4; // DBC increments by four for each packet 2399 break; 2400 2401 case kAVCSignalModeMask_SDL: 2402 case kAVCSignalModeMask_DVCPro25: 2403 case kAVCSignalModeMask_HD: 2404 default: // SD video stream 2405 dbc += 1; // DBC increments by one for each packet 2406 break; 2407 }; 2408 dataPacketNum++; 2409 2410 // check if frame is done 2411 if (dataPacketNum == pGlobalData->numDataPacketsPerFrame ) 2412 { 2413 // syslog(LOG_INFO, "frame done\n"); 2414 // DVCIsochCompleteEvent theEvent; 2415 2416 // post a DV event to let the curious know... 2417 // theEvent.eventHeader.deviceID = gpDVFWData->deviceID; 2418 // theEvent.eventHeader.theEvent = kDVIsochWriteComplete; 2419 // theEvent.pFrameBuffer = (Ptr) pImageBuffer; 2420 // theEvent.fwCycleTime = syt; 2421 // FIXME: DVCPostEvent( (DVCEventRecordPtr) &theEvent ); 2422 // syslog(LOG_INFO, "DVCPostEvent\n"); 2423 2424 // pImageBuffer = (UInt32 *) pDVCDriverData->imageBuffer; 2425 dataPacketNum = 0; 2426 //pDVCDriverData->playData.imageBuffer = GetNextOutputFrame(); 2427 2428 if(pGlobalData->fUpdateBuffers) { 2429 pLastImageBuffer = pGlobalData->pImageBuffer; 2430 2431 DVGetNextFullOutputFrame(&pGlobalData->fStreamVars.fFrames, 2432 (UInt8 **)&(pGlobalData->pImageBuffer), 2433 pGlobalData->fStreamVars.fDVFrameSize); 2434 pImageBuffer = pGlobalData->pImageBuffer; 2435 2436 // Mute the audio on repeating frames, based on repeating frame sequences 2437 if (pImageBuffer == pLastImageBuffer) 2438 DVSilenceFrame(pGlobalData->fStreamVars.fSignalMode, (UInt8 *)pImageBuffer); 2439 } // End if(pGlobalData->fUpdateBuffers) 2440 } // end if end frame 2441 } // end if empty 2442 2443 // Find next send packet start command. 2444 pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; 2445 while (pCurrentDCLCommand != NULL) 2446 { 2447 if (pCurrentDCLCommand->opcode != kDCLSendPacketStartOp) 2448 pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; 2449 else 2450 break; 2451 } 2452 pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentDCLCommand; 2453 } 2454 pGlobalData->nextSYT = syt; 2455 pGlobalData->nextDBC = dbc; 2456 pGlobalData->nextDataPacketNum = dataPacketNum; 2457 2458} 2459 2460static void DVHandleOutput(DVLocalOutPtr pLocalData) 2461{ 2462 DVGlobalOutPtr pGlobalData; 2463 DVLocalOutPtr pPrevLocalData; 2464 UInt32 nominalFrameCycleTime; 2465 UInt32 fractionalFrameCycleCount, 2466 fractionalFrameCycleOffset; 2467 SInt32 timeDrift; 2468 UInt32 cycleDrift; 2469 UInt32 projectedTimeStamp, 2470 projectedSYT; 2471#if TIMING 2472 CFAbsoluteTime cstart, cend; 2473 cstart = CFAbsoluteTimeGetCurrent(); 2474#endif 2475 2476 //syslog(LOG_INFO, "DVHandleOutput: 0x%x\n", pDCLCommandPtr); 2477 pPrevLocalData = pLocalData->pPrevLocalData; 2478 pGlobalData = pLocalData->pGlobalData; 2479 nominalFrameCycleTime = pGlobalData->nominalFrameCycleTime; 2480 2481 // Undo skipping empty packet if we're currently skipping a packet. 2482 if (pLocalData->skippingEmptyPacket) 2483 { 2484 ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort, 2485 pLocalData->pBufferGroupSkipEmptyPacketDCLJump, pLocalData->pBufferGroupDontSkipEmptyPacketDCLLabel); 2486 pGlobalData->activePackets++; 2487 pLocalData->skippingEmptyPacket = false; 2488 } 2489 2490 // Compute time drift. 2491 2492 // Compute the projected time stamp value for the first packet of the current 2493 // buffer group the next time this proc is called for the current buffer group. 2494 2495 // Start at time stamp of first packet in next buffer group to be sent. 2496 projectedTimeStamp = *pLocalData->pBufferGroupTimeStampPtr; // Time last packet in group was sent last time round 2497 projectedTimeStamp = AddFWCycleTimeToFWCycleTime(projectedTimeStamp, 1 << 12); 2498 2499 // Add the total number of cycles for all active buffer group packets. 2500 projectedTimeStamp = AddFWCycleTimeToFWCycleTime(projectedTimeStamp, pGlobalData->activePackets << 12); 2501 2502 // Subtract the number of cycles for all packets in the current buffer group. 2503 projectedTimeStamp = SubtractFWCycleTimeFromFWCycleTime(projectedTimeStamp, pLocalData->numPackets << 12); 2504 2505 // Compute the projected SYT value for the first packet of the current buffer group 2506 // the next time this proc is called for the current buffer group. 2507 2508 // Start with the SYT value to use for the first packet of the next frame. 2509 projectedSYT = pGlobalData->nextSYT; 2510 2511 // Subtract the SYT offset between frames if we aren't at the start of a frame 2512 if(pGlobalData->nextDataPacketNum != 0) { 2513 projectedSYT = SubtractFWCycleTimeFromFWCycleTime(projectedSYT, nominalFrameCycleTime); 2514 2515 // Add the fraction of the SYT offset between the start of the frame and the 2516 // first data packet for the current buffer group. 2517 fractionalFrameCycleOffset = 2518 ((nominalFrameCycleTime & 0x0FFF) * pGlobalData->nextDataPacketNum) / 2519 pGlobalData->numDataPacketsPerFrame; 2520 2521 fractionalFrameCycleCount = 2522 ((nominalFrameCycleTime & 0x01FFF000) * pGlobalData->nextDataPacketNum) / 2523 pGlobalData->numDataPacketsPerFrame; 2524 fractionalFrameCycleCount = 2525 (fractionalFrameCycleCount & 0x01FFF000) + 2526 (((fractionalFrameCycleCount & 0x0FFF) * 3072) / 4096); 2527 2528 projectedSYT = AddFWCycleTimeToFWCycleTime (projectedSYT, fractionalFrameCycleOffset); 2529 projectedSYT = AddFWCycleTimeToFWCycleTime (projectedSYT, fractionalFrameCycleCount); 2530 } 2531 2532 // The time drift is the difference between the projected time stamp and SYT. 2533 // We must convert the time drift to cycles. 2534 cycleDrift = AddFWCycleTimeToFWCycleTime(projectedTimeStamp, kPlaySYTDelay << 12); 2535 cycleDrift = SubtractFWCycleTimeFromFWCycleTime(cycleDrift, projectedSYT); 2536//syslog(LOG_INFO, "time drift %x group %p\n", cycleDrift >> 12, pLocalData ); 2537 timeDrift = (cycleDrift >> 12) & 0x000F; 2538 // Skip an empty packet if we're drifting. 2539 // Only consider positive drifting. 2540 if ((timeDrift > 0) && (timeDrift < 0x0008)) 2541 { 2542 ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort, 2543 pLocalData->pBufferGroupSkipEmptyPacketDCLJump, pLocalData->pBufferGroupSkipEmptyPacketDCLLabel); 2544 pGlobalData->activePackets--; 2545 pLocalData->skippingEmptyPacket = true; 2546 } 2547 2548 DVUpdateOutputBuffers( pLocalData ); 2549 2550 // Update DCL jumps to call underrun proc after this buffer group. 2551 //zzz check errors. 2552 ModifyDCLJump (pGlobalData->fStreamVars.pFWLocalIsochPort, 2553 pLocalData->pEndOfBufferGroupDCLJump, pGlobalData->pUnderrunDCLLabel); 2554 ModifyDCLJump (pGlobalData->fStreamVars.pFWLocalIsochPort, 2555 pPrevLocalData->pEndOfBufferGroupDCLJump, pLocalData->pStartOfBufferGroupDCLLabel); 2556 pGlobalData->fSharedDCLVars.fDMAPos = pLocalData->fBlockNum; 2557#if TIMING 2558 cend = CFAbsoluteTimeGetCurrent(); 2559 DVLog(pGlobalData->fStreamVars.fThread, 'isoc', cstart, cend); 2560#endif 2561} 2562 2563static void DVWritePoll(DVGlobalOutPtr globs) 2564{ 2565 int i, pos; 2566 pos = globs->fSharedDCLVars.fDMAPos; 2567 for(i=pos; i<kNumPlayBufferGroups; i++) 2568 if(*globs->fLocalDataArray[i].pBufferGroupTimeStampPtr != 0xffffffff) { 2569 DVHandleOutput(&globs->fLocalDataArray[i]); 2570 *globs->fLocalDataArray[i].pBufferGroupTimeStampPtr = 0xffffffff; 2571 } 2572 2573 for(i=0; i<pos; i++) 2574 if(*globs->fLocalDataArray[i].pBufferGroupTimeStampPtr != 0xffffffff) { 2575 DVHandleOutput(&globs->fLocalDataArray[i]); 2576 *globs->fLocalDataArray[i].pBufferGroupTimeStampPtr = 0xffffffff; 2577 } 2578} 2579 2580 2581static void doDVHandleOutputUnderrun( DVGlobalOutPtr pGlobalData ) 2582{ 2583 IOReturn err; 2584 // FIXME 2585 2586 syslog(LOG_INFO, "DVHandleOutputUnderrun: 0x%p\n", pGlobalData); 2587 2588 DVStream *stream; 2589 2590 if ((pGlobalData->pendingDVWriteUnderrunHandler == true) && (pGlobalData->deferredDVWriteFree == true)) 2591 { 2592 // Free the globalout data struct 2593 free(pGlobalData); 2594 return; 2595 } 2596 pGlobalData->pendingDVWriteUnderrunHandler = false; 2597 2598 2599 stream = &pGlobalData->fStreamVars; 2600 2601 // See if stream still open. If not, we're done! 2602 if (stream->fIsochChannelRef == NULL) 2603 return; 2604 2605 closeStream(&pGlobalData->fStreamVars); 2606 2607 FreeDCLCommandPool(pGlobalData); 2608 2609 BreakP2PConnectionForWrite(pGlobalData->fStreamVars.pDVDevice,0,pGlobalData->fStreamVars.fIsocChannel); 2610 2611 err = buildWriteProgram(pGlobalData); 2612 if(err != kIOReturnSuccess) 2613 syslog(LOG_INFO, "DVHandleOutputUnderrun: buildWriteProgram returned %x\n", err); 2614 2615 err = DVWriteStart(pGlobalData); 2616} 2617 2618static void DVHandleOutputUnderrun( DCLCommandPtr pDCLCommandPtr ) 2619{ 2620 DVGlobalOutPtr pGlobalData; 2621 2622#ifdef kIDH_Verbose_Debug_Logging 2623 syslog(LOG_INFO, "DVLib: DVHandleOutputUnderrun begin\n"); 2624#endif 2625 2626 pGlobalData = (DVGlobalOutPtr)((DCLCallProcPtr)pDCLCommandPtr)->procData; 2627 if (pGlobalData->dvWriteStopInProgress == false) 2628 { 2629 pGlobalData->pendingDVWriteUnderrunHandler = true; 2630 DVRequest(pGlobalData->fStreamVars.fThread, doDVHandleOutputUnderrun, pGlobalData, 0); 2631 } 2632 2633#ifdef kIDH_Verbose_Debug_Logging 2634 syslog(LOG_INFO, "DVLib: DVHandleOutputUnderrun end\n"); 2635#endif 2636} 2637 2638 2639static void DVDisposeDCLOutput( DVGlobalOutPtr pOutputData ) 2640{ 2641 DVLocalOutPtr pLocalData, pNextLocalData; 2642 UInt32 bufferGroupNum; 2643 2644#ifdef kIDH_Verbose_Debug_Logging 2645 syslog(LOG_INFO, "DVLib: DVDisposeDCLOutput begin\n"); 2646#endif 2647 2648 // syslog(LOG_INFO, "DVDisposeDCLOutput\n"); 2649 if( pOutputData != NULL ) 2650 { 2651 // Deallocate play buffer group data records. 2652 // and update lists associated with them 2653 pLocalData = &pOutputData->fLocalDataArray[0]; 2654 for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++) 2655 { 2656 if( pLocalData != NULL ) 2657 { 2658 pNextLocalData = pLocalData->pNextLocalData; 2659 DVDeallocatePlayBufferGroup (pLocalData); 2660 pLocalData = pNextLocalData; 2661 } 2662 } 2663 2664 FreeDCLCommandPool(pOutputData); 2665 2666 /* don't dispose of the frame buffer here.. wait since its shared 2667 DVReleaseFrameIO(); 2668 */ 2669 2670 if( pOutputData->fStreamVars.fDCLBuffers != NULL) 2671 { 2672 //free( pOutputData->pTransmitBuffers); //pOutputData->fDCLBufferSize ); 2673 vm_deallocate(mach_task_self(), (vm_address_t)pOutputData->fStreamVars.fDCLBuffers, 2674 pOutputData->fStreamVars.fDCLBufferSize); 2675 } 2676 //free( pOutputData); //, sizeof(DVGlobalOut) ); 2677 } 2678 2679#ifdef kIDH_Verbose_Debug_Logging 2680 syslog(LOG_INFO, "DVLib: DVDisposeDCLOutput end\n"); 2681#endif 2682 2683} 2684 2685static IOReturn allocateBuffers(DVGlobalOutPtr pGlobalData) 2686{ 2687 UInt32 numDataPacketsPerPage; 2688 UInt32 numEmptyPackets; 2689 UInt32 pageSize; 2690 UInt32 emptySize; // Space used by empty packer headers. 2691 UInt32 transmitBuffersSize; 2692 2693 IOReturn res; 2694 2695#ifdef kIDH_Verbose_Debug_Logging 2696 syslog(LOG_INFO, "DVLib: allocateBuffers begin\n"); 2697#endif 2698 2699 // Setup CIP header static bits, plus packet size based on signal mode 2700 UInt8 stype = pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_STYPE; 2701 switch (stype) 2702 { 2703 case kAVCSignalModeMask_SDL: 2704 pGlobalData->fHeader0 = 0x003c0000; 2705 pGlobalData->fHeader1 = 0x80040000; 2706 pGlobalData->fDataPacketSize = kDVSDLPayloadPacketSize; // Data portion, in bytes 2707 break; 2708 2709 case kAVCSignalModeMask_DVCPro25: 2710 pGlobalData->fHeader0 = 0x00780000; 2711 pGlobalData->fHeader1 = 0x80780000; 2712 pGlobalData->fDataPacketSize = kDVSDPayloadPacketSize; // Data portion, in bytes 2713 break; 2714 2715 case kAVCSignalModeMask_DVCPro50: 2716 pGlobalData->fHeader0 = 0x00784000; 2717 pGlobalData->fHeader1 = 0x80740000; 2718 pGlobalData->fDataPacketSize = kDVCPro50PayloadPacketSize; // Data portion, in bytes 2719 break; 2720 2721 case kAVCSignalModeMask_DVCPro100: 2722 pGlobalData->fHeader0 = 0x00788000; 2723 pGlobalData->fHeader1 = 0x80700000; 2724 pGlobalData->fDataPacketSize = kDVCPro50PayloadPacketSize; // Data portion, in bytes 2725 break; 2726 2727 case kAVCSignalModeMask_HD: 2728 pGlobalData->fHeader0 = 0x00F00000; 2729 pGlobalData->fHeader1 = 0x80080000; 2730 pGlobalData->fDataPacketSize = kDVCPro50PayloadPacketSize; // Data portion, in bytes 2731 break; 2732 2733 default: // Must be SD video stream 2734 pGlobalData->fHeader0 = 0x00780000; 2735 pGlobalData->fHeader1 = 0x80000000; 2736 pGlobalData->fDataPacketSize = kDVSDPayloadPacketSize; // Data portion, in bytes 2737 break; 2738 }; 2739 2740 pGlobalData->fDataQuadSize = pGlobalData->fDataPacketSize/4; // Data portion, in quads 2741 pGlobalData->fAlignQuadSize = (pGlobalData->fDataPacketSize + kDVPacketCIPSize + 15)/16; 2742 pGlobalData->fAlignQuadSize *= 4; // Packet size padded out to 16 byte boundary, in quads 2743 pGlobalData->fSharedDCLVars.fAlignedPacketSize = 4*pGlobalData->fAlignQuadSize; //Packet size in bytes 2744 pGlobalData->fSharedDCLVars.fPacketDataSize = pGlobalData->fDataPacketSize; 2745 2746 //////////////////////////////////////////////// 2747 // 2748 // set timing values for appropriate video system 2749 // 2750 if( !(pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_50) ) 2751 { 2752 //syslog(LOG_INFO, "NTSC output\n"); 2753 pGlobalData->playFramePeriodNumerator = kNTSCPlayFramePeriodNumerator; 2754 pGlobalData->playFramePeriodDenominator = kNTSCPlayFramePeriodDenominator; 2755 2756 pGlobalData->playFrameRateNumerator = kNTSCFrameRateNumerator; 2757 pGlobalData->playFrameRateDenominator = kNTSCFrameRateDenominator; 2758 2759 pGlobalData->numDataPacketsPerFrame = kNTSCNumDataPacketsPerDVFrame; 2760 pGlobalData->numDataPacketsPerGroup = kNTSCNumDataPacketsPerGroup; 2761 } 2762 else 2763 { 2764 //syslog(LOG_INFO, "PAL output\n"); 2765 pGlobalData->fHeader1 |= kPALBit; 2766 pGlobalData->playFramePeriodNumerator = kPALPlayFramePeriodNumerator; 2767 pGlobalData->playFramePeriodDenominator = kPALPlayFramePeriodDenominator; 2768 2769 pGlobalData->playFrameRateNumerator = kPALFrameRateNumerator; 2770 pGlobalData->playFrameRateDenominator = kPALFrameRateDenominator; 2771 2772 pGlobalData->numDataPacketsPerFrame = kPALNumDataPacketsPerDVFrame; 2773 pGlobalData->numDataPacketsPerGroup = kPALNumDataPacketsPerGroup; 2774 } 2775 2776 // Compute nominal frame period cycle time. 2777 pGlobalData->nominalFrameCycleTime = ConvertFractionalSecondsToFWCycleTime 2778 (pGlobalData->playFramePeriodNumerator, pGlobalData->playFramePeriodDenominator); 2779 2780 pGlobalData->fSharedDCLVars.fNumGroups = kNumPlayBufferGroups; 2781 pGlobalData->fSharedDCLVars.fGroupSize = pGlobalData->numDataPacketsPerGroup; 2782 2783 pageSize = PAGE_SIZE; 2784 numDataPacketsPerPage = pageSize / 2785 (pGlobalData->fDataPacketSize + kDVPacketCIPSize + kDVPacketAlignSlop); 2786#if ALT_TIMING 2787 numEmptyPackets = getEmptyPacketsPerGroup(pGlobalData, pGlobalData->numDataPacketsPerGroup) * kNumPlayBufferGroups; 2788#else 2789 numEmptyPackets = 2790 getEmptyPacketsPerGroup(pGlobalData, pGlobalData->numDataPacketsPerGroup * kNumPlayBufferGroups) + kNumPlayBufferGroups/2; 2791#endif 2792 2793 transmitBuffersSize = pGlobalData->numDataPacketsPerGroup * kNumPlayBufferGroups * pageSize; 2794 transmitBuffersSize /= numDataPacketsPerPage; 2795 // add pages for empty packets and time stamps 2796 emptySize = numEmptyPackets * (kDVPacketCIPSize + kDVPacketAlignSlop); 2797 // Allocate. 2798 //syslog(LOG_INFO, "DVWrite: IOMalloc: pGlobalData->pTransmitBuffers size %d, empty %d\n",transmitBuffersSize, emptySize); 2799 //pGlobalData->pTransmitBuffers = (UInt8 *)malloc( transmitBuffersSize + emptySize + pageSize ); 2800 pGlobalData->fStreamVars.fDCLBufferSize = 2801 transmitBuffersSize + emptySize + sizeof(UInt32)*kNumPlayBufferGroups; 2802 vm_allocate(mach_task_self(), (vm_address_t *)&pGlobalData->fStreamVars.fDCLBuffers, 2803 pGlobalData->fStreamVars.fDCLBufferSize, VM_FLAGS_ANYWHERE); 2804 //syslog(LOG_INFO, "DCL buffers at %p\n", pGlobalData->fStreamVars.fDCLBuffers); 2805 if( pGlobalData->fStreamVars.fDCLBuffers == NULL ) { 2806 res = kIOReturnNoMemory; 2807 goto bail; 2808 } 2809 bzero( pGlobalData->fStreamVars.fDCLBuffers, pGlobalData->fStreamVars.fDCLBufferSize ); 2810 pGlobalData->pEmptyTransmitBuffers = pGlobalData->fStreamVars.fDCLBuffers + transmitBuffersSize; 2811 pGlobalData->fSharedDCLVars.fTimeStampPtrs = (UInt32 *)(pGlobalData->pEmptyTransmitBuffers + emptySize); 2812 2813#ifdef kIDH_Verbose_Debug_Logging 2814 syslog(LOG_INFO, "DVLib: allocateBuffers end\n"); 2815#endif 2816 2817 return kIOReturnSuccess; 2818 2819bail: 2820 DVDisposeDCLOutput( pGlobalData ); 2821 2822#ifdef kIDH_Verbose_Debug_Logging 2823 syslog(LOG_INFO, "DVLib: allocateBuffers end:fail\n"); 2824#endif 2825 2826 return res; 2827} 2828 2829/* 2830 The write program is built of kNumPlayBufferGroups blocks of kDCLSendPacketStartOps, 2831 kNumDataPacketsPerPlayBufferGroup of the ops in each block send empty DV packets (just the CIP header) so that the timing 2832 comes out right. 2833 In addition, the callproc (DVHandleOutput) adjusts the blocks to skip an empty packet when the Mac is sending data too slowly. 2834 2835 LoopDCL: 2836 SetTagSyncBits(tag=1, sync=0) 2837 2838 kNumPlayBufferGroups* 2839 SendPacketStart (full packet/empty packet) 2840 or, for first empty packet in group: 2841 Jump (initially to SendEmptyLabel, altered to SkipEmptyLabel when falling behind) 2842 SendEmptyLabel: 2843 SendPacketStart (empty packet) 2844 SkipEmptyLabel: 2845 Jump (initially to EndOfGroup, except last group jumps to Underrun) 2846 EndOfGroup: 2847 TimeStamp 2848 UpdateDCLList(TimeStamp) 2849 CallProc(DVHandleOutput) 2850 UpdateDCLList(All the SendPackets) 2851 2852 Jump (LoopDCL) 2853 2854 Underrun: 2855 CallProc(DVHandleOutputUnderrun) 2856*/ 2857static IOReturn buildWriteProgram(DVGlobalOutPtr pGlobalData) 2858{ 2859 2860 UInt32 numEmptyPacketsInPlayBufferGroup; 2861 2862 DCLCommandPtr pDCLCommand; 2863 DCLCommandPtr pFirstBufferGroupDCLCommand; 2864 DCLLabelPtr pUnderrunDCLLabel, 2865 pBufferGroupDCLLabel, 2866 pDCLLabel; 2867 DCLTransferPacketPtr pDCLTransferPacket; 2868 DCLCallProcPtr pDCLCallProc; 2869 DCLSetTagSyncBitsPtr pDCLSetTagSyncBits; 2870 DCLJumpPtr pDCLJump, 2871 pBufferGroupDCLJump; 2872 DCLLabelPtr pBufferGroupSkipEmptyPacketDCLLabel; 2873 DCLUpdateDCLListPtr pDCLUpdateDCLList; 2874 DCLPtrTimeStampPtr pDCLTimeStamp; 2875 2876 DVLocalOutPtr pPlayBufferGroupData; 2877 UInt32 * pTransmitBuffer; 2878 UInt8 * pEmptyTransmitBuffer; 2879 volatile UInt32 * pTimeStampPtr; 2880 UInt32 bufferGroupNum; 2881 UInt32 dataPacketNum; 2882 UInt32 numPackets; 2883 UInt32 emptyPacketNumerator; 2884 UInt32 pageOffset; 2885 IOReturn res; 2886 2887 UInt32 totalDCLSize; 2888 UInt32 totalEmpty, emptySoFar; 2889 2890#ifdef kIDH_Verbose_Debug_Logging 2891 syslog(LOG_INFO, "DVLib: buildWriteProgram begin\n"); 2892#endif 2893 2894#if ALT_TIMING 2895 totalEmpty = getEmptyPacketsPerGroup(pGlobalData, pGlobalData->numDataPacketsPerGroup) * kNumPlayBufferGroups; 2896#else 2897 totalEmpty = getEmptyPacketsPerGroup(pGlobalData, pGlobalData->numDataPacketsPerGroup * kNumPlayBufferGroups) + kNumPlayBufferGroups/2; 2898#endif 2899 2900 // syslog(LOG_INFO, "total empty %d\n", totalEmpty); 2901 emptySoFar = 0; 2902 pTransmitBuffer = (UInt32 *) pGlobalData->fStreamVars.fDCLBuffers; 2903 pEmptyTransmitBuffer = pGlobalData->pEmptyTransmitBuffers; 2904 pTimeStampPtr = pGlobalData->fSharedDCLVars.fTimeStampPtrs; 2905 2906 ///////////////////////////////////////// 2907 // Start Up DCL Allocation Engine 2908 // Allocate DCL command pool. 2909 // 2910 // DCLs: 2911 // Start Label + SetTagSyncBits + DCLJump + DCLLabel + DCLCallProc 2912 // kNumPlayBufferGroups * ( (kNumDataPacketsPerPlayBufferGroup + numEmptyPacketsPerPlayBufferGroup) * DCLTransferPacket + 3 * DCLLabel + 2 * DCLJump + DCLPtrTimeStamp + DCLUpdateDCLList + DCLCallProc + DCLUpdateDCLList) 2913 2914 totalDCLSize = 2 * sizeof(DCLLabel) + sizeof(DCLSetTagSyncBits) + sizeof(DCLJump) + sizeof(DCLCallProc) + 2915 kNumPlayBufferGroups * (pGlobalData->numDataPacketsPerGroup * sizeof(DCLTransferPacket) + 3*sizeof(DCLLabel) + 2*sizeof(DCLJump) + sizeof(DCLPtrTimeStamp) + 2*sizeof(DCLUpdateDCLList) + sizeof(DCLCallProc) + totalEmpty * sizeof(DCLTransferPacket)); 2916 2917 res = AllocateDCLCommandPool(pGlobalData, totalDCLSize); 2918 if (res) 2919 goto bail; 2920 2921 //////////////////////////////////// 2922 // Actually Create DCL Program 2923 // 2924 2925 // Initialize total packet count. 2926 pGlobalData->totalPackets = 0; 2927 pGlobalData->activePackets = 0; 2928 2929 // Set isoch packet tag bits to the way DV likes 'em 2930 pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLSetTagSyncBits)); 2931 pDCLCommand = (DCLCommandPtr) pDCLSetTagSyncBits; 2932 pDCLSetTagSyncBits->opcode = kDCLSetTagSyncBitsOp; 2933 pDCLSetTagSyncBits->tagBits = 1; 2934 pDCLSetTagSyncBits->syncBits = 0; 2935 2936 // Set the pointer to the start of this DCL program 2937 pGlobalData->fStreamVars.pDCLList = pDCLCommand; 2938 2939 for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++) 2940 { 2941 // Allocate a buffer group data record. 2942 pPlayBufferGroupData = DVAllocatePlayBufferGroup( pGlobalData, bufferGroupNum); 2943 2944 // Initialize for loop. 2945 dataPacketNum = 0; 2946 numPackets = 0; 2947 emptyPacketNumerator = 0; 2948#if ALT_TIMING 2949 numEmptyPacketsInPlayBufferGroup = totalEmpty/kNumPlayBufferGroups; 2950#else 2951 numEmptyPacketsInPlayBufferGroup = (totalEmpty*(bufferGroupNum+1)+kNumPlayBufferGroups/2)/kNumPlayBufferGroups - emptySoFar; 2952#endif 2953 emptySoFar += numEmptyPacketsInPlayBufferGroup; 2954 pFirstBufferGroupDCLCommand = NULL; 2955 pBufferGroupSkipEmptyPacketDCLLabel = NULL; 2956 pGlobalData->fSharedDCLVars.fDataOffset[bufferGroupNum] = 2957 (UInt8*)pTransmitBuffer - pGlobalData->fStreamVars.fDCLBuffers; 2958 2959 // Create label for start of buffer group. 2960 pBufferGroupDCLLabel = (DCLLabelPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLLabel)); 2961 pPlayBufferGroupData->pStartOfBufferGroupDCLLabel = pBufferGroupDCLLabel; 2962 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pBufferGroupDCLLabel; 2963 pDCLCommand = (DCLCommandPtr) pBufferGroupDCLLabel; 2964 pBufferGroupDCLLabel->opcode = kDCLLabelOp; 2965 2966 while (dataPacketNum < pGlobalData->numDataPacketsPerGroup) 2967 { 2968 // Send a packet: CIP header + payload. 2969 pDCLTransferPacket = (DCLTransferPacketPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLTransferPacket)); 2970 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket; 2971 pDCLCommand = (DCLCommandPtr) pDCLTransferPacket; 2972 pDCLTransferPacket->opcode = kDCLSendPacketStartOp; 2973 pDCLTransferPacket->size = pGlobalData->fDataPacketSize + kDVPacketCIPSize; 2974 2975 // check for buffer crossing page 2976 pageOffset = (UInt32) (pTransmitBuffer + pGlobalData->fAlignQuadSize) & 0x0fff; 2977 if (pageOffset < (4*pGlobalData->fAlignQuadSize) && pageOffset > 0) 2978 { 2979 // if it does, increment buffer pointer 2980 // and lop off page rollover to start at next page 2981 pTransmitBuffer += pGlobalData->fAlignQuadSize; 2982 pTransmitBuffer = (UInt32 *)((UInt32)pTransmitBuffer & 0xfffff000); 2983 } 2984 2985 pDCLTransferPacket->buffer = (UInt8 *) pTransmitBuffer; 2986 // increment by multiple of 16 to maintain cache alignment 2987 pTransmitBuffer += pGlobalData->fAlignQuadSize; 2988 2989 // Save first data packet DCL command. 2990 if (pFirstBufferGroupDCLCommand == NULL) 2991 pFirstBufferGroupDCLCommand = (DCLCommandPtr) pDCLCommand; 2992 2993 dataPacketNum++; 2994 numPackets++; 2995 emptyPacketNumerator += numEmptyPacketsInPlayBufferGroup; 2996 2997 if (emptyPacketNumerator >= pGlobalData->numDataPacketsPerGroup) 2998 { 2999 // Add skip jump if this is the first empty packet in the buffer group. 3000 if (pBufferGroupSkipEmptyPacketDCLLabel == NULL) 3001 { 3002 pDCLJump = (DCLJumpPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLJump)); 3003 pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLJump = pDCLJump; 3004 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLJump; 3005 pDCLCommand = (DCLCommandPtr) pDCLJump; 3006 pDCLJump->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag; 3007 3008 pDCLLabel = (DCLLabelPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLLabel)); 3009 pPlayBufferGroupData->pBufferGroupDontSkipEmptyPacketDCLLabel = pDCLLabel; 3010 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLLabel; 3011 pDCLCommand = (DCLCommandPtr) pDCLLabel; 3012 pDCLLabel->opcode = kDCLLabelOp; 3013 pDCLJump->pJumpDCLLabel = pDCLLabel; 3014 } 3015 3016 // Send a packet. 3017 // Just CIP header. 3018 pDCLTransferPacket = (DCLTransferPacketPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLTransferPacket)); 3019 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket; 3020 pDCLCommand = (DCLCommandPtr) pDCLTransferPacket; 3021 pDCLTransferPacket->opcode = kDCLSendPacketStartOp; 3022 pDCLTransferPacket->buffer = pEmptyTransmitBuffer; 3023 pDCLTransferPacket->size = kDVPacketCIPSize; 3024 3025 // increment 16 bytes to maintain alignment 3026 pEmptyTransmitBuffer += kDVPacketCIPSize+kDVPacketAlignSlop; 3027 numPackets++; 3028 emptyPacketNumerator -= pGlobalData->numDataPacketsPerGroup; 3029 3030 // Add skip jump label if this is the first empty packet in the 3031 // buffer group. 3032 if (pBufferGroupSkipEmptyPacketDCLLabel == NULL) 3033 { 3034 // Add skip label. 3035 pDCLLabel = (DCLLabelPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLLabel)); 3036 pBufferGroupSkipEmptyPacketDCLLabel = pDCLLabel; 3037 pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLLabel = pBufferGroupSkipEmptyPacketDCLLabel; 3038 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLLabel; 3039 pDCLCommand = (DCLCommandPtr) pDCLLabel; 3040 pDCLLabel->opcode = kDCLLabelOp; 3041 } 3042 } 3043 } 3044 // Save number of packets in this buffer group, DCL update list size, and last 3045 // DCL command. 3046 pPlayBufferGroupData->numPackets = numPackets; 3047 pPlayBufferGroupData->pFirstBufferGroupDCLCommand = pFirstBufferGroupDCLCommand; 3048 pPlayBufferGroupData->pLastBufferGroupDCLCommand = (DCLCommandPtr) pDCLCommand; 3049 3050 // Create buffer group update list. 3051 DVCreatePlayBufferGroupUpdateList( pPlayBufferGroupData ); 3052 3053 // Update total packet count. 3054 pGlobalData->totalPackets += numPackets; 3055 pGlobalData->activePackets += numPackets; 3056 // work out if we should start by skipping this empty packet. 3057 3058#if ALT_TIMING 3059 { 3060 UInt32 nominalProgramCycleTime = 0; 3061 UInt32 nominalActivePackets = 0; 3062 SInt32 cycleDrift = 0; 3063 3064 nominalProgramCycleTime = ConvertFractionalSecondsToFWCycleTime( pGlobalData->playFramePeriodNumerator*(kNumPlayBufferGroups/2), 3065 pGlobalData->playFramePeriodDenominator ); 3066 nominalActivePackets = ((nominalProgramCycleTime & 0x01FFF000) >> 12); 3067 cycleDrift = pGlobalData->activePackets - ((nominalActivePackets*(bufferGroupNum+1)) / kNumPlayBufferGroups); 3068 3069// syslog(LOG_INFO, "Group %d, active %d, nominal %d, cycleDrift %d\n", bufferGroupNum+1, pGlobalData->activePackets-numPackets, ((nominalActivePackets*(bufferGroupNum)) / kNumPlayBufferGroups), cycleDrift); 3070 3071 if(cycleDrift > 0) { 3072 pGlobalData->activePackets--; 3073 pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLJump->pJumpDCLLabel = pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLLabel; 3074 pPlayBufferGroupData->skippingEmptyPacket = true; 3075 } 3076 else 3077 pPlayBufferGroupData->skippingEmptyPacket = false; 3078 } 3079#else 3080 emptyError = getEmptyPacketsPerGroup(pGlobalData, pGlobalData->numDataPacketsPerGroup*(bufferGroupNum+1)); 3081 emptyError = pGlobalData->activePackets - pGlobalData->numDataPacketsPerGroup*(bufferGroupNum+1) - emptyError; 3082 3083 //syslog(LOG_INFO, "Group %d, %d empty packets, Current error %d\n", bufferGroupNum, numEmptyPacketsInPlayBufferGroup, emptyError); 3084 if(emptyError > 0) { 3085 pGlobalData->activePackets--; 3086 pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLJump->pJumpDCLLabel = pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLLabel; 3087 pPlayBufferGroupData->skippingEmptyPacket = true; 3088 } 3089 else 3090 pPlayBufferGroupData->skippingEmptyPacket = false; 3091 #endif 3092 3093 // Get time stamp at end of buffer group. 3094 pDCLTimeStamp = (DCLPtrTimeStampPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLPtrTimeStamp)); 3095 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTimeStamp; 3096 pDCLCommand = (DCLCommandPtr) pDCLTimeStamp; 3097 pDCLTimeStamp->opcode = kDCLPtrTimeStampOp; 3098 *pTimeStampPtr = 0xffffffff; // Init to impossible time stamp 3099 pDCLTimeStamp->timeStampPtr = pTimeStampPtr++; 3100 3101 pPlayBufferGroupData->pBufferGroupTimeStampPtr = pDCLTimeStamp->timeStampPtr; 3102 pPlayBufferGroupData->timeStampUpdateDCLList = (DCLCommandPtr) pDCLTimeStamp; 3103 3104 // Create update DCL list to update time stamp. 3105 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLUpdateDCLList)); 3106 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList; 3107 pDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList; 3108 pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp; 3109 pDCLUpdateDCLList->dclCommandList = &(pPlayBufferGroupData->timeStampUpdateDCLList); 3110 pDCLUpdateDCLList->numDCLCommands = 1; 3111 3112#if 0 3113 // TODO: Merge this update DCL list with the timestamp update list, above!!!!! 3114 // Create update DCL list to update buffers. 3115 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLUpdateDCLList)); 3116 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList; 3117 pDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList; 3118 pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp; 3119 pDCLUpdateDCLList->dclCommandList = pPlayBufferGroupData->bufferGroupUpdateDCLList; 3120 pDCLUpdateDCLList->numDCLCommands = pPlayBufferGroupData->updateListSize; 3121#endif 3122 3123 // Create end of buffer group jump. 3124 pBufferGroupDCLJump = (DCLJumpPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLJump)); 3125 pPlayBufferGroupData->pEndOfBufferGroupDCLJump = pBufferGroupDCLJump; 3126 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pBufferGroupDCLJump; 3127 pDCLCommand = (DCLCommandPtr) pBufferGroupDCLJump; 3128 pBufferGroupDCLJump->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag; 3129 pBufferGroupDCLJump->pJumpDCLLabel = nil; // For now, this will be updated later! 3130 } 3131 3132 // Create label for underrun. 3133 pUnderrunDCLLabel = (DCLLabelPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLLabel)); 3134 pGlobalData->pUnderrunDCLLabel = pUnderrunDCLLabel; 3135 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pUnderrunDCLLabel; 3136 pDCLCommand = (DCLCommandPtr) pUnderrunDCLLabel; 3137 pUnderrunDCLLabel->opcode = kDCLLabelOp; 3138 3139 // Send a garbage packet (just CIP only!). Required for a valid DCL program! 3140 pDCLTransferPacket = (DCLTransferPacketPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLTransferPacket)); 3141 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket; 3142 pDCLCommand = (DCLCommandPtr) pDCLTransferPacket; 3143 pDCLTransferPacket->opcode = kDCLSendPacketStartOp; 3144 pDCLTransferPacket->buffer = pGlobalData->pEmptyTransmitBuffers; 3145 pDCLTransferPacket->size = kDVPacketCIPSize; 3146 3147 // Call underrun proc. 3148 // This is the last command. 3149 pDCLCallProc = (DCLCallProcPtr) AllocateDCLCommand (pGlobalData, sizeof (DCLCallProc)); 3150 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLCallProc; 3151 pDCLCallProc->pNextDCLCommand = NULL; 3152 pDCLCallProc->opcode = kDCLCallProcOp; 3153 pDCLCallProc->proc = DVHandleOutputUnderrun; 3154 pDCLCallProc->procData = (UInt32) pGlobalData; 3155 3156 // Fix up jump targets 3157 for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++) 3158 { 3159 pPlayBufferGroupData = &pGlobalData->fLocalDataArray[bufferGroupNum]; 3160 3161 if (bufferGroupNum == (kNumPlayBufferGroups-1)) 3162 pPlayBufferGroupData->pEndOfBufferGroupDCLJump->pJumpDCLLabel = 3163 pGlobalData->pUnderrunDCLLabel; 3164 else 3165 pPlayBufferGroupData->pEndOfBufferGroupDCLJump->pJumpDCLLabel = 3166 pGlobalData->fLocalDataArray[bufferGroupNum+1].pStartOfBufferGroupDCLLabel; 3167 } 3168 3169#ifdef kIDH_Verbose_Debug_Logging 3170 syslog(LOG_INFO, "DVLib: buildWriteProgram end\n"); 3171#endif 3172 return kIOReturnSuccess; 3173 3174bail: 3175 3176#ifdef kIDH_Verbose_Debug_Logging 3177 syslog(LOG_INFO, "DVLib: buildWriteProgram end:fail\n"); 3178#endif 3179 3180 return res; 3181} 3182 3183DVGlobalOutPtr DVAllocWrite(DVDevice *device, DVThread *thread) 3184{ 3185 DVGlobalOutPtr globs; 3186 3187#ifdef kIDH_Verbose_Debug_Logging 3188 syslog(LOG_INFO, "DVLib: DVAllocWrite begin\n"); 3189#endif 3190 3191 globs = malloc(sizeof(DVGlobalOut)); 3192 if(!globs) 3193 return NULL; 3194 bzero(globs, sizeof(DVGlobalOut)); 3195 initStream(&globs->fStreamVars, device, device->fOutPlug, device->fWriteChan, thread); 3196 globs->fUpdateBuffers = 1; 3197 3198#ifdef kIDH_Verbose_Debug_Logging 3199 syslog(LOG_INFO, "DVLib: DVAllocWrite end\n"); 3200#endif 3201 3202 return globs; 3203} 3204 3205IOReturn DVWriteSetSignalMode(DVGlobalOutPtr globs, UInt8 mode) 3206{ 3207 globs->fStreamVars.fSignalMode = mode; 3208 3209#ifdef kIDH_Verbose_Debug_Logging 3210 syslog(LOG_INFO, "DVLib: DVWriteSetSignalMode begin\n"); 3211#endif 3212 3213 switch (mode) 3214 { 3215 // NTSC SD or DVCPro25 3216 case kAVCSignalModeSD525_60: 3217 case kAVCSignalModeDVCPro525_60: 3218 globs->fStreamVars.fDVFrameSize = kFrameSize_SD525_60; 3219 break; 3220 3221 // PAL SD or DVCPro25 3222 case kAVCSignalModeSD625_50: 3223 case kAVCSignalModeDVCPro625_50: 3224 globs->fStreamVars.fDVFrameSize = kFrameSize_SD625_50; 3225 break; 3226 3227 // NTSC SDL 3228 case kAVCSignalModeSDL525_60: 3229 globs->fStreamVars.fDVFrameSize = kFrameSize_SDL525_60; 3230 break; 3231 3232 // PAL SDL 3233 case kAVCSignalModeSDL625_50: 3234 globs->fStreamVars.fDVFrameSize = kFrameSize_SDL625_50; 3235 break; 3236 3237 // NTSC DVCPro50 or HD 3238 case kAVCSignalModeDVCPro50_525_60: 3239 case kAVCSignalModeHD1125_60: 3240 globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro50_525_60; 3241 break; 3242 3243 // PAL DVCPro50 or HD 3244 case kAVCSignalModeDVCPro50_625_50: 3245 case kAVCSignalModeHD1250_50: 3246 globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro50_625_50; 3247 break; 3248 3249 // NTSC DVCPro100 3250 case kAVCSignalModeDVCPro100_525_60: 3251 globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro100_525_60; 3252 break; 3253 3254 // PAL DVCPro100 3255 case kAVCSignalModeDVCPro100_625_50: 3256 globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro100_625_50; 3257 break; 3258 3259 default: 3260 globs->fStreamVars.fDVFrameSize = kFrameSize_SD625_50; 3261 break; 3262 }; 3263 3264#ifdef kIDH_Verbose_Debug_Logging 3265 syslog(LOG_INFO, "DVLib: DVWriteSetSignalMode end\n"); 3266#endif 3267 3268 return kIOReturnSuccess; 3269} 3270 3271IOReturn DVWriteAllocFrames(DVGlobalOutPtr pGlobalData, UInt32 numFrames, 3272 DVFrameVars **frameVars, UInt8 **frames) 3273{ 3274 IOReturn err; 3275 3276#ifdef kIDH_Verbose_Debug_Logging 3277 syslog(LOG_INFO, "DVLib: DVWriteAllocFrames begin\n"); 3278#endif 3279 3280 do { 3281 err = DVAllocFrames(&pGlobalData->fStreamVars.fFrames, 3282 numFrames, 3283 pGlobalData->fStreamVars.fDVFrameSize, 3284 frameVars, 3285 frames); 3286 if(err != kIOReturnSuccess) 3287 break; 3288 err = allocateBuffers(pGlobalData); 3289 if(err != kIOReturnSuccess) 3290 break; 3291 3292 err = buildWriteProgram(pGlobalData); 3293 } while (0); 3294 3295#ifdef kIDH_Verbose_Debug_Logging 3296 syslog(LOG_INFO, "DVLib: DVWriteAllocFrames end\n"); 3297#endif 3298 3299 return err; 3300} 3301 3302UInt8 * DVWriteGetDCLBuffer(DVGlobalOutPtr pGlobalData, DVSharedVars **varPtr) 3303{ 3304 // Caller is now responsible for filling up the DCL buffers 3305 pGlobalData->fUpdateBuffers = 0; 3306 *varPtr = &pGlobalData->fSharedDCLVars; 3307 return pGlobalData->fStreamVars.fDCLBuffers; 3308} 3309 3310static IOReturn doDVWriteStart(DVGlobalOutPtr pGlobalData) 3311{ 3312 IOReturn err; 3313 DVLocalOutPtr pPlayBufferGroupData; 3314 UInt32 bufferGroupNum; 3315 int i; 3316 DVThread * dvThread = pGlobalData->fStreamVars.fThread; 3317 3318#ifdef kIDH_Verbose_Debug_Logging 3319 syslog(LOG_INFO, "DVLib: doDVWriteStart begin\n"); 3320#endif 3321 3322 do { 3323 3324 // Set up all of the buffer groups. 3325 //syslog(LOG_INFO, "DVWrite: Setup all of the buffer groups\n"); 3326 3327 pGlobalData->nextSYT = kPlaySYTDelay<<12; 3328 pGlobalData->nextDBC = 0; 3329 pGlobalData->nextDataPacketNum = 0; 3330 pGlobalData->pImageBuffer = NULL; 3331 pGlobalData->fSharedDCLVars.fDMAPos = 0; 3332 3333 pGlobalData->pendingDVWriteUnderrunHandler = false; 3334 pGlobalData->deferredDVWriteFree = false; 3335 pGlobalData->dvWriteStopInProgress = false; 3336 3337 pPlayBufferGroupData = &pGlobalData->fLocalDataArray[0]; 3338 for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++) 3339 { 3340 DVUpdateOutputBuffers( pPlayBufferGroupData); 3341 pPlayBufferGroupData = pPlayBufferGroupData->pNextLocalData; 3342 } 3343 err = openStream(&pGlobalData->fStreamVars, true, pGlobalData->fDataPacketSize + kDVPacketCIPSize); 3344 3345 for(i=0; i<kDVMaxStreamsActive; i++) { 3346 if(dvThread->fOutStreams[i] == NULL) { 3347 dvThread->fOutStreams[i] = pGlobalData; 3348 break; 3349 } 3350 else if(dvThread->fOutStreams[i] == pGlobalData) { 3351 break; // Happens when restarting. 3352 } 3353 } 3354 3355 } while (0); 3356 //syslog(LOG_INFO, "doDVWriteStart exit, err %x\n", err); 3357 3358#ifdef kIDH_Verbose_Debug_Logging 3359 syslog(LOG_INFO, "DVLib: doDVWriteStart end\n"); 3360#endif 3361 3362 return err; 3363} 3364 3365IOReturn DVWriteStart(DVGlobalOutPtr pGlobalData) 3366{ 3367 IOReturn err; 3368 3369#ifdef kIDH_Verbose_Debug_Logging 3370 syslog(LOG_INFO, "DVLib: DVWriteStart begin\n"); 3371#endif 3372 3373 err = DVRequest(pGlobalData->fStreamVars.fThread, doDVWriteStart, pGlobalData, 0); 3374 3375#ifdef kIDH_Verbose_Debug_Logging 3376 syslog(LOG_INFO, "DVLib: DVWriteStart end\n"); 3377#endif 3378 3379 return err; 3380} 3381 3382static void doDVWriteStop(DVGlobalOutPtr pGlobalData) 3383{ 3384 int i; 3385 3386#ifdef kIDH_Verbose_Debug_Logging 3387 syslog(LOG_INFO, "DVLib: doDVWriteStop begin\n"); 3388#endif 3389 3390 pGlobalData->dvWriteStopInProgress = true; 3391 3392 DVThread * dvThread = pGlobalData->fStreamVars.fThread; 3393 3394 for(i=0; i<kDVMaxStreamsActive; i++) { 3395 if(dvThread->fOutStreams[i] == pGlobalData) { 3396 dvThread->fOutStreams[i] = NULL; 3397 break; 3398 } 3399 } 3400 closeStream(&pGlobalData->fStreamVars); 3401 3402 BreakP2PConnectionForWrite(pGlobalData->fStreamVars.pDVDevice,0,pGlobalData->fStreamVars.fIsocChannel); 3403 3404 DVDisposeDCLOutput(pGlobalData); 3405 3406 pGlobalData->dvWriteStopInProgress = false; 3407 3408#ifdef kIDH_Verbose_Debug_Logging 3409 syslog(LOG_INFO, "DVLib: doDVWriteStop end\n"); 3410#endif 3411 3412} 3413 3414void DVWriteStop(DVGlobalOutPtr pGlobalData) 3415{ 3416#ifdef kIDH_Verbose_Debug_Logging 3417 syslog(LOG_INFO, "DVLib: DVWriteStop begin\n"); 3418#endif 3419 3420 DVRequest(pGlobalData->fStreamVars.fThread, doDVWriteStop, pGlobalData, 0); 3421 3422#ifdef kIDH_Verbose_Debug_Logging 3423 syslog(LOG_INFO, "DVLib: DVWriteStop end\n"); 3424#endif 3425 3426} 3427 3428void DVWriteFreeFrames(DVGlobalOutPtr globs) 3429{ 3430 3431#ifdef kIDH_Verbose_Debug_Logging 3432 syslog(LOG_INFO, "DVLib: DVWriteFreeFrames begin\n"); 3433#endif 3434 3435 DVFreeFrames(&globs->fStreamVars.fFrames); 3436 3437#ifdef kIDH_Verbose_Debug_Logging 3438 syslog(LOG_INFO, "DVLib: DVWriteFreeFrames end\n"); 3439#endif 3440 3441} 3442 3443void DVWriteFree(DVGlobalOutPtr globs) 3444{ 3445 3446#ifdef kIDH_Verbose_Debug_Logging 3447 syslog(LOG_INFO, "DVLib: DVWriteFree begin\n"); 3448#endif 3449 3450 if (globs->pendingDVWriteUnderrunHandler == true) 3451 globs->deferredDVWriteFree = true; 3452 else 3453 free(globs); 3454 3455#ifdef kIDH_Verbose_Debug_Logging 3456 syslog(LOG_INFO, "DVLib: DVWriteFree end\n"); 3457#endif 3458 3459} 3460 3461DVGlobalInPtr DVAllocRead(DVDevice *device, DVThread *thread) 3462{ 3463 DVGlobalInPtr globs; 3464 3465#ifdef kIDH_Verbose_Debug_Logging 3466 syslog(LOG_INFO, "DVLib: DVAllocRead begin\n"); 3467#endif 3468 3469 globs = malloc(sizeof(DVGlobalIn)); 3470 if(!globs) 3471 return NULL; 3472 bzero(globs, sizeof(DVGlobalIn)); 3473 initStream(&globs->fStreamVars, device, kNoPlug, device->fReadChan, thread); 3474 3475 // Set the initial read signal mode for standard DV. 3476 // This can be overriden later by a call to DVReadSetSignalMode 3477 if (device->standard == 0) 3478 DVReadSetSignalMode(globs,0x00); // NTSC-DV 3479 else 3480 DVReadSetSignalMode(globs,0x80); // PAL-DV 3481 3482 return globs; 3483 3484#ifdef kIDH_Verbose_Debug_Logging 3485 syslog(LOG_INFO, "DVLib: DVAllocRead end\n"); 3486#endif 3487 3488} 3489 3490IOReturn DVReadSetSignalMode(DVGlobalInPtr globs, UInt8 mode) 3491{ 3492 3493#ifdef kIDH_Verbose_Debug_Logging 3494 syslog(LOG_INFO, "DVLib: DVReadSetSignalMode begin\n"); 3495#endif 3496 3497 globs->fStreamVars.fSignalMode = mode; 3498 3499 switch (mode) 3500 { 3501 // NTSC SD or DVCPro25 3502 case kAVCSignalModeSD525_60: 3503 case kAVCSignalModeDVCPro525_60: 3504 globs->fStreamVars.fDVFrameSize = kFrameSize_SD525_60; 3505 break; 3506 3507 // PAL SD or DVCPro25 3508 case kAVCSignalModeSD625_50: 3509 case kAVCSignalModeDVCPro625_50: 3510 globs->fStreamVars.fDVFrameSize = kFrameSize_SD625_50; 3511 break; 3512 3513 // NTSC SDL 3514 case kAVCSignalModeSDL525_60: 3515 // override SDL modes to SD 3516 globs->fStreamVars.fSignalMode = kAVCSignalModeSD525_60; 3517 globs->fStreamVars.fDVFrameSize = kFrameSize_SD525_60; 3518 break; 3519 3520 // PAL SDL 3521 case kAVCSignalModeSDL625_50: 3522 // override SDL modes to SD 3523 globs->fStreamVars.fSignalMode = kAVCSignalModeSD625_50; 3524 globs->fStreamVars.fDVFrameSize = kFrameSize_SD625_50; 3525 break; 3526 3527 // NTSC DVCPro50 or HD 3528 case kAVCSignalModeDVCPro50_525_60: 3529 case kAVCSignalModeHD1125_60: 3530 globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro50_525_60; 3531 break; 3532 3533 // PAL DVCPro50 or HD 3534 case kAVCSignalModeDVCPro50_625_50: 3535 case kAVCSignalModeHD1250_50: 3536 globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro50_625_50; 3537 break; 3538 3539 // NTSC DVCPro100 3540 case kAVCSignalModeDVCPro100_525_60: 3541 globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro100_525_60; 3542 break; 3543 3544 // PAL DVCPro100 3545 case kAVCSignalModeDVCPro100_625_50: 3546 globs->fStreamVars.fDVFrameSize = kFrameSize_DVCPro100_625_50; 3547 break; 3548 3549 default: 3550 // override the specified mode if it's not one of our supported modes. 3551 globs->fStreamVars.fSignalMode = kAVCSignalModeSD625_50; 3552 globs->fStreamVars.fDVFrameSize = kFrameSize_SD625_50; 3553 break; 3554 }; 3555 3556 3557#ifdef kIDH_Verbose_Debug_Logging 3558 syslog(LOG_INFO, "DVLib: DVReadSetSignalMode end\n"); 3559#endif 3560 3561 return kIOReturnSuccess; 3562} 3563 3564IOReturn DVReadAllocFrames(DVGlobalInPtr globs, UInt32 numFrames, 3565 DVFrameVars **frameVars, UInt8 **frames) 3566{ 3567 IOReturn err; 3568 3569#ifdef kIDH_Verbose_Debug_Logging 3570 syslog(LOG_INFO, "DVLib: DVReadAllocFrames begin\n"); 3571#endif 3572 3573 err = DVAllocFrames(&globs->fStreamVars.fFrames, 3574 numFrames, 3575 globs->fStreamVars.fDVFrameSize, 3576 frameVars, 3577 frames); 3578 3579#ifdef kIDH_Verbose_Debug_Logging 3580 syslog(LOG_INFO, "DVLib: DVReadAllocFrames end\n"); 3581#endif 3582 3583 return err; 3584} 3585 3586static void doDVReadHandleInputUnderrun( DVGlobalInPtr pGlobalData ) 3587{ 3588 UInt32 timeNow, lastFrameTime; 3589 DVStream *stream; 3590 int pingPongNum; 3591 3592 3593 if ((pGlobalData->pendingDVReadUnderrunHandler == true) && (pGlobalData->deferredDVReadFree == true)) 3594 { 3595 // Free the globalin data struct 3596 free(pGlobalData); 3597 return; 3598 } 3599 pGlobalData->pendingDVReadUnderrunHandler = false; 3600 3601 stream = &pGlobalData->fStreamVars; 3602 3603 // See if stream still open. If not, we're done! 3604 if (stream->fIsochChannelRef == NULL) 3605 return; 3606 3607 (*stream->pFWDevice)-> 3608 GetCycleTime(stream->pFWDevice, &timeNow); 3609 syslog(LOG_INFO, "At %8.3f Req time %8.3f, now %8.3f\n", 3610 stream->fThread->setTimeoutTime, stream->fThread->requestTimeoutTime, CFAbsoluteTimeGetCurrent()); 3611 syslog(LOG_INFO, "DVReadHandleInputUnderrun: 0x%p, last block = %d, status %d, writer %d reader %d timeNow %x\n", 3612 pGlobalData, pGlobalData->fState, stream->fFrames.fStatus, 3613 stream->fFrames.fWriter, stream->fFrames.fReader, timeNow); 3614 3615 lastFrameTime = stream->fFrames.fFrameTime[(stream->fFrames.fWriter-1)%stream->fFrames.fNumFrames]; 3616 3617 // Stop 3618 (*stream->fIsochChannelRef)->Stop(stream->fIsochChannelRef); 3619 3620 // Fixup DCL program jumps and timestamps 3621 for (pingPongNum = 0; pingPongNum < kNumPingPongs; pingPongNum++) 3622 { 3623 if (pingPongNum < (kNumPingPongs-1)) 3624 ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort, 3625 pGlobalData->fLocalDataArray[pingPongNum].fStateJmp, pGlobalData->fLocalDataArray[pingPongNum+1].fStateLabel); 3626 else 3627 ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort, 3628 pGlobalData->fLocalDataArray[pingPongNum].fStateJmp, pGlobalData->fTerminal); 3629 3630 *pGlobalData->fLocalDataArray[pingPongNum].fTimeStampPtr = 0xffffffff; 3631 } 3632 3633 // Reset some vars 3634 pGlobalData->fState = 0; 3635 pGlobalData->fSynced = 0; 3636 pGlobalData->fRestarted = true; 3637 pGlobalData->fLastFrameTime = lastFrameTime; 3638 3639 // Restart 3640 (*stream->fIsochChannelRef)->Start(stream->fIsochChannelRef); 3641} 3642 3643static void DVReadHandleInputUnderrun( DCLCommandPtr pDCLCommandPtr ) 3644{ 3645 DVGlobalInPtr pGlobalData; 3646 3647#ifdef kIDH_Verbose_Debug_Logging 3648 syslog(LOG_INFO, "DVLib: DVReadHandleInputUnderrun begin\n"); 3649#endif 3650 3651 pGlobalData = (DVGlobalInPtr)((DCLCallProcPtr)pDCLCommandPtr)->procData; 3652 if (pGlobalData->dvReadStopInProgress == false) 3653 { 3654 pGlobalData->pendingDVReadUnderrunHandler = true; 3655 DVRequest(pGlobalData->fStreamVars.fThread, doDVReadHandleInputUnderrun, pGlobalData, 0); 3656 } 3657 3658#ifdef kIDH_Verbose_Debug_Logging 3659 syslog(LOG_INFO, "DVLib: DVReadHandleInputUnderrun end\n"); 3660#endif 3661 3662} 3663 3664static void DVStorePackets(DVLocalInPtr pLocalData) 3665{ 3666 DVGlobalInPtr pGlobalData; 3667 DCLCommandPtr pCurrentCmd; 3668 DCLTransferPacketPtr pDCLTransferPacket; 3669 UInt8 * pPacketBuffer; 3670 UInt32 packetHeader, packetSize, packetNum, packetPerFrame; 3671 bool vSyncDetected; 3672 UInt8 currentSequenceCount; 3673 int prevBlock; 3674 UInt8 fn; 3675 UInt8 stype; 3676 UInt32 actualModeFrameSize; 3677 short syncData; 3678 UInt32 cipHeader; 3679 3680#if TIMING 3681 CFAbsoluteTime cstart, cend; 3682 cstart = CFAbsoluteTimeGetCurrent(); 3683#endif 3684 3685 pGlobalData = pLocalData->pGlobalData; 3686 3687 //printf("Timestamp %p = %x\n", pLocalData->fTimeStampPtr, *pLocalData->fTimeStampPtr); 3688 3689 // Get info from ping pong data. 3690 pCurrentCmd = pLocalData->fFirstCmd; 3691 3692 // How many packets we talkin'? 3693 packetPerFrame = (pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_50) ? 3694 kPALNumDataPacketsPerDVFrame : kNTSCNumDataPacketsPerDVFrame; 3695 for ( packetNum = 0; packetNum < kNumPacketsPerInputBuffer; packetNum++ ) 3696 { 3697 // compute size of transfer 3698 pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentCmd; 3699 pPacketBuffer = (UInt8*)pDCLTransferPacket->buffer; 3700 packetHeader = *((UInt32*) pPacketBuffer); 3701 pPacketBuffer += 4; // 4 byte 1394 header 3702 packetSize = (packetHeader & kFWIsochDataLength) >> kFWIsochDataLengthPhase; 3703#if 1 3704 // Calculate fn 3705 fn = ((pPacketBuffer[2] & 0xC0) >> 6); 3706 if (fn == 0) 3707 fn = 1; 3708 else 3709 fn = 1 << fn; 3710 3711 // Check for corrupt packets, otherwise we may die horribly later in bcopy() 3712 if(packetSize < 8) { 3713 syslog(LOG_INFO, "DVStorePackets: size %d header 0x%x\n", packetSize, packetHeader); 3714 packetSize = 8; 3715 } 3716 else 3717 { 3718 // Check for packet size not matching CIP header specified packet size 3719 if(packetSize > 8 && packetSize != (pPacketBuffer[1]*4*fn) + 8) { 3720 syslog(LOG_INFO, "DVStorePackets: size %d header 0x%x\n", packetSize, packetHeader); 3721 packetSize = 8; 3722 } 3723 3724 // Check to make sure the signal mode in the CIP header is what we're expecting 3725 cipHeader = *(UInt32 *)(pPacketBuffer+4); 3726 cipHeader = EndianU32_BtoN( cipHeader ); 3727 if (pGlobalData->fStreamVars.fSignalMode != ((cipHeader >> 16) & 0xff)) 3728 { 3729 // CIP DV-mode doesn't match the configured mode! To prevent a crash, we 3730 // should only store packets if the CIP DV-mode frame-size will 3731 // fit into our allocated frame-buffers! 3732 3733 if (((cipHeader >> 16) & 0xff) & kAVCSignalModeMask_50) 3734 actualModeFrameSize = kPALNumDataPacketsPerDVFrame * (packetSize-8); 3735 else 3736 actualModeFrameSize = kNTSCNumDataPacketsPerDVFrame * (packetSize-8); 3737 3738 if (actualModeFrameSize > pGlobalData->fStreamVars.fDVFrameSize) 3739 { 3740 syslog(LOG_INFO, "DVStorePackets (received frame too large for frame-buffer): expected DV mode: %d, actual DV mode: %d\n", 3741 pGlobalData->fStreamVars.fSignalMode, (cipHeader >> 16) & 0xff); 3742 packetSize = 8; 3743 } 3744 } 3745 } 3746#endif 3747 // skip empty packets 3748 if( packetSize > 8 ) { 3749 // get current data block sequence counter value and increment saved value 3750 currentSequenceCount = pPacketBuffer[3]; 3751 3752 // Increment lastSequenceCount based on stream type 3753 // TODO: This will need to change to support 2x,4x modes on some signal types 3754 stype = pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_STYPE; 3755 switch (stype) 3756 { 3757 case kAVCSignalModeMask_DVCPro50: 3758 pGlobalData->lastSequenceCount += 2; 3759 break; 3760 3761 case kAVCSignalModeMask_DVCPro100: 3762 pGlobalData->lastSequenceCount += 4; 3763 break; 3764 3765 case kAVCSignalModeMask_SDL: 3766 case kAVCSignalModeMask_DVCPro25: 3767 case kAVCSignalModeMask_HD: 3768 default: // SD video stream 3769 pGlobalData->lastSequenceCount += 1; 3770 break; 3771 }; 3772 3773 // Want size minus CIP header 3774 packetSize -= 8; 3775 // detect vSync 3776 3777 syncData = *(short *)(pPacketBuffer + 8); syncData = EndianS16_BtoN(syncData); 3778 3779 vSyncDetected = ((syncData & 0xE0F8 ) == 0x0000 ); 3780 if( vSyncDetected ) { 3781 // Calculate when Sync arrived. 3782 UInt32 frameEnd = SubtractFWCycleTimeFromFWCycleTime(*pLocalData->fTimeStampPtr, (kNumPacketsPerInputBuffer - packetNum) << 12); 3783 UInt32 cip2 = *(UInt32 *)(pPacketBuffer+4); 3784 cip2 = EndianU32_BtoN( cip2 ); 3785 pGlobalData->fStreamVars.fSignalMode = (cip2 >> 16) & 0xff; 3786 packetPerFrame = (pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_50) ? 3787 kPALNumDataPacketsPerDVFrame : kNTSCNumDataPacketsPerDVFrame; 3788 // if we got our frameSync at the right time 3789 if( pGlobalData->packetCount == packetPerFrame ) { 3790 //printf("Frame received @ %x (w%d r%d)\n", frameEnd, pGlobalData->fStreamVars.fFrames.fWriter, pGlobalData->fStreamVars.fFrames.fReader); 3791 3792 // Set amount read 3793 DVSetInputFrameSizeAndMode(&pGlobalData->fStreamVars.fFrames, packetPerFrame * packetSize, 3794 pGlobalData->fStreamVars.fSignalMode, frameEnd); 3795 } 3796 else { 3797 //printf("Sync detected @ %x\n", frameEnd); 3798 if(pGlobalData->fRestarted) { 3799 // Calculate how many frames missed. 3800 // Fiddly mess from OHCI, have 16 bits from the middle of the cycle register (3 second bits + 13 cyle bits) 3801 UInt32 lastFrameTime; 3802 SInt32 cycleDiff, secsDiff; 3803 UInt32 dropped; 3804 3805 lastFrameTime = pGlobalData->fLastFrameTime; 3806 cycleDiff = ((frameEnd & 0x01FFF000) - (lastFrameTime & 0x01FFF000)); 3807 if(cycleDiff < 0) { 3808 cycleDiff += 8000 << 12; 3809 frameEnd -= 0x02000000; 3810 } 3811 secsDiff = (frameEnd & 0x0e000000) - (lastFrameTime & 0x0e000000); 3812 if(secsDiff < 0) 3813 secsDiff += 0x10000000; 3814 secsDiff >>= 25; 3815 cycleDiff >>= 12; 3816 cycleDiff += secsDiff * 8000; 3817 if(pGlobalData->fStreamVars.fSignalMode & kAVCSignalModeMask_50) 3818 dropped = (cycleDiff * kPALFrameRateNumerator + (4000*kPALFrameRateDenominator)) / (8000*kPALFrameRateDenominator); 3819 else 3820 dropped = (cycleDiff * kNTSCFrameRateNumerator + (4000*kNTSCFrameRateDenominator)) / (8000*kNTSCFrameRateDenominator); 3821 //printf("At sync, dropped %d frames\n", dropped); 3822 pGlobalData->fStreamVars.fFrames.fDroppedFrames += dropped; 3823 pGlobalData->fRestarted = false; 3824 } 3825 } 3826 3827 // start a new frame 3828 pGlobalData->packetCount = 0; 3829 pGlobalData->lastSequenceCount = currentSequenceCount; 3830 DVGetNextEmptyInputFrame(&pGlobalData->fStreamVars.fFrames, 3831 &(pGlobalData->pImageBuffer), 3832 pGlobalData->fStreamVars.fDVFrameSize); 3833 //printf("Filling frame %p (w%d r%d)\n", 3834 // pGlobalData->pImageBuffer, pGlobalData->fStreamVars.fFrames.fWriter, pGlobalData->fStreamVars.fFrames.fReader); 3835 3836 pGlobalData->fSynced = true; 3837 } 3838 3839 if(pGlobalData->fSynced) { 3840 // skip over CIP header 3841 pPacketBuffer += 8; // 8 bytes 3842 3843 if (currentSequenceCount == pGlobalData->lastSequenceCount && pGlobalData->packetCount < packetPerFrame) { 3844 // store the packet 3845 bcopy( pPacketBuffer, (void *)((UInt32) pGlobalData->pImageBuffer + (pGlobalData->packetCount * packetSize)), packetSize ); 3846 pGlobalData->packetCount++; 3847 } 3848 else { 3849 // IOLog("DVStorePacket: dropped frame: packet out of sequence\n"); 3850 // packet out of sequence or too many packets between vSync detection, start new frame 3851 //printf("Lost sync: %d-%d; %d-%d\n", 3852 // currentSequenceCount, pGlobalData->lastSequenceCount, pGlobalData->packetCount, packetPerFrame); 3853 pGlobalData->packetCount = 0; 3854 pGlobalData->fSynced = false; 3855 } 3856 } 3857 // Set last count to current count to resynch counts if bad sequence 3858 pGlobalData->lastSequenceCount = currentSequenceCount; 3859 } 3860 // update for next packet 3861 pCurrentCmd = pCurrentCmd->pNextDCLCommand; 3862 } 3863 3864 3865 // This block is ready for reuse, link previous block to this, this one to terminator 3866 3867 pGlobalData->fState = pLocalData->fBlockNum; 3868 3869 if(pLocalData->fBlockNum == 0) 3870 prevBlock = kNumPingPongs-1; 3871 else 3872 prevBlock = pLocalData->fBlockNum-1; 3873 3874 ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort, 3875 pGlobalData->fLocalDataArray[prevBlock].fStateJmp, pLocalData->fStateLabel); 3876 ModifyDCLJump(pGlobalData->fStreamVars.pFWLocalIsochPort, pLocalData->fStateJmp, pGlobalData->fTerminal); 3877 3878#if TIMING 3879 cend = CFAbsoluteTimeGetCurrent(); 3880 DVLog(pGlobalData->fStreamVars.fThread, 'isoc', cstart, cend); 3881#endif 3882} 3883 3884void DVReadPoll(DVGlobalInPtr globs) 3885{ 3886 int i, pos; 3887 pos = globs->fState; 3888 for(i=pos; i<kNumPingPongs; i++) 3889 if(*globs->fLocalDataArray[i].fTimeStampPtr != 0xffffffff) { 3890 DVStorePackets(&globs->fLocalDataArray[i]); 3891 *globs->fLocalDataArray[i].fTimeStampPtr = 0xffffffff; 3892 } 3893 3894 for(i=0; i<pos; i++) 3895 if(*globs->fLocalDataArray[i].fTimeStampPtr != 0xffffffff) { 3896 DVStorePackets(&globs->fLocalDataArray[i]); 3897 *globs->fLocalDataArray[i].fTimeStampPtr = 0xffffffff; 3898 } 3899} 3900 3901IOReturn DVReadStart(DVGlobalInPtr globs) 3902{ 3903 DCLCommandPtr opcodes; 3904 UInt8 * pingPongBuffer = NULL; 3905 UInt8 * pingPongPtr; 3906 UInt8 * pDCLCommand; 3907 DCLLabelPtr pStartDCLLabel; 3908 DCLLabelPtr pBlockDCLLabel; 3909 DCLLabelPtr pUnderrunDCLLabel; 3910 DCLTransferPacketPtr pDCLTransferPacket; 3911 DCLPtrTimeStampPtr pDCLTimeStamp; 3912// DCLCallProcPtr pDCLPingPongProc; 3913 DCLCallProcPtr pUnderrunDCLCallProc; 3914 DCLJumpPtr pDCLPingPongLoop; 3915 int pingPongNum, packetNum; 3916 UInt32 updateListSize; 3917 UInt32 bufferSize; 3918 DCLUpdateDCLListPtr pDCLUpdateDCLList; 3919 DCLCommandPtr *updateDCLList, *startUpdateDCLList; 3920 DVLocalInPtr pLocalData; 3921 IOReturn res; 3922 UInt32 * timeStampPtr; 3923 int i; 3924 UInt32 packetBufferSize; 3925 UInt32 alignedDVPacketSize; 3926 UInt32 pingPongBufferSize; 3927 3928#ifdef kIDH_Verbose_Debug_Logging 3929 syslog(LOG_INFO, "DVLib: DVReadStart begin\n"); 3930#endif 3931 3932 //syslog(LOG_INFO, "DVReadStart() %p\n", globs); 3933 3934 // init variables 3935 pingPongBuffer = NULL; 3936 3937 globs->fStreamVars.pDCLList = NULL; 3938 globs->ppUpdateDCLList = NULL; 3939 globs->pImageBuffer = NULL; 3940 globs->fStreamVars.fDCLBuffers = NULL; 3941// globs->fStreamVars.fSignalMode = kAVCSignalModeMask_50; // initialize to bigger packets per frame (PAL) 3942 globs->packetCount = 0; 3943 globs->fState = 0; 3944 3945 globs->pendingDVReadUnderrunHandler = false; 3946 globs->deferredDVReadFree = false; 3947 globs->dvReadStopInProgress = false; 3948 3949 switch (globs->fStreamVars.fSignalMode) 3950 { 3951 3952 case kAVCSignalModeSDL525_60: 3953 case kAVCSignalModeSDL625_50: 3954 packetBufferSize = 252; 3955 alignedDVPacketSize = 512; 3956 break; 3957 3958 case kAVCSignalModeDVCPro50_525_60: 3959 case kAVCSignalModeHD1125_60: 3960 case kAVCSignalModeDVCPro50_625_50: 3961 case kAVCSignalModeHD1250_50: 3962 packetBufferSize = 972; 3963 alignedDVPacketSize = 1024; 3964 break; 3965 3966 case kAVCSignalModeDVCPro100_525_60: 3967 case kAVCSignalModeDVCPro100_625_50: 3968 packetBufferSize = 1932; 3969 alignedDVPacketSize = 2048; 3970 break; 3971 3972 case kAVCSignalModeSD525_60: 3973 case kAVCSignalModeDVCPro525_60: 3974 case kAVCSignalModeSD625_50: 3975 case kAVCSignalModeDVCPro625_50: 3976 default: 3977 packetBufferSize = 492; 3978 alignedDVPacketSize = 512; 3979 break; 3980 }; 3981 3982 pingPongBufferSize = kNumPingPongs * kNumPacketsPerPingPong * alignedDVPacketSize; 3983 3984 // Create ping pong buffer, overrun buffer and time stamp buffer 3985 //zzz should allocate in initialization routine. 3986 bufferSize = pingPongBufferSize + alignedDVPacketSize + kNumPingPongs * sizeof(UInt32); 3987 vm_allocate(mach_task_self(), (vm_address_t *)&pingPongBuffer, 3988 bufferSize, VM_FLAGS_ANYWHERE); 3989 if (pingPongBuffer == NULL) 3990 { 3991 // syslog(LOG_INFO, "DVRead::Start : IOMalloc: pingPongBuffer failed\n"); 3992 res = kIOReturnNoMemory; 3993 goto bail; 3994 } 3995 timeStampPtr = (UInt32 *)(pingPongBuffer + pingPongBufferSize + alignedDVPacketSize); 3996 globs->fStreamVars.fDCLBuffers = pingPongBuffer; 3997 globs->fStreamVars.fDCLBufferSize = bufferSize; 3998 bzero( pingPongBuffer, bufferSize ); 3999 4000 // Get pointer to start of DCL commands and update list. 4001 opcodes = (DCLCommandPtr)malloc(kRecordDCLProgramSize); 4002 globs->fStreamVars.pDCLList = opcodes; 4003 if (opcodes == NULL) 4004 { 4005 // syslog(LOG_INFO, "DVRead::Start : IOMalloc: opcodes failed\n"); 4006 res = kIOReturnNoMemory; 4007 goto bail; 4008 } 4009 bzero( opcodes, kRecordDCLProgramSize ); 4010 pDCLCommand = (UInt8 *)opcodes; 4011 updateDCLList = (DCLCommandPtr *)malloc(kRecordNumDCLs * sizeof(DCLCommandPtr)); 4012 globs->ppUpdateDCLList = updateDCLList; 4013 if (updateDCLList == NULL) 4014 { 4015 // syslog(LOG_INFO, "DVRead::Start : IOMalloc: updateDCLList failed\n"); 4016 res = kIOReturnNoMemory; 4017 goto bail; 4018 } 4019 bzero( updateDCLList, kRecordNumDCLs * sizeof(DCLCommandPtr)); 4020 4021 // Create label for start of loop. 4022 pStartDCLLabel = (DCLLabelPtr) pDCLCommand; 4023 pDCLCommand += sizeof (DCLLabel); 4024 pStartDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4025 pStartDCLLabel->opcode = kDCLLabelOp; 4026 pingPongPtr = pingPongBuffer; 4027 4028 // Create kNumPingPongs ping pong buffer lists of 100 packets each. 4029 for (pingPongNum = 0; pingPongNum < kNumPingPongs; pingPongNum++) 4030 { 4031 // Create the DCL input record record and fill it in. 4032 pLocalData = &globs->fLocalDataArray[pingPongNum]; 4033 //pLocalData->fFirstCmd = (DCLCommandPtr) pDCLCommand; 4034 pLocalData->pGlobalData = globs; 4035 pLocalData->fBlockNum = pingPongNum; 4036 pLocalData->fTimeStampPtr = timeStampPtr; 4037 *timeStampPtr = 0xffffffff; 4038 startUpdateDCLList = updateDCLList; 4039 updateListSize = 0; 4040 // Create block start label 4041 pBlockDCLLabel = (DCLLabelPtr) pDCLCommand; 4042 pDCLCommand += sizeof (DCLLabel); 4043 pBlockDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4044 pBlockDCLLabel->opcode = kDCLLabelOp; 4045 pLocalData->fStateLabel = pBlockDCLLabel; 4046 4047 pLocalData->fFirstCmd = (DCLCommandPtr) pDCLCommand; 4048 4049 // Create transfer DCL for each packet. 4050 for (packetNum = 0; packetNum < kNumPacketsPerPingPong; packetNum++) 4051 { 4052 // Receive one packet up to packetBufferSize bytes. 4053 pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand; 4054 pDCLCommand += sizeof (DCLTransferPacket); 4055 pDCLTransferPacket->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4056 pDCLTransferPacket->opcode = kDCLReceivePacketStartOp; 4057 pDCLTransferPacket->buffer = pingPongPtr; 4058 pDCLTransferPacket->size = packetBufferSize; 4059 4060 *updateDCLList++ = (DCLCommandPtr) pDCLTransferPacket; 4061 updateListSize++; 4062 pingPongPtr += alignedDVPacketSize; 4063 } 4064 4065 // Create timestamp. 4066 pDCLTimeStamp = (DCLPtrTimeStampPtr) pDCLCommand; 4067 pDCLCommand += sizeof (DCLPtrTimeStamp); 4068 pDCLTimeStamp->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4069 pDCLTimeStamp->opcode = kDCLPtrTimeStampOp; 4070 pDCLTimeStamp->timeStampPtr = timeStampPtr++; 4071 *updateDCLList++ = (DCLCommandPtr) pDCLTimeStamp; 4072 updateListSize++; 4073 // Create update DCL list. 4074 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand; 4075 pDCLCommand += sizeof (DCLUpdateDCLList); 4076 pDCLUpdateDCLList->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4077 pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp; 4078 pDCLUpdateDCLList->dclCommandList = startUpdateDCLList; 4079 pDCLUpdateDCLList->numDCLCommands = updateListSize; 4080 4081 // Jump to next block (to terminator for last block) 4082 pDCLPingPongLoop = (DCLJumpPtr) pDCLCommand; 4083 pDCLCommand += sizeof (DCLJump); 4084 pDCLPingPongLoop->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4085 pDCLPingPongLoop->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag; 4086 pDCLPingPongLoop->pJumpDCLLabel = (DCLLabelPtr)pDCLCommand; 4087 pLocalData->fStateJmp = pDCLPingPongLoop; 4088 4089 } 4090 4091 // Create label for underrun. 4092 pUnderrunDCLLabel = (DCLLabelPtr) pDCLCommand; 4093 //pGlobalData->pUnderrunDCLLabel = pUnderrunDCLLabel; 4094 pDCLCommand += sizeof (DCLLabel); 4095 pUnderrunDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4096 pUnderrunDCLLabel->opcode = kDCLLabelOp; 4097 globs->fTerminal = pUnderrunDCLLabel; 4098 4099 // Create receive command for underrun packet 4100 pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand; 4101 pDCLCommand += sizeof (DCLTransferPacket); 4102 pDCLTransferPacket->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4103 pDCLTransferPacket->opcode = kDCLReceivePacketStartOp; 4104 pDCLTransferPacket->buffer = pingPongPtr; 4105 pDCLTransferPacket->size = packetBufferSize; 4106 4107 // Call underrun proc. 4108 pUnderrunDCLCallProc = (DCLCallProcPtr) pDCLCommand; 4109 pDCLCommand += sizeof (DCLCallProc); 4110 pUnderrunDCLCallProc->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4111 pUnderrunDCLCallProc->opcode = kDCLCallProcOp; 4112 pUnderrunDCLCallProc->proc = DVReadHandleInputUnderrun; 4113 pUnderrunDCLCallProc->procData = (UInt32)globs; 4114 4115 // Create closed loop at end to flush isoc packets out of FIFO 4116 4117 pUnderrunDCLLabel = (DCLLabelPtr) pDCLCommand; 4118 pDCLCommand += sizeof (DCLLabel); 4119 pUnderrunDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4120 pUnderrunDCLLabel->opcode = kDCLLabelOp; 4121 4122 // Create receive command for underrun packet 4123 pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand; 4124 pDCLCommand += sizeof (DCLTransferPacket); 4125 pDCLTransferPacket->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 4126 pDCLTransferPacket->opcode = kDCLReceivePacketStartOp; 4127 pDCLTransferPacket->buffer = pingPongPtr; 4128 pDCLTransferPacket->size = packetBufferSize; 4129 4130 // Loop back to keep dumping packets into the bucket 4131 // This is the last command. 4132 pDCLPingPongLoop = (DCLJumpPtr) pDCLCommand; 4133 pDCLPingPongLoop->pNextDCLCommand = NULL; 4134 pDCLPingPongLoop->opcode = kDCLJumpOp; 4135 pDCLPingPongLoop->pJumpDCLLabel = pUnderrunDCLLabel; 4136 4137 // Initialize isochronous channel. 4138 res = openStream(&globs->fStreamVars, false, kDVSDPayloadPacketSize + kDVPacketCIPSize); 4139 if(res != kIOReturnSuccess) 4140 goto bail; 4141 4142 for(i=0; i<kDVMaxStreamsActive; i++) { 4143 if(globs->fStreamVars.fThread->fInStreams[i] == NULL) { 4144 globs->fStreamVars.fThread->fInStreams[i] = globs; 4145 break; 4146 } 4147 } 4148 4149 //syslog(LOG_INFO, "DVRead::Started()\n"); 4150 4151#ifdef kIDH_Verbose_Debug_Logging 4152 syslog(LOG_INFO, "DVLib: DVReadStart end\n"); 4153#endif 4154 4155 return kIOReturnSuccess; 4156 4157bail: 4158 syslog(LOG_INFO, "DVRead::Start() failed: 0x%x\n", res); 4159 //Stop(); 4160 4161#ifdef kIDH_Verbose_Debug_Logging 4162 syslog(LOG_INFO, "DVLib: DVReadStart end:bail\n"); 4163#endif 4164 4165 return res; 4166} 4167 4168static IOReturn doDVReadStop(DVGlobalInPtr pGlobalData) 4169{ 4170 int i; 4171 4172#ifdef kIDH_Verbose_Debug_Logging 4173 syslog(LOG_INFO, "DVLib: doDVReadStop begin\n"); 4174#endif 4175 4176 pGlobalData->dvReadStopInProgress = true; 4177 4178 //syslog(LOG_INFO, "doDVReadStop()0x%x\n", pGlobalData); 4179 for(i=0; i<kDVMaxStreamsActive; i++) { 4180 if(pGlobalData->fStreamVars.fThread->fInStreams[i] == pGlobalData) { 4181 pGlobalData->fStreamVars.fThread->fInStreams[i] = NULL; 4182 break; 4183 } 4184 } 4185 4186#ifdef USE_P2P_CONNECTIONS_FOR_DV_READ 4187 BreakP2PConnectionForRead(pGlobalData->fStreamVars.pDVDevice,0,pGlobalData->fStreamVars.fIsocChannel); 4188#endif 4189 4190 closeStream(&pGlobalData->fStreamVars); 4191 if ( pGlobalData->ppUpdateDCLList) { 4192 free( pGlobalData->ppUpdateDCLList); //,kRecordNumDCLs * sizeof(DCLCommandPtr)); 4193 pGlobalData->ppUpdateDCLList = NULL; 4194 } 4195 if ( pGlobalData->fStreamVars.pDCLList) { 4196 //bzero(pGlobalData->fStreamVars.pDCLList, kRecordDCLProgramSize); 4197 free( pGlobalData->fStreamVars.pDCLList); //, kRecordDCLProgramSize); 4198 pGlobalData->fStreamVars.pDCLList = NULL; 4199 } 4200 if ( pGlobalData->fStreamVars.fDCLBuffers) { 4201 vm_deallocate(mach_task_self(), (vm_address_t)pGlobalData->fStreamVars.fDCLBuffers, 4202 pGlobalData->fStreamVars.fDCLBufferSize); 4203 pGlobalData->fStreamVars.fDCLBuffers = NULL; 4204 } 4205 4206 pGlobalData->dvReadStopInProgress = false; 4207 4208#ifdef kIDH_Verbose_Debug_Logging 4209 syslog(LOG_INFO, "DVLib: doDVReadStop end\n"); 4210#endif 4211 4212 return kIOReturnSuccess; 4213} 4214 4215void DVReadStop(DVGlobalInPtr pGlobalData) 4216{ 4217#ifdef kIDH_Verbose_Debug_Logging 4218 syslog(LOG_INFO, "DVLib: DVReadStop begin\n"); 4219#endif 4220 4221 DVRequest(pGlobalData->fStreamVars.fThread, doDVReadStop, pGlobalData, 0); 4222 4223#ifdef kIDH_Verbose_Debug_Logging 4224 syslog(LOG_INFO, "DVLib: DVReadStop end\n"); 4225#endif 4226 4227} 4228 4229void DVReadFreeFrames(DVGlobalInPtr globs) 4230{ 4231#ifdef kIDH_Verbose_Debug_Logging 4232 syslog(LOG_INFO, "DVLib: DVReadFreeFrames begin\n"); 4233#endif 4234 4235 DVFreeFrames(&globs->fStreamVars.fFrames); 4236 4237#ifdef kIDH_Verbose_Debug_Logging 4238 syslog(LOG_INFO, "DVLib: DVReadFreeFrames end\n"); 4239#endif 4240 4241} 4242 4243void DVReadFree(DVGlobalInPtr globs) 4244{ 4245 4246#ifdef kIDH_Verbose_Debug_Logging 4247 syslog(LOG_INFO, "DVLib: DVReadFree begin\n"); 4248#endif 4249 4250 // Defer freeing of the globalin data struct 4251 // if we have a pending input underrun to deal with. 4252 4253 if (globs->pendingDVReadUnderrunHandler == true) 4254 globs->deferredDVReadFree = true; 4255 else 4256 free(globs); 4257 4258#ifdef kIDH_Verbose_Debug_Logging 4259 syslog(LOG_INFO, "DVLib: DVReadFree end\n"); 4260#endif 4261 4262} 4263 4264void DVLog(DVThread *thread, UInt32 tag, CFAbsoluteTime start, CFAbsoluteTime end) 4265{ 4266#if TIMING 4267 Log * log; 4268 4269 log = &thread->fLog[thread->fLogPos]; 4270 log->tag = tag; 4271 log->start = start; 4272 log->end = end; 4273 thread->fLogPos++; 4274 if(thread->fLogPos >= kLogSize) 4275 thread->fLogPos = 0; 4276#endif 4277} 4278 4279void DVDumpLog(DVThread *thread) 4280{ 4281#if TIMING 4282 Log * log; 4283 UInt32 tag; 4284 int i; 4285 4286 for(i=thread->fLogPos; i<kLogSize; i++) { 4287 log = &thread->fLog[i]; 4288 tag = log->tag; 4289 if(tag) { 4290 syslog(LOG_INFO, "%d %c%c%c%c %8.3f to %8.3f\n", i, tag>>24, tag>>16, tag>>8, tag, log->start, log->end); 4291 } 4292 else 4293 syslog(LOG_INFO, "%d %x %8.3f to %8.3f\n", i, tag, log->start, log->end); 4294 } 4295 4296 for(i=0; i< thread->fLogPos; i++) { 4297 log = &thread->fLog[i]; 4298 tag = log->tag; 4299 if(tag) { 4300 syslog(LOG_INFO, "%d %c%c%c%c %8.3f to %8.3f\n", i, tag>>24, tag>>16, tag>>8, tag, log->start, log->end); 4301 } 4302 else 4303 syslog(LOG_INFO, "%d %x %8.3f to %8.3f\n", i, tag, log->start, log->end); 4304 } 4305#endif 4306} 4307