1/* 2 File: DVIsochComponent.c 3 4 Contains: DV version of the Isoch component 5 6 Version: 1.0 7 8 Copyright: � 1999-2000 by Apple Computer, Inc., all rights reserved. 9 10 File Ownership: 11 12 DRI: Richard Sepulveda 13 14 Other Contact: Jay Lloyd, Kevin Williams 15 16 Technology: DV 17 18 Writers: 19 20 (CK) Casey King 21 (SF) Sean Findley 22 (KW) Kevin Williams 23 (jkl) Jay Lloyd 24 (GDW) George D. Wilson Jr. 25 (SW) Sean Williams 26 (RS) Richard Sepulveda 27 28 Change History (most recent first): 29 30 <DV86> 3/16/00 SF [2438610] Put 1-second delay before checking camera 31 configuration. 32 <DV85> 2/14/00 CK [2432944] A little more to kill this bug <sf,cp> 33 <DV84> 2/10/00 SF [2432944] Add retries to bandwidth/channel allocations. 34 <DV83> 12/7/99 jkl Changed isocMedia to isochMedia. 35 <DV82> 11/1/99 jkl Added useCMP atom for turning on and off CMP. Moved CMP from 36 device specific to global. Moved the check for useCMP in the 37 resource to global allocate time. Changed CMPWrite to update the 38 expectedValue after each attempt to try to make it succeed. Some 39 time the Canon camera arbitrarily fails on this. This needs to 40 be redone so the entire operation can make sure the values are 41 correct. 42 <DV81> 10/25/99 KW If an error occurs during one of the calls to FSL during 43 cmpResetStage1..9, set the reset stage to kNoResetsProcessing. 44 This ensures that the next bus reset will be processed. 45 <DV80> 10/22/99 KW In updateDeviceList, do not zero out localFWReferenceID when a 46 device is removed. Zeroing out the localFWReferenceID causes the 47 cmp bus reset routines to stop propogating. In doAVCTransaction 48 deallocated the command object in the event of an error. 49 <DV79> 9/28/99 KW In IDHRead and IDHWrite, do not tear down read/write 50 notification if an error occurs. 51 <DV78> 9/21/99 jkl Backed out this read/write postEvent deferred stuff. A 52 stack-based variable was killing it and it needs more analysis. 53 <DV77> 9/20/99 jkl Really made the previous change. The DVFamilyLib postEvent was 54 commented as meaning to defer the rest of the read/write 55 complete notification to another deferred task, but was calling 56 CallSecondaryInterruptHandler2 to do it. Since the postEvents 57 for the read/write complete are already at deferred task, this 58 call basically did nothing. Now QueueSecondaryInterruptHandler 59 is used which definitely postpones the completion of postEvent 60 to another deferred task. This is now much more of a risky 61 change. 62 <76> 9/17/99 jkl Changed isoch read/write complete notification callProcs to be 63 called in another SIH. 64 <75> 8/29/99 RS Fixed problem with unfriendly clients who wouldn't cancel their 65 notifications before closing the isoch component. This could 66 cause a crash if we callback and the client isn't there anymore. 67 68 <74> 8/28/99 KW Dispose of all clients signed up for notifications when last 69 instance is closed. Fixes crashes for hot plugging. 70 <73> 8/17/99 jkl Changed CMP check to look for file type of INIT instead of gdfx. 71 <72> 8/16/99 RS Added isoch version atom to device list. 72 <71> 8/16/99 jkl Changed useCMP function to be off by default and look for a 73 'ucmp' resource id -20756 before using CMP. FireWire 2.2 or 74 greater check is still there. 75 <70> 8/16/99 jkl Replicated a default DV name atom property in old name property 76 location. Moved the bus reset notification proc with FireWire to 77 only be active during the isoch read and write. This makes sure 78 an instance is always open with the call proc address valid. 79 <69> 8/12/99 jkl Bracketed the name QTCopyAtomToPtr with lock/unlock container 80 calls. 81 <68> 8/10/99 jkl Added camera name updating routine. 82 <67> 8/9/99 RS Added IDHUpdateDeviceList() to API. The client can now change 83 r/w atoms in the internal device list. This currently includes 84 device name. Completed the bus reset generated IDHDeviceChanged 85 notification. The client can now be notified at interrupt time 86 whether a device state has been changed. 87 <66> 8/9/99 jkl Added handleBusReset call proc for interrupt level bus reset 88 notification. 89 <65> 8/9/99 jkl Added some camera name stuff. Moved the name atom to be a direct 90 child of the device atom. Default name is DV, if a name has been 91 entered for the device then use it, else if the vendor is known 92 then name is "vendor name DV". 93 <64> 8/6/99 jkl More work to get rid of DVFamily.h. Added defines for 94 getDeviceStandard AVC transaction. Also changed default camera 95 name to DV and left off standard. 96 <63> 8/6/99 jkl Changed kNTSCStandard to be ntscIn from QTComponents.h. 97 <62> 8/3/99 RS Properly handling device disconnect by propogating errors to 98 client(s). 99 <61> 7/29/99 jkl Set input channel when camera is listener during bus reset 100 handling. Some cameras do not follow the spec. Made sure to set 101 bus reset processing state to noProcessing after bus reset 102 processing has been interrupted. 103 <60> 7/28/99 jkl Added all of the bus reset stages for CMP. Still not robust 104 enough to handle errors during bus reset. Added Gestalt check 105 for FireWire 2.2 or greater. CMP does not run if this check 106 fails, allowing HaveBlue to run on FireWire 2.1. 107 <59> 7/28/99 jkl Changed FWRegisterDriver to use the device description instead 108 of driver refNum for client specific data. This lets the bus 109 reset handling get the device description. Nobody was using the 110 refNum. Turned on bus reset management. 111 <58> 7/28/99 jkl Moved isochPortCommandObject and asynchCommandObject allocation 112 to updateDeviceList, device added routine. Set max payload for 113 asynch command object to 512. Changed all of the cmp routines to 114 use the already allocated asynch command object. Changed local 115 pcrBuffer modifications to always use FWRead and 116 FWCompareAndSwap. Reduced overhead ID from 14 to 12. 117 <57> 7/23/99 jkl Turned off CMP bus reset handling. 118 <56> 7/22/99 jkl CMP, added correct speed, bandwidth, and overheadID calculations 119 and configuration to manage reconnections after bus reset. 120 <55> 7/20/99 jkl Fixed CMP bug where device not broadcasting could look 121 connected. Turned off broadcast bit to disconnect plug before 122 changing channel on a device only broadcasting. Sony is not 123 going to like this but it solves compatibility problems and 124 strictly follows the spec. 125 <54> 7/20/99 jkl Turned CMP on. Can create a file in Preferences folder called 126 "no cmp" to disable CMP. 127 <53> 7/18/99 jkl Fixed command object allocation in irmAllocateBandwidth. Fixed 128 initial overhead ID value for output plug control register. 129 <52> 7/16/99 jkl Added latest CMP code. 130 <51> 7/16/99 KW Moved FireWire callbacks to here. Register all devices with 131 FireWire that have ever been seen when the first isoch component 132 is opened. Likewise, Unregister all devices when the last isoch 133 component is closed. Ensure that the device notification ID for 134 a device is zeroed out after the notification has been disposed 135 of. 136 <50> 7/14/99 jkl Fixed dclProgramID mistake. 137 <49> 7/14/99 jkl Made sure isochPortCommandObjects are allocated safely and not 138 prematurely deallocated. Made sure disable read and write are 139 safe if extraneous calls are made to them. 140 <48> 7/13/99 jkl Reverted to previous version. Added fix for device control 141 getTimeCode failing after hot plug. 142 <47> 7/12/99 jkl Added a bunch of CMP stuff. Almost ready to turn on. 143 <46> 7/12/99 RS Changed component instance storage from system heap to 144 application heap to work around misbehaved apps that don't 145 CloseComponent. 146 <45> 7/10/99 RS Added notification for device added/removed so that we can 147 update the fwClientID in the device control component if the 148 camera is removed then re-added. 149 <44> 7/8/99 RS Fixed problem where the device control instance was being 150 prematurely released before all of the clients were finished. 151 <OX43> 7/7/99 SW Just removed some unused variables to stop compiler warnings. 152 <42> 7/7/99 jkl Cleared driverRefNum and fwClientID fields on device removed, 153 and updated them on device added for an already known device. 154 Also updated localFWReferenceID in case the same camera is 155 plugged into a different FireWire interface on the machine. 156 <41> 7/5/99 jkl Added SetMaxPayload for client. 157 <40> 7/2/99 RS Replaced event recording with logger to increase debug 158 capability. 159 <39> 7/1/99 RS Passing actual device description pointer instead of client 160 instance to isoch callbacks since the client can change deviceID 161 behind our back. 162 <38> 6/30/99 RS Fixed error codes returned in certain functions. Removed 163 openDeviceConnection() function because it is no long needed. 164 Fixed bug with device name atom. Fixed bug where we were 165 disabling read/writes in Close() if device was already possibly 166 disabled. 167 <37> 6/28/99 RS Moved IDHGetClientID from public to private call. Added 168 kIDHErrDeviceTimeout errors for sync read/writes timeouts. 169 Created public structs for IDHDimension and IDHResolution. Added 170 deviceID to atom tree. 171 <36> 6/28/99 RS Moved open device control from OpenDevice to SetConfig so that 172 client doesn't have to Open a device for read/write in order to 173 device control. Added device enable/disable notification. 174 Returning error on getConfig if no previous setConfig. 175 <35> 6/27/99 jkl Added default to NTSC in getDeviceStandard for devices that may 176 not have any device control capability. 177 <34> 6/26/99 jkl Integrated Richard's, Kevin's, and my changes to get read and 178 write working. Wired clock back up. Too much other stuff to 179 mention. Compare revisions if you really want to know. 180 <33> 6/24/99 RS Added the DVCWriteFrame() and DVGetNextEmptyFrame() equivalent. 181 We think all of the plumbing is in. So let the fun debug begin. 182 <32> 6/24/99 KW Not ready for prime time but things compile. Errors exist. 183 <31> 6/24/99 jkl Yanked all of the DV driver code into here. Some fun. 184 <OX30> 6/22/99 SW Add support for private calls to the IDH DV component instead of 185 just using morphed GetDeviceStatus() calls. 186 <29> 6/21/99 RS Added timeouts to synchronous reads and writes. The timeout has 187 initially been set to 1/15 second (2 frame times). 188 <28> 6/20/99 RS Moved device atom to device description structure to correctly 189 handle device added/removed issues. Added PAL audio format 190 config. Initialize device atom seed to 1. More cleanup. 191 <27> 6/19/99 RS Removed getting connectionID in IDHGetDeviceStatus (not needed). 192 <26> 6/19/99 RS Added deviceAtom and device standard to device description 193 structure. Allocating correct buffer size according to camera 194 format (ntsc or pal). Fixed bug where deviceID could change with 195 last connection going to zero (BAD). Alot of general cleanup. 196 <25> 6/18/99 RS Added kIDHUniqueIDType to device atom tree. Added some auxillary 197 functions to help traverse atom list. 198 <24> 6/18/99 GDW Made device control component handling global verses per 199 instance. 200 <23> 6/18/99 GDW Made some changes for additional device control component. 201 <22> 6/17/99 RS Made some changes to open and close device to handle device 202 access a little more gracefully. 203 <21> 6/17/99 RS Added FWClientID to device descriptor for device control. Fixed 204 bug when groing from write to read mode on a camera. Buffers 205 weren't being allocated. 206 <20> 6/17/99 jkl Added fwClientID to DVGetLocalFWReferenceID call to make the 207 fwClientID part of the device info so IDH can execute 208 getDeviceStandard by itself. 209 <19> 6/16/99 RS Added Firewire Node ID to device structure. Added AVC 210 transaction code to isoch component to work around DVDriver hang 211 problem. Check for sync I/O problem when called at non-task 212 time. 213 <18> 6/17/99 GDW Added more device control calls. 214 <17> 6/16/99 RS Do parameter checking on all public IDH functions. Turn on 215 exclusive access checking. Fix bug with I/O direction atom size. 216 <16> 6/16/99 GDW Add calls to device control component. 217 <15> 6/15/99 RS Updating device list everytime a device is added or removed. 218 Locking down atom container when we are copying data from atom 219 to pointer. 220 <14> 6/15/99 RS Added synchronous I/O and passing a 'nil' buffer into IDHWrite. 221 <13> 6/15/99 RS Changed IODirection on DV configs from input to InputAndOutput. 222 <12> 6/15/99 RS Merged DVFamilyLib into Isoch component. Added seed for device 223 list validity check from client. Create component globals in 224 register and free in unregister. Check seed when client does a 225 SetConfig. 226 <OX11> 6/11/99 SW MasterInterfaces integration 227 <10> 6/10/99 RS Added two new IDH functions ReleaseBuffer and CancelIO. Added 228 notification version of Reads and Writes. MAJOR CHANGES. 229 <9> 6/8/99 RS Fixed bug storing IDHDeviceStatus in atom list. 230 <8> 6/7/99 RS Keep track of open for reads/writes per device. 231 <7> 6/7/99 RS Saving open permissions in component instance. Replaced Fail 232 macro with new macro that displays function return code (better 233 for debug). Disable device on close based on permissions flags. 234 Returning bufferlist on read/write completion callback. Fixed 235 bug in IDHWrite where we weren't doing a DVCWriteFrame. 236 <6> 6/4/99 SW Adjust for slight changes in IDH.i 237 <5> 6/1/99 RS Added private functions to find device atom given any of its 238 siblings and a function to get device status given a device ID. 239 Added device standard and firewire node ID to status struct. 240 Save open permissions in device status. 241 <4> 5/24/99 RS Changed param type in SetDeviceConfig. Allow user to get device 242 status on any device (not just configured device). Changed 243 IDHIsochReadData and IDHIsochWriteData to IDHReadData and 244 IDHWrite. 245 <3> 5/24/99 RS We are now returning a copy of device descrip atom container. 246 <2> 5/20/99 RS Added queueing of isoch reads and write. Changed error return 247 code names. 248*/ 249 250/* ��� TO DO ��� 251 252 camera tracking 253 if a camera goes offline, do we return an error from getdevicestatus or set the active flag 254 super find atom 255 turn on permanent locks by client 256 review atom list (i.e. isoch container atom) 257*/ 258 259//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 260// Includes 261 262#include <DeviceControl.h> 263#include <DeviceControlPriv.h> 264#include <DriverServices.h> 265#include <Gestalt.h> 266#include <Resources.h> 267#include <Sound.h> 268#include <TextUtils.h> 269#include <DeviceControl.h> 270#include <IsochronousDataHandler.h> 271#include <IsochronousDataHandlerPriv.h> 272#include <Folders.h> 273 274#include <fp.h> 275#include <stddef.h> 276#include <stdio.h> 277 278#include "DVVers.h" 279#include "FireWire.h" 280#include "GenericDriverFamily.h" 281#include "LoggerAndDebugMacros.h" 282#include "OxcartDebug.h" 283#include "DVDCLOut.h" 284#include "DVDCLIn.h" 285 286#define kDVDeviceInfo 'ddin' // DV device info 287#define kBuffersPerDevice 5 // number of buffers per device for reads and writes 288#define kMaxDevicesActive 64 // max devices on firewire bus 289#define kMaxInstances 10 // max clients attached to a device 290#define kMaxNotifications 100 // 100 notifcaionts can be supported 291#define kNTSCCompressedBufferSize 120000 292#define kPALCompressedBufferSize 144000 293#define kIDHSeedAtomType 'seed' // seed for device atom validity 294#define kIDHDevicePresentType 'pres' // is device present? 295#define kServiceTypeDVServices 'avc ' 296#define kTimeoutDuration (1000 / 15) * durationMillisecond // 1/15 second (2 frame times) 297#define kMaxRetries 8 298 299#if PRAGMA_ALIGN_SUPPORTED 300#pragma options align=mac68k 301#endif 302 303#define kNoResetsProcessing 0 304#define kResetProcessing 1 305#define kResetInterrupted 2 306#define kResetFailed 3 307 308#define koPCRaddrHi 0x0000FFFF 309#define koPCRaddrLo 0xF0000904 310#define kiPCRaddrHi 0x0000FFFF 311#define kiPCRaddrLo 0xF0000984 312 313//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 314// globals 315ComponentInstance gCurInstance = 0; 316 317typedef struct IsochComponentInstance IsochComponentInstance, 318 *IsochComponentInstancePtr; 319typedef struct IsochComponentGlobals IsochComponentGlobals, 320 *IsochComponentGlobalsPtr, 321 **IsochComponentGlobalsHandle; 322 323 324struct IDHDVCompleteEvent { 325 IDHEventHeader eventHeader; 326 Ptr frameBuffer; 327 UInt32 bufferSize; 328 UInt32 fwCycleTime; 329 330}; 331typedef struct IDHDVCompleteEvent IDHDVCompleteEvent; 332 333 334// internal frame queue structure 335typedef struct QueueElement { 336 struct QElem *qLink; // standard queue vars 337 short qType; 338 short locks; // number of clients owning buffer 339 Ptr buffer; // the data 340 long size; // size of the data 341 } QueueElement, *QueueElementPtr; 342 343// describes a device on the firewire bus 344struct DeviceDescription { 345 IsochComponentGlobals *componentGlobals; // isoch component globals 346 QHdrPtr freeQueue, // holds free buffers 347 usedQueue; // holds buffers being used by client 348 IDHDeviceID deviceID; // persistent unique ID for each device 349 FWReferenceID fwClientID; // volatile FW Client ID for FSL, unique for all active devices 350 FWReferenceID localFWReferenceID; // reference to local node, may change if more than one FW interface is available 351 RegEntryID regEntryID; // used to register driver with FireWire 352 CSRNodeUniqueID uniqueID; // peristent 64-bit EUID for 1394 353 IDHNotificationID readIsochNotificationID; // read notification ID 354 IDHNotificationID writeIsochNotificationID; // write notification ID 355 IsochComponentInstance *instancePtr[kMaxInstances]; // clients that are attached to device 356 ComponentInstance deviceControlInstance; // device control component instance 357 IDHNotificationID deviceControlNotificationID; // tell me when device is added/removed so that i can adjust fwClientID 358 Component clock; // FireWire clock component, client's get their own instance, not sure why 359 UInt32 standard; // device standard 360 QTAtomContainer deviceContainer; // contains device database 361 IsochPortID isochPortID; // contains FireWire isoch port ID for active stream 362 IsochChannelID outputIsochChannelID; // FireWire channel ID for isoch transmit 363 IsochChannelID inputIsochChannelID; // FireWire channel ID for isoch receive 364 DVGlobalOutPtr pGlobalDVOutData; // global data for output DCL 365 DVGlobalInPtr pGlobalDVInData; // global data for input DCL 366 DCLProgramID dclProgramID; // ID of DCL program 367 FWCommandObjectID isochPortCommandObjectID; // FireWire command object used in init/release isoch port routines 368 FWCommandObjectID startIsochPortCommandObjectID; // FireWire command object used in start isoch port routines 369 FWCommandObjectID stopIsochPortCommandObjectID; // FireWire command object used in stop isoch port routines 370 FWCommandObjectID asynchCommandObjectID; // FireWire command object used in CMP 371 FWAddressSpaceID pcrID; // address space ID of plug control register 372 UInt32 pcrBuffer; // pcr buffer space, use FWRead and FWLock to access 373 UInt32 pcrIndex; // pcr number that was allocated 374 UInt32 resetStatus; // used in bus reset processing to keep up with reset stage 375 UInt32 buffer[2]; // buffer for pcr reads and locks 376 UInt32 expectedPCR; // value to check for successful update of PCR 377 UInt32 cmpBandwidth; // allocated isoch bandwidth for a stream, used in re-establishing connection after bus reset 378 UInt32 cmpOverheadID; // overheadID for a stream, used in re-establishing connection after bus reset 379 UInt32 cmpChannel; // channel for a stream, used in re-establishing connection after bus reset 380 DriverRefNum refNum; // volatile driver refNum, unique for all active devices 381 SInt16 deviceControlCount; // number of clients using device control 382 SInt16 nQueueElements; // holds number of buffers avail 383 SInt16 readLocks; // num clients that have device open for reads 384 SInt16 writeLocks; // num clients that have device open for writes 385 SInt16 exclusiveAccess; // does client have exclusive access? 386 Boolean complete; // I/O complete flag for synchronous operation 387 Boolean active; // device is currently online 388 }; 389 390typedef struct DeviceDescription DeviceDescription, *DeviceDescriptionPtr; 391 392struct ClientNotification { 393 ComponentInstance ihc; 394 IDHDeviceID deviceID; 395 IDHNotificationProc notificationProc; 396 IDHEvent events; 397 void *userData; 398 }; 399 400typedef struct ClientNotification ClientNotification; 401 402// component globals 403struct IsochComponentGlobals { 404 IsochComponentInstancePtr lastInstance; // last instance opened 405 UInt32 useCMP; // CMP off by default, turn on by adding 'ucmp' resource 406 DeviceDescription deviceDescription[kMaxDevicesActive]; // description of each device 407 ClientNotification clientNotification[kMaxNotifications]; // arbirtary # of notifications 408 UInt32 nDevices; // number of devices in the list 409 UInt32 seed; // keep track of device lists 410 IsochComponentInstance *localInstance; // our local instance 411 Boolean unRegistered; // was component unregistered? 412 }; 413 414// per component instance variables 415struct IsochComponentInstance { 416 Handle instanceHandle; // instance storage handle 417 ComponentInstance self; // this component 418 IsochComponentGlobalsPtr gGlobals; // pointer to component globals 419 QTAtomSpec currentConfig; // current device config set by client 420 IDHDeviceID deviceID; // persistent unique ID for each device, seed value 421 long permissions; // open permissions 422 QHdrPtr readQueue; // queue of read requests 423 QHdrPtr writeQueue; // queue of write requests 424 Boolean timeout; // timeout for synchronous reads 425 Boolean hasDeviceControl; // does this client have device control? 426 }; 427 428// convenience stuff for getDeviceStandard 429typedef struct AVCCTSFrameStruct { 430 UInt8 cmdType_respCode; // cmd type/response code 431 UInt8 headerAddress; 432 UInt8 opcode; 433 UInt8 operand[5]; 434} AVCCTSFrameStruct, *AVCCTSFrameStructPtr; 435 436enum { 437 kAVCStatusInquiryCommand = 0x01, 438 kAVCOutputSignalModeOpcode = 0x78, 439 kAVCInputSignalModeOpcode = 0x79, 440 kAVCSignalModeSD525_60 = 0x00, 441 kAVCSignalModeSDL525_60 = 0x04, 442 kAVCSignalModeHD1125_60 = 0x08, 443 kAVCSignalModeSD625_50 = 0x80, 444 kAVCSignalModeSDL625_50 = 0x84, 445 kAVCSignalModeHD1250_50 = 0x88, 446 kAVCSignalModeDummyOperand = 0xff 447}; 448 449/************************************************************************************/ 450// Begin Dispatch Stuff 451 452// Used by Type's .k.h to create prototypes for our routines 453#define IDH_BASENAME() IDH 454#define IDH_GLOBALS() ComponentInstance 455 456#define IDHDV_BASENAME() IDHDV 457#define IDHDV_GLOBALS() ComponentInstance 458 459#include "IsochronousDataHandler.k.h" 460#include "IsochronousDataHandlerPriv.k.h" 461 462// Used by Component Dispatch Helper to call our routines 463#define CALLCOMPONENT_BASENAME() IDH 464#define CALLCOMPONENT_GLOBALS() IsochComponentInstancePtr storage 465 466// Other defines for Component Dispatch Helper 467#define COMPONENT_DISPATCH_FILE "IDHDispatch.h" /* describes what to dispatch */ 468 469#define COMPONENT_UPP_SELECT_ROOT() IDH /* root for Type's UPP_PREFIX and SELECT_PREFIX */ 470#define COMPONENT_SUBTYPE_UPP_SELECT_ROOT() IDHDV 471 472#include "Components.k.h" /* std .k.h */ 473#include "QuickTimeComponents.k.h" /* Type & SubType .k.h */ 474#include "ComponentDispatchHelper.c" /* make our dispatcher and cando */ 475 476// End Dispatch Stuff 477/************************************************************************************/ 478 479// local prototypes 480OSErr addBuffersToQueue( DeviceDescription *deviceDescriptionPtr); 481OSErr checkSeed( IsochComponentGlobalsPtr gGlobals, QTAtomSpec *configID); 482OSErr closeDeviceControl( ComponentInstance ih, DeviceDescriptionPtr deviceDescriptionPtr); 483OSStatus deviceControlCallback( IDHGenericEvent *event, void *userData); 484OSErr doAVCTransaction( FWReferenceID ih, DVCTransactionParams* inTransaction); 485OSErr findAtom( QTAtomSpec *atomSpec, OSType theType, QTAtom *theAtom); 486OSErr findDeviceDescriptionforDevice( IsochComponentInstancePtr ih, UInt32 deviceID, DeviceDescription **deviceDescription); 487OSErr getDeviceID( QTAtomSpec *configID, UInt32 *deviceID); 488OSErr getDeviceStandard( FWReferenceID ih, UInt32 * pStandard ); 489OSStatus localCompletionRoutine(IDHGenericEvent *event, void *userData); 490OSStatus myTimerHandler( void *p1, void *p2); 491OSErr postEvent(IsochComponentGlobals* gGlobals, IDHDeviceID deviceID, 492 IDHEvent event, void* privateData); 493OSStatus postEventSIH(void* p1, void* p2); 494OSStatus readNotifyProc( IDHGenericEvent *event, void *userData); 495OSErr setupAVCTransaction( FWReferenceID ih, DVCTransactionParams *pParams); 496OSErr setupVideoAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard); 497OSErr setup32kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard); 498OSErr setup44kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard); 499OSErr setup48kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard); 500OSStatus writeNotifyProc( IDHGenericEvent *event, void *userData); 501OSStatus cameraNameLookup(DeviceDescriptionPtr pDeviceDescription, UInt8 *name); 502OSStatus updateCameraName(CSRNodeUniqueID *guid, UInt8 *name); 503OSErr updateDeviceList(IsochComponentInstancePtr ih, GDFDeviceEventData *pGDFData, IDHDeviceID *deviceID, Boolean doAdd); 504OSStatus handleDeviceAdded(ComponentInstance ihc, GDFDeviceEventData *pGDFData); 505OSStatus handleDeviceRemoved(ComponentInstance ihc, GDFDeviceEventData *pGDFData); 506OSStatus initIsochPort( FWClientInitIsochPortParams *pInitIsochPortParams, UInt32* outCommandAcceptance); 507OSStatus releaseIsochPort(FWClientReleaseIsochPortParams *pReleaseIsochPortParams, UInt32* outCommandAcceptance); 508OSStatus stopIsochPort( FWClientIsochPortControlParams *pIsochPortControlParams, UInt32* outCommandAcceptance); 509OSStatus startIsochPort(FWClientIsochPortControlParams *pIsochPortControlParams, UInt32* outCommandAcceptance); 510void isochPortCommandCompletionProc(FWCommandObjectID fwCommandObjectID, OSStatus commandStatus, UInt32 completionProcData); 511OSStatus doLocalTalkerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams); 512OSStatus doRemoteTalkerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams); 513OSStatus trialLocalTalkerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams); 514OSStatus trialRemoteTalkerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams); 515OSStatus doLocalListenerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams); 516OSStatus doRemoteListenerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams); 517OSStatus trialLocalListenerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams); 518OSStatus trialRemoteListenerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams); 519OSErr cmpNewPointToPointConnection(UInt32 pcrOffset, FWClientID clientID, UInt32 channel, UInt32 speed, UInt32 overhead, DeviceDescriptionPtr pDeviceDescription); 520OSErr cmpDisposePointToPointConnection(UInt32 pcrOffset, FWClientID clientID, DeviceDescriptionPtr pDeviceDescription); 521OSStatus irmReleaseChannel(FWClientID fwClientID, UInt32 channel, DeviceDescriptionPtr pDeviceDescription); 522OSStatus irmReleaseBandwidth(FWClientID fwClientID, UInt32 fwBandwidthUnits, DeviceDescriptionPtr pDeviceDescription); 523OSStatus irmAllocateChannel(FWClientID fwClientID, UInt32 *channel, DeviceDescriptionPtr pDeviceDescription); 524OSStatus irmAllocateBandwidth(FWClientID fwClientID, UInt32 fwBandwidthUnits, DeviceDescriptionPtr pDeviceDescription); 525UInt32 irmCalculateBandwidthUnits(UInt32 pcrValue); 526OSStatus cmpHandleLocalLock(FWClientAsynchRequestParamsPtr pFWClientAsynchRequestParams, UInt32 *pCommandAcceptance); 527OSErr cmpRead(UInt32 pcrOffset, FWClientID clientID, UInt32 *pcrValue, DeviceDescriptionPtr pDeviceDescription); 528OSErr cmpWrite(UInt32 pcrOffset, FWClientID clientID, UInt32 expectedPCRValue, UInt32 newPCRValue, DeviceDescriptionPtr pDeviceDescription); 529OSStatus cmpHandleBusReset(FWClientInterfaceParamsPtr pParams, UInt32 *pCommandAcceptance); 530OSErr cmpResetRead(UInt32 offsetLo, FWClientID clientID, FWCommandCompletionProcPtr completionProc, DeviceDescriptionPtr deviceDescriptionPtr); 531OSErr cmpResetWrite(UInt32 offsetLo, FWClientID clientID, FWCommandCompletionProcPtr completionProc, DeviceDescriptionPtr deviceDescriptionPtr); 532void cmpResetStageOne(DeviceDescriptionPtr pDeviceDescription); 533void cmpResetStageTwo(FWCommandObjectID theObjectID, OSStatus status, UInt32 data); 534void cmpResetStageThree(FWCommandObjectID theObjectID, OSStatus status, UInt32 data); 535void cmpResetStageFour(FWCommandObjectID theObjectID, OSStatus status, UInt32 data); 536void cmpResetStageFive(FWCommandObjectID theObjectID, OSStatus status, UInt32 data); 537void cmpResetStageSix(FWCommandObjectID theObjectID, OSStatus status, UInt32 data); 538void cmpResetStageSeven(FWCommandObjectID theObjectID, OSStatus status, UInt32 data); 539void cmpResetStageEight(FWCommandObjectID theObjectID, OSStatus status, UInt32 data); 540void cmpResetStageNine(FWCommandObjectID theObjectID, OSStatus status, UInt32 data); 541void cmpResetComplete(FWCommandObjectID theObjectID, OSStatus status, UInt32 data); 542OSErr enableRead(IsochComponentInstancePtr ih); 543OSErr enableWrite(IsochComponentInstancePtr ih); 544OSErr disableRead(IsochComponentInstancePtr ih); 545OSErr disableWrite(IsochComponentInstancePtr ih); 546OSErr dclInitOutput(DeviceDescriptionPtr pDeviceDescription, IsochComponentGlobals* isochComponentGlobals); 547DVLocalOutPtr dclAllocatePlayBufferGroup(DVGlobalOutPtr pGlobalData); 548DCLCommandPtr dclAllocateCommand(DCLCommandPoolPtr pDCLCommandPool, UInt32 dclSize); 549DCLCommandBlockPtr dclAllocateCommandBlock(DCLCommandPoolPtr pDCLCommandPool); 550DCLCommandPoolPtr dclAllocateCommandPool(void); 551void dclDeallocateCommandPool( DCLCommandPoolPtr pDCLCommandPool ); 552void dclDeallocatePlayBufferGroup( DVLocalOutPtr pLocalData ); 553void dclDeallocateCommandBlock(DCLCommandBlockPtr pDCLCommandBlock); 554void handleDVOutput(DCLCommandPtr pDCLCommandPtr); 555void handleDVOutputUnderrun(DCLCommandPtr pDCLCommandPtr); 556void updateDVOutputBuffers(DCLCommandPtr pDCLCommandPtr); 557void handleDVOutputUnderrunCompletion(FWCommandObjectID fwCommandObjectID, OSStatus commandStatus, UInt32 completionProcData); 558OSErr createDVPlayBufferGroupUpdateList( DVLocalOutPtr pLocalData); 559OSErr disposeDCLOutput( DVGlobalOutPtr pOutputData ); 560UInt32 addFWCycleTimeToFWCycleTime( UInt32 cycleTime1, UInt32 cycleTime2 ); 561UInt32 subtractFWCycleTimeFromFWCycleTime( UInt32 cycleTime1, UInt32 cycleTime2 ); 562UInt32 convertFractionalSecondsToFWCycleTime( UInt32 secondsNumerator, UInt32 secondsDenominator ); 563OSErr getNextFullOutputFrame( DVIODataPtr pOData, UInt32** ppFrame ); 564OSErr getNextEmptyOutputFrame( DVIODataPtr pOData, UInt32** ppFrame); 565OSErr queueNextFullOutputFrame( DVIODataPtr pOData, UInt32* pFrame ); 566OSErr getNextEmptyInputFrame( DVIODataPtr pIData, UInt32** ppFrame ); 567OSErr getNextFullInputFrame( DVIODataPtr pIData, UInt32** ppFrame ); 568OSErr releaseFullInputFrame( DVIODataPtr pIData, UInt32* pFrame ); 569Boolean isDVFinished( DVIODataPtr pIOData ); 570OSErr getCurrentDCLFrame( DVIODataPtr pIOData, UInt32** ppFrame ); 571OSErr initDVFrameOutput(UInt32 standard, DVIODataPtr* ppIOData); 572OSErr initDVFrameInput(UInt32 standard, DVIODataPtr* ppIOData); 573OSErr releaseDVFrameIO( DVIODataPtr pIOData ); 574void deleteDVFrameAndElement( DVFrameQElemPtr pQElem ); 575OSErr dclInitInput(DeviceDescriptionPtr pDeviceDescription, IsochComponentGlobals* isochComponentGlobals); 576void storeDVPackets( DCLCommandPtr pDCLCommandPtr ); 577OSErr disposeDCLInput( DVGlobalInPtr pInputData ); 578OSErr writeFrame( IsochComponentInstancePtr ih, char *tmpBuffPtr); 579OSErr getEmptyOutputFrame( IsochComponentInstancePtr ih, Ptr *tmpBuffPtr, UInt32 *size); 580OSStatus registerDevice(RegEntryID* inRegEntryID, FWDriverID* outDriverID, DeviceDescriptionPtr pDeviceDescription); 581Boolean useCMP(void); 582OSStatus handleBusReset(FWClientInterfaceParamsPtr pParams, UInt32 *pCommandAcceptance); 583 584//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 585// Component Routines 586 587#pragma mark - 588#pragma mark ���������� Standard Component Calls ���������� 589 590//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 591// Reverses anything done in the open call. 592// See this mark for more information on variables handling: GlobalsAndPrefs. 593static pascal ComponentResult IDHClose( IsochComponentInstancePtr iGlobals, ComponentInstance self ) 594{ 595 IsochComponentGlobalsHandle globHdl = 0L; // Handle to our globals 596 OSErr result = noErr; 597 IsochComponentGlobalsPtr gGlobals; 598 UInt32 i; 599 600 RecordEventLogger( 'isoc', 'clos', 0, (unsigned long) iGlobals); 601 602 FailMessage(self == 0); 603 604 globHdl = (IsochComponentGlobalsHandle) GetComponentRefcon((Component) self); // Try and get our refCon 605 if ( (globHdl == nil) || ((UInt32) globHdl == 0xFFFFFFFF) || (iGlobals == nil)) // If its all F's this is a close for register 606 { // otherwise it is a real close 607 return(noErr); 608 } 609 610 gGlobals = *globHdl; 611 612 if( iGlobals->deviceID && iGlobals->hasDeviceControl) // Close device control 613 { 614 DeviceDescription *deviceDescriptionPtr; 615 616 result = findDeviceDescriptionforDevice( iGlobals, iGlobals->deviceID, &deviceDescriptionPtr); 617 FailWithVal( result != noErr, Exit, result); 618 619 result = closeDeviceControl( (ComponentInstance) iGlobals, deviceDescriptionPtr); 620 FailMessage( result != noErr); 621 622 iGlobals->hasDeviceControl = false; 623 } 624 625 if( iGlobals->permissions) 626 IDHCloseDevice( (ComponentInstance) iGlobals); // close device in case the client forgot to 627 628 for( i=0; i<kMaxNotifications; ++i) // purge all notifications for this client 629 { 630 if( gGlobals->clientNotification[i].ihc == (ComponentInstance) iGlobals) 631 { 632 RecordEventLogger( 'isoc', 'clos', 'not-', (unsigned long) iGlobals); 633 634 gGlobals->clientNotification[i].deviceID = 0; 635 gGlobals->clientNotification[i].ihc = 0; 636 } 637 } 638 639 PBQueueDelete( iGlobals->readQueue); // delete queues 640 PBQueueDelete( iGlobals->writeQueue); 641 642 if (CountComponentInstances((Component)self) <= 1) // Is this the last close? 643 { 644 int i; 645 QueueElement *qep; 646 647 RecordEventLogger( 'isoc', 'clos', 0, 'last'); 648 649 for( i=0; i<kMaxDevicesActive; ++i) // free queue elements 650 { 651 DeviceDescription *deviceDescriptionPtr = &gGlobals->deviceDescription[i]; 652 653 // teardown read just in case the client forgot 654 if( deviceDescriptionPtr->deviceID && deviceDescriptionPtr->readIsochNotificationID) 655 { 656 result = IDHCancelNotification( (ComponentInstance)gGlobals->localInstance, deviceDescriptionPtr->readIsochNotificationID); 657 FailMessage( result != noErr); 658 659 result = IDHDisposeNotification( (ComponentInstance)gGlobals->localInstance, deviceDescriptionPtr->readIsochNotificationID); 660 FailMessage( result != noErr); 661 662 deviceDescriptionPtr->readIsochNotificationID = nil; 663 664 if( deviceDescriptionPtr->readLocks > 0) 665 { 666 result = disableRead((IsochComponentInstancePtr) iGlobals); 667 FailMessage( result != noErr); 668 669 deviceDescriptionPtr->readLocks = 0; 670 } 671 } 672 673 // teardown write just in case the client forgot 674 if( deviceDescriptionPtr->deviceID && deviceDescriptionPtr->writeIsochNotificationID) 675 { 676 result = IDHCancelNotification( (ComponentInstance)gGlobals->localInstance, deviceDescriptionPtr->writeIsochNotificationID); 677 FailMessage( result != noErr); 678 679 result = IDHDisposeNotification( (ComponentInstance)gGlobals->localInstance, deviceDescriptionPtr->writeIsochNotificationID); 680 FailMessage( result != noErr); 681 682 deviceDescriptionPtr->writeIsochNotificationID = nil; 683 684 if( deviceDescriptionPtr->writeLocks > 0) 685 { 686 result = disableWrite((IsochComponentInstancePtr) iGlobals); 687 FailMessage( result != noErr); 688 689 deviceDescriptionPtr->writeLocks = 0; 690 } 691 } 692 693 // free all of the queue buffers 694 while( PBDequeueFirst( gGlobals->deviceDescription[i].freeQueue, (QElemPtr *) &qep) == noErr) 695 { 696 if( qep) 697 { 698 if( qep->buffer) 699 DisposePtr( qep->buffer); 700 701 DisposePtr( (char *) qep); 702 } 703 } 704 705 while( PBDequeueFirst( gGlobals->deviceDescription[i].usedQueue, (QElemPtr *) &qep) == noErr) 706 { 707 if( qep) 708 { 709 if( qep->buffer) 710 DisposePtr( qep->buffer); 711 712 DisposePtr( (char *) qep); 713 } 714 } 715 716 gGlobals->deviceDescription[i].readLocks = gGlobals->deviceDescription[i].writeLocks = 0; 717 } 718 719 720 // Unregister all devices that have ever been seen. 721 for (i=0; i < gGlobals->nDevices; ++i) 722 { 723 result = FWUnregisterDriver(gGlobals->deviceDescription[i].fwClientID); 724 FailMessage(noErr != result); 725 } 726 727 // make sure all notifications are cancelled 728 for (i = 0; i < kMaxNotifications; ++i) 729 { 730 if( gGlobals->clientNotification[i].deviceID != 0 && 731 gGlobals->clientNotification[i].ihc != (ComponentInstance) gGlobals->localInstance) 732 { 733 gGlobals->clientNotification[i].deviceID = 0; 734 log_debugstr( "All notifications weren't cancelled in last close !!!"); 735 } 736 } 737 738 if( gGlobals->unRegistered) 739 { 740 for( i=0; i<kMaxDevicesActive; ++i) // free queue elements 741 { 742 DeviceDescription *deviceDescriptionPtr = &gGlobals->deviceDescription[i]; 743 744 result = closeDeviceControl( (ComponentInstance) gGlobals->localInstance, deviceDescriptionPtr); 745 FailMessage( result != noErr); 746 747 if( deviceDescriptionPtr->deviceContainer) // free device atoms 748 { 749 result = QTRemoveChildren( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer); 750 FailMessage( result != noErr); 751 752 result = QTDisposeAtomContainer( deviceDescriptionPtr->deviceContainer); 753 FailMessage( result != noErr); 754 755 deviceDescriptionPtr->deviceContainer = nil; 756 } 757 } 758 759 for( i=0; i<kMaxDevicesActive; ++i) 760 { 761 PBQueueDelete( gGlobals->deviceDescription[i].freeQueue); // delete device queues 762 PBQueueDelete( gGlobals->deviceDescription[i].usedQueue); 763 } 764 765 if( gGlobals->localInstance) 766 DisposePtr( (Ptr) gGlobals->localInstance); 767 768 HUnlock((Handle)globHdl); 769 DisposeHandle((Handle)globHdl); 770 SetComponentRefcon((Component) self, 0xFFFFFFFF); // component is now unused 771 gGlobals = nil; 772 } 773 } 774 775 if( iGlobals != nil && iGlobals->instanceHandle) // dispose instance handle 776 DisposeHandle( iGlobals->instanceHandle); 777 778Exit: 779 FailMessage( result != noErr); 780 781 return (result); 782} 783 784pascal ComponentResult IDHVersion( IsochComponentInstance *storage) 785{ 786#pragma unused (storage) 787 788 RecordEventLogger( 'isoc', 'vers', 0, 0); 789 790 return 0x10000; 791} 792 793pascal ComponentResult IDHTarget(struct IsochComponentInstance *storage, ComponentInstance parentComponent) 794{ 795#pragma unused (storage, parentComponent) 796 797 RecordEventLogger( 'isoc', 'targ', 0, 0); 798 799 return(noErr); 800} 801 802 803//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 804// Opens the component instance. 805// See this mark for more information on variables handling: GlobalsAndPrefs. 806static pascal ComponentResult IDHOpen( struct IsochComponentInstance *unused1, ComponentInstance self ) 807{ 808#pragma unused (unused1) 809 810 IsochComponentInstancePtr instancePtr = nil; // Pointer to instance globals 811 Handle instanceHandle = nil; // Handle to instance globals 812 ComponentResult result = noErr; // Result return by this routine 813 IsochComponentGlobalsHandle refConHdl = nil; 814 IsochComponentGlobalsPtr gGlobals = nil; 815 816 // Check the ComponentRefcon to see if this 'Open' request is part of the 817 // registering process (Open, Register, Close) or a true 'Open'. 818 // By convention in FWD, the ComponentRefcon is used to convey Registration 819 // information and to point to a structure of items that are shared by component 820 // instances as shown below: 821 // 822 // NULL 823 // The component has NOT been successfully registered. 824 // 825 // 0xFFFFFFFF 826 // The component has been successfully registered, but NO shared data 827 // has been allocated or initialized. 828 // 829 // Other Value 830 // Any other value means that the component has been successfully 831 // registered. Additionally, it points to the data that is shared 832 // between ComponentInstances. 833 834//��� RecordEventLogger( 'isoc', 'open', 0, 0); 835 836 SetComponentInstanceStorage(self, (Handle) 0); // save instance ptr in component 837 838 refConHdl = (IsochComponentGlobalsHandle) GetComponentRefcon((Component) self); 839 if ( refConHdl == nil ) // Is this a register call? 840 { 841 RecordEventLogger( 'isoc', 'open', 'reg ', 0); 842 gCurInstance = self; // Save for register 843 return(noErr); // Just return lt register happen 844 } 845 846 //====================================================================== 847 // Start allocating instance storage 848 849 ReserveMem( sizeof(IsochComponentInstance) ); 850 instanceHandle = NewHandleClear( sizeof(IsochComponentInstance) ); // allocate instance storage 851 FailWithAction( instanceHandle == nil, result = MemError(), BadExit); 852 853 HLock((Handle) instanceHandle); 854 instancePtr = (IsochComponentInstancePtr) *instanceHandle; 855 instancePtr->instanceHandle = instanceHandle; 856 instancePtr->self = self; 857 SetComponentInstanceStorage(self, (Handle) instancePtr); // save instance ptr in component 858 859 RecordEventLogger( 'isoc', 'open', 0, (unsigned long) instancePtr); 860 861Exit: 862 instancePtr->gGlobals = *refConHdl; 863 gGlobals = *refConHdl; 864 gGlobals->lastInstance = instancePtr; 865 866 // allocate queues for client read and write requests 867 result = PBQueueCreate( &instancePtr->readQueue); 868 FailWithVal( result != noErr, BadExit, result); 869 870 result = PBQueueInit( instancePtr->readQueue); 871 FailWithVal( result != noErr, BadExit, result); 872 873 result = PBQueueCreate( &instancePtr->writeQueue); 874 FailWithVal( result != noErr, BadExit, result); 875 876 result = PBQueueInit( instancePtr->writeQueue); 877 FailWithVal( result != noErr, BadExit, result); 878 879 FailMessage( result != noErr); 880 881 if (1 == CountComponentInstances((Component)self)) // Is this the first Open? 882 { 883 // Register all devices that are currently online. 884 UInt32 devIndex; 885 OSStatus status; 886 RecordEventLogger('isoc', '1st ', 'open', gGlobals->nDevices); 887 888 for (devIndex = 0; devIndex < gGlobals->nDevices; ++devIndex) 889 { 890 status = registerDevice( 891 &gGlobals->deviceDescription[devIndex].regEntryID, 892 &gGlobals->deviceDescription[devIndex].fwClientID, 893 &gGlobals->deviceDescription[devIndex]); 894 895 FailMessage(noErr != status); 896 } 897 } 898 899 return result; 900 901BadExit: 902 903 // chunk component stuff if last instance 904 if (CountComponentInstances((Component)self) == 1 && gGlobals != nil) 905 { 906 int i; 907 908 for( i=0; i<kMaxDevicesActive; ++i) 909 { 910 PBQueueDelete( gGlobals->deviceDescription[i].freeQueue); // release queues 911 PBQueueDelete( gGlobals->deviceDescription[i].usedQueue); // release queues 912 } 913 914 DisposeHandle( (Handle) refConHdl); 915 refConHdl = nil; 916 gGlobals = nil; 917 918 SetComponentRefcon((Component) self, (SInt32) 0xFFFFFFFF); 919 } 920 921 if( instanceHandle != nil) 922 { 923 DisposeHandle( instanceHandle); 924 instanceHandle = nil; 925 } 926 927 FailMessage( result != noErr); 928 929 return result; 930} 931 932//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 933// Registers the component. Returns non-zero result if component should not 934// be registered. This routine is called by the IDHOpen routine 935// after the instance globals are allocated, but before the component globals 936// are instantiated. This routine should not call any other functions that 937// require component globals or preferences. 938// See this mark for more information on variables handling: GlobalsAndPrefs. 939static pascal ComponentResult IDHRegister( IsochComponentInstancePtr globals ) 940{ 941#pragma unused( globals) 942 943 ComponentResult result = false; // Assume success 944 int i; 945 IsochComponentGlobalsHandle refConHdl; 946 IsochComponentGlobals *gGlobals; 947 IsochComponentInstance *localInstance; 948 949 RecordEventLogger( 'isoc', 'reg ', 0, 0); 950 951 //========================================================================= 952 // Allocate globals for all component instances 953 954 ReserveMem(sizeof(IsochComponentGlobals)); 955 refConHdl = (IsochComponentGlobalsHandle) NewHandleSysClear(sizeof(IsochComponentGlobals)); // Try and allocate refCon data 956 FailWithAction( refConHdl == nil, result = MemError(), Exit); 957 958 HLock( (Handle) refConHdl); 959 gGlobals = *refConHdl; 960 961 SetComponentRefcon((Component) gCurInstance, (long) refConHdl); 962 963 for( i=0; i<kMaxDevicesActive; ++i) // initialize device decription structs 964 { 965 int j; 966 967 // create free and used queue for each device 968 result = PBQueueCreate( &gGlobals->deviceDescription[i].freeQueue); 969 FailWithVal( result != noErr, Exit, result); 970 971 result = PBQueueInit( gGlobals->deviceDescription[i].freeQueue); 972 FailWithVal( result != noErr, Exit, result); 973 974 result = PBQueueCreate( &gGlobals->deviceDescription[i].usedQueue); 975 FailWithVal( result != noErr, Exit, result); 976 977 result = PBQueueInit( gGlobals->deviceDescription[i].usedQueue); 978 FailWithVal( result != noErr, Exit, result); 979 980 // initialize other variables 981 gGlobals->deviceDescription[i].nQueueElements = 0; 982 gGlobals->deviceDescription[i].deviceID = nil; 983 gGlobals->deviceDescription[i].readLocks = 0; 984 gGlobals->deviceDescription[i].writeLocks = 0; 985 gGlobals->deviceDescription[i].exclusiveAccess = 0; 986 gGlobals->deviceDescription[i].readIsochNotificationID = nil; 987 gGlobals->deviceDescription[i].writeIsochNotificationID = nil; 988 989 for( j=0; j<kMaxInstances; ++j) 990 gGlobals->deviceDescription[i].instancePtr[j] = nil; 991 } 992 993 // see if CMP should be turned on 994 gGlobals->useCMP = useCMP(); 995 996 localInstance = (IsochComponentInstance *) NewPtrSysClear( sizeof( IsochComponentInstance)); 997 FailWithAction( localInstance == NULL, result = MemError(), Exit); 998 999 localInstance->self = (ComponentInstance) localInstance; 1000 localInstance->gGlobals = gGlobals; // pointer to component globals 1001 1002 gGlobals->localInstance = localInstance; 1003 1004 gGlobals->seed = 1; 1005 gGlobals->nDevices = 0; 1006 1007Exit: 1008 return result; 1009} 1010 1011//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1012// The component is being unregistered. Mark the globals to be disposed. 1013// See this mark for more information on variables handling: GlobalsAndPrefs. 1014static pascal ComponentResult IDHUnregister( IsochComponentInstancePtr iGlobals ) 1015{ 1016 IsochComponentGlobalsPtr gGlobals; 1017 1018 RecordEventLogger( 'isoc', 'ureg', 0, 0); 1019 1020 FailIf(iGlobals == nil, Exit); 1021 1022 gGlobals = iGlobals->gGlobals; 1023 FailIf(gGlobals == nil, Exit); 1024 1025 gGlobals->unRegistered = true; 1026 1027Exit: 1028 return noErr; 1029} 1030 1031#pragma mark - 1032#pragma mark ���������� IDH Component Calls ���������� 1033 1034pascal ComponentResult IDHCancelNotification( ComponentInstance ihc, IDHNotificationID notificationID) 1035{ 1036 OSErr result = noErr; 1037 ClientNotification* clientNotification = (ClientNotification*)notificationID; 1038 1039 RecordEventLogger( 'isoc', 'canc', 'el ', 'noti'); 1040 1041 FailWithAction( clientNotification == nil, result = paramErr, Exit); 1042 1043 clientNotification->events = 0; 1044 1045Exit: 1046 return result; 1047} 1048 1049pascal ComponentResult IDHCancelPendingIO( ComponentInstance ihc, IDHParameterBlock *pb) 1050{ 1051 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1052 OSErr result = noErr; 1053 QHdrPtr queue = nil; 1054 1055 RecordEventLogger( 'isoc', 'canc', 'el ', 'pend'); 1056 1057 FailWithAction( pb == nil, result = paramErr, Exit); 1058 1059 if( ih->permissions & kIDHOpenForReadTransactions) 1060 queue = ih->readQueue; 1061 1062 if( ih->permissions & kIDHOpenForWriteTransactions) 1063 queue = ih->writeQueue; 1064 1065 if( queue) 1066 { 1067 result = PBDequeue( (QElem *) pb, queue); 1068// FailWithVal( result != noErr, Exit, result); 1069 if( result != noErr) 1070 goto Exit; 1071 } 1072 1073Exit: 1074 return result; 1075 1076} 1077 1078pascal ComponentResult IDHCloseDevice( ComponentInstance ihc) 1079{ 1080 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1081 OSErr result = noErr; 1082 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 1083 DeviceDescription *deviceDescriptionPtr = nil; 1084 short i; 1085 IDHParameterBlock *IORequest; 1086 1087 RecordEventLogger( 'isoc', 'clos', ' dev', 0); 1088 1089 FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); 1090 1091 if( ih->permissions == 0) // client has no open devices? 1092 goto Exit; 1093 1094 // flush IO queues 1095 while( PBDequeueFirst( ih->readQueue, (QElemPtr *) &IORequest) == noErr) ; 1096 while( PBDequeueFirst( ih->writeQueue, (QElemPtr *) &IORequest) == noErr) ; 1097 1098 result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); // find the device 1099 FailWithVal( result != noErr, Exit, result); 1100 1101 for( i=0; i<kMaxInstances; ++i) // remove instance from device list 1102 { 1103 if( deviceDescriptionPtr->instancePtr[i] == ih) 1104 { 1105 deviceDescriptionPtr->instancePtr[i] = nil; 1106 } 1107 } 1108 1109 FailWithAction( deviceDescriptionPtr->deviceID == nil, result = kIDHErrDeviceNotOpened, Exit); 1110 1111 if( ih->permissions & kIDHOpenForReadTransactions) // tear down read 1112 { 1113 if( --deviceDescriptionPtr->readLocks <= 0) // is device completely freed by clients? 1114 { 1115 if( deviceDescriptionPtr->readIsochNotificationID) 1116 { 1117 result = IDHCancelNotification( (ComponentInstance) gGlobals->localInstance, 1118 deviceDescriptionPtr->readIsochNotificationID); 1119 FailMessage( result != noErr); 1120 1121 result = IDHDisposeNotification( (ComponentInstance) gGlobals->localInstance, 1122 deviceDescriptionPtr->readIsochNotificationID); 1123 FailMessage( result != noErr); 1124 1125 deviceDescriptionPtr->readIsochNotificationID = nil; 1126 } 1127 1128 result = disableRead(ih); 1129 FailMessage( result != noErr); 1130 1131 deviceDescriptionPtr->exclusiveAccess = false; 1132 } 1133 } 1134 1135 if( ih->permissions & kIDHOpenForWriteTransactions) // tear down write 1136 { 1137 if( --deviceDescriptionPtr->writeLocks <= 0) // is device completely freed by clients? 1138 { 1139 if( deviceDescriptionPtr->writeIsochNotificationID) 1140 { 1141 result = IDHCancelNotification( (ComponentInstance) gGlobals->localInstance, 1142 deviceDescriptionPtr->writeIsochNotificationID); 1143 FailMessage( result != noErr); 1144 1145 result = IDHDisposeNotification( (ComponentInstance) gGlobals->localInstance, 1146 deviceDescriptionPtr->writeIsochNotificationID); 1147 FailMessage( result != noErr); 1148 1149 deviceDescriptionPtr->writeIsochNotificationID = nil; 1150 } 1151 1152 result = disableWrite(ih); 1153 FailMessage( result != noErr); 1154 1155 deviceDescriptionPtr->exclusiveAccess = false; 1156 } 1157 } 1158 1159 result = postEvent( ih->gGlobals, ih->deviceID, 1160 (ih->permissions & kIDHOpenForReadTransactions)?kIDHEventReadDisabled:kIDHEventWriteDisabled, nil); 1161 FailWithVal( result != noErr, Exit, result); 1162 1163Exit: 1164 ih->permissions = 0; // make sure device is closed 1165 1166 return result; 1167} 1168 1169pascal ComponentResult IDHDisposeNotification( 1170 ComponentInstance ihc, 1171 IDHNotificationID notificationID) 1172{ 1173 OSErr result = noErr; 1174 ClientNotification* clientNotification = (ClientNotification*)notificationID; 1175 1176 RecordEventLogger( 'isoc', 'disp', 'ose ', 'noti'); 1177 1178 FailWithAction( clientNotification == nil, result = paramErr, Exit); 1179 1180 clientNotification->deviceID = 0; 1181 1182Exit: 1183 return result; 1184} 1185 1186pascal ComponentResult IDHGetDeviceClock( ComponentInstance ihc, 1187 Component *clock ) 1188{ 1189 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1190 DeviceDescription *deviceDescriptionPtr; 1191 OSErr result = noErr; 1192 1193 RecordEventLogger( 'isoc', 'get ', 'clok', 0); 1194 1195 FailWithAction( clock == nil, result = paramErr, Exit); 1196 1197 FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); 1198 1199 result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); 1200 FailWithVal( result != noErr, Exit, result); 1201 1202// FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); 1203 1204 *clock = deviceDescriptionPtr->clock; 1205 1206Exit: 1207 return result; 1208} 1209 1210//��� USER BETTER KEEP HIS DEVICE LIST AROUND IF THIS IS TO MEAN ANYTHING 1211pascal ComponentResult IDHGetDeviceConfiguration( ComponentInstance ihc, 1212 QTAtomSpec *configID ) 1213{ 1214 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1215 OSErr result = noErr; 1216 1217 RecordEventLogger( 'isoc', 'get ', 'dev ', 'conf'); 1218 1219 FailWithAction( configID == nil, result = paramErr, Exit); 1220 FailWithAction( ih->currentConfig.container == nil || ih->currentConfig.atom == nil, 1221 result = kIDHErrDeviceNotConfigured, Exit); 1222 1223 *configID = ih->currentConfig; 1224 1225Exit: 1226 return result; 1227} 1228 1229pascal ComponentResult IDHGetDeviceControl(ComponentInstance ihc, ComponentInstance *deviceControl) 1230{ 1231 ComponentResult result = noErr; 1232 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1233 DeviceDescription *deviceDescriptionPtr; 1234 1235 RecordEventLogger( 'isoc', 'get ', 'dev ', 'ctrl'); 1236 1237 if ( deviceControl == nil ) 1238 return(paramErr); 1239 1240 FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); 1241 1242 result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); 1243 FailWithVal( result != noErr, Exit, result); 1244 1245 FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); 1246 1247 *deviceControl = deviceDescriptionPtr->deviceControlInstance; 1248 1249 FailMessageVal( *deviceControl == nil, (long) ih); 1250 1251Exit: 1252 return(result); 1253} 1254 1255//��� USER MUST FREE ATOM LIST WHEN FINISHED 1256pascal ComponentResult IDHGetDeviceList( ComponentInstance ihc, 1257 QTAtomContainer *deviceList ) 1258 1259{ 1260 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1261 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 1262 OSErr result = noErr; 1263 QTAtomContainer container = nil; 1264 short devIndex; 1265 UInt32 version; 1266 1267 RecordEventLogger( 'isoc', 'get ', 'dev ', 'list'); 1268 1269 FailWithAction( deviceList == nil, result = paramErr, Exit); 1270 1271 // create device atom list now 1272 result = QTNewAtomContainer( &container); 1273 FailWithVal( result != noErr, Exit, result); 1274 1275 // save seed 1276 result = QTInsertChild( container, kParentAtomIsContainer, kIDHSeedAtomType, 0, 0, 1277 sizeof( gGlobals->seed), &gGlobals->seed, nil); 1278 FailWithVal( result != noErr, Exit, result); 1279 1280 version = (DVVersion << 24) | (DVRevision << 16) | DVBuildNumber; 1281 1282 // save isoch version 1283 result = QTInsertChild( container, kParentAtomIsContainer, kIDHIsochVersionAtomType, 0, 0, 1284 sizeof( UInt32), &version, nil); 1285 FailWithVal( result != noErr, Exit, result); 1286 1287 // save useCMP value 1288 result = QTInsertChild( container, kParentAtomIsContainer, kIDHUseCMPAtomType, 0, 0, 1289 sizeof( UInt32), &gGlobals->useCMP, nil); 1290 FailWithVal( result != noErr, Exit, result); 1291 1292 // save each active device 1293 for( devIndex=0; devIndex<kMaxDevicesActive; ++devIndex) 1294 { 1295 if( gGlobals->deviceDescription[devIndex].deviceID != 0 && gGlobals->deviceDescription[devIndex].active) 1296 { 1297 result = QTInsertChildren( container, kParentAtomIsContainer, gGlobals->deviceDescription[devIndex].deviceContainer); 1298 FailWithVal( result != noErr, Exit, result); 1299 } 1300 } 1301 1302 *deviceList = container; 1303 1304Exit: 1305 if( result != noErr && container) 1306 { 1307 QTRemoveChildren( container, kParentAtomIsContainer); 1308 QTDisposeAtomContainer( container); 1309 container = nil; 1310 } 1311 1312 return result; 1313} 1314 1315pascal ComponentResult IDHGetDeviceStatus( ComponentInstance ihc, 1316 const QTAtomSpec *devSpec, 1317 IDHDeviceStatus *status ) 1318{ 1319 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1320 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 1321 OSErr result = noErr; 1322 IDHDeviceID deviceID = nil; 1323 QTAtom deviceInfoAtom, deviceAtom; 1324 QTAtomSpec volatileAtomSpec; 1325 long size; 1326 DeviceDescription *deviceDescriptionPtr; 1327 1328 RecordEventLogger( 'isoc', 'get ', 'stat', 0); 1329 1330 FailWithAction( devSpec == nil, result = paramErr, Exit); 1331 FailWithAction( status == nil, result = paramErr, Exit); 1332 1333 volatileAtomSpec = *devSpec; 1334 1335 result = checkSeed( ih->gGlobals, &volatileAtomSpec); 1336 if( result != noErr) 1337 goto Exit; 1338 1339 result = getDeviceID( &volatileAtomSpec, &deviceID); 1340 FailWithVal( result != noErr, Exit, result); 1341 1342 result = findDeviceDescriptionforDevice( ih, deviceID, &deviceDescriptionPtr); // find description for this device 1343 FailWithVal( result != noErr, Exit, result); 1344 1345 deviceAtom = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType, 1, nil); 1346 FailWithAction( deviceAtom == nil, result = kIDHErrDeviceList, Exit); 1347 1348 // find device status for this device 1349 deviceInfoAtom = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, deviceAtom, kDVDeviceInfo, 1, nil); 1350 FailWithAction( deviceInfoAtom == nil, result = kIDHErrDeviceList, Exit); 1351 1352 QTLockContainer( deviceDescriptionPtr->deviceContainer); 1353 1354 // get the value of the mediaType atom 1355 QTCopyAtomDataToPtr( deviceDescriptionPtr->deviceContainer, deviceInfoAtom, true, sizeof( IDHDeviceStatus), 1356 status, &size); 1357 1358 QTUnlockContainer( deviceDescriptionPtr->deviceContainer); 1359 1360 status->version = 100; 1361 status->physicallyConnected = true; 1362 status->readEnabled = deviceDescriptionPtr->readLocks; 1363 status->writeEnabled = deviceDescriptionPtr->writeLocks; 1364 status->exclusiveAccess = deviceDescriptionPtr->exclusiveAccess; 1365 status->currentBandwidth = 0; 1366 status->currentChannel = 0; 1367 1368 //��� need to make this work with camera tracking 1369 status->deviceActive = deviceDescriptionPtr->active; 1370 status->inputStandard = deviceDescriptionPtr->standard; 1371// JKL *** what to to with this? does this mean deviceID, cameraFWClientID, or localNodeFWClientID 1372// Think this is for clock to set the localFWReferenceID 1373 status->localNodeID = (PsuedoID) deviceDescriptionPtr->localFWReferenceID; 1374 1375 result = QTSetAtomData( deviceDescriptionPtr->deviceContainer, deviceInfoAtom, sizeof( IDHDeviceStatus), status); 1376 FailWithVal( result != noErr, Exit, result); 1377 1378Exit: 1379 return result; 1380} 1381 1382pascal ComponentResult IDHNewNotification( ComponentInstance ihc, 1383 IDHDeviceID deviceID, 1384 IDHNotificationProc notificationProc, 1385 void *userData, 1386 IDHNotificationID *notificationID) 1387{ 1388 IsochComponentGlobalsPtr gGlobals = ((IsochComponentInstancePtr)ihc)->gGlobals; 1389 UInt32 i; 1390 Boolean addedClient = false; 1391 OSErr result = noErr; 1392 1393 RecordEventLogger( 'isoc', 'new ', 'noti', 'fy '); 1394 1395 FailWithAction( notificationProc == nil, result = paramErr, Exit); 1396 FailWithAction( notificationID == nil, result = paramErr, Exit); 1397 1398 i = 0; 1399 while (i < kMaxNotifications) 1400 { 1401 if (0 == gGlobals->clientNotification[i].deviceID) 1402 { 1403 gGlobals->clientNotification[i].ihc = ihc; 1404 gGlobals->clientNotification[i].deviceID = deviceID; 1405 gGlobals->clientNotification[i].notificationProc = notificationProc; 1406 gGlobals->clientNotification[i].events = 0; 1407 gGlobals->clientNotification[i].userData = userData; 1408 *notificationID = (UInt32)&gGlobals->clientNotification[i]; 1409 addedClient = true; 1410 break; 1411 } 1412 1413 ++i; 1414 } 1415 1416 if (!addedClient) // List is full. Unable to add addtional clients 1417 result = paramErr; 1418 1419Exit: 1420 return result; 1421} 1422 1423pascal ComponentResult IDHNotifyMeWhen( ComponentInstance ihc, 1424 IDHNotificationID notificationID, 1425 IDHEvent events ) 1426{ 1427 OSErr result = noErr; 1428 ClientNotification* clientNotification = (ClientNotification*)notificationID; 1429 1430 RecordEventLogger( 'isoc', 'noti', 'when', events); 1431 1432 FailWithAction( clientNotification == nil, result = paramErr, Exit); 1433 1434 clientNotification->events = events; 1435 1436Exit: 1437 return result; 1438} 1439 1440pascal ComponentResult IDHOpenDevice( ComponentInstance ihc, UInt32 permissions) 1441{ 1442 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1443 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 1444 OSErr result = noErr; 1445 short i; 1446 DeviceDescription *deviceDescriptionPtr = nil; 1447 Component devcComp = 0; 1448 ComponentInstance devc = 0; 1449 1450 RecordEventLogger( 'isoc', 'open', ' dev', 0); 1451 1452 FailWithAction( permissions == 0, result = paramErr, Exit); 1453 1454 FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); 1455 1456 result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); 1457 FailWithVal( result != noErr, Exit, result); 1458 1459 FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); 1460 1461 // trying to reopen for read or write? 1462 if( ih->permissions & kIDHOpenForReadTransactions && permissions & kIDHOpenForReadTransactions) 1463 goto Exit; // don't do anything 1464 1465 if( ih->permissions & kIDHOpenForWriteTransactions && permissions & kIDHOpenForWriteTransactions) 1466 goto Exit; // don't do anything 1467 1468 // check for switching directions before opening 1469 FailWithAction( ih->permissions & kIDHOpenForReadTransactions && permissions & kIDHOpenForWriteTransactions, 1470 result = kIDHErrDeviceInUse, Exit); //��� 1471 1472 FailWithAction( ih->permissions & kIDHOpenForWriteTransactions && permissions & kIDHOpenForReadTransactions, 1473 result = kIDHErrDeviceInUse, Exit); //��� 1474 1475 // make sure device wasn't already opened for exclusive access 1476 FailWithAction( deviceDescriptionPtr->exclusiveAccess == true, result = kIDHErrDeviceInUse, Exit); 1477 1478 if( permissions & kIDHOpenForReadTransactions) // add buffers to queue for read devices 1479 { 1480 result = addBuffersToQueue( deviceDescriptionPtr); 1481 FailWithVal( result != noErr, Exit, result); 1482 } 1483 1484 // if user is opening for read, make sure device isn't already opened for writes 1485 if( permissions & kIDHOpenForReadTransactions) 1486 { 1487 FailWithAction( deviceDescriptionPtr->writeLocks, result = kIDHErrDeviceInUse, Exit); 1488 1489 if( deviceDescriptionPtr->readLocks == 0) 1490 { 1491 result = enableRead(ih); 1492 FailWithVal( result != noErr, Exit, result); 1493 } 1494 1495 ++deviceDescriptionPtr->readLocks; // keep track of read count 1496 } 1497 1498 // if user is opening for write, make sure device isn't already opened 1499 if( permissions & kIDHOpenForWriteTransactions) 1500 { 1501 FailWithAction( deviceDescriptionPtr->readLocks || deviceDescriptionPtr->writeLocks, result = kIDHErrDeviceInUse, Exit); 1502 1503 result = enableWrite(ih); 1504 FailWithVal( result != noErr, Exit, result); 1505 1506 deviceDescriptionPtr->writeLocks = 1; // keep track of write count 1507 } 1508 1509 if( permissions & kIDHOpenWithExclusiveAccess) 1510 deviceDescriptionPtr->exclusiveAccess = true; 1511 1512 ih->permissions = permissions; // save the permissions 1513 1514 // see if this client has already been registered for this device 1515 for( i=0; i<kMaxInstances; ++i) 1516 if( deviceDescriptionPtr->instancePtr[i] == ih) 1517 break; 1518 1519 if( i >= kMaxInstances) // client not registered? 1520 { 1521 for( i=0; i<kMaxInstances; ++i) 1522 { 1523 if( deviceDescriptionPtr->instancePtr[i] == nil) // find an empty slot, and add client 1524 { 1525 deviceDescriptionPtr->instancePtr[i] = ih; 1526 break; 1527 } 1528 } 1529 1530 FailWithAction( i >= kMaxInstances, result = kIDHErrInvalidIndex, Exit); // no slots available 1531 } 1532 1533 result = postEvent( ih->gGlobals, ih->deviceID, 1534 (permissions & kIDHOpenForReadTransactions)?kIDHEventReadEnabled:kIDHEventWriteEnabled, nil); 1535 FailWithVal( result != noErr, Exit, result); 1536 1537Exit: 1538 return result; 1539} 1540 1541// can be called synchronously at task level only 1542pascal ComponentResult IDHRead( ComponentInstance ihc, IDHParameterBlock *pb) 1543{ 1544 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1545 OSErr result = noErr; 1546 DeviceDescription *deviceDescriptionPtr; 1547 Boolean synchronous = false; 1548 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 1549 1550 RecordEventLogger( 'isoc', 'read', (unsigned long) ih->readQueue, (unsigned long) pb); 1551 1552 FailWithAction( pb == nil, result = paramErr, Exit); 1553 1554 // can't do sync reads at non-task level 1555 FailWithAction( pb->completionProc == nil && CurrentExecutionLevel() != kTaskLevel, result = paramErr, Exit); 1556 1557 FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); 1558 1559 result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); 1560 FailWithVal( result != noErr, Exit, result); 1561 1562 FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); 1563 1564 if( deviceDescriptionPtr->readIsochNotificationID == nil) 1565 { 1566 result = IDHNewNotification( (ComponentInstance) gGlobals->localInstance, ih->deviceID, readNotifyProc, 1567 (void *) ih->gGlobals, &deviceDescriptionPtr->readIsochNotificationID); 1568 FailWithVal( result != noErr, Exit, result); 1569 } 1570 1571 if ( deviceDescriptionPtr->readIsochNotificationID ) 1572 { 1573 result = IDHNotifyMeWhen( (ComponentInstance) gGlobals->localInstance, deviceDescriptionPtr->readIsochNotificationID, 1574 kIDHPrivateEventReadComplete); 1575 FailWithVal( result != noErr, Exit, result); 1576 } 1577 1578 if( pb->completionProc == nil) // synchronous read 1579 { 1580 synchronous = true; 1581 1582 pb->completionProc = localCompletionRoutine; 1583 pb->refCon = deviceDescriptionPtr; 1584 1585 deviceDescriptionPtr->complete = false; 1586 } 1587 1588 PBEnqueueLast( (QElemPtr) pb, ih->readQueue); // queue the read 1589 1590 if( synchronous) // synchronous read 1591 { 1592 AbsoluteTime expirationTime; 1593 TimerID theTimer; 1594 1595 ih->timeout = false; 1596 1597 // expiration is current time + 1/15 second (2 frame times) 1598 expirationTime = AddDurationToAbsolute( kTimeoutDuration, UpTime()); 1599 1600 result = SetInterruptTimer( &expirationTime, myTimerHandler, ih, &theTimer); 1601 FailWithVal( result != noErr, Exit, result); 1602 1603 while( deviceDescriptionPtr->complete == false && ih->timeout == false) // loop until complete or timeout 1604 ; 1605 1606 expirationTime = DurationToAbsolute( 0); 1607 CancelTimer( theTimer, &expirationTime); 1608 1609 pb->completionProc = nil; 1610 1611 FailWithAction( ih->timeout == true, result = kIDHErrDeviceTimeout, Exit); //��� correct error code 1612 } 1613 1614Exit: 1615 1616 return result; 1617} 1618 1619pascal ComponentResult IDHReleaseBuffer( ComponentInstance ihc, IDHParameterBlock *pb) 1620{ 1621 OSErr result = noErr; 1622 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1623 DeviceDescription *deviceDescriptionPtr; 1624 QueueElement *qep; 1625 1626 RecordEventLogger( 'isoc', 'rele', 'ase ', 'buff'); 1627 1628 FailWithAction( pb == nil, result = paramErr, Exit); 1629 1630 FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); 1631 1632 result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); 1633 FailWithVal( result != noErr, Exit, result); 1634 1635 qep = (QueueElement *) deviceDescriptionPtr->usedQueue->qHead; 1636 while( qep) // find this buffer in the list of used buffers 1637 { 1638 if( qep->buffer == pb->buffer) // is this our buffer? 1639 { 1640 if( --qep->locks <= 0) // are all of the locks gone? 1641 { 1642 qep->locks = 0; 1643 1644 // remove from used queue 1645 PBDequeue( (QElemPtr) qep, deviceDescriptionPtr->usedQueue); 1646 1647 // enqueue this list in the free queue 1648 PBEnqueueLast( (QElemPtr) qep, deviceDescriptionPtr->freeQueue); 1649 } 1650 1651 break; 1652 } 1653 1654 // check next element in the used queue 1655 qep = (QueueElement *) qep->qLink; 1656 } 1657 1658Exit: 1659 return result; 1660} 1661 1662pascal ComponentResult IDHSetDeviceConfiguration( ComponentInstance ihc, 1663 const QTAtomSpec *configID) 1664{ 1665 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1666 OSErr result = noErr; 1667 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 1668 QTAtomSpec volatileAtomSpec; 1669 IDHDeviceID previousDeviceID; 1670 DeviceDescription *deviceDescriptionPtr; 1671 1672 RecordEventLogger( 'isoc', 'set ', 'dev ', 'conf'); 1673 1674 FailWithAction( configID == nil, result = paramErr, Exit); 1675 1676 FailWithAction( configID->container == nil, result = paramErr, Exit); 1677 1678 // if the client is setting to the same config, then we are ok 1679 if( configID->container == ih->currentConfig.container && 1680 configID->atom == ih->currentConfig.atom) 1681 goto Exit; 1682 1683 // device already in use, please close device first 1684 FailWithAction( ih->permissions != 0, result = kIDHErrDeviceInUse, Exit); 1685 1686 previousDeviceID = ih->deviceID; 1687 1688 volatileAtomSpec = *configID; 1689 result = getDeviceID( &volatileAtomSpec, &ih->deviceID); 1690 FailWithVal( result != noErr, Exit, result); 1691 1692 result = checkSeed( ih->gGlobals, &volatileAtomSpec); 1693 FailWithVal( result != noErr, Exit, result); 1694 1695 ih->currentConfig = *configID; 1696 1697 result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); 1698 FailWithVal( result != noErr, Exit, result); 1699 1700 FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); 1701 1702 // if this client already has device control, free the previous connection 1703 if( previousDeviceID && ih->hasDeviceControl) 1704 { 1705 DeviceDescription *deviceDescriptionPtr2; 1706 1707 result = findDeviceDescriptionforDevice( ih, previousDeviceID, &deviceDescriptionPtr2); 1708 FailWithVal( result != noErr, Exit, result); 1709 1710 result = closeDeviceControl( ihc, deviceDescriptionPtr2); 1711 FailMessage( result != noErr); 1712 1713 ih->hasDeviceControl = false; 1714 } 1715 1716 // ======================================================================= 1717 // All should be good here from a device stand point, now open the device 1718 // control component. If the devc is not nil either we didn't release it 1719 // from close or the same client is calling open again. 1720 1721 if ( deviceDescriptionPtr->deviceControlInstance == nil) 1722 { 1723 ComponentDescription devcDesc; 1724 Component devcComp; 1725 ComponentInstance devc; 1726 1727 devcDesc.componentType = kDeviceControlComponentType; 1728 devcDesc.componentSubType = kDeviceControlSubtypeFWDV; 1729 devcDesc.componentManufacturer = 0; 1730 devcDesc.componentFlags = 0L; 1731 devcDesc.componentFlagsMask = 0L; 1732 1733 devcComp = FindNextComponent( devcComp, &devcDesc); 1734 FailMessage( devcComp == nil); 1735 1736 if ( devcComp ) 1737 { 1738 result = OpenAComponent(devcComp, &devc); 1739 FailWithVal( result != noErr, Exit, result); 1740 1741 result = DeviceControlSetDeviceConnectionID(devc, (DeviceConnectionID) deviceDescriptionPtr->fwClientID); //��� deviceID); 1742 FailWithVal( result != noErr, Exit, result); 1743 1744 result = DeviceControlEnableAVCTransactions(devc); 1745 FailWithVal( result != noErr, Exit, result); 1746 1747 deviceDescriptionPtr->deviceControlInstance = devc; 1748 1749 // now sign up for callback in case device is added or removed and we need to update connectionID 1750 if( deviceDescriptionPtr->deviceControlNotificationID == nil) 1751 { 1752 result = IDHNewNotification( (ComponentInstance) gGlobals->localInstance, ih->deviceID, deviceControlCallback, deviceDescriptionPtr, 1753 &deviceDescriptionPtr->deviceControlNotificationID); 1754 FailWithVal( result != noErr, Exit, result); 1755 } 1756 1757 if ( deviceDescriptionPtr->deviceControlNotificationID ) 1758 { 1759 result = IDHNotifyMeWhen( (ComponentInstance) gGlobals->localInstance, deviceDescriptionPtr->deviceControlNotificationID, 1760 kIDHEventDeviceAdded | kIDHEventDeviceRemoved); 1761 FailWithVal( result != noErr, Exit, result); 1762 } 1763 } 1764 } 1765 1766 if( ih->hasDeviceControl == false && deviceDescriptionPtr->deviceControlInstance != nil) 1767 { 1768 ih->hasDeviceControl = true; 1769 ++deviceDescriptionPtr->deviceControlCount; 1770 } 1771 1772Exit: 1773 return result; 1774} 1775 1776pascal ComponentResult IDHUpdateDeviceList( ComponentInstance ihc, 1777 QTAtomContainer *deviceList ) 1778 1779{ 1780 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1781 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 1782 OSErr result = noErr; 1783 QTAtomContainer container = nil; 1784 short nDVDevices, i; 1785 QTAtomSpec atomSpec; 1786 1787 RecordEventLogger( 'isoc', 'updt', 'dev ', 'list'); 1788 1789 FailWithAction( deviceList == nil, result = paramErr, Exit); 1790 1791 atomSpec.container = *deviceList; 1792 1793 result = checkSeed( gGlobals, &atomSpec); // make sure the container is current 1794 if( result != noErr) 1795 goto Exit; 1796 1797 // check for useCMP value changing 1798 if (result == noErr) 1799 { 1800 QTAtom useCMPAtom; 1801 UInt32 useCMPValue; 1802 1803 useCMPAtom = QTFindChildByIndex(*deviceList, kParentAtomIsContainer, kIDHUseCMPAtomType, 1, nil); 1804 if (useCMPAtom) 1805 { 1806 QTLockContainer(*deviceList); 1807 result = QTCopyAtomDataToPtr(*deviceList, useCMPAtom, true, 4, &useCMPValue, nil); 1808 QTUnlockContainer(*deviceList); 1809 1810 if (result == noErr) 1811 gGlobals->useCMP = useCMPValue; 1812 1813 } 1814 } 1815 1816 // move all volatile atoms here 1817 nDVDevices = QTCountChildrenOfType( *deviceList, kParentAtomIsContainer, kIDHDeviceAtomType); 1818 for( i=0; i<nDVDevices; ++i) 1819 { 1820 QTAtom deviceAtomNew, nameAtomNew, deviceIDAtom; 1821 QTAtom deviceAtomOld, nameAtomOld; 1822 DeviceDescription *deviceDescriptionPtr; 1823 IDHDeviceID deviceID; 1824 UInt8 newName[256]; 1825 SInt32 actualSize; 1826 1827 // get the client supplied atoms 1828 deviceAtomNew = QTFindChildByIndex( *deviceList, kParentAtomIsContainer, kIDHDeviceAtomType, i + 1, nil); 1829 FailIf( deviceAtomNew == nil, Exit); 1830 1831 nameAtomNew = QTFindChildByIndex( *deviceList, deviceAtomNew, kIDHNameAtomType, 1, nil); 1832 FailIf( nameAtomNew == nil, Exit); 1833 1834 deviceIDAtom = QTFindChildByIndex( *deviceList, deviceAtomNew, kIDHDeviceIDType, 1, nil); 1835 FailIf( deviceIDAtom == nil, Exit); 1836 1837 QTLockContainer( *deviceList); 1838 1839 QTCopyAtomDataToPtr( *deviceList, deviceIDAtom, true, sizeof( IDHDeviceID), &deviceID, nil); 1840 1841 QTUnlockContainer( *deviceList); 1842 1843 // find the local copy of this device container 1844 result = findDeviceDescriptionforDevice( ih, deviceID, &deviceDescriptionPtr); 1845 FailWithVal( result != noErr, Exit, result); 1846 1847 deviceAtomOld = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType, 1, nil); 1848 FailIf( deviceAtomOld == nil, Exit); 1849 1850 nameAtomOld = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, deviceAtomOld, kIDHNameAtomType, 1, nil); 1851 FailIf( nameAtomOld == nil, Exit); 1852 1853 // get new name 1854 QTLockContainer( *deviceList); 1855 result = QTCopyAtomDataToPtr(*deviceList, nameAtomNew, true, 256, newName, &actualSize); 1856 QTUnlockContainer( *deviceList); 1857 FailWithVal( result != noErr, Exit, result); 1858 1859 // update prefs file with new name 1860 // JKL, don't want to do this for now since FCP might be using this routine to toggle CMP 1861// updateCameraName(&deviceDescriptionPtr->uniqueID, newName); 1862 1863 // copy the new data into the current atom 1864 result = QTReplaceAtom( deviceDescriptionPtr->deviceContainer, nameAtomOld, *deviceList, nameAtomNew); 1865 FailWithVal( result != noErr, Exit, result); 1866 } 1867 1868Exit: 1869 return result; 1870} 1871 1872// can be called synchronously at task level only 1873pascal ComponentResult IDHWrite( ComponentInstance ihc, IDHParameterBlock *pb) 1874{ 1875 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1876 OSErr result = noErr; 1877 DeviceDescription *deviceDescriptionPtr; 1878 Boolean synchronous = false; 1879 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 1880 1881 RecordEventLogger( 'isoc', 'writ', 0, 0); 1882 1883 FailWithAction( pb == nil, result = paramErr, Exit); 1884 1885 // can't do sync writes at non-task level 1886 FailWithAction( pb->completionProc == nil && CurrentExecutionLevel() != kTaskLevel, result = paramErr, Exit); 1887 1888 // check for illegal condition 1889 FailWithAction( pb->completionProc == nil && pb->buffer == nil, result = paramErr, Exit); 1890 1891 FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit); 1892 1893 result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); 1894 FailWithVal( result != noErr, Exit, result); 1895 1896 FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit); 1897 1898 if( deviceDescriptionPtr->writeIsochNotificationID == nil) 1899 { 1900 result = IDHNewNotification( (ComponentInstance) gGlobals->localInstance, ih->deviceID, writeNotifyProc, 1901 (void *) ih->gGlobals, &deviceDescriptionPtr->writeIsochNotificationID ); 1902 FailWithVal( result != noErr, Exit, result); 1903 } 1904 1905 if ( deviceDescriptionPtr->writeIsochNotificationID ) 1906 { 1907 result = IDHNotifyMeWhen( (ComponentInstance) gGlobals->localInstance, deviceDescriptionPtr->writeIsochNotificationID, 1908 kIDHPrivateEventWriteComplete); 1909 FailWithVal( result != noErr, Exit, result); 1910 } 1911 1912 if( pb->completionProc == nil) // synchronous write 1913 { 1914 synchronous = true; 1915 1916 pb->completionProc = localCompletionRoutine; 1917 pb->refCon = deviceDescriptionPtr; 1918 1919 deviceDescriptionPtr->complete = false; 1920 } 1921 1922 PBEnqueueLast( (QElemPtr) pb, ih->writeQueue); 1923 1924 if( synchronous) // synchronous write 1925 { 1926 AbsoluteTime expirationTime; 1927 TimerID theTimer; 1928 1929 ih->timeout = false; 1930 1931 // expiration is current time + 1/15 second (2 frame times) 1932 expirationTime = AddDurationToAbsolute( kTimeoutDuration, UpTime()); 1933 1934 result = SetInterruptTimer( &expirationTime, myTimerHandler, ih, &theTimer); 1935 FailWithVal( result != noErr, Exit, result); 1936 1937 while( deviceDescriptionPtr->complete == false && ih->timeout == false) // loop until complete or timeout 1938 ; 1939 1940 expirationTime = DurationToAbsolute( 0); 1941 CancelTimer( theTimer, &expirationTime); 1942 1943 pb->completionProc = nil; 1944 1945 FailWithAction( ih->timeout == true, result = kIDHErrDeviceTimeout, Exit); //��� correct error code 1946 } 1947 1948Exit: 1949 1950 return result; 1951} 1952 1953#pragma mark - 1954#pragma mark ���������� IDHDV Private Component Calls ���������� 1955 1956pascal ComponentResult IDHDVPrivateCall( ComponentInstance ihc, IDHDVPrivateSelector selector, void *privateData) 1957{ 1958 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 1959 OSErr result = noErr; 1960 1961 switch (selector) 1962 { 1963 case kIDHDVPrivateSelectorDeviceAdded: 1964 RecordEventLogger( 'isoc', 'get ', 'priv', 'dadd'); 1965 result = handleDeviceAdded(ihc, (GDFDeviceEventData*) privateData); 1966 break; 1967 1968 case kIDHDVPrivateSelectorDeviceRemoved: 1969 RecordEventLogger( 'isoc', 'get ', 'priv', 'remv'); 1970 result = handleDeviceRemoved(ihc, (GDFDeviceEventData*) privateData); 1971 break; 1972 } 1973 1974 return result; 1975} 1976 1977#pragma mark - 1978#pragma mark ���������� IDH Internal Calls ���������� 1979 1980OSErr addBuffersToQueue( DeviceDescription *deviceDescriptionPtr) 1981{ 1982 QElemPtr qelem; 1983 OSErr result = noErr; 1984 QueueElement *qep; 1985 short j; 1986 1987 if( countQueueElements( deviceDescriptionPtr->freeQueue) > 0 || countQueueElements( deviceDescriptionPtr->usedQueue) > 0) // are there already buffers? 1988 { 1989 while( PBDequeueFirst( deviceDescriptionPtr->usedQueue, &qelem) == noErr) // move buffers from used to free queue 1990 { 1991 ((QueueElement *)qelem)->locks = 0; 1992 1993 PBEnqueueLast( qelem, deviceDescriptionPtr->freeQueue); 1994 } 1995 } 1996 else 1997 { 1998 for( j=0; j<kBuffersPerDevice; ++j) // add buffers to this devices queues 1999 { 2000 qep = (QueueElement *) NewPtrSysClear( sizeof( QueueElement)); 2001 FailWithAction( qep == nil, result = MemError(), Exit); 2002 2003 qep->buffer = NewPtrSys( (deviceDescriptionPtr->standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize); 2004 FailWithAction( qep->buffer == nil, result = MemError(), Exit); 2005 2006 qep->locks = 0; // initialize to no client locks 2007 2008 PBEnqueueLast( (QElemPtr) qep, deviceDescriptionPtr->freeQueue); 2009 } 2010 2011 deviceDescriptionPtr->nQueueElements = kBuffersPerDevice; // save number of buffers 2012 } 2013 2014Exit: 2015 return result; 2016 2017BadExit: 2018 // dispose buffers if error 2019 while( PBDequeueFirst( deviceDescriptionPtr->freeQueue, (QElemPtr *) &qep) == noErr) 2020 { 2021 if( qep) 2022 { 2023 if( qep->buffer) 2024 DisposePtr( qep->buffer); 2025 2026 DisposePtr( (char *) qep); 2027 } 2028 } 2029 2030 while( PBDequeueFirst( deviceDescriptionPtr->usedQueue, (QElemPtr *) &qep) == noErr) 2031 { 2032 if( qep) 2033 { 2034 if( qep->buffer) 2035 DisposePtr( qep->buffer); 2036 2037 DisposePtr( (char *) qep); 2038 } 2039 } 2040 2041 deviceDescriptionPtr->nQueueElements = 0; 2042 2043 return result; 2044} 2045 2046OSErr closeDeviceControl( ComponentInstance ihc, DeviceDescriptionPtr deviceDescriptionPtr) 2047{ 2048 OSErr result = noErr; 2049 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 2050 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 2051 2052 if( deviceDescriptionPtr->deviceControlInstance) 2053 { 2054 if( --deviceDescriptionPtr->deviceControlCount <= 0) 2055 { 2056 deviceDescriptionPtr->deviceControlCount = 0; 2057 2058 result = IDHCancelNotification( (ComponentInstance) gGlobals->localInstance, deviceDescriptionPtr->deviceControlNotificationID); 2059 FailMessage( result != noErr); 2060 2061 result = IDHDisposeNotification((ComponentInstance) gGlobals->localInstance, deviceDescriptionPtr->deviceControlNotificationID); 2062 FailMessage( result != noErr); 2063 deviceDescriptionPtr->deviceControlNotificationID = 0; 2064 2065 result = DeviceControlDisableAVCTransactions(deviceDescriptionPtr->deviceControlInstance); 2066 result = DeviceControlSetDeviceConnectionID(deviceDescriptionPtr->deviceControlInstance, 0); 2067 2068 CloseComponent(deviceDescriptionPtr->deviceControlInstance); 2069 2070 deviceDescriptionPtr->deviceControlInstance = nil; 2071 } 2072 } 2073 2074Exit: 2075 return result; 2076} 2077 2078OSErr checkSeed( IsochComponentGlobalsPtr gGlobals, QTAtomSpec *configID) 2079{ 2080 QTAtom seedAtom; 2081 OSErr result = noErr; 2082 UInt32 seed; 2083 2084 // look for device in device container 2085 seedAtom = QTFindChildByIndex( configID->container, kParentAtomIsContainer, kIDHSeedAtomType, 1, nil); 2086 FailWithAction( seedAtom == nil, result = kIDHErrDeviceList, Exit); 2087 2088 QTLockContainer( configID->container); 2089 2090 // get the value of the devicePresent atom 2091 QTCopyAtomDataToPtr( configID->container, seedAtom, true, sizeof( seed), &seed, nil); 2092 2093 QTUnlockContainer( configID->container); 2094 2095 // seed has expired? 2096 if( seed != gGlobals->seed) 2097 { 2098 result = kIDHErrDeviceList; 2099 goto Exit; 2100 } 2101 2102Exit: 2103 return result; 2104} 2105 2106int countQueueElements( QHdrPtr queue) 2107{ 2108 QElem *qptr; 2109 int nElements = 0; 2110 2111 qptr = queue->qHead; 2112 while( qptr) 2113 { 2114 ++nElements; 2115 qptr = qptr->qLink; 2116 } 2117 2118 return nElements; 2119} 2120 2121// called when a device is added/removed and updates device control clientID 2122OSStatus deviceControlCallback( IDHGenericEvent *event, void *userData) 2123{ 2124 OSErr result = noErr; 2125 DeviceDescription *deviceDescriptionPtr = (DeviceDescriptionPtr) userData; 2126 IsochComponentGlobalsPtr gGlobals = deviceDescriptionPtr->componentGlobals; 2127 2128 RecordEventLogger( 'isoc', 'devc', 'calb', event->eventHeader.event); 2129 2130 switch( event->eventHeader.event) 2131 { 2132 case kIDHEventDeviceAdded: 2133 2134 result = DeviceControlDisableAVCTransactions(deviceDescriptionPtr->deviceControlInstance); 2135 FailMessageVal( result != noErr, result); 2136 2137 result = DeviceControlSetDeviceConnectionID(deviceDescriptionPtr->deviceControlInstance, 2138 (DeviceConnectionID) deviceDescriptionPtr->fwClientID); 2139 FailWithVal( result != noErr, Exit, result); 2140 2141 result = DeviceControlEnableAVCTransactions(deviceDescriptionPtr->deviceControlInstance); 2142 FailWithVal( result != noErr, Exit, result); 2143 2144 break; 2145 2146 case kIDHEventDeviceRemoved: 2147 result = DeviceControlDisableAVCTransactions(deviceDescriptionPtr->deviceControlInstance); 2148 FailWithVal( result != noErr, Exit, result); 2149 2150 break; 2151 2152 default: 2153 FailMessage( (event->eventHeader.event & (kIDHEventDeviceRemoved | kIDHEventDeviceAdded)) == nil); 2154 break; 2155 } 2156 2157 result = IDHNotifyMeWhen( (ComponentInstance) gGlobals->localInstance, deviceDescriptionPtr->deviceControlNotificationID, 2158 kIDHEventDeviceAdded | kIDHEventDeviceRemoved); 2159 FailWithVal( result != noErr, Exit, result); 2160 2161Exit: 2162 return result; 2163} 2164 2165OSErr doAVCTransaction( FWReferenceID refID, DVCTransactionParams* inTransaction) 2166{ 2167 FWCommandObjectID commandObjectID; 2168 OSErr result = noErr; 2169 FCPResponseHandler *responseHandler = 0; 2170 UInt32 fwCommandFlags = kFWCommandSyncFlag; 2171 2172 // allocate command object for sending FCP commands synchronously. 2173 result = FWAllocateFCPCommandObject(&commandObjectID); 2174 FailWithVal( result != noErr, Exit1, result); 2175 2176 // Set up FCP command params to tell camera to do something. 2177 result = FWSetFWCommandParams( commandObjectID, // objectID 2178 refID, // ref ID 2179 fwCommandFlags, // cmd flags 2180 nil, // completion proc 2181 0); // completion data 2182 FailWithVal( result != noErr, Exit, result); 2183 2184 2185 result = FWSetFCPCommandParams( commandObjectID, // objectID 2186 inTransaction->commandBufferPtr, // cmd buffer 2187 inTransaction->commandLength, // cmd length 2188 inTransaction->responseBufferPtr, // response buffer 2189 inTransaction->responseBufferSize, // response size 2190 100 * durationMillisecond, // timeout 2191 8, // max retries 2192 0, // transfer flags 2193 responseHandler ); // response handler 2194 FailWithVal( result != noErr, Exit, result); 2195 2196 // send the FCP command 2197 result = FWSendFCPCommand(commandObjectID); 2198 FailWithVal( result != noErr, Exit, result); 2199 2200Exit: 2201 FWDeallocateFWCommandObject(commandObjectID); 2202 2203Exit1: 2204 return result; 2205} 2206 2207OSErr findDeviceDescriptionforDevice( IsochComponentInstancePtr ih, UInt32 deviceID, DeviceDescription **deviceDescription) 2208{ 2209 OSErr result = noErr; 2210 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 2211 short i; 2212 2213 *deviceDescription = nil; 2214 for( i=0; i<kMaxDevicesActive; ++i) 2215 { 2216 if( gGlobals->deviceDescription[i].deviceID == deviceID) 2217 { 2218 *deviceDescription = &gGlobals->deviceDescription[i]; 2219 break; 2220 } 2221 } 2222 2223 if( *deviceDescription == nil) 2224 result = kIDHErrInvalidDeviceID; 2225 2226Exit: 2227 return result; 2228} 2229 2230//��� do a super find atom someday 2231OSErr findAtom( QTAtomSpec *atomSpec, OSType theType, QTAtom *theAtom) 2232{ 2233 OSErr result = noErr; 2234 OSType type; 2235 QTAtom atom; 2236 2237 atom = atomSpec->atom; 2238 2239 result = QTGetAtomTypeAndID( atomSpec->container, atom, (long *) &type, nil); 2240 FailWithVal( result != noErr, Exit, result); 2241 2242 while( type != kIDHDeviceAtomType && type != theType) 2243 { 2244 atom = QTGetAtomParent( atomSpec->container, atom); // should be isoch atom 2245 FailWithAction( atom == nil || atom == -1, result = kIDHErrDeviceList, Exit); 2246 2247 result = QTGetAtomTypeAndID( atomSpec->container, atom, (long *) &type, nil); 2248 FailWithVal( result != noErr, Exit, result); 2249 } 2250 2251 if( theType == type) 2252 { 2253 *theAtom = atom; 2254 result = noErr; 2255 } 2256 else 2257 { 2258 *theAtom = nil; 2259 result = kIDHErrDeviceList; 2260 } 2261 2262Exit: 2263 return result; 2264} 2265 2266OSErr getDeviceID( QTAtomSpec *configID, UInt32 *deviceID) 2267{ 2268 OSErr result = noErr; 2269 QTAtom deviceAtom; 2270 2271 *deviceID = nil; 2272 2273 result = findAtom( configID, kIDHDeviceAtomType, &deviceAtom); 2274 FailWithVal( result != noErr, Exit, result); 2275 2276 result = QTGetAtomTypeAndID( configID->container, deviceAtom, nil, (long *) deviceID); 2277 FailWithVal( result != noErr, Exit, result); 2278 2279Exit: 2280 return result; 2281} 2282 2283 2284OSErr getDeviceStandard( FWReferenceID clientID, UInt32 * pStandard ) 2285{ 2286 AVCCTSFrameStruct avcFrame; 2287 DVCTransactionParams transactionParams; 2288 UInt8 responseBuffer[ 16 ]; 2289 OSErr theErr = noErr; 2290 UInt32 currentSignal, AVCStatus; 2291 2292 *pStandard = ntscIn; 2293 2294 // fill up the avc frame 2295 avcFrame.cmdType_respCode = kAVCStatusInquiryCommand; 2296 avcFrame.headerAddress = 0x20; // for now 2297 avcFrame.opcode = kAVCOutputSignalModeOpcode; 2298 avcFrame.operand[ 0 ] = kAVCSignalModeDummyOperand; 2299 2300 // fill up the transaction parameter block 2301 transactionParams.commandBufferPtr = (Ptr) &avcFrame; 2302 transactionParams.commandLength = 4; 2303 transactionParams.responseBufferPtr = (Ptr) responseBuffer; 2304 transactionParams.responseBufferSize = 16; 2305 transactionParams.responseHandler = nil; 2306 2307// some cameras need some time before they can respond to this command 2308 DelayFor ( 1 * durationSecond ); 2309 2310 theErr = setupAVCTransaction( clientID, &transactionParams ); 2311 FailWithVal( theErr != noErr, Exit, theErr); 2312 2313 currentSignal = ((responseBuffer[ 2 ] << 8) | responseBuffer[ 3 ]); 2314 AVCStatus = responseBuffer[ 0 ]; 2315 2316 switch (currentSignal & 0x000000ff) 2317 { 2318 case kAVCSignalModeSD525_60: 2319 case kAVCSignalModeSDL525_60: 2320 case kAVCSignalModeHD1125_60: 2321 *pStandard = ntscIn; 2322 break; 2323 2324 case kAVCSignalModeSD625_50: 2325 case kAVCSignalModeSDL625_50: 2326 case kAVCSignalModeHD1250_50: 2327 *pStandard = palIn; 2328 break; 2329 } 2330 2331Exit: 2332 2333// JKL, because of devices that do not have device control, it is probably not safe 2334// to return an error here. Just default to NTSC. Need a better solution for this: 2335// user input? examining the stream? If this is just for setting the buffer size 2336// might be better to waste 100k in the NTSC case and just use PAL buffer size. 2337 if (theErr != noErr) 2338 { 2339 *pStandard = ntscIn; 2340 theErr = noErr; 2341 } 2342 2343 return theErr; 2344} 2345 2346OSStatus localCompletionRoutine( IDHGenericEvent *event, void *userData) 2347{ 2348#pragma unused (event) 2349 2350 DeviceDescription *deviceDescriptionPtr = (DeviceDescription *) userData; 2351 2352 deviceDescriptionPtr->complete = true; // tell the read/write operation that operation is complete 2353 2354 return noErr; 2355} 2356 2357OSStatus myTimerHandler( void *p1, void *p2) 2358{ 2359#pragma unused( p2) 2360 2361 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) p1; 2362 2363 ih->timeout = true; 2364 2365 return noErr; 2366} 2367 2368OSErr postEvent(IsochComponentGlobals* gGlobals, 2369 IDHDeviceID deviceID, 2370 IDHEvent event, 2371 void* privateData) 2372{ 2373 UInt32 i; 2374 IDHDeviceConnectionEvent connectionEvent; 2375 OSErr error = noErr; 2376 2377 // We now have two broad classifications of events - ones that need to be 2378 // reported ASAP, which are stream related: 2379 // 2380 // kIDHPrivateEventReadComplete 2381 // kIDHPrivateEventWriteComplete 2382 // 2383 // and ones that are device management related, whose notifications will 2384 // probably generate massive amounts of task-level only Toolbox calls: 2385 // 2386 // kIDHEventDeviceAdded 2387 // kIDHEventDeviceRemoved 2388 // kIDHEventReadEnabled 2389 // kIDHEventReadDisabled 2390 // kIDHEventWriteEnabled 2391 // kIDHEventWriteDisabled 2392 // 2393 // kIDHPrivateEventReadComplete and kIDHPrivateEventWriteComplete are posted to a secondary 2394 // interrupt handler. All other events are handled immediately. 2395 2396 2397 RecordEventLogger( 'isoc', 'post', deviceID, event); 2398 2399 for (i = 0; i < kMaxNotifications ; ++i) 2400 { 2401 ClientNotification* clientNotification = &gGlobals->clientNotification[i]; 2402 IDHDeviceID clientDeviceID = clientNotification->deviceID; 2403 IDHEvent wantedEvents = clientNotification->events; 2404 2405 if (event & wantedEvents) 2406 { 2407 // Send notification if the device matches the client's desired device 2408 // or client specified all devices. 2409 if ((kIDHDeviceIDEveryDevice == clientDeviceID) || 2410 (deviceID == clientDeviceID) ) 2411 { 2412 // we currently only support a one-shot notification, like clock callbacks 2413 clientNotification->events = 0; 2414 2415 switch(event) 2416 { 2417 case kIDHPrivateEventReadComplete: 2418 case kIDHPrivateEventWriteComplete: 2419 2420 (*clientNotification->notificationProc) 2421 ((IDHGenericEvent*)privateData, 2422 clientNotification->userData); 2423 break; 2424 2425 case kIDHEventDeviceChanged: 2426 case kIDHEventDeviceAdded: 2427 case kIDHEventDeviceRemoved: 2428 case kIDHEventReadEnabled: 2429 case kIDHEventReadDisabled: 2430 case kIDHEventWriteEnabled: 2431 case kIDHEventWriteDisabled: 2432 2433 connectionEvent.eventHeader.event = event; 2434 connectionEvent.eventHeader.deviceID = deviceID; 2435 connectionEvent.eventHeader.notificationID = 2436 (UInt32)clientNotification; 2437 2438 (*clientNotification->notificationProc) 2439 ((IDHGenericEvent*)&connectionEvent, 2440 clientNotification->userData); 2441 break; 2442 2443 default: 2444 RecordEventLogger( 'isoc', 'post', '????', event); 2445 break; 2446 } 2447 2448 } 2449 } 2450 } 2451 2452 return error; 2453 2454} 2455 2456 2457OSStatus postEventSIH(void* p1, void* p2) 2458{ 2459 ClientNotification *clientNotification = (ClientNotification *) p1; 2460 IDHGenericEvent *privateData = (IDHGenericEvent *) p2; 2461 OSStatus status = noErr; 2462 2463 // call the routine 2464 (*clientNotification->notificationProc) (privateData, clientNotification->userData); 2465 2466 return status; 2467} 2468 2469 2470OSStatus readNotifyProc( IDHGenericEvent *event, void *userData) 2471{ 2472 OSErr result = noErr; 2473 IsochComponentGlobalsPtr gGlobals = userData; 2474 IDHDVCompleteEvent* readCompletePtr = (IDHDVCompleteEvent*) event; 2475 DeviceDescription *deviceDescriptionPtr = nil; 2476 short i; 2477 QueueElementPtr qep; 2478 2479 RecordEventLogger( 'isoc', 'read', 'comp', ((char *) readCompletePtr->frameBuffer)[640] & 0xf); 2480 2481 FailIf( event->eventHeader.event != kIDHPrivateEventReadComplete, Exit); 2482 2483 // find the device description that belongs to this read callback 2484 deviceDescriptionPtr = nil; 2485 for( i=0; i<kMaxDevicesActive; ++i) 2486 { 2487 if( gGlobals->deviceDescription[i].deviceID == event->eventHeader.deviceID) 2488 { 2489 deviceDescriptionPtr = &gGlobals->deviceDescription[i]; 2490 break; 2491 } 2492 } 2493 2494 FailIf( deviceDescriptionPtr == nil, Exit); // couldn't find device in tree 2495 2496 // find a buffer to copy the data into 2497 if( (result = PBDequeueFirst( deviceDescriptionPtr->freeQueue, (QElemPtr *) &qep)) != noErr) 2498 if( (result = PBDequeueFirst( deviceDescriptionPtr->usedQueue, (QElemPtr *) &qep)) != noErr) //��� changes when lock 2499 { 2500 FailWithVal( result != noErr, Exit, result); // no queue elems available 2501 } 2502 2503 qep->locks = 0; // reset lock 2504 2505 // make sure we have enuf room 2506 FailIf( readCompletePtr->bufferSize > kPALCompressedBufferSize, Exit); 2507// (deviceDescriptionPtr->standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize, Exit); 2508 2509 // copy the data and save the size 2510 BlockMoveData( readCompletePtr->frameBuffer, qep->buffer, readCompletePtr->bufferSize); 2511 qep->size = readCompletePtr->bufferSize; 2512 2513 // find all of instances that need to be serviced for this device 2514 for( i=0; i<kMaxInstances; ++i) 2515 { 2516 IsochComponentInstancePtr ih = deviceDescriptionPtr->instancePtr[i]; 2517 IDHParameterBlock *readRequest; 2518 2519 if( deviceDescriptionPtr->instancePtr[i] == nil) // no instance? 2520 continue; 2521 2522 // get a read request 2523 if( PBDequeueFirst( ih->readQueue, (QElemPtr *) &readRequest) != noErr) 2524 continue; 2525 2526 readRequest->actualCount = 0; 2527 readRequest->result = noErr; 2528 2529 // does the user want an internal buffer or copy to user buffer 2530 if( readRequest->buffer == nil) 2531 { 2532 RecordEventLogger( 'isoc', 'redc', 'read', 'nil '); 2533 2534 readRequest->buffer = readCompletePtr->frameBuffer; // return internal buffer 2535 readRequest->actualCount = readCompletePtr->bufferSize; 2536 2537 ++qep->locks; // add a lock to this buffer 2538 } 2539 else 2540 { 2541 RecordEventLogger( 'isoc', 'redc', 'read', 'buff'); 2542 2543 if( readCompletePtr->bufferSize <= readRequest->requestedCount) // do we have enuf room? 2544 { 2545 // copy the buffer into client buffer 2546 BlockMoveData( readCompletePtr->frameBuffer, readRequest->buffer, readCompletePtr->bufferSize); 2547 readRequest->actualCount = readCompletePtr->bufferSize; 2548 } 2549 } 2550 2551 // call the client callback 2552 result = (*readRequest->completionProc)( (IDHGenericEvent *) readRequest, readRequest->refCon); 2553 2554 } // end of processing instances 2555 2556 if( qep->locks > 0) // if this buffer has locks, move it to the usedQueue else requeue on free queue 2557 PBEnqueueLast( (QElemPtr) qep, deviceDescriptionPtr->usedQueue); 2558 else 2559 PBEnqueueLast( (QElemPtr) qep, deviceDescriptionPtr->freeQueue); 2560 2561 // reset read complete notification 2562 result = IDHNotifyMeWhen( (ComponentInstance) gGlobals->localInstance, deviceDescriptionPtr->readIsochNotificationID, 2563 kIDHPrivateEventReadComplete); 2564 2565Exit: 2566 return result; 2567} 2568 2569OSErr setupAVCTransaction( FWReferenceID refID, DVCTransactionParams *pParams ) 2570{ 2571 DVCTransactionParams transactionParams; 2572 OSErr error = noErr; 2573 2574 // fill out the internal transaction block 2575 transactionParams.commandBufferPtr = pParams->commandBufferPtr; 2576 transactionParams.commandLength = pParams->commandLength; 2577 transactionParams.responseBufferPtr = pParams->responseBufferPtr; 2578 transactionParams.responseBufferSize = pParams->responseBufferSize; 2579 transactionParams.responseHandler = nil; //��� pParams->responseHandler; 2580 2581 error = doAVCTransaction( refID, &transactionParams ); 2582 FailWithVal( error != noErr, Exit, error); 2583 2584Exit: 2585 return( error ); 2586} 2587 2588OSErr setupVideoAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard) // add DV NTSC config 2589{ 2590 OSErr result = noErr; 2591 QTAtom configAtom; 2592 OSType type; 2593 long size; 2594 float interval; 2595 long direction; 2596 IDHDimension dimension; 2597 IDHResolution resolution; 2598 Fixed refresh; 2599 OSType pixel; 2600 OSType decoType; 2601 Component decoComponent; 2602 ComponentDescription compDescrip; 2603 2604 // create a vide NTSC mode 2605 result = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType, 2606 0, 0, 0, nil, &configAtom); 2607 FailWithVal( result != noErr, Exit, result); 2608 2609 type = kIDHVideoMediaAtomType; 2610 result = QTInsertChild( container, configAtom, kIDHIsochMediaType, 2611 0, 0, sizeof( type), &type, nil); 2612 FailWithVal( result != noErr, Exit, result); 2613 2614 // for compatibility with Hemingway releases prior to our d13 release 2615 result = QTInsertChild( container, configAtom, kIDHNameAtomType, 2616 0, 0, 3, "\pDV", nil); 2617 FailWithVal( result != noErr, Exit, result); 2618 2619 type = (standard == ntscIn)?'DVC ':'DVCP'; 2620 result = QTInsertChild( container, configAtom, kIDHDataTypeAtomType, 2621 0, 0, sizeof( type), &type, nil); 2622 FailWithVal( result != noErr, Exit, result); 2623 2624 size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; 2625 result = QTInsertChild( container, configAtom, kIDHDataSizeAtomType, 2626 0, 0, sizeof( size), &size, nil); 2627 FailWithVal( result != noErr, Exit, result); 2628 2629 size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; 2630 result = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType, 2631 0, 0, sizeof( size), &size, nil); 2632 FailWithVal( result != noErr, Exit, result); 2633 2634 interval = 29.97; 2635 result = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType, 2636 0, 0, sizeof( interval), &interval, nil); 2637 FailWithVal( result != noErr, Exit, result); 2638 2639 direction = kIDHDataTypeIsInputAndOutput; 2640 result = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType, 2641 0, 0, sizeof( direction), &direction, nil); 2642 FailWithVal( result != noErr, Exit, result); 2643 2644 dimension.x = 720; dimension.y = (standard == ntscIn)?480:576; 2645 result = QTInsertChild( container, configAtom, kIDHVideoDimensionsAtomType, 2646 0, 0, sizeof( dimension), &dimension, nil); 2647 FailWithVal( result != noErr, Exit, result); 2648 2649 resolution.x = 72 << 16; resolution.y = 72 << 16; 2650 result = QTInsertChild( container, configAtom, kIDHVideoResolutionAtomType, 2651 0, 0, sizeof( resolution), &resolution, nil); 2652 FailWithVal( result != noErr, Exit, result); 2653 2654 refresh = (29 << 16) + 97; //��� 2655 result = QTInsertChild( container, configAtom, kIDHVideoRefreshRateAtomType, 2656 0, 0, sizeof( refresh), &refresh, nil); 2657 FailWithVal( result != noErr, Exit, result); 2658 2659 pixel = 'dv '; //��� 2660 result = QTInsertChild( container, configAtom, kIDHVideoPixelTypeAtomType, 2661 0, 0, sizeof( pixel), &pixel, nil); 2662 FailWithVal( result != noErr, Exit, result); 2663 2664//��� kIDHVideoDecompressorsAtomType = FOUR_CHAR_CODE('deco'), 2665 2666 decoType = (standard == ntscIn)?'dvc ':'dvcp'; 2667 result = QTInsertChild( container, configAtom, kIDHVideoDecompressorTypeAtomType, 2668 0, 0, sizeof( decoType), &decoType, nil); 2669 FailWithVal( result != noErr, Exit, result); 2670 2671 compDescrip.componentType = 'imdc'; 2672 compDescrip.componentSubType = decoType; 2673 compDescrip.componentManufacturer = 0; 2674 compDescrip.componentFlags = 0; 2675 compDescrip.componentFlagsMask = 0; 2676 2677 decoComponent = FindNextComponent( nil, &compDescrip); 2678 result = QTInsertChild( container, configAtom, kIDHVideoDecompressorComponentAtomType, 2679 0, 0, sizeof( decoComponent), &decoComponent, nil); 2680 FailWithVal( result != noErr, Exit, result); 2681 2682Exit: 2683 return result; 2684} 2685 2686OSErr setup48kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard) 2687{ 2688 OSErr err; 2689 QTAtom configAtom; 2690 2691 StringPtr name; 2692 OSType type; 2693 long size; 2694 Fixed rate; 2695 float interval; 2696 long direction; 2697 2698 // create a vide NTSC mode 2699 err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType, 2700 0, 0, 0, nil, &configAtom); 2701 FailWithVal( err != noErr, Exit, err); 2702 2703 type = kIDHSoundMediaAtomType; 2704 err = QTInsertChild( container, configAtom, kIDHIsochMediaType, 2705 0, 0, sizeof( type), &type, nil); 2706 FailWithVal( err != noErr, Exit, err); 2707 2708 name = "\pDV-48khz"; 2709 err = QTInsertChild( container, configAtom, kIDHNameAtomType, 2710 0, 0, name[0], name, nil); 2711 FailWithVal( err != noErr, Exit, err); 2712 2713 type = 'DV48'; 2714 err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType, 2715 0, 0, sizeof( type), &type, nil); 2716 FailWithVal( err != noErr, Exit, err); 2717 2718 size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; 2719 err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType, 2720 0, 0, sizeof( size), &size, nil); 2721 FailWithVal( err != noErr, Exit, err); 2722 2723 size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; 2724 err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType, 2725 0, 0, sizeof( size), &size, nil); 2726 FailWithVal( err != noErr, Exit, err); 2727 2728 interval = 29.97; 2729 err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType, 2730 0, 0, sizeof( interval), &interval, nil); 2731 FailWithVal( err != noErr, Exit, err); 2732 2733 direction = kIDHDataTypeIsInputAndOutput; 2734 err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType, 2735 0, 0, sizeof( direction), &direction, nil); 2736 FailWithVal( err != noErr, Exit, err); 2737 2738 size = 2; 2739 err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType, 2740 0, 0, sizeof( size), &size, nil); 2741 FailWithVal( err != noErr, Exit, err); 2742 2743 size = 2; 2744 err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType, 2745 0, 0, sizeof( size), &size, nil); 2746 FailWithVal( err != noErr, Exit, err); 2747 2748 rate = rate44khz; 2749 err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType, 2750 0, 0, sizeof( rate), &rate, nil); 2751 FailWithVal( err != noErr, Exit, err); 2752 2753Exit: 2754 return err; 2755} // sound 1 config 2756 2757OSErr setup32kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard) 2758{ 2759 OSErr err; 2760 QTAtom configAtom; 2761 2762 StringPtr name; 2763 OSType type; 2764 long size; 2765 Fixed rate; 2766 float interval; 2767 long direction; 2768 2769 // create a vide NTSC mode 2770 err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType, 2771 0, 0, 0, nil, &configAtom); 2772 FailWithVal( err != noErr, Exit, err); 2773 2774 type = kIDHSoundMediaAtomType; 2775 err = QTInsertChild( container, configAtom, kIDHIsochMediaType, 2776 0, 0, sizeof( type), &type, nil); 2777 FailWithVal( err != noErr, Exit, err); 2778 2779 name = "\pDV-32khz"; 2780 err = QTInsertChild( container, configAtom, kIDHNameAtomType, 2781 0, 0, name[0], name, nil); 2782 FailWithVal( err != noErr, Exit, err); 2783 2784 type = 'DV32'; 2785 err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType, 2786 0, 0, sizeof( type), &type, nil); 2787 FailWithVal( err != noErr, Exit, err); 2788 2789 size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; 2790 err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType, 2791 0, 0, sizeof( size), &size, nil); 2792 FailWithVal( err != noErr, Exit, err); 2793 2794 size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; 2795 err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType, 2796 0, 0, sizeof( size), &size, nil); 2797 FailWithVal( err != noErr, Exit, err); 2798 2799 interval = 29.97; 2800 err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType, 2801 0, 0, sizeof( interval), &interval, nil); 2802 FailWithVal( err != noErr, Exit, err); 2803 2804 direction = kIDHDataTypeIsInputAndOutput; 2805 err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType, 2806 0, 0, sizeof( direction), &direction, nil); 2807 FailWithVal( err != noErr, Exit, err); 2808 2809 size = 4; 2810 err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType, 2811 0, 0, sizeof( size), &size, nil); 2812 FailWithVal( err != noErr, Exit, err); 2813 2814 size = 2; 2815 err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType, 2816 0, 0, sizeof( size), &size, nil); 2817 FailWithVal( err != noErr, Exit, err); 2818 2819 rate = 32000 << 16; 2820 err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType, 2821 0, 0, sizeof( rate), &rate, nil); 2822 FailWithVal( err != noErr, Exit, err); 2823 2824Exit: 2825 return err; 2826} // sound 2 config 2827 2828OSErr setup44kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard) 2829{ 2830 OSErr err; 2831 QTAtom configAtom; 2832 2833 StringPtr name; 2834 OSType type; 2835 long size; 2836 Fixed rate; 2837 float interval; 2838 long direction; 2839 2840 // create a vide NTSC mode 2841 err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType, 2842 0, 0, 0, nil, &configAtom); 2843 FailWithVal( err != noErr, Exit, err); 2844 2845 type = kIDHSoundMediaAtomType; 2846 err = QTInsertChild( container, configAtom, kIDHIsochMediaType, 2847 0, 0, sizeof( type), &type, nil); 2848 FailWithVal( err != noErr, Exit, err); 2849 2850 name = "\pDV-44khz"; 2851 err = QTInsertChild( container, configAtom, kIDHNameAtomType, 2852 0, 0, name[0], name, nil); 2853 FailWithVal( err != noErr, Exit, err); 2854 2855 type = 'DV44'; 2856 err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType, 2857 0, 0, sizeof( type), &type, nil); 2858 FailWithVal( err != noErr, Exit, err); 2859 2860 size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; 2861 err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType, 2862 0, 0, sizeof( size), &size, nil); 2863 FailWithVal( err != noErr, Exit, err); 2864 2865 size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; 2866 err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType, 2867 0, 0, sizeof( size), &size, nil); 2868 FailWithVal( err != noErr, Exit, err); 2869 2870 interval = 29.97; 2871 err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType, 2872 0, 0, sizeof( interval), &interval, nil); 2873 FailWithVal( err != noErr, Exit, err); 2874 2875 direction = kIDHDataTypeIsInputAndOutput; 2876 err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType, 2877 0, 0, sizeof( direction), &direction, nil); 2878 FailWithVal( err != noErr, Exit, err); 2879 2880 size = 4; 2881 err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType, 2882 0, 0, sizeof( size), &size, nil); 2883 FailWithVal( err != noErr, Exit, err); 2884 2885 size = 2; 2886 err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType, 2887 0, 0, sizeof( size), &size, nil); 2888 FailWithVal( err != noErr, Exit, err); 2889 2890 rate = 44100 << 16; 2891 err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType, 2892 0, 0, sizeof( rate), &rate, nil); 2893 FailWithVal( err != noErr, Exit, err); 2894 2895Exit: 2896 return err; 2897} // sound 3 config 2898 2899OSErr updateDeviceList(IsochComponentInstancePtr ih, GDFDeviceEventData *pGDFData, IDHDeviceID *deviceID, Boolean doAdd) 2900{ 2901 OSErr result = noErr; 2902 QTAtom deviceAtom, isocAtom; 2903 IsochComponentGlobalsPtr gGlobals = ih->gGlobals; 2904 Boolean listChanged = false, foundDevice = false; 2905 DeviceDescription *deviceDescriptionPtr; 2906 IDHDeviceStatus deviceStatus; 2907 UInt32 standard; 2908 UInt32 devIndex; 2909 FWReferenceID localFWReferenceID; 2910 ComponentDescription clkDesc; 2911 2912 RecordEventLogger( 'isoc', 'updt', pGDFData->driverRefNum, 0); 2913 2914 ++gGlobals->seed; 2915 2916 if (doAdd) 2917 { 2918 // The refNum of a driver is NOT a constant IF the driver is allowed to close 2919 // once it has been opened. Our expert never allows the driver to be closed. 2920 // So use that refNum to search for the device in. 2921 // The same provision holds true for the RegEntryID so we could do that. 2922 2923 // look for existing device 2924 for( devIndex=0; devIndex < gGlobals->nDevices; ++devIndex) 2925 { 2926 if (pGDFData->driverRefNum == gGlobals->deviceDescription[devIndex].refNum) 2927 { 2928 FWDriverID clientID = gGlobals->deviceDescription[devIndex].fwClientID; 2929 gGlobals->deviceDescription[devIndex].active = true; 2930 foundDevice = true; 2931 2932 // max packet size for s100, set again in case clientID changes 2933 FWSetMaxPayloadSize(clientID, 512); 2934 2935 // Driver/RegEntry ID would change if device wasplugged into a different 2936 // interface/card. Can fix in future by looking at UniqueID in "new" 2937 // devices and see if they match any of the old devices. 2938 2939 // if there are more than one FW interfaces on the machine, its conceivable 2940 // that the same device could get plugged into a different interface 2941 // update the local FW reference just in case 2942 result = FWGetLocalFWReferenceIDFromFWReferenceID(clientID, &localFWReferenceID); 2943 FailWithVal( result != noErr, Exit, result); 2944 gGlobals->deviceDescription[devIndex].localFWReferenceID = localFWReferenceID; 2945 2946 *deviceID = gGlobals->deviceDescription[devIndex].deviceID; 2947 } 2948 } 2949 2950 if (!foundDevice) 2951 { 2952 FWDriverID clientID; 2953 CSRNodeUniqueID csrNodeUniqueID; 2954 Str255 cameraName; 2955 2956 deviceDescriptionPtr = &gGlobals->deviceDescription[gGlobals->nDevices]; 2957 2958 result = registerDevice( 2959 &pGDFData->deviceRegEntryID, 2960 &clientID, 2961 deviceDescriptionPtr); 2962 2963 FailIf(noErr != result, Exit); 2964 2965 RecordEventLogger( 'isoc', 'updt', 'add ', 'reg '); 2966 2967 result = FWGetUniqueID(clientID, &csrNodeUniqueID); 2968 FailIf( result != noErr, Exit); 2969 2970 // add its description 2971 gGlobals->nDevices++; 2972 2973 result = FWGetLocalFWReferenceIDFromFWReferenceID(clientID, &localFWReferenceID); 2974 FailWithVal( result != noErr, Exit, result); 2975 2976 *deviceID = gGlobals->nDevices; 2977 2978 deviceDescriptionPtr->componentGlobals = gGlobals; 2979 deviceDescriptionPtr->regEntryID = pGDFData->deviceRegEntryID; 2980 deviceDescriptionPtr->refNum = pGDFData->driverRefNum; 2981 deviceDescriptionPtr->deviceID = *deviceID; 2982 deviceDescriptionPtr->fwClientID = clientID; 2983 deviceDescriptionPtr->localFWReferenceID = localFWReferenceID; 2984 deviceDescriptionPtr->uniqueID.hi = csrNodeUniqueID.hi; 2985 deviceDescriptionPtr->uniqueID.lo = csrNodeUniqueID.lo; 2986 deviceDescriptionPtr->deviceControlNotificationID = 0; 2987 2988 // max packet size for s100 2989 FWSetMaxPayloadSize(clientID, 512); 2990 2991 // add the device standard (PAL, NTSC) 2992 result = getDeviceStandard(clientID, &standard); 2993 FailWithVal( result != noErr, Exit, result); 2994 2995 deviceDescriptionPtr->standard = standard; 2996 deviceDescriptionPtr->isochPortID = 0; 2997 deviceDescriptionPtr->outputIsochChannelID = 0; 2998 deviceDescriptionPtr->inputIsochChannelID = 0; 2999 deviceDescriptionPtr->pGlobalDVOutData = nil; 3000 deviceDescriptionPtr->pGlobalDVInData = nil; 3001 deviceDescriptionPtr->dclProgramID = 0; 3002 deviceDescriptionPtr->active = true; 3003 3004 // allocate command objects that may be used at non-task level 3005 // jkl, do these need to be deallocated somewhere? 3006 result = FWAllocateIsochPortCommandObject(&deviceDescriptionPtr->isochPortCommandObjectID); 3007 FailWithVal( result != noErr, Exit, result); 3008 result = FWAllocateIsochPortCommandObject(&deviceDescriptionPtr->stopIsochPortCommandObjectID); 3009 FailWithVal( result != noErr, Exit, result); 3010 result = FWAllocateIsochPortCommandObject(&deviceDescriptionPtr->startIsochPortCommandObjectID); 3011 FailWithVal( result != noErr, Exit, result); 3012 result = FWAllocateAsynchCommandObject(&deviceDescriptionPtr->asynchCommandObjectID); 3013 FailWithVal( result != noErr, Exit, result); 3014 FWSetAsynchCommandMaxPayloadSize(deviceDescriptionPtr->asynchCommandObjectID, 512); 3015 3016 // find clock component 3017 // wouldn't it be better for us to open an instance on OpenDevice, set FWClockPrivLocalReference, etc. 3018 clkDesc.componentType = clockComponentType; 3019 clkDesc.componentSubType = 'fwcy'; 3020 clkDesc.componentManufacturer = 'appl'; 3021 clkDesc.componentFlags = 0L; 3022 clkDesc.componentFlagsMask = 0L; 3023 3024 deviceDescriptionPtr->clock = 0; 3025 deviceDescriptionPtr->clock = FindNextComponent( deviceDescriptionPtr->clock, &clkDesc); // Look for FireWire clock component 3026 FailMessage( deviceDescriptionPtr->clock == nil); 3027 3028 // create device description atom structure 3029 result = QTNewAtomContainer( &deviceDescriptionPtr->deviceContainer); 3030 FailWithVal( result != noErr, Exit, result); 3031 3032 // add a device atom 3033 result = QTInsertChild( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType, 3034 (long) *deviceID, 0, 0, nil, &deviceAtom); 3035 FailWithVal( result != noErr, Exit, result); 3036 3037 // add the unique 64 bit FireWire GUID id to device atom 3038 result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHUniqueIDType, 3039 0, 0, sizeof(CSRNodeUniqueID), &csrNodeUniqueID, nil); 3040 FailWithVal( result != noErr, Exit, result); 3041 3042 result = cameraNameLookup(deviceDescriptionPtr, cameraName); 3043 FailWithVal( result != noErr, Exit, result); 3044 result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHNameAtomType, 3045 0, 0, cameraName[0] + 1, cameraName, nil); 3046 3047 // add the IDH unique id to device atom 3048 result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHDeviceIDType, 3049 0, 0, sizeof(deviceDescriptionPtr->deviceID), &deviceDescriptionPtr->deviceID, nil); 3050 FailWithVal( result != noErr, Exit, result); 3051 3052 // create a device status structure and add it to the device atom 3053 deviceStatus.version = 1; 3054 deviceStatus.physicallyConnected = true; 3055 deviceStatus.readEnabled = false; 3056 deviceStatus.writeEnabled = false; 3057 deviceStatus.exclusiveAccess = false; 3058 deviceStatus.currentBandwidth = 1; 3059 deviceStatus.currentChannel = 0; 3060 deviceStatus.inputStandard = 0; 3061 deviceStatus.deviceActive = false; 3062 3063 result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kDVDeviceInfo, 3064 0, 0, sizeof( IDHDeviceStatus), &deviceStatus, nil); 3065 FailWithVal( result != noErr, Exit, result); 3066 3067 // add isoch descriptions to structure 3068 result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHIsochServiceAtomType, 3069 0, 0, 0, nil, &isocAtom); 3070 FailWithVal( result != noErr, Exit, result); 3071 3072 // add the configs to the isoc atom 3073 result = setupVideoAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard); 3074 FailWithVal( result != noErr, Exit, result); 3075 3076 if( standard == ntscIn) 3077 { 3078 result = setup48kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard); 3079 FailWithVal( result != noErr, Exit, result); 3080 3081 result = setup32kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard); 3082 FailWithVal( result != noErr, Exit, result); 3083 } 3084 else // PAL audio 3085 { 3086 result = setup44kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard); 3087 FailWithVal( result != noErr, Exit, result); 3088 } 3089 } 3090 } 3091 else // process device disabled 3092 { 3093 RecordEventLogger( 'isoc', 'updt', 'disa', 0); 3094 3095 for( devIndex=0; devIndex < gGlobals->nDevices; ++devIndex) // find disabled device in list 3096 { 3097 if (gGlobals->deviceDescription[devIndex].refNum == pGDFData->driverRefNum) // do we match? 3098 { 3099 DeviceDescription *deviceDescriptionPtr = &(gGlobals->deviceDescription[devIndex]); 3100 int i; 3101 3102 gGlobals->deviceDescription[devIndex].active = false; 3103 3104 *deviceID = gGlobals->deviceDescription[devIndex].deviceID; 3105 3106 RecordEventLogger( 'isoc', 'updt', 'disa', 'foun'); 3107 3108 // find all of instances that have pending I/O for this device 3109 for( i=0; i<kMaxInstances; ++i) 3110 { 3111 IsochComponentInstancePtr ih = deviceDescriptionPtr->instancePtr[i]; 3112 IDHParameterBlock *writeRequest, *readRequest; 3113 3114 if( deviceDescriptionPtr->instancePtr[i] == nil) // no instance? 3115 continue; 3116 3117 // get a read request 3118 while( PBDequeueFirst( ih->readQueue, (QElemPtr *) &readRequest) == noErr) 3119 { 3120 RecordEventLogger( 'isoc', 'updt', 'disa', 'disr'); 3121 3122 readRequest->result = kIDHErrDeviceDisconnected; 3123 3124 // call the client callback 3125 result = (*readRequest->completionProc)( (IDHGenericEvent *) readRequest, readRequest->refCon); 3126 } 3127 3128 // get a read request 3129 while( PBDequeueFirst( ih->writeQueue, (QElemPtr *) &writeRequest) == noErr) 3130 { 3131 RecordEventLogger( 'isoc', 'updt', 'disa', 'disw'); 3132 3133 writeRequest->result = kIDHErrDeviceDisconnected; 3134 3135 // call the client callback 3136 result = (*writeRequest->completionProc)( (IDHGenericEvent *) writeRequest, writeRequest->refCon); 3137 } 3138 } // end of processing instances 3139 3140 break; 3141 } 3142 } 3143 } 3144 3145Exit: 3146 return result; 3147} 3148 3149 3150OSStatus writeNotifyProc( IDHGenericEvent *event, void *userData) 3151{ 3152 OSErr result = noErr; 3153 IsochComponentGlobalsPtr gGlobals = userData; 3154 DeviceDescription *deviceDescriptionPtr; 3155 short i; 3156 3157 RecordEventLogger( 'isoc', 'writ', 'comp', 'lete'); 3158 3159 FailIf( event->eventHeader.event != kIDHPrivateEventWriteComplete, Exit); // make sure this is a write 3160 3161 deviceDescriptionPtr = nil; // find device causing notification in list 3162 for( i=0; i<kMaxDevicesActive; ++i) 3163 { 3164 if( gGlobals->deviceDescription[i].deviceID == event->eventHeader.deviceID) 3165 { 3166 deviceDescriptionPtr = &gGlobals->deviceDescription[i]; 3167 break; 3168 } 3169 } 3170 3171 FailIf( deviceDescriptionPtr == nil, Exit); // couldn't find device in list 3172 3173 for( i=0; i<kMaxInstances; ++i) // process each client for this device 3174 { 3175 IsochComponentInstancePtr ih = deviceDescriptionPtr->instancePtr[i]; 3176 IDHParameterBlock *writeRequest; 3177 Ptr tmpBuffPtr; 3178 unsigned long frameSize; 3179 3180 if( deviceDescriptionPtr->instancePtr[i] == nil) // no instance? Skip to next. 3181 continue; 3182 3183 if( PBDequeueFirst( ih->writeQueue, (QElemPtr *) &writeRequest) != noErr) // get a write request 3184 continue; 3185 3186 // Get a buffer for output 3187 result = getEmptyOutputFrame( ih, &tmpBuffPtr, &frameSize); 3188 FailWithVal( result != noErr, Exit, result); 3189 3190 writeRequest->actualCount = 0; 3191 writeRequest->result = noErr; 3192 3193 FailMessage( frameSize < writeRequest->requestedCount) // make sure buffer is big enough 3194 if( frameSize < writeRequest->requestedCount) 3195 result = kIDHErrDeviceWriteError; 3196 3197 if( result == noErr) // valid frame avail? 3198 { 3199 if( writeRequest->buffer == nil) // user wants buffer 3200 { 3201 writeRequest->buffer = tmpBuffPtr; // pass the buffer back to the client 3202 3203 // call clients callback so that he can copy his data into buffer 3204 result = (*writeRequest->completionProc)( (IDHGenericEvent *) writeRequest, writeRequest->refCon); 3205 FailWithVal( result != noErr, Exit, result); 3206 3207 // write the frame 3208 result = writeFrame( ih, tmpBuffPtr); 3209 FailWithVal( result != noErr, Exit, result); 3210 } 3211 else // client supplied frame 3212 { 3213 // move the client data into the buffer 3214 BlockMoveData( writeRequest->buffer, tmpBuffPtr, writeRequest->requestedCount); 3215 writeRequest->actualCount = writeRequest->requestedCount; 3216 3217 // write the frame 3218 result = writeFrame( ih, tmpBuffPtr); 3219 FailWithVal( result != noErr, Exit, result); 3220 3221 // save the result and call clients callback 3222 writeRequest->result = result; 3223 result = (*writeRequest->completionProc)( (IDHGenericEvent *) writeRequest, writeRequest->refCon); 3224 FailMessage( result != noErr); 3225 } 3226 3227 } // valid frame avail? 3228 3229 } // next client 3230 3231 // reset callback 3232 result = IDHNotifyMeWhen( (ComponentInstance) gGlobals->localInstance, deviceDescriptionPtr->writeIsochNotificationID, 3233 kIDHPrivateEventWriteComplete); 3234 3235Exit: 3236 return result; 3237} 3238 3239 3240OSStatus cameraNameLookup(DeviceDescriptionPtr pDeviceDescription, UInt8 *name) 3241{ 3242 Handle h; 3243 FSSpec fileSpec; 3244 Str255 cameraName = "\pDV"; 3245 SInt32 dirID; 3246 UInt32 *pGuid; 3247 UInt32 guidCount; 3248 UInt32 i, index; 3249 OSStatus result = noErr; 3250 SInt16 refNum; 3251 Boolean foundName = false; 3252 3253 BlockMoveData(cameraName, name, cameraName[0] + 1); 3254 3255 // first look for a "DV Names" preferences file 3256 // find the preferences folder 3257 result = FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, &refNum, &dirID); 3258 if (result != noErr) 3259 return noErr; 3260 3261 result = FSMakeFSSpec(refNum, dirID, "\pDV Names", &fileSpec); 3262 if (result == noErr) 3263 { 3264 // prefs file exsits, open it 3265 refNum = FSpOpenResFile(&fileSpec, fsRdPerm); 3266 result = ResError(); 3267 } 3268 3269 if (result == noErr) 3270 { 3271 // read guid resource and look for matching guid 3272 h = Get1Resource('guid', -20775); // jkl, get resource assignment and constant 3273 result = ResError(); 3274 if (h && (result == noErr)) 3275 { 3276 HLock(h); 3277 3278 // first long is number of guid's stored in resource 3279 pGuid = (UInt32 *) *h; 3280 guidCount = *pGuid; 3281 pGuid++; 3282 3283 for (i = 0, index = 1; i < (guidCount * 2); i+=2, index++) 3284 { 3285 if ((pGuid[i] == pDeviceDescription->uniqueID.hi) && (pGuid[i+1] == pDeviceDescription->uniqueID.lo)) 3286 { 3287 // found device, get its name 3288 GetIndString(cameraName, -20775, index); 3289 if (cameraName[0]) 3290 { 3291 BlockMoveData(cameraName, name, cameraName[0] + 1); 3292 foundName = true; 3293 break; 3294 } 3295 } 3296 } 3297 HUnlock(h); 3298 ReleaseResource(h); 3299 } 3300 3301 CloseResFile(refNum); 3302 } 3303 3304 if (!foundName) 3305 { 3306 // look in local vendor ID resource stored in QT FW DV Support to at least determine manufacturer name 3307 result = FindFolder(kOnSystemDisk, kExtensionFolderType, kDontCreateFolder, &refNum, &dirID); 3308 if (result != noErr) 3309 return noErr; 3310 } 3311 3312 // jkl, this should be changed to search by type and creator, not name 3313 result = FSMakeFSSpec(refNum, dirID, "\pQuickTime FireWire DV Support", &fileSpec); 3314 if (result == noErr) 3315 { 3316 // prefs file exsits, open it 3317 refNum = FSpOpenResFile(&fileSpec, fsRdPerm); 3318 result = ResError(); 3319 if (result != noErr) 3320 return noErr; 3321 } 3322 3323 if (result == noErr) 3324 { 3325 // read vendor id resource and look for matching guid 3326 h = Get1Resource('vnid', -20775); // jkl, get resource assignment and constant 3327 result = ResError(); 3328 if (h && (result == noErr)) 3329 { 3330 HLock(h); 3331 3332 // first long is number of vendor id's stored in resource 3333 guidCount = **((UInt32 **) h); 3334 3335 pGuid = *((UInt32 **) h); 3336 pGuid++; 3337 3338 for (i = 0, index = 1; i < guidCount; i++, index++) 3339 { 3340 if (pGuid[i] == (pDeviceDescription->uniqueID.hi >> 8)) 3341 { 3342 // found device, get its name 3343 GetIndString(cameraName, -20775, index); 3344 if (cameraName[0]) 3345 { 3346 BlockMoveData(cameraName, name, cameraName[0] + 1); 3347 BlockMoveData(" DV", name + name[0] + 1, 3); 3348 name[0] += 3; 3349 break; 3350 } 3351 } 3352 } 3353 HUnlock(h); 3354 ReleaseResource(h); 3355 } 3356 3357 CloseResFile(refNum); 3358 } 3359 3360 // don't fail because can't find a name 3361 return noErr; 3362} 3363 3364 3365struct UniqueIDAndName { 3366 CSRNodeUniqueID guid; 3367 Str255 name; 3368}; 3369typedef struct UniqueIDAndName UniqueIDAndName, *UniqueIDAndNamePtr; 3370 3371// structural representation of preferences file data 3372struct CameraNamePrefs { 3373 UInt32 idNameCount; 3374 UniqueIDAndName idName[]; 3375}; 3376typedef struct CameraNamePrefs CameraNamePrefs, *CameraNamePrefsPtr; 3377 3378OSStatus updateCameraName(CSRNodeUniqueID *guid, UInt8 *name) 3379{ 3380 UniqueIDAndNamePtr pGuidName; 3381 FSSpec fileSpec; 3382 SInt32 dirID; 3383 SInt32 requestedCount; 3384 UInt32 recordCount; 3385 UInt32 i; 3386 OSStatus result = noErr; 3387 SInt16 refNum, vRefNum; 3388 Boolean foundGuid = false; 3389 Boolean fileOpened = false; 3390 3391 // look for a "DV Names" preferences file, jkl - name needs to be localized 3392 // find the preferences folder 3393 result = FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, &vRefNum, &dirID); 3394 if (result != noErr) 3395 return noErr; 3396 3397 result = FSMakeFSSpec(vRefNum, dirID, "\pDV Names", &fileSpec); 3398 if (result == fnfErr) 3399 result = FSpCreate(&fileSpec, 'dvcf', 'pref', smSystemScript); 3400 3401 if (result == noErr) 3402 result = FSpOpenDF(&fileSpec, fsRdWrPerm, &refNum); 3403 3404 if (result == noErr) 3405 { 3406 fileOpened = true; 3407 result = SetFPos(refNum, fsFromStart, 0); 3408 } 3409 3410 if (result == noErr) 3411 { 3412 requestedCount = 4; 3413 result = FSRead(refNum, &requestedCount, &recordCount); 3414 } 3415 3416 if ((result == noErr) && (requestedCount == 4)) 3417 { 3418 requestedCount = recordCount * sizeof(UniqueIDAndName); 3419 3420 // allocate memory to read all of the data 3421 pGuidName = (UniqueIDAndNamePtr) NewPtr(requestedCount); 3422 if (pGuidName == nil) 3423 result = memFullErr; 3424 3425 if (result == noErr) 3426 result = FSRead(refNum, &requestedCount, pGuidName); 3427 3428 if (result == noErr) 3429 { 3430 for (i = 0; i < recordCount; i++) 3431 { 3432 if ((pGuidName[i].guid.hi == guid->hi) && (pGuidName[i].guid.lo == guid->lo)) 3433 { 3434 BlockMoveData(name, pGuidName[i].name, name[0] + 1); 3435 foundGuid = true; 3436 break; 3437 } 3438 } 3439 } 3440 } 3441 else 3442 { 3443 // prefs file is empty 3444 result = noErr; 3445 recordCount = 1; 3446 requestedCount = sizeof(UniqueIDAndName); 3447 3448 // allocate memory for new record 3449 pGuidName = (UniqueIDAndNamePtr) NewPtr(requestedCount); 3450 if (pGuidName == nil) 3451 result = memFullErr; 3452 3453 if (result == noErr) 3454 { 3455 BlockMoveData(name, pGuidName[0].name, name[0] + 1); 3456 pGuidName[0].guid = *guid; 3457 foundGuid = true; 3458 } 3459 } 3460 3461 if ((result == noErr) && !foundGuid) 3462 { 3463 // allocate space for new record 3464 requestedCount = GetPtrSize((Ptr) pGuidName); 3465 requestedCount += sizeof(UniqueIDAndName); 3466 SetPtrSize((Ptr) pGuidName, requestedCount); 3467 result = MemError(); 3468 3469 if (result == noErr) 3470 { 3471 BlockMoveData(name, pGuidName[recordCount].name, name[0] + 1); 3472 pGuidName[recordCount].guid = *guid; 3473 } 3474 recordCount++; 3475 } 3476 3477 if (result == noErr) 3478 { 3479 // write data back to disk 3480 result = SetFPos(refNum, fsFromStart, 0); 3481 3482 requestedCount = 4; 3483 if (result == noErr) 3484 result = FSWrite(refNum, &requestedCount, &recordCount); 3485 3486 requestedCount = GetPtrSize((Ptr) pGuidName); 3487 if (result == noErr) 3488 result = FSWrite(refNum, &requestedCount, pGuidName); 3489 } 3490 3491 if (fileOpened) 3492 FSClose(refNum); 3493 3494 FlushVol(nil, vRefNum); 3495 3496 return result; 3497} 3498 3499#pragma mark - 3500#pragma mark ���������� Firewire Calls ���������� 3501 3502OSStatus handleDeviceAdded(ComponentInstance ihc, GDFDeviceEventData *pGDFData) 3503{ 3504 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 3505 IDHDeviceID deviceID; 3506 OSStatus status = noErr; 3507 3508 RecordEventLogger( 'isoc', 'hana', 0, 0); //��� 3509 3510 // update component info 3511 status = updateDeviceList(ih, pGDFData, &deviceID, true /* activate */); 3512 3513 // Post deviceAddedEvent to anybody that wants one 3514 postEvent(ih->gGlobals, deviceID, kIDHEventDeviceAdded, nil); 3515 3516 return status; 3517} 3518 3519 3520OSStatus handleDeviceRemoved(ComponentInstance ihc, GDFDeviceEventData *pGDFData) 3521{ 3522 IsochComponentInstancePtr ih = (IsochComponentInstancePtr) ihc; 3523 IDHDeviceID deviceID; 3524 OSStatus status = noErr; 3525 3526 RecordEventLogger( 'isoc', 'hanr', 0, 0); 3527 3528 // update component info 3529 status = updateDeviceList(ih, pGDFData, &deviceID, false /* deactivate */); 3530 3531 // Post deviceAddedEvent to anybody that wants one 3532 postEvent(ih->gGlobals, deviceID, kIDHEventDeviceRemoved, nil); 3533 3534 return status; 3535} 3536 3537 3538OSStatus initIsochPort(FWClientInitIsochPortParams *pInitIsochPortParams, UInt32* outCommandAcceptance) 3539{ 3540 DeviceDescriptionPtr pDeviceDescription; 3541 OSErr error = noErr; 3542 Boolean portIsTalker, trial; 3543 Boolean portIsLocal = false; 3544 3545 pDeviceDescription = (DeviceDescriptionPtr) pInitIsochPortParams->fwClientIsochPortParams.refCon; 3546 3547 // Get port information 3548 portIsTalker = pInitIsochPortParams->fwClientIsochPortParams.portIsTalker; 3549 trial = pInitIsochPortParams->trial; 3550 3551 // if input and call is not for talker, then call is for local port 3552 if ((pDeviceDescription->inputIsochChannelID == pInitIsochPortParams->fwClientIsochPortParams.isochChannelID) && !portIsTalker) 3553 portIsLocal = true; 3554 // JKL, really could be an else here 3555 // if output and call is for talker, then call is for local port 3556 if ((pDeviceDescription->outputIsochChannelID == pInitIsochPortParams->fwClientIsochPortParams.isochChannelID) && portIsTalker) 3557 portIsLocal = true; 3558 3559 if (portIsTalker) 3560 { 3561 if (!trial) 3562 { 3563 if (portIsLocal) 3564 error = doLocalTalkerPort(pDeviceDescription, pInitIsochPortParams); 3565 else 3566 error = doRemoteTalkerPort(pDeviceDescription, pInitIsochPortParams); 3567 } 3568 else 3569 { 3570 if (portIsLocal) 3571 error = trialLocalTalkerPort(pDeviceDescription, pInitIsochPortParams); 3572 else 3573 error = trialRemoteTalkerPort(pDeviceDescription, pInitIsochPortParams); 3574 } 3575 } 3576 else 3577 { 3578 if (!trial) 3579 { 3580 if (portIsLocal) 3581 error = doLocalListenerPort(pDeviceDescription, pInitIsochPortParams); 3582 else 3583 error = doRemoteListenerPort(pDeviceDescription, pInitIsochPortParams); 3584 } 3585 else 3586 { 3587 if (portIsLocal) 3588 error = trialLocalListenerPort(pDeviceDescription, pInitIsochPortParams); 3589 else 3590 error = trialRemoteListenerPort(pDeviceDescription, pInitIsochPortParams); 3591 } 3592 } 3593 3594 FailMessageVal( error != noErr, error); 3595 3596 FWClientCommandIsComplete( 3597 pInitIsochPortParams->fwClientInterfaceParams.fwClientCommandID, 3598 error); 3599 3600 *outCommandAcceptance = kFWClientCommandAcceptNoMore; 3601 3602 return error; 3603} 3604 3605 3606OSStatus doLocalTalkerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams) 3607{ 3608 OSStatus error = noErr; 3609 3610 error = FWAllocateIsochPortID(&pDeviceDescription->isochPortID, pDeviceDescription->dclProgramID, 3611 pInitIsochPortParams->channelNum, pInitIsochPortParams->speed, true); 3612 FailMessageVal( error != noErr, error); 3613 3614 // Send an allocate isoch port command to allocate port for talking 3615 if (error == noErr) 3616 { 3617 FWSetFWCommandParams(pDeviceDescription->isochPortCommandObjectID, pDeviceDescription->fwClientID, kFWCommandSyncFlag, nil, 0); 3618 FWSetIsochPortCommandIsochPortID(pDeviceDescription->isochPortCommandObjectID, pDeviceDescription->isochPortID); 3619 error = FWAllocateLocalIsochronousPort(pDeviceDescription->isochPortCommandObjectID); 3620 FailMessageVal( error != noErr, error); 3621 } 3622 3623 if (pDeviceDescription->componentGlobals->useCMP) 3624 { 3625 if (error == noErr) 3626 error = cmpNewPointToPointConnection(4 * pDeviceDescription->pcrIndex, 3627 pDeviceDescription->localFWReferenceID, 3628 pInitIsochPortParams->channelNum, 3629 pInitIsochPortParams->speed, 3630 pDeviceDescription->cmpOverheadID, 3631 pDeviceDescription); 3632 } 3633 3634 return error; 3635} 3636 3637 3638OSStatus doRemoteTalkerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams) 3639{ 3640 OSStatus error = noErr; 3641 3642 if (pDeviceDescription->componentGlobals->useCMP) 3643 { 3644 // set camera's output plug 3645 if (error == noErr) 3646 error = cmpNewPointToPointConnection(0x04, pDeviceDescription->fwClientID, pInitIsochPortParams->channelNum, 3647 pInitIsochPortParams->speed, pDeviceDescription->cmpOverheadID, pDeviceDescription); 3648 } 3649 3650 return error; 3651} 3652 3653 3654OSStatus trialLocalTalkerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams) 3655{ 3656 UInt32 localOutputPCRValue, pcrValue; 3657 UInt32 fwBandwidthUnits; 3658 UInt32 channelNum; 3659 OSStatus error = noErr; 3660 3661 if (pDeviceDescription->componentGlobals->useCMP) 3662 { 3663 error = cmpRead(4 * pDeviceDescription->pcrIndex, pDeviceDescription->localFWReferenceID, &pcrValue, pDeviceDescription); 3664 3665 if (error == noErr) 3666 { 3667 // initialize mac output plug, turns on connected bit, 448 overhead unlike cameras so two streams fit in started 0x1333 bandwidth, 122 quadlet payload 3668 // jkl, need to computer overhead, ask Eric 3669 pDeviceDescription->cmpOverheadID = 0x0c; 3670 localOutputPCRValue = 0x8000007a | (pDeviceDescription->cmpOverheadID << 10); 3671 error = cmpWrite(4 * pDeviceDescription->pcrIndex, pDeviceDescription->localFWReferenceID, 3672 pcrValue, localOutputPCRValue, pDeviceDescription); 3673 } 3674 3675 if (error == noErr) 3676 { 3677 // reserve bandwidth 3678 // jkl, problem with this is final speed may be faster than s100, allocated bandwidth will be too much and not enough bandwidth will get deallocated 3679 // could either stay at default s100 or fix up the bandwidth in the commit phase 3680 fwBandwidthUnits = irmCalculateBandwidthUnits(localOutputPCRValue); 3681 error = irmAllocateBandwidth(pDeviceDescription->fwClientID, fwBandwidthUnits, pDeviceDescription); 3682 } 3683 3684 // reserve channel 3685 if (error == noErr) 3686 { 3687 pDeviceDescription->cmpBandwidth = fwBandwidthUnits; 3688 3689 channelNum = 0; 3690 3691 // reserve channel 3692 // jkl, what if further init stuff fails - like target device in camera mode, how do we know to release resources 3693 error = irmAllocateChannel(pDeviceDescription->fwClientID, &channelNum, pDeviceDescription); 3694 3695 if (error == noErr) 3696 { 3697 pDeviceDescription->cmpChannel = channelNum; 3698 3699 if (channelNum < 32) 3700 { 3701 pInitIsochPortParams->supportedChannelNumHi = ((UInt32) 0x80000000) >> channelNum; 3702 pInitIsochPortParams->supportedChannelNumLo = 0; 3703 } 3704 else 3705 { 3706 channelNum -= 32; 3707 pInitIsochPortParams->supportedChannelNumHi = 0; 3708 pInitIsochPortParams->supportedChannelNumLo = ((UInt32) 0x80000000) >> channelNum; 3709 } 3710 } 3711 } 3712 3713 // set speed 3714 if (error == noErr) 3715 { 3716 UInt32 localOutputMasterPlugValue; 3717 3718 error = cmpRead(0x00, pDeviceDescription->localFWReferenceID, &localOutputMasterPlugValue, pDeviceDescription); 3719 if (error == noErr) 3720 pInitIsochPortParams->speed = (localOutputMasterPlugValue >> 30) & 3; 3721 else 3722 { 3723 pInitIsochPortParams->speed = kFWSpeed100MBit; 3724 3725 // don't fail for this 3726 error = noErr; 3727 } 3728 } 3729 3730 } 3731 else 3732 { 3733 // no CMP just use channel 63, should make sure bandwidth is allocated 3734 pInitIsochPortParams->supportedChannelNumHi = 0; 3735 pInitIsochPortParams->supportedChannelNumLo = 1; 3736 3737 // set speed 3738 pInitIsochPortParams->speed = kFWSpeed100MBit; 3739 } 3740 3741 return error; 3742} 3743 3744 3745OSStatus trialRemoteTalkerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams) 3746{ 3747 UInt32 fwBandwidthUnits; 3748 UInt32 channelNum; 3749 UInt32 pcrValue; 3750 OSStatus error = noErr; 3751 3752 if (pDeviceDescription->componentGlobals->useCMP) 3753 { 3754 // determine current state of device 3755 error = cmpRead(0x04, pDeviceDescription->fwClientID, &pcrValue, pDeviceDescription); 3756 if (error == noErr) 3757 { 3758 // save channelNum 3759 channelNum = (pcrValue >> 16) & 0x3f; 3760 3761 // if there is a point to point connection or if camera is broadcasting on a channel other than 63, 3762 // use existing channel and bandwidth 3763 if ((pcrValue & 0x3f000000) || (((pcrValue & 0xC0000000) == 0xC0000000) && (channelNum != 63))) 3764 { 3765 if (channelNum < 32) 3766 { 3767 pInitIsochPortParams->supportedChannelNumHi = ((UInt32) 0x80000000) >> channelNum; 3768 pInitIsochPortParams->supportedChannelNumLo = 0; 3769 } 3770 else 3771 { 3772 channelNum -= 32; 3773 pInitIsochPortParams->supportedChannelNumHi = 0; 3774 pInitIsochPortParams->supportedChannelNumLo = ((UInt32) 0x80000000) >> channelNum; 3775 } 3776 3777 pDeviceDescription->cmpChannel = channelNum; 3778 pDeviceDescription->cmpBandwidth = irmCalculateBandwidthUnits(pcrValue); 3779 pDeviceDescription->cmpOverheadID = (pcrValue >> 10) & 0x0f; 3780 } 3781 else 3782 { 3783 if ((pcrValue & 0xC0000000) == 0xC0000000) 3784 { 3785 // device is broadcasting on 63, clear broadcast, release channel and bandwidth 3786 error = cmpWrite(0x04, pDeviceDescription->fwClientID, pcrValue, pcrValue & 0xbfffffff, pDeviceDescription); 3787 if (error == noErr) 3788 error = irmReleaseChannel(pDeviceDescription->fwClientID, 63, pDeviceDescription); 3789 if (error == noErr) 3790 { 3791 fwBandwidthUnits = irmCalculateBandwidthUnits(pcrValue); 3792 error = irmReleaseBandwidth(pDeviceDescription->fwClientID, fwBandwidthUnits, pDeviceDescription); 3793 } 3794 } 3795 3796 // allocate bandwidth 3797 // jkl, bandwidth could be wrong if speed is negotiated faster than s100, too much is allocated and not enough gets deallocated 3798 // could just hard wire to s100 or re-check bandwith in commit phase 3799 pDeviceDescription->cmpOverheadID = 0x0c; 3800 fwBandwidthUnits = irmCalculateBandwidthUnits((pcrValue & 0x03ff) | (pDeviceDescription->cmpOverheadID << 10)); 3801 error = irmAllocateBandwidth(pDeviceDescription->fwClientID, fwBandwidthUnits, pDeviceDescription); 3802 3803 if (error == noErr) 3804 { 3805 pDeviceDescription->cmpBandwidth = fwBandwidthUnits; 3806 3807 // allocate channel 3808 channelNum = 0; 3809 error = irmAllocateChannel(pDeviceDescription->fwClientID, &channelNum, pDeviceDescription); 3810 if (error == noErr) 3811 { 3812 pDeviceDescription->cmpChannel = channelNum; 3813 3814 if (channelNum < 32) 3815 { 3816 pInitIsochPortParams->supportedChannelNumHi = ((UInt32) 0x80000000) >> channelNum; 3817 pInitIsochPortParams->supportedChannelNumLo = 0; 3818 } 3819 else 3820 { 3821 channelNum -= 32; 3822 pInitIsochPortParams->supportedChannelNumHi = 0; 3823 pInitIsochPortParams->supportedChannelNumLo = ((UInt32) 0x80000000) >> channelNum; 3824 } 3825 } 3826 } 3827 } 3828 } 3829 3830 // set speed 3831 if (error == noErr) 3832 { 3833 UInt32 remoteOutputMasterPlugValue; 3834 3835 error = cmpRead(0x00, pDeviceDescription->fwClientID, &remoteOutputMasterPlugValue, pDeviceDescription); 3836 if (error == noErr) 3837 pInitIsochPortParams->speed = (remoteOutputMasterPlugValue >> 30) & 3; 3838 else 3839 { 3840 pInitIsochPortParams->speed = kFWSpeed100MBit; 3841 3842 // don't fail for this 3843 error = noErr; 3844 } 3845 } 3846 3847 } 3848 else 3849 { 3850 // just use channel 63 3851 pInitIsochPortParams->supportedChannelNumHi = 0; 3852 pInitIsochPortParams->supportedChannelNumLo = 1; 3853 3854 // set speed 3855 pInitIsochPortParams->speed = kFWSpeed100MBit; 3856 } 3857 3858 return error; 3859} 3860 3861 3862OSStatus doLocalListenerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams) 3863{ 3864 OSStatus error = noErr; 3865 3866 error = FWAllocateIsochPortID(&pDeviceDescription->isochPortID, pDeviceDescription->dclProgramID, 3867 pInitIsochPortParams->channelNum, pInitIsochPortParams->speed, false); 3868 FailMessageVal( error != noErr, error); 3869 3870 // Send an allocate isoch port command to allocate port for listening 3871 if (error == noErr) 3872 { 3873 FWSetFWCommandParams(pDeviceDescription->isochPortCommandObjectID, pDeviceDescription->fwClientID, kFWCommandSyncFlag, nil, 0); 3874 FWSetIsochPortCommandIsochPortID(pDeviceDescription->isochPortCommandObjectID, pDeviceDescription->isochPortID); 3875 error = FWAllocateLocalIsochronousPort(pDeviceDescription->isochPortCommandObjectID); 3876 FailMessageVal( error != noErr, error); 3877 } 3878 3879 if (pDeviceDescription->componentGlobals->useCMP) 3880 { 3881 // set mac's input plug 3882 if (error == noErr) 3883 error = cmpNewPointToPointConnection(0x80 + (4 * pDeviceDescription->pcrIndex), 3884 pDeviceDescription->localFWReferenceID, 3885 pInitIsochPortParams->channelNum, 0, 0, pDeviceDescription); 3886 } 3887 3888 return error; 3889} 3890 3891 3892OSStatus doRemoteListenerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams) 3893{ 3894 OSStatus error = noErr; 3895 3896 if (pDeviceDescription->componentGlobals->useCMP) 3897 { 3898 if (error == noErr) 3899 { 3900 // set camera's input plug 3901 error = cmpNewPointToPointConnection(0x84, pDeviceDescription->fwClientID, pInitIsochPortParams->channelNum, 0, 0, pDeviceDescription); 3902 } 3903 } 3904 3905 return error; 3906} 3907 3908 3909OSStatus trialLocalListenerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams) 3910{ 3911 UInt32 pcrValue; 3912 OSStatus error = noErr; 3913 3914 if (pDeviceDescription->componentGlobals->useCMP) 3915 { 3916 // initialize mac plug, on-line, read value should be 0 3917 error = cmpRead(4 * pDeviceDescription->pcrIndex, pDeviceDescription->localFWReferenceID, &pcrValue, pDeviceDescription); 3918 if (error == noErr) 3919 error = cmpWrite(4 * pDeviceDescription->pcrIndex, pDeviceDescription->localFWReferenceID, 3920 pcrValue, 0x80000000, pDeviceDescription); 3921 3922 if (error == noErr) 3923 error = cmpRead(0x80, pDeviceDescription->localFWReferenceID, &pcrValue, pDeviceDescription); 3924 3925 if (error == noErr) 3926 pInitIsochPortParams->speed = (pcrValue >> 30) & 3; 3927 else 3928 { 3929 pInitIsochPortParams->speed = kFWSpeed100MBit; 3930 3931 // don't fail for this 3932 error = noErr; 3933 } 3934 } 3935 else 3936 pInitIsochPortParams->speed = kFWSpeed100MBit; 3937 3938 pInitIsochPortParams->supportedChannelNumHi = 0xffffffff; 3939 pInitIsochPortParams->supportedChannelNumLo = 0xffffffff; 3940 3941 return error; 3942} 3943 3944 3945OSStatus trialRemoteListenerPort(DeviceDescriptionPtr pDeviceDescription, FWClientInitIsochPortParams *pInitIsochPortParams) 3946{ 3947 UInt32 remoteInputMasterPlugValue; 3948 OSStatus error = noErr; 3949 3950 if (pDeviceDescription->componentGlobals->useCMP) 3951 { 3952 error = cmpRead(0x80, pDeviceDescription->fwClientID, &remoteInputMasterPlugValue, pDeviceDescription); 3953 if (error == noErr) 3954 pInitIsochPortParams->speed = (remoteInputMasterPlugValue >> 30) & 3; 3955 else 3956 { 3957 pInitIsochPortParams->speed = kFWSpeed100MBit; 3958 3959 // don't fail for this 3960 error = noErr; 3961 } 3962 } 3963 else 3964 pInitIsochPortParams->speed = kFWSpeed100MBit; 3965 3966 pInitIsochPortParams->supportedChannelNumHi = 0xffffffff; 3967 pInitIsochPortParams->supportedChannelNumLo = 0xffffffff; 3968 3969 return error; 3970} 3971 3972 3973OSStatus releaseIsochPort(FWClientReleaseIsochPortParams *pReleaseIsochPortParams, UInt32* outCommandAcceptance) 3974{ 3975 DeviceDescriptionPtr pDeviceDescription; 3976 FWReferenceID fwClientID; 3977 Boolean portIsTalker; 3978 Boolean portIsLocal = false; 3979 OSErr error = noErr; 3980 3981 pDeviceDescription = (DeviceDescriptionPtr) pReleaseIsochPortParams->fwClientIsochPortParams.refCon; 3982 3983 // Get port information 3984 fwClientID = pReleaseIsochPortParams->fwClientInterfaceParams.fwReferenceID; 3985 portIsTalker = pReleaseIsochPortParams->fwClientIsochPortParams.portIsTalker; 3986 3987 // if input and call is not for talker, then call is for local port 3988 if ((pDeviceDescription->inputIsochChannelID == pReleaseIsochPortParams->fwClientIsochPortParams.isochChannelID) && !portIsTalker) 3989 portIsLocal = true; 3990 // JKL, really could be an else here 3991 // if output and call is for talker, then call is for local port 3992 if ((pDeviceDescription->outputIsochChannelID == pReleaseIsochPortParams->fwClientIsochPortParams.isochChannelID) && portIsTalker) 3993 portIsLocal = true; 3994 3995 // if called for local port, release port from FSL 3996 if (portIsLocal) 3997 { 3998 FWSetFWCommandParams(pDeviceDescription->isochPortCommandObjectID, pDeviceDescription->fwClientID, kFWCommandSyncFlag, nil, 0); 3999 FWSetIsochPortCommandIsochPortID(pDeviceDescription->isochPortCommandObjectID, pDeviceDescription->isochPortID); 4000 FWReleaseLocalIsochronousPort(pDeviceDescription->isochPortCommandObjectID); 4001 4002 FWDeallocateIsochPortID(pDeviceDescription->isochPortID); 4003 pDeviceDescription->isochPortID = 0; 4004 } 4005 4006 if (pDeviceDescription->componentGlobals->useCMP) 4007 { 4008 if (portIsTalker) 4009 { 4010 if (portIsLocal) 4011 error = cmpDisposePointToPointConnection(pDeviceDescription->pcrIndex * 4, pDeviceDescription->localFWReferenceID, pDeviceDescription); 4012 else 4013 error = cmpDisposePointToPointConnection(0x04, fwClientID, pDeviceDescription); 4014 } 4015 else 4016 { 4017 if (portIsLocal) 4018 error = cmpDisposePointToPointConnection(0x80 + (pDeviceDescription->pcrIndex * 4), pDeviceDescription->localFWReferenceID, pDeviceDescription); 4019 else 4020 error = cmpDisposePointToPointConnection(0x84, fwClientID, pDeviceDescription); 4021 } 4022 } 4023 4024 FWClientCommandIsComplete( 4025 pReleaseIsochPortParams->fwClientInterfaceParams.fwClientCommandID, 4026 error); 4027 4028 *outCommandAcceptance = kFWClientCommandAcceptNoMore; 4029 4030 return error; 4031} 4032 4033 4034OSStatus startIsochPort(FWClientIsochPortControlParams *pIsochPortControlParams, UInt32* outCommandAcceptance) 4035{ 4036 DeviceDescriptionPtr pDeviceDescription; 4037 FWClientCommandID fwClientCommandID; 4038 FWReferenceID fwClientID; 4039 Boolean completionIsPending = false; 4040 Boolean portIsTalker; 4041 Boolean portIsLocal = false; 4042 OSErr error = noErr; 4043 4044 RecordEventLogger( 'isoc', 'strt', 'port', 'bgn '); 4045 4046 pDeviceDescription = (DeviceDescriptionPtr) pIsochPortControlParams->fwClientIsochPortParams.refCon; 4047 4048 // Get port information 4049 fwClientID = pIsochPortControlParams->fwClientInterfaceParams.fwReferenceID; 4050 portIsTalker = pIsochPortControlParams->fwClientIsochPortParams.portIsTalker; 4051 4052 // if input and call is not for talker, then call is for local port 4053 if ((pDeviceDescription->inputIsochChannelID == pIsochPortControlParams->fwClientIsochPortParams.isochChannelID) && !portIsTalker) 4054 portIsLocal = true; 4055 // JKL, really could be an else here 4056 // if output and call is for talker, then call is for local port 4057 if ((pDeviceDescription->outputIsochChannelID == pIsochPortControlParams->fwClientIsochPortParams.isochChannelID) && portIsTalker) 4058 portIsLocal = true; 4059 4060 // if called for local port, start port 4061 if (portIsLocal) 4062 { 4063 fwClientCommandID = pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID; 4064 FWSetFWCommandParams(pDeviceDescription->startIsochPortCommandObjectID, pDeviceDescription->fwClientID, 0, isochPortCommandCompletionProc, (UInt32) fwClientCommandID); 4065 FWSetIsochPortCommandIsochPortID(pDeviceDescription->startIsochPortCommandObjectID, pDeviceDescription->isochPortID); 4066 error = FWStartLocalIsochronousPort(pDeviceDescription->startIsochPortCommandObjectID); 4067 FailMessageVal( error != noErr, error); 4068 completionIsPending = true; //zzz what if above call returns an error? 4069 } 4070 4071 if ((error == noErr) && completionIsPending) 4072 error = kIDHErrCompletionPending; 4073 4074 if (error != kIDHErrCompletionPending) 4075 { 4076 FWClientCommandIsComplete( 4077 pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID, 4078 error); 4079 } 4080 else 4081 { 4082 error = noErr; 4083 } 4084 4085 *outCommandAcceptance = kFWClientCommandAcceptNoMore; 4086 4087 return error; 4088} 4089 4090 4091OSStatus stopIsochPort(FWClientIsochPortControlParams *pIsochPortControlParams, UInt32* outCommandAcceptance) 4092{ 4093 DeviceDescriptionPtr pDeviceDescription; 4094 FWClientCommandID fwClientCommandID; 4095 FWReferenceID fwClientID; 4096 Boolean completionIsPending = false; 4097 Boolean portIsTalker; 4098 Boolean portIsLocal = false; 4099 OSErr error = noErr; 4100 4101 pDeviceDescription = (DeviceDescriptionPtr) pIsochPortControlParams->fwClientIsochPortParams.refCon; 4102 4103 // Get port information 4104 fwClientID = pIsochPortControlParams->fwClientInterfaceParams.fwReferenceID; 4105 portIsTalker = pIsochPortControlParams->fwClientIsochPortParams.portIsTalker; 4106 4107 // if input and call is not for talker, then call is for local port 4108 if ((pDeviceDescription->inputIsochChannelID == pIsochPortControlParams->fwClientIsochPortParams.isochChannelID) && !portIsTalker) 4109 portIsLocal = true; 4110 // JKL, really could be an else here 4111 // if output and call is for talker, then call is for local port 4112 if ((pDeviceDescription->outputIsochChannelID == pIsochPortControlParams->fwClientIsochPortParams.isochChannelID) && portIsTalker) 4113 portIsLocal = true; 4114 4115 // if called for local port, stop port 4116 if (portIsLocal) 4117 { 4118 fwClientCommandID = pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID; 4119 FWSetFWCommandParams(pDeviceDescription->stopIsochPortCommandObjectID, pDeviceDescription->fwClientID, 0, isochPortCommandCompletionProc, (UInt32) fwClientCommandID); 4120 FWSetIsochPortCommandIsochPortID(pDeviceDescription->stopIsochPortCommandObjectID, pDeviceDescription->isochPortID); 4121 error = FWStopLocalIsochronousPort(pDeviceDescription->stopIsochPortCommandObjectID); 4122 FailMessageVal( error != noErr, error); 4123 completionIsPending = true; //zzz what if above call returns an error? 4124 } 4125 4126 if ((error == noErr) && completionIsPending) 4127 error = kIDHErrCompletionPending; 4128 4129 if (error != kIDHErrCompletionPending) 4130 { 4131 FWClientCommandIsComplete( 4132 pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID, 4133 error); 4134 } 4135 else 4136 { 4137 error = noErr; 4138 } 4139 4140 *outCommandAcceptance = kFWClientCommandAcceptNoMore; 4141 4142 return error; 4143} 4144 4145 4146void isochPortCommandCompletionProc(FWCommandObjectID fwCommandObjectID, OSStatus commandStatus, UInt32 completionProcData) 4147{ 4148 FWClientCommandIsComplete((FWClientCommandID) completionProcData, commandStatus); 4149} 4150 4151//////////////////////////////////////////////////////////////////////////////// 4152// 4153// cmpDisposePointToPointConnection 4154// 4155// Tear down a point to point connection through the client's plug control register. 4156// 4157// *** Must be task level only 4158OSErr cmpDisposePointToPointConnection ( 4159 UInt32 pcrOffset, // offset of register address from fffff0000900 4160 FWClientID clientID, 4161 DeviceDescriptionPtr pDeviceDescription) 4162{ 4163 UInt32 pcrValue, expectedPCRValue; 4164 OSErr err = noErr; 4165 4166 if (pcrOffset > 0x00fc) 4167 err = addressRangeErr; 4168 4169 // get existing plug control register value 4170 if (err == noErr) 4171 err = cmpRead(pcrOffset, clientID, &pcrValue, pDeviceDescription); 4172 4173 if (err == noErr) 4174 { 4175 expectedPCRValue = pcrValue; 4176 4177 // decrement point to point counter 4178 // jkl, only if it is already set, need to fix this 4179 if (pcrValue & 0x3f000000) 4180 pcrValue -= 0x01000000; 4181 4182 // if point to point goes to zero, also turn off broadcast 4183 // jkl, Sony suggests to also make sure camera is stopped 4184 if (!(pcrValue & 0x3f000000)) 4185 pcrValue &= 0xbfffffff; 4186 4187 err = cmpWrite(pcrOffset, clientID, expectedPCRValue, pcrValue, pDeviceDescription); 4188 4189 // release isochronous resources if counter goes to zero and device was talking 4190 if (err == noErr) 4191 { 4192 if (!(pcrValue & 0x3f000000) && (pcrOffset < 0x080)) 4193 { 4194 irmReleaseChannel(clientID, (pcrValue & 0x003f0000) >> 16, pDeviceDescription); 4195 irmReleaseBandwidth(clientID, irmCalculateBandwidthUnits(pcrValue), pDeviceDescription); 4196 } 4197 } 4198 } 4199 4200 return err; 4201} 4202 4203 4204//////////////////////////////////////////////////////////////////////////////// 4205// 4206// cmpNewPointToPointConnection 4207// 4208// Create a point to point connection through the client's and the local 4209// plug control register. 4210// 4211// *** Must be task level only 4212OSErr cmpNewPointToPointConnection ( 4213 UInt32 pcrOffset, // offset of register address from fffff0000900 4214 FWClientID clientID, 4215 UInt32 channel, 4216 UInt32 speed, 4217 UInt32 overhead, 4218 DeviceDescriptionPtr pDeviceDescription) 4219{ 4220 UInt32 pcrValue, expectedPCRValue; 4221 OSErr err = noErr; 4222 4223 if (pcrOffset > 0x00fc) 4224 err = addressRangeErr; 4225 4226 // get existing plug control register value 4227 if (err == noErr) 4228 err = cmpRead(pcrOffset, clientID, &pcrValue, pDeviceDescription); 4229 4230 if (err == noErr) 4231 { 4232 expectedPCRValue = pcrValue; 4233 4234 // increment point to point counter, will this ever overflow?, not turning off broadcast 4235 pcrValue += 0x01000000; 4236 4237 if (pcrOffset < 0x80) 4238 {// setting up output plug 4239 // set speed 4240 pcrValue |= (speed << 14); 4241 4242 // set overhead 4243 pcrValue |= (overhead << 10); 4244 4245 // if not already broadcasting or if point-to-point counter was previously not 0, set channel 4246 if (((pcrValue & 0x3f000000) == 0x01000000) && !(pcrValue & 0x40000000)) 4247 { 4248 // set channel number 4249 pcrValue &= 0xffc0ffff; 4250 pcrValue |= (channel << 16); 4251 } 4252 } 4253 else 4254 { 4255 // for input plug just set channel if no point-to-point exists 4256 if ((pcrValue & 0x3f000000) == 0x01000000) 4257 { 4258 // set channel number 4259 pcrValue &= 0xffc0ffff; 4260 pcrValue |= (channel << 16); 4261 } 4262 } 4263 4264 err = cmpWrite(pcrOffset, clientID, expectedPCRValue, pcrValue, pDeviceDescription); 4265 } 4266 4267 return err; 4268} 4269 4270 4271//////////////////////////////////////////////////////////////////////////////// 4272// 4273// cmpRead 4274// 4275// Read the plug control register specified by the offset. 4276// 4277// *** Must be task level only 4278OSErr cmpRead ( 4279 UInt32 pcrOffset, // offset of register address from fffff0000900 4280 FWClientID clientID, 4281 UInt32 *pcrValue, 4282 DeviceDescriptionPtr deviceDescriptionPtr) 4283{ 4284 FWCommandObjectID fwCommandObjectID = nil; 4285 UInt32 retryCount; 4286 OSErr err = noErr; 4287 4288 if (pcrOffset > 0x00fc) 4289 err = addressRangeErr; 4290 4291 fwCommandObjectID = deviceDescriptionPtr->asynchCommandObjectID; 4292 4293 // set command params for synchronous read 4294 if (err == noErr) 4295 err = FWSetFWCommandParams(fwCommandObjectID, clientID, kFWCommandSyncFlag, nil, 0); 4296 4297 // set more command params for synchronous read 4298 if (err == noErr) 4299 err = FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000900 + pcrOffset, (Ptr) pcrValue, 4); 4300 4301 if (err == noErr) 4302 { 4303 retryCount = 10; 4304 do 4305 { 4306 retryCount--; 4307 err = FWRead(fwCommandObjectID); 4308 if (err == noErr) 4309 return err; 4310 4311 // don't slam the camera too hard 4312 DelayForHardware(DurationToAbsolute(1 * durationMillisecond)); 4313 } 4314 // probably should retry only for specific error like retryExceeded or timeOut 4315 while (err && retryCount); 4316 4317 err = retryExceededErr; 4318 } 4319 4320 return err; 4321} 4322 4323 4324//////////////////////////////////////////////////////////////////////////////// 4325// 4326// cmpWrite 4327// 4328// Write a plug control register through a compare and swap lock transaction. 4329// The plug control register is specified by the offset. After the transaction 4330// The expectedPCRValue is set to the value of the PCR prior before the request. 4331// If this value equals the original passed in value the command completed. 4332// 4333// *** Must be task level only 4334 4335OSErr cmpWrite ( 4336 UInt32 pcrOffset, // offset of register address from fffff0000900 4337 FWClientID clientID, 4338 UInt32 expectedPCRValue, 4339 UInt32 newPCRValue, 4340 DeviceDescriptionPtr deviceDescriptionPtr) 4341{ 4342 FWCommandObjectID fwCommandObjectID = nil; 4343 UInt32 compareAndSwapBuffer[2]; 4344 UInt32 retryCount; 4345 OSErr err = noErr; 4346 4347 if (pcrOffset > 0x00fc) 4348 err = addressRangeErr; 4349 4350 fwCommandObjectID = deviceDescriptionPtr->asynchCommandObjectID; 4351 4352 // set command params for synchronous lock 4353 if (err == noErr) 4354 err = FWSetFWCommandParams(fwCommandObjectID, clientID, kFWCommandSyncFlag, nil, 0); 4355 4356 // set more command params for synchronous lock 4357 if (err == noErr) 4358 { 4359 compareAndSwapBuffer[0] = expectedPCRValue; 4360 compareAndSwapBuffer[1] = newPCRValue; 4361 err = FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000900 + pcrOffset, (Ptr) compareAndSwapBuffer, 8); 4362 } 4363 4364 retryCount = 10; 4365 do 4366 { 4367 retryCount--; 4368 // JKL, fix this, arguments need to be fixed up after each try 4369 err = FWCompareAndSwap(fwCommandObjectID); 4370 if (err == noErr) 4371 { 4372 if (compareAndSwapBuffer[0] == expectedPCRValue) 4373 return err; 4374 else 4375 { 4376 // force it to try again, although probably lost cause at this point 4377 // jkl, need to start back at the beginning of the write command to redo values 4378 err = retryExceededErr; 4379 4380 // jkl ***, hack, reset expectedPCRValue to what was returned even though this no longer may be a valid starting argument 4381 expectedPCRValue = compareAndSwapBuffer[0]; 4382 } 4383 } 4384 4385 // don't slam the camera too hard 4386 DelayForHardware(DurationToAbsolute(1 * durationMillisecond)); 4387 } 4388 // probably should retry only for specific error like retryExceeded or timeOut 4389 while (err && retryCount); 4390 4391 return err; 4392} 4393 4394 4395//////////////////////////////////////////////////////////////////////////////// 4396// 4397// cmpHandleLocalLock 4398// 4399// This is a notification routine that is called once the response to a lock 4400// transaction to one of the PCR addresses has been sent. One way to handle 4401// this is to look at the result of the transaction, is it consistent with 4402// the current configuration. Does the configuration change to match the PCR 4403// request or is the PCR updated with the current configuration overriding 4404// the lock request. This may also be called for locks initiated by the driver 4405// to a local PCR. 4406// 4407// There is also a LockRequest notification that could be setup to look at the 4408// request. I don't know if we have the ability to override the lock request 4409// and basically deny it before FSL responds. Something to talk over with Eric 4410// and Collin. 4411// 4412OSStatus cmpHandleLocalLock( 4413 FWClientAsynchRequestParamsPtr pFWClientAsynchRequestParams, 4414 UInt32 *pCommandAcceptance) 4415{ 4416 DeviceDescriptionPtr pDeviceDescription; 4417 OSStatus status = noErr; 4418 4419 pDeviceDescription = (DeviceDescriptionPtr) pFWClientAsynchRequestParams->pAddressSpecificData; 4420 4421 // now what? 4422 4423 // Complete FireWire client command. 4424 FWClientCommandIsComplete(pFWClientAsynchRequestParams->fwClientInterfaceParams.fwClientCommandID, status); 4425 *pCommandAcceptance = kFWClientCommandAcceptNoMore; 4426 4427 return status; 4428} 4429 4430 4431// *** Must be task level only 4432OSStatus irmReleaseChannel( 4433 FWClientID fwClientID, 4434 UInt32 channel, 4435 DeviceDescriptionPtr deviceDescriptionPtr) 4436{ 4437 FWReferenceID fwIsochResourceManagerID; 4438 FWCommandObjectID fwCommandObjectID = nil; 4439 UInt32 asynchCommandArgs[2]; 4440 UInt32 clippedChannel, saveMaxRT; 4441 OSStatus status = noErr; 4442 4443 status = FWGetFWIsochResourceManagerID(fwClientID, &fwIsochResourceManagerID); 4444 4445 if ((status == noErr) && (fwIsochResourceManagerID != (FWReferenceID) kInvalidFWIsochResourceManagerID)) 4446 { 4447 fwCommandObjectID = deviceDescriptionPtr->asynchCommandObjectID; 4448 4449 FWSetFWCommandParams(fwCommandObjectID, fwIsochResourceManagerID, kFWCommandSyncFlag, nil, 0); 4450 4451 FWGetAsynchCommandMaxRetries ( fwCommandObjectID, &saveMaxRT ); 4452 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, kMaxRetries ); 4453 4454 if (channel < 32) 4455 FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000224, (Ptr) &asynchCommandArgs[0], 4); 4456 else 4457 FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000228, (Ptr) &asynchCommandArgs[0], 4); 4458 4459 // read channel allocated register 4460 status = FWRead(fwCommandObjectID); 4461 4462 if (status == noErr) 4463 { 4464 // check if channel is reserved 4465 clippedChannel = (channel & 0x0000001f); 4466 if (!(asynchCommandArgs[0] & (0x80000000 >> clippedChannel))) 4467 { 4468 // channel is allocated, deallocate it 4469 asynchCommandArgs[1] = asynchCommandArgs[0] | (0x80000000 >> clippedChannel); 4470 4471 // use existing settings except for length 4472 FWSetAsynchCommandLength(fwCommandObjectID, 8); 4473 4474 status = FWCompareAndSwap(fwCommandObjectID); 4475 } 4476 } 4477 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, saveMaxRT ); 4478 } 4479 4480 return status; 4481} 4482 4483 4484// *** Must be task level only 4485OSStatus irmReleaseBandwidth( 4486 FWClientID fwClientID, 4487 UInt32 fwBandwidthUnits, 4488 DeviceDescriptionPtr deviceDescriptionPtr) 4489{ 4490 FWReferenceID fwIsochResourceManagerID; 4491 FWCommandObjectID fwCommandObjectID = nil; 4492 UInt32 asynchCommandArgs[2], saveMaxRT; 4493 OSStatus status = noErr; 4494 4495 status = FWGetFWIsochResourceManagerID(fwClientID, &fwIsochResourceManagerID); 4496 4497 if ((status == noErr) && (fwIsochResourceManagerID != (FWReferenceID) kInvalidFWIsochResourceManagerID)) 4498 { 4499 // read IRM bandwidth register 4500 fwCommandObjectID = deviceDescriptionPtr->asynchCommandObjectID; 4501 4502 FWSetFWCommandParams(fwCommandObjectID, fwIsochResourceManagerID, kFWCommandSyncFlag, nil, 0); 4503 4504 FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000220, (Ptr) &asynchCommandArgs[0], 8); 4505 4506 FWGetAsynchCommandMaxRetries ( fwCommandObjectID, &saveMaxRT ); 4507 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, kMaxRetries ); 4508 4509 // Set up arguments for add. 4510 // First parameter is the threshold, second is amount to add. 4511 // JKL *** Sony uses 0x1388 for starting available bandwidth which is nice since most of the 4512 // camcorders are allocating more bandwidth for one channel than necessary and not enough is 4513 // left for an additional channel 4514 // p1394 says IRM max bandwidth value should be 0x1333, 4915 4515 // asynchCommandArgs[0] = 0x1388; 4516 asynchCommandArgs[0] = 0x1333; 4517 asynchCommandArgs[1] = fwBandwidthUnits; 4518 4519 // Add to bandwidth allocation. 4520 status = FWClippedAdd(fwCommandObjectID); 4521 4522 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, saveMaxRT ); 4523 } 4524 4525 return status; 4526} 4527 4528 4529// *** Must be task level only 4530OSStatus irmAllocateChannel( 4531 FWClientID fwClientID, 4532 UInt32 *channel, 4533 DeviceDescriptionPtr deviceDescriptionPtr) 4534{ 4535 FWReferenceID fwIsochResourceManagerID; 4536 FWCommandObjectID fwCommandObjectID = nil; 4537 UInt32 asynchCommandArgs[2], channelArgs, saveMaxRT; 4538 OSStatus status = noErr; 4539 4540 status = FWGetFWIsochResourceManagerID(fwClientID, &fwIsochResourceManagerID); 4541 4542 // JKL *** this is not right since noErr could get returned but not have an IRM 4543 if ((status == noErr) && (fwIsochResourceManagerID != (FWReferenceID) kInvalidFWIsochResourceManagerID)) 4544 { 4545 // read IRM channel register 4546 fwCommandObjectID = deviceDescriptionPtr->asynchCommandObjectID; 4547 4548 FWSetFWCommandParams(fwCommandObjectID, fwIsochResourceManagerID, kFWCommandSyncFlag, nil, 0); 4549 4550 // populate both command args with the channel registers 4551 FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000224, (Ptr) &asynchCommandArgs[0], 4); 4552 4553 FWGetAsynchCommandMaxRetries ( fwCommandObjectID, &saveMaxRT ); 4554 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, kMaxRetries ); 4555 4556 // read channel hi allocated register 4557 status = FWRead(fwCommandObjectID); 4558 4559 if (status == noErr) 4560 { 4561 FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000228, (Ptr) &asynchCommandArgs[1], 4); 4562 4563 // read channel lo allocated register 4564 status = FWRead(fwCommandObjectID); 4565 } 4566 4567 if (status == noErr) 4568 { 4569 // get next available channel 4570 if (*channel < 32) 4571 channelArgs = asynchCommandArgs[0]; 4572 else 4573 channelArgs = asynchCommandArgs[1]; 4574 while (! (channelArgs & (0x80000000 >> (*channel & 0x0000001f)))) 4575 { 4576 *channel = *channel + 1; 4577 if (*channel > 31) 4578 channelArgs = asynchCommandArgs[1]; 4579 4580 if (*channel > 63) 4581 break; 4582 } 4583 4584 // hopefully a channel got allocated 4585 if (*channel < 32) 4586 { 4587 // set channel hi address 4588 FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000224, (Ptr) &asynchCommandArgs[0], 8); 4589 } 4590 else if (*channel < 64) 4591 { 4592 // set channel lo address 4593 FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000228, (Ptr) &asynchCommandArgs[0], 8); 4594 } 4595 else 4596 status = noChannelsAvailableErr; 4597 4598 if (status == noErr) 4599 { 4600 // clear allocated channel bit 4601 asynchCommandArgs[1] = asynchCommandArgs[0] & ~(0x80000000 >> (*channel & 0x01f)); 4602 4603 // do the command 4604 status = FWCompareAndSwap(fwCommandObjectID); 4605 } 4606 } 4607 4608 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, saveMaxRT ); 4609 } 4610 4611 return status; 4612} 4613 4614 4615// *** Must be task level only 4616OSStatus irmAllocateBandwidth( 4617 FWClientID fwClientID, 4618 UInt32 fwBandwidthUnits, 4619 DeviceDescriptionPtr deviceDescriptionPtr) 4620{ 4621 FWReferenceID fwIsochResourceManagerID; 4622 FWCommandObjectID fwCommandObjectID = nil; 4623 UInt32 asynchCommandArgs[2], saveMaxRT; 4624 OSStatus status = noErr; 4625 4626 status = FWGetFWIsochResourceManagerID(fwClientID, &fwIsochResourceManagerID); 4627 4628 // JKL *** this is not right since noErr could get returned but not have an IRM 4629 if ((status == noErr) && (fwIsochResourceManagerID != (FWReferenceID) kInvalidFWIsochResourceManagerID)) 4630 { 4631 fwCommandObjectID = deviceDescriptionPtr->asynchCommandObjectID; 4632 4633 FWSetFWCommandParams(fwCommandObjectID, fwIsochResourceManagerID, kFWCommandSyncFlag, nil, 0); 4634 4635 // subtract bandwidth with a min at 0 4636 asynchCommandArgs[0] = 0; 4637 asynchCommandArgs[1] = fwBandwidthUnits; 4638 FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000220, (Ptr) &asynchCommandArgs[0], 8); 4639 4640 FWGetAsynchCommandMaxRetries ( fwCommandObjectID, &saveMaxRT ); 4641 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, kMaxRetries ); 4642 4643 // Subtract from bandwidth allocation. 4644 status = FWThresholdSubtract(fwCommandObjectID); 4645 4646 // Check if bandwidth was allocated. 4647 if (status == noErr) 4648 { 4649 // Bandwidth was allocated if old bandwidth value is greater 4650 // or equal to what we asked for. 4651 if (asynchCommandArgs[0] < asynchCommandArgs[1]) 4652 status = insufficientBandwidthErr; 4653 } 4654 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, saveMaxRT ); 4655 } 4656 4657 return status; 4658} 4659 4660 4661UInt32 irmCalculateBandwidthUnits( 4662 UInt32 pcrValue) 4663{ 4664 UInt32 pcrDataRate, 4665 pcrOverheadID, 4666 pcrPayload, 4667 fwBandwidthUnits; 4668 4669 // set bandwidth units according to 61883 formula and PCR value 4670 // JKL *** all cameras do not set these values correctly, some set the 4671 // overhead too high and don't leave enough bandwidth for two streams 4672 4673 // computer data rate multiplier 4674 pcrDataRate = (pcrValue & 0x0000c000) >> 14; 4675 switch (pcrDataRate) 4676 { 4677 case 0: 4678 pcrDataRate = 16; 4679 break; 4680 case 1: 4681 pcrDataRate = 8; 4682 break; 4683 case 2: 4684 pcrDataRate = 4; 4685 break; 4686 } 4687 4688 pcrPayload = pcrValue & 0x03ff; 4689 pcrOverheadID = (pcrValue & 0x03c00) >> 10; 4690 4691 // 0 is max for overhead 4692 if (!pcrOverheadID) 4693 pcrOverheadID = 16; 4694 4695 fwBandwidthUnits = (pcrOverheadID * 32) + ((pcrPayload + 3) * pcrDataRate); 4696 4697 return fwBandwidthUnits; 4698} 4699 4700 4701OSStatus cmpHandleBusReset(FWClientInterfaceParamsPtr pParams, UInt32 *pCommandAcceptance) 4702{ 4703 DeviceDescriptionPtr pDeviceDescription; 4704 OSErr error = noErr; 4705 4706 pDeviceDescription = (DeviceDescriptionPtr) pParams->fwClientSpecificData; 4707 4708 RecordEventLogger( 'cmp ', 'busR', pDeviceDescription->resetStatus, error); 4709 if (pDeviceDescription->resetStatus == kResetInterrupted) 4710 pDeviceDescription->resetStatus = kNoResetsProcessing; 4711 4712 cmpResetStageOne(pDeviceDescription); 4713 4714 FWClientCommandIsComplete(pParams->fwClientCommandID, error); 4715 *pCommandAcceptance = kFWClientCommandAcceptNoMore; 4716 4717 return error; 4718} 4719 4720 4721// 4722// clear local PCR, FSL can do this for us 4723// 4724void cmpResetStageOne(DeviceDescriptionPtr pDeviceDescription) 4725{ 4726 OSErr error = noErr; 4727 4728 RecordEventLogger( 'cmp ', 'res1', pDeviceDescription->resetStatus, error); 4729 if (pDeviceDescription->resetStatus == kNoResetsProcessing) 4730 { 4731 pDeviceDescription->resetStatus = kResetProcessing; 4732 4733 if (pDeviceDescription->inputIsochChannelID) 4734 { 4735 error = cmpResetRead(0xf0000980 + (4 * pDeviceDescription->pcrIndex), pDeviceDescription->localFWReferenceID, 4736 cmpResetStageTwo, pDeviceDescription); 4737 } 4738 else 4739 { 4740 error = cmpResetRead(0xf0000900 + (4 * pDeviceDescription->pcrIndex), pDeviceDescription->localFWReferenceID, 4741 cmpResetStageTwo, pDeviceDescription); 4742 } 4743 4744 if (noErr != error) 4745 pDeviceDescription->resetStatus = kNoResetsProcessing; 4746 } 4747 else 4748 pDeviceDescription->resetStatus = kResetInterrupted; 4749} 4750 4751 4752// 4753// complete clearing local PCR 4754// 4755void cmpResetStageTwo(FWCommandObjectID theObjectID, OSStatus status, UInt32 data) 4756{ 4757 DeviceDescriptionPtr pDeviceDescription = (DeviceDescriptionPtr) data; 4758 OSErr error = noErr; 4759 4760 RecordEventLogger( 'cmp ', 'res2', pDeviceDescription->resetStatus, status); 4761 if (pDeviceDescription->resetStatus == kResetProcessing) 4762 { 4763 if (status == noErr) 4764 { 4765 pDeviceDescription->buffer[0]; 4766 if (pDeviceDescription->inputIsochChannelID) 4767 { 4768 pDeviceDescription->buffer[1] = pDeviceDescription->buffer[0] & 0x803f0000; 4769 error = cmpResetWrite(0xf0000980 + (4 * pDeviceDescription->pcrIndex), pDeviceDescription->localFWReferenceID, 4770 cmpResetStageThree, pDeviceDescription); 4771 } 4772 else 4773 { 4774 pDeviceDescription->buffer[1] = pDeviceDescription->buffer[0] & 0x803fc3ff; 4775 error = cmpResetWrite(0xf0000900 + (4 * pDeviceDescription->pcrIndex), pDeviceDescription->localFWReferenceID, 4776 cmpResetStageThree, pDeviceDescription); 4777 } 4778 } 4779 4780 if ((noErr != status) || (noErr != error)) 4781 pDeviceDescription->resetStatus = kNoResetsProcessing; 4782 } 4783 else 4784 { 4785 // another bus reset came in, start over 4786 pDeviceDescription->resetStatus = kNoResetsProcessing; 4787 cmpResetStageOne(pDeviceDescription); 4788 } 4789} 4790 4791 4792// 4793// re-allocate channel, read IRM channel 4794// 4795void cmpResetStageThree(FWCommandObjectID theObjectID, OSStatus status, UInt32 data) 4796{ 4797 DeviceDescriptionPtr pDeviceDescription = (DeviceDescriptionPtr) data; 4798 FWReferenceID fwIsochResourceManagerID; 4799 OSErr error = noErr; 4800 4801 RecordEventLogger( 'cmp ', 'res3', pDeviceDescription->resetStatus, status); 4802 if (pDeviceDescription->resetStatus == kResetProcessing) 4803 { 4804 if (status == noErr) 4805 { 4806 error = FWGetFWIsochResourceManagerID(pDeviceDescription->fwClientID, &fwIsochResourceManagerID); 4807 4808 if (error == noErr) 4809 { 4810 if (pDeviceDescription->cmpChannel < 32) 4811 error = cmpResetRead(0xf0000224, fwIsochResourceManagerID, cmpResetStageFour, pDeviceDescription); 4812 else 4813 error = cmpResetRead(0xf0000228, fwIsochResourceManagerID, cmpResetStageFour, pDeviceDescription); 4814 } 4815 } 4816 4817 if ((noErr != status) || (noErr != error)) 4818 pDeviceDescription->resetStatus = kNoResetsProcessing; 4819 } 4820 else 4821 { 4822 // another bus reset came in, start over 4823 pDeviceDescription->resetStatus = kNoResetsProcessing; 4824 cmpResetStageOne(pDeviceDescription); 4825 } 4826} 4827 4828 4829// 4830// complete re-allocating channel 4831// jkl, this might already be allocated 4832void cmpResetStageFour(FWCommandObjectID theObjectID, OSStatus status, UInt32 data) 4833{ 4834 DeviceDescriptionPtr pDeviceDescription = (DeviceDescriptionPtr) data; 4835 FWReferenceID fwIsochResourceManagerID; 4836 OSErr error = noErr; 4837 4838 RecordEventLogger( 'cmp ', 'res4', pDeviceDescription->resetStatus, status); 4839 if (pDeviceDescription->resetStatus == kResetProcessing) 4840 { 4841 if (status == noErr) 4842 { 4843 error = FWGetFWIsochResourceManagerID(pDeviceDescription->fwClientID, &fwIsochResourceManagerID); 4844 4845 if (error == noErr) 4846 { 4847 if (pDeviceDescription->cmpChannel < 32) 4848 { 4849 pDeviceDescription->buffer[1] = pDeviceDescription->buffer[0] & ~(0x80000000 >> pDeviceDescription->cmpChannel); 4850 error = cmpResetWrite(0xf0000224, fwIsochResourceManagerID, cmpResetStageFive, pDeviceDescription); 4851 } 4852 else 4853 { 4854 pDeviceDescription->buffer[1] = pDeviceDescription->buffer[0] & ~(0x80000000 >> (pDeviceDescription->cmpChannel - 32)); 4855 error = cmpResetWrite(0xf0000228, fwIsochResourceManagerID, cmpResetStageFive, pDeviceDescription); 4856 } 4857 } 4858 } 4859 4860 if ((noErr != status) || (noErr != error)) 4861 pDeviceDescription->resetStatus = kNoResetsProcessing; 4862 } 4863 else 4864 { 4865 // another bus reset came in, start over 4866 pDeviceDescription->resetStatus = kNoResetsProcessing; 4867 cmpResetStageOne(pDeviceDescription); 4868 } 4869} 4870 4871 4872// 4873// re-allocate bandwidth 4874// jkl, this might already be allocated 4875void cmpResetStageFive(FWCommandObjectID theObjectID, OSStatus status, UInt32 data) 4876{ 4877 FWCommandObjectID fwCommandObjectID; 4878 DeviceDescriptionPtr pDeviceDescription = (DeviceDescriptionPtr) data; 4879 FWReferenceID fwIsochResourceManagerID; 4880 OSErr error = noErr; 4881 UInt32 saveMaxRT; 4882 4883 RecordEventLogger( 'cmp ', 'res5', pDeviceDescription->resetStatus, status); 4884 if (pDeviceDescription->resetStatus == kResetProcessing) 4885 { 4886 if (status == noErr) 4887 { 4888 error = FWGetFWIsochResourceManagerID(pDeviceDescription->fwClientID, &fwIsochResourceManagerID); 4889 4890 if (error == noErr) 4891 { 4892 fwCommandObjectID = pDeviceDescription->asynchCommandObjectID; 4893 4894 // set command params for synchronous read 4895 error = FWSetFWCommandParams(fwCommandObjectID, fwIsochResourceManagerID, 0, cmpResetStageSix, (UInt32) pDeviceDescription); 4896 4897 // set more command params for synchronous read 4898 if (error == noErr) 4899 error = FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, 0xf0000220, (Ptr) &(pDeviceDescription->buffer[0]), 8); 4900 4901 FWGetAsynchCommandMaxRetries ( fwCommandObjectID, &saveMaxRT ); 4902 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, kMaxRetries ); 4903 4904 if (error == noErr) 4905 { 4906 pDeviceDescription->buffer[0] = 0; 4907 pDeviceDescription->buffer[1] = pDeviceDescription->cmpBandwidth; 4908 4909 error = FWThresholdSubtract(fwCommandObjectID); 4910 } 4911 4912 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, saveMaxRT ); 4913 } 4914 } 4915 4916 if ((noErr != status) || (noErr != error)) 4917 pDeviceDescription->resetStatus = kNoResetsProcessing; 4918 } 4919 else 4920 { 4921 // another bus reset came in, start over 4922 pDeviceDescription->resetStatus = kNoResetsProcessing; 4923 cmpResetStageOne(pDeviceDescription); 4924 } 4925} 4926 4927 4928// 4929// set oPCR, read it first 4930// 4931void cmpResetStageSix(FWCommandObjectID theObjectID, OSStatus status, UInt32 data) 4932{ 4933 DeviceDescriptionPtr pDeviceDescription = (DeviceDescriptionPtr) data; 4934 OSErr error = noErr; 4935 4936 RecordEventLogger( 'cmp ', 'res6', pDeviceDescription->resetStatus, status); 4937 if (pDeviceDescription->resetStatus == kResetProcessing) 4938 { 4939 if (status == noErr) 4940 { 4941 if (pDeviceDescription->inputIsochChannelID) 4942 { 4943 error = cmpResetRead(0xf0000904, pDeviceDescription->fwClientID, 4944 cmpResetStageSeven, pDeviceDescription); 4945 } 4946 else 4947 { 4948 error = cmpResetRead(0xf0000900 + (4 * pDeviceDescription->pcrIndex), pDeviceDescription->localFWReferenceID, 4949 cmpResetStageSeven, pDeviceDescription); 4950 } 4951 } 4952 4953 if ((noErr != status) || (noErr != error)) 4954 pDeviceDescription->resetStatus = kNoResetsProcessing; 4955 4956 } 4957 else 4958 { 4959 // another bus reset came in, start over 4960 pDeviceDescription->resetStatus = kNoResetsProcessing; 4961 cmpResetStageOne(pDeviceDescription); 4962 } 4963} 4964 4965 4966 4967// 4968// complete oPCR 4969// 4970void cmpResetStageSeven(FWCommandObjectID theObjectID, OSStatus status, UInt32 data) 4971{ 4972 DeviceDescriptionPtr pDeviceDescription = (DeviceDescriptionPtr) data; 4973 OSErr error = noErr; 4974 4975 RecordEventLogger( 'cmp ', 'res7', pDeviceDescription->resetStatus, status); 4976 if (pDeviceDescription->resetStatus == kResetProcessing) 4977 { 4978 if (status == noErr) 4979 { 4980 if (pDeviceDescription->inputIsochChannelID) 4981 { 4982 pDeviceDescription->buffer[1] = pDeviceDescription->buffer[0] + 0x01000000; 4983 pDeviceDescription->buffer[1] |= (pDeviceDescription->cmpOverheadID << 10); 4984 error = cmpResetWrite(0xf0000904, pDeviceDescription->fwClientID, cmpResetStageEight, pDeviceDescription); 4985 } 4986 else 4987 { 4988 pDeviceDescription->buffer[1] = pDeviceDescription->buffer[0] + 0x01000000; 4989 pDeviceDescription->buffer[1] |= (pDeviceDescription->cmpOverheadID << 10); 4990 error = cmpResetWrite(0xf0000900 + (4 * pDeviceDescription->pcrIndex), pDeviceDescription->localFWReferenceID, 4991 cmpResetStageEight, pDeviceDescription); 4992 } 4993 } 4994 4995 if ((noErr != status) || (noErr != error)) 4996 pDeviceDescription->resetStatus = kNoResetsProcessing; 4997 } 4998 else 4999 { 5000 // another bus reset came in, start over 5001 pDeviceDescription->resetStatus = kNoResetsProcessing; 5002 cmpResetStageOne(pDeviceDescription); 5003 } 5004} 5005 5006 5007// 5008// set iPCR, read it first 5009// 5010void cmpResetStageEight(FWCommandObjectID theObjectID, OSStatus status, UInt32 data) 5011{ 5012 DeviceDescriptionPtr pDeviceDescription = (DeviceDescriptionPtr) data; 5013 OSErr error = noErr; 5014 5015 RecordEventLogger( 'cmp ', 'res8', pDeviceDescription->resetStatus, status); 5016 if (pDeviceDescription->resetStatus == kResetProcessing) 5017 { 5018 if (status == noErr) 5019 { 5020 if (pDeviceDescription->outputIsochChannelID) 5021 { 5022 error = cmpResetRead(0xf0000984, pDeviceDescription->fwClientID, 5023 cmpResetStageNine, pDeviceDescription); 5024 } 5025 else 5026 { 5027 error = cmpResetRead(0xf0000980 + (4 * pDeviceDescription->pcrIndex), pDeviceDescription->localFWReferenceID, 5028 cmpResetStageNine, pDeviceDescription); 5029 } 5030 } 5031 5032 if ((noErr != status) || (noErr != error)) 5033 pDeviceDescription->resetStatus = kNoResetsProcessing; 5034 } 5035 else 5036 { 5037 // another bus reset came in, start over 5038 pDeviceDescription->resetStatus = kNoResetsProcessing; 5039 cmpResetStageOne(pDeviceDescription); 5040 } 5041} 5042 5043 5044// 5045// complete iPCR 5046// 5047void cmpResetStageNine(FWCommandObjectID theObjectID, OSStatus status, UInt32 data) 5048{ 5049 DeviceDescriptionPtr pDeviceDescription = (DeviceDescriptionPtr) data; 5050 OSErr error = noErr; 5051 5052 RecordEventLogger( 'cmp ', 'res9', pDeviceDescription->resetStatus, status); 5053 if (pDeviceDescription->resetStatus == kResetProcessing) 5054 { 5055 if (status == noErr) 5056 { 5057 if (pDeviceDescription->outputIsochChannelID) 5058 { 5059 pDeviceDescription->buffer[1] = (pDeviceDescription->buffer[0] + 0x01000000) & 0xffc0ffff; 5060 pDeviceDescription->buffer[1] |= (pDeviceDescription->cmpChannel << 16); 5061 error = cmpResetWrite(0xf0000984, pDeviceDescription->fwClientID, cmpResetComplete, pDeviceDescription); 5062 } 5063 else 5064 { 5065 pDeviceDescription->buffer[1] = (pDeviceDescription->buffer[0] + 0x01000000) & 0xffc0ffff; 5066 pDeviceDescription->buffer[1] |= (pDeviceDescription->cmpChannel << 16); 5067 error = cmpResetWrite(0xf0000980 + (4 * pDeviceDescription->pcrIndex), pDeviceDescription->localFWReferenceID, 5068 cmpResetComplete, pDeviceDescription); 5069 } 5070 } 5071 5072 if ((noErr != status) || (noErr != error)) 5073 pDeviceDescription->resetStatus = kNoResetsProcessing; 5074 5075 } 5076 else 5077 { 5078 // another bus reset came in, start over 5079 pDeviceDescription->resetStatus = kNoResetsProcessing; 5080 cmpResetStageOne(pDeviceDescription); 5081 } 5082} 5083 5084 5085void cmpResetComplete(FWCommandObjectID theObjectID, OSStatus status, UInt32 data) 5086{ 5087 DeviceDescriptionPtr pDeviceDescription = (DeviceDescriptionPtr) data; 5088 OSErr error = noErr; 5089 5090 RecordEventLogger( 'cmp ', 'res ', 'comp', status); 5091 pDeviceDescription->resetStatus = kNoResetsProcessing; 5092} 5093 5094 5095// 5096// Do an asynch read 5097// 5098OSErr cmpResetRead ( 5099 UInt32 offsetLo, 5100 FWClientID clientID, 5101 FWCommandCompletionProcPtr completionProc, 5102 DeviceDescriptionPtr deviceDescriptionPtr) 5103{ 5104 FWCommandObjectID fwCommandObjectID; 5105 OSErr error = noErr; 5106 UInt32 saveMaxRT; 5107 5108 fwCommandObjectID = deviceDescriptionPtr->asynchCommandObjectID; 5109 5110 // set command params for synchronous read 5111 error = FWSetFWCommandParams(fwCommandObjectID, clientID, 0, completionProc, (UInt32) deviceDescriptionPtr); 5112 5113 // set more command params for synchronous read 5114 if (error == noErr) 5115 error = FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, offsetLo, (Ptr) &(deviceDescriptionPtr->buffer[0]), 4); 5116 5117 FWGetAsynchCommandMaxRetries ( fwCommandObjectID, &saveMaxRT ); 5118 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, kMaxRetries ); 5119 5120 if (error == noErr) 5121 error = FWRead(fwCommandObjectID); 5122 5123 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, saveMaxRT ); 5124 5125 return error; 5126} 5127 5128 5129// 5130// Do an asynch write, really a lock 5131// 5132OSErr cmpResetWrite ( 5133 UInt32 offsetLo, 5134 FWClientID clientID, 5135 FWCommandCompletionProcPtr completionProc, 5136 DeviceDescriptionPtr deviceDescriptionPtr) 5137{ 5138 FWCommandObjectID fwCommandObjectID; 5139 OSErr error = noErr; 5140 UInt32 saveMaxRT; 5141 5142 fwCommandObjectID = deviceDescriptionPtr->asynchCommandObjectID; 5143 5144 // set command params for synchronous read 5145 error = FWSetFWCommandParams(fwCommandObjectID, clientID, 0, completionProc, (UInt32) deviceDescriptionPtr); 5146 5147 // set more command params for synchronous read 5148 if (error == noErr) 5149 error = FWSetCommonAsynchCommandParams(fwCommandObjectID, 0x0000ffff, offsetLo, (Ptr) &(deviceDescriptionPtr->buffer[0]), 8); 5150 5151 FWGetAsynchCommandMaxRetries ( fwCommandObjectID, &saveMaxRT ); 5152 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, kMaxRetries ); 5153 5154 if (error == noErr) 5155 error = FWCompareAndSwap(fwCommandObjectID); 5156 5157 FWSetAsynchCommandMaxRetries ( fwCommandObjectID, saveMaxRT ); 5158 5159 return error; 5160} 5161 5162 5163Boolean useCMP() 5164{ 5165 Handle h; 5166 Str63 fileName; 5167 CInfoPBRec catInfoPB; 5168 FSSpec fileSpec; 5169 SInt32 extfDirID; 5170 SInt16 extfIndex = 1; 5171 SInt16 extfVRefNum, fRef; 5172 SInt32 gestaltVers; 5173 OSErr err; 5174 Boolean useCMP = false; // default is to not use it 5175 5176 // use cmp only if FireWire 2.2 or greater 5177 err = Gestalt(gestaltFireWireVersion, &gestaltVers); 5178 if (err == noErr) 5179 { 5180 if (gestaltVers >= 0x0220) 5181 useCMP = true; 5182 } 5183 5184 // if FireWire 2.2 or greater check if useGestalt resource is available and its value matches 5185 if (useCMP) 5186 { 5187 // get a shortcut to the extensions folder 5188 err = FindFolder(kOnSystemDisk, kExtensionFolderType, kDontCreateFolder, &extfVRefNum, &extfDirID); 5189 5190 if (err == noErr) 5191 { 5192 // iterate through files in extensions folder 5193 while (err == noErr) 5194 { 5195 fileName[ 0 ] = '\0'; 5196 fileName[ 1 ] = '\0'; 5197 catInfoPB.hFileInfo.ioNamePtr = &fileName[ 0 ]; 5198 catInfoPB.hFileInfo.ioVRefNum = extfVRefNum; 5199 catInfoPB.hFileInfo.ioFDirIndex = extfIndex++; 5200 catInfoPB.hFileInfo.ioDirID = extfDirID; 5201 err = PBGetCatInfoSync(&catInfoPB); 5202 if (err == noErr) 5203 { 5204 // find the file matching these attributes 5205 if ((catInfoPB.hFileInfo.ioFlAttrib & 0x10) != 0 || 5206 (catInfoPB.hFileInfo.ioFlFndrInfo.fdType != 'INIT') || 5207 (catInfoPB.hFileInfo.ioFlFndrInfo.fdCreator != 'dvfw')) 5208 continue; 5209 5210 // found our file, make an FSSpec 5211 err = FSMakeFSSpec(extfVRefNum, extfDirID, catInfoPB.hFileInfo.ioNamePtr, &fileSpec); 5212 5213 break; 5214 5215 } 5216 } 5217 } 5218 5219 if (err == noErr) 5220 { 5221 fRef = FSpOpenResFile(&fileSpec, fsRdPerm); 5222 err = ResError(); 5223 if (err == noErr) 5224 { 5225 h = Get1Resource('ucmp', -20756); 5226 err = ResError(); 5227 if ((err == noErr) && (h != nil)) 5228 useCMP = true; 5229 else 5230 useCMP = false; 5231 5232 CloseResFile(fRef); 5233 } 5234 } 5235 5236 // turn off useCMP in case of any other error 5237 if (err != noErr) 5238 useCMP = false; 5239 } 5240 5241 return useCMP; 5242} 5243 5244 5245OSErr enableRead(IsochComponentInstancePtr ih) 5246{ 5247 FWCommandObjectID isochChannelCommandObjectID = nil; 5248 DeviceDescriptionPtr pDeviceDescription; 5249 SInt32 time; 5250 OSErr error = noErr; 5251 5252 error = findDeviceDescriptionforDevice(ih, ih->deviceID, &pDeviceDescription); 5253 FailMessageVal( error != noErr, error); 5254 5255 if (error == noErr) 5256 { 5257 error = dclInitInput(pDeviceDescription, ih->gGlobals); 5258 FailMessageVal( error != noErr, error); 5259 } 5260 5261 if (error == noErr) 5262 { 5263 // JKL, how do we know the speed before doing CMP, IRM 5264 error = FWAllocateIsochronousChannelID(&pDeviceDescription->inputIsochChannelID, false, 30000000, kFWSpeed100MBit); 5265 FailMessageVal( error != noErr, error); 5266 if (error != noErr) 5267 disposeDCLInput(pDeviceDescription->pGlobalDVInData); 5268 } 5269 5270 // add a talking client, camera 5271 if (error == noErr) 5272 { 5273 error = FWAddIsochronousChannelClient(pDeviceDescription->inputIsochChannelID, pDeviceDescription->fwClientID, (UInt32) pDeviceDescription, true); 5274 FailMessageVal( error != noErr, error); 5275 if (error != noErr) 5276 { 5277 FWDeallocateIsochronousChannelID(pDeviceDescription->inputIsochChannelID); 5278 pDeviceDescription->inputIsochChannelID = nil; 5279 disposeDCLInput(pDeviceDescription->pGlobalDVInData); 5280 } 5281 } 5282 5283 // add a listening client, mac 5284 if (error == noErr) 5285 { 5286 error = FWAddIsochronousChannelClient(pDeviceDescription->inputIsochChannelID, pDeviceDescription->fwClientID, (UInt32) pDeviceDescription, false); 5287 FailMessageVal( error != noErr, error); 5288 if( error != noErr ) 5289 { 5290 FWDeallocateIsochronousChannelID(pDeviceDescription->inputIsochChannelID); 5291 pDeviceDescription->inputIsochChannelID = nil; 5292 disposeDCLInput(pDeviceDescription->pGlobalDVInData); 5293 } 5294 } 5295 5296 // Initialize the isochronous channel 5297 if (error == noErr) 5298 { 5299 if (pDeviceDescription->componentGlobals->useCMP) 5300 { 5301 pDeviceDescription->resetStatus = kNoResetsProcessing; 5302 5303 // allocate PCR space from FSL 5304 // JKL, for now should get pcr #1, what if we don't 5305 error = FWAllocatePCRAddressSpace(&pDeviceDescription->pcrID, pDeviceDescription->fwClientID, 5306 (Ptr) &pDeviceDescription->pcrBuffer, 5307 kFWAddressReadEnable | kFWAddressLockEnable | 5308 kFWAddressLockRequestNotify | kFWAddressLockCompleteNotify, 5309 (Ptr) pDeviceDescription, true /* inputPCR */, 1, &pDeviceDescription->pcrIndex); 5310 FailMessageVal( error != noErr, error); 5311 5312 // JKL, not using lock call backs, could be used to respond to device trying to modify local PCR's 5313 // if (error == noErr) 5314 // error = FWSetFWClientLockCompleteProc(pDeviceDescription->fwClientID, pcrHandleLocalLock); 5315 // 5316 // if (error == noErr) 5317 // error = FWSetFWClientLockRequestProc(pDeviceDescription->fwClientID, pcrHandleLocalLock); 5318 5319 // add bus reset proc 5320 if (error == noErr) 5321 error = FWSetFWClientBusManagementNotifyProc(pDeviceDescription->fwClientID, (FWClientResetNotifyProcPtr) cmpHandleBusReset); 5322 FailMessageVal( error != noErr, error); 5323 } 5324 5325 // register for bus reset notification from FireWire for DV deviceChanged notification 5326 // unregister at release 5327 if (error == noErr) 5328 { 5329 error = FWSetFWClientResetNotifyProc(pDeviceDescription->fwClientID, handleBusReset); 5330 FailMessageVal( error != noErr, error); 5331 } 5332 5333 if (error == noErr) 5334 { 5335 error = FWAllocateIsochChannelCommandObject(&isochChannelCommandObjectID); 5336 FailMessageVal( error != noErr, error); 5337 } 5338 5339 if (error == noErr) 5340 { 5341 FWSetFWCommandParams(isochChannelCommandObjectID, (FWReferenceID) kInvalidFWReferenceID, kFWCommandSyncFlag, nil, 0); 5342 FWSetIsochChannelCommandIsochChannelID(isochChannelCommandObjectID, pDeviceDescription->inputIsochChannelID); 5343 error = FWInitializeIsochronousChannel(isochChannelCommandObjectID); 5344 FailMessageVal( error != noErr, error); 5345 } 5346 5347 if (error != noErr) 5348 { 5349 // release channel even though init failed, part of init (listener or talker) may have succeeded 5350 FWReleaseIsochronousChannel(isochChannelCommandObjectID); 5351 FWDeallocateIsochronousChannelID(pDeviceDescription->inputIsochChannelID); 5352 pDeviceDescription->inputIsochChannelID = nil; 5353 disposeDCLInput(pDeviceDescription->pGlobalDVInData); 5354 } 5355 else 5356 { 5357 // Start the isochronous channel 5358 error = FWSetFWCommandParams(isochChannelCommandObjectID, (FWReferenceID) kInvalidFWReferenceID, kFWCommandSyncFlag, nil, 0); 5359 FailMessageVal( error != noErr, error); 5360 error = FWSetIsochChannelCommandIsochChannelID(isochChannelCommandObjectID, pDeviceDescription->inputIsochChannelID); 5361 FailMessageVal( error != noErr, error); 5362 5363 // JKL, revisit this. 5364 // delay because some (many) cameras send bad data immediately after you change the plug control registers 5365 // (at least that's my guess, It could be a bug somewhere in FSL... who knows... 5366 5367 // we reprogram the PCRs with the above FWInitializeIsochronousChannel call 5368 5369 // the delay was arrived at by good ole' trial and error 5370 time = TickCount(); 5371 while( TickCount() < (time + 7) ) 5372 { 5373 // Yes...really do nothing 5374 ; 5375 } 5376 5377 error = FWStartIsochronousChannel(isochChannelCommandObjectID); 5378 FailMessageVal( error != noErr, error); 5379 if (error != noErr) 5380 { 5381 FWReleaseIsochronousChannel(isochChannelCommandObjectID); 5382 FWDeallocateIsochronousChannelID(pDeviceDescription->inputIsochChannelID); 5383 pDeviceDescription->inputIsochChannelID = nil; 5384 disposeDCLInput(pDeviceDescription->pGlobalDVInData); 5385 } 5386 } 5387 } 5388 5389 if (isochChannelCommandObjectID) 5390 FWDeallocateFWCommandObject(isochChannelCommandObjectID); 5391 5392 // JKL, readEnabledNotification? 5393 if (error) 5394 FWSetFWClientResetNotifyProc(pDeviceDescription->fwClientID, nil); 5395 5396 FailMessageVal( error != noErr, error); 5397 5398 return error; 5399} 5400 5401 5402OSErr disableRead(IsochComponentInstancePtr ih) 5403{ 5404 FWCommandObjectID isochChannelCommandObjectID = nil; 5405 DeviceDescriptionPtr pDeviceDescription; 5406 OSErr error = noErr; 5407 5408 error = findDeviceDescriptionforDevice(ih, ih->deviceID, &pDeviceDescription); 5409 5410 if (error == noErr) 5411 { 5412 if (pDeviceDescription->inputIsochChannelID) 5413 { 5414 if (error == noErr) 5415 error = FWAllocateIsochChannelCommandObject(&isochChannelCommandObjectID); 5416 5417 if (error == noErr) 5418 { 5419 // stop channel 5420 FWSetFWCommandParams(isochChannelCommandObjectID, (FWReferenceID) kInvalidFWReferenceID, kFWCommandSyncFlag, nil, 0); 5421 FWSetIsochChannelCommandIsochChannelID(isochChannelCommandObjectID, pDeviceDescription->inputIsochChannelID); 5422 FWStopIsochronousChannel(isochChannelCommandObjectID); 5423 5424 // release channel 5425 FWSetFWCommandParams(isochChannelCommandObjectID, (FWReferenceID) kInvalidFWReferenceID, kFWCommandSyncFlag, nil, 0); 5426 FWSetIsochChannelCommandIsochChannelID(isochChannelCommandObjectID, pDeviceDescription->inputIsochChannelID); 5427 FWReleaseIsochronousChannel(isochChannelCommandObjectID); 5428 FWDeallocateIsochronousChannelID(pDeviceDescription->inputIsochChannelID); 5429 pDeviceDescription->inputIsochChannelID = 0; 5430 5431 if (pDeviceDescription->componentGlobals->useCMP) 5432 { 5433 // JKL, should clear pcr before deallocating? 5434 FWDeallocateAddressSpace(pDeviceDescription->pcrID); 5435 pDeviceDescription->pcrID = 0; 5436 pDeviceDescription->pcrIndex = 0; 5437 5438 FWSetFWClientBusManagementNotifyProc(pDeviceDescription->fwClientID, (FWClientResetNotifyProcPtr) nil); 5439 5440 // JKL, not using lock call backs or bus management yet 5441 // FWSetFWClientLockCompleteProc(pDeviceDescription->fwClientID, (FWClientLockProcPtr) nil); 5442 // FWSetFWClientLockRequestProc(pDeviceDescription->fwClientID, (FWClientLockProcPtr) nil); 5443 } 5444 } 5445 5446 // unregister bus reset notification 5447 FWSetFWClientResetNotifyProc(pDeviceDescription->fwClientID, (FWClientResetNotifyProcPtr) nil); 5448 5449 disposeDCLInput(pDeviceDescription->pGlobalDVInData); 5450 } 5451 } 5452 return error; 5453} 5454 5455 5456OSErr enableWrite(IsochComponentInstancePtr ih) 5457{ 5458 FWCommandObjectID isochChannelCommandObjectID = nil; 5459 DeviceDescriptionPtr pDeviceDescription; 5460 SInt32 time; 5461 OSErr error = noErr; 5462 5463 error = findDeviceDescriptionforDevice(ih, ih->deviceID, &pDeviceDescription); 5464 5465 if (error == noErr) 5466 error = dclInitOutput(pDeviceDescription, ih->gGlobals); 5467 5468 if (error == noErr) 5469 { 5470 // JKL, how do we know the speed before doing CMP, IRM 5471 error = FWAllocateIsochronousChannelID(&pDeviceDescription->outputIsochChannelID, false, 30000000, kFWSpeed100MBit); 5472 if (error != noErr) 5473 disposeDCLOutput(pDeviceDescription->pGlobalDVOutData); 5474 } 5475 5476 // add a talking client, mac 5477 if (error == noErr) 5478 { 5479 error = FWAddIsochronousChannelClient(pDeviceDescription->outputIsochChannelID, pDeviceDescription->fwClientID, (UInt32) pDeviceDescription, true); 5480 if (error != noErr) 5481 { 5482 FWDeallocateIsochronousChannelID(pDeviceDescription->outputIsochChannelID); 5483 pDeviceDescription->outputIsochChannelID = nil; 5484 disposeDCLOutput(pDeviceDescription->pGlobalDVOutData); 5485 } 5486 } 5487 5488 // add a listening client, camera 5489 if (error == noErr) 5490 { 5491 error = FWAddIsochronousChannelClient(pDeviceDescription->outputIsochChannelID, pDeviceDescription->fwClientID, (UInt32) pDeviceDescription, false); 5492 if (error != noErr) 5493 { 5494 FWDeallocateIsochronousChannelID(pDeviceDescription->outputIsochChannelID); 5495 pDeviceDescription->outputIsochChannelID = nil; 5496 disposeDCLOutput(pDeviceDescription->pGlobalDVOutData); 5497 } 5498 } 5499 5500 // Initialize the isochronous channel 5501 if (error == noErr) 5502 { 5503 5504 if (pDeviceDescription->componentGlobals->useCMP) 5505 { 5506 pDeviceDescription->resetStatus = kNoResetsProcessing; 5507 5508 // allocate PCR space from FSL 5509 // JKL, for now should get pcr #1, what if we don't 5510 error = FWAllocatePCRAddressSpace(&pDeviceDescription->pcrID, pDeviceDescription->fwClientID, 5511 (Ptr) &pDeviceDescription->pcrBuffer, 5512 kFWAddressReadEnable | kFWAddressLockEnable | 5513 kFWAddressLockRequestNotify | kFWAddressLockCompleteNotify, 5514 (Ptr) pDeviceDescription, false /* outputPCR */, 1, &pDeviceDescription->pcrIndex); 5515 FailMessageVal( error != noErr, error); 5516 5517 // JKL, not using lock call backs, could be used to respond to a device trying to modify local PCR's 5518 // if (error == noErr) 5519 // error = FWSetFWClientLockCompleteProc(pDeviceDescription->fwClientID, cmpHandleLocalLock); 5520 // 5521 // if (error == noErr) 5522 // error = FWSetFWClientLockRequestProc(pDeviceDescription->fwClientID, cmpHandleLocalLock); 5523 5524 // add bus reset proc 5525 if (error == noErr) 5526 error = FWSetFWClientBusManagementNotifyProc(pDeviceDescription->fwClientID, (FWClientResetNotifyProcPtr) cmpHandleBusReset); 5527 FailMessageVal( error != noErr, error); 5528 } 5529 5530 // register for bus reset notification from FireWire for DV deviceChanged notification 5531 // unregister at release 5532 if (error == noErr) 5533 { 5534 error = FWSetFWClientResetNotifyProc(pDeviceDescription->fwClientID, handleBusReset); 5535 FailMessageVal( error != noErr, error); 5536 } 5537 5538 if (error == noErr) 5539 { 5540 error = FWAllocateIsochChannelCommandObject(&isochChannelCommandObjectID); 5541 FailMessageVal( error != noErr, error); 5542 } 5543 5544 if (error == noErr) 5545 { 5546 FWSetFWCommandParams(isochChannelCommandObjectID, (FWReferenceID) kInvalidFWReferenceID, kFWCommandSyncFlag, nil, 0); 5547 FWSetIsochChannelCommandIsochChannelID(isochChannelCommandObjectID, pDeviceDescription->outputIsochChannelID); 5548 error = FWInitializeIsochronousChannel(isochChannelCommandObjectID); 5549 } 5550 5551 if (error != noErr) 5552 { 5553 // release channel even though init failed, part of init (listener or talker) may have succeeded 5554 FWReleaseIsochronousChannel(isochChannelCommandObjectID); 5555 FWDeallocateIsochronousChannelID(pDeviceDescription->outputIsochChannelID); 5556 pDeviceDescription->outputIsochChannelID = nil; 5557 disposeDCLOutput(pDeviceDescription->pGlobalDVOutData); 5558 } 5559 else 5560 { 5561 // Start the isochronous channel 5562 error = FWSetFWCommandParams(isochChannelCommandObjectID, (FWReferenceID) kInvalidFWReferenceID, kFWCommandSyncFlag, nil, 0); 5563 error = FWSetIsochChannelCommandIsochChannelID(isochChannelCommandObjectID, pDeviceDescription->outputIsochChannelID); 5564 5565 // delay because some (many) cameras send bad data immediately after you change the plug control registers 5566 // (at least that's my guess, It could be a bug somewhere in FSL... who knows... 5567 // we reprogram the PCRs with the above FWInitializeIsochronousChannel call 5568 // the delay was arrived at by good ole' trial and error 5569 5570 error = FWStartIsochronousChannel(isochChannelCommandObjectID); 5571 if (error == noErr) 5572 { 5573 time = TickCount(); 5574 while( TickCount() < (time + 60) ) 5575 { 5576 // Yes...really do nothing 5577 ; 5578 } 5579 } 5580 else 5581 { 5582 FWReleaseIsochronousChannel(isochChannelCommandObjectID); 5583 FWDeallocateIsochronousChannelID(pDeviceDescription->outputIsochChannelID); 5584 pDeviceDescription->outputIsochChannelID = nil; 5585 disposeDCLOutput(pDeviceDescription->pGlobalDVOutData); 5586 } 5587 } 5588 } 5589 5590 if (error) 5591 FWSetFWClientResetNotifyProc(pDeviceDescription->fwClientID, nil); 5592 5593 if (isochChannelCommandObjectID) 5594 FWDeallocateFWCommandObject(isochChannelCommandObjectID); 5595 5596 // JKL, writeEnabledNotification 5597 5598 return error; 5599} 5600 5601 5602OSErr disableWrite(IsochComponentInstancePtr ih) 5603{ 5604 FWCommandObjectID isochChannelCommandObjectID = nil; 5605 DeviceDescriptionPtr pDeviceDescription; 5606 OSErr error = noErr; 5607 5608 error = findDeviceDescriptionforDevice(ih, ih->deviceID, &pDeviceDescription); 5609 5610 if (error == noErr) 5611 { 5612 if (pDeviceDescription->outputIsochChannelID) 5613 { 5614 if (error == noErr) 5615 error = FWAllocateIsochChannelCommandObject(&isochChannelCommandObjectID); 5616 5617 if (error == noErr) 5618 { 5619 // JKL, need top delay stopping transmit until all queued frames are sent 5620 // originally had a isFinished call and then delayed 2 * ticks * howeverManyFramesAreQueued 5621 // stop channel 5622 FWSetFWCommandParams(isochChannelCommandObjectID, (FWReferenceID) kInvalidFWReferenceID, kFWCommandSyncFlag, nil, 0); 5623 FWSetIsochChannelCommandIsochChannelID(isochChannelCommandObjectID, pDeviceDescription->outputIsochChannelID); 5624 FWStopIsochronousChannel(isochChannelCommandObjectID); 5625 5626 // release channel 5627 FWSetFWCommandParams(isochChannelCommandObjectID, (FWReferenceID) kInvalidFWReferenceID, kFWCommandSyncFlag, nil, 0); 5628 FWSetIsochChannelCommandIsochChannelID(isochChannelCommandObjectID, pDeviceDescription->outputIsochChannelID); 5629 FWReleaseIsochronousChannel(isochChannelCommandObjectID); 5630 FWDeallocateIsochronousChannelID(pDeviceDescription->outputIsochChannelID); 5631 pDeviceDescription->outputIsochChannelID = 0; 5632 5633 if (pDeviceDescription->componentGlobals->useCMP) 5634 { 5635 // jkl, should clear pcr before deallocating 5636 FWDeallocateAddressSpace(pDeviceDescription->pcrID); 5637 pDeviceDescription->pcrID = 0; 5638 pDeviceDescription->pcrIndex = 0; 5639 5640 FWSetFWClientBusManagementNotifyProc(pDeviceDescription->fwClientID, (FWClientResetNotifyProcPtr) nil); 5641 5642 // JKL, not using lock call backs or bus management yet 5643 // FWSetFWClientLockCompleteProc(pDeviceDescription->fwClientID, (FWClientLockProcPtr) nil); 5644 // FWSetFWClientLockRequestProc(pDeviceDescription->fwClientID, (FWClientLockProcPtr) nil); 5645 } 5646 } 5647 5648 // unregister bus reset notification 5649 FWSetFWClientResetNotifyProc(pDeviceDescription->fwClientID, (FWClientResetNotifyProcPtr) nil); 5650 5651 disposeDCLOutput(pDeviceDescription->pGlobalDVOutData); 5652 } 5653 } 5654 return error; 5655} 5656 5657 5658OSErr dclInitOutput(DeviceDescriptionPtr pDeviceDescription, 5659 IsochComponentGlobals* isochComponentGlobals) 5660{ 5661 float A, B, C, d, n; 5662 UInt32 numEmptyPacketsPerPlayBufferGroup; 5663 UInt32 transmitBuffersSize; 5664 DCLCommandPoolPtr pDCLCommandPool; 5665 DCLCommandPtr pDCLCommand; 5666 DCLCommandPtr pFirstBufferGroupDCLCommand; 5667 DVGlobalOutPtr pGlobalData; 5668 DCLLabelPtr pUnderrunDCLLabel, 5669 pLoopDCLLabel, 5670 pBufferGroupDCLLabel, 5671 pDCLLabel; 5672 DCLTransferPacketPtr pDCLTransferPacket; 5673 DCLCallProcPtr pDCLCallProc; 5674 DCLSetTagSyncBitsPtr pDCLSetTagSyncBits; 5675 DCLJumpPtr pDCLJump, 5676 pBufferGroupDCLJump; 5677 DCLLabelPtr pBufferGroupSkipEmptyPacketDCLLabel; 5678 DCLUpdateDCLListPtr pDCLUpdateDCLList; 5679 DCLTimeStampPtr pDCLTimeStamp; 5680 5681 DVLocalOutPtr pPlayBufferGroupData; 5682 UInt32 *pTransmitBuffer; 5683 UInt32 bufferGroupNum, 5684 dataPacketNum, 5685 numPackets; 5686 UInt32 emptyPacketNumerator; 5687 UInt32 playFrameRateNumerator, playFrameRateDenominator; 5688 UInt32 numDataPacketsPerPage; 5689 UInt32 pageSize; 5690 OSErr error = noErr; 5691 5692 // allocate space for global data 5693 pGlobalData = PoolAllocateResident(sizeof(DVGlobalOut), true); 5694 if (pGlobalData == nil) 5695 error = memFullErr; 5696 5697 if (error == noErr) 5698 { 5699 pDeviceDescription->pGlobalDVOutData = pGlobalData; 5700 5701 pGlobalData->isochComponentGlobals = isochComponentGlobals; 5702 pGlobalData->deviceID = pDeviceDescription->deviceID; 5703 pGlobalData->pBufferGroupDataList = nil; 5704 pGlobalData->pDCLCommandPool = nil; 5705 pGlobalData->pDVFrameOutputData = nil; 5706 pGlobalData->pTransmitBuffers = nil; 5707 pGlobalData->isNTSC = (pDeviceDescription->standard == ntscIn); 5708 pGlobalData->localFWReferenceID = pDeviceDescription->localFWReferenceID; 5709 5710 error = initDVFrameOutput(pDeviceDescription->standard, &pGlobalData->pDVFrameOutputData); 5711 } 5712 5713 if (error == noErr) 5714 { 5715 error = FWCreateDCLProgram(&pGlobalData->DCLProgramID); 5716 pDeviceDescription->dclProgramID = pGlobalData->DCLProgramID; 5717 } 5718 5719 if (error == noErr) 5720 { 5721 error = FWAllocateIsochChannelCommandObject(&pGlobalData->isochChannelCommandObjectID); 5722 } 5723 5724 5725 if (error == noErr) 5726 { 5727 if( pGlobalData->isNTSC ) 5728 { 5729 pGlobalData->playFramePeriodNumerator = kNTSCPlayFramePeriodNumerator; 5730 pGlobalData->playFramePeriodDenominator = kNTSCPlayFramePeriodDenominator; 5731 playFrameRateNumerator = kNTSCFrameRateNumerator; 5732 playFrameRateDenominator = kNTSCFrameRateDenominator; 5733 pGlobalData->numDataPacketsPerFrame = kNTSCNumDataPacketsPerDVFrame; 5734 } 5735 else 5736 { 5737 pGlobalData->playFramePeriodNumerator = kPALPlayFramePeriodNumerator; 5738 pGlobalData->playFramePeriodDenominator = kPALPlayFramePeriodDenominator; 5739 playFrameRateNumerator = kPALFrameRateNumerator; 5740 playFrameRateDenominator = kPALFrameRateDenominator; 5741 pGlobalData->numDataPacketsPerFrame = kPALNumDataPacketsPerDVFrame; 5742 } 5743 5744 // Compute nominal frame period cycle time. 5745 pGlobalData->nominalFrameCycleTime = convertFractionalSecondsToFWCycleTime 5746 (pGlobalData->playFramePeriodNumerator, pGlobalData->playFramePeriodDenominator); 5747 5748 // Compute the number of data packets per empty packet. 5749 // If the frame rate is expressed as n/d, the number of data packets per buffer group 5750 // expressed as A, and the number of data packets per frame as C, then the number of 5751 // empty packets per buffer group B should be 5752 // 5753 // B = int (8000*d/n*A/C - A + 1) 5754 // 5755 // in order to ensure that the frame rate may be maintained by periodically reducing 5756 // the number of empty packets in a buffer group by 1. 5757 // 5758 A = (float) kNumDataPacketsPerPlayBufferGroup; 5759 C = (float) pGlobalData->numDataPacketsPerFrame; 5760 n = (float) playFrameRateNumerator; 5761 d = (float) playFrameRateDenominator; 5762 B = 8000.0*d/n*A/C - A + 1; 5763 numEmptyPacketsPerPlayBufferGroup = (UInt32) B; 5764 5765 5766 ///////////////////////////////////////// 5767 // Allocate transmit buffers. 5768 // 5769 5770 // Compute size. 5771 5772 // to prevent packets crossing page boundaries 5773 // allocate buffer memory based on pages, 5774 // there is enough extra room in each page for the empty packets 5775 pageSize = GetLogicalPageSize(); 5776 numDataPacketsPerPage = pageSize / (kDVPacketTransferSize + kDVPacketAlignSlop); 5777 transmitBuffersSize = kNumDataPacketsPerPlayBufferGroup / numDataPacketsPerPage * pageSize; 5778 transmitBuffersSize *= kNumPlayBufferGroups; 5779 5780 // add an extra page to account for first page not being page aligned 5781 transmitBuffersSize += pageSize; 5782 5783 // Allocate. 5784 pGlobalData->pTransmitBuffers = PoolAllocateResident(transmitBuffersSize, false); 5785 if (pGlobalData->pTransmitBuffers == nil) 5786 error = memFullErr; 5787 else 5788 pTransmitBuffer = (UInt32 *) pGlobalData->pTransmitBuffers; 5789 } 5790 5791 if (error == noErr) 5792 { 5793 5794 ///////////////////////////////////////// 5795 // Start Up DCL Allocation Engine 5796 // Allocate DCL command pool. 5797 5798 pDCLCommandPool = dclAllocateCommandPool(); 5799 if (pDCLCommandPool == nil) 5800 error = memFullErr; 5801 else 5802 pGlobalData->pDCLCommandPool = pDCLCommandPool; 5803 } 5804 5805 if (error == noErr) 5806 { 5807 //////////////////////////////////// 5808 // Create DCL Program 5809 // 5810 5811 // Initialize total packet count. 5812 pGlobalData->totalPackets = 0; 5813 5814 // Create label for start of loop. 5815 pLoopDCLLabel = (DCLLabelPtr) dclAllocateCommand(pDCLCommandPool, sizeof (DCLLabel)); 5816 //zzz check error 5817 pDCLCommand = (DCLCommandPtr) pLoopDCLLabel; 5818 5819 pGlobalData->pDCLList = pDCLCommand; 5820 pLoopDCLLabel->opcode = kDCLLabelOp; 5821 5822 // Set isoch packet tag bits to the way DV likes 'em 5823 pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr) dclAllocateCommand(pDCLCommandPool, sizeof (DCLSetTagSyncBits)); 5824 //zzz check error 5825 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLSetTagSyncBits; 5826 pDCLCommand = (DCLCommandPtr) pDCLSetTagSyncBits; 5827 pDCLSetTagSyncBits->opcode = kDCLSetTagSyncBitsOp; 5828 pDCLSetTagSyncBits->tagBits = 1; 5829 pDCLSetTagSyncBits->syncBits = 0; 5830 5831 for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++) 5832 { 5833 // Allocate a buffer group data record. 5834 pPlayBufferGroupData = dclAllocatePlayBufferGroup(pGlobalData); 5835 if (pPlayBufferGroupData == nil) 5836 { 5837 error = memFullErr; 5838 goto bail; 5839 } 5840 5841 5842 // Initialize for loop. 5843 dataPacketNum = 0; 5844 numPackets = 0; 5845 emptyPacketNumerator = 0; 5846 pFirstBufferGroupDCLCommand = nil; 5847 pBufferGroupSkipEmptyPacketDCLLabel = nil; 5848 5849 while (dataPacketNum < kNumDataPacketsPerPlayBufferGroup) 5850 { 5851 // Send a packet: CIP header + payload. 5852 pDCLTransferPacket = (DCLTransferPacketPtr) dclAllocateCommand(pDCLCommandPool, sizeof (DCLTransferPacket)); 5853 if( pDCLTransferPacket == nil ) 5854 { 5855 error = memFullErr; 5856 goto bail; 5857 } 5858 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket; 5859 pDCLCommand = (DCLCommandPtr) pDCLTransferPacket; 5860 pDCLTransferPacket->opcode = kDCLSendPacketStartOp; 5861 pDCLTransferPacket->size = kDVPacketTransferSize; 5862 5863 // check for buffer crossing page 5864 if (((UInt32) (pTransmitBuffer + kDVPacketAlignOffset) & 0x0fff) < (kDVPacketAlignOffset * 4)) 5865 { 5866 // if it does, increment buffer pointer 5867 // and lop off page rollover to start at next page 5868 pTransmitBuffer += kDVPacketAlignOffset; 5869 pTransmitBuffer = (UInt32 *) ((UInt32) pTransmitBuffer & 0xfffff000); 5870 } 5871 5872 pDCLTransferPacket->buffer = (Ptr) pTransmitBuffer; 5873 // increment by 496 bytes to maintain cache alignment 5874 pTransmitBuffer += kDVPacketAlignOffset; 5875 5876 // Save first data packet DCL command. 5877 if (pFirstBufferGroupDCLCommand == nil) 5878 pFirstBufferGroupDCLCommand = (DCLCommandPtr) pDCLCommand; 5879 5880 dataPacketNum++; 5881 numPackets++; 5882 emptyPacketNumerator += numEmptyPacketsPerPlayBufferGroup; 5883 5884 if (emptyPacketNumerator >= kNumDataPacketsPerPlayBufferGroup) 5885 { 5886 // Add skip jump if this is the first empty packet in the buffer group. 5887 if (pBufferGroupSkipEmptyPacketDCLLabel == nil) 5888 { 5889 pDCLJump = (DCLJumpPtr) dclAllocateCommand(pDCLCommandPool, sizeof (DCLJump)); 5890 if( pDCLJump == nil ) 5891 { 5892 error = memFullErr; 5893 goto bail; 5894 } 5895 pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLJump = pDCLJump; 5896 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLJump; 5897 pDCLCommand = (DCLCommandPtr) pDCLJump; 5898 pDCLJump->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag; 5899 5900 pDCLLabel = (DCLLabelPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLLabel)); 5901 if( pDCLLabel == nil ) 5902 { 5903 error = memFullErr; 5904 goto bail; 5905 } 5906 pPlayBufferGroupData->pBufferGroupDontSkipEmptyPacketDCLLabel = pDCLLabel; 5907 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLLabel; 5908 pDCLCommand = (DCLCommandPtr) pDCLLabel; 5909 pDCLLabel->opcode = kDCLLabelOp; 5910 5911 pDCLJump->pJumpDCLLabel = pDCLLabel; 5912 } 5913 5914 // Send a packet. 5915 // Just CIP header. 5916 pDCLTransferPacket = (DCLTransferPacketPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLTransferPacket)); 5917 if( pDCLTransferPacket == nil ) 5918 { 5919 error = memFullErr; 5920 goto bail; 5921 } 5922 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket; 5923 pDCLCommand = (DCLCommandPtr) pDCLTransferPacket; 5924 pDCLTransferPacket->opcode = kDCLSendPacketStartOp; 5925 pDCLTransferPacket->buffer = (Ptr) pTransmitBuffer; 5926 pDCLTransferPacket->size = kDVPacketCIPSize; 5927 5928 // increment 16 bytes to maintain alignment 5929 pTransmitBuffer += kDVEmptyPacketAlignOffset; 5930 numPackets++; 5931 emptyPacketNumerator -= kNumDataPacketsPerPlayBufferGroup; 5932 5933 // Add skip jump label if this is the first empty packet in the 5934 // buffer group. 5935 if (pBufferGroupSkipEmptyPacketDCLLabel == nil) 5936 { 5937 // Add skip label. 5938 pDCLLabel = (DCLLabelPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLLabel)); 5939 if( pDCLLabel == nil ) 5940 { 5941 error = memFullErr; 5942 goto bail; 5943 } 5944 pBufferGroupSkipEmptyPacketDCLLabel = pDCLLabel; 5945 pPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLLabel = pBufferGroupSkipEmptyPacketDCLLabel; 5946 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLLabel; 5947 pDCLCommand = (DCLCommandPtr) pDCLLabel; 5948 pDCLLabel->opcode = kDCLLabelOp; 5949 } 5950 } 5951 } 5952 5953 // Save number of packets in this buffer group, DCL update list size, and last 5954 // DCL command. 5955 pPlayBufferGroupData->numPackets = numPackets; 5956 pPlayBufferGroupData->pFirstBufferGroupDCLCommand = pFirstBufferGroupDCLCommand; 5957 pPlayBufferGroupData->pLastBufferGroupDCLCommand = (DCLCommandPtr) pDCLCommand; 5958 5959 // Create buffer group update list. 5960 createDVPlayBufferGroupUpdateList( pPlayBufferGroupData ); 5961 5962 // Update total packet count. 5963 pGlobalData->totalPackets += numPackets; 5964 5965 // Create end of buffer group jump. 5966 pBufferGroupDCLJump = (DCLJumpPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLJump)); 5967 if( pBufferGroupDCLJump == nil ) 5968 { 5969 error = memFullErr; 5970 goto bail; 5971 } 5972 pPlayBufferGroupData->pEndOfBufferGroupDCLJump = pBufferGroupDCLJump; 5973 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pBufferGroupDCLJump; 5974 pDCLCommand = (DCLCommandPtr) pBufferGroupDCLJump; 5975 pBufferGroupDCLJump->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag; 5976 5977 // Create label for end of buffer group. 5978 pBufferGroupDCLLabel = (DCLLabelPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLLabel)); 5979 if( pBufferGroupDCLLabel == nil ) 5980 { 5981 error = memFullErr; 5982 goto bail; 5983 } 5984 pPlayBufferGroupData->pEndOfBufferGroupDCLLabel = pBufferGroupDCLLabel; 5985 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pBufferGroupDCLLabel; 5986 pDCLCommand = (DCLCommandPtr) pBufferGroupDCLLabel; 5987 pBufferGroupDCLLabel->opcode = kDCLLabelOp; 5988 5989 // Set end of buffer group jump to jump to end of buffer group. 5990 pBufferGroupDCLJump->pJumpDCLLabel = pBufferGroupDCLLabel; 5991 5992 // Get time stamp at end of buffer group. 5993 pDCLTimeStamp = (DCLTimeStampPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLTimeStamp)); 5994 if( pDCLTimeStamp == nil ) 5995 { 5996 error = memFullErr; 5997 goto bail; 5998 } 5999 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTimeStamp; 6000 pDCLCommand = (DCLCommandPtr) pDCLTimeStamp; 6001 pDCLTimeStamp->opcode = kDCLTimeStampOp; 6002 pPlayBufferGroupData->pBufferGroupDCLTimeStamp = pDCLTimeStamp; 6003 pPlayBufferGroupData->timeStampUpdateDCLList = (DCLCommandPtr) pDCLTimeStamp; 6004 6005 // Create update DCL list to update time stamp. 6006 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLUpdateDCLList)); 6007 if( pDCLUpdateDCLList == nil ) 6008 { 6009 error = memFullErr; 6010 goto bail; 6011 } 6012 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList; 6013 pDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList; 6014 pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp; 6015 pDCLUpdateDCLList->dclCommandList = &(pPlayBufferGroupData->timeStampUpdateDCLList); 6016 pDCLUpdateDCLList->numDCLCommands = 1; 6017 6018 // Call a proc at end of buffer group. 6019 pDCLCallProc = (DCLCallProcPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLCallProc)); 6020 if( pDCLCallProc == nil ) 6021 { 6022 error = memFullErr; 6023 goto bail; 6024 } 6025 pPlayBufferGroupData->pBufferGroupDCLCallProc = pDCLCallProc; 6026 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLCallProc; 6027 pDCLCommand = (DCLCommandPtr) pDCLCallProc; 6028 pDCLCallProc->opcode = kDCLCallProcOp; 6029 pDCLCallProc->proc = handleDVOutput; 6030 pDCLCallProc->procData = (UInt32) pPlayBufferGroupData; 6031 6032 // Create update DCL list to update buffers. 6033 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLUpdateDCLList)); 6034 if( pDCLUpdateDCLList == nil ) 6035 { 6036 error = memFullErr; 6037 goto bail; 6038 } 6039 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList; 6040 pDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList; 6041 pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp; 6042 pDCLUpdateDCLList->dclCommandList = pPlayBufferGroupData->bufferGroupUpdateDCLList; 6043 pDCLUpdateDCLList->numDCLCommands = pPlayBufferGroupData->updateListSize; 6044 } 6045 6046 // Loop to first buffer group. 6047 pDCLJump = (DCLJumpPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLJump)); 6048 if( pDCLJump == nil ) 6049 { 6050 error = memFullErr; 6051 goto bail; 6052 } 6053 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLJump; 6054 pDCLCommand = (DCLCommandPtr) pDCLJump; 6055 pDCLJump->opcode = kDCLJumpOp; 6056 pDCLJump->pJumpDCLLabel = pLoopDCLLabel; 6057 6058 // Create label for underrun. 6059 pUnderrunDCLLabel = (DCLLabelPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLLabel)); 6060 if( pUnderrunDCLLabel == nil ) 6061 { 6062 error = memFullErr; 6063 goto bail; 6064 } 6065 pGlobalData->pUnderrunDCLLabel = pUnderrunDCLLabel; 6066 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pUnderrunDCLLabel; 6067 pDCLCommand = (DCLCommandPtr) pUnderrunDCLLabel; 6068 pUnderrunDCLLabel->opcode = kDCLLabelOp; 6069 6070 // Set last buffer group's jump DCL to jump to underrun. 6071 pBufferGroupDCLJump->pJumpDCLLabel = pUnderrunDCLLabel; 6072 6073 // Call underrun proc. 6074 // This is the last command. 6075 pDCLCallProc = (DCLCallProcPtr) dclAllocateCommand (pDCLCommandPool, sizeof (DCLCallProc)); 6076 if( pDCLCallProc == nil ) 6077 { 6078 error = memFullErr; 6079 goto bail; 6080 } 6081 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLCallProc; 6082 pDCLCallProc->pNextDCLCommand = nil; 6083 pDCLCallProc->opcode = kDCLCallProcOp; 6084 pDCLCallProc->proc = handleDVOutputUnderrun; 6085 pDCLCallProc->procData = (UInt32) pDeviceDescription; 6086 6087 // Initialize number of active play packets. 6088 pGlobalData->activePackets = pGlobalData->totalPackets; 6089 } 6090 6091 // Set up all of the buffer groups. 6092 if (error == noErr) 6093 { 6094 pGlobalData->nextSYT = kPlaySYTDelay; 6095 pGlobalData->nextDBC = 0; 6096 pGlobalData->nextDataPacketNum = 0; 6097 pGlobalData->pImageBuffer = nil; 6098 pPlayBufferGroupData = pGlobalData->pBufferGroupDataList; 6099 for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++) 6100 { 6101 updateDVOutputBuffers( (DCLCommandPtr) pPlayBufferGroupData->pBufferGroupDCLCallProc ); 6102 pPlayBufferGroupData = pPlayBufferGroupData->pNextLocalData; 6103 } 6104 } 6105 6106 if (error == noErr) 6107 error = FWSetDCLProgramStart(pGlobalData->DCLProgramID, pGlobalData->pDCLList); 6108 6109// jkl, do we need to do this? 6110// if (error == noErr) 6111// error = FWSetDCLProgramStartEvent(pGlobalData->DCLProgramID, kFWDCLCycleEvent, 0, BitRange (12, 15)); 6112 6113bail: 6114 // if we had a problem, lets clean it up 6115 if (error != noErr) 6116 { 6117 disposeDCLOutput(pDeviceDescription->pGlobalDVOutData); 6118 pGlobalData = nil; 6119 } 6120 6121 return error; 6122} 6123 6124 6125//////////////////////////////////////////////////////////////////////////////// 6126// 6127// DVHandleOutput 6128// 6129// This routine handles isochronous sending of DV data. 6130// 6131 6132void handleDVOutput(DCLCommandPtr pDCLCommandPtr) 6133{ 6134 DCLCallProcPtr pDCLCallProc; 6135 DCLTimeStampPtr pDCLTimeStamp; 6136 DVLocalOutPtr pLocalData; 6137 DVGlobalOutPtr pGlobalData; 6138 DVLocalOutPtr pPrevLocalData; 6139 UInt32 nominalFrameCycleTime; 6140 UInt32 fractionalFrameCycleCount, 6141 fractionalFrameCycleOffset; 6142 SInt32 timeDrift; 6143 UInt32 cycleDrift; 6144 UInt32 projectedTimeStamp, 6145 projectedSYT; 6146 6147 // Recast pDCLCommandPtr. 6148 pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr; 6149 6150 // Get data for buffer group and driver data. 6151 pLocalData = (DVLocalOutPtr) pDCLCallProc->procData; 6152 pPrevLocalData = pLocalData->pPrevLocalData; 6153 pGlobalData = pLocalData->pGlobalData; 6154 nominalFrameCycleTime = pGlobalData->nominalFrameCycleTime; 6155 6156 // Undo skipping empty packet if we're currently skipping a packet. 6157 if (pLocalData->skippingEmptyPacket) 6158 { 6159 FWModifyDCLJump( pGlobalData->DCLProgramID, pLocalData->pBufferGroupSkipEmptyPacketDCLJump, pLocalData->pBufferGroupDontSkipEmptyPacketDCLLabel); 6160 pGlobalData->activePackets++; 6161 pLocalData->skippingEmptyPacket = false; 6162 } 6163 6164 // Compute time drift. 6165 6166 // Compute the projected time stamp value for the first packet of the current 6167 // buffer group the next time this proc is called for the current buffer group. 6168 6169 // Start at time stamp of first packet in next buffer group to be sent. 6170 pDCLTimeStamp = pLocalData->pBufferGroupDCLTimeStamp; 6171 projectedTimeStamp = pDCLTimeStamp->timeStamp; 6172 projectedTimeStamp = addFWCycleTimeToFWCycleTime(projectedTimeStamp, 1 << 12); 6173 6174 // Add the total number of cycles for all active buffer group packets. 6175 projectedTimeStamp = addFWCycleTimeToFWCycleTime(projectedTimeStamp, pGlobalData->activePackets << 12); 6176 6177 // Subtract the number of cycles for all packets in the current buffer group. 6178 projectedTimeStamp = subtractFWCycleTimeFromFWCycleTime(projectedTimeStamp, pLocalData->numPackets << 12); 6179 6180 // Compute the projected SYT value for the first packet of the current buffer group 6181 // the next time this proc is called for the current buffer group. 6182 6183 // Start with the SYT value to use for the first packet of the next frame. 6184 projectedSYT = pGlobalData->nextSYT; 6185 6186 // Subtract the SYT offset between frames. 6187 projectedSYT = subtractFWCycleTimeFromFWCycleTime(projectedSYT, nominalFrameCycleTime); 6188 6189 // Add the fraction of the SYT offset between the start of the frame and the 6190 // first data packet for the current buffer group. 6191 fractionalFrameCycleOffset = 6192 ((nominalFrameCycleTime & 0x0FFF) * pGlobalData->nextDataPacketNum) / 6193 pGlobalData->numDataPacketsPerFrame; 6194 6195 fractionalFrameCycleCount = 6196 ((nominalFrameCycleTime & 0x01FFF000) * pGlobalData->nextDataPacketNum) / 6197 pGlobalData->numDataPacketsPerFrame; 6198 fractionalFrameCycleCount = 6199 (fractionalFrameCycleCount & 0x01FFF000) + 6200 (((fractionalFrameCycleCount & 0x0FFF) * 3072) / 4096); 6201 6202 projectedSYT = addFWCycleTimeToFWCycleTime (projectedSYT, fractionalFrameCycleOffset); 6203 projectedSYT = addFWCycleTimeToFWCycleTime (projectedSYT, fractionalFrameCycleCount); 6204 6205 // The time drift is the difference between the projected time stamp and SYT. 6206 // We must convert the time drift to cycles. 6207 cycleDrift = addFWCycleTimeToFWCycleTime(projectedTimeStamp, kPlaySYTDelay << 12); 6208 cycleDrift = subtractFWCycleTimeFromFWCycleTime(cycleDrift, projectedSYT); 6209 timeDrift = (cycleDrift >> 12) & 0x0F; 6210 6211 // Skip an empty packet if we're drifting. 6212 // Only consider positive drifting. 6213 if ((timeDrift > 0) && (timeDrift < 8)) 6214 { 6215 FWModifyDCLJump (pGlobalData->DCLProgramID, pLocalData->pBufferGroupSkipEmptyPacketDCLJump, pLocalData->pBufferGroupSkipEmptyPacketDCLLabel); 6216 pGlobalData->activePackets--; 6217 pLocalData->skippingEmptyPacket = true; 6218 } 6219 6220 updateDVOutputBuffers( pDCLCommandPtr ); 6221 6222 // Update DCL jumps to call underrun proc after this buffer group. 6223 //zzz check errors. 6224 FWModifyDCLJump (pGlobalData->DCLProgramID, 6225 pLocalData->pEndOfBufferGroupDCLJump, 6226 pGlobalData->pUnderrunDCLLabel); 6227 FWModifyDCLJump (pGlobalData->DCLProgramID, 6228 pPrevLocalData->pEndOfBufferGroupDCLJump, 6229 pPrevLocalData->pEndOfBufferGroupDCLLabel); 6230} 6231 6232//////////////////////////////////////////////////////////////////////////////// 6233// 6234// DVUpdateOutputBuffers 6235// 6236// This routine updates the buffers for sending DV data. 6237// 6238 6239void updateDVOutputBuffers(DCLCommandPtr pDCLCommandPtr) 6240{ 6241 DCLCommandPtr pCurrentDCLCommand; 6242 DCLCallProcPtr pDCLCallProc; 6243 DCLTransferPacketPtr pDCLTransferPacket; 6244 DVLocalOutPtr pLocalData, 6245 pPrevLocalData; 6246 DVGlobalOutPtr pGlobalData; 6247 UInt32 localNodeID; 6248 UInt32 generation; 6249 UInt32 nominalFrameCycleTime; 6250 UInt32 syt; 6251 UInt32 *pBuffer, 6252 *pImageBuffer, 6253 *pLastImageBuffer; 6254 UInt32 packetNum, 6255 dataPacketNum, 6256 numPackets; 6257 UInt32 dbc; 6258 6259 // Recast pDCLCommandPtr. 6260 pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr; 6261 6262 // Get data for buffer group. 6263 pLocalData = (DVLocalOutPtr) pDCLCallProc->procData; 6264 6265 // Get driver data and first DCL command. 6266 pGlobalData = pLocalData->pGlobalData; 6267 pCurrentDCLCommand = pLocalData->pFirstBufferGroupDCLCommand; 6268 nominalFrameCycleTime = pGlobalData->nominalFrameCycleTime; 6269 6270 // Get data for previous buffer group. 6271 pPrevLocalData = pLocalData->pPrevLocalData; 6272 syt = pGlobalData->nextSYT; 6273 dbc = pGlobalData->nextDBC; 6274 dataPacketNum = pGlobalData->nextDataPacketNum; 6275 6276 // Get local node ID. 6277 FWGetNodeID( pGlobalData->localFWReferenceID, &localNodeID, &generation); 6278 6279 // Get first send packet command for this buffer group. 6280 while (pCurrentDCLCommand->opcode != kDCLSendPacketStartOp) 6281 pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; 6282 pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentDCLCommand; 6283 6284 // Update the packet buffers. 6285 numPackets = pLocalData->numPackets; 6286 6287 // Get the next frame to output 6288 if( pGlobalData->pImageBuffer == nil ) 6289 getNextFullOutputFrame( pGlobalData->pDVFrameOutputData, &(pGlobalData->pImageBuffer) ); 6290 6291 pImageBuffer = ( pGlobalData->pImageBuffer + (kDVPacketQuadSize * dataPacketNum) ); 6292 for( packetNum = 0; packetNum < numPackets; packetNum++) 6293 { 6294 // Set up packet header. 6295 pBuffer = (UInt32 *) pDCLTransferPacket->buffer; 6296 pBuffer[0] = 0x00780000 | (localNodeID << 24) | (dbc & 0xFF); 6297 if( pGlobalData->isNTSC ) 6298 pBuffer[1] = 0x8000FFFF; 6299 else 6300 pBuffer[1] = 0x8080FFFF; // set PAL bit 6301 6302 // if not an empty packet 6303 if (pDCLTransferPacket->size == 488) 6304 { 6305 // Set SYT field if this is the first data packet in the frame. 6306 if (dataPacketNum == 0) 6307 { 6308 if( pGlobalData->isNTSC ) 6309 pBuffer[1] = 0x80000000 | (syt & 0xFFFF); 6310 else 6311 pBuffer[1] = 0x80800000 | (syt & 0xFFFF); // PAL bit 6312 6313 syt = addFWCycleTimeToFWCycleTime(syt, pGlobalData->nominalFrameCycleTime); 6314 } 6315 6316 // Copy data into packet. 6317 BlockMoveData(pImageBuffer, pDCLTransferPacket->buffer + kDVPacketCIPSize, kDVPacketDataSize); 6318 pImageBuffer += 120; 6319 dbc++; 6320 dataPacketNum++; 6321 6322 // check if frame is done 6323 if (dataPacketNum == pGlobalData->numDataPacketsPerFrame ) 6324 { 6325 IDHDVCompleteEvent event; 6326 6327 event.eventHeader.deviceID = pGlobalData->deviceID; 6328 event.eventHeader.event = kIDHPrivateEventWriteComplete; 6329 event.frameBuffer = (Ptr) pImageBuffer; 6330 event.fwCycleTime = syt; 6331 6332 postEvent( 6333 pGlobalData->isochComponentGlobals, 6334 pGlobalData->deviceID, 6335 kIDHPrivateEventWriteComplete, 6336 (void*)&event); 6337 6338 dataPacketNum = 0; 6339 pLastImageBuffer = pGlobalData->pImageBuffer; 6340 getNextFullOutputFrame( pGlobalData->pDVFrameOutputData, &(pGlobalData->pImageBuffer) ); 6341 pImageBuffer = pGlobalData->pImageBuffer; 6342 6343 // Mute the audio on repeating frames, based on repeating frame sequences 6344 if (pImageBuffer == pLastImageBuffer) 6345 { 6346 UInt32 i,j,k,n; 6347 UInt8 *tPtr; 6348 6349 6350 { 6351 // Get DSF flag in byte 3 of header (Blue Book p. 113) 6352 tPtr = (UInt8 *)pImageBuffer; 6353 if ((tPtr[3] &= 0x80) == 0) 6354 n=10; // ntsc 6355 else 6356 n=12; // pal 6357 6358 // Go thru the frame (10 times for ntsc, 12 for pal) 6359 for (i=0;i<n;i++) 6360 { 6361 6362 // Yet another attempt ... 6363 // Mute all the audio samples 6364 6365 for (i=0;i<n;i++) 6366 { 6367 for (j=0;j<9;j++) 6368 { 6369 tPtr = (UInt8 *)pImageBuffer + (i * 12000) + ((j * 16 + 6) * 80) + 8; 6370 for (k=0;k<72;k++) 6371 *tPtr++ = 0x0; 6372 } 6373 6374 } 6375 } 6376 } 6377 } 6378 } 6379 } 6380 6381 6382 // Find next send packet start command. 6383 pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; 6384 while (pCurrentDCLCommand != nil) 6385 { 6386 if (pCurrentDCLCommand->opcode != kDCLSendPacketStartOp) 6387 pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand; 6388 else 6389 break; 6390 } 6391 pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentDCLCommand; 6392 } 6393 pGlobalData->nextSYT = syt; 6394 pGlobalData->nextDBC = dbc; 6395 pGlobalData->nextDataPacketNum = dataPacketNum; 6396 6397 // Call to update DCL's if we need to. We have to do this on underrun because the update 6398 // DCL command won't be run to reflect the changes we've made here. 6399 if (pLocalData->needsUpdate) 6400 { 6401 FWUpdateDCLList (pGlobalData->DCLProgramID, pLocalData->bufferGroupUpdateDCLList, pLocalData->updateListSize); 6402 pLocalData->needsUpdate = false; 6403 } 6404} 6405 6406//////////////////////////////////////////////////////////////////////////////// 6407// 6408// DVHandleOutputUnderrun 6409// 6410// This routine handles underruns for sending DV data. 6411// 6412 6413void handleDVOutputUnderrun(DCLCommandPtr pDCLCommandPtr) 6414{ 6415 DCLCallProcPtr pDCLCallProc; 6416 DeviceDescriptionPtr pDeviceDescription; 6417 FWCommandObjectID isochChannelCommandObjectID; 6418 6419 // Recast pDCLCommandPtr. 6420 pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr; 6421 6422 // Get driver data. 6423 pDeviceDescription = (DeviceDescriptionPtr) pDCLCallProc->procData; 6424 6425 // Set up params for stopping isochronous channel. 6426 isochChannelCommandObjectID = pDeviceDescription->pGlobalDVOutData->isochChannelCommandObjectID; 6427 FWSetFWCommandParams(isochChannelCommandObjectID, (FWReferenceID) kInvalidFWReferenceID, 0, handleDVOutputUnderrunCompletion, (UInt32) pDCLCallProc); 6428 FWSetIsochChannelCommandIsochChannelID(isochChannelCommandObjectID, pDeviceDescription->outputIsochChannelID); 6429 6430 // Stop the isochronous channel. 6431 FWStopIsochronousChannel(isochChannelCommandObjectID); 6432} 6433 6434 6435//////////////////////////////////////////////////////////////////////////////// 6436// 6437// DVHandleOuputUnderrunCompletion 6438// 6439// This routine handles underruns for sending DV data. 6440// 6441 6442void handleDVOutputUnderrunCompletion ( 6443 FWCommandObjectID fwCommandObjectID, 6444 OSStatus commandStatus, 6445 UInt32 completionProcData) 6446{ 6447 DCLCallProcPtr pDCLCallProc; 6448 DeviceDescriptionPtr pDeviceDescription; 6449 DVLocalOutPtr pDVPlayBufferGroupData; 6450 FWCommandObjectID isochChannelCommandObjectID; 6451 UInt32 bufferGroupNum; 6452 6453 // Get DCL call proc data. 6454 pDCLCallProc = (DCLCallProcPtr) completionProcData; 6455 6456 // Get driver data. 6457 pDeviceDescription = (DeviceDescriptionPtr) pDCLCallProc->procData; 6458 6459 // Reset next SYT, dbc, and data packet num. 6460 pDeviceDescription->pGlobalDVOutData->nextSYT = kPlaySYTDelay; 6461 pDeviceDescription->pGlobalDVOutData->nextDBC = 0; 6462 pDeviceDescription->pGlobalDVOutData->nextDataPacketNum = 0; 6463 pDeviceDescription->pGlobalDVOutData->pImageBuffer = nil; 6464 6465 // Reset up all of the buffer groups. 6466 pDVPlayBufferGroupData = pDeviceDescription->pGlobalDVOutData->pBufferGroupDataList; 6467 for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++) 6468 { 6469 // Update buffer group buffers. 6470 // jkl, no update needed, Lynx fwim and OHCI fwim don't do anything for this anyway 6471// pDVPlayBufferGroupData->needsUpdate = true; 6472 updateDVOutputBuffers((DCLCommandPtr) pDVPlayBufferGroupData->pBufferGroupDCLCallProc); 6473 6474 // Update buffer group jump DCL. 6475 if (bufferGroupNum < (kNumPlayBufferGroups - 1)) 6476 { 6477 FWModifyDCLJump (pDeviceDescription->pGlobalDVOutData->DCLProgramID, 6478 pDVPlayBufferGroupData->pEndOfBufferGroupDCLJump, 6479 pDVPlayBufferGroupData->pEndOfBufferGroupDCLLabel); 6480 } 6481 else 6482 { 6483 FWModifyDCLJump (pDeviceDescription->pGlobalDVOutData->DCLProgramID, 6484 pDVPlayBufferGroupData->pEndOfBufferGroupDCLJump, 6485 pDeviceDescription->pGlobalDVOutData->pUnderrunDCLLabel); 6486 } 6487 6488 pDVPlayBufferGroupData = pDVPlayBufferGroupData->pNextLocalData; 6489 } 6490 6491 // Set up params for starting isochronous channel. 6492 isochChannelCommandObjectID = pDeviceDescription->pGlobalDVOutData->isochChannelCommandObjectID; 6493 FWSetFWCommandParams (isochChannelCommandObjectID, (FWReferenceID) kInvalidFWReferenceID, 0, nil, 0); 6494 FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID, pDeviceDescription->outputIsochChannelID); 6495 6496 // Restart the isochronous channel. 6497 FWStartIsochronousChannel (isochChannelCommandObjectID); 6498} 6499 6500 6501 6502/////////////////////////////////////////////////////////////////////// 6503// 6504// DVDisposeDCLOutput 6505// 6506/////////////////////////////////////////////////////////////////////// 6507OSErr disposeDCLOutput( DVGlobalOutPtr pOutputData ) 6508{ 6509 DVLocalOutPtr pLocalData, 6510 pNextLocalData; 6511 UInt32 bufferGroupNum; 6512 OSErr error = noErr; 6513 6514 if( pOutputData != nil ) 6515 { 6516 // Deallocate play buffer group data records. 6517 // and update lists associated with them 6518 pLocalData = pOutputData->pBufferGroupDataList; 6519 for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++) 6520 { 6521 if( pLocalData != nil ) 6522 { 6523 pNextLocalData = pLocalData->pNextLocalData; 6524 dclDeallocatePlayBufferGroup (pLocalData); 6525 pLocalData = pNextLocalData; 6526 } 6527 } 6528 6529 if( pOutputData->pDCLCommandPool != nil ) 6530 dclDeallocateCommandPool( pOutputData->pDCLCommandPool ); 6531 6532 if( pOutputData->pDVFrameOutputData != nil ) 6533 releaseDVFrameIO( pOutputData->pDVFrameOutputData ); 6534 6535 FWDisposeDCLProgram( pOutputData->DCLProgramID ); 6536 6537 if( pOutputData->pTransmitBuffers != nil ) 6538 PoolDeallocate ( pOutputData->pTransmitBuffers ); 6539 6540 if( pOutputData->isochChannelCommandObjectID != nil ) 6541 FWDeallocateFWCommandObject ( pOutputData->isochChannelCommandObjectID ); 6542 6543 PoolDeallocate ( pOutputData ); 6544 } 6545 return( error ); 6546} 6547 6548 6549////////////////////////////////////////////////////////////////////////////////////// 6550////////////////////////////////////////////////////////////////////////////////////// 6551// Utilitiy Routines 6552////////////////////////////////////////////////////////////////////////////////////// 6553////////////////////////////////////////////////////////////////////////////////////// 6554 6555 6556 6557/////////////////////////////////////////////////////////////////////////////////// 6558// Buffer Allocation Routines 6559// For Output 6560/////////////////// 6561 6562//////////////////////////////////////////////////////////////////////////////// 6563// 6564// DVCAllocatePlayBufferGroup 6565// 6566// This routine allocates a buffer group for playing. 6567// 6568 6569DVLocalOutPtr dclAllocatePlayBufferGroup(DVGlobalOutPtr pGlobalData) 6570{ 6571 DVLocalOutPtr pLocalData = nil, 6572 pPrevLocalData, 6573 pNextLocalData; 6574 OSErr error = noErr; 6575 6576 // Allocate buffer group data record. 6577 pLocalData = (DVLocalOutPtr) PoolAllocateResident(sizeof (DVLocalOut), true); 6578 if (pLocalData != nil) 6579 pLocalData->pGlobalData = pGlobalData; 6580 else 6581 error = memFullErr; 6582 6583 // Insert buffer group data record into list. 6584 if (error == noErr) 6585 { 6586 pNextLocalData = pGlobalData->pBufferGroupDataList; 6587 if (pNextLocalData != nil) 6588 { 6589 pPrevLocalData = pNextLocalData->pPrevLocalData; 6590 6591 pNextLocalData->pPrevLocalData = pLocalData; 6592 pLocalData->pNextLocalData = pNextLocalData; 6593 } 6594 else 6595 { 6596 pPrevLocalData = pLocalData; 6597 6598 pGlobalData->pBufferGroupDataList = pLocalData; 6599 } 6600 6601 pPrevLocalData->pNextLocalData = pLocalData; 6602 pLocalData->pPrevLocalData = pPrevLocalData; 6603 } 6604 6605 return pLocalData; 6606} 6607 6608 6609//////////////////////////////////////////////////////////////////////////////// 6610// 6611// DVDeallocatePlayBufferGroup 6612// 6613// This routine deallocates a buffer group for playing. 6614// 6615 6616void dclDeallocatePlayBufferGroup( DVLocalOutPtr pLocalData ) 6617{ 6618 if (pLocalData != nil) 6619 { 6620 if (pLocalData->bufferGroupUpdateDCLList != nil) 6621 PoolDeallocate ((Ptr) pLocalData->bufferGroupUpdateDCLList); 6622 6623 PoolDeallocate ( pLocalData ); 6624 } 6625} 6626 6627 6628//////////////////////////////////////////////////////////////////////////////// 6629// 6630// DVCreatePlayBufferGroupUpdateList 6631// 6632// This routine creates the update list for a play buffer group. 6633// 6634 6635OSErr createDVPlayBufferGroupUpdateList( DVLocalOutPtr pLocalData) 6636{ 6637 DCLCommandPtr pDCLCommand, 6638 pLastDCLCommand; 6639 DCLCommandPtr *updateDCLList, 6640 *pUpdateDCLListEntry; 6641 UInt32 opcode; 6642 UInt32 updateListSize; 6643 OSErr error = noErr; 6644 6645 // Loop through all DCL commands in buffer group and count all send packet DCL 6646 // commands. 6647 pDCLCommand = pLocalData->pFirstBufferGroupDCLCommand; 6648 pLastDCLCommand = pLocalData->pLastBufferGroupDCLCommand; 6649 updateListSize = 0; 6650 while (pDCLCommand != pLastDCLCommand) 6651 { 6652 opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask; 6653 if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp)) 6654 updateListSize++; 6655 6656 pDCLCommand = pDCLCommand->pNextDCLCommand; 6657 } 6658 opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask; 6659 if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp)) 6660 updateListSize++; 6661 6662 // Allocate update list. 6663 updateDCLList = (DCLCommandPtr *) 6664 PoolAllocateResident (updateListSize * sizeof (DCLCommandPtr), false); 6665 if (updateDCLList == nil) 6666 error = memFullErr; 6667 6668 // Loop through all DCL commands in buffer group and add all send packet DCL 6669 // commands to update list. 6670 if (error == noErr) 6671 { 6672 pDCLCommand = pLocalData->pFirstBufferGroupDCLCommand; 6673 pLastDCLCommand = pLocalData->pLastBufferGroupDCLCommand; 6674 pUpdateDCLListEntry = updateDCLList; 6675 6676 while (pDCLCommand != pLastDCLCommand) 6677 { 6678 opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask; 6679 if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp)) 6680 *pUpdateDCLListEntry++ = pDCLCommand; 6681 6682 pDCLCommand = pDCLCommand->pNextDCLCommand; 6683 } 6684 6685 opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask; 6686 if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp)) 6687 *pUpdateDCLListEntry++ = pDCLCommand; 6688 } 6689 6690 // Save update list. 6691 if (error == noErr) 6692 { 6693 pLocalData->bufferGroupUpdateDCLList = updateDCLList; 6694 pLocalData->updateListSize = updateListSize; 6695 } 6696 else 6697 { 6698 pLocalData->bufferGroupUpdateDCLList = nil; 6699 pLocalData->updateListSize = 0; 6700 } 6701 6702 return ( error ); 6703} 6704 6705 6706//////////////////////////////////////////////////////////////////////////////////// 6707// DCL Allocation Routines 6708// 6709// We run our own allocation engine because of the sheer number of DCLs. The command 6710// pool holds larger blocks out of which we allocate the DCL commands, this takes 6711// some work out of the hands of the memory manager. 6712// 6713/////////////////// 6714 6715//////////////////////////////////////////////////////////////////////////////// 6716// 6717// AllocateDCLCommand 6718// 6719// This routine allocates a DCL command. 6720// 6721 6722DCLCommandPtr dclAllocateCommand(DCLCommandPoolPtr pDCLCommandPool, UInt32 dclSize) 6723{ 6724 DCLCommandBlockPtr pDCLCommandBlock; 6725 DCLCommandPtr pDCLCommand; 6726 6727 // Get last DCL command block in pool. 6728 pDCLCommandBlock = pDCLCommandPool->pLastDCLCommandBlock; 6729 6730 // Check if we have enough room in command block. Allocate a new block if there 6731 // is not enough room. 6732 if (pDCLCommandBlock != nil) 6733 { 6734 if( dclSize > (kDCLCommandPoolBlockSize - pDCLCommandBlock->blockLevel) ) 6735 pDCLCommandBlock = dclAllocateCommandBlock( pDCLCommandPool ); 6736 } 6737 else 6738 { 6739 pDCLCommandBlock = dclAllocateCommandBlock ( pDCLCommandPool ); 6740 } 6741 6742 // Allocate a DCL from the command block. 6743 if (pDCLCommandBlock != nil) 6744 { 6745 pDCLCommand = 6746 (DCLCommandPtr) (pDCLCommandBlock->block + pDCLCommandBlock->blockLevel); 6747 pDCLCommandBlock->blockLevel += dclSize; 6748 } 6749 else 6750 { 6751 pDCLCommand = nil; 6752 } 6753 6754 return pDCLCommand; 6755} 6756 6757 6758//////////////////////////////////////////////////////////////////////////////// 6759// 6760// AllocateDCLCommandBlock 6761// 6762// This routine allocates a DCL command block. 6763// 6764 6765DCLCommandBlockPtr dclAllocateCommandBlock( DCLCommandPoolPtr pDCLCommandPool ) 6766{ 6767 DCLCommandBlockPtr pDCLCommandBlock = nil; 6768 Ptr block; 6769 OSStatus error = noErr; 6770 6771 // Allocate command block record. 6772 pDCLCommandBlock = 6773 (DCLCommandBlockPtr) PoolAllocateResident( sizeof(DCLCommandBlock), true ); 6774 if( pDCLCommandBlock == nil ) 6775 error = memFullErr; 6776 6777 // Allocate command block block. 6778 if( error == noErr ) 6779 { 6780 block = PoolAllocateResident( kDCLCommandPoolBlockSize, false ); 6781 if (block != nil) 6782 pDCLCommandBlock->block = block; 6783 else 6784 error = memFullErr; 6785 } 6786 6787 // Insert command block into pool. 6788 if( error == noErr ) 6789 { 6790 if( pDCLCommandPool->pFirstDCLCommandBlock != nil ) 6791 pDCLCommandPool->pLastDCLCommandBlock->pNextDCLCommandBlock = pDCLCommandBlock; 6792 else 6793 pDCLCommandPool->pFirstDCLCommandBlock = pDCLCommandBlock; 6794 6795 pDCLCommandPool->pLastDCLCommandBlock = pDCLCommandBlock; 6796 pDCLCommandBlock->pNextDCLCommandBlock = nil; 6797 } 6798 6799 // Clean up on error. 6800 if( ( error != noErr ) && ( pDCLCommandBlock != nil ) ) 6801 { 6802 dclDeallocateCommandBlock( pDCLCommandBlock ); 6803 pDCLCommandBlock = nil; 6804 } 6805 6806 // Return results. 6807 return( pDCLCommandBlock ); 6808} 6809 6810 6811//////////////////////////////////////////////////////////////////////////////// 6812// 6813// DeallocateDCLCommandBlock 6814// 6815// This routine deallocates a DCL command block. 6816// 6817 6818void dclDeallocateCommandBlock( DCLCommandBlockPtr pDCLCommandBlock ) 6819{ 6820 if( pDCLCommandBlock != nil ) 6821 { 6822 // Deallocate command block block. 6823 if( pDCLCommandBlock->block != nil ) 6824 PoolDeallocate( pDCLCommandBlock->block ); 6825 6826 // Deallocate command block record. 6827 PoolDeallocate( (Ptr) pDCLCommandBlock ); 6828 6829 //zzz if there were any errors...? 6830 } 6831} 6832 6833//////////////////////////////////////////////////////////////////////////////// 6834// 6835// AllocateDCLCommandPool 6836// 6837// This routine allocates a DCL command pool. 6838// 6839 6840DCLCommandPoolPtr dclAllocateCommandPool( void ) 6841{ 6842 DCLCommandPoolPtr pDCLCommandPool; 6843 6844 // Allocate DCL command pool record. 6845 pDCLCommandPool = (DCLCommandPoolPtr) PoolAllocateResident( sizeof( DCLCommandPool ), true ); 6846 6847 return (pDCLCommandPool); 6848} 6849 6850//////////////////////////////////////////////////////////////////////////////// 6851// 6852// DeallocateDCLCommandPool 6853// 6854// This routine deallocates a DCL command pool. 6855// 6856 6857void dclDeallocateCommandPool( DCLCommandPoolPtr pDCLCommandPool ) 6858{ 6859 DCLCommandBlockPtr pDCLCommandBlock, 6860 pNextDCLCommandBlock; 6861 6862 if( pDCLCommandPool != nil ) 6863 { 6864 // Deallocate all command blocks. 6865 pDCLCommandBlock = pDCLCommandPool->pFirstDCLCommandBlock; 6866 while( pDCLCommandBlock != nil ) 6867 { 6868 pNextDCLCommandBlock = pDCLCommandBlock->pNextDCLCommandBlock; 6869 dclDeallocateCommandBlock( pDCLCommandBlock ); 6870 pDCLCommandBlock = pNextDCLCommandBlock; 6871 } 6872 6873 // Deallocate command pool record. 6874 PoolDeallocate ((Ptr) pDCLCommandPool); 6875 //zzz if there was an error...? 6876 } 6877} 6878 6879 6880//////////////////////////////////////////////////////////////////////////////// 6881// 6882// AddFWCycleTimeToFWCycleTime 6883// 6884// This routine adds the two given cycle times. 6885// 6886 6887UInt32 addFWCycleTimeToFWCycleTime( UInt32 cycleTime1, UInt32 cycleTime2 ) 6888{ 6889 UInt32 secondCount, 6890 cycleCount, 6891 cycleOffset; 6892 UInt32 cycleTime; 6893 6894 // Add cycle offsets. 6895 cycleOffset = (cycleTime1 & 0x0FFF) + (cycleTime2 & 0x0FFF); 6896 6897 // Add cycle counts. 6898 cycleCount = (cycleTime1 & 0x01FFF000) + (cycleTime2 & 0x01FFF000); 6899 6900 // Add any carry over from cycle offset to cycle count. 6901 if (cycleOffset > 3071) 6902 { 6903 cycleCount += 0x1000; 6904 cycleOffset -= 3072; 6905 } 6906 6907 // Add secondCounts. 6908 secondCount = (cycleTime1 & 0xFE000000) + (cycleTime2 & 0xFE000000); 6909 6910 // Add any carry over from cycle count to secondCount. 6911 if (cycleCount > (7999 << 12)) 6912 { 6913 secondCount += 0x02000000; 6914 cycleCount -= (8000 << 12); 6915 } 6916 6917 // Put everything together into cycle time. 6918 cycleTime = secondCount | cycleCount | cycleOffset; 6919 6920 return (cycleTime); 6921} 6922 6923 6924//////////////////////////////////////////////////////////////////////////////// 6925// 6926// SubtractFWCycleTimeFromFWCycleTime 6927// 6928// This routine subtracts the two given cycle times. 6929// 6930 6931UInt32 subtractFWCycleTimeFromFWCycleTime( UInt32 cycleTime1, UInt32 cycleTime2 ) 6932{ 6933 SInt32 secondCount, 6934 cycleCount, 6935 cycleOffset; 6936 UInt32 cycleTime; 6937 6938 // Subtract cycle offsets. 6939 cycleOffset = (cycleTime1 & 0x0FFF) - (cycleTime2 & 0x0FFF); 6940 6941 // Subtract cycle counts. 6942 cycleCount = (cycleTime1 & 0x01FFF000) - (cycleTime2 & 0x01FFF000); 6943 6944 // Subtract any borrow over from cycle offset to cycle count. 6945 6946 if (cycleOffset < 0) 6947 { 6948 cycleCount -= 0x1000; 6949 cycleOffset += 3072; 6950 } 6951 6952 // Subtract secondCounts. 6953 secondCount = (cycleTime1 & 0xFE000000) - (cycleTime2 & 0xFE000000); 6954 6955 // Subtract any borrow over from cycle count to secondCount. 6956 if (cycleCount < 0) 6957 { 6958 secondCount -= 0x02000000; 6959 cycleCount += (8000 << 12); 6960 } 6961 6962 // Put everything together into cycle time. 6963 cycleTime = secondCount | cycleCount | cycleOffset; 6964 6965 return (cycleTime); 6966} 6967 6968 6969//////////////////////////////////////////////////////////////////////////////// 6970// 6971// ConvertFractionalSecondsToFWCycleTime 6972// 6973// This routine converts a time represented in fractional seconds to a time 6974// represented in cycle timer format. 6975// 6976 6977UInt32 convertFractionalSecondsToFWCycleTime( UInt32 secondsNumerator, UInt32 secondsDenominator ) 6978{ 6979 float fSecondCount; 6980 float fCycleCount; 6981 float fCycleOffset; 6982 UInt32 iSecondsCount; 6983 UInt32 iCycleCount; 6984 UInt32 iCycleOffset; 6985 UInt32 secondsCycleTime; 6986 6987 // Convert fractional seconds into floating point and compute seconds count. 6988 fSecondCount = ((float) secondsNumerator) / ((float) secondsDenominator); 6989 iSecondsCount = (UInt32) fSecondCount; 6990 6991 // Subtract whole seconds out of fSecondCount and convert to cycle count. 6992 fCycleCount = (fSecondCount - ((float) iSecondsCount)) * 8000.0; 6993 iCycleCount = (UInt32) fCycleCount; 6994 6995 // Subtract whole cycles out of fCycleCount and convert to cycle offset. 6996 fCycleOffset = (fCycleCount - ((float) iCycleCount)) * 3072.0; 6997 iCycleOffset = (UInt32) fCycleOffset; 6998 6999 // Convert to cycle timer format. 7000 secondsCycleTime = (iSecondsCount << 25) | (iCycleCount << 12) | iCycleOffset; 7001 7002 return (secondsCycleTime); 7003} 7004 7005////////////////////////////////////////////////////////////////////// 7006// DVGetNextFullOutputFrame 7007// 7008// Returns next frame full of data for output 7009// 7010 7011OSErr getNextFullOutputFrame( DVIODataPtr pOData, UInt32** ppFrame ) 7012{ 7013 OSErr error = noErr; 7014 QElemPtr pQElem; 7015 7016 // dequeue an element from the output list 7017 error = PBDequeueFirst( pOData->pFullQ, &pQElem); 7018 7019 // if we got a frame 7020 if( error == noErr ) 7021 { 7022 // put old frame on empty queue 7023 error = PBEnqueueLast( pOData->pCurFrameElem, pOData->pEmptyQ ); 7024 //zzz what if we can't enqueue 7025 7026 // save new frame element 7027 pOData->pCurFrameElem = pQElem; 7028 7029 // return the actual frame 7030 *ppFrame = ((DVFrameQElemPtr)pQElem)->pFrame; 7031 } 7032 else 7033 // return old frame 7034 *ppFrame = ((DVFrameQElemPtr)pOData->pCurFrameElem)->pFrame; 7035 7036 return( error ); 7037} 7038 7039/////////////////////////////////////////////////////////////////////// 7040// 7041// DVGetNextEmptyOutputFrame 7042// 7043/////////////////////////////////////////////////////////////////////// 7044 7045OSErr getNextEmptyOutputFrame( DVIODataPtr pOData, UInt32** ppFrame) 7046{ 7047 OSErr error = noErr; 7048 DVFrameQElemPtr pQElem; 7049 7050 // dequeue an element from the empty list 7051 error = PBDequeueFirst( pOData->pEmptyQ, (QElemPtr *) &pQElem ); 7052 7053 // if we got an element 7054 if( error == noErr ) 7055 { 7056 // put the frame on the busy queue 7057 error = PBEnqueueLast( (QElemPtr) pQElem, pOData->pBusyQ ); 7058 //zzz and if we get an error 7059 7060 // return the frame 7061 *ppFrame = pQElem->pFrame; 7062 } 7063 else 7064 *ppFrame = nil; 7065 7066 return( error ); 7067} 7068 7069/////////////////////////////////////////////////////////////////////// 7070// 7071// DVQueueNextFullOutputFrame 7072// 7073/////////////////////////////////////////////////////////////////////// 7074 7075OSErr queueNextFullOutputFrame( DVIODataPtr pOData, UInt32* pFrame ) 7076{ 7077 OSStatus error = noErr; 7078 QElemPtr pCurElem; 7079 7080 // find frame in busy queue 7081 pCurElem = pOData->pBusyQ->qHead; 7082 while( pCurElem != nil) 7083 { 7084 // is it the one we want? 7085 if( ((DVFrameQElemPtr)pCurElem)->pFrame == pFrame ) 7086 break; 7087 else 7088 // next 7089 pCurElem = pCurElem->qLink; 7090 } 7091 7092 // if we found it 7093 if( pCurElem != nil ) 7094 { 7095 // get the element from the busy queue 7096 error = PBDequeue( pCurElem, pOData->pBusyQ ); 7097 7098 // and put it on the full queue 7099 if( error == noErr ) 7100 error = PBEnqueueLast( pCurElem, pOData->pFullQ ); 7101 } 7102 else 7103 error = kDVFrameNotFoundErr; 7104 7105 return( error ); 7106} 7107 7108////////////////////////////////////////////////////////////////////// 7109// DVGetNextEmptyInputFrame 7110// 7111// Returns next empty frame for input 7112// 7113 7114OSErr getNextEmptyInputFrame( DVIODataPtr pIData, UInt32** ppFrame ) 7115{ 7116 OSErr error = noErr; 7117 QElemPtr pQElem; 7118 7119 // dequeue an element from the output list 7120 error = PBDequeueFirst( pIData->pEmptyQ, &pQElem); 7121 7122 if( error != noErr ) 7123 { 7124 error = PBDequeueFirst( pIData->pFullQ, &pQElem); 7125 } 7126 7127 // if we got a frame 7128 if( error == noErr ) 7129 { 7130 // put old frame on full queue 7131 error = PBEnqueueLast( pIData->pCurFrameElem, pIData->pFullQ ); 7132 //zzz what if we can't enqueue 7133 7134 // save new frame element 7135 pIData->pCurFrameElem = pQElem; 7136 7137 // return the actual frame 7138 *ppFrame = ((DVFrameQElemPtr)pQElem)->pFrame; 7139 } 7140 else 7141 // return old frame 7142 *ppFrame = ((DVFrameQElemPtr)pIData->pCurFrameElem)->pFrame; 7143 7144 return( error ); 7145} 7146 7147////////////////////////////////////////////////////////////////////// 7148// 7149// DVGetNextFullInputFrame 7150// 7151// Returns next full frame of data for input 7152// 7153 7154OSErr getNextFullInputFrame( DVIODataPtr pIData, UInt32** ppFrame ) 7155{ 7156 OSErr error = noErr; 7157 DVFrameQElemPtr pQElem; 7158 7159 // dequeue an element from the full list 7160 error = PBDequeueFirst( pIData->pFullQ, (QElemPtr *) &pQElem ); 7161 7162 // if we got an element 7163 if( error == noErr ) 7164 { 7165 // put the frame on the busy queue 7166 error = PBEnqueueLast( (QElemPtr) pQElem, pIData->pBusyQ ); 7167 //zzz and if we get an error 7168 7169 // return the frame 7170 *ppFrame = pQElem->pFrame; 7171 } 7172 else 7173 *ppFrame = nil; 7174 7175 return( error ); 7176} 7177 7178/////////////////////////////////////////////////////////////////////// 7179// 7180// DVReleaseFullInputFrame 7181// 7182/////////////////////////////////////////////////////////////////////// 7183 7184OSErr releaseFullInputFrame( DVIODataPtr pIData, UInt32* pFrame ) 7185{ 7186 OSStatus error = noErr; 7187 QElemPtr pCurElem; 7188 7189 // find frame in busy queue 7190 pCurElem = pIData->pBusyQ->qHead; 7191 while( pCurElem != nil) 7192 { 7193 // is it the one we want? 7194 if( ((DVFrameQElemPtr)pCurElem)->pFrame == pFrame ) 7195 break; 7196 else 7197 // next 7198 pCurElem = pCurElem->qLink; 7199 } 7200 7201 // if we found it 7202 if( pCurElem != nil ) 7203 { 7204 // get the element from the busy queue 7205 error = PBDequeue( pCurElem, pIData->pBusyQ ); 7206 7207 // and put it on the empty queue 7208 if( error == noErr ) 7209 error = PBEnqueueLast( pCurElem, pIData->pEmptyQ ); 7210 } 7211 else 7212 error = kDVFrameNotFoundErr; 7213 7214 return( error ); 7215} 7216 7217////////////////////////////////////////////////////////////////////// 7218// 7219// DVGetCurrentDCLFrame 7220// 7221 7222Boolean isDVFinished( DVIODataPtr pIOData ) 7223{ 7224 Boolean result = false; 7225 7226 if( pIOData != nil ) 7227 { 7228 if( pIOData->pFullQ->qHead == nil ) 7229 result = true; 7230 else 7231 result = false; 7232 } 7233 else 7234 result = false; 7235 7236 return( result ); 7237} 7238 7239////////////////////////////////////////////////////////////////////// 7240// 7241// DVGetCurrentDCLFrame 7242// 7243 7244OSErr getCurrentDCLFrame( DVIODataPtr pIOData, UInt32** ppFrame ) 7245{ 7246 OSErr error = noErr; 7247 7248 if( pIOData != nil ) 7249 { 7250 // get the current frame 7251 *ppFrame = ((DVFrameQElemPtr)pIOData->pCurFrameElem)->pFrame; 7252 } 7253 else 7254 { 7255 error = kDVFrameNotFoundErr; 7256 *ppFrame = nil; 7257 } 7258 return( error ); 7259} 7260 7261/////////////////////////////////////////////////////////////////////// 7262// 7263// DVInitFrameIO 7264// 7265 7266OSErr initDVFrameInput(UInt32 standard, DVIODataPtr* ppIOData) 7267{ 7268 OSErr error = noErr; 7269 DVIODataPtr pIOData; 7270 DVFrameQElemPtr pQElem[kNumInputDVFrames]; 7271 UInt32 i; 7272 UInt32 frameSize; 7273 7274 // create output data struct 7275 pIOData = (DVIODataPtr) PoolAllocateResident( sizeof( DVIOData ), true ); 7276 7277 if( pIOData == nil ) 7278 { 7279 error = memFullErr; 7280 goto bail; 7281 } 7282 7283 // create busy queue 7284 error = PBQueueCreate( &(pIOData->pBusyQ) ); 7285 if( error != noErr ) 7286 goto bail; 7287 7288 error = PBQueueInit( pIOData->pBusyQ ); 7289 if( error != noErr ) 7290 goto bail; 7291 7292 // create empty queue 7293 error = PBQueueCreate( &(pIOData->pEmptyQ) ); 7294 if( error != noErr ) 7295 goto bail; 7296 7297 error = PBQueueInit( pIOData->pEmptyQ ); 7298 if( error != noErr ) 7299 goto bail; 7300 7301 7302 // create full queue 7303 error = PBQueueCreate( &(pIOData->pFullQ) ); 7304 if( error != noErr ) 7305 goto bail; 7306 7307 error = PBQueueInit( pIOData->pFullQ ); 7308 if( error != noErr ) 7309 goto bail; 7310 7311 for(i = 0; i < kNumInputDVFrames; i++) 7312 { 7313 // create queue elements 7314 pQElem[i] = (DVFrameQElemPtr) PoolAllocateResident( sizeof(DVFrameQElem), true ); 7315 if ( pQElem[i] == nil ) 7316 { 7317 error = memFullErr; 7318 goto bail; 7319 } 7320 7321 // create frames 7322 if (standard == ntscIn) 7323 frameSize = kNTSCCompressedBufferSize; 7324 else 7325 frameSize = kPALCompressedBufferSize; 7326 7327 pQElem[i]->pFrame = (UInt32 *) PoolAllocateResident( frameSize, true ); 7328 if ( pQElem[i]->pFrame == nil ) 7329 { 7330 error = memFullErr; 7331 goto bail; 7332 } 7333 } 7334 7335 // set current frame to start 7336 pIOData->pCurFrameElem = (QElemPtr) pQElem[0]; 7337 7338 // insert the rest of the queue elements into empty queue 7339 for(i = 1; i < kNumInputDVFrames; i++ ) 7340 { 7341 error = PBEnqueueLast( (QElemPtr) pQElem[i], pIOData->pEmptyQ ); 7342 } 7343 7344bail: 7345 if( error != noErr ) 7346 { 7347 releaseDVFrameIO( pIOData ); 7348 pIOData = nil; 7349 } 7350 7351 *ppIOData = pIOData; 7352 7353 return( error ); 7354} 7355 7356/////////////////////////////////////////////////////////////////////// 7357// 7358// initDVFrameOutput 7359// 7360OSErr initDVFrameOutput(UInt32 standard, DVIODataPtr* ppIOData) 7361{ 7362 OSErr error = noErr; 7363 DVIODataPtr pIOData; 7364 DVFrameQElemPtr pQElem[kNumOutputDVFrames]; 7365 UInt32 i; 7366 UInt32 frameSize; 7367 7368 // create output data struct 7369 pIOData = (DVIODataPtr) PoolAllocateResident(sizeof(DVIOData), true); 7370 7371 if( pIOData == nil ) 7372 { 7373 error = memFullErr; 7374 goto bail; 7375 } 7376 7377 // create busy queue 7378 error = PBQueueCreate( &(pIOData->pBusyQ) ); 7379 if( error != noErr ) 7380 goto bail; 7381 7382 error = PBQueueInit( pIOData->pBusyQ ); 7383 if( error != noErr ) 7384 goto bail; 7385 7386 // create empty queue 7387 error = PBQueueCreate( &(pIOData->pEmptyQ) ); 7388 if( error != noErr ) 7389 goto bail; 7390 7391 error = PBQueueInit( pIOData->pEmptyQ ); 7392 if( error != noErr ) 7393 goto bail; 7394 7395 // create full queue 7396 error = PBQueueCreate( &(pIOData->pFullQ) ); 7397 if( error != noErr ) 7398 goto bail; 7399 7400 error = PBQueueInit( pIOData->pFullQ ); 7401 if( error != noErr ) 7402 goto bail; 7403 7404 for(i = 0; i < kNumOutputDVFrames; i++) 7405 { 7406 // create queue elements 7407 pQElem[i] = (DVFrameQElemPtr) PoolAllocateResident( sizeof(DVFrameQElem), true ); 7408 if ( pQElem[i] == nil ) 7409 { 7410 error = memFullErr; 7411 goto bail; 7412 } 7413 7414 // create frames 7415 if (standard == ntscIn) 7416 frameSize = kNTSCCompressedBufferSize; 7417 else 7418 frameSize = kPALCompressedBufferSize; 7419 7420 pQElem[i]->pFrame = (UInt32 *) PoolAllocateResident( frameSize, true ); 7421 if ( pQElem[i]->pFrame == nil ) 7422 { 7423 error = memFullErr; 7424 goto bail; 7425 } 7426 } 7427 7428 // set current frame to start 7429 pIOData->pCurFrameElem = (QElemPtr) pQElem[0]; 7430 7431 // insert the rest of the queue elements into empty queue 7432 for(i = 1; i < kNumOutputDVFrames; i++ ) 7433 { 7434 error = PBEnqueueLast( (QElemPtr) pQElem[i], pIOData->pEmptyQ ); 7435 } 7436 7437bail: 7438 if( error != noErr ) 7439 { 7440 releaseDVFrameIO( pIOData ); 7441 pIOData = nil; 7442 } 7443 7444 *ppIOData = pIOData; 7445 7446 return( error ); 7447} 7448 7449/////////////////////////////////////////////////////////////////////// 7450// 7451// DVDeleteFrameAndElement 7452// 7453/////////////////////////////////////////////////////////////////////// 7454 7455static void deleteDVFrameAndElement( DVFrameQElemPtr pQElem ) 7456{ 7457 // deallocate frame 7458 // checks just to be safe 7459 if( pQElem != nil ) 7460 { 7461 if( pQElem->pFrame != nil ) 7462 PoolDeallocate( pQElem->pFrame ); 7463 7464 // deallocate queue element 7465 PoolDeallocate( pQElem ); 7466 7467 //zzz never check errors 7468 } 7469} 7470 7471/////////////////////////////////////////////////////////////////////// 7472// 7473// DVReleaseFrameIO 7474// 7475/////////////////////////////////////////////////////////////////////// 7476 7477OSErr releaseDVFrameIO( DVIODataPtr pIOData ) 7478{ 7479 OSErr error = noErr; 7480 QElemPtr pQElem; 7481 7482 if( pIOData != nil ) 7483 { 7484 if( pIOData->pBusyQ != nil ) 7485 { 7486 // dequeue and delete all elements in the busy queue 7487 do { 7488 error = PBDequeueFirst( pIOData->pBusyQ, (QElemPtr *) &pQElem ); 7489 7490 if( error == noErr ) 7491 deleteDVFrameAndElement( (DVFrameQElemPtr) pQElem ); 7492 7493 } while( error == noErr ); 7494 7495 error = PBQueueDelete( pIOData->pBusyQ ); 7496 } 7497 7498 7499 if( pIOData->pEmptyQ != nil ) 7500 { 7501 // dequeue and delete all elements in the empty queue 7502 do { 7503 error = PBDequeueFirst( pIOData->pEmptyQ, (QElemPtr *) &pQElem ); 7504 7505 if( error == noErr ) 7506 deleteDVFrameAndElement( (DVFrameQElemPtr) pQElem ); 7507 7508 } while( error == noErr ); 7509 7510 error = PBQueueDelete( pIOData->pEmptyQ ); 7511 } 7512 7513 7514 if( pIOData->pFullQ != nil ) 7515 { 7516 // dequeue and delete all elements in the full queue 7517 do { 7518 error = PBDequeueFirst( pIOData->pFullQ, (QElemPtr *) &pQElem ); 7519 7520 if( error == noErr ) 7521 deleteDVFrameAndElement( (DVFrameQElemPtr) pQElem ); 7522 7523 } while( error == noErr ); 7524 7525 error = PBQueueDelete( pIOData->pFullQ ); 7526 } 7527 7528 // delete current frame and element 7529 if( pIOData->pCurFrameElem != nil ) 7530 deleteDVFrameAndElement( (DVFrameQElemPtr) pIOData->pCurFrameElem ); 7531 7532 // dump the main guy 7533 PoolDeallocate( pIOData ); 7534 } 7535 7536 return( error ); 7537} 7538 7539 7540/////////////////////////////////////////////////////////////////////// 7541// 7542// DVInitDCLInput 7543// 7544/////////////////////////////////////////////////////////////////////// 7545 7546OSErr dclInitInput(DeviceDescriptionPtr pDeviceDescription, 7547 IsochComponentGlobals* isochComponentGlobals ) 7548{ 7549 Ptr pReceiveBuffer; 7550 Ptr pDCLCommand; 7551 DVGlobalInPtr pGlobalData; 7552 DCLLabelPtr pStartDCLLabel; 7553 DVLocalInPtr pLocalData; 7554 DCLCommandPtr *updateDCLList, 7555 *startUpdateDCLList; 7556 DCLUpdateDCLListPtr pDCLUpdateDCLList; 7557 DCLTransferPacketPtr pDCLTransferPacket; 7558 DCLCallProcPtr pDCLCallProc; 7559 DCLJumpPtr pDCLInputLoop; 7560 UInt32 packetNum; 7561 UInt32 bufferNum; 7562 UInt32 updateListSize; 7563 OSErr error = noErr; 7564 7565 // Create the global data structure 7566 pGlobalData = PoolAllocateResident( sizeof(DVGlobalIn), true ); 7567 if( pGlobalData == nil ) 7568 error = memFullErr; 7569 else 7570 pDeviceDescription->pGlobalDVInData = pGlobalData; 7571 7572 pGlobalData->isochComponentGlobals = isochComponentGlobals; 7573 pGlobalData->deviceID = pDeviceDescription->deviceID; 7574 pGlobalData->pDCLList = nil; 7575 pGlobalData->ppUpdateDCLList = nil; 7576 pGlobalData->pDVFrameInputData = nil; 7577 7578 // Create input buffer. Add slop for page alignment 7579 pGlobalData->pReceiveBuffers = PoolAllocateResident(kInputBufferSize + 4096, false); 7580 if( pGlobalData->pReceiveBuffers == nil ) 7581 { 7582 error = memFullErr; 7583 goto bail; 7584 } 7585 pReceiveBuffer = pGlobalData->pReceiveBuffers; 7586 7587 // Align buffer, should be aligned already 7588 pReceiveBuffer = (Ptr) ((((UInt32) pReceiveBuffer) + 4096) & 0xfffff000); 7589 7590 #ifdef dbg_in_init 7591 ASSERTVAR( error, "Error initializing input DCL data structures. Error: %d" ); 7592 #endif 7593 7594 // init frame IO 7595 error = initDVFrameInput(pDeviceDescription->standard, &pGlobalData->pDVFrameInputData); 7596 if( error != noErr ) 7597 goto bail; 7598 7599 error = getCurrentDCLFrame( pGlobalData->pDVFrameInputData, (UInt32 **) &(pGlobalData->pImageBuffer) ); 7600 if( error != noErr ) 7601 goto bail; 7602 7603 #ifdef dbg_in_init 7604 ASSERTVAR( error, "Error initializing input DCL frame I/O system. Error: %d" ); 7605 #endif 7606 7607 // Fill out global structure 7608 pGlobalData->isNTSC = (pDeviceDescription->standard == ntscIn); 7609 pGlobalData->packetCount = 0; 7610 7611 error = FWCreateDCLProgram( &(pGlobalData->DCLProgramID) ); 7612 pDeviceDescription->dclProgramID = pGlobalData->DCLProgramID; 7613 if( error != noErr ) 7614 goto bail; 7615 7616 // create list of DCLs for channel 7617 // make sure we zero it so deallocation can work even if not fully initialized 7618 pGlobalData->pDCLList = (DCLCommandPtr) PoolAllocateResident( kDCLReadProgramSize, true ); 7619 if ( pGlobalData->pDCLList == nil ) 7620 { 7621 error = memFullErr; 7622 goto bail; 7623 } 7624 7625 // create list of update DCLs for channel 7626 // make sure we zero it so deallocation can work even if not fully initialized 7627 pGlobalData->ppUpdateDCLList = (DCLCommandPtr *) PoolAllocateResident( kNumInputDCLs * sizeof (DCLCommandPtr), true ); 7628 if ( pGlobalData->ppUpdateDCLList == nil ) 7629 { 7630 error = memFullErr; 7631 goto bail; 7632 } 7633 7634 #ifdef dbg_in_init 7635 DEBUGVAR( "Initialized input DCL commands. Error: %d", error ); 7636 #endif 7637 7638 // Get pointer to start of DCL commands and update list. 7639 pDCLCommand = (Ptr) pGlobalData->pDCLList; 7640 updateDCLList = pGlobalData->ppUpdateDCLList; 7641 7642 // Create label for start of loop. 7643 pStartDCLLabel = (DCLLabelPtr) pDCLCommand; 7644 pDCLCommand += sizeof( DCLLabel ); 7645 pStartDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 7646 pStartDCLLabel->opcode = kDCLLabelOp; 7647 7648 7649 // Create input buffer lists of 100 packets each. 7650 for (bufferNum = 0; bufferNum < kNumInputBuffers; bufferNum++) 7651 { 7652 // Create the DCL input record record and fill it in. 7653 pLocalData = (DVLocalInPtr) PoolAllocateResident( sizeof(DVLocalIn), true ); 7654 if( pLocalData == nil ) 7655 { 7656 error = memFullErr; 7657 goto bail; 7658 } 7659 pLocalData->pFirstCmd = (DCLCommandPtr) pDCLCommand; 7660 pLocalData->pGlobalData = pGlobalData; 7661 7662 startUpdateDCLList = updateDCLList; 7663 updateListSize = 0; 7664 // Create transfer DCL for each packet. 7665 for (packetNum = 0; packetNum < kNumPacketsPerInputBuffer; packetNum++) 7666 { 7667 // Receive one packet up to kReceiveDVPacketSize bytes. 7668 pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand; 7669 pDCLCommand += sizeof (DCLTransferPacket); 7670 pDCLTransferPacket->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 7671 pDCLTransferPacket->opcode = kDCLReceivePacketStartOp; 7672 pDCLTransferPacket->buffer = pReceiveBuffer; 7673 pDCLTransferPacket->size = kReceiveDVPacketSize; 7674 7675 *updateDCLList++ = (DCLCommandPtr) pDCLTransferPacket; 7676 updateListSize++; 7677 pReceiveBuffer += kAlignedDVPacketSize; 7678 } 7679 7680 // Create update DCL list. 7681 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand; 7682 pDCLCommand += sizeof (DCLUpdateDCLList); 7683 pDCLUpdateDCLList->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 7684 pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp; 7685 pDCLUpdateDCLList->dclCommandList = startUpdateDCLList; 7686 pDCLUpdateDCLList->numDCLCommands = updateListSize; 7687 7688 // Call the DVStorePackets proc. 7689 pDCLCallProc = (DCLCallProcPtr) pDCLCommand; 7690 pDCLCommand += sizeof (DCLCallProc); 7691 pDCLCallProc->pNextDCLCommand = (DCLCommandPtr) pDCLCommand; 7692 pDCLCallProc->opcode = kDCLCallProcOp; 7693 pDCLCallProc->proc = storeDVPackets; 7694 pDCLCallProc->procData = (UInt32) pLocalData; 7695 } 7696 7697 7698 #ifdef dbg_in_init 7699 DEBUGVAR( "Created input DCL program. Error: %d", error ); 7700 #endif 7701 7702 // Loop to start of ping pong. 7703 pDCLInputLoop = (DCLJumpPtr) pDCLCommand; 7704 pDCLInputLoop->pNextDCLCommand = nil; 7705 pDCLInputLoop->opcode = kDCLJumpOp; 7706 pDCLInputLoop->pJumpDCLLabel = pStartDCLLabel; 7707 7708 // Set start of DCL program. 7709 error = FWSetDCLProgramStart (pGlobalData->DCLProgramID, pGlobalData->pDCLList); 7710 7711bail: 7712 if( error != noErr ) 7713 { 7714 disposeDCLInput( pGlobalData ); 7715 pGlobalData = nil; 7716 } 7717 7718 return( error ); 7719} 7720 7721/////////////////////////////////////////////////////////////////////// 7722// 7723// DVStorePackets( 7724// 7725/////////////////////////////////////////////////////////////////////// 7726 7727void storeDVPackets( DCLCommandPtr pDCLCommandPtr ) 7728{ 7729 DCLCallProcPtr pDCLCallProc; 7730 DVLocalInPtr pLocalData; 7731 DVGlobalInPtr pGlobalData; 7732 DCLCommandPtr pCurrentCmd; 7733 DCLTransferPacketPtr pDCLTransferPacket; 7734 Ptr pPacketBuffer; 7735 UInt32 packetHeader, packetSize, packetNum, packetPerFrame; 7736 Boolean vSyncDetected; 7737 UInt8 currentSequenceCount; 7738 7739 // Recast DCL command. 7740 pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr; 7741 7742 // Get input data. 7743 pLocalData = (DVLocalInPtr) pDCLCallProc->procData; 7744 pGlobalData = pLocalData->pGlobalData; 7745 7746 // Get info from ping pong data. 7747 pCurrentCmd = pLocalData->pFirstCmd; 7748 7749 // How many packets we talkin'? 7750 packetPerFrame = pGlobalData->isNTSC ? kNumPacketsPerNTSCFrame : kNumPacketsPerPALFrame; 7751 7752 for ( packetNum = 0; packetNum < kNumPacketsPerInputBuffer; packetNum++ ) 7753 { 7754 // compute size of transfer 7755 pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentCmd; 7756 pPacketBuffer = pDCLTransferPacket->buffer; 7757 packetHeader = *((UInt32*) pPacketBuffer); 7758 pPacketBuffer += 4; // 4 byte 1394 header 7759 packetSize = (packetHeader & kFWIsochDataLength) >> kFWIsochDataLengthPhase; 7760 7761 // detect vSync 7762 if( packetSize > 8 ) 7763 vSyncDetected = ((*(short *)(pPacketBuffer + 8) & 0xE0F8 ) == 0x0000 ); 7764 else 7765 vSyncDetected = false; 7766 7767 // get current data block sequence counter value and increment saved value 7768 // saved value will be decremented at the end for null packets which do not 7769 // increment data block count 7770 currentSequenceCount = pPacketBuffer[3]; 7771 pGlobalData->lastSequenceCount++; 7772 7773 // skip over CIP header 7774 pPacketBuffer += 8; // 8 bytes 7775 packetSize -= 8; 7776 7777// RecordEventLogger( 'isoc', 'cnt ', pGlobalData->lastSequenceCount, currentSequenceCount); 7778 7779 if( vSyncDetected ) 7780 { 7781 if( pGlobalData->packetCount == packetPerFrame ) // if we got our frameSync at the right time 7782 { 7783 IDHDVCompleteEvent event; 7784 7785 // post a DV event to let the curious know... 7786 event.eventHeader.deviceID = pGlobalData->deviceID; 7787 event.eventHeader.event = kIDHPrivateEventReadComplete; 7788 event.frameBuffer = (Ptr) pGlobalData->pImageBuffer; 7789 event.bufferSize = pGlobalData->packetCount * kDVPayloadPacketSize; 7790 event.fwCycleTime = (packetHeader & kFWIsochSy) >> kFWIsochSyPhase; 7791 7792 postEvent( 7793 pGlobalData->isochComponentGlobals, 7794 pGlobalData->deviceID, 7795 kIDHPrivateEventReadComplete, 7796 (void*)&event); 7797 7798 getNextEmptyInputFrame( pGlobalData->pDVFrameInputData, (UInt32 **) &(pGlobalData->pImageBuffer) ); // get a new frame 7799 } 7800 7801 pGlobalData->packetCount = 0; // start a new frame 7802 7803 if ((packetSize == kDVPayloadPacketSize) && (currentSequenceCount == pGlobalData->lastSequenceCount)) 7804 { 7805 // store the packet 7806 BlockMoveData 7807 ( 7808 pPacketBuffer, 7809 (Ptr)((UInt32) pGlobalData->pImageBuffer + (pGlobalData->packetCount * kDVPayloadPacketSize)), 7810 packetSize 7811 ); 7812 7813 pGlobalData->packetCount++; 7814 } 7815 } 7816 else 7817 { 7818 if (currentSequenceCount == pGlobalData->lastSequenceCount) 7819 { 7820 if ((pGlobalData->packetCount < packetPerFrame) && (packetSize == kDVPayloadPacketSize)) 7821 { 7822 // store the packet 7823 BlockMoveData 7824 ( 7825 pPacketBuffer, 7826 (Ptr)((UInt32) pGlobalData->pImageBuffer + (pGlobalData->packetCount * kDVPayloadPacketSize)), 7827 packetSize 7828 ); 7829 7830 pGlobalData->packetCount++; 7831 } 7832 else if ((pGlobalData->packetCount >= packetPerFrame) && (packetSize > 0)) 7833 { 7834 // too many packets between vSync detection, start new frame 7835 pGlobalData->packetCount = 0; 7836 7837 RecordEventLogger( 'isoc', 'stor', 0, '2man'); 7838 7839 } 7840 } 7841 else 7842 { 7843 // packet out of sequence, start new frame 7844 pGlobalData->packetCount = 0; 7845 7846 RecordEventLogger( '****', 'seq!', currentSequenceCount, pGlobalData->lastSequenceCount); 7847 } 7848 } 7849 7850 // if null packet, decrement saved count since DBC is not incremented 7851 // otherwise set last count to current count to resynch counts if bad sequence 7852 if (packetSize == 0) // already deceremented CIP header from packet size 7853 pGlobalData->lastSequenceCount--; 7854 else if( packetSize == kDVPayloadPacketSize) 7855 pGlobalData->lastSequenceCount = currentSequenceCount; 7856 else 7857 { 7858 pGlobalData->lastSequenceCount--; 7859 RecordEventLogger( '****', 'wird', pGlobalData->lastSequenceCount, packetSize); 7860// DebugStr( "\pWeird packet"); 7861 } 7862 7863 // update for next packet 7864 pCurrentCmd = pCurrentCmd->pNextDCLCommand; 7865 } 7866} 7867 7868 7869/////////////////////////////////////////////////////////////////////// 7870// 7871// DVDisposeDCLInput 7872// 7873/////////////////////////////////////////////////////////////////////// 7874 7875OSErr disposeDCLInput( DVGlobalInPtr pInputData ) 7876{ 7877 Ptr pDCLCommand; 7878 DCLCallProcPtr pDCLPingPongProc; 7879 short bufferNum; 7880 OSErr error = noErr; 7881 7882 if( pInputData != nil ) 7883 { 7884 // deallocate receive buffer 7885 if (pInputData->pReceiveBuffers != nil) 7886 PoolDeallocate(pInputData->pReceiveBuffers); 7887 7888 // traverse through the DCL program to get to where 7889 // the buffers are and deallocate them 7890 if( pInputData->pDCLList != nil ) 7891 { 7892 pDCLCommand = (Ptr) pInputData->pDCLList + sizeof (DCLLabel); 7893 7894 // for all call procs 7895 for (bufferNum = 0; bufferNum < kNumInputBuffers; bufferNum++) 7896 { 7897 // find the call proc 7898 pDCLCommand += sizeof (DCLTransferPacket) * kNumPacketsPerInputBuffer + 7899 sizeof (DCLUpdateDCLList); 7900 7901 // dealloc the call proc 7902 pDCLPingPongProc = (DCLCallProcPtr) pDCLCommand; 7903 pDCLCommand += sizeof (DCLCallProc); 7904 if( pDCLPingPongProc->procData != nil ) 7905 PoolDeallocate( (LogicalAddress) pDCLPingPongProc->procData ); 7906 } 7907 7908 PoolDeallocate( pInputData->pDCLList ); 7909 } 7910 7911 // release update list 7912 if( pInputData->ppUpdateDCLList != nil ) 7913 error = PoolDeallocate( pInputData->ppUpdateDCLList ); 7914 7915 // release frame IO 7916 if( pInputData->pDVFrameInputData != nil ) 7917 error = releaseDVFrameIO( pInputData->pDVFrameInputData ); 7918 7919 // dispose the program 7920 error = FWDisposeDCLProgram( pInputData->DCLProgramID ); 7921 7922 // and the whole bloody structure 7923 PoolDeallocate( pInputData ); 7924 } 7925 return( error ); 7926} 7927 7928OSErr writeFrame(IsochComponentInstancePtr ih, char *tmpBuffPtr) 7929{ 7930 DeviceDescriptionPtr pDeviceDescription; 7931 OSErr error = noErr; 7932 7933 error = findDeviceDescriptionforDevice(ih, ih->deviceID, &pDeviceDescription); 7934 7935 if (error == noErr) 7936 error = queueNextFullOutputFrame(pDeviceDescription->pGlobalDVOutData->pDVFrameOutputData, (UInt32 *) tmpBuffPtr); 7937 FailWithVal( error != noErr, Exit, error); 7938 7939Exit: 7940 return error; 7941} 7942 7943OSErr getEmptyOutputFrame(IsochComponentInstancePtr ih, Ptr *tmpBuffPtr, UInt32 *size) 7944{ 7945 DeviceDescriptionPtr pDeviceDescription; 7946 OSErr error = noErr; 7947 7948 error = findDeviceDescriptionforDevice(ih, ih->deviceID, &pDeviceDescription); 7949 FailWithVal( error != noErr, Exit, error); 7950 7951 *size = (pDeviceDescription->standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize; 7952 7953 error = getNextEmptyOutputFrame(pDeviceDescription->pGlobalDVOutData->pDVFrameOutputData, (UInt32 **) tmpBuffPtr); 7954 FailWithVal( error != noErr, Exit, error); 7955 7956Exit: 7957 return error; 7958} 7959 7960//==================================================================================== 7961// 7962// registerDevice() 7963// Register the device and install the FireWire port callback routines and bus reset proc. 7964// 7965//==================================================================================== 7966OSStatus registerDevice( 7967 RegEntryID* inRegEntryID, 7968 FWDriverID* outDriverID, 7969 DeviceDescriptionPtr pDeviceDescription) 7970{ 7971 CSRROMEntryID csrROMEntryID; 7972 OSStatus err = noErr; 7973 7974 err = FWRegisterDriver( 7975 inRegEntryID, 7976 outDriverID, 7977 &csrROMEntryID, 7978 (UInt32) pDeviceDescription); 7979 7980 if (err) 7981 goto Exit; 7982 7983 err = FWSetFWClientInitIsochPortProc(*outDriverID, initIsochPort); 7984 if (err) 7985 goto Exit; 7986 7987 err = FWSetFWClientStartIsochPortProc(*outDriverID, startIsochPort); 7988 if (err) 7989 goto Exit; 7990 7991 err = FWSetFWClientStopIsochPortProc(*outDriverID, stopIsochPort); 7992 if (err) 7993 goto Exit; 7994 7995 err = FWSetFWClientReleaseIsochPortProc(*outDriverID, releaseIsochPort); 7996 7997Exit: 7998 return err; 7999} 8000 8001// handle any reset notifications for the device 8002OSStatus handleBusReset(FWClientInterfaceParamsPtr pParams, UInt32 *pCommandAcceptance) 8003{ 8004 DeviceDescriptionPtr pDeviceDescription; 8005 OSErr error = noErr; 8006 8007 pDeviceDescription = (DeviceDescriptionPtr) pParams->fwClientSpecificData; 8008 8009 RecordEventLogger( 'bus ', 'res ', (UInt32) pDeviceDescription->fwClientID, 0); 8010 8011 FWClientCommandIsComplete(pParams->fwClientCommandID, error); 8012 *pCommandAcceptance = kFWClientCommandAcceptNoMore; 8013 8014 error = postEvent( pDeviceDescription->componentGlobals, pDeviceDescription->deviceID, kIDHEventDeviceChanged, nil); 8015 8016 return error; 8017} 8018