1/*
2 * Copyright (c) 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <Carbon/Carbon.h>
25
26typedef struct IsochComponentInstance IsochComponentInstance, *IsochComponentInstancePtr;
27typedef struct IsochComponentGlobals IsochComponentGlobals, *IsochComponentGlobalsPtr;
28
29#define CALLCOMPONENT_BASENAME() IDHDV
30#define CALLCOMPONENT_GLOBALS()	IsochComponentInstancePtr storage
31
32#define IDH_BASENAME()	FWDV
33#define IDH_GLOBALS()	IsochComponentInstancePtr storage
34#include "IsochronousDataHandler.k.h"
35
36#include "DeviceControlPriv.h"
37
38#include "DVVers.h"
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <unistd.h> // usleep()
43#include <pthread.h>
44#include <syslog.h>	// Debug messages
45
46// Timebase stuff
47#include <mach/clock.h>
48#include <mach/clock_types.h>
49// Trace stuff
50#include <sys/syscall.h>
51
52#include <CoreFoundation/CoreFoundation.h>
53#include <IOKit/IOKitLib.h>
54
55#include <IOKit/IOMessage.h>
56#include <IOKit/firewire/IOFireWireFamilyCommon.h>
57#include <IOKit/avc/IOFireWireAVCConsts.h>
58
59#include "DVLib.h"
60
61#define kDVRequestID 0
62#define kIOPending 1
63#define kIORunning 2
64#define kMaxDeviceClients 4
65
66#define kDCLBlockTime (100.0/8000.0)
67
68#define DEBUG 0
69//#define DRAWRINGBUFFERGRAPH
70/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
71
72#define kDVDeviceInfo 			'ddin'	// DV device info
73#define kMaxInstances			10	// max clients attached to a device
74#define kMaxNotifications		100	// 100 notifications can be supported
75#define kNTSCCompressedBufferSize	120000
76#define	kPALCompressedBufferSize	144000
77#define kIDHSeedAtomType		'seed'	// seed for device atom validity
78#define kIDHDevicePresentType		'pres'	// is device present?
79#define	kServiceTypeDVServices		'avc '
80#define kTimeoutDuration		(1000 / 15) * durationMillisecond	// 1/15 second (2 frame times)
81
82typedef OSStatus (*RequestFunc)(IsochComponentInstancePtr ih, void *params);
83
84typedef struct ClientNotification {
85        ComponentInstance 	ihc;
86        IDHDeviceID			deviceID;
87        IDHNotificationProc	notificationProc;
88        IDHEvent			events;
89        void				*userData;
90} ClientNotification;
91
92// describes a device on the firewire bus
93typedef struct DeviceDescription {
94    DVDevice 		*fDevice;
95    IsochComponentGlobalsPtr fGlobals;
96    UInt32 		fNumOutputFrames;
97    UInt8* bufMem[kDVMaxFrames];
98    DVFrameVars *fReadSharedVars;	// Structure shared with isoc program thread
99    DVFrameVars *fWriteSharedVars;	// Structure shared with isoc program thread
100    DVGlobalOutPtr fWrite;
101    DVGlobalInPtr fRead;
102    UInt8 * 	fDCLBuffer;			// DCL Buffers shared with kernel driver
103    DVSharedVars *fSharedWriteVars;	// For access to output DCL variables
104    UInt32 *	fOldWriteTimeStamps;
105    int			fDCLReadPos;		// Which block the DCL write program will process next
106    int			fBufWritePos;		// Next block to write data into
107    int			fFrameBufferPos;	// Current offset into current frame buffer
108    int			fDCLSavedPacketNum; // Current packet in DCL buffer when we're waiting for a frame
109    UInt8 *		fDCLSavedWritePos;	// Current position in DCL buffer when we're waiting for the next frame
110    int			fBufSize;			// NTSC or PAL frame
111    int			fOldDrop;			// Dropped before
112    int			fOldRead;			// Where DV driver was before
113    IsochComponentInstancePtr	fOpenClients[kMaxDeviceClients];	// component instances doing I/O to/from device
114    int			fBufferLocks[kDVMaxFrames];
115    ComponentInstance	deviceControlInstance;		// device control component instance
116    Component		clock;				// FireWire clock component, clients get their own instance, not sure why
117    QTAtomContainer	deviceContainer;		// contains device database
118    SInt16		deviceControlCount;		// number of clients using device control
119    SInt16		readLocks;			// num clients that have device open for reads
120    SInt16		writeLocks;			// num clients that have device open for writes
121    Boolean		fActive;			// device is currently online
122    UInt8		fOutputMode;		// AVC output signal mode - NTSC/SDL etc.
123    UInt8		fWaitingStartWrite;	// 1 = if we're filling up buffers before starting to write, 2 = need to retry start
124    UInt8		fConnected;			// Number of times device has been selected (via IDHSetDeviceConfiguration)
125    UInt8		fReadStage;
126    UInt8		fNoAVC;				// True if device doesn't do AVC commands
127#ifdef DRAWRINGBUFFERGRAPH
128	Ptr		fScreenBaseAddr;
129	UInt32	fPixDepth;
130	UInt32	fRowBytes;
131#endif
132} DeviceDescription, *DeviceDescriptionPtr;
133
134#ifdef DRAWRINGBUFFERGRAPH
135static void	SetUpBlitGlobals(DeviceDescriptionPtr ddp);
136static void	BlitBufferGraph(DeviceDescriptionPtr ddp);
137#endif
138
139struct IsochComponentGlobals
140{
141    // Globals
142    UInt32		useCMP;					// CMP off by default, turn on by adding 'ucmp' resource
143    DeviceDescription	deviceDescription[kDVMaxDevicesActive];	// description of each device
144    ClientNotification	clientNotification[kMaxNotifications];	// arbirtary # of notifications
145    UInt32		nDevices;				// number of devices in the list
146    UInt32		seed;					// keep track of device lists
147
148    // X Stuff
149    DVThread *			fDVThread;
150    CFBundleRef			fBundleID;				// Of the DV component's bundle
151    UInt16				fBundleResRef;			// ref for the resource file
152
153    int					fNumInstances;
154};
155
156
157struct IsochComponentInstance
158{
159    // Instance variables
160    ComponentInstance	self;
161    QTAtomSpec		currentConfig;				// current device config set by client
162    IDHDeviceID		deviceID;					// current deviceID
163    UInt16			fClientIndex;				// into device client list
164    long		permissions;					// open permissions
165    IDHParameterBlock *	fHead;					// Of I/O queue
166    IDHParameterBlock *	fTail;					// Of I/O queue
167    IDHParameterBlock *	fActiveHead;			// Of I/Os referencing the ring buffer
168    IDHParameterBlock *	fActiveTail;			// Of I/O referencing the ring buffer
169    UInt32			fSyncRequest;				// Flag to indicate completion of synchronous operation
170    ComponentResult	fSyncResult;				// Result of sync operation
171    Boolean			hasDeviceControl;			// does this client have device control?
172};
173
174/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
175
176/* Function prototypes */
177
178pascal ComponentResult
179FWDVICodecComponentDispatch(ComponentParameters *params, char ** storage);
180static pascal ComponentResult
181FWDVIDHCloseDevice(IsochComponentInstancePtr ih);
182
183static OSStatus doAVCTransaction(DeviceDescriptionPtr deviceDescriptionPtr,
184                DVCTransactionParams* inTransaction);
185
186static OSStatus disableRead(DeviceDescription *deviceDescriptionPtr);
187static void disableWrite(DeviceDescription *deviceDescriptionPtr);
188
189/* Globals */
190static IsochComponentGlobals globals;
191
192
193/* ---------------------- Debug Stuff -------------------------- */
194#ifdef DEBUG
195#define FailMessage(cond)		assert (!(cond))
196#else
197#define FailMessage(cond)		{}
198#endif
199#define FailWithVal(cond, handler,num)	\
200        if (cond) {			\
201                goto handler;		\
202        }
203#define FailWithAction(cond, action, handler)	\
204        if (cond) {				\
205                { action; }			\
206                goto handler;			\
207        }
208
209#define FailIf(cond, handler)	\
210        if (cond) {		\
211            FailMessage(false);	\
212                goto handler;	\
213        }
214
215#if DEBUG
216static char * print4(UInt32 val, char *buf)
217{
218    char a, b, c, d;
219    a = val>>24;
220    b = val>>16;
221    c = val>>8;
222    d = val;
223
224    if(a >= ' ' && b >= ' ' && c >= ' ' && d >= ' ')
225        //printf("%c%c%c%c", a, b, c, d);
226        //syslog(LOG_INFO, "%c%c%c%c", a, b, c, d);
227        snprintf(buf, 8, "%c%c%c%c", a, b, c, d);
228    else
229        //printf(" 0x%x ", (int)val);
230        //syslog(LOG_INFO, " 0x%x ", (int)val);
231        snprintf(buf, 8, " 0x%x ", (int)val);
232
233    return buf + strlen(buf);
234}
235
236static void RecordEventLogger(UInt32 a, UInt32 b, UInt32 c, UInt32 d)
237{
238    char buf[256];
239    char *curr = buf;
240    snprintf(buf, 11, "0x%x:", (unsigned int) pthread_self());
241    curr = buf + strlen(buf);
242    if(a)
243    curr = print4(a, curr);
244    if(b)
245    curr = print4(b, curr);
246    if(c)
247    curr = print4(c, curr);
248    if(d)
249    curr = print4(d, curr);
250    printf("%s\n", buf);
251    syslog(LOG_INFO, buf);
252}
253#else
254#define RecordEventLogger(a, b, c, d)
255#endif
256
257//masks for SYS_kdebug_trace code
258#define kKernelTraceEnable	(1 << 0 )
259#define kKernelTraceDisable	(1 << 1 )
260#define kIOFWDVTrace 0x08001000
261
262#if 0
263static int pKGSysCall_Start (int code, int param1, int param2, int param3, int param4, int param5, int param6 )
264{
265	return syscall ( SYS_kdebug_trace, code | kKernelTraceEnable, param1, param2, param3, param4, param5, param6 );
266}
267
268static int pKGSysCall_End (int code, int param1, int param2, int param3, int param4, int param5, int param6 )
269{
270	return syscall ( SYS_kdebug_trace, code | kKernelTraceDisable, param1, param2, param3, param4, param5, param6 );
271}
272#endif
273
274static int pKGSysCall_Insert (int code, int param1, int param2, int param3, int param4, int param5, int param6 )
275{
276	return syscall ( SYS_kdebug_trace, code , param1, param2, param3, param4, param5, param6 );
277}
278
279static void dropMsg(DeviceDescription *deviceDescriptionPtr, UInt32 dropped)
280{
281    IsochComponentGlobalsPtr g = deviceDescriptionPtr->fGlobals;
282    UInt32 i;
283    IDHDeviceFrameDroppedEvent dropEvent;
284    pKGSysCall_Insert (kIOFWDVTrace, 'drop', dropped-deviceDescriptionPtr->fOldDrop, dropped, 0, 0, 0);
285
286    for (i = 0; i < kMaxNotifications ; ++i)
287    {
288        ClientNotification* clientNotification = &g->clientNotification[i];
289        IDHDeviceID clientDeviceID = clientNotification->deviceID;
290        IDHEvent wantedEvents = clientNotification->events;
291        if (kIDHEventFrameDropped & wantedEvents)
292        {
293            // Send notification if the device matches the client's desired device
294            // or client specified all devices.
295            if ((kIDHDeviceIDEveryDevice == clientDeviceID) ||
296                    ((IDHDeviceID)deviceDescriptionPtr == clientDeviceID) )
297            {
298                // we currently only support a one-shot notification, like clock callbacks
299                clientNotification->events = 0;
300
301                dropEvent.eventHeader.event = kIDHEventFrameDropped;
302                dropEvent.eventHeader.deviceID = (IDHDeviceID)deviceDescriptionPtr;
303                dropEvent.eventHeader.notificationID =
304                                (UInt32)clientNotification;
305                dropEvent.totalDropped = dropped;
306                dropEvent.newlyDropped = dropped - deviceDescriptionPtr->fOldDrop;
307
308                (*clientNotification->notificationProc)
309                                ((IDHGenericEvent*)&dropEvent,
310                                clientNotification->userData);
311            }
312        }
313    }
314
315    // syslog(LOG_INFO,"Just dropped %ld frames (total %ld)!\n", dropped-deviceDescriptionPtr->fOldDrop, dropped);
316
317    deviceDescriptionPtr->fOldDrop = dropped;
318}
319
320static inline UInt32 cycles(UInt32 cycleReg)
321{
322#if 0
323    UInt32 result;
324    result = ((cycleReg & 0xFE000000) >> 25) * 8000;
325    result += (cycleReg & 0x01FFF000) >> 12;
326    return result;
327#else
328	return (cycleReg & 0x01FFF000) >> 12;
329#endif
330}
331
332/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
333
334OSStatus findDeviceDescriptionforDevice( IsochComponentInstancePtr ih, UInt32 deviceID, DeviceDescription **deviceDescription)
335{
336    OSStatus	result = noErr;
337    *deviceDescription = (DeviceDescriptionPtr)deviceID;
338    return result;
339}
340
341//��� do a super find atom someday
342static OSStatus findAtom( const QTAtomSpec *atomSpec, OSType theType, QTAtom *theAtom)
343{
344        OSStatus result = noErr;
345        OSType type;
346        QTAtom atom;
347
348        atom = atomSpec->atom;
349
350        result = QTGetAtomTypeAndID( atomSpec->container, atom, (long *) &type, nil);
351        FailWithVal( result != noErr, Exit, result);
352
353        while( type != kIDHDeviceAtomType && type != theType)
354        {
355                atom = QTGetAtomParent( atomSpec->container, atom); // should be isoch atom
356                FailWithAction( atom == nil || atom == -1, result = kIDHErrDeviceList, Exit);
357
358                result = QTGetAtomTypeAndID( atomSpec->container, atom, (long *) &type, nil);
359                FailWithVal( result != noErr, Exit, result);
360        }
361
362        if( theType == type)
363        {
364                *theAtom = atom;
365                result = noErr;
366        }
367        else
368        {
369                *theAtom = nil;
370                result = kIDHErrDeviceList;
371        }
372
373Exit:
374        return result;
375}
376
377static OSStatus getDeviceID( QTAtomSpec *configID, UInt32 *deviceID)
378{
379        OSStatus result = noErr;
380        QTAtom deviceAtom;
381
382        *deviceID = nil;
383
384        result = findAtom( configID, kIDHDeviceAtomType, &deviceAtom);
385        FailWithVal( result != noErr, Exit, result);
386
387        result = QTGetAtomTypeAndID( configID->container, deviceAtom, nil, (long *) deviceID);
388        FailWithVal( result != noErr, Exit, result);
389
390Exit:
391        return result;
392}
393
394static OSStatus closeDeviceControl( IsochComponentInstancePtr ih, DeviceDescriptionPtr deviceDescriptionPtr)
395{
396        OSStatus 						result = noErr;
397
398#ifdef kIDH_Verbose_Debug_Logging
399	syslog(LOG_INFO, "IDH: closeDeviceControl begin\n");
400#endif
401
402        if( deviceDescriptionPtr->deviceControlInstance)
403        {
404                if( --deviceDescriptionPtr->deviceControlCount <= 0)
405                {
406                        deviceDescriptionPtr->deviceControlCount = 0;
407
408                        result = DeviceControlDisableAVCTransactions(deviceDescriptionPtr->deviceControlInstance);
409                        result = DeviceControlSetDeviceConnectionID(deviceDescriptionPtr->deviceControlInstance,
410                                                                                            kIDHInvalidDeviceID);
411
412                        CloseComponent(deviceDescriptionPtr->deviceControlInstance);
413
414                        deviceDescriptionPtr->deviceControlInstance = nil;
415                }
416        }
417
418#ifdef kIDH_Verbose_Debug_Logging
419		syslog(LOG_INFO, "IDH: closeDeviceControl end\n");
420#endif
421
422        return result;
423}
424
425OSStatus checkSeed( IsochComponentGlobalsPtr gGlobals, QTAtomSpec *configID)
426{
427        QTAtom 		seedAtom;
428        OSStatus 		result = noErr;
429        UInt32		seed;
430
431        // look for device in device container
432        seedAtom = QTFindChildByIndex( configID->container, kParentAtomIsContainer, kIDHSeedAtomType, 1, nil);
433        FailWithAction( seedAtom == nil, result = kIDHErrDeviceList, Exit);
434
435        QTLockContainer( configID->container);
436
437        // get the value of the devicePresent atom
438        QTCopyAtomDataToPtr( configID->container, seedAtom, true, sizeof( seed), &seed, nil);
439
440        QTUnlockContainer( configID->container);
441
442        // seed has expired?
443        if( seed != gGlobals->seed)
444        {
445                result = kIDHErrDeviceList;
446                goto Exit;
447        }
448
449Exit:
450        return result;
451}
452
453static OSStatus setupVideoAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard, Boolean isSDL, Boolean isDVCPro)
454{
455    OSStatus 					result = noErr;
456    QTAtom 					configAtom;
457    OSType 					type;
458    long 					size;
459    float 					interval;
460    long					direction;
461    IDHDimension 			dimension;
462    IDHResolution 			resolution;
463    Fixed 					refresh;
464    OSType 					pixel;
465    OSType 					decoType;
466    Component 				decoComponent;
467    ComponentDescription 	compDescrip;
468
469#ifdef kIDH_Verbose_Debug_Logging
470	syslog(LOG_INFO, "IDH: setupVideoAtoms begin\n");
471#endif
472
473    // create a vide NTSC mode
474    result = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType,
475                    0, 0, 0, nil, &configAtom);
476    FailWithVal( result != noErr, Exit, result);
477
478    type = kIDHVideoMediaAtomType;
479    result = QTInsertChild( container, configAtom, kIDHIsochMediaType,
480                    0, 0, sizeof( type), &type, nil);
481    FailWithVal( result != noErr, Exit, result);
482
483    if(isSDL) {
484        result = QTInsertChild( container, configAtom, kIDHNameAtomType,
485                        0, 0, 7, "\pDV-SDL", nil);
486    }
487    else if(isDVCPro) {
488        result = QTInsertChild( container, configAtom, kIDHNameAtomType,
489                        0, 0, 7, "\pDVCPro", nil);
490    }
491    else {
492        result = QTInsertChild( container, configAtom, kIDHNameAtomType,
493                        0, 0, 3, "\pDV", nil);
494    }
495    FailWithVal( result != noErr, Exit, result);
496
497    type = (standard == ntscIn)?'DVC ':'DVCP';
498    result = QTInsertChild( container, configAtom, kIDHDataTypeAtomType,
499                    0, 0, sizeof( type), &type, nil);
500    FailWithVal( result != noErr, Exit, result);
501
502    size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
503    if(isSDL)
504        size /= 2;
505    result = QTInsertChild( container, configAtom, kIDHDataSizeAtomType,
506                    0, 0, sizeof( size), &size, nil);
507    FailWithVal( result != noErr, Exit, result);
508
509    result = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType,
510                    0, 0, sizeof( size), &size, nil);
511    FailWithVal( result != noErr, Exit, result);
512
513    interval = 29.97;
514    result = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType,
515                    0, 0, sizeof( interval), &interval, nil);
516    FailWithVal( result != noErr, Exit, result);
517
518    direction = kIDHDataTypeIsInputAndOutput;
519    result = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType,
520                    0, 0, sizeof( direction), &direction, nil);
521    FailWithVal( result != noErr, Exit, result);
522
523    dimension.x = 720; dimension.y = (standard == ntscIn)?480:576;
524    result = QTInsertChild( container, configAtom, kIDHVideoDimensionsAtomType,
525                    0, 0, sizeof( dimension), &dimension, nil);
526    FailWithVal( result != noErr, Exit, result);
527
528    resolution.x = 72 << 16; resolution.y = 72 << 16;
529    result = QTInsertChild( container, configAtom, kIDHVideoResolutionAtomType,
530                    0, 0, sizeof( resolution), &resolution, nil);
531    FailWithVal( result != noErr, Exit, result);
532
533    refresh = (29 << 16) + 97; //���
534    result = QTInsertChild( container, configAtom, kIDHVideoRefreshRateAtomType,
535                    0, 0, sizeof( refresh), &refresh, nil);
536    FailWithVal( result != noErr, Exit, result);
537
538    pixel = 'dv  '; //���
539    result = QTInsertChild( container, configAtom, kIDHVideoPixelTypeAtomType,
540                    0, 0, sizeof( pixel), &pixel, nil);
541    FailWithVal( result != noErr, Exit, result);
542
543//���	kIDHVideoDecompressorsAtomType		= FOUR_CHAR_CODE('deco'),
544
545    decoType = (standard == ntscIn)?'dvc ':'dvcp';
546    result = QTInsertChild( container, configAtom, kIDHVideoDecompressorTypeAtomType,
547                    0, 0, sizeof( decoType), &decoType, nil);
548    FailWithVal( result != noErr, Exit, result);
549
550    compDescrip.componentType = 'imdc';
551    compDescrip.componentSubType = decoType;
552    compDescrip.componentManufacturer = 0;
553    compDescrip.componentFlags = 0;
554    compDescrip.componentFlagsMask = 0;
555
556    decoComponent = FindNextComponent( nil, &compDescrip);
557    result = QTInsertChild( container, configAtom, kIDHVideoDecompressorComponentAtomType,
558                    0, 0, sizeof( decoComponent), &decoComponent, nil);
559    FailWithVal( result != noErr, Exit, result);
560
561Exit:
562
563#ifdef kIDH_Verbose_Debug_Logging
564		syslog(LOG_INFO, "IDH: setupVideoAtoms end\n");
565#endif
566
567	return result;
568}
569
570static OSStatus setup48kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard)
571{
572        OSStatus 		err;
573        QTAtom 		configAtom;
574
575        StringPtr 	name;
576        OSType 		type;
577        long 		size;
578        Fixed 		rate;
579        float 		interval;
580        long 		direction;
581
582        // create a vide NTSC mode
583        err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType,
584                        0, 0, 0, nil, &configAtom);
585        FailWithVal( err != noErr, Exit, err);
586
587        type = kIDHSoundMediaAtomType;
588        err = QTInsertChild( container, configAtom, kIDHIsochMediaType,
589                        0, 0, sizeof( type), &type, nil);
590        FailWithVal( err != noErr, Exit, err);
591
592        name = "\pDV-48khz";
593        err = QTInsertChild( container, configAtom, kIDHNameAtomType,
594                        0, 0, name[0]+1, name, nil);
595        FailWithVal( err != noErr, Exit, err);
596
597        type = 'DV48';
598        err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType,
599                        0, 0, sizeof( type), &type, nil);
600        FailWithVal( err != noErr, Exit, err);
601
602        size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
603        err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType,
604                        0, 0, sizeof( size), &size, nil);
605        FailWithVal( err != noErr, Exit, err);
606
607        size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
608        err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType,
609                        0, 0, sizeof( size), &size, nil);
610        FailWithVal( err != noErr, Exit, err);
611
612        interval = 29.97;
613        err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType,
614                        0, 0, sizeof( interval), &interval, nil);
615        FailWithVal( err != noErr, Exit, err);
616
617        direction = kIDHDataTypeIsInputAndOutput;
618        err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType,
619                        0, 0, sizeof( direction), &direction, nil);
620        FailWithVal( err != noErr, Exit, err);
621
622        size = 2;
623        err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType,
624                        0, 0, sizeof( size), &size, nil);
625        FailWithVal( err != noErr, Exit, err);
626
627        size = 2;
628        err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType,
629                        0, 0, sizeof( size), &size, nil);
630        FailWithVal( err != noErr, Exit, err);
631
632        rate = rate44khz;
633        err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType,
634                        0, 0, sizeof( rate), &rate, nil);
635        FailWithVal( err != noErr, Exit, err);
636
637Exit:
638        return err;
639} // sound 1 config
640
641static OSStatus setup32kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard)
642{
643        OSStatus err;
644        QTAtom configAtom;
645
646        StringPtr 	name;
647        OSType 		type;
648        long 		size;
649        Fixed 		rate;
650        float 		interval;
651        long 		direction;
652
653        // create a vide NTSC mode
654        err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType,
655                        0, 0, 0, nil, &configAtom);
656        FailWithVal( err != noErr, Exit, err);
657
658        type = kIDHSoundMediaAtomType;
659        err = QTInsertChild( container, configAtom, kIDHIsochMediaType,
660                        0, 0, sizeof( type), &type, nil);
661        FailWithVal( err != noErr, Exit, err);
662
663        name = "\pDV-32khz";
664        err = QTInsertChild( container, configAtom, kIDHNameAtomType,
665                        0, 0, name[0]+1, name, nil);
666        FailWithVal( err != noErr, Exit, err);
667
668        type = 'DV32';
669        err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType,
670                        0, 0, sizeof( type), &type, nil);
671        FailWithVal( err != noErr, Exit, err);
672
673        size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
674        err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType,
675                        0, 0, sizeof( size), &size, nil);
676        FailWithVal( err != noErr, Exit, err);
677
678        size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
679        err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType,
680                        0, 0, sizeof( size), &size, nil);
681        FailWithVal( err != noErr, Exit, err);
682
683        interval = 29.97;
684        err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType,
685                        0, 0, sizeof( interval), &interval, nil);
686        FailWithVal( err != noErr, Exit, err);
687
688        direction = kIDHDataTypeIsInputAndOutput;
689        err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType,
690                        0, 0, sizeof( direction), &direction, nil);
691        FailWithVal( err != noErr, Exit, err);
692
693        size = 4;
694        err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType,
695                        0, 0, sizeof( size), &size, nil);
696        FailWithVal( err != noErr, Exit, err);
697
698        size = 2;
699        err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType,
700                        0, 0, sizeof( size), &size, nil);
701        FailWithVal( err != noErr, Exit, err);
702
703        rate = 32000 << 16;
704        err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType,
705                        0, 0, sizeof( rate), &rate, nil);
706        FailWithVal( err != noErr, Exit, err);
707
708Exit:
709        return err;
710} // sound 2 config
711
712static OSStatus setup44kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard)
713{
714        OSStatus err;
715        QTAtom configAtom;
716
717        StringPtr 	name;
718        OSType 		type;
719        long 		size;
720        Fixed 		rate;
721        float 		interval;
722        long 		direction;
723
724        // create a vide NTSC mode
725        err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType,
726                        0, 0, 0, nil, &configAtom);
727        FailWithVal( err != noErr, Exit, err);
728
729        type = kIDHSoundMediaAtomType;
730        err = QTInsertChild( container, configAtom, kIDHIsochMediaType,
731                        0, 0, sizeof( type), &type, nil);
732        FailWithVal( err != noErr, Exit, err);
733
734        name = "\pDV-44khz";
735        err = QTInsertChild( container, configAtom, kIDHNameAtomType,
736                        0, 0, name[0]+1, name, nil);
737        FailWithVal( err != noErr, Exit, err);
738
739        type = 'DV44';
740        err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType,
741                        0, 0, sizeof( type), &type, nil);
742        FailWithVal( err != noErr, Exit, err);
743
744        size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
745        err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType,
746                        0, 0, sizeof( size), &size, nil);
747        FailWithVal( err != noErr, Exit, err);
748
749        size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
750        err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType,
751                        0, 0, sizeof( size), &size, nil);
752        FailWithVal( err != noErr, Exit, err);
753
754        interval = 29.97;
755        err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType,
756                        0, 0, sizeof( interval), &interval, nil);
757        FailWithVal( err != noErr, Exit, err);
758
759        direction = kIDHDataTypeIsInputAndOutput;
760        err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType,
761                        0, 0, sizeof( direction), &direction, nil);
762        FailWithVal( err != noErr, Exit, err);
763
764        size = 4;
765        err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType,
766                        0, 0, sizeof( size), &size, nil);
767        FailWithVal( err != noErr, Exit, err);
768
769        size = 2;
770        err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType,
771                        0, 0, sizeof( size), &size, nil);
772        FailWithVal( err != noErr, Exit, err);
773
774        rate = 44100 << 16;
775        err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType,
776                        0, 0, sizeof( rate), &rate, nil);
777        FailWithVal( err != noErr, Exit, err);
778
779Exit:
780        return err;
781} // sound 3 config
782
783static OSStatus cameraNameLookup(DeviceDescriptionPtr pDeviceDescription, UInt8 *name)
784{
785    OSStatus	result	= noErr;
786    int 		len 	= strlen(pDeviceDescription->fDevice->fName);
787
788#ifdef kIDH_Verbose_Debug_Logging
789	syslog(LOG_INFO, "IDH: cameraNameLookup begin\n");
790#endif
791
792	if(len)
793	{
794        if(len>255)
795            len = 255;
796        name[0] = len;
797        BlockMoveData(pDeviceDescription->fDevice->fName, name+1, len);
798    }
799    else
800	{
801        // Look up vendor ID in resource list
802		UInt32		vendorID	= pDeviceDescription->fDevice->fGUID >> 40;
803		CFStringRef cameraName	= CFStringCreateWithCString(kCFAllocatorDefault, "DV", CFStringGetSystemEncoding());
804        SInt16		refNum		= -1, localizedRefNum = -1;
805		Boolean		stringFound	= false;
806
807		CFBundleRef myRef = 0;
808
809		// read vendor id resource and look for matching guid
810		if(pDeviceDescription->fGlobals->fBundleID == 0)
811		{
812			myRef = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.IOFWDVComponents"));
813			CFBundleOpenBundleResourceFiles(myRef, &refNum, &localizedRefNum);
814			pDeviceDescription->fGlobals->fBundleID = myRef;
815			pDeviceDescription->fGlobals->fBundleResRef = localizedRefNum;
816		}
817		else
818		{
819			myRef = pDeviceDescription->fGlobals->fBundleID;
820		}
821
822		if( myRef )
823		{
824			// form the key
825			CFStringRef keyRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("VENDOR_%08X"), vendorID);
826
827			if( keyRef )
828			{
829				// lookup the value
830				CFStringRef localizedString = CFBundleCopyLocalizedString ( myRef,  keyRef, cameraName, NULL );
831
832				if ( localizedString )
833				{
834					CFMutableArrayRef names = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
835
836					if (localizedString && CFStringGetLength(localizedString) > 0)
837					{
838						CFArrayAppendValue(names, (const void *)localizedString);
839					}
840
841					if (cameraName && CFStringGetLength(cameraName) > 0)
842					{
843						CFArrayAppendValue(names, (const void *)cameraName);
844					}
845
846					CFStringRef vendorAndCameraName = CFStringCreateByCombiningStrings(kCFAllocatorDefault, names, CFSTR(" "));
847
848					if ( vendorAndCameraName )
849					{
850						stringFound = CFStringGetPascalString ( vendorAndCameraName, name, sizeof(name), CFStringGetSystemEncoding());
851						CFRelease( vendorAndCameraName );
852					}
853
854					CFRelease(names);
855					CFRelease( localizedString );
856				}
857
858				CFRelease( keyRef );
859			}
860		}
861
862		if(stringFound == false)
863		{
864			CFStringGetPascalString ( CFSTR("DV"), name, sizeof(name), CFStringGetSystemEncoding());
865		}
866
867		CFRelease(cameraName);
868	}
869
870#ifdef kIDH_Verbose_Debug_Logging
871	syslog(LOG_INFO, "IDH: cameraNameLookup end\n");
872#endif
873
874	return result;
875}
876
877static OSStatus postEvent(IsochComponentGlobalsPtr g, IDHDeviceID deviceID, IDHEvent event)
878{
879        UInt32 i;
880        IDHDeviceConnectionEvent connectionEvent;
881        OSStatus error = noErr;
882
883        // We now have two broad classifications of events - ones that need to be
884        // reported ASAP, which are stream related:
885        //
886        // 		kIDHPrivateEventReadComplete
887        //		kIDHPrivateEventWriteComplete
888        //
889        // and ones that are device management related, whose notifications will
890        // probably generate massive amounts of task-level only Toolbox calls:
891        //
892        //		kIDHEventDeviceAdded
893        //		kIDHEventDeviceRemoved
894        //		kIDHEventReadEnabled
895        //		kIDHEventReadDisabled
896        //		kIDHEventWriteEnabled
897        //		kIDHEventWriteDisabled
898        //
899        // kIDHPrivateEventReadComplete and kIDHPrivateEventWriteComplete are posted to a secondary
900        // interrupt handler. All other events are handled immediately.
901
902
903        RecordEventLogger( 'isoc', 'post', deviceID, event);
904
905        for (i = 0; i < kMaxNotifications ; ++i)
906        {
907                ClientNotification* clientNotification = &g->clientNotification[i];
908                IDHDeviceID clientDeviceID = clientNotification->deviceID;
909                IDHEvent wantedEvents = clientNotification->events;
910                if (event & wantedEvents)
911                {
912                        // Send notification if the device matches the client's desired device
913                        // or client specified all devices.
914                        if ((kIDHDeviceIDEveryDevice == clientDeviceID) ||
915                                (deviceID == clientDeviceID) )
916                        {
917                                // we currently only support a one-shot notification, like clock callbacks
918                                clientNotification->events = 0;
919
920                                switch(event)
921                                {
922                                        case kIDHEventDeviceChanged:
923                                        case kIDHEventDeviceAdded:
924                                        case kIDHEventDeviceRemoved:
925                                        case kIDHEventReadEnabled:
926                                        case kIDHEventReadDisabled:
927                                        case kIDHEventWriteEnabled:
928                                        case kIDHEventWriteDisabled:
929
930                                                connectionEvent.eventHeader.event = event;
931                                                connectionEvent.eventHeader.deviceID = deviceID;
932                                                connectionEvent.eventHeader.notificationID =
933                                                                (UInt32)clientNotification;
934
935                                                (*clientNotification->notificationProc)
936                                                                ((IDHGenericEvent*)&connectionEvent,
937                                                                clientNotification->userData);
938                                                break;
939
940                                        default:
941                                                RecordEventLogger( 'isoc', 'post', '????', event);
942                                                break;
943                                }
944
945                        }
946                }
947        }
948
949        RecordEventLogger( 'isoc', 'post', 'end ', event);
950        return error;
951
952}
953
954static void deviceMessage(void * refcon, UInt32 messageType, void *messageArgument)
955{
956
957#ifdef kIDH_Verbose_Debug_Logging
958	syslog(LOG_INFO, "IDH: deviceMessage begin\n");
959#endif
960
961	// refcon is 1-based device index.
962    DeviceDescriptionPtr deviceDescriptionPtr = &globals.deviceDescription[(int)refcon-1];
963    //syslog(LOG_INFO,"Got message: refcon %d, type 0x%x arg %p\n",
964    //    refcon, messageType, messageArgument);
965    if(messageType == kIOFWMessageServiceIsRequestingClose) {
966        //syslog(LOG_INFO,"Device # %d, ptr %p requesting close\n",
967        //	refcon-1, deviceDescriptionPtr);
968        deviceDescriptionPtr->fActive = false;
969        if(deviceDescriptionPtr->deviceControlInstance) {
970            DeviceControlDisableAVCTransactions(deviceDescriptionPtr->deviceControlInstance);
971            DeviceControlSetDeviceConnectionID(deviceDescriptionPtr->deviceControlInstance,
972                                                                                kIDHInvalidDeviceID);
973        }
974        if(deviceDescriptionPtr->fDevice) {
975
976			if(deviceDescriptionPtr->fRead != NULL)
977				disableRead(deviceDescriptionPtr);
978			if(deviceDescriptionPtr->fWrite != NULL)
979				disableWrite(deviceDescriptionPtr);
980
981            DVDeviceTerminate(deviceDescriptionPtr->fDevice);
982            deviceDescriptionPtr->fDevice = NULL;
983        }
984        // post a DV event to let the curious know...
985        postEvent(deviceDescriptionPtr->fGlobals, (IDHDeviceID)deviceDescriptionPtr, kIDHEventDeviceRemoved);
986    }
987
988#ifdef kIDH_Verbose_Debug_Logging
989	syslog(LOG_INFO, "IDH: deviceMessage end\n");
990#endif
991}
992
993
994static OSStatus enableRead(DeviceDescription *deviceDescriptionPtr)
995{
996    OSStatus		result;
997
998#ifdef kIDH_Verbose_Debug_Logging
999	syslog(LOG_INFO, "IDH: enableRead begin\n");
1000#endif
1001
1002    deviceDescriptionPtr->fNumOutputFrames = 4;
1003    deviceDescriptionPtr->fRead = DVAllocRead(deviceDescriptionPtr->fDevice, globals.fDVThread);
1004
1005	// Get the current device's output-signal mode, and set the signal mode approprietely
1006	{
1007		OSStatus err;
1008		DVCTransactionParams transaction;
1009		UInt8 out[8];
1010		UInt8 in[8];
1011
1012		out[0] = kAVCStatusInquiryCommand;
1013		out[1] = kAVCUnitAddress;
1014		out[2] = kAVCOutputPlugSignalFormatOpcode;
1015		out[3] = 0;	// Plug
1016		out[4] = out[5] = out[6] = out[7] = 0xff;
1017		transaction.commandBufferPtr = out;
1018		transaction.commandLength = sizeof(out);
1019		transaction.responseBufferPtr = in;
1020		transaction.responseBufferSize = sizeof(in);
1021		transaction.responseHandler = NULL;
1022
1023		err = doAVCTransaction(deviceDescriptionPtr, &transaction);
1024		if(err == noErr && in[0] == 0xc)
1025		{
1026			// Set the mode based on the response from this command
1027			result = DVReadSetSignalMode(deviceDescriptionPtr->fRead, in[5]);
1028		}
1029	}
1030
1031	result = DVReadAllocFrames(deviceDescriptionPtr->fRead, deviceDescriptionPtr->fNumOutputFrames,
1032        &deviceDescriptionPtr->fReadSharedVars, deviceDescriptionPtr->bufMem);
1033    if(result == noErr)
1034        result = DVReadStart(deviceDescriptionPtr->fRead);
1035    if(result == noErr) {
1036        deviceDescriptionPtr->fOldDrop = deviceDescriptionPtr->fReadSharedVars->fDroppedFrames;
1037        DVSetTimeoutTime(deviceDescriptionPtr->fGlobals->fDVThread, CFAbsoluteTimeGetCurrent() + kDCLBlockTime);
1038    }
1039
1040#ifdef kIDH_Verbose_Debug_Logging
1041	syslog(LOG_INFO, "IDH: enableRead end\n");
1042#endif
1043
1044	return result;
1045}
1046
1047static OSStatus disableRead(DeviceDescription *deviceDescriptionPtr)
1048{
1049
1050#ifdef kIDH_Verbose_Debug_Logging
1051	syslog(LOG_INFO, "IDH: disableRead begin\n");
1052#endif
1053
1054    if(deviceDescriptionPtr->fRead) {
1055        DVReadStop(deviceDescriptionPtr->fRead);
1056        DVReadFreeFrames(deviceDescriptionPtr->fRead);
1057        DVReadFree(deviceDescriptionPtr->fRead);
1058        deviceDescriptionPtr->fRead = NULL;
1059    }
1060
1061#ifdef kIDH_Verbose_Debug_Logging
1062	syslog(LOG_INFO, "IDH: disableRead end\n");
1063#endif
1064
1065	return noErr;
1066}
1067
1068static OSStatus enableWrite(DeviceDescription *deviceDescriptionPtr)
1069{
1070    OSStatus		result;
1071    int i;
1072
1073#ifdef kIDH_Verbose_Debug_Logging
1074	syslog(LOG_INFO, "IDH: enableWrite begin\n");
1075#endif
1076
1077    deviceDescriptionPtr->fNumOutputFrames = 4;
1078    deviceDescriptionPtr->fWrite = DVAllocWrite(deviceDescriptionPtr->fDevice,
1079                                                        deviceDescriptionPtr->fGlobals->fDVThread);
1080    result = DVWriteSetSignalMode(deviceDescriptionPtr->fWrite, deviceDescriptionPtr->fOutputMode);
1081    result = DVWriteAllocFrames(deviceDescriptionPtr->fWrite, deviceDescriptionPtr->fNumOutputFrames,
1082            &deviceDescriptionPtr->fWriteSharedVars, deviceDescriptionPtr->bufMem);
1083    deviceDescriptionPtr->fDCLBuffer = DVWriteGetDCLBuffer(deviceDescriptionPtr->fWrite,
1084                                                            &deviceDescriptionPtr->fSharedWriteVars);
1085    deviceDescriptionPtr->fBufSize = (deviceDescriptionPtr->fDevice->standard == ntscIn)?
1086                                    kNTSCCompressedBufferSize:kPALCompressedBufferSize;
1087    if((deviceDescriptionPtr->fOutputMode & 0x7c) == 4)
1088        deviceDescriptionPtr->fBufSize /= 2;	// SDL
1089	else if((deviceDescriptionPtr->fOutputMode & 0x7c) == 0x74)
1090        deviceDescriptionPtr->fBufSize *= 2;	// DVCPro50
1091
1092    deviceDescriptionPtr->fOldWriteTimeStamps =
1093        (UInt32 *)NewPtr(deviceDescriptionPtr->fSharedWriteVars->fNumGroups*sizeof(UInt32));
1094    for(i=0; i<deviceDescriptionPtr->fSharedWriteVars->fNumGroups; i++) {
1095        deviceDescriptionPtr->fOldWriteTimeStamps[i] = deviceDescriptionPtr->fSharedWriteVars->fTimeStampPtrs[i];
1096    }
1097    deviceDescriptionPtr->fDCLReadPos = 0;
1098    deviceDescriptionPtr->fBufWritePos = 0;
1099    deviceDescriptionPtr->fFrameBufferPos = 0;
1100    deviceDescriptionPtr->fDCLSavedWritePos = NULL;
1101    deviceDescriptionPtr->fDCLSavedPacketNum = 0;
1102
1103    deviceDescriptionPtr->fWaitingStartWrite = 1;
1104    deviceDescriptionPtr->fWriteSharedVars->fReader = deviceDescriptionPtr->fWriteSharedVars->fWriter = 0;
1105    deviceDescriptionPtr->fOldDrop = deviceDescriptionPtr->fWriteSharedVars->fDroppedFrames;
1106
1107    DVSetTimeoutTime(deviceDescriptionPtr->fGlobals->fDVThread, CFAbsoluteTimeGetCurrent() + kDCLBlockTime);
1108
1109#ifdef kIDH_Verbose_Debug_Logging
1110	syslog(LOG_INFO, "IDH: enableWrite end\n");
1111#endif
1112
1113    return result;
1114}
1115
1116static void disableWrite(DeviceDescription *deviceDescriptionPtr)
1117{
1118#ifdef kIDH_Verbose_Debug_Logging
1119	syslog(LOG_INFO, "IDH: disableWrite begin\n");
1120#endif
1121
1122	if (deviceDescriptionPtr->fWrite)
1123	{
1124		DVWriteStop(deviceDescriptionPtr->fWrite);
1125		DVWriteFreeFrames(deviceDescriptionPtr->fWrite);
1126		DVWriteFree(deviceDescriptionPtr->fWrite);
1127		deviceDescriptionPtr->fWrite = NULL;
1128		if(deviceDescriptionPtr->fOldWriteTimeStamps)
1129		{
1130			DisposePtr((Ptr)deviceDescriptionPtr->fOldWriteTimeStamps);
1131			deviceDescriptionPtr->fOldWriteTimeStamps = NULL;
1132		}
1133	}
1134	else
1135	{
1136		syslog(LOG_INFO, "IDH: disableWrite called with deviceDescriptionPtr->fWrite == NULL\n");
1137	}
1138
1139#ifdef kIDH_Verbose_Debug_Logging
1140	syslog(LOG_INFO, "IDH: disableWrite end\n");
1141#endif
1142
1143}
1144
1145static OSStatus sendMsg(IsochComponentInstancePtr ih, RequestFunc request, void *params)
1146{
1147    return DVRequest(globals.fDVThread, request, ih, (UInt32)params);
1148}
1149
1150static OSStatus doAVCTransaction(DeviceDescriptionPtr deviceDescriptionPtr,
1151                DVCTransactionParams* inTransaction)
1152{
1153    IOReturn result = kIDHErrDeviceNotConfigured;
1154    if(deviceDescriptionPtr->fConnected) {
1155        if(!deviceDescriptionPtr->fActive)
1156            return kIDHErrDeviceDisconnected;
1157        if(deviceDescriptionPtr->fNoAVC > 1)
1158            return kIOReturnTimeout;
1159        else {
1160            result = (*deviceDescriptionPtr->fDevice->fAVCInterface)->AVCCommand(deviceDescriptionPtr->fDevice->fAVCInterface,
1161                inTransaction->commandBufferPtr, inTransaction->commandLength,
1162                inTransaction->responseBufferPtr, &inTransaction->responseBufferSize);
1163
1164            if(result == kIOReturnTimeout)
1165                deviceDescriptionPtr->fNoAVC++;
1166            else
1167                deviceDescriptionPtr->fNoAVC = 0;
1168        }
1169    }
1170    return result;
1171}
1172
1173
1174static void deviceArrived(void *refcon, DVDevice *device, UInt32 index, UInt32 refound)
1175{
1176    IsochComponentGlobalsPtr g = (IsochComponentGlobalsPtr)refcon;
1177    OSStatus 			result = noErr;
1178    QTAtom 			deviceAtom, isocAtom;
1179    DeviceDescriptionPtr	deviceDescriptionPtr;
1180    IDHDeviceStatus		deviceStatus;
1181    ComponentDescription	clkDesc;
1182
1183#ifdef kIDH_Verbose_Debug_Logging
1184	syslog(LOG_INFO, "IDH: deviceArrived begin\n");
1185#endif
1186
1187    RecordEventLogger( 'isoc', 'addv', (int)g, index);
1188    //syslog(LOG_INFO,"deviceArrived: device 0x%x\n", index);
1189
1190    ++g->seed;
1191
1192    // device index is 1-based.
1193    deviceDescriptionPtr = &g->deviceDescription[index-1];
1194
1195    do {
1196        // look for existing device
1197        if( refound) {
1198            // Get device back to old state, set fActive to true after everything is restored, not before!
1199            deviceDescriptionPtr->fDevice = device;
1200            if(deviceDescriptionPtr->fConnected) {
1201                IOReturn result;
1202                result = DVDeviceOpen(g->fDVThread, deviceDescriptionPtr->fDevice);
1203                if(result == kIOReturnSuccess) {
1204                    if(deviceDescriptionPtr->readLocks) {
1205                        enableRead(deviceDescriptionPtr);
1206                    }
1207                    if(deviceDescriptionPtr->writeLocks) {
1208                        enableWrite(deviceDescriptionPtr);
1209                    }
1210                }
1211            }
1212            deviceDescriptionPtr->fActive = true;
1213        }
1214        else {
1215            Str255 cameraName;
1216
1217            bzero(deviceDescriptionPtr, sizeof(*deviceDescriptionPtr));
1218            deviceDescriptionPtr->fActive = true;
1219            deviceDescriptionPtr->fGlobals = g;
1220            deviceDescriptionPtr->fDevice = device;
1221#ifdef DRAWRINGBUFFERGRAPH
1222            deviceDescriptionPtr->fScreenBaseAddr = 0;
1223#endif
1224            RecordEventLogger( 'isoc', 'updt', 'add ', 'reg ');
1225
1226            // add its description
1227            g->nDevices++;
1228
1229            //*deviceID = ih->nDevices;
1230
1231
1232            // find clock component
1233            // wouldn't it be better for us to open an instance on OpenDevice, set FWClockPrivLocalReference, etc.
1234            clkDesc.componentType 			= clockComponentType;
1235            clkDesc.componentSubType 		= 'fwcy';
1236            clkDesc.componentManufacturer 		= 'appl';
1237            clkDesc.componentFlags 			= 0L;
1238            clkDesc.componentFlagsMask 		= 0L;
1239
1240            deviceDescriptionPtr->clock = FindNextComponent( deviceDescriptionPtr->clock, &clkDesc);	// Look for FireWire clock component
1241            FailMessage( deviceDescriptionPtr->clock == nil);
1242            // create device description atom structure
1243            result = QTNewAtomContainer( &deviceDescriptionPtr->deviceContainer);
1244            if( result != noErr)break;
1245
1246            // add a device atom
1247            result = QTInsertChild( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType,
1248                                    (long) deviceDescriptionPtr, 0, 0, nil, &deviceAtom);
1249            if( result != noErr)break;
1250
1251            // add the unique 64 bit FireWire GUID id to device atom
1252            result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHUniqueIDType,
1253                                    0, 0, sizeof(device->fGUID), &device->fGUID, nil);
1254            if( result != noErr)break;
1255
1256            result = cameraNameLookup(deviceDescriptionPtr, cameraName);
1257            if( result != noErr)break;
1258            result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHNameAtomType,
1259                                    0, 0, cameraName[0] + 1, cameraName, nil);
1260
1261            // add the IDH unique id to device atom
1262            result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHDeviceIDType,
1263                                    0, 0, sizeof(deviceDescriptionPtr), &deviceDescriptionPtr, nil);
1264            if( result != noErr)break;
1265
1266            // create a device status structure and add it to the device atom
1267            deviceStatus.version 		= 0x200;
1268            deviceStatus.physicallyConnected 	= true;
1269            deviceStatus.readEnabled 		= false;
1270            deviceStatus.writeEnabled 		= false;
1271            deviceStatus.exclusiveAccess 	= false;
1272            deviceStatus.currentBandwidth 	= 0;
1273            deviceStatus.currentChannel 	= 0;
1274            deviceStatus.inputStandard		= deviceDescriptionPtr->fDevice->standard;
1275            deviceStatus.inputFormat		= kIDHDV_SD;
1276
1277            deviceStatus.outputFormats 		= deviceDescriptionPtr->fDevice->fDVFormats;
1278            deviceStatus.deviceActive 		= false;
1279
1280            result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kDVDeviceInfo,
1281                                    0, 0, sizeof( IDHDeviceStatus), &deviceStatus, nil);
1282            if( result != noErr)break;
1283
1284            // add isoch descriptions to structure
1285            result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHIsochServiceAtomType,
1286                                    0, 0, 0, nil, &isocAtom);
1287            if( result != noErr)break;
1288
1289            // add the configs to the isoc atom
1290            result = setupVideoAtoms( deviceDescriptionPtr->deviceContainer, isocAtom,
1291                deviceDescriptionPtr->fDevice->standard, false,
1292                deviceDescriptionPtr->fDevice->fDVFormats & (1 << kIDHDVCPro_25));
1293            if( result != noErr)break;
1294            if(deviceDescriptionPtr->fDevice->fDVFormats & (1 << kIDHDV_SDL)) {
1295                result = setupVideoAtoms( deviceDescriptionPtr->deviceContainer, isocAtom,
1296                 deviceDescriptionPtr->fDevice->standard, true,
1297                 deviceDescriptionPtr->fDevice->fDVFormats & (1 << kIDHDVCPro_25));
1298                if( result != noErr)break;
1299            }
1300
1301            if( deviceDescriptionPtr->fDevice->standard == ntscIn)
1302            {
1303                    result = setup48kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom,
1304                     ntscIn);
1305                    if( result != noErr)break;
1306
1307                    result = setup32kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom,
1308                     ntscIn);
1309                    if( result != noErr)break;
1310            }
1311            else	// PAL audio
1312            {
1313                    result = setup44kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom,
1314                     deviceDescriptionPtr->fDevice->standard);
1315                    if( result != noErr)break;
1316            }
1317
1318			// Set output signal mode, default to standard DV
1319			deviceDescriptionPtr->fOutputMode = 0;
1320			if(deviceDescriptionPtr->fDevice->standard != ntscIn)
1321				deviceDescriptionPtr->fOutputMode |= 0x80;
1322		}
1323    } while(false);
1324
1325    postEvent(g, (IDHDeviceID)deviceDescriptionPtr, kIDHEventDeviceAdded);
1326
1327#ifdef kIDH_Verbose_Debug_Logging
1328	syslog(LOG_INFO, "IDH: deviceArrived end\n");
1329#endif
1330
1331}
1332
1333static UInt8 *getNextFrame(DeviceDescription *deviceDescriptionPtr, IsochComponentInstancePtr client, int slack, int waiting)
1334{
1335    ComponentResult err = noErr;
1336    IDHParameterBlock *pb;
1337
1338    pb = client->fActiveHead;
1339    if(pb && !waiting) {
1340        if(deviceDescriptionPtr->fWaitingStartWrite) {
1341            IOReturn res;
1342            res = DVWriteStart(deviceDescriptionPtr->fWrite);
1343            //if(res == kIOReturnNoResources || res == kIOReturnNoSpace || res == kIOFireWireBusReset) {
1344            if(res != kIOReturnSuccess) {
1345                //syslog(LOG_INFO, "start write returned %x\n", res);
1346                err = kIDHErrDeviceCantWrite;
1347                deviceDescriptionPtr->fWaitingStartWrite = 2;
1348            }
1349            else
1350                deviceDescriptionPtr->fWaitingStartWrite = 0;
1351        }
1352
1353        client->fActiveHead = (IDHParameterBlock *)pb->reserved1;
1354        if(client->fActiveHead == NULL)
1355            client->fActiveTail = NULL;
1356        pb->actualCount = deviceDescriptionPtr->fBufSize;
1357        pb->result = err;
1358
1359        //syslog(LOG_INFO, "write callback, buffer = %p\n", pb->buffer);
1360        //syslog(LOG_INFO, "pb %p = req %d actual %d\n",
1361        //    pb, pb->requestedCount, pb->actualCount);
1362        if(pb->completionProc) {
1363            err = pb->completionProc((IDHGenericEvent *)pb, pb->refCon);
1364            if(err != noErr) {
1365                syslog(LOG_INFO, "write callback for pb %p returned error %d\n", pb, err);
1366            }
1367        }
1368    }
1369    if(client->fActiveHead) {
1370        pb = client->fActiveHead;
1371        // We have to copy the buffer because QuickTime only uses one buffer to send data to us,
1372        // so if they drop a frame we don't have anything to send (because they are overwriting the
1373        // buffer with new data)
1374        bcopy(pb->buffer, (UInt8 *)deviceDescriptionPtr->bufMem[0], deviceDescriptionPtr->fBufSize);
1375    }
1376    else {
1377        //syslog(LOG_INFO, "Waiting for next IDHWrite, %d DCL blocks free\n", slack);
1378        if(slack < 3) {
1379            // No new frame to write, re-use the last one, after muting the audio
1380            deviceDescriptionPtr->fWriteSharedVars->fDroppedFrames++;
1381            dropMsg(deviceDescriptionPtr, deviceDescriptionPtr->fWriteSharedVars->fDroppedFrames);
1382            DVSilenceFrame(deviceDescriptionPtr->fOutputMode, (UInt8 *)deviceDescriptionPtr->bufMem[0]);
1383        }
1384        else {
1385            return NULL;	// OK to wait for next IDHWrite
1386        }
1387    }
1388    deviceDescriptionPtr->fFrameBufferPos = 0;
1389    return (UInt8 *)deviceDescriptionPtr->bufMem[0];
1390}
1391
1392static int fillDCLGroup(DeviceDescription *deviceDescriptionPtr, IsochComponentInstancePtr client, int group, int slack)
1393{
1394    UInt8 *dclPtr;
1395    UInt8 *dataPtr;
1396    UInt32 dataSize = deviceDescriptionPtr->fSharedWriteVars->fPacketDataSize;
1397    UInt32 packetSize = deviceDescriptionPtr->fSharedWriteVars->fAlignedPacketSize;
1398    int i;
1399    int start;
1400    // If we're waiting for a new frame, restore the current DCL pointer
1401	if(deviceDescriptionPtr->fDCLSavedWritePos != NULL) {
1402        dclPtr = deviceDescriptionPtr->fDCLSavedWritePos;
1403        dataPtr = getNextFrame(deviceDescriptionPtr, client, slack, true);
1404        //syslog(LOG_INFO, "Waiting for next frame, new frame = 0x%x\n", dataPtr);
1405        if(dataPtr == NULL)
1406            return 0;	// Waiting for next frame.
1407        deviceDescriptionPtr->fDCLSavedWritePos = NULL;	// Got a frame, carry on
1408        start = deviceDescriptionPtr->fDCLSavedPacketNum;
1409        deviceDescriptionPtr->fDCLSavedPacketNum = 0;
1410    }
1411    else {
1412        dclPtr = deviceDescriptionPtr->fDCLBuffer + deviceDescriptionPtr->fSharedWriteVars->fDataOffset[group];
1413        start = 0;
1414    }
1415
1416    if(deviceDescriptionPtr->fWaitingStartWrite) {
1417        if(!client->fActiveHead) {
1418            return 0;	// No data, not running yet.
1419        }
1420        else {
1421            bcopy(client->fActiveHead->buffer, (UInt8 *)deviceDescriptionPtr->bufMem[0],
1422                                        deviceDescriptionPtr->fBufSize);
1423        }
1424    }
1425    dataPtr = (UInt8 *)deviceDescriptionPtr->bufMem[0];
1426
1427    dataPtr += deviceDescriptionPtr->fFrameBufferPos;
1428
1429    for(i=start; i<deviceDescriptionPtr->fSharedWriteVars->fGroupSize; i++) {
1430        int pageOffset;
1431        // check for buffer crossing page
1432        pageOffset = (int) (dclPtr + packetSize) & 0x0fff;
1433        if (pageOffset < packetSize && pageOffset > 0) {
1434            // if it does, increment buffer pointer
1435            // and lop off page rollover to start at next page
1436            dclPtr += packetSize;
1437            dclPtr = (UInt8 *)((int)dclPtr & 0xfffff000);
1438        }
1439        bcopy(dataPtr, dclPtr+8, dataSize);
1440        dataPtr += dataSize;
1441        deviceDescriptionPtr->fFrameBufferPos += dataSize;
1442        dclPtr += packetSize;
1443
1444        if(deviceDescriptionPtr->fFrameBufferPos >= deviceDescriptionPtr->fBufSize) {
1445            dataPtr = getNextFrame(deviceDescriptionPtr, client, slack, false);
1446            if(dataPtr == NULL) {
1447                deviceDescriptionPtr->fDCLSavedWritePos = dclPtr;
1448                deviceDescriptionPtr->fDCLSavedPacketNum = i+1;
1449                return 0;	// Waiting for next frame.
1450            }
1451            deviceDescriptionPtr->fFrameBufferPos = 0;
1452            deviceDescriptionPtr->fDCLSavedWritePos = NULL;
1453            deviceDescriptionPtr->fDCLSavedPacketNum = 0;
1454        }
1455    }
1456    return 1;
1457}
1458
1459static CFAbsoluteTime processWrites(DeviceDescription *deviceDescriptionPtr)
1460{
1461    int i;
1462    int changed;
1463    int done;
1464    int emptyBlocks, ahead;
1465    int numGroups = deviceDescriptionPtr->fSharedWriteVars->fNumGroups;
1466    IsochComponentInstancePtr client;
1467    int pos;
1468    changed = 0;
1469
1470    client = deviceDescriptionPtr->fOpenClients[0];
1471
1472    // If we failed to start writing last time through, reset to try again
1473    if(deviceDescriptionPtr->fWaitingStartWrite == 2) {
1474        for(i=0; i<deviceDescriptionPtr->fSharedWriteVars->fNumGroups; i++) {
1475            deviceDescriptionPtr->fOldWriteTimeStamps[i] = deviceDescriptionPtr->fSharedWriteVars->fTimeStampPtrs[i];
1476        }
1477        //deviceDescriptionPtr->fDCLReadPos = 0;
1478        deviceDescriptionPtr->fBufWritePos = 0;
1479        deviceDescriptionPtr->fFrameBufferPos = 0;
1480        deviceDescriptionPtr->fDCLSavedWritePos = NULL;
1481        deviceDescriptionPtr->fDCLSavedPacketNum = 0;
1482        deviceDescriptionPtr->fWaitingStartWrite = 1;
1483    }
1484    // First find out where the hardware is
1485    pos = deviceDescriptionPtr->fSharedWriteVars->fDMAPos;
1486    ahead = deviceDescriptionPtr->fBufWritePos - pos;
1487    if(ahead < 0)
1488        ahead += numGroups;
1489    emptyBlocks = 4-ahead;
1490    //printf("pos %d wripos %d ahead %d\n", pos, deviceDescriptionPtr->fBufWritePos, ahead);
1491
1492    if(emptyBlocks>3)
1493        emptyBlocks = 3;
1494
1495    done = 0;
1496    for(i=0; i<emptyBlocks; i++) {
1497        int ok;
1498        ok =
1499            fillDCLGroup(deviceDescriptionPtr, client, (deviceDescriptionPtr->fBufWritePos + i) % numGroups,
1500                            ahead+done);
1501        if(!ok)
1502            break;
1503        done += ok;
1504    }
1505    deviceDescriptionPtr->fBufWritePos += done;
1506    deviceDescriptionPtr->fBufWritePos %= numGroups;
1507    return CFAbsoluteTimeGetCurrent() + kDCLBlockTime;
1508}
1509
1510static CFAbsoluteTime processReads(DeviceDescription *deviceDescriptionPtr)
1511{
1512    int doneFrames = 0;
1513    int frameIndex;
1514    IsochComponentInstancePtr client;
1515    int i;
1516    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
1517    UInt32 cycleTimeNow;
1518    SInt32 frameDiff;
1519
1520    (*deviceDescriptionPtr->fDevice->fDevInterface)->
1521        GetCycleTime(deviceDescriptionPtr->fDevice->fDevInterface, &cycleTimeNow);
1522
1523    frameIndex = deviceDescriptionPtr->fReadSharedVars->fReader % deviceDescriptionPtr->fNumOutputFrames;
1524    if(deviceDescriptionPtr->fReadSharedVars->fReader <
1525                            deviceDescriptionPtr->fReadSharedVars->fWriter) {
1526        UInt8 *buffer = deviceDescriptionPtr->bufMem[frameIndex];
1527        UInt32 frameSize = deviceDescriptionPtr->fReadSharedVars->fFrameSize[frameIndex];
1528        UInt32 frameTime = cycles(deviceDescriptionPtr->fReadSharedVars->fFrameTime[frameIndex]);
1529
1530        // Drop out if too soon
1531        //printf("Cycle now %x frame %x\n", cycles(cycleTimeNow), frameTime);
1532        frameDiff = cycles(cycleTimeNow) - frameTime;
1533        if(frameDiff < 0)
1534            frameDiff += 8000;
1535
1536        frameDiff = 200 - frameDiff;
1537        if(frameDiff > 0) {
1538            //printf("Delaying for %d cycles\n", frameDiff);
1539            return now + frameDiff/8000.0;
1540        }
1541
1542         // Lock buffer while we process stuff
1543        deviceDescriptionPtr->fBufferLocks[frameIndex]++;
1544        if(deviceDescriptionPtr->fOldDrop < deviceDescriptionPtr->fReadSharedVars->fDroppedFrames) {
1545            dropMsg(deviceDescriptionPtr, deviceDescriptionPtr->fReadSharedVars->fDroppedFrames);
1546        }
1547        for(i=0; i<kMaxDeviceClients; i++) {
1548            client = deviceDescriptionPtr->fOpenClients[i];
1549            if(client) {
1550                if(client->fClientIndex != i) {
1551                    syslog(LOG_INFO, "processReads: client %p of %p index is %d not %d\n",
1552                        client, deviceDescriptionPtr, client->fClientIndex, i);
1553                }
1554                if(deviceDescriptionPtr->fReadStage == 1) {
1555                    syslog(LOG_INFO, "client %d open, head/tail is %p/%p\n", i, client->fHead, client->fTail);
1556                }
1557                if(client->fHead) {
1558                    IDHParameterBlock *pb = client->fHead;
1559                    OSStatus err;
1560
1561                    pb->actualCount = frameSize;
1562
1563                    if(pb->buffer != nil) {
1564                        // copy frame
1565                        bcopy(buffer, pb->buffer, frameSize);
1566                    }
1567                    else {
1568                        deviceDescriptionPtr->fBufferLocks[frameIndex]++;
1569                        pb->buffer = buffer;
1570                    }
1571                    client->fHead = (IDHParameterBlock *)pb->reserved1;
1572                    pb->reserved1 = frameTime;
1573                    if(client->fHead == NULL)
1574                        client->fTail = NULL;
1575                    pb->result = noErr;
1576
1577                    //syslog(LOG_INFO, "read callback, buffer = %p\n", pb->buffer);
1578                    //syslog(LOG_INFO, "pb %p = req %d actual %d\n",
1579                    //    pb, pb->requestedCount, pb->actualCount);
1580                    {
1581#ifdef TIMING
1582                        CFAbsoluteTime cstart, cend;
1583                        cstart = CFAbsoluteTimeGetCurrent();
1584#endif
1585                        err = pb->completionProc((IDHGenericEvent *)pb, pb->refCon);
1586#ifdef TIMING
1587                        cend = CFAbsoluteTimeGetCurrent();
1588                        if(cend-cstart > 0.05)
1589                            syslog(LOG_INFO, "read callback took %8.3f to %8.3f\n", cstart, cend);
1590#endif
1591                        if(err != noErr) {
1592                            syslog(LOG_INFO, "read callback for pb %p returned error %d\n", pb, err);
1593                        }
1594                    }
1595                    doneFrames++;
1596                }
1597            }
1598        }
1599        // unlock buffer
1600        deviceDescriptionPtr->fBufferLocks[frameIndex]--;
1601        if(doneFrames && deviceDescriptionPtr->fBufferLocks[frameIndex] == 0)
1602            deviceDescriptionPtr->fReadSharedVars->fReader += 1;   // release buffer
1603    }
1604
1605    return now+kDCLBlockTime;
1606}
1607
1608static ComponentResult queueWrite(IsochComponentInstancePtr client, void *params)
1609{
1610    IDHParameterBlock *pb = (IDHParameterBlock *)params;
1611
1612    if(pb->buffer) {
1613        if(client->fActiveTail == NULL) {
1614            client->fActiveHead = pb;
1615        }
1616        else
1617            client->fActiveTail->reserved1 = (UInt32)pb;
1618        client->fActiveTail = pb;
1619    }
1620    else {
1621        if(client->fTail == NULL)
1622            client->fHead = pb;
1623        else
1624            client->fTail->reserved1 = (UInt32)pb;
1625        client->fTail = pb;
1626    }
1627    pb->reserved1 = 0;
1628    return noErr;
1629}
1630
1631static ComponentResult queueRead(IsochComponentInstancePtr client, void *params)
1632{
1633    IDHParameterBlock *pbNew = (IDHParameterBlock *)params;
1634    if(client->fTail == NULL)
1635        client->fHead = pbNew;
1636    else
1637        client->fTail->reserved1 = (UInt32)pbNew;
1638    client->fTail = pbNew;
1639    pbNew->reserved1 = 0;
1640
1641    return noErr;
1642}
1643
1644ComponentResult processOpen(IsochComponentInstancePtr ih, void *params)
1645{
1646    UInt32 permissions = (UInt32)params;
1647    ComponentResult result = noErr;
1648    int i;
1649
1650    DeviceDescription *deviceDescriptionPtr;
1651    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);	// find the device
1652    FailWithVal( result != noErr, Exit, result);
1653
1654    FailWithAction( deviceDescriptionPtr->fActive == false, result = kIDHErrDeviceDisconnected, Exit);
1655
1656    // trying to reopen for read or write?
1657    if( ih->permissions & kIDHOpenForReadTransactions && permissions & kIDHOpenForReadTransactions)
1658            goto Exit;	// don't do anything
1659
1660    if( ih->permissions & kIDHOpenForWriteTransactions && permissions & kIDHOpenForWriteTransactions)
1661            goto Exit;	// don't do anything
1662
1663    // check for switching directions before opening
1664    FailWithAction( ih->permissions & kIDHOpenForReadTransactions && permissions & kIDHOpenForWriteTransactions,
1665            result = kIDHErrDeviceInUse, Exit);
1666
1667    FailWithAction( ih->permissions & kIDHOpenForWriteTransactions && permissions & kIDHOpenForReadTransactions,
1668            result = kIDHErrDeviceInUse, Exit);
1669
1670    // if user is opening for read, make sure device isn't already opened for writes
1671    if( permissions & kIDHOpenForReadTransactions)
1672    {
1673        FailWithAction( deviceDescriptionPtr->writeLocks, result = kIDHErrDeviceInUse, Exit);
1674
1675        if( deviceDescriptionPtr->readLocks == 0)
1676        {
1677            result = enableRead(deviceDescriptionPtr);
1678            FailWithVal( result != noErr, Exit, result);
1679        }
1680
1681        ++deviceDescriptionPtr->readLocks;	// keep track of read count
1682        //syslog(LOG_INFO, "ih %p dev %p Opened for read, count %d\n",
1683        //    ih, deviceDescriptionPtr, deviceDescriptionPtr->readLocks);
1684        RecordEventLogger( 'open', ' Now', ih, deviceDescriptionPtr->readLocks);
1685    }
1686
1687    // if user is opening for write, make sure device isn't already opened
1688    if( permissions & kIDHOpenForWriteTransactions)
1689    {
1690        FailWithAction( deviceDescriptionPtr->readLocks || deviceDescriptionPtr->writeLocks,
1691                        result = kIDHErrDeviceInUse, Exit);
1692
1693        result = enableWrite(deviceDescriptionPtr);
1694        FailWithVal( result != noErr, Exit, result);
1695
1696        deviceDescriptionPtr->writeLocks = 1;	// keep track of write count
1697    }
1698
1699//        if( permissions & kIDHOpenWithExclusiveAccess)
1700//                deviceDescriptionPtr->exclusiveAccess = true;
1701
1702    ih->permissions = permissions;	// save the permissions
1703    // Setup device->component pointer
1704    for(i=0; i<kMaxDeviceClients; i++) {
1705        if(!deviceDescriptionPtr->fOpenClients[i]) {
1706            deviceDescriptionPtr->fOpenClients[i] = ih;
1707            ih->fClientIndex = i;
1708            break;
1709        }
1710    }
1711
1712Exit:
1713    return result;
1714}
1715
1716static ComponentResult processClose(IsochComponentInstancePtr ih, void *junk)
1717{
1718    ComponentResult result = noErr;
1719    DeviceDescription *deviceDescriptionPtr;
1720
1721#ifdef kIDH_Verbose_Debug_Logging
1722	syslog(LOG_INFO, "IDH: processClose begin\n");
1723#endif
1724
1725    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);	// find the device
1726    FailWithVal( result != noErr, Exit, result);
1727    if( ih->permissions & kIDHOpenForReadTransactions)	// tear down read
1728    {
1729        //syslog(LOG_INFO, "ih %p dev %p Closing from read, count %d\n",
1730        //    ih, deviceDescriptionPtr, deviceDescriptionPtr->readLocks);
1731        if( --deviceDescriptionPtr->readLocks <= 0)	// is device completely freed by clients?
1732        {
1733            if(deviceDescriptionPtr->fActive)
1734                disableRead(deviceDescriptionPtr);
1735            //    volatile int *fWriter,*fReader,*fDrop,*fStatus;
1736
1737            //if(deviceDescriptionPtr->fSharedVars) {
1738                // printf("fWriter: %ld", deviceDescriptionPtr->fSharedVars->fWriter);
1739                //  printf(" fReader: %ld", deviceDescriptionPtr->fSharedVars->fReader);
1740                //  printf(" fDrop: %ld", deviceDescriptionPtr->fSharedVars->fDroppedFrames);
1741                //  printf(" fStatus: %ld", deviceDescriptionPtr->fSharedVars->fStatus);
1742                //  printf("\n");
1743            //}
1744
1745            //deviceDescriptionPtr->exclusiveAccess = false;
1746        }
1747    }
1748
1749    if( ih->permissions & kIDHOpenForWriteTransactions) // tear down write
1750    {
1751        if( --deviceDescriptionPtr->writeLocks <= 0)	// is device completely freed by clients?
1752        {
1753            if(deviceDescriptionPtr->fActive)
1754                disableWrite(deviceDescriptionPtr);
1755            //if(deviceDescriptionPtr->fSharedVars) {
1756            //      printf("fWriter: %ld", deviceDescriptionPtr->fSharedVars->fWriter);
1757            //     printf(" fReader: %ld", deviceDescriptionPtr->fSharedVars->fReader);
1758            //      printf(" fDrop: %ld", deviceDescriptionPtr->fSharedVars->fDroppedFrames);
1759            //       printf(" fStatus: %ld", deviceDescriptionPtr->fSharedVars->fStatus);
1760            //       printf("\n");
1761            //}
1762
1763            //deviceDescriptionPtr->exclusiveAccess = false;
1764        }
1765    }
1766
1767    deviceDescriptionPtr->fOpenClients[ih->fClientIndex] = nil;
1768Exit:
1769
1770#ifdef kIDH_Verbose_Debug_Logging
1771syslog(LOG_INFO, "IDH: processClose end\n");
1772#endif
1773
1774return result;
1775
1776}
1777
1778static ComponentResult processCancelPendingIO(IsochComponentInstancePtr client, void *params)
1779{
1780    while(client->fHead) {
1781        IDHParameterBlock *pb = client->fHead;
1782        //syslog(LOG_INFO, "Cancelling IO %p, buffer = %p\n", pb, pb->buffer);
1783
1784        client->fHead = (IDHParameterBlock *)pb->reserved1;
1785        pb->reserved1 = NULL;
1786    }
1787    client->fTail = NULL;
1788
1789    return noErr;
1790}
1791
1792#if TIMING
1793/* raw read of the timebase register */
1794static void clock_get_uptime( register AbsoluteTime *result)
1795{
1796#ifdef __ppc__
1797
1798        register UInt32  hic;
1799        do {
1800	  asm volatile("  mftbu %0" : "=r" (result->hi));
1801	  asm volatile("  mftb  %0" : "=r" (result->lo));
1802	  asm volatile("  mftbu %0" : "=r" (hic));
1803        } while (hic != result->hi);
1804
1805#else
1806        result->lo = 0;
1807        result->hi = 0;
1808#endif /* __ppc__ */
1809
1810}
1811#endif
1812
1813static void timerTick(CFRunLoopTimerRef timer, void *info)
1814{
1815    IsochComponentGlobalsPtr g = (IsochComponentGlobalsPtr)info;
1816    int dev;
1817    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
1818    CFAbsoluteTime fireDate = now + 100.0;
1819#ifdef TIMING
1820    if(now > g->fDVThread->requestTimeoutTime + .03) {
1821        pKGSysCall_Insert (kIOFWDVTrace, 'late', (UInt32)((now-g->fDVThread->requestTimeoutTime)*1000), 0, 0, 0, 0);
1822        syslog(LOG_INFO, "Late timer tick, @ %8.3f, wanted %8.3f\n", now, g->fDVThread->requestTimeoutTime);
1823        DVDumpLog(g->fDVThread);
1824    }
1825#endif
1826    for(dev = 0; dev<g->nDevices; dev++) {
1827        DeviceDescription *deviceDescriptionPtr;
1828        deviceDescriptionPtr = &g->deviceDescription[dev];
1829
1830        // Process I/O queues
1831        if(deviceDescriptionPtr && deviceDescriptionPtr->fActive) {
1832#if TIMING
1833            clock_get_uptime(&timestamp1);
1834#endif
1835            if(deviceDescriptionPtr->fRead) {
1836                fireDate = CFAbsoluteTimeGetCurrent() + kDCLBlockTime;
1837            }
1838
1839            if(deviceDescriptionPtr->writeLocks) {
1840                CFAbsoluteTime writeDate;
1841                writeDate = processWrites(deviceDescriptionPtr);
1842                if(writeDate < fireDate)
1843                    fireDate = writeDate;
1844            }
1845            if(deviceDescriptionPtr->readLocks) {
1846                CFAbsoluteTime readDate;
1847                readDate = processReads(deviceDescriptionPtr);
1848                if(readDate < fireDate)
1849                    fireDate = readDate;
1850            }
1851#if TIMING
1852            clock_get_uptime(&timestamp2);
1853            start = (((unsigned long long)timestamp1.hi) << 32) |
1854                    (unsigned long long)((unsigned int)(timestamp1.lo));
1855
1856            stop = (((unsigned long long)timestamp2.hi) << 32) |
1857                    (unsigned long long)((unsigned int)(timestamp2.lo));
1858
1859            elapsed_msecs = (int)(((double)(stop - start)) / divisor);
1860            if(elapsed_msecs > worst_callback) {
1861                pKGSysCall_Insert (kIOFWDVTrace, 'call', elapsed_msecs, 0, 0, 0, 0);
1862                syslog(LOG_INFO, "callback delay %d mSec\n",
1863                        elapsed_msecs);
1864                worst_callback = elapsed_msecs;
1865            }
1866#endif
1867        }
1868    }
1869    DVSetTimeoutTime(g->fDVThread, fireDate);
1870#if TIMING
1871    DVLog(g->fDVThread, 'timr', now, CFAbsoluteTimeGetCurrent());
1872#endif
1873}
1874
1875/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1876
1877static pascal ComponentResult
1878FWDVComponentOpen(IsochComponentInstancePtr storage, ComponentInstance self)
1879{
1880    IsochComponentGlobalsPtr g = &globals;
1881
1882#ifdef kIDH_Verbose_Debug_Logging
1883	syslog(LOG_INFO, "IDH: FWDVComponentOpen begin\n");
1884#endif
1885
1886    RecordEventLogger( 'isoc', 'open', g->fNumInstances, 0);
1887    if( nil == (storage = (IsochComponentInstancePtr)NewPtrClear(sizeof(IsochComponentInstance))))
1888        return(MemError());
1889
1890    RecordEventLogger( 'isoc', 'ope2', (int)storage, 0);
1891    //syslog(LOG_INFO, "%x: FWDVComponentOpen count %d\n", pthread_self(), g->fNumInstances);
1892
1893    SetComponentInstanceStorage(self, (Handle) storage);
1894
1895    // One-time initialization of globals
1896    if (!g->fDVThread) {
1897        g->fDVThread = DVCreateThread(deviceArrived, g, timerTick, g, deviceMessage);
1898        if (!g->fDVThread)
1899            return(MemError());
1900        g->nDevices=0;
1901        DVRunThread(g->fDVThread);
1902    }
1903
1904    g->fNumInstances++;
1905
1906#ifdef kIDH_Verbose_Debug_Logging
1907	syslog(LOG_INFO, "IDH: FWDVComponentOpen fNumInstances: %d\n",g->fNumInstances);
1908#endif
1909
1910#ifdef kIDH_Verbose_Debug_Logging
1911	syslog(LOG_INFO, "IDH: FWDVComponentOpen end\n");
1912#endif
1913
1914    return(noErr);
1915}
1916
1917/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1918
1919static pascal ComponentResult
1920FWDVComponentClose(IsochComponentInstancePtr ih, ComponentInstance self)
1921{
1922    int i;
1923    IsochComponentGlobalsPtr g = &globals;
1924
1925#ifdef kIDH_Verbose_Debug_Logging
1926	syslog(LOG_INFO, "IDH: FWDVComponentClose begin\n");
1927#endif
1928
1929    RecordEventLogger( 'isoc', 'clos', ih, self);
1930    if( !ih)
1931        return( noErr );
1932
1933    if(ih->hasDeviceControl) {
1934        DeviceDescriptionPtr deviceDescriptionPtr;
1935        if(findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr) == noErr)
1936        	closeDeviceControl( ih, deviceDescriptionPtr);
1937    }
1938
1939    if( ih->permissions )
1940        FWDVIDHCloseDevice(ih);
1941
1942    //syslog(LOG_INFO, "%x: FWDVComponentClose count %d\n", pthread_self(), g->fNumInstances);
1943    g->fNumInstances--;
1944
1945#ifdef kIDH_Verbose_Debug_Logging
1946	syslog(LOG_INFO, "IDH: FWDVComponentClose fNumInstances: %d\n",g->fNumInstances);
1947#endif
1948
1949    if(g->fNumInstances == 0) {
1950
1951        // Free all mach ports etc.
1952        for(i=0; i<g->nDevices; i++) {
1953            DeviceDescriptionPtr dev = &g->deviceDescription[i];
1954            dev->fConnected = 0;
1955            if(dev->fDevice) {
1956                DVDeviceTerminate(dev->fDevice);
1957                dev->fDevice = NULL;
1958            }
1959            if(dev->deviceContainer) {
1960                QTDisposeAtomContainer(dev->deviceContainer);
1961                dev->deviceContainer = NULL;
1962            }
1963        }
1964        if(g->fDVThread) {
1965            //syslog(LOG_INFO, "%x: Calling DVFreeThread\n", pthread_self());
1966            DVFreeThread(g->fDVThread);
1967            g->fDVThread = NULL;
1968        }
1969    }
1970
1971    DisposePtr((Ptr) ih);
1972
1973    SetComponentInstanceStorage(self, (Handle) nil );
1974    RecordEventLogger( 'isoc', 'clos', 'end ', 0);
1975
1976#ifdef kIDH_Verbose_Debug_Logging
1977	syslog(LOG_INFO, "IDH: FWDVComponentClose end\n");
1978#endif
1979
1980	return( noErr );
1981}
1982
1983/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1984
1985static pascal ComponentResult
1986FWDVComponentVersion(IsochComponentInstancePtr storage)
1987{
1988    RecordEventLogger( 'isoc', 'vers', 0, 0);
1989    return (DVVersion << 16) | DVRevision;
1990}
1991
1992static pascal ComponentResult
1993FWDVComponentRegister(IsochComponentInstancePtr storage)
1994{
1995    // need to re-register with each source type?
1996    RecordEventLogger( 'isoc', 'reg ', 0, 0);
1997    return( noErr );
1998}
1999
2000/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001static pascal ComponentResult
2002FWDVIDHGetDeviceList(IsochComponentInstancePtr storage,
2003                     QTAtomContainer *deviceList )
2004{
2005    OSStatus 		result = noErr;
2006    QTAtomContainer	container = nil;
2007    int			devIndex;
2008    UInt32		version;
2009    IsochComponentGlobalsPtr g = &globals;
2010
2011#ifdef kIDH_Verbose_Debug_Logging
2012	syslog(LOG_INFO, "IDH: FWDVIDHGetDeviceList begin\n");
2013#endif
2014
2015    RecordEventLogger( 'isoc', 'get ', 'dev ', 'list');
2016    do {
2017        // create device atom list now
2018        result = QTNewAtomContainer( &container);
2019        if(result != noErr)
2020            break;
2021
2022        // save seed
2023        result = QTInsertChild( container, kParentAtomIsContainer, kIDHSeedAtomType, 0, 0,
2024                                sizeof( g->seed), &g->seed, nil);
2025        if(result != noErr)
2026            break;
2027
2028        version = (DVVersion << 24) | (DVRevision << 16) | DVBuildNumber;
2029
2030        // save isoch version
2031        result = QTInsertChild( container, kParentAtomIsContainer, kIDHIsochVersionAtomType, 0, 0,
2032                                sizeof( UInt32), &version, nil);
2033        if(result != noErr)
2034            break;
2035
2036        // save useCMP value
2037        result = QTInsertChild( container, kParentAtomIsContainer, kIDHUseCMPAtomType, 0, 0,
2038                                sizeof( UInt32), &g->useCMP, nil);
2039        if(result != noErr)
2040            break;
2041
2042        // save each active device
2043        for( devIndex=0; devIndex<kDVMaxDevicesActive; ++devIndex)
2044        {
2045            if( g->deviceDescription[devIndex].fDevice != 0 && g->deviceDescription[devIndex].fActive)
2046            {
2047                result = QTInsertChildren( container, kParentAtomIsContainer,
2048                                                  g->deviceDescription[devIndex].deviceContainer);
2049                if(result != noErr)
2050                    break;
2051            }
2052        }
2053
2054        *deviceList = container;
2055        return noErr;
2056    } while (false);
2057
2058    if(container) {
2059        QTRemoveChildren( container, kParentAtomIsContainer);
2060        QTDisposeAtomContainer( container);
2061    }
2062
2063#ifdef kIDH_Verbose_Debug_Logging
2064	syslog(LOG_INFO, "IDH: FWDVIDHGetDeviceList end\n");
2065#endif
2066
2067	return result;
2068}
2069
2070static pascal ComponentResult
2071FWDVIDHSetDeviceConfiguration(IsochComponentInstancePtr ih,
2072                              const QTAtomSpec	*configID)
2073{
2074    OSStatus 				result = noErr;
2075    QTAtomSpec			volatileAtomSpec;
2076    QTAtom				nameAtom;
2077    IDHDeviceID			previousDeviceID;
2078    DeviceDescription	*deviceDescriptionPtr;
2079    IsochComponentGlobalsPtr g = &globals;
2080    Boolean				isSDL;
2081
2082#ifdef kIDH_Verbose_Debug_Logging
2083	syslog(LOG_INFO, "IDH: FWDVIDHSetDeviceConfiguration begin\n");
2084#endif
2085
2086    RecordEventLogger( 'isoc', 'set ', 'conf', ih);
2087
2088    FailWithAction( configID == nil, result = paramErr, Exit);
2089
2090    FailWithAction( configID->container == nil, result = paramErr, Exit);
2091
2092    // if the client is setting to the same config, then we are ok
2093    if( configID->container == ih->currentConfig.container &&
2094            configID->atom == ih->currentConfig.atom)
2095        goto Exit;
2096
2097    // device already in use, please close device first
2098    FailWithAction( ih->permissions != 0, result = kIDHErrDeviceInUse, Exit);
2099
2100    previousDeviceID = ih->deviceID;
2101
2102    volatileAtomSpec = *configID;
2103    result = getDeviceID( &volatileAtomSpec, &ih->deviceID);
2104    FailWithVal( result != noErr, Exit, result);
2105
2106    result = checkSeed( g, &volatileAtomSpec);
2107    FailWithVal( result != noErr, Exit, result);
2108
2109    ih->currentConfig = *configID;
2110
2111    nameAtom = QTFindChildByIndex( configID->container, configID->atom, kIDHNameAtomType, 1, nil);
2112    if( nameAtom != nil) {
2113        Str255 name;
2114        long size;
2115        QTCopyAtomDataToPtr( configID->container, nameAtom, true, 255, name, &size);
2116        isSDL = !strncmp(name, "\pDV-SDL", *name);
2117    }
2118    else
2119        isSDL = false;
2120
2121    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
2122    FailWithVal( result != noErr, Exit, result);
2123
2124    // Open device
2125    if(deviceDescriptionPtr->fDevice->fDevInterface == NULL) {
2126        result = DVDeviceOpen(g->fDVThread, deviceDescriptionPtr->fDevice);
2127        if (result != kIOReturnSuccess) {
2128            goto Exit;
2129        }
2130        deviceDescriptionPtr->fConnected = 1;
2131    }
2132    else
2133        deviceDescriptionPtr->fConnected++;
2134
2135    FailWithAction( deviceDescriptionPtr->fActive == false, result = kIDHErrDeviceDisconnected, Exit);
2136
2137    // if this client had a previous connection, close that and if it had device control,
2138    // close that too.
2139    if( previousDeviceID && previousDeviceID != ih->deviceID) {
2140        DeviceDescription *deviceDescriptionPtr2;
2141
2142        result = findDeviceDescriptionforDevice( ih, previousDeviceID, &deviceDescriptionPtr2);
2143        FailWithVal( result != noErr, Exit, result);
2144        if(deviceDescriptionPtr2->fConnected) {
2145            deviceDescriptionPtr2->fConnected--;
2146            // Close device if nobody else has it open and it hasn't been unplugged already
2147            if(deviceDescriptionPtr2->fConnected == 0 && deviceDescriptionPtr2->fActive &&
2148                deviceDescriptionPtr2->fDevice->fDevInterface) {
2149                DVDeviceClose(deviceDescriptionPtr2->fDevice);
2150            }
2151        }
2152        if(ih->hasDeviceControl) {
2153                result = closeDeviceControl( ih, deviceDescriptionPtr2);
2154                FailMessage( result != noErr);
2155
2156                ih->hasDeviceControl = false;
2157        }
2158    }
2159
2160Exit:
2161    RecordEventLogger( 'isoc', 'set ', 'Exit', ih);
2162
2163#ifdef kIDH_Verbose_Debug_Logging
2164	syslog(LOG_INFO, "IDH: FWDVIDHSetDeviceConfiguration end\n");
2165#endif
2166
2167    return result;
2168}
2169
2170static pascal ComponentResult
2171FWDVIDHOpenDevice(IsochComponentInstancePtr ih, UInt32 permissions)
2172{
2173    ComponentResult result = noErr;
2174    IsochComponentGlobalsPtr g = &globals;
2175
2176#ifdef kIDH_Verbose_Debug_Logging
2177	syslog(LOG_INFO, "IDH: FWDVIDHOpenDevice begin\n");
2178#endif
2179
2180    RecordEventLogger( 'open', ' dev', ih, permissions);
2181
2182    FailWithAction( permissions == 0, result = paramErr, Exit);
2183
2184    FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2185
2186	{
2187		DeviceDescription* description ;
2188		FailWithAction( noErr != findDeviceDescriptionforDevice( ih, ih->deviceID, & description ), result = kIDHErrDeviceNotConfigured, Exit ) ;
2189
2190		FailWithAction( description == nil, result = kIDHErrDeviceNotConfigured, Exit ) ;
2191		FailWithAction( description->fDevice == nil, result = kIDHErrDeviceNotConfigured, Exit ) ;
2192		FailWithAction( description->fDevice->fDevInterface == nil, result = kIDHErrDeviceNotConfigured, Exit ) ;
2193		FailWithAction( description->fDevice->fAVCInterface == nil, result = kIDHErrDeviceNotConfigured, Exit ) ;
2194	}
2195
2196    result = sendMsg(ih, processOpen, (void *)permissions);
2197
2198    FailWithVal( result != noErr, Exit, result);
2199    result = postEvent( g, ih->deviceID,
2200            (permissions & kIDHOpenForReadTransactions)?kIDHEventReadEnabled:kIDHEventWriteEnabled);
2201    FailWithVal( result != noErr, Exit, result);
2202#ifdef DRAWRINGBUFFERGRAPH
2203	SetUpBlitGlobals((DeviceDescription	*)ih->deviceID);
2204#endif
2205
2206Exit:
2207
2208#ifdef kIDH_Verbose_Debug_Logging
2209		syslog(LOG_INFO, "IDH: FWDVIDHOpenDevice end\n");
2210#endif
2211
2212	return result;
2213}
2214
2215static pascal ComponentResult
2216FWDVIDHCloseDevice(IsochComponentInstancePtr ih)
2217{
2218    OSStatus 			result = noErr;
2219    IsochComponentGlobalsPtr g = &globals;
2220
2221#ifdef kIDH_Verbose_Debug_Logging
2222	syslog(LOG_INFO, "IDH: FWDVIDHCloseDevice begin\n");
2223#endif
2224
2225    RecordEventLogger( 'isoc', 'clos', ' dev', ih);
2226
2227    FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2228
2229    if( ih->permissions == 0)	// client has no open devices?
2230            goto Exit;
2231
2232    //syslog(LOG_INFO, "%x: FWDVIDHCloseDevice\n", pthread_self());
2233    result = sendMsg(ih, processClose, 0);
2234    FailWithVal( result != noErr, Exit, result);
2235    result = postEvent( g, ih->deviceID,
2236            (ih->permissions & kIDHOpenForReadTransactions)?kIDHEventReadDisabled:kIDHEventWriteDisabled);
2237    FailWithVal( result != noErr, Exit, result);
2238
2239Exit:
2240    ih->permissions = 0;	// make sure device is closed
2241    ih->fClientIndex = 0xdead;
2242
2243#ifdef kIDH_Verbose_Debug_Logging
2244	syslog(LOG_INFO, "IDH: FWDVIDHCloseDevice end\n");
2245#endif
2246
2247    return result;
2248}
2249
2250//��� USER BETTER KEEP HIS DEVICE LIST AROUND IF THIS IS TO MEAN ANYTHING
2251static pascal ComponentResult
2252FWDVIDHGetDeviceConfiguration(IsochComponentInstancePtr ih, QTAtomSpec *configID )
2253{
2254    OSStatus 	result = noErr;
2255
2256#ifdef kIDH_Verbose_Debug_Logging
2257	syslog(LOG_INFO, "IDH: FWDVIDHGetDeviceConfiguration begin\n");
2258#endif
2259
2260    RecordEventLogger( 'isoc', 'get ', 'dev ', 'conf');
2261
2262    FailWithAction( configID == nil, result = paramErr, Exit);
2263    FailWithAction( ih->currentConfig.container == nil || ih->currentConfig.atom == nil,
2264            result = kIDHErrDeviceNotConfigured, Exit);
2265
2266    *configID = ih->currentConfig;
2267
2268Exit:
2269
2270#ifdef kIDH_Verbose_Debug_Logging
2271		syslog(LOG_INFO, "IDH: FWDVIDHGetDeviceConfiguration end\n");
2272#endif
2273
2274	return result;
2275}
2276
2277static pascal ComponentResult
2278FWDVIDHGetDeviceStatus(IsochComponentInstancePtr ih, const QTAtomSpec *devSpec, IDHDeviceStatus *status )
2279{
2280        OSStatus 			result = noErr;
2281        IDHDeviceID		deviceID = nil;
2282        QTAtom			deviceInfoAtom, deviceAtom;
2283        QTAtomSpec		volatileAtomSpec;
2284        DeviceDescription	*deviceDescriptionPtr;
2285        IsochComponentGlobalsPtr g = &globals;
2286        UInt8			inputFormat = kIDHDV_SD;
2287
2288#ifdef kIDH_Verbose_Debug_Logging
2289		syslog(LOG_INFO, "IDH: FWDVIDHGetDeviceStatus begin\n");
2290#endif
2291
2292		RecordEventLogger( 'isoc', 'get ', 'stat', ih);
2293        FailWithAction( devSpec == nil, result = paramErr, Exit);
2294        FailWithAction( status == nil, result = paramErr, Exit);
2295
2296        volatileAtomSpec = *devSpec;
2297
2298        result = checkSeed( g, &volatileAtomSpec);
2299        if( result != noErr)
2300                goto Exit;
2301
2302        result = getDeviceID( &volatileAtomSpec, &deviceID);
2303        FailWithVal( result != noErr, Exit, result);
2304
2305        result = findDeviceDescriptionforDevice( ih, deviceID, &deviceDescriptionPtr);	// find description for this device
2306        FailWithVal( result != noErr, Exit, result);
2307
2308        deviceAtom = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType, 1, nil);
2309        FailWithAction( deviceAtom == nil, result = kIDHErrDeviceList, Exit);
2310
2311        // find device status for this device
2312        deviceInfoAtom = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, deviceAtom, kDVDeviceInfo, 1, nil);
2313        FailWithAction( deviceInfoAtom == nil, result = kIDHErrDeviceList, Exit);
2314
2315        // Ask device what it's currently configured to transmit
2316        // Need to ask info for plug 0 for Panasonic AJ250, which always says 'DV' for kAVCOutputSignalModeOpcode,
2317        // even when sending DVCPro25.
2318#if 1
2319        {
2320            OSStatus err;
2321            DVCTransactionParams transaction;
2322            UInt8 out[8];
2323            UInt8 in[8];
2324
2325            out[0] = kAVCStatusInquiryCommand;
2326            out[1] = kAVCUnitAddress;
2327            out[2] = kAVCOutputPlugSignalFormatOpcode;
2328            out[3] = 0;	// Plug
2329            out[4] = out[5] = out[6] = out[7] = 0xff;
2330            transaction.commandBufferPtr = out;
2331            transaction.commandLength = sizeof(out);
2332            transaction.responseBufferPtr = in;
2333            transaction.responseBufferSize = sizeof(in);
2334            transaction.responseHandler = NULL;
2335
2336            err = doAVCTransaction(deviceDescriptionPtr, &transaction);
2337            if(err == noErr && in[0] == 0xc) {
2338                inputFormat = (in[5] >> 2) & 0x1f; // Fish out STYPE field
2339            }
2340        }
2341#else
2342        {
2343            OSStatus err;
2344            DVCTransactionParams transaction;
2345            UInt8 out[4];
2346            UInt8 in[4];
2347
2348            out[0] = kAVCStatusInquiryCommand;
2349            out[1] = IOAVCAddress(kAVCTapeRecorder, 0);
2350            out[2] = kAVCOutputSignalModeOpcode;
2351            out[3] = kAVCSignalModeDummyOperand;
2352
2353            transaction.commandBufferPtr = out;
2354            transaction.commandLength = sizeof(out);
2355            transaction.responseBufferPtr = in;
2356            transaction.responseBufferSize = sizeof(in);
2357            transaction.responseHandler = NULL;
2358
2359            err = doAVCTransaction(deviceDescriptionPtr, &transaction);
2360            if(err == noErr && in[0] == 0xc) {
2361                inputFormat = (in[3] >> 2) & 0x1f; // Fish out STYPE field
2362            }
2363        }
2364#endif
2365        //status->version = 				0x200;
2366        status->physicallyConnected =	true;
2367        status->readEnabled = 			deviceDescriptionPtr->readLocks;
2368        status->writeEnabled = 			deviceDescriptionPtr->writeLocks;
2369        status->exclusiveAccess = 		0;//deviceDescriptionPtr->exclusiveAccess;
2370        status->currentBandwidth = 		0;
2371        status->currentChannel = 		0;
2372
2373        //��� need to make this work with camera tracking
2374        status->deviceActive = 			deviceDescriptionPtr->fActive;
2375        status->inputFormat =			inputFormat;
2376        if(deviceDescriptionPtr->fActive) {
2377            status->inputStandard =			deviceDescriptionPtr->fDevice->standard;
2378
2379            // Does caller want extended status?
2380            if(status->version == 0x200)
2381                status->outputFormats = 	deviceDescriptionPtr->fDevice->fDVFormats;
2382        }
2383// JKL *** what to to with this? does this mean deviceID, cameraFWClientID, or localNodeFWClientID
2384// Think this is for clock to set the localFWReferenceID
2385        status->localNodeID	= 		(PsuedoID) deviceDescriptionPtr->fDevice;
2386
2387        result = QTSetAtomData( deviceDescriptionPtr->deviceContainer, deviceInfoAtom, sizeof( IDHDeviceStatus), status);
2388        FailWithVal( result != noErr, Exit, result);
2389
2390Exit:
2391
2392#ifdef kIDH_Verbose_Debug_Logging
2393			syslog(LOG_INFO, "IDH: FWDVIDHGetDeviceStatus end\n");
2394#endif
2395
2396        return result;
2397}
2398
2399static pascal ComponentResult
2400FWDVIDHGetDeviceClock(IsochComponentInstancePtr ih, Component *clock )
2401{
2402    DeviceDescription	*deviceDescriptionPtr;
2403    OSStatus 		result = noErr;
2404
2405    RecordEventLogger( 'isoc', 'get ', 'clok', 0);
2406
2407    FailWithAction( clock == nil, result = paramErr, Exit);
2408
2409    FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2410
2411    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
2412    FailWithVal( result != noErr, Exit, result);
2413
2414//	FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit);
2415
2416    *clock = deviceDescriptionPtr->clock;
2417
2418Exit:
2419    return result;
2420}
2421
2422// can be called synchronously at task level only
2423static pascal ComponentResult
2424FWDVIDHRead(IsochComponentInstancePtr ih, IDHParameterBlock *pb)
2425{
2426        OSStatus 			result = noErr;
2427        DeviceDescription	*deviceDescriptionPtr;
2428
2429        RecordEventLogger( 'isoc', 'read', (unsigned long) ih, (unsigned long) pb );
2430
2431        //syslog(LOG_INFO, "FWDVIDHRead, completion = %p buffer = %p\n", pb->completionProc, pb->buffer);
2432        //syslog(LOG_INFO, "pb %p = req %d actual %d, result %d\n",
2433        //    pb, pb->requestedCount, pb->actualCount, pb->result);
2434
2435        FailWithAction( pb == nil, result = paramErr, Exit);
2436
2437        // can't do sync reads in I/O thread
2438        //FailWithAction( pb->completionProc == nil && CurrentExecutionLevel() != kTaskLevel, result = paramErr, Exit);
2439
2440        FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2441
2442        FailWithAction( !(ih->permissions & kIDHOpenForReadTransactions), result = kIDHErrDeviceNotOpened, Exit);
2443
2444        result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
2445        FailWithVal( result != noErr, Exit, result);
2446
2447        FailWithAction( deviceDescriptionPtr->fActive == false, result = kIDHErrDeviceDisconnected, Exit);
2448
2449        if( pb->completionProc == nil) // synchronous read
2450        {
2451            int frameIndex = deviceDescriptionPtr->fReadSharedVars->fReader % deviceDescriptionPtr->fNumOutputFrames;
2452            UInt8 *buffer = (UInt8 *)deviceDescriptionPtr->bufMem[frameIndex];
2453            UInt32 frameSize;
2454
2455            // wait for writer
2456            // if (*devices[refNum].fReader + 1 >= *devices[refNum].fWriter) return -1;
2457            if( deviceDescriptionPtr->fOldDrop <
2458                deviceDescriptionPtr->fReadSharedVars->fDroppedFrames) {
2459                    dropMsg(deviceDescriptionPtr, deviceDescriptionPtr->fReadSharedVars->fDroppedFrames);
2460            }
2461
2462            while (deviceDescriptionPtr->fReadSharedVars->fReader >= deviceDescriptionPtr->fReadSharedVars->fWriter)
2463            {
2464                usleep(12500);	// time DCL block takes to run
2465            }
2466            frameSize = deviceDescriptionPtr->fReadSharedVars->fFrameSize[frameIndex];
2467            pb->actualCount = frameSize;
2468            pb->reserved1 = cycles(deviceDescriptionPtr->fReadSharedVars->fFrameTime[frameIndex]);
2469            if(pb->buffer != nil) {
2470                // copy frame
2471                bcopy(buffer, pb->buffer, frameSize);
2472                deviceDescriptionPtr->fReadSharedVars->fReader += 1;   // release buffer
2473            }
2474            else
2475                pb->buffer = buffer;
2476            pb->result = noErr;
2477        }
2478        else {
2479            pb->result = kIDHErrCompletionPending;
2480            //syslog(LOG_INFO, "FWDVIDHRead end, completion = %p buffer = %p\n", pb->completionProc, pb->buffer);
2481            //syslog(LOG_INFO, "pb %p = req %d actual %d, result %d\n",
2482            //    pb, pb->requestedCount, pb->actualCount, pb->result);
2483
2484            result = sendMsg(ih, queueRead, pb);
2485        }
2486
2487Exit:
2488#ifdef DRAWRINGBUFFERGRAPH
2489	BlitBufferGraph(deviceDescriptionPtr);
2490#endif
2491        return result;
2492}
2493
2494static pascal ComponentResult
2495FWDVIDHReleaseBuffer(IsochComponentInstancePtr ih, IDHParameterBlock *pb)
2496{
2497    OSStatus 		result = noErr;
2498    int			frameIndex;
2499    DeviceDescription	*deviceDescriptionPtr;
2500
2501    RecordEventLogger( 'isoc', 'rele', 'ase ', 'buff');
2502
2503    FailWithAction( pb == nil, result = paramErr, Exit);
2504
2505    FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2506
2507    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
2508    FailWithVal( result != noErr, Exit, result);
2509    frameIndex = deviceDescriptionPtr->fReadSharedVars->fReader % deviceDescriptionPtr->fNumOutputFrames;
2510    if(pb->buffer == (Ptr)deviceDescriptionPtr->bufMem[frameIndex]) {
2511        if(--deviceDescriptionPtr->fBufferLocks[frameIndex] == 0)
2512            deviceDescriptionPtr->fReadSharedVars->fReader += 1;   // release buffer, this isn't quite right if several buffers are held.
2513    }
2514Exit:
2515    return result;
2516}
2517
2518static pascal ComponentResult
2519FWDVIDHCancelPendingIO(IsochComponentInstancePtr ih, IDHParameterBlock *pb)
2520{
2521    OSStatus 		result = noErr;
2522    DeviceDescription	*deviceDescriptionPtr;
2523
2524    RecordEventLogger( 'isoc', 'canc', 'elIO', 0);
2525
2526    FailWithAction( pb == nil, result = paramErr, Exit);
2527
2528    FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2529
2530    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
2531    FailWithVal( result != noErr, Exit, result);
2532
2533    result = sendMsg(ih, processCancelPendingIO, pb);
2534
2535Exit:
2536#ifdef DRAWRINGBUFFERGRAPH
2537	BlitBufferGraph(deviceDescriptionPtr);
2538#endif
2539    return result;
2540}
2541
2542// can be called synchronously at task level only
2543static pascal ComponentResult
2544FWDVIDHWrite(IsochComponentInstancePtr ih, IDHParameterBlock *pb)
2545{
2546    OSStatus 		result = noErr;
2547    DeviceDescription	*deviceDescriptionPtr;
2548
2549    RecordEventLogger( 'isoc', 'writ', ih, pb);
2550
2551    FailWithAction( pb == nil, result = paramErr, Exit);
2552
2553    // check for illegal condition
2554    FailWithAction( pb->completionProc == nil && pb->buffer == nil, result = paramErr, Exit);
2555
2556    FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2557
2558    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
2559    FailWithVal( result != noErr, Exit, result);
2560
2561    FailWithAction( deviceDescriptionPtr->fActive == false, result = kIDHErrDeviceDisconnected, Exit);
2562
2563    if( pb->completionProc == nil) // synchronous write
2564    {
2565        pb->result = kIDHErrCompletionPending;
2566
2567        result = sendMsg(ih, queueWrite, pb);
2568        while (pb->result == kIDHErrCompletionPending)
2569        {
2570            usleep(12500);	// time DCL block takes to run
2571        }
2572    }
2573    else {
2574        result = sendMsg(ih, queueWrite, pb);
2575    }
2576
2577
2578Exit:
2579#ifdef DRAWRINGBUFFERGRAPH
2580	BlitBufferGraph(deviceDescriptionPtr);
2581#endif
2582    return result;
2583}
2584
2585static pascal ComponentResult
2586FWDVIDHGetDeviceControl(IsochComponentInstancePtr ih, ComponentInstance *deviceControl)
2587{
2588    ComponentResult				result = noErr;
2589    DeviceDescription			*deviceDescriptionPtr;
2590
2591    RecordEventLogger( 'isoc', 'get ', 'dev ', 'ctrl');
2592
2593    if ( deviceControl == nil )
2594            return(paramErr);
2595
2596    FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2597
2598    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
2599    FailWithVal( result != noErr, Exit, result);
2600
2601    FailWithAction( deviceDescriptionPtr->fActive == false, result = kIDHErrDeviceDisconnected, Exit);
2602
2603    // =======================================================================
2604    // All should be good here from a device stand point, now open the device
2605    // control component.  If the devc is not nil either we didn't release it
2606    // from close or the same client is calling open again.
2607
2608    if ( deviceDescriptionPtr->deviceControlInstance == nil)
2609    {
2610        ComponentDescription	devcDesc;
2611        Component		devcComp;
2612        ComponentInstance	devc;
2613
2614        devcDesc.componentType 		= kDeviceControlComponentType;
2615        devcDesc.componentSubType 	= kDeviceControlSubtypeFWDV;
2616        devcDesc.componentManufacturer 	= 0;
2617        devcDesc.componentFlags 	= 0L;
2618        devcDesc.componentFlagsMask 	= 0L;
2619
2620        devcComp = nil;
2621        devcComp = FindNextComponent( devcComp, &devcDesc);
2622        FailMessage( devcComp == nil);
2623        if ( devcComp )
2624        {
2625            result = OpenAComponent(devcComp, &devc);
2626            FailWithVal( result != noErr, Exit, result);
2627
2628            result = DeviceControlSetDeviceConnectionID(devc,
2629                (DeviceConnectionID) deviceDescriptionPtr->fDevice->fAVCInterface);
2630            FailWithVal( result != noErr, Exit, result);
2631            result = DeviceControlEnableAVCTransactions(devc);
2632            FailWithVal( result != noErr, Exit, result);
2633
2634            deviceDescriptionPtr->deviceControlInstance = devc;
2635        }
2636    }
2637
2638    if( ih->hasDeviceControl == false && deviceDescriptionPtr->deviceControlInstance != nil)
2639    {
2640            ih->hasDeviceControl = true;
2641            ++deviceDescriptionPtr->deviceControlCount;
2642    }
2643
2644
2645    *deviceControl = deviceDescriptionPtr->deviceControlInstance;
2646
2647    FailMessage( *deviceControl == nil);
2648
2649Exit:
2650    return(result);
2651}
2652
2653static pascal ComponentResult
2654FWDVIDHUpdateDeviceList(IsochComponentInstancePtr ih, QTAtomContainer *deviceList )
2655{
2656    OSStatus 			result = noErr;
2657    short			nDVDevices, i;
2658    QTAtomSpec		atomSpec;
2659    IsochComponentGlobalsPtr g = &globals;
2660
2661    RecordEventLogger( 'isoc', 'updt', 'dev ', 'list');
2662
2663    FailWithAction( deviceList == nil, result = paramErr, Exit);
2664
2665    atomSpec.container = *deviceList;
2666
2667    result = checkSeed( g, &atomSpec);	// make sure the container is current
2668    if( result != noErr)
2669            goto Exit;
2670
2671    // check for useCMP value changing
2672    if (result == noErr)
2673    {
2674            QTAtom	useCMPAtom;
2675            UInt32	useCMPValue;
2676
2677            useCMPAtom = QTFindChildByIndex(*deviceList, kParentAtomIsContainer, kIDHUseCMPAtomType, 1, nil);
2678            if (useCMPAtom)
2679            {
2680                    QTLockContainer(*deviceList);
2681                    result = QTCopyAtomDataToPtr(*deviceList, useCMPAtom, true, 4, &useCMPValue, nil);
2682                    QTUnlockContainer(*deviceList);
2683
2684                    if (result == noErr)
2685                            g->useCMP = useCMPValue;
2686
2687            }
2688    }
2689
2690    // move all volatile atoms here
2691    nDVDevices = QTCountChildrenOfType( *deviceList, kParentAtomIsContainer, kIDHDeviceAtomType);
2692    for( i=0; i<nDVDevices; ++i)
2693    {
2694            QTAtom 				deviceAtomNew, nameAtomNew, deviceIDAtom;
2695            QTAtom 				deviceAtomOld, nameAtomOld;
2696            DeviceDescription	*deviceDescriptionPtr;
2697            IDHDeviceID			deviceID;
2698            UInt8				newName[256];
2699            SInt32				actualSize;
2700
2701            // get the client supplied atoms
2702            deviceAtomNew = QTFindChildByIndex( *deviceList, kParentAtomIsContainer, kIDHDeviceAtomType, i + 1, nil);
2703            FailIf( deviceAtomNew == nil, Exit);
2704
2705            nameAtomNew = QTFindChildByIndex( *deviceList, deviceAtomNew, kIDHNameAtomType, 1, nil);
2706            FailIf( nameAtomNew == nil, Exit);
2707
2708            deviceIDAtom = QTFindChildByIndex( *deviceList, deviceAtomNew, kIDHDeviceIDType, 1, nil);
2709            FailIf( deviceIDAtom == nil, Exit);
2710
2711            QTLockContainer( *deviceList);
2712
2713            QTCopyAtomDataToPtr( *deviceList, deviceIDAtom, true, sizeof( IDHDeviceID), &deviceID, nil);
2714
2715            QTUnlockContainer( *deviceList);
2716
2717            // find the local copy of this device container
2718            result = findDeviceDescriptionforDevice( ih, deviceID, &deviceDescriptionPtr);
2719            FailWithVal( result != noErr, Exit, result);
2720
2721            deviceAtomOld = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType, 1, nil);
2722            FailIf( deviceAtomOld == nil, Exit);
2723
2724            nameAtomOld = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, deviceAtomOld, kIDHNameAtomType, 1, nil);
2725            FailIf( nameAtomOld == nil, Exit);
2726
2727            // get new name
2728            QTLockContainer( *deviceList);
2729            result = QTCopyAtomDataToPtr(*deviceList, nameAtomNew, true, 256, newName, &actualSize);
2730            QTUnlockContainer( *deviceList);
2731            FailWithVal( result != noErr, Exit, result);
2732
2733            // update prefs file with new name
2734            // JKL, don't want to do this for now since FCP might be using this routine to toggle CMP
2735//		updateCameraName(&deviceDescriptionPtr->uniqueID, newName);
2736
2737            // copy the new data into the current atom
2738            result = QTReplaceAtom( deviceDescriptionPtr->deviceContainer, nameAtomOld, *deviceList, nameAtomNew);
2739            FailWithVal( result != noErr, Exit, result);
2740    }
2741
2742Exit:
2743    return result;
2744}
2745
2746static pascal ComponentResult
2747FWDVIDHGetDeviceTime(IsochComponentInstancePtr ih, TimeRecord *time)
2748{
2749    OSStatus 		result;
2750    DeviceDescription	*deviceDescriptionPtr;
2751    UInt32 		busTime, cycleTime;
2752    UInt64		cycles;
2753
2754    FailWithAction( time == nil, result = paramErr, Exit);
2755
2756    FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2757
2758    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
2759    FailWithVal( result != noErr, Exit, result);
2760
2761    FailWithAction( deviceDescriptionPtr->fActive == false, result = kIDHErrDeviceDisconnected, Exit);
2762
2763     result = (*deviceDescriptionPtr->fDevice->fDevInterface)->
2764        GetBusCycleTime(deviceDescriptionPtr->fDevice->fDevInterface, &busTime, &cycleTime);
2765
2766    if(result == noErr) {
2767        cycles = busTime * 8000;				// Seconds converted to cycles
2768        cycles += (cycleTime >> 12) & 0x1fff;	// Extract cycle count from cyletime register
2769
2770        time->value.lo = cycles & 0xffffffff;
2771        time->value.hi = (cycles >> 32) & 0xffffffff;
2772        time->scale = 8000;
2773    }
2774Exit:
2775    return result;
2776}
2777
2778static pascal ComponentResult
2779FWDVIDHNewNotification(IsochComponentInstancePtr ihc, IDHDeviceID deviceID,
2780    IDHNotificationProc notificationProc, void* userData, IDHNotificationID* notificationID)
2781{
2782    UInt32	i;
2783    Boolean	addedClient = false;
2784    OSStatus 	result = noErr;
2785    IsochComponentGlobalsPtr g = &globals;
2786
2787    RecordEventLogger( 'isoc', 'new ', 'noti', 'fy  ');
2788
2789    FailWithAction( notificationProc == nil, result = paramErr, Exit);
2790    FailWithAction( notificationID == nil, result = paramErr, Exit);
2791
2792    i = 0;
2793    while (i < kMaxNotifications)
2794    {
2795        if (0 == g->clientNotification[i].deviceID)
2796        {
2797            g->clientNotification[i].deviceID = deviceID;
2798            g->clientNotification[i].notificationProc = notificationProc;
2799            g->clientNotification[i].events = 0;
2800            g->clientNotification[i].userData = userData;
2801            *notificationID = (UInt32)&g->clientNotification[i];
2802            addedClient = true;
2803            break;
2804        }
2805
2806        ++i;
2807    }
2808
2809    if (!addedClient)				// List is full. Unable to add addtional clients
2810            result = paramErr;
2811
2812Exit:
2813    return result;
2814}
2815
2816static pascal ComponentResult
2817FWDVIDHNotifyMeWhen(ComponentInstance idh, IDHNotificationID notificationID, IDHEvent events)
2818{
2819    OSStatus 		result = noErr;
2820    ClientNotification*	clientNotification = (ClientNotification*)notificationID;
2821
2822    RecordEventLogger( 'isoc', 'noti', 'when', events);
2823
2824    FailWithAction( clientNotification == nil, result = paramErr, Exit);
2825
2826    clientNotification->events = events;
2827
2828Exit:
2829    return result;
2830}
2831
2832static pascal ComponentResult
2833FWDVIDHCancelNotification(ComponentInstance idh, IDHNotificationID notificationID)
2834{
2835    OSStatus 		result = noErr;
2836    ClientNotification*	clientNotification = (ClientNotification*)notificationID;
2837
2838    RecordEventLogger( 'isoc', 'canc', 'el  ', 'noti');
2839
2840    FailWithAction( clientNotification == nil, result = paramErr, Exit);
2841
2842    clientNotification->events = 0;
2843
2844Exit:
2845    return result;
2846}
2847
2848static pascal ComponentResult
2849FWDVIDHDisposeNotification(ComponentInstance idh, IDHNotificationID notificationID)
2850{
2851    OSStatus 		result = noErr;
2852    ClientNotification*	clientNotification = (ClientNotification*)notificationID;
2853
2854    RecordEventLogger( 'isoc', 'disp', 'ose ', 'noti');
2855
2856    FailWithAction( clientNotification == nil, result = paramErr, Exit);
2857
2858    clientNotification->deviceID = 0;
2859
2860Exit:
2861    return result;
2862}
2863
2864static pascal ComponentResult
2865FWDVIDHSetFormat(IsochComponentInstancePtr ih, UInt32 format)
2866{
2867    OSStatus 		result = noErr;
2868    DeviceDescription	*deviceDescriptionPtr;
2869
2870    RecordEventLogger( 'isoc', 'setf', 'ormt', format);
2871    FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2872
2873    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
2874    FailWithVal( result != noErr, Exit, result);
2875
2876    deviceDescriptionPtr->fOutputMode = format << 2;	// Get STYPE field into position
2877    if(deviceDescriptionPtr->fDevice->standard != ntscIn)
2878        deviceDescriptionPtr->fOutputMode |= 0x80;	// PAL flag
2879
2880Exit:
2881    return result;
2882}
2883
2884static pascal ComponentResult
2885FWDVIDHGetFormat(IsochComponentInstancePtr ih, UInt32 *format)
2886{
2887    OSStatus 		result = noErr;
2888    DeviceDescription	*deviceDescriptionPtr;
2889
2890    RecordEventLogger( 'isoc', 'getf', 'ormt', format);
2891    FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
2892
2893    result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
2894    FailWithVal( result != noErr, Exit, result);
2895
2896    *format = (deviceDescriptionPtr->fOutputMode >> 2) & 0x1f;	// Return just STYPE field, in bottom bits
2897
2898Exit:
2899    return result;
2900}
2901
2902/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2903
2904#define DoCDispatchWS(x,p,s)		\
2905    case k ## x ## Select:		\
2906        /* printf("FWDV" #x "{"); */	\
2907        { ComponentResult err;		\
2908            err = CallComponentFunctionWithStorageProcInfo( s, p, (ProcPtr) FWDV ## x,	\
2909                                                uppCall ## x ## ProcInfo );		\
2910        /* printf("%ld}\n", err); */	\
2911        return err;	}
2912
2913#define DoDispatchWS(x,p,s)		\
2914    case k ## x ## Select:		\
2915        /* printf("FWDV" #x "{"); */	\
2916        { ComponentResult err;		\
2917            err = CallComponentFunctionWithStorageProcInfo( s, p, (ProcPtr) FWDV ## x,	\
2918                                                upp ## x ## ProcInfo );			\
2919        /* printf("%ld}\n", err); */ 	\
2920        return err;	}
2921
2922
2923static pascal ComponentResult
2924FWDVComponentCanDo(IsochComponentInstancePtr storage, short selector)
2925{
2926    ComponentResult result;
2927    RecordEventLogger( 'isoc', 'cand', 0, 0);
2928
2929    switch(selector) {
2930        /* Standard selectors */
2931        case kComponentOpenSelect:
2932        case kComponentCloseSelect:
2933        case kComponentCanDoSelect:
2934        case kComponentVersionSelect:
2935
2936        /* IDH selectors */
2937        case kIDHGetDeviceListSelect:
2938        case kIDHGetDeviceConfigurationSelect:
2939        case kIDHSetDeviceConfigurationSelect:
2940        case kIDHGetDeviceStatusSelect:
2941        case kIDHGetDeviceClockSelect:
2942        case kIDHOpenDeviceSelect:
2943        case kIDHCloseDeviceSelect:
2944        case kIDHReadSelect:
2945        case kIDHWriteSelect:
2946        case kIDHNewNotificationSelect:
2947        case kIDHNotifyMeWhenSelect:
2948        case kIDHCancelNotificationSelect:
2949        case kIDHDisposeNotificationSelect:
2950        case kIDHReleaseBufferSelect:
2951        case kIDHCancelPendingIOSelect:
2952        case kIDHGetDeviceControlSelect:
2953        case kIDHUpdateDeviceListSelect:
2954        case kIDHGetDeviceTimeSelect:
2955        case kIDHSetFormatSelect:
2956        case kIDHGetFormatSelect:
2957            return(true);
2958
2959        default:
2960            RecordEventLogger( 'isoc', 'cant', selector, 0);
2961            result = false;
2962            return (result);
2963    }
2964}
2965
2966
2967pascal ComponentResult
2968FWDVICodecComponentDispatch(ComponentParameters *params, char ** storage)
2969{
2970    ComponentResult result;
2971
2972    /*	If the selector is less than zero, it's a Component manager selector.	*/
2973
2974    if ( params->what < 0  ) {
2975        switch ( params->what ) {
2976            DoCDispatchWS( ComponentOpen, params, storage );
2977            DoCDispatchWS( ComponentClose, params, storage );
2978            DoCDispatchWS( ComponentRegister, params, storage );
2979            DoCDispatchWS( ComponentCanDo, params, storage );
2980            DoCDispatchWS( ComponentVersion, params, storage );
2981
2982            default :
2983                return (paramErr);
2984        }
2985    }
2986
2987    /*
2988     *	Here we dispatch the rest of our calls. We use the magic thing manager routine which
2989     *	calls our subroutines with the proper parameters. The prototypes are in Image Codec.h.
2990     */
2991    switch ( params->what ) {
2992        DoDispatchWS( IDHGetDeviceList, params, storage );
2993        DoDispatchWS( IDHGetDeviceConfiguration, params, storage );
2994        DoDispatchWS( IDHSetDeviceConfiguration, params, storage );
2995        DoDispatchWS( IDHGetDeviceStatus, params, storage );
2996        DoDispatchWS( IDHGetDeviceClock, params, storage );
2997        DoDispatchWS( IDHOpenDevice, params, storage );
2998        DoDispatchWS( IDHCloseDevice, params, storage );
2999        DoDispatchWS( IDHRead, params, storage );
3000        DoDispatchWS( IDHWrite, params, storage );
3001        DoDispatchWS( IDHReleaseBuffer, params, storage );
3002        DoDispatchWS( IDHCancelPendingIO, params, storage );
3003        DoDispatchWS( IDHGetDeviceControl, params, storage );
3004        DoDispatchWS( IDHUpdateDeviceList, params, storage );
3005        DoDispatchWS( IDHGetDeviceTime, params, storage );
3006        DoDispatchWS( IDHNewNotification, params, storage );
3007        DoDispatchWS( IDHNotifyMeWhen, params, storage );
3008        DoDispatchWS( IDHCancelNotification, params, storage );
3009        DoDispatchWS( IDHDisposeNotification, params, storage );
3010        DoDispatchWS( IDHSetFormat, params, storage );
3011        DoDispatchWS( IDHGetFormat, params, storage );
3012
3013    default:
3014        {
3015            int len = params->paramSize/4;
3016            int i;
3017            printf("IDH unimp:%d %d ", params->what, params->paramSize);
3018            for(i=0; i<len; i++)
3019                printf("0x%lx ", params->params[i]);
3020            printf("\n");
3021            result = paramErr;
3022            return(result);
3023        }
3024    }
3025}
3026
3027#ifdef DRAWRINGBUFFERGRAPH
3028
3029static void SetUpBlitGlobals(DeviceDescriptionPtr ddp)
3030{
3031	GDHandle gdh =  GetMainDevice();
3032if (gdh)
3033	{
3034	ddp->fScreenBaseAddr = gdh[0]->gdPMap[0]->baseAddr;
3035	ddp->fRowBytes = gdh[0]->gdPMap[0]->rowBytes & 0x3FFF;
3036	ddp->fPixDepth = gdh[0]->gdPMap[0]->pixelSize;
3037	}
3038}
3039
3040#define spacerColour 0xFFFF
3041#define unusedColour 0x0000
3042#define emptyColour (16<<10) + (16<<5) +(16)
3043#define hasDataColour (0<<10) + (31<<5) +(0)
3044#define readColour (31<<10) + (31<<5) +(0)
3045#define writeColour (0<<10) + (31<<5) +(31)
3046#define collisionColour (31<<10) + (0<<5) +(0)
3047
3048static void BlitBufferGraph(DeviceDescriptionPtr ddp)
3049{
3050	short * line0Ptr = nil;
3051	short * line00Ptr = nil;
3052	short * line1Ptr = nil;
3053	short * line2Ptr = nil;
3054	short * line3Ptr = nil;
3055	short buffCol = 0;
3056	long flags =0;
3057	int x,i,read,write;
3058	if (ddp->fPixDepth != 16 || ddp->fScreenBaseAddr ==0 || ddp->fRowBytes ==0)
3059		return;
3060	line00Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*18-ddp->fRowBytes/4);
3061	line0Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*19-ddp->fRowBytes/4);
3062	line1Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*16-ddp->fRowBytes/4);
3063	line2Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*17-ddp->fRowBytes/4);
3064	line3Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*15-ddp->fRowBytes/4);
3065	read = ddp->fSharedVars->fReader % ddp->fNumOutputFrames;
3066	write = ddp->fSharedVars->fWriter % ddp->fNumOutputFrames;
3067	for(x =0;x < ddp->fNumOutputFrames; x++)
3068		{
3069		*line1Ptr++ = (short)spacerColour;
3070		*line2Ptr++ = (short)spacerColour;
3071		*line0Ptr++ = (short)spacerColour;
3072		*line00Ptr++ = (short)spacerColour;
3073
3074		for(i=0;i<ddp->fBufferLocks[x];i++) {
3075			short* beardPtr = line0Ptr+ddp->fRowBytes*i*2;
3076			*beardPtr++ = unusedColour;
3077			*beardPtr++ = unusedColour;
3078			*beardPtr++ = unusedColour;
3079			*beardPtr++ = unusedColour;
3080		}
3081
3082		if (ddp->fBufferLocks[x]) {
3083			buffCol = hasDataColour;
3084		} else {
3085			buffCol = emptyColour;
3086		}
3087		*line1Ptr++ = buffCol;
3088		*line1Ptr++ = buffCol;
3089		*line1Ptr++ = buffCol;
3090		*line1Ptr++ = buffCol;
3091
3092		*line2Ptr++ = buffCol;
3093		*line2Ptr++ = buffCol;
3094		*line2Ptr++ = buffCol;
3095		*line2Ptr++ = buffCol;
3096
3097		buffCol = (short)spacerColour;
3098		if (read == x)
3099			buffCol = readColour;
3100		if (write == x)
3101			{
3102			if (buffCol == readColour)
3103				buffCol = collisionColour;
3104			else
3105				buffCol = writeColour;
3106			}
3107		*line00Ptr++ = buffCol;
3108		*line00Ptr++ = buffCol;
3109		*line00Ptr++ = buffCol;
3110		*line00Ptr++ = buffCol;
3111
3112		*line0Ptr++ = buffCol;
3113		*line0Ptr++ = buffCol;
3114		*line0Ptr++ = buffCol;
3115		*line0Ptr++ = buffCol;
3116		}
3117
3118
3119}
3120#endif
3121
3122