DVIsochComponent.c [plain text]
#include <Carbon/Carbon.h>
typedef struct IsochComponentInstance IsochComponentInstance, *IsochComponentInstancePtr;
typedef struct IsochComponentGlobals IsochComponentGlobals, *IsochComponentGlobalsPtr;
#define CALLCOMPONENT_BASENAME() IDHDV
#define CALLCOMPONENT_GLOBALS() IsochComponentInstancePtr storage
#define IDH_BASENAME() FWDV
#define IDH_GLOBALS() IsochComponentInstancePtr storage
#include "IsochronousDataHandler.k.h"
#include "DeviceControlPriv.h"
#include "DVVers.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // usleep()
#include <pthread.h>
#include <syslog.h> // Debug messages
#include <mach/clock.h>
#include <mach/clock_types.h>
#include <sys/syscall.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/iokitmig.h>
#include <mach/mach_port.h>
#include <IOKit/DV/IOFWDVClient.h>
#include <IOKit/IOMessage.h>
#define kDVRequestID 0
#define kIOPending 1
#define kIORunning 2
#define kMaxDeviceClients 4
#define DEBUG 0
#define kDVDeviceInfo 'ddin' // DV device info
#define kMaxDevicesActive 64 // max devices on firewire bus
#define kMaxInstances 10 // max clients attached to a device
#define kMaxNotifications 100 // 100 notifications can be supported
#define kNTSCCompressedBufferSize 120000
#define kPALCompressedBufferSize 144000
#define kIDHSeedAtomType 'seed' // seed for device atom validity
#define kIDHDevicePresentType 'pres' // is device present?
#define kServiceTypeDVServices 'avc '
#define kTimeoutDuration (1000 / 15) * durationMillisecond // 1/15 second (2 frame times)
typedef struct ClientNotification {
ComponentInstance ihc;
IDHDeviceID deviceID;
IDHNotificationProc notificationProc;
IDHEvent events;
void *userData;
} ClientNotification;
typedef struct DeviceDescription {
UInt64 fGUID; io_object_t fID; io_connect_t fConnection;
io_object_t fNotification; IsochComponentGlobalsPtr fGlobals;
UInt32 fNumOutputFrames;
vm_address_t *bufMem; IOFWDVSharedVars *fSharedVars; vm_address_t fDCLBuffer; IOFWDVWriteSharedData *fSharedWriteVars; UInt32 * fOldWriteTimeStamps;
int fDCLReadPos; int fBufWritePos; int fFrameBufferPos; int fDCLSavedPacketNum; UInt8 * fDCLSavedWritePos; int fBufSize; int fOldDrop; int fOldRead; IsochComponentInstancePtr fOpenClients[kMaxDeviceClients]; int fBufferLocks[kDVNumOutputFrames];
ComponentInstance deviceControlInstance; Component clock; UInt32 standard; QTAtomContainer deviceContainer; SInt16 deviceControlCount; SInt16 readLocks; SInt16 writeLocks; Boolean active; Boolean fHasSDL; UInt8 fOutputMode; Boolean fWaitingStartWrite; Boolean fConnected; #ifdef DRAWRINGBUFFERGRAPH
Ptr fScreenBaseAddr;
UInt32 fPixDepth;
UInt32 fRowBytes;
#endif
} DeviceDescription, *DeviceDescriptionPtr;
#ifdef DRAWRINGBUFFERGRAPH
static void SetUpBlitGlobals(DeviceDescriptionPtr ddp);
static void BlitBufferGraph(DeviceDescriptionPtr ddp);
#endif
struct IsochComponentGlobals
{
UInt32 useCMP; DeviceDescription deviceDescription[kMaxDevicesActive]; ClientNotification clientNotification[kMaxNotifications]; UInt32 nDevices; UInt32 seed;
mach_port_t fMasterDevicePort; IONotificationPortRef fNotifyPort; mach_port_t fNotifyMachPort; io_iterator_t fMatchEnumer; pthread_t fWorkThread; pthread_attr_t fThreadAttr;
pthread_mutex_t fGlobalsMutex; pthread_cond_t fSyncCond;
UInt32 fGlobalsState; CFBundleRef fBundleID;
int fNumInstances;
};
struct IsochComponentInstance
{
ComponentInstance self;
QTAtomSpec currentConfig; IDHDeviceID deviceID; UInt16 fClientIndex; long permissions; IDHParameterBlock * fHead; IDHParameterBlock * fTail; IDHParameterBlock * fActiveHead; IDHParameterBlock * fActiveTail; UInt32 fSyncRequest; ComponentResult fSyncResult; Boolean hasDeviceControl; };
typedef struct {
UInt32 fRequest;
IsochComponentInstancePtr fInstance;
void * fParams;
} DVRequest;
typedef struct {
mach_msg_header_t msgHdr;
DVRequest dvRequest;
} SendMsg;
typedef struct {
mach_msg_header_t msgHdr;
union {
OSNotificationHeader notifyHeader;
DVRequest dvRequest;
UInt8 grr[72]; }body;
mach_msg_trailer_t trailer;
} ReceiveMsg;
pascal ComponentResult
FWDVICodecComponentDispatch(ComponentParameters *params, char ** storage);
static pascal ComponentResult
FWDVIDHCloseDevice(IsochComponentInstancePtr ih);
static IsochComponentGlobals globals;
#ifdef DEBUG
#define FailMessage(cond) assert (!(cond))
#else
#define FailMessage(cond) {}
#endif
#define FailWithVal(cond, handler,num) \
if (cond) { \
goto handler; \
}
#define FailWithAction(cond, action, handler) \
if (cond) { \
{ action; } \
goto handler; \
}
#define FailIf(cond, handler) \
if (cond) { \
FailMessage(false); \
goto handler; \
}
#if DEBUG
static char * print4(UInt32 val, char *buf)
{
char a, b, c, d;
a = val>>24;
b = val>>16;
c = val>>8;
d = val;
if(a >= ' ' && b >= ' ' && c >= ' ' && d >= ' ')
sprintf(buf, "%c%c%c%c", a, b, c, d);
else
sprintf(buf, " 0x%x ", (int)val);
return buf + strlen(buf);
}
static void RecordEventLogger(UInt32 a, UInt32 b, UInt32 c, UInt32 d)
{
char buf[256];
char *curr = buf;
sprintf(buf, "0x%x:", pthread_self());
curr = buf + strlen(buf);
if(a)
curr = print4(a, curr);
if(b)
curr = print4(b, curr);
if(c)
curr = print4(c, curr);
if(d)
curr = print4(d, curr);
printf("%s\n", buf);
syslog(LOG_INFO, buf);
}
#else
#define RecordEventLogger(a, b, c, d)
#endif
#define kKernelTraceEnable (1 << 0 )
#define kKernelTraceDisable (1 << 1 )
#define kIOFWDVTrace 0x08001000
static int pKGSysCall_Start (int code, int param1, int param2, int param3, int param4, int param5, int param6 )
{
return syscall ( SYS_kdebug_trace, code | kKernelTraceEnable, param1, param2, param3, param4, param5, param6 );
}
static int pKGSysCall_End (int code, int param1, int param2, int param3, int param4, int param5, int param6 )
{
return syscall ( SYS_kdebug_trace, code | kKernelTraceDisable, param1, param2, param3, param4, param5, param6 );
}
static int pKGSysCall_Insert (int code, int param1, int param2, int param3, int param4, int param5, int param6 )
{
return syscall ( SYS_kdebug_trace, code , param1, param2, param3, param4, param5, param6 );
}
static void dropMsg(DeviceDescription *deviceDescriptionPtr)
{
pKGSysCall_Insert (kIOFWDVTrace, 'drop', deviceDescriptionPtr->fSharedVars->fDroppedFrames-
deviceDescriptionPtr->fOldDrop, deviceDescriptionPtr->fSharedVars->fDroppedFrames, 0, 0, 0);
syslog(LOG_INFO,"Just dropped %ld frames (total %ld)!\n",
deviceDescriptionPtr->fSharedVars->fDroppedFrames-deviceDescriptionPtr->fOldDrop,
deviceDescriptionPtr->fSharedVars->fDroppedFrames);
deviceDescriptionPtr->fOldDrop = deviceDescriptionPtr->fSharedVars->fDroppedFrames;
}
static void signalSync(UInt32 *var, UInt32 val)
{
pthread_mutex_lock(&globals.fGlobalsMutex);
*var = val;
pthread_mutex_unlock(&globals.fGlobalsMutex);
pthread_cond_broadcast(&globals.fSyncCond);
}
static void waitSync(UInt32 *var)
{
if(!*var) {
pthread_mutex_lock(&globals.fGlobalsMutex);
while(!*var) {
pthread_cond_wait(&globals.fSyncCond, &globals.fGlobalsMutex);
}
pthread_mutex_unlock(&globals.fGlobalsMutex);
}
}
OSErr findDeviceDescriptionforDevice( IsochComponentInstancePtr ih, UInt32 deviceID, DeviceDescription **deviceDescription)
{
OSErr result = noErr;
*deviceDescription = (DeviceDescriptionPtr)deviceID;
return result;
}
static OSErr findAtom( const QTAtomSpec *atomSpec, OSType theType, QTAtom *theAtom)
{
OSErr result = noErr;
OSType type;
QTAtom atom;
atom = atomSpec->atom;
result = QTGetAtomTypeAndID( atomSpec->container, atom, (long *) &type, nil);
FailWithVal( result != noErr, Exit, result);
while( type != kIDHDeviceAtomType && type != theType)
{
atom = QTGetAtomParent( atomSpec->container, atom); FailWithAction( atom == nil || atom == -1, result = kIDHErrDeviceList, Exit);
result = QTGetAtomTypeAndID( atomSpec->container, atom, (long *) &type, nil);
FailWithVal( result != noErr, Exit, result);
}
if( theType == type)
{
*theAtom = atom;
result = noErr;
}
else
{
*theAtom = nil;
result = kIDHErrDeviceList;
}
Exit:
return result;
}
static OSErr getDeviceID( QTAtomSpec *configID, UInt32 *deviceID)
{
OSErr result = noErr;
QTAtom deviceAtom;
*deviceID = nil;
result = findAtom( configID, kIDHDeviceAtomType, &deviceAtom);
FailWithVal( result != noErr, Exit, result);
result = QTGetAtomTypeAndID( configID->container, deviceAtom, nil, (long *) deviceID);
FailWithVal( result != noErr, Exit, result);
Exit:
return result;
}
static OSErr closeDeviceControl( IsochComponentInstancePtr ih, DeviceDescriptionPtr deviceDescriptionPtr)
{
OSErr result = noErr;
if( deviceDescriptionPtr->deviceControlInstance)
{
if( --deviceDescriptionPtr->deviceControlCount <= 0)
{
deviceDescriptionPtr->deviceControlCount = 0;
result = DeviceControlDisableAVCTransactions(deviceDescriptionPtr->deviceControlInstance);
result = DeviceControlSetDeviceConnectionID(deviceDescriptionPtr->deviceControlInstance,
kIDHInvalidDeviceID);
CloseComponent(deviceDescriptionPtr->deviceControlInstance);
deviceDescriptionPtr->deviceControlInstance = nil;
}
}
return result;
}
OSErr checkSeed( IsochComponentGlobalsPtr gGlobals, QTAtomSpec *configID)
{
QTAtom seedAtom;
OSErr result = noErr;
UInt32 seed;
seedAtom = QTFindChildByIndex( configID->container, kParentAtomIsContainer, kIDHSeedAtomType, 1, nil);
FailWithAction( seedAtom == nil, result = kIDHErrDeviceList, Exit);
QTLockContainer( configID->container);
QTCopyAtomDataToPtr( configID->container, seedAtom, true, sizeof( seed), &seed, nil);
QTUnlockContainer( configID->container);
if( seed != gGlobals->seed)
{
result = kIDHErrDeviceList;
goto Exit;
}
Exit:
return result;
}
static OSErr setupVideoAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard, Boolean isSDL)
{
OSErr result = noErr;
QTAtom configAtom;
OSType type;
long size;
float interval;
long direction;
IDHDimension dimension;
IDHResolution resolution;
Fixed refresh;
OSType pixel;
OSType decoType;
Component decoComponent;
ComponentDescription compDescrip;
result = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType,
0, 0, 0, nil, &configAtom);
FailWithVal( result != noErr, Exit, result);
type = kIDHVideoMediaAtomType;
result = QTInsertChild( container, configAtom, kIDHIsochMediaType,
0, 0, sizeof( type), &type, nil);
FailWithVal( result != noErr, Exit, result);
if(isSDL) {
result = QTInsertChild( container, configAtom, kIDHNameAtomType,
0, 0, 7, "\pDV-SDL", nil);
}
else {
result = QTInsertChild( container, configAtom, kIDHNameAtomType,
0, 0, 3, "\pDV", nil);
}
FailWithVal( result != noErr, Exit, result);
type = (standard == ntscIn)?'DVC ':'DVCP';
result = QTInsertChild( container, configAtom, kIDHDataTypeAtomType,
0, 0, sizeof( type), &type, nil);
FailWithVal( result != noErr, Exit, result);
size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
if(isSDL)
size /= 2;
result = QTInsertChild( container, configAtom, kIDHDataSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( result != noErr, Exit, result);
result = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( result != noErr, Exit, result);
interval = 29.97;
result = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType,
0, 0, sizeof( interval), &interval, nil);
FailWithVal( result != noErr, Exit, result);
direction = kIDHDataTypeIsInputAndOutput;
result = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType,
0, 0, sizeof( direction), &direction, nil);
FailWithVal( result != noErr, Exit, result);
dimension.x = 720; dimension.y = (standard == ntscIn)?480:576;
result = QTInsertChild( container, configAtom, kIDHVideoDimensionsAtomType,
0, 0, sizeof( dimension), &dimension, nil);
FailWithVal( result != noErr, Exit, result);
resolution.x = 72 << 16; resolution.y = 72 << 16;
result = QTInsertChild( container, configAtom, kIDHVideoResolutionAtomType,
0, 0, sizeof( resolution), &resolution, nil);
FailWithVal( result != noErr, Exit, result);
refresh = (29 << 16) + 97; result = QTInsertChild( container, configAtom, kIDHVideoRefreshRateAtomType,
0, 0, sizeof( refresh), &refresh, nil);
FailWithVal( result != noErr, Exit, result);
pixel = 'dv '; result = QTInsertChild( container, configAtom, kIDHVideoPixelTypeAtomType,
0, 0, sizeof( pixel), &pixel, nil);
FailWithVal( result != noErr, Exit, result);
decoType = (standard == ntscIn)?'dvc ':'dvcp';
result = QTInsertChild( container, configAtom, kIDHVideoDecompressorTypeAtomType,
0, 0, sizeof( decoType), &decoType, nil);
FailWithVal( result != noErr, Exit, result);
compDescrip.componentType = 'imdc';
compDescrip.componentSubType = decoType;
compDescrip.componentManufacturer = 0;
compDescrip.componentFlags = 0;
compDescrip.componentFlagsMask = 0;
decoComponent = FindNextComponent( nil, &compDescrip);
result = QTInsertChild( container, configAtom, kIDHVideoDecompressorComponentAtomType,
0, 0, sizeof( decoComponent), &decoComponent, nil);
FailWithVal( result != noErr, Exit, result);
Exit:
return result;
}
static OSErr setup48kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard)
{
OSErr err;
QTAtom configAtom;
StringPtr name;
OSType type;
long size;
Fixed rate;
float interval;
long direction;
err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType,
0, 0, 0, nil, &configAtom);
FailWithVal( err != noErr, Exit, err);
type = kIDHSoundMediaAtomType;
err = QTInsertChild( container, configAtom, kIDHIsochMediaType,
0, 0, sizeof( type), &type, nil);
FailWithVal( err != noErr, Exit, err);
name = "\pDV-48khz";
err = QTInsertChild( container, configAtom, kIDHNameAtomType,
0, 0, name[0]+1, name, nil);
FailWithVal( err != noErr, Exit, err);
type = 'DV48';
err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType,
0, 0, sizeof( type), &type, nil);
FailWithVal( err != noErr, Exit, err);
size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
interval = 29.97;
err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType,
0, 0, sizeof( interval), &interval, nil);
FailWithVal( err != noErr, Exit, err);
direction = kIDHDataTypeIsInputAndOutput;
err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType,
0, 0, sizeof( direction), &direction, nil);
FailWithVal( err != noErr, Exit, err);
size = 2;
err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
size = 2;
err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
rate = rate44khz;
err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType,
0, 0, sizeof( rate), &rate, nil);
FailWithVal( err != noErr, Exit, err);
Exit:
return err;
}
static OSErr setup32kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard)
{
OSErr err;
QTAtom configAtom;
StringPtr name;
OSType type;
long size;
Fixed rate;
float interval;
long direction;
err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType,
0, 0, 0, nil, &configAtom);
FailWithVal( err != noErr, Exit, err);
type = kIDHSoundMediaAtomType;
err = QTInsertChild( container, configAtom, kIDHIsochMediaType,
0, 0, sizeof( type), &type, nil);
FailWithVal( err != noErr, Exit, err);
name = "\pDV-32khz";
err = QTInsertChild( container, configAtom, kIDHNameAtomType,
0, 0, name[0]+1, name, nil);
FailWithVal( err != noErr, Exit, err);
type = 'DV32';
err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType,
0, 0, sizeof( type), &type, nil);
FailWithVal( err != noErr, Exit, err);
size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
interval = 29.97;
err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType,
0, 0, sizeof( interval), &interval, nil);
FailWithVal( err != noErr, Exit, err);
direction = kIDHDataTypeIsInputAndOutput;
err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType,
0, 0, sizeof( direction), &direction, nil);
FailWithVal( err != noErr, Exit, err);
size = 4;
err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
size = 2;
err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
rate = 32000 << 16;
err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType,
0, 0, sizeof( rate), &rate, nil);
FailWithVal( err != noErr, Exit, err);
Exit:
return err;
}
static OSErr setup44kAudioAtoms( QTAtomContainer container, QTAtom isocAtom, UInt32 standard)
{
OSErr err;
QTAtom configAtom;
StringPtr name;
OSType type;
long size;
Fixed rate;
float interval;
long direction;
err = QTInsertChild( container, isocAtom, kIDHIsochModeAtomType,
0, 0, 0, nil, &configAtom);
FailWithVal( err != noErr, Exit, err);
type = kIDHSoundMediaAtomType;
err = QTInsertChild( container, configAtom, kIDHIsochMediaType,
0, 0, sizeof( type), &type, nil);
FailWithVal( err != noErr, Exit, err);
name = "\pDV-44khz";
err = QTInsertChild( container, configAtom, kIDHNameAtomType,
0, 0, name[0]+1, name, nil);
FailWithVal( err != noErr, Exit, err);
type = 'DV44';
err = QTInsertChild( container, configAtom, kIDHDataTypeAtomType,
0, 0, sizeof( type), &type, nil);
FailWithVal( err != noErr, Exit, err);
size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
err = QTInsertChild( container, configAtom, kIDHDataSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
size = (standard == ntscIn)?kNTSCCompressedBufferSize:kPALCompressedBufferSize;
err = QTInsertChild( container, configAtom, kIDHDataBufferSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
interval = 29.97;
err = QTInsertChild( container, configAtom, kIDHDataIntervalAtomType,
0, 0, sizeof( interval), &interval, nil);
FailWithVal( err != noErr, Exit, err);
direction = kIDHDataTypeIsInputAndOutput;
err = QTInsertChild( container, configAtom, kIDHDataIODirectionAtomType,
0, 0, sizeof( direction), &direction, nil);
FailWithVal( err != noErr, Exit, err);
size = 4;
err = QTInsertChild( container, configAtom, kIDHSoundChannelCountAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
size = 2;
err = QTInsertChild( container, configAtom, kIDHSoundSampleSizeAtomType,
0, 0, sizeof( size), &size, nil);
FailWithVal( err != noErr, Exit, err);
rate = 44100 << 16;
err = QTInsertChild( container, configAtom, kIDHSoundSampleRateAtomType,
0, 0, sizeof( rate), &rate, nil);
FailWithVal( err != noErr, Exit, err);
Exit:
return err;
}
static OSStatus cameraNameLookup(DeviceDescriptionPtr pDeviceDescription, UInt8 *name)
{
CFDictionaryRef properties;
CFStringRef dataDesc;
OSStatus result;
Boolean done;
result = IORegistryEntryCreateCFProperties(pDeviceDescription->fID,
&properties, kCFAllocatorDefault, kNilOptions);
if(result != noErr)
return result;
dataDesc = (CFStringRef)CFDictionaryGetValue(properties, CFSTR("FireWire Product Name"));
if(dataDesc) {
done = CFStringGetPascalString(dataDesc, name, 255, kCFStringEncodingMacRoman);
}
else {
UInt32 vendorID = pDeviceDescription->fGUID >> 40;
Handle h;
UInt32 *pGuid;
UInt32 guidCount;
UInt32 i, index;
Str255 cameraName = "\pDV"; SInt16 refNum = -1, localizedRefNum = -1;
BlockMoveData(cameraName, name, cameraName[0] + 1);
if(pDeviceDescription->fGlobals->fBundleID == 0) {
CFBundleRef myRef;
myRef = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.IOFWDVComponents"));
CFBundleOpenBundleResourceFiles(myRef, &refNum, &localizedRefNum);
pDeviceDescription->fGlobals->fBundleID = myRef;
}
h = Get1Resource('vnid', -20775); result = ResError();
if (h && (result == noErr)) {
HLock(h);
guidCount = **((UInt32 **) h);
pGuid = *((UInt32 **) h);
pGuid++;
for (i = 0, index = 1; i < guidCount; i++, index++) {
if (pGuid[i] == vendorID) {
GetIndString(cameraName, -20775, index);
if (cameraName[0]) {
BlockMoveData(cameraName, name, cameraName[0] + 1);
BlockMoveData(" DV", name + name[0] + 1, 3);
name[0] += 3;
break;
}
}
}
HUnlock(h);
ReleaseResource(h);
}
}
CFRelease(properties);
return result;
}
static OSErr postEvent(IsochComponentGlobalsPtr g, IDHDeviceID deviceID, IDHEvent event)
{
UInt32 i;
IDHDeviceConnectionEvent connectionEvent;
OSErr error = noErr;
RecordEventLogger( 'isoc', 'post', deviceID, event);
for (i = 0; i < kMaxNotifications ; ++i)
{
ClientNotification* clientNotification = &g->clientNotification[i];
IDHDeviceID clientDeviceID = clientNotification->deviceID;
IDHEvent wantedEvents = clientNotification->events;
if (event & wantedEvents)
{
if ((kIDHDeviceIDEveryDevice == clientDeviceID) ||
(deviceID == clientDeviceID) )
{
clientNotification->events = 0;
switch(event)
{
case kIDHEventDeviceChanged:
case kIDHEventDeviceAdded:
case kIDHEventDeviceRemoved:
case kIDHEventReadEnabled:
case kIDHEventReadDisabled:
case kIDHEventWriteEnabled:
case kIDHEventWriteDisabled:
connectionEvent.eventHeader.event = event;
connectionEvent.eventHeader.deviceID = deviceID;
connectionEvent.eventHeader.notificationID =
(UInt32)clientNotification;
(*clientNotification->notificationProc)
((IDHGenericEvent*)&connectionEvent,
clientNotification->userData);
break;
default:
RecordEventLogger( 'isoc', 'post', '????', event);
break;
}
}
}
}
RecordEventLogger( 'isoc', 'post', 'end ', event);
return error;
}
static void deviceMessage(void * refcon, io_service_t service,
natural_t messageType, void *messageArgument)
{
if(messageType == kIOMessageServiceIsTerminated) {
DeviceDescriptionPtr deviceDescriptionPtr = (DeviceDescriptionPtr)refcon;
if(deviceDescriptionPtr->deviceControlInstance) {
DeviceControlDisableAVCTransactions(deviceDescriptionPtr->deviceControlInstance);
DeviceControlSetDeviceConnectionID(deviceDescriptionPtr->deviceControlInstance,
kIDHInvalidDeviceID);
}
if(deviceDescriptionPtr->fConnection) {
IOServiceClose(deviceDescriptionPtr->fConnection);
deviceDescriptionPtr->fConnection = NULL;
}
if(deviceDescriptionPtr->fNotification) {
IOObjectRelease(deviceDescriptionPtr->fNotification);
deviceDescriptionPtr->fNotification = NULL;
}
if(deviceDescriptionPtr->fID) {
IOObjectRelease(deviceDescriptionPtr->fID);
deviceDescriptionPtr->fID = NULL;
}
postEvent(deviceDescriptionPtr->fGlobals, (IDHDeviceID)deviceDescriptionPtr, kIDHEventDeviceRemoved);
}
}
static OSStatus registerDevice(DeviceDescriptionPtr pDeviceDescription)
{
OSStatus err = noErr;
return err;
}
static OSStatus findBuffers(DeviceDescription *deviceDescriptionPtr)
{
unsigned int size;
int nFrames;
vm_address_t *buffs;
vm_size_t shmemSize;
int i;
OSStatus result = noErr;
size = 0;
nFrames = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection,
kDVGetNumOutputFrames, NULL, 0, NULL, &size);
if(nFrames < 0)
return nFrames;
buffs = (vm_address_t *)NewPtr(nFrames * sizeof(vm_address_t));
if(!buffs)
return MemError();
for(i=0; i<nFrames; i++) {
result = IOConnectMapMemory(deviceDescriptionPtr->fConnection,i,mach_task_self(),
&buffs[i],&shmemSize,kIOMapAnywhere);
FailIf(result != noErr, Exit);
bzero((void *)buffs[i], shmemSize);
}
result = IOConnectMapMemory(deviceDescriptionPtr->fConnection,kDVNumOutputFrames+4,mach_task_self(),
(vm_address_t *)&deviceDescriptionPtr->fSharedVars,&shmemSize,kIOMapAnywhere);
FailIf(result != noErr, Exit);
deviceDescriptionPtr->fNumOutputFrames = nFrames;
deviceDescriptionPtr->bufMem = buffs;
deviceDescriptionPtr->fBufSize = (deviceDescriptionPtr->standard == ntscIn)?
kNTSCCompressedBufferSize:kPALCompressedBufferSize;
Exit:
return result;
}
static OSStatus enableRead(DeviceDescription *deviceDescriptionPtr)
{
unsigned int size;
OSStatus result;
findBuffers(deviceDescriptionPtr);
size = 0;
result = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection,
kDVReadStart, NULL, 0, NULL, &size);
if(result == noErr) {
deviceDescriptionPtr->fOldDrop = deviceDescriptionPtr->fSharedVars->fDroppedFrames;
}
return result;
}
static OSStatus disableRead(DeviceDescription *deviceDescriptionPtr)
{
unsigned int size;
OSStatus result;
size = 0;
result = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection,
kDVReadStop, NULL, 0, NULL, &size);
return result;
}
static OSStatus enableWrite(DeviceDescription *deviceDescriptionPtr)
{
unsigned int size;
OSStatus result;
vm_size_t shmemSize;
int mode;
findBuffers(deviceDescriptionPtr);
size = 0;
mode = deviceDescriptionPtr->fOutputMode;
result = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection,
kDVSetWriteSignalMode, &mode, 1, NULL, &size);
{
int i;
result = IOConnectMapMemory(deviceDescriptionPtr->fConnection,kDVNumOutputFrames+5,mach_task_self(),
(vm_address_t *)&deviceDescriptionPtr->fSharedWriteVars,&shmemSize,kIOMapAnywhere);
FailIf(result != noErr, Exit);
deviceDescriptionPtr->fOldWriteTimeStamps =
(UInt32 *)NewPtr(deviceDescriptionPtr->fSharedWriteVars->fNumGroups*sizeof(UInt32));
for(i=0; i<deviceDescriptionPtr->fSharedWriteVars->fNumGroups; i++) {
deviceDescriptionPtr->fOldWriteTimeStamps[i] = deviceDescriptionPtr->fSharedWriteVars->fGroupData[i].fTimeStamp;
}
deviceDescriptionPtr->fDCLReadPos = 0;
deviceDescriptionPtr->fBufWritePos = 0;
deviceDescriptionPtr->fFrameBufferPos = 0;
deviceDescriptionPtr->fDCLSavedWritePos = NULL;
deviceDescriptionPtr->fDCLSavedPacketNum = 0;
result = IOConnectMapMemory(deviceDescriptionPtr->fConnection,kDVNumOutputFrames+6,mach_task_self(),
&deviceDescriptionPtr->fDCLBuffer,&shmemSize,kIOMapAnywhere);
FailIf(result != noErr, Exit);
}
deviceDescriptionPtr->fWaitingStartWrite = 1;
deviceDescriptionPtr->fSharedVars->fReader = deviceDescriptionPtr->fSharedVars->fWriter = 0;
deviceDescriptionPtr->fOldDrop = deviceDescriptionPtr->fSharedVars->fDroppedFrames;
deviceDescriptionPtr->fOldRead = deviceDescriptionPtr->fSharedVars->fReader;
Exit:
syslog(LOG_INFO, "enable write, result %x\n", result);
return result;
}
static OSStatus disableWrite(DeviceDescription *deviceDescriptionPtr)
{
unsigned int size;
OSStatus result;
size = 0;
result = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection,
kDVWriteStop, NULL, 0, NULL, &size);
if(deviceDescriptionPtr->fOldWriteTimeStamps) {
DisposePtr((Ptr)deviceDescriptionPtr->fOldWriteTimeStamps);
deviceDescriptionPtr->fOldWriteTimeStamps = NULL;
}
syslog(LOG_INFO, "disable write\n");
return result;
}
static OSStatus sendMsg(IsochComponentInstancePtr ih, UInt32 request, void *params)
{
IsochComponentGlobalsPtr g = &globals;
SendMsg msg;
bzero( &msg, sizeof(msg));
msg.msgHdr.msgh_remote_port = g->fNotifyMachPort;
msg.msgHdr.msgh_bits = MACH_MSGH_BITS(
MACH_MSG_TYPE_COPY_SEND,
MACH_MSG_TYPE_COPY_SEND );
msg.msgHdr.msgh_size = sizeof(msg);
msg.msgHdr.msgh_id = kDVRequestID;
msg.dvRequest.fRequest = request;
msg.dvRequest.fInstance = ih;
msg.dvRequest.fParams = params;
return mach_msg(&msg.msgHdr, MACH_SEND_MSG,
msg.msgHdr.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
}
static OSStatus addDevice(IsochComponentGlobalsPtr g, io_object_t obj, DeviceDescriptionPtr *deviceIDPtr)
{
OSErr result = noErr;
QTAtom deviceAtom, isocAtom;
DeviceDescriptionPtr deviceDescriptionPtr;
IDHDeviceStatus deviceStatus;
UInt32 standard;
Boolean hasSDL;
UInt32 devIndex;
UInt64 newGUID;
ComponentDescription clkDesc;
CFDictionaryRef properties;
CFNumberRef dataDesc;
CFBooleanRef ntscDesc;
CFBooleanRef sdlDesc;
RecordEventLogger( 'isoc', 'addv', (int)g, obj);
++g->seed;
result = IORegistryEntryCreateCFProperties(obj, &properties, kCFAllocatorDefault, kNilOptions);
if(result != noErr)
return result;
dataDesc = (CFNumberRef)CFDictionaryGetValue(properties, CFSTR("GUID"));
CFNumberGetValue(dataDesc, kCFNumberSInt64Type, &newGUID);
ntscDesc = (CFBooleanRef)CFDictionaryGetValue(properties, CFSTR("NTSC"));
standard = ntscIn;
if(ntscDesc && ! CFBooleanGetValue(ntscDesc)) {
standard = palIn;
}
sdlDesc = (CFBooleanRef)CFDictionaryGetValue(properties, CFSTR("SDL"));
hasSDL = false;
if(sdlDesc && CFBooleanGetValue(sdlDesc)) {
hasSDL = true;
}
CFRelease(properties);
for( devIndex=0; devIndex < g->nDevices; ++devIndex) {
deviceDescriptionPtr = &g->deviceDescription[devIndex];
if (newGUID == deviceDescriptionPtr->fGUID) {
deviceDescriptionPtr->fID = obj;
*deviceIDPtr = deviceDescriptionPtr;
if(deviceDescriptionPtr->fConnected) {
int numFrames;
unsigned int size;
result = IOServiceOpen(deviceDescriptionPtr->fID, mach_task_self(), 11,
&deviceDescriptionPtr->fConnection);
if (result != kIOReturnSuccess) {
return result;
}
#if 0
numFrames = 10;
size = 0;
io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection,
kDVSetNumOutputFrames, &numFrames, 1, NULL, &size);
#endif
if(deviceDescriptionPtr->readLocks) {
enableRead(deviceDescriptionPtr);
}
if(deviceDescriptionPtr->writeLocks) {
enableWrite(deviceDescriptionPtr);
}
}
return noErr; }
}
do {
Str255 cameraName;
deviceDescriptionPtr = &g->deviceDescription[g->nDevices];
deviceDescriptionPtr->fGlobals = g;
deviceDescriptionPtr->fID = obj;
#ifdef DRAWRINGBUFFERGRAPH
deviceDescriptionPtr->fScreenBaseAddr = 0;
#endif
result = registerDevice(deviceDescriptionPtr);
if(noErr != result)
break;
RecordEventLogger( 'isoc', 'updt', 'add ', 'reg ');
g->nDevices++;
deviceDescriptionPtr->fGUID = newGUID;
deviceDescriptionPtr->standard = standard;
deviceDescriptionPtr->active = true;
deviceDescriptionPtr->fHasSDL = hasSDL;
clkDesc.componentType = clockComponentType;
clkDesc.componentSubType = 'fwcy';
clkDesc.componentManufacturer = 'appl';
clkDesc.componentFlags = 0L;
clkDesc.componentFlagsMask = 0L;
deviceDescriptionPtr->clock = FindNextComponent( deviceDescriptionPtr->clock, &clkDesc); FailMessage( deviceDescriptionPtr->clock == nil);
result = QTNewAtomContainer( &deviceDescriptionPtr->deviceContainer);
if( result != noErr)break;
result = QTInsertChild( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType,
(long) deviceDescriptionPtr, 0, 0, nil, &deviceAtom);
if( result != noErr)break;
result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHUniqueIDType,
0, 0, sizeof(newGUID), &newGUID, nil);
if( result != noErr)break;
result = cameraNameLookup(deviceDescriptionPtr, cameraName);
if( result != noErr)break;
result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHNameAtomType,
0, 0, cameraName[0] + 1, cameraName, nil);
result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHDeviceIDType,
0, 0, sizeof(deviceDescriptionPtr), &deviceDescriptionPtr, nil);
if( result != noErr)break;
deviceStatus.version = 1;
deviceStatus.physicallyConnected = true;
deviceStatus.readEnabled = false;
deviceStatus.writeEnabled = false;
deviceStatus.exclusiveAccess = false;
deviceStatus.currentBandwidth = 1;
deviceStatus.currentChannel = 0;
deviceStatus.inputStandard = standard;
deviceStatus.deviceActive = false;
result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kDVDeviceInfo,
0, 0, sizeof( IDHDeviceStatus), &deviceStatus, nil);
if( result != noErr)break;
result = QTInsertChild( deviceDescriptionPtr->deviceContainer, deviceAtom, kIDHIsochServiceAtomType,
0, 0, 0, nil, &isocAtom);
if( result != noErr)break;
result = setupVideoAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard, false);
if( result != noErr)break;
if(hasSDL) {
result = setupVideoAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard, true);
if( result != noErr)break;
}
if( standard == ntscIn)
{
result = setup48kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard);
if( result != noErr)break;
result = setup32kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard);
if( result != noErr)break;
}
else {
result = setup44kAudioAtoms( deviceDescriptionPtr->deviceContainer, isocAtom, standard);
if( result != noErr)break;
}
*deviceIDPtr = deviceDescriptionPtr;
return noErr;
} while(false);
return result;
}
static void deviceArrived(void *refcon, io_iterator_t iterator )
{
io_object_t obj;
IsochComponentGlobalsPtr ih = (IsochComponentGlobalsPtr)refcon;
while(obj = IOIteratorNext(iterator)) {
OSErr result;
DeviceDescriptionPtr deviceDescriptionPtr;
result = addDevice(ih, obj, &deviceDescriptionPtr);
if(result == noErr) {
postEvent(ih, (IDHDeviceID)deviceDescriptionPtr, kIDHEventDeviceAdded);
IOServiceAddInterestNotification(ih->fNotifyPort, deviceDescriptionPtr->fID,
kIOGeneralInterest, deviceMessage, deviceDescriptionPtr,
&deviceDescriptionPtr->fNotification);
}
}
}
#define TIMING 0
void clock_get_uptime( register AbsoluteTime *result)
{
#ifdef __ppc__
register UInt32 hic;
do {
asm volatile(" mftbu %0" : "=r" (result->hi));
asm volatile(" mftb %0" : "=r" (result->lo));
asm volatile(" mftbu %0" : "=r" (hic));
} while (hic != result->hi);
#else
result->lo = 0;
result->hi = 0;
#endif
}
#if TIMING
#define WATCHDOG 1
#if WATCHDOG
int RTThreadRunning;
AbsoluteTime startTime;
pthread_t watchThread;
static void watchdog_thread_start(IsochComponentGlobalsPtr g)
{
double divisor;
unsigned int delta;
unsigned int abs_to_ns_num;
unsigned int abs_to_ns_denom;
unsigned int proc_to_abs_num;
unsigned int proc_to_abs_denom;
unsigned long long start, stop;
int elapsed_msecs;
(void)MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom,
&proc_to_abs_num, &proc_to_abs_denom);
divisor = ((double)abs_to_ns_denom / (double)abs_to_ns_num) * 1000000;
while (1) {
if(RTThreadRunning) {
AbsoluteTime now;
clock_get_uptime(&now);
start = (((unsigned long long)startTime.hi) << 32) |
(unsigned long long)((unsigned int)(startTime.lo));
stop = (((unsigned long long)now.hi) << 32) |
(unsigned long long)((unsigned int)(now.lo));
elapsed_msecs = (int)(((double)(stop - start)) / divisor);
if(elapsed_msecs>100) {
syslog(LOG_INFO, "Thread running for %d mSec\n", elapsed_msecs);
*(int *)0 = 0xdeadbeef; }
}
usleep(30000);
}
}
#endif
#endif
static void incrementWriteBuffer(DeviceDescription *deviceDescriptionPtr)
{
deviceDescriptionPtr->fSharedVars->fWriter += 1; if(deviceDescriptionPtr->fWaitingStartWrite && deviceDescriptionPtr->fSharedVars->fWriter == 4) {
unsigned int size = 0;
io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection,
kDVWriteStart, NULL, 0, NULL, &size);
deviceDescriptionPtr->fWaitingStartWrite = 0;
}
}
static void silenceFrame(DeviceDescription *deviceDescriptionPtr, UInt8* frame)
{
UInt32 i,j,k,n;
UInt8 *tPtr;
tPtr = frame;
if ((tPtr[3] &= 0x80) == 0)
n=10; else
n=12;
if(deviceDescriptionPtr->fOutputMode & 4) n /= 2;
for (i=0;i<n;i++)
{
for (j=0;j<9;j++)
{
tPtr = frame + (i * 12000) + ((j * 16 + 6) * 80) + 8;
for (k=0;k<72;k++)
*tPtr++ = 0x0;
}
}
}
static UInt8 *getNextFrame(DeviceDescription *deviceDescriptionPtr, IsochComponentInstancePtr client, int slack, int waiting)
{
ComponentResult err;
IDHParameterBlock *pb;
pb = client->fActiveHead;
if(pb && !waiting) {
if(deviceDescriptionPtr->fWaitingStartWrite) {
unsigned int size = 0;
io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection,
kDVWriteStart, NULL, 0, NULL, &size);
deviceDescriptionPtr->fWaitingStartWrite = 0;
}
client->fActiveHead = (IDHParameterBlock *)pb->reserved1;
if(client->fActiveHead == NULL)
client->fActiveTail = NULL;
pb->actualCount = deviceDescriptionPtr->fBufSize;
pb->result = noErr;
if(pb->completionProc) {
err = pb->completionProc((IDHGenericEvent *)pb, pb->refCon);
if(err != noErr) {
syslog(LOG_INFO, "write callback for pb %p returned error %d\n", pb, err);
}
}
}
if(client->fActiveHead) {
pb = client->fActiveHead;
bcopy(pb->buffer, (UInt8 *)deviceDescriptionPtr->bufMem[0], deviceDescriptionPtr->fBufSize);
}
else {
if(slack < 3) {
deviceDescriptionPtr->fSharedVars->fDroppedFrames++;
dropMsg(deviceDescriptionPtr);
silenceFrame(deviceDescriptionPtr, (UInt8 *)deviceDescriptionPtr->bufMem[0]);
}
else {
return NULL; }
}
deviceDescriptionPtr->fFrameBufferPos = 0;
return (UInt8 *)deviceDescriptionPtr->bufMem[0];
}
static int fillDCLGroup(DeviceDescription *deviceDescriptionPtr, IsochComponentInstancePtr client, int group, int slack)
{
UInt8 *dclPtr;
UInt8 *dataPtr;
UInt32 dataSize = deviceDescriptionPtr->fSharedWriteVars->fPacketDataSize;
UInt32 packetSize = deviceDescriptionPtr->fSharedWriteVars->fAlignedPacketSize;
int i;
int start;
if(deviceDescriptionPtr->fDCLSavedWritePos != NULL) {
dclPtr = deviceDescriptionPtr->fDCLSavedWritePos;
dataPtr = getNextFrame(deviceDescriptionPtr, client, slack, true);
if(dataPtr == NULL)
return 0; deviceDescriptionPtr->fDCLSavedWritePos = NULL; start = deviceDescriptionPtr->fDCLSavedPacketNum;
deviceDescriptionPtr->fDCLSavedPacketNum = 0;
}
else {
dclPtr = (UInt8 *)deviceDescriptionPtr->fDCLBuffer + deviceDescriptionPtr->fSharedWriteVars->fGroupData[group].fDataOffset;
start = 0;
}
if(deviceDescriptionPtr->fWaitingStartWrite) {
if(!client->fActiveHead) {
return 0; }
else {
bcopy(client->fActiveHead->buffer, (UInt8 *)deviceDescriptionPtr->bufMem[0], deviceDescriptionPtr->fBufSize);
}
}
dataPtr = (UInt8 *)deviceDescriptionPtr->bufMem[0];
dataPtr += deviceDescriptionPtr->fFrameBufferPos;
for(i=start; i<deviceDescriptionPtr->fSharedWriteVars->fGroupSize; i++) {
if (((int) (dclPtr + packetSize) & 0x0fff) < packetSize) {
dclPtr += packetSize;
dclPtr = (UInt8 *)((int)dclPtr & 0xfffff000);
}
bcopy(dataPtr, dclPtr+8, dataSize);
dataPtr += dataSize;
deviceDescriptionPtr->fFrameBufferPos += dataSize;
dclPtr += packetSize;
if(deviceDescriptionPtr->fFrameBufferPos >= deviceDescriptionPtr->fBufSize) {
dataPtr = getNextFrame(deviceDescriptionPtr, client, slack, false);
if(dataPtr == NULL) {
deviceDescriptionPtr->fDCLSavedWritePos = dclPtr;
deviceDescriptionPtr->fDCLSavedPacketNum = i+1;
return 0; }
deviceDescriptionPtr->fFrameBufferPos = 0;
deviceDescriptionPtr->fDCLSavedWritePos = NULL;
deviceDescriptionPtr->fDCLSavedPacketNum = 0;
}
}
return 1;
}
static void processWrites(DeviceDescription *deviceDescriptionPtr)
{
int i;
int changed;
int done;
int pos;
int emptyBlocks;
int numGroups = deviceDescriptionPtr->fSharedWriteVars->fNumGroups;
IsochComponentInstancePtr client;
changed = 0;
client = deviceDescriptionPtr->fOpenClients[0];
pos = deviceDescriptionPtr->fDCLReadPos;
for(i=pos; i< pos+numGroups; i++) {
int mod = i % numGroups;
if(deviceDescriptionPtr->fOldWriteTimeStamps[mod] !=
deviceDescriptionPtr->fSharedWriteVars->fGroupData[mod].fTimeStamp) {
deviceDescriptionPtr->fOldWriteTimeStamps[mod] = deviceDescriptionPtr->fSharedWriteVars->fGroupData[mod].fTimeStamp;
deviceDescriptionPtr->fDCLReadPos = i;
}
}
emptyBlocks = numGroups-(deviceDescriptionPtr->fBufWritePos - deviceDescriptionPtr->fDCLReadPos);
if(emptyBlocks >= numGroups && !deviceDescriptionPtr->fWaitingStartWrite) {
syslog(LOG_INFO, "DCL wrap!!: %d\n", emptyBlocks);
}
if(emptyBlocks>3)
emptyBlocks = 3;
done = 0;
for(i=0; i<emptyBlocks; i++) {
int ok;
ok =
fillDCLGroup(deviceDescriptionPtr, client, (deviceDescriptionPtr->fBufWritePos + i) % numGroups,
deviceDescriptionPtr->fBufWritePos+done - deviceDescriptionPtr->fDCLReadPos);
if(!ok)
break;
done += ok;
}
deviceDescriptionPtr->fBufWritePos += done;
}
static int processReads(DeviceDescription *deviceDescriptionPtr)
{
int doneFrames = 0;
int frameIndex;
IsochComponentInstancePtr client;
int i;
frameIndex = deviceDescriptionPtr->fSharedVars->fReader % deviceDescriptionPtr->fNumOutputFrames;
if(deviceDescriptionPtr->fSharedVars->fReader + 1 <
deviceDescriptionPtr->fSharedVars->fWriter) {
UInt8 *buffer = (UInt8 *)deviceDescriptionPtr->bufMem[frameIndex];
UInt32 frameSize = deviceDescriptionPtr->fSharedVars->fFrameSize[frameIndex];
deviceDescriptionPtr->fBufferLocks[frameIndex]++;
if(deviceDescriptionPtr->fOldDrop < deviceDescriptionPtr->fSharedVars->fDroppedFrames) {
dropMsg(deviceDescriptionPtr);
}
for(i=0; i<kMaxDeviceClients; i++) {
client = deviceDescriptionPtr->fOpenClients[i];
if(client) {
if(client->fClientIndex != i) {
syslog(LOG_INFO, "processReads: client %p of %p index is %d not %d\n",
client, deviceDescriptionPtr, client->fClientIndex, i);
}
if(client->fHead) {
IDHParameterBlock *pb = client->fHead;
OSStatus err;
pb->actualCount = frameSize;
if(pb->buffer != nil) {
bcopy(buffer, pb->buffer, frameSize);
}
else {
deviceDescriptionPtr->fBufferLocks[frameIndex]++;
pb->buffer = buffer;
}
client->fHead = (IDHParameterBlock *)pb->reserved1;
if(client->fHead == NULL)
client->fTail = NULL;
pb->result = noErr;
err = pb->completionProc((IDHGenericEvent *)pb, pb->refCon);
if(err != noErr) {
syslog(LOG_INFO, "read callback for pb %p returned error %d\n", pb, err);
}
doneFrames++;
}
}
}
deviceDescriptionPtr->fBufferLocks[frameIndex]--;
if(doneFrames && deviceDescriptionPtr->fBufferLocks[frameIndex] == 0)
deviceDescriptionPtr->fSharedVars->fReader += 1; }
return doneFrames;
}
static void queueWrite(IsochComponentInstancePtr client, IDHParameterBlock *pb)
{
if(pb->buffer) {
if(client->fActiveTail == NULL) {
client->fActiveHead = pb;
}
else
client->fActiveTail->reserved1 = (UInt32)pb;
client->fActiveTail = pb;
}
else {
if(client->fTail == NULL)
client->fHead = pb;
else
client->fTail->reserved1 = (UInt32)pb;
client->fTail = pb;
}
pb->reserved1 = 0;
}
void processOpen(IsochComponentInstancePtr ih, DeviceDescription *deviceDescriptionPtr, UInt32 permissions)
{
ComponentResult result = noErr;
int i;
FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit);
if( ih->permissions & kIDHOpenForReadTransactions && permissions & kIDHOpenForReadTransactions)
goto Exit;
if( ih->permissions & kIDHOpenForWriteTransactions && permissions & kIDHOpenForWriteTransactions)
goto Exit;
FailWithAction( ih->permissions & kIDHOpenForReadTransactions && permissions & kIDHOpenForWriteTransactions,
result = kIDHErrDeviceInUse, Exit);
FailWithAction( ih->permissions & kIDHOpenForWriteTransactions && permissions & kIDHOpenForReadTransactions,
result = kIDHErrDeviceInUse, Exit);
if( permissions & kIDHOpenForReadTransactions)
{
FailWithAction( deviceDescriptionPtr->writeLocks, result = kIDHErrDeviceInUse, Exit);
if( deviceDescriptionPtr->readLocks == 0)
{
result = enableRead(deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
}
++deviceDescriptionPtr->readLocks; RecordEventLogger( 'open', ' Now', ih, deviceDescriptionPtr->readLocks);
}
if( permissions & kIDHOpenForWriteTransactions)
{
FailWithAction( deviceDescriptionPtr->readLocks || deviceDescriptionPtr->writeLocks,
result = kIDHErrDeviceInUse, Exit);
result = enableWrite(deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
deviceDescriptionPtr->writeLocks = 1; }
ih->permissions = permissions; for(i=0; i<kMaxDeviceClients; i++) {
if(!deviceDescriptionPtr->fOpenClients[i]) {
deviceDescriptionPtr->fOpenClients[i] = ih;
ih->fClientIndex = i;
break;
}
}
Exit:
ih->fSyncResult = result;
signalSync(&ih->fSyncRequest, 1);
}
void processClose(IsochComponentInstancePtr ih, DeviceDescription *deviceDescriptionPtr)
{
if( ih->permissions & kIDHOpenForReadTransactions) {
if( --deviceDescriptionPtr->readLocks <= 0) {
disableRead(deviceDescriptionPtr);
}
}
if( ih->permissions & kIDHOpenForWriteTransactions) {
if( --deviceDescriptionPtr->writeLocks <= 0) {
disableWrite(deviceDescriptionPtr);
}
}
deviceDescriptionPtr->fOpenClients[ih->fClientIndex] = nil;
ih->fSyncResult = noErr;
signalSync(&ih->fSyncRequest, 1);
}
static void processCancelPendingIO(IsochComponentInstancePtr client)
{
while(client->fHead) {
IDHParameterBlock *pb = client->fHead;
client->fHead = (IDHParameterBlock *)pb->reserved1;
pb->reserved1 = NULL;
}
client->fTail = NULL;
}
static void DVIsoch_thread_start(IsochComponentGlobalsPtr g)
{
ReceiveMsg msg;
kern_return_t err;
int delay;
#if TIMING
double divisor;
int worst_sched = 0;
int worst_callback = 0;
int worst_msg = 0;
{
unsigned int delta;
unsigned int abs_to_ns_num;
unsigned int abs_to_ns_denom;
unsigned int proc_to_abs_num;
unsigned int proc_to_abs_denom;
(void)MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom,
&proc_to_abs_num, &proc_to_abs_denom);
divisor = ((double)abs_to_ns_denom / (double)abs_to_ns_num) * 1000000;
}
#endif
deviceArrived(g, g->fMatchEnumer);
signalSync(&g->fGlobalsState, 1);
delay = 15; while(true) {
int dev;
#if TIMING
AbsoluteTime timestamp1;
AbsoluteTime timestamp2;
unsigned long long start, stop;
int elapsed_msecs;
#endif
DeviceDescription *deviceDescriptionPtr;
for(dev = 0; dev<g->nDevices; dev++) {
deviceDescriptionPtr = &g->deviceDescription[dev];
if(deviceDescriptionPtr) {
#if TIMING
clock_get_uptime(×tamp1);
#endif
if(deviceDescriptionPtr->writeLocks)
processWrites(deviceDescriptionPtr);
if(deviceDescriptionPtr->readLocks)
processReads(deviceDescriptionPtr);
#if TIMING
clock_get_uptime(×tamp2);
start = (((unsigned long long)timestamp1.hi) << 32) |
(unsigned long long)((unsigned int)(timestamp1.lo));
stop = (((unsigned long long)timestamp2.hi) << 32) |
(unsigned long long)((unsigned int)(timestamp2.lo));
elapsed_msecs = (int)(((double)(stop - start)) / divisor);
if(elapsed_msecs > worst_callback) {
pKGSysCall_Insert (kIOFWDVTrace, 'call', elapsed_msecs, 0, 0, 0, 0);
syslog(LOG_INFO, "callback delay %d mSec\n",
elapsed_msecs);
worst_callback = elapsed_msecs;
}
#endif
}
}
#if TIMING
clock_get_uptime(×tamp1);
#if WATCHDOG
RTThreadRunning=0;
#endif
#endif
err = mach_msg(&msg.msgHdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT,
0, sizeof(msg), g->fNotifyMachPort, delay, MACH_PORT_NULL);
#if TIMING
#if WATCHDOG
clock_get_uptime(&startTime);
RTThreadRunning=1;
#endif
clock_get_uptime(×tamp2);
start = (((unsigned long long)timestamp1.hi) << 32) |
(unsigned long long)((unsigned int)(timestamp1.lo));
stop = (((unsigned long long)timestamp2.hi) << 32) |
(unsigned long long)((unsigned int)(timestamp2.lo));
elapsed_msecs = (int)(((double)(stop - start)) / divisor);
if(elapsed_msecs > worst_sched) {
pKGSysCall_Insert (kIOFWDVTrace, 'schd', elapsed_msecs, 0, 0, 0, 0);
syslog(LOG_INFO, "schedule delay %d mSec\n",
elapsed_msecs);
worst_sched = elapsed_msecs;
}
#endif
if(err == MACH_MSG_SUCCESS) {
IsochComponentInstancePtr client;
switch (msg.msgHdr.msgh_id) {
case kOSNotificationMessageID:
IODispatchCalloutFromMessage(NULL, &msg.msgHdr, g->fNotifyPort);
break;
case kDVRequestID:
client = msg.body.dvRequest.fInstance;
deviceDescriptionPtr = (DeviceDescriptionPtr)client->deviceID;
switch(msg.body.dvRequest.fRequest) {
case kComponentCloseSelect:
pthread_exit(NULL);
break;
case kIDHReadSelect:
{
IDHParameterBlock *pbNew = (IDHParameterBlock *)msg.body.dvRequest.fParams;
if(client) {
if(client->fTail == NULL)
client->fHead = pbNew;
else
client->fTail->reserved1 = (UInt32)pbNew;
client->fTail = pbNew;
}
pbNew->reserved1 = 0;
break;
}
case kIDHWriteSelect:
{
IDHParameterBlock *pbNew = (IDHParameterBlock *)msg.body.dvRequest.fParams;
if(client) {
queueWrite(client, pbNew);
}
break;
}
case kIDHCancelPendingIOSelect:
if(client) {
processCancelPendingIO(client);
}
client->fSyncResult = noErr;
signalSync(&client->fSyncRequest, 1);
break;
case kIDHCloseDeviceSelect:
processClose(client, deviceDescriptionPtr);
break;
case kIDHOpenDeviceSelect:
processOpen(client, deviceDescriptionPtr, (UInt32)msg.body.dvRequest.fParams);
break;
default:
printf("DVIsoch : Unknown DVRequest %ld, params %p\n", msg.body.dvRequest.fRequest, msg.body.dvRequest.fParams);
}
break;
default:
printf("DVIsoch : Unexpected msg id %d\n", msg.msgHdr.msgh_id);
}
#if TIMING
clock_get_uptime(×tamp1);
start = (((unsigned long long)timestamp2.hi) << 32) |
(unsigned long long)((unsigned int)(timestamp2.lo));
stop = (((unsigned long long)timestamp1.hi) << 32) |
(unsigned long long)((unsigned int)(timestamp1.lo));
elapsed_msecs = (int)(((double)(stop - start)) / divisor);
if(elapsed_msecs > worst_msg) {
pKGSysCall_Insert (kIOFWDVTrace, 'msg ', elapsed_msecs, 0, 0, 0, 0);
syslog(LOG_INFO, "message process delay %d mSec for message %d (%d)\n",
elapsed_msecs, msg.msgHdr.msgh_id, msg.body.dvRequest.fRequest);
worst_msg = elapsed_msecs;
}
#endif
}
else if(err != MACH_RCV_TIMED_OUT) {
printf("DVIsoch : Receive err 0x%x, size %d(max %ld)\n", err, msg.msgHdr.msgh_size, sizeof(msg));
}
}
}
static pascal ComponentResult
FWDVComponentOpen(IsochComponentInstancePtr storage, ComponentInstance self)
{
kern_return_t err = noErr;
IsochComponentGlobalsPtr g = &globals;
RecordEventLogger( 'isoc', 'open', 0, 0);
if( nil == (storage = (IsochComponentInstancePtr)NewPtrClear(sizeof(IsochComponentInstance))))
return(MemError());
RecordEventLogger( 'isoc', 'ope2', (int)storage, 0);
SetComponentInstanceStorage(self, (Handle) storage);
if (!g->fMasterDevicePort) {
policy_base_data_t thePolicyBase;
host_priority_info_data_t priorityDefaults;
int count;
err = IOMasterPort(bootstrap_port, &g->fMasterDevicePort);
if (err != KERN_SUCCESS) {
RecordEventLogger( 'isoc', 'opep', (int)err, 0);
return err;
}
g->fNotifyPort = IONotificationPortCreate(g->fMasterDevicePort);
g->fNotifyMachPort = IONotificationPortGetMachPort(g->fNotifyPort);
err = IOServiceAddMatchingNotification( g->fNotifyPort,
kIOMatchedNotification, IOServiceMatching( kDVKernelDriverName ),
deviceArrived, g, &g->fMatchEnumer );
if (err != kIOReturnSuccess) {
return err;
}
err = mach_port_insert_right(mach_task_self(), g->fNotifyMachPort, g->fNotifyMachPort,
MACH_MSG_TYPE_MAKE_SEND);
FailWithVal( err != noErr, Exit, err);
g->fGlobalsState = 0;
err = pthread_mutex_init(&g->fGlobalsMutex, NULL);
FailWithVal( err != noErr, Exit, err);
err = pthread_cond_init(&g->fSyncCond, NULL);
FailWithVal( err != noErr, Exit, err);
err = pthread_attr_init(&g->fThreadAttr);
FailWithVal( err != noErr, Exit, err);
err = pthread_create(&g->fWorkThread, &g->fThreadAttr,
(void *)DVIsoch_thread_start, g);
FailWithVal( err != noErr, Exit, err);
#if 0
count = HOST_PRIORITY_INFO_COUNT;
err = host_info ( mach_host_self(), HOST_PRIORITY_INFO, (host_info_t)&priorityDefaults, &count);
FailWithVal( err != noErr, Exit, err);
thePolicyBase.rr.base_priority = priorityDefaults.user_priority; thePolicyBase.rr.quantum = 10;
err = thread_policy (pthread_mach_thread_np(g->fWorkThread),
POLICY_RR, (policy_base_t)&thePolicyBase.rr, POLICY_RR_BASE_COUNT, FALSE );
#endif
#if 1
{
double mult;
unsigned int delta;
unsigned int abs_to_ns_num;
unsigned int abs_to_ns_denom;
unsigned int proc_to_abs_num;
unsigned int proc_to_abs_denom;
thread_time_constraint_policy_data_t constraints;
(void)MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom,
&proc_to_abs_num, &proc_to_abs_denom);
mult = ((double)abs_to_ns_denom / (double)abs_to_ns_num) * 1000000;
constraints.period = 15*mult;
constraints.computation = 2*mult;
constraints.constraint = 30*mult;
constraints.preemptible = TRUE;
err = thread_policy_set(pthread_mach_thread_np(g->fWorkThread), THREAD_TIME_CONSTRAINT_POLICY,
(thread_policy_t)&constraints, THREAD_TIME_CONSTRAINT_POLICY_COUNT);
#if WATCHDOG
if(watchThread == 0) {
err = pthread_create(&watchThread, &g->fThreadAttr,
(void *)watchdog_thread_start, g);
constraints.period = 30*mult;
constraints.computation = 1*mult;
constraints.constraint = 30*mult;
constraints.preemptible = TRUE;
err = thread_policy_set(pthread_mach_thread_np(watchThread), THREAD_TIME_CONSTRAINT_POLICY,
(thread_policy_t)&constraints, THREAD_TIME_CONSTRAINT_POLICY_COUNT);
}
#endif
}
#endif
#if 0
thePolicyBase.ts.base_priority = 72;
err = thread_policy(pthread_mach_thread_np(g->fWorkThread),
POLICY_TIMESHARE, (policy_base_t)&thePolicyBase.ts,
POLICY_TIMESHARE_BASE_COUNT, TRUE);
#endif
FailWithVal( err != noErr, Exit, err);
}
waitSync(&g->fGlobalsState);
g->fNumInstances++;
Exit:
return( err );
}
static pascal ComponentResult
FWDVComponentClose(IsochComponentInstancePtr ih, ComponentInstance self)
{
int i;
IsochComponentGlobalsPtr g = &globals;
RecordEventLogger( 'isoc', 'clos', ih, self);
if( !ih)
return( noErr );
if(ih->hasDeviceControl) {
DeviceDescriptionPtr deviceDescriptionPtr;
if(findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr) == noErr)
closeDeviceControl( ih, deviceDescriptionPtr);
}
if( ih->permissions )
FWDVIDHCloseDevice(ih);
g->fNumInstances--;
if(g->fNumInstances == 0) {
if(g->fWorkThread) {
void *status;
int err;
sendMsg(ih, kComponentCloseSelect, ih);
err = pthread_join(g->fWorkThread, &status);
}
for(i=0; i<g->nDevices; i++) {
DeviceDescriptionPtr dev = &g->deviceDescription[i];
if(dev->fConnection) {
IOConnectRelease(dev->fConnection);
dev->fConnection = NULL;
}
dev->fConnected = 0;
if(dev->fNotification) {
IOObjectRelease(dev->fNotification);
dev->fNotification = NULL;
}
if(dev->fID) {
IOObjectRelease(dev->fID);
dev->fID = NULL;
}
}
if(g->fMatchEnumer)
IOObjectRelease(g->fMatchEnumer);
if(g->fNotifyPort)
IONotificationPortDestroy(g->fNotifyPort);
g->fGlobalsState = 0;
g->fMasterDevicePort = NULL;
}
DisposePtr((Ptr) ih);
SetComponentInstanceStorage(self, (Handle) nil );
RecordEventLogger( 'isoc', 'clos', 'end ', 0);
return( noErr );
}
static pascal ComponentResult
FWDVComponentVersion(IsochComponentInstancePtr storage)
{
RecordEventLogger( 'isoc', 'vers', 0, 0);
return 0x10001;
}
static pascal ComponentResult
FWDVComponentRegister(IsochComponentInstancePtr storage)
{
RecordEventLogger( 'isoc', 'reg ', 0, 0);
return( noErr );
}
static pascal ComponentResult
FWDVIDHGetDeviceList(IsochComponentInstancePtr storage,
QTAtomContainer *deviceList )
{
OSErr result = noErr;
QTAtomContainer container = nil;
int devIndex;
UInt32 version;
IsochComponentGlobalsPtr g = &globals;
RecordEventLogger( 'isoc', 'get ', 'dev ', 'list');
do {
result = QTNewAtomContainer( &container);
if(result != noErr)
break;
result = QTInsertChild( container, kParentAtomIsContainer, kIDHSeedAtomType, 0, 0,
sizeof( g->seed), &g->seed, nil);
if(result != noErr)
break;
version = (DVVersion << 24) | (DVRevision << 16) | DVBuildNumber;
result = QTInsertChild( container, kParentAtomIsContainer, kIDHIsochVersionAtomType, 0, 0,
sizeof( UInt32), &version, nil);
if(result != noErr)
break;
result = QTInsertChild( container, kParentAtomIsContainer, kIDHUseCMPAtomType, 0, 0,
sizeof( UInt32), &g->useCMP, nil);
if(result != noErr)
break;
for( devIndex=0; devIndex<kMaxDevicesActive; ++devIndex)
{
if( g->deviceDescription[devIndex].fID != 0 && g->deviceDescription[devIndex].active)
{
result = QTInsertChildren( container, kParentAtomIsContainer,
g->deviceDescription[devIndex].deviceContainer);
if(result != noErr)
break;
}
}
*deviceList = container;
return noErr;
} while (false);
if(container) {
QTRemoveChildren( container, kParentAtomIsContainer);
QTDisposeAtomContainer( container);
}
return result;
}
static pascal ComponentResult
FWDVIDHSetDeviceConfiguration(IsochComponentInstancePtr ih,
const QTAtomSpec *configID)
{
OSErr result = noErr;
QTAtomSpec volatileAtomSpec;
QTAtom nameAtom;
IDHDeviceID previousDeviceID;
DeviceDescription *deviceDescriptionPtr;
IsochComponentGlobalsPtr g = &globals;
Boolean isSDL;
int numFrames;
unsigned int size;
RecordEventLogger( 'isoc', 'set ', 'conf', ih);
FailWithAction( configID == nil, result = paramErr, Exit);
FailWithAction( configID->container == nil, result = paramErr, Exit);
if( configID->container == ih->currentConfig.container &&
configID->atom == ih->currentConfig.atom)
goto Exit;
FailWithAction( ih->permissions != 0, result = kIDHErrDeviceInUse, Exit);
previousDeviceID = ih->deviceID;
volatileAtomSpec = *configID;
result = getDeviceID( &volatileAtomSpec, &ih->deviceID);
FailWithVal( result != noErr, Exit, result);
result = checkSeed( g, &volatileAtomSpec);
FailWithVal( result != noErr, Exit, result);
ih->currentConfig = *configID;
nameAtom = QTFindChildByIndex( configID->container, configID->atom, kIDHNameAtomType, 1, nil);
if( nameAtom != nil) {
Str255 name;
long size;
QTCopyAtomDataToPtr( configID->container, nameAtom, true, 255, name, &size);
isSDL = !strncmp(name, "\pDV-SDL", *name);
}
else
isSDL = false;
result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
if(deviceDescriptionPtr->fConnection == NULL) {
result = IOServiceOpen(deviceDescriptionPtr->fID, mach_task_self(), 11,
&deviceDescriptionPtr->fConnection);
if (result != kIOReturnSuccess) {
goto Exit;
}
#if 0
numFrames = 10;
size = 0;
io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection,
kDVSetNumOutputFrames, &numFrames, 1, NULL, &size);
#endif
deviceDescriptionPtr->fConnected = 1;
}
FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit);
if( previousDeviceID && previousDeviceID != ih->deviceID) {
DeviceDescription *deviceDescriptionPtr2;
result = findDeviceDescriptionforDevice( ih, previousDeviceID, &deviceDescriptionPtr2);
FailWithVal( result != noErr, Exit, result);
if(deviceDescriptionPtr2->fConnection) {
IOConnectRelease(deviceDescriptionPtr2->fConnection);
deviceDescriptionPtr2->fConnection = nil;
}
if(ih->hasDeviceControl) {
result = closeDeviceControl( ih, deviceDescriptionPtr2);
FailMessage( result != noErr);
ih->hasDeviceControl = false;
}
}
deviceDescriptionPtr->fOutputMode = 0;
if(isSDL)
deviceDescriptionPtr->fOutputMode |= 4;
if(deviceDescriptionPtr->standard != ntscIn)
deviceDescriptionPtr->fOutputMode |= 0x80;
Exit:
RecordEventLogger( 'isoc', 'set ', 'Exit', ih);
return result;
}
static pascal ComponentResult
FWDVIDHOpenDevice(IsochComponentInstancePtr ih, UInt32 permissions)
{
ComponentResult result = noErr;
IsochComponentGlobalsPtr g = &globals;
RecordEventLogger( 'open', ' dev', ih, permissions);
FailWithAction( permissions == 0, result = paramErr, Exit);
FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
ih->fSyncRequest = 0;
result = sendMsg(ih, kIDHOpenDeviceSelect, (void *)permissions);
waitSync(&ih->fSyncRequest);
result = ih->fSyncResult;
FailWithVal( result != noErr, Exit, result);
result = postEvent( g, ih->deviceID,
(permissions & kIDHOpenForReadTransactions)?kIDHEventReadEnabled:kIDHEventWriteEnabled);
FailWithVal( result != noErr, Exit, result);
#ifdef DRAWRINGBUFFERGRAPH
SetUpBlitGlobals((DeviceDescription *)ih->deviceID);
#endif
Exit:
return result;
}
static pascal ComponentResult
FWDVIDHCloseDevice(IsochComponentInstancePtr ih)
{
OSErr result = noErr;
DeviceDescription *deviceDescriptionPtr;
IsochComponentGlobalsPtr g = &globals;
RecordEventLogger( 'isoc', 'clos', ' dev', ih);
FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
if( ih->permissions == 0) goto Exit;
result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result);
if(globals.fWorkThread == pthread_self()) {
processClose(ih, deviceDescriptionPtr);
result = noErr;
}
else {
ih->fSyncRequest = 0;
result = sendMsg(ih, kIDHCloseDeviceSelect, 0);
waitSync(&ih->fSyncRequest);
result = ih->fSyncResult;
FailWithVal( result != noErr, Exit, result);
}
result = postEvent( g, ih->deviceID,
(ih->permissions & kIDHOpenForReadTransactions)?kIDHEventReadDisabled:kIDHEventWriteDisabled);
FailWithVal( result != noErr, Exit, result);
Exit:
ih->permissions = 0; ih->fClientIndex = 0xdead;
return result;
}
static pascal ComponentResult
FWDVIDHGetDeviceConfiguration(IsochComponentInstancePtr ih, QTAtomSpec *configID )
{
OSErr result = noErr;
RecordEventLogger( 'isoc', 'get ', 'dev ', 'conf');
FailWithAction( configID == nil, result = paramErr, Exit);
FailWithAction( ih->currentConfig.container == nil || ih->currentConfig.atom == nil,
result = kIDHErrDeviceNotConfigured, Exit);
*configID = ih->currentConfig;
Exit:
return result;
}
static pascal ComponentResult
FWDVIDHGetDeviceStatus(IsochComponentInstancePtr ih, const QTAtomSpec *devSpec, IDHDeviceStatus *status )
{
OSErr result = noErr;
IDHDeviceID deviceID = nil;
QTAtom deviceInfoAtom, deviceAtom;
QTAtomSpec volatileAtomSpec;
long size;
DeviceDescription *deviceDescriptionPtr;
IsochComponentGlobalsPtr g = &globals;
RecordEventLogger( 'isoc', 'get ', 'stat', ih);
FailWithAction( devSpec == nil, result = paramErr, Exit);
FailWithAction( status == nil, result = paramErr, Exit);
volatileAtomSpec = *devSpec;
result = checkSeed( g, &volatileAtomSpec);
if( result != noErr)
goto Exit;
result = getDeviceID( &volatileAtomSpec, &deviceID);
FailWithVal( result != noErr, Exit, result);
result = findDeviceDescriptionforDevice( ih, deviceID, &deviceDescriptionPtr); FailWithVal( result != noErr, Exit, result);
deviceAtom = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType, 1, nil);
FailWithAction( deviceAtom == nil, result = kIDHErrDeviceList, Exit);
deviceInfoAtom = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, deviceAtom, kDVDeviceInfo, 1, nil);
FailWithAction( deviceInfoAtom == nil, result = kIDHErrDeviceList, Exit);
QTLockContainer( deviceDescriptionPtr->deviceContainer);
QTCopyAtomDataToPtr( deviceDescriptionPtr->deviceContainer, deviceInfoAtom, true, sizeof( IDHDeviceStatus),
status, &size);
QTUnlockContainer( deviceDescriptionPtr->deviceContainer);
status->version = 100;
status->physicallyConnected = true;
status->readEnabled = deviceDescriptionPtr->readLocks;
status->writeEnabled = deviceDescriptionPtr->writeLocks;
status->exclusiveAccess = 0; status->currentBandwidth = 0;
status->currentChannel = 0;
status->deviceActive = deviceDescriptionPtr->active;
status->inputStandard = deviceDescriptionPtr->standard;
status->localNodeID = (PsuedoID) deviceDescriptionPtr->fID;
result = QTSetAtomData( deviceDescriptionPtr->deviceContainer, deviceInfoAtom, sizeof( IDHDeviceStatus), status);
FailWithVal( result != noErr, Exit, result);
Exit:
return result;
}
static pascal ComponentResult
FWDVIDHGetDeviceClock(IsochComponentInstancePtr ih, Component *clock )
{
DeviceDescription *deviceDescriptionPtr;
OSErr result = noErr;
RecordEventLogger( 'isoc', 'get ', 'clok', 0);
FailWithAction( clock == nil, result = paramErr, Exit);
FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
*clock = deviceDescriptionPtr->clock;
Exit:
return result;
}
static pascal ComponentResult
FWDVIDHRead(IsochComponentInstancePtr ih, IDHParameterBlock *pb)
{
OSErr result = noErr;
DeviceDescription *deviceDescriptionPtr;
RecordEventLogger( 'isoc', 'read', (unsigned long) ih, (unsigned long) pb );
FailWithAction( pb == nil, result = paramErr, Exit);
FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
FailWithAction( !(ih->permissions & kIDHOpenForReadTransactions), result = kIDHErrDeviceNotOpened, Exit);
result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit);
if( pb->completionProc == nil) {
int frameIndex = deviceDescriptionPtr->fSharedVars->fReader % deviceDescriptionPtr->fNumOutputFrames;
UInt8 *buffer = (UInt8 *)deviceDescriptionPtr->bufMem[frameIndex];
UInt32 frameSize;
if( deviceDescriptionPtr->fOldDrop <
deviceDescriptionPtr->fSharedVars->fDroppedFrames) {
dropMsg(deviceDescriptionPtr);
}
while (deviceDescriptionPtr->fSharedVars->fReader + 1 >= deviceDescriptionPtr->fSharedVars->fWriter)
{
usleep(15000); }
frameSize = deviceDescriptionPtr->fSharedVars->fFrameSize[frameIndex];
pb->actualCount = frameSize;
if(pb->buffer != nil) {
bcopy(buffer, pb->buffer, frameSize);
deviceDescriptionPtr->fSharedVars->fReader += 1; }
else
pb->buffer = buffer;
pb->result = noErr;
}
else {
pb->result = kIDHErrCompletionPending;
result = sendMsg(ih, kIDHReadSelect, pb);
}
Exit:
#ifdef DRAWRINGBUFFERGRAPH
BlitBufferGraph(deviceDescriptionPtr);
#endif
return result;
}
static pascal ComponentResult
FWDVIDHReleaseBuffer(IsochComponentInstancePtr ih, IDHParameterBlock *pb)
{
OSErr result = noErr;
int frameIndex;
DeviceDescription *deviceDescriptionPtr;
RecordEventLogger( 'isoc', 'rele', 'ase ', 'buff');
FailWithAction( pb == nil, result = paramErr, Exit);
FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
frameIndex = deviceDescriptionPtr->fSharedVars->fReader % deviceDescriptionPtr->fNumOutputFrames;
if(pb->buffer == (Ptr)deviceDescriptionPtr->bufMem[frameIndex]) {
if(--deviceDescriptionPtr->fBufferLocks[frameIndex] == 0)
deviceDescriptionPtr->fSharedVars->fReader += 1; }
Exit:
return result;
}
static pascal ComponentResult
FWDVIDHCancelPendingIO(IsochComponentInstancePtr ih, IDHParameterBlock *pb)
{
OSErr result = noErr;
DeviceDescription *deviceDescriptionPtr;
RecordEventLogger( 'isoc', 'canc', 'elIO', 0);
FailWithAction( pb == nil, result = paramErr, Exit);
FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
if(globals.fWorkThread == pthread_self()) {
processCancelPendingIO(ih);
result = noErr;
}
else {
ih->fSyncRequest = 0;
result = sendMsg(ih, kIDHCancelPendingIOSelect, pb);
waitSync(&ih->fSyncRequest);
result = ih->fSyncResult;
}
Exit:
#ifdef DRAWRINGBUFFERGRAPH
BlitBufferGraph(deviceDescriptionPtr);
#endif
return result;
}
static pascal ComponentResult
FWDVIDHWrite(IsochComponentInstancePtr ih, IDHParameterBlock *pb)
{
OSErr result = noErr;
DeviceDescription *deviceDescriptionPtr;
RecordEventLogger( 'isoc', 'writ', ih, pb);
FailWithAction( pb == nil, result = paramErr, Exit);
FailWithAction( pb->completionProc == nil && pb->buffer == nil, result = paramErr, Exit);
FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit);
if( pb->completionProc == nil) {
pb->result = kIDHErrCompletionPending;
result = sendMsg(ih, kIDHWriteSelect, pb);
while (pb->result == kIDHErrCompletionPending)
{
usleep(15000); }
}
else {
if(globals.fWorkThread == pthread_self()) {
queueWrite(ih, pb);
}
else
result = sendMsg(ih, kIDHWriteSelect, pb);
}
Exit:
#ifdef DRAWRINGBUFFERGRAPH
BlitBufferGraph(deviceDescriptionPtr);
#endif
return result;
}
static pascal ComponentResult
FWDVIDHGetDeviceControl(IsochComponentInstancePtr ih, ComponentInstance *deviceControl)
{
ComponentResult result = noErr;
DeviceDescription *deviceDescriptionPtr;
RecordEventLogger( 'isoc', 'get ', 'dev ', 'ctrl');
if ( deviceControl == nil )
return(paramErr);
FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit);
if ( deviceDescriptionPtr->deviceControlInstance == nil)
{
ComponentDescription devcDesc;
Component devcComp;
ComponentInstance devc;
devcDesc.componentType = kDeviceControlComponentType;
devcDesc.componentSubType = kDeviceControlSubtypeFWDV;
devcDesc.componentManufacturer = 0;
devcDesc.componentFlags = 0L;
devcDesc.componentFlagsMask = 0L;
devcComp = nil;
devcComp = FindNextComponent( devcComp, &devcDesc);
FailMessage( devcComp == nil);
if ( devcComp )
{
result = OpenAComponent(devcComp, &devc);
FailWithVal( result != noErr, Exit, result);
result = DeviceControlSetDeviceConnectionID(devc,
(DeviceConnectionID) deviceDescriptionPtr->fConnection);
FailWithVal( result != noErr, Exit, result);
result = DeviceControlEnableAVCTransactions(devc);
FailWithVal( result != noErr, Exit, result);
deviceDescriptionPtr->deviceControlInstance = devc;
}
}
if( ih->hasDeviceControl == false && deviceDescriptionPtr->deviceControlInstance != nil)
{
ih->hasDeviceControl = true;
++deviceDescriptionPtr->deviceControlCount;
}
*deviceControl = deviceDescriptionPtr->deviceControlInstance;
FailMessage( *deviceControl == nil);
Exit:
return(result);
}
static pascal ComponentResult
FWDVIDHUpdateDeviceList(IsochComponentInstancePtr ih, QTAtomContainer *deviceList )
{
OSErr result = noErr;
short nDVDevices, i;
QTAtomSpec atomSpec;
IsochComponentGlobalsPtr g = &globals;
RecordEventLogger( 'isoc', 'updt', 'dev ', 'list');
FailWithAction( deviceList == nil, result = paramErr, Exit);
atomSpec.container = *deviceList;
result = checkSeed( g, &atomSpec); if( result != noErr)
goto Exit;
if (result == noErr)
{
QTAtom useCMPAtom;
UInt32 useCMPValue;
useCMPAtom = QTFindChildByIndex(*deviceList, kParentAtomIsContainer, kIDHUseCMPAtomType, 1, nil);
if (useCMPAtom)
{
QTLockContainer(*deviceList);
result = QTCopyAtomDataToPtr(*deviceList, useCMPAtom, true, 4, &useCMPValue, nil);
QTUnlockContainer(*deviceList);
if (result == noErr)
g->useCMP = useCMPValue;
}
}
nDVDevices = QTCountChildrenOfType( *deviceList, kParentAtomIsContainer, kIDHDeviceAtomType);
for( i=0; i<nDVDevices; ++i)
{
QTAtom deviceAtomNew, nameAtomNew, deviceIDAtom;
QTAtom deviceAtomOld, nameAtomOld;
DeviceDescription *deviceDescriptionPtr;
IDHDeviceID deviceID;
UInt8 newName[256];
SInt32 actualSize;
deviceAtomNew = QTFindChildByIndex( *deviceList, kParentAtomIsContainer, kIDHDeviceAtomType, i + 1, nil);
FailIf( deviceAtomNew == nil, Exit);
nameAtomNew = QTFindChildByIndex( *deviceList, deviceAtomNew, kIDHNameAtomType, 1, nil);
FailIf( nameAtomNew == nil, Exit);
deviceIDAtom = QTFindChildByIndex( *deviceList, deviceAtomNew, kIDHDeviceIDType, 1, nil);
FailIf( deviceIDAtom == nil, Exit);
QTLockContainer( *deviceList);
QTCopyAtomDataToPtr( *deviceList, deviceIDAtom, true, sizeof( IDHDeviceID), &deviceID, nil);
QTUnlockContainer( *deviceList);
result = findDeviceDescriptionforDevice( ih, deviceID, &deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
deviceAtomOld = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, kParentAtomIsContainer, kIDHDeviceAtomType, 1, nil);
FailIf( deviceAtomOld == nil, Exit);
nameAtomOld = QTFindChildByIndex( deviceDescriptionPtr->deviceContainer, deviceAtomOld, kIDHNameAtomType, 1, nil);
FailIf( nameAtomOld == nil, Exit);
QTLockContainer( *deviceList);
result = QTCopyAtomDataToPtr(*deviceList, nameAtomNew, true, 256, newName, &actualSize);
QTUnlockContainer( *deviceList);
FailWithVal( result != noErr, Exit, result);
result = QTReplaceAtom( deviceDescriptionPtr->deviceContainer, nameAtomOld, *deviceList, nameAtomNew);
FailWithVal( result != noErr, Exit, result);
}
Exit:
return result;
}
static pascal ComponentResult
FWDVIDHGetDeviceTime(IsochComponentInstancePtr ih, TimeRecord *time)
{
OSErr result = noErr;
DeviceDescription *deviceDescriptionPtr;
UInt32 info[2];
UInt64 cycles;
int size;
FailWithAction( time == nil, result = paramErr, Exit);
FailWithAction( ih->deviceID == nil, result = kIDHErrDeviceNotConfigured, Exit);
result = findDeviceDescriptionforDevice( ih, ih->deviceID, &deviceDescriptionPtr);
FailWithVal( result != noErr, Exit, result);
FailWithAction( deviceDescriptionPtr->active == false, result = kIDHErrDeviceDisconnected, Exit);
size = 2;
result = io_connect_method_scalarI_scalarO(deviceDescriptionPtr->fConnection,
kDVGetDeviceTime, NULL, 0, (int *)info, &size);
cycles = info[0] * 8000; cycles += (info[1] >> 12) & 0x1fff;
time->value.lo = cycles & 0xffffffff;
time->value.hi = (cycles >> 32) & 0xffffffff;
time->scale = 8000;
Exit:
return result;
}
static pascal ComponentResult
FWDVIDHNewNotification(IsochComponentInstancePtr ihc, IDHDeviceID deviceID,
IDHNotificationProc notificationProc, void* userData, IDHNotificationID* notificationID)
{
UInt32 i;
Boolean addedClient = false;
OSErr result = noErr;
IsochComponentGlobalsPtr g = &globals;
RecordEventLogger( 'isoc', 'new ', 'noti', 'fy ');
FailWithAction( notificationProc == nil, result = paramErr, Exit);
FailWithAction( notificationID == nil, result = paramErr, Exit);
i = 0;
while (i < kMaxNotifications)
{
if (0 == g->clientNotification[i].deviceID)
{
g->clientNotification[i].deviceID = deviceID;
g->clientNotification[i].notificationProc = notificationProc;
g->clientNotification[i].events = 0;
g->clientNotification[i].userData = userData;
*notificationID = (UInt32)&g->clientNotification[i];
addedClient = true;
break;
}
++i;
}
if (!addedClient) result = paramErr;
Exit:
return result;
}
static pascal ComponentResult
FWDVIDHNotifyMeWhen(ComponentInstance idh, IDHNotificationID notificationID, IDHEvent events)
{
OSErr result = noErr;
ClientNotification* clientNotification = (ClientNotification*)notificationID;
RecordEventLogger( 'isoc', 'noti', 'when', events);
FailWithAction( clientNotification == nil, result = paramErr, Exit);
clientNotification->events = events;
Exit:
return result;
}
static pascal ComponentResult
FWDVIDHCancelNotification(ComponentInstance idh, IDHNotificationID notificationID)
{
OSErr result = noErr;
ClientNotification* clientNotification = (ClientNotification*)notificationID;
RecordEventLogger( 'isoc', 'canc', 'el ', 'noti');
FailWithAction( clientNotification == nil, result = paramErr, Exit);
clientNotification->events = 0;
Exit:
return result;
}
static pascal ComponentResult
FWDVIDHDisposeNotification(ComponentInstance idh, IDHNotificationID notificationID)
{
OSErr result = noErr;
ClientNotification* clientNotification = (ClientNotification*)notificationID;
RecordEventLogger( 'isoc', 'disp', 'ose ', 'noti');
FailWithAction( clientNotification == nil, result = paramErr, Exit);
clientNotification->deviceID = 0;
Exit:
return result;
}
#define DoCDispatchWS(x,p,s) \
case k ## x ## Select: \
\
{ ComponentResult err; \
err = CallComponentFunctionWithStorageProcInfo( s, p, (ProcPtr) FWDV ## x, \
uppCall ## x ## ProcInfo ); \
\
return err; }
#define DoDispatchWS(x,p,s) \
case k ## x ## Select: \
\
{ ComponentResult err; \
err = CallComponentFunctionWithStorageProcInfo( s, p, (ProcPtr) FWDV ## x, \
upp ## x ## ProcInfo ); \
\
return err; }
static pascal ComponentResult
FWDVComponentCanDo(IsochComponentInstancePtr storage, short selector)
{
ComponentResult result;
RecordEventLogger( 'isoc', 'cand', 0, 0);
switch(selector) {
case kComponentOpenSelect:
case kComponentCloseSelect:
case kComponentCanDoSelect:
case kComponentVersionSelect:
case kIDHGetDeviceListSelect:
case kIDHGetDeviceConfigurationSelect:
case kIDHSetDeviceConfigurationSelect:
case kIDHGetDeviceStatusSelect:
case kIDHGetDeviceClockSelect:
case kIDHOpenDeviceSelect:
case kIDHCloseDeviceSelect:
case kIDHReadSelect:
case kIDHWriteSelect:
case kIDHNewNotificationSelect:
case kIDHNotifyMeWhenSelect:
case kIDHCancelNotificationSelect:
case kIDHDisposeNotificationSelect:
case kIDHReleaseBufferSelect:
case kIDHCancelPendingIOSelect:
case kIDHGetDeviceControlSelect:
case kIDHUpdateDeviceListSelect:
case kIDHGetDeviceTimeSelect:
return(true);
default:
RecordEventLogger( 'isoc', 'cant', selector, 0);
result = false;
return (result);
}
}
pascal ComponentResult
FWDVICodecComponentDispatch(ComponentParameters *params, char ** storage)
{
ComponentResult result;
if ( params->what < 0 ) {
switch ( params->what ) {
DoCDispatchWS( ComponentOpen, params, storage );
DoCDispatchWS( ComponentClose, params, storage );
DoCDispatchWS( ComponentRegister, params, storage );
DoCDispatchWS( ComponentCanDo, params, storage );
DoCDispatchWS( ComponentVersion, params, storage );
default :
return (paramErr);
}
}
switch ( params->what ) {
DoDispatchWS( IDHGetDeviceList, params, storage );
DoDispatchWS( IDHGetDeviceConfiguration, params, storage );
DoDispatchWS( IDHSetDeviceConfiguration, params, storage );
DoDispatchWS( IDHGetDeviceStatus, params, storage );
DoDispatchWS( IDHGetDeviceClock, params, storage );
DoDispatchWS( IDHOpenDevice, params, storage );
DoDispatchWS( IDHCloseDevice, params, storage );
DoDispatchWS( IDHRead, params, storage );
DoDispatchWS( IDHWrite, params, storage );
DoDispatchWS( IDHReleaseBuffer, params, storage );
DoDispatchWS( IDHCancelPendingIO, params, storage );
DoDispatchWS( IDHGetDeviceControl, params, storage );
DoDispatchWS( IDHUpdateDeviceList, params, storage );
DoDispatchWS( IDHGetDeviceTime, params, storage );
DoDispatchWS( IDHNewNotification, params, storage );
DoDispatchWS( IDHNotifyMeWhen, params, storage );
DoDispatchWS( IDHCancelNotification, params, storage );
DoDispatchWS( IDHDisposeNotification, params, storage );
default:
{
int len = params->paramSize/4;
int i;
printf("IDH unimp:%d %d ", params->what, params->paramSize);
for(i=0; i<len; i++)
printf("0x%lx ", params->params[i]);
printf("\n");
result = paramErr;
return(result);
}
}
}
#ifdef DRAWRINGBUFFERGRAPH
static void SetUpBlitGlobals(DeviceDescriptionPtr ddp)
{
GDHandle gdh = GetMainDevice();
if (gdh)
{
ddp->fScreenBaseAddr = gdh[0]->gdPMap[0]->baseAddr;
ddp->fRowBytes = gdh[0]->gdPMap[0]->rowBytes & 0x3FFF;
ddp->fPixDepth = gdh[0]->gdPMap[0]->pixelSize;
}
}
#define spacerColour 0xFFFF
#define unusedColour 0x0000
#define emptyColour (16<<10) + (16<<5) +(16)
#define hasDataColour (0<<10) + (31<<5) +(0)
#define readColour (31<<10) + (31<<5) +(0)
#define writeColour (0<<10) + (31<<5) +(31)
#define collisionColour (31<<10) + (0<<5) +(0)
static void BlitBufferGraph(DeviceDescriptionPtr ddp)
{
short * line0Ptr = nil;
short * line00Ptr = nil;
short * line1Ptr = nil;
short * line2Ptr = nil;
short * line3Ptr = nil;
short buffCol = 0;
long flags =0;
int x,i,read,write;
if (ddp->fPixDepth != 16 || ddp->fScreenBaseAddr ==0 || ddp->fRowBytes ==0)
return;
line00Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*18-ddp->fRowBytes/4);
line0Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*19-ddp->fRowBytes/4);
line1Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*16-ddp->fRowBytes/4);
line2Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*17-ddp->fRowBytes/4);
line3Ptr =(short*) (ddp->fScreenBaseAddr + ddp->fRowBytes*15-ddp->fRowBytes/4);
read = ddp->fSharedVars->fReader % ddp->fNumOutputFrames;
write = ddp->fSharedVars->fWriter % ddp->fNumOutputFrames;
for(x =0;x < ddp->fNumOutputFrames; x++)
{
*line1Ptr++ = (short)spacerColour;
*line2Ptr++ = (short)spacerColour;
*line0Ptr++ = (short)spacerColour;
*line00Ptr++ = (short)spacerColour;
for(i=0;i<ddp->fBufferLocks[x];i++) {
short* beardPtr = line0Ptr+ddp->fRowBytes*i*2;
*beardPtr++ = unusedColour;
*beardPtr++ = unusedColour;
*beardPtr++ = unusedColour;
*beardPtr++ = unusedColour;
}
if (ddp->fBufferLocks[x]) {
buffCol = hasDataColour;
} else {
buffCol = emptyColour;
}
*line1Ptr++ = buffCol;
*line1Ptr++ = buffCol;
*line1Ptr++ = buffCol;
*line1Ptr++ = buffCol;
*line2Ptr++ = buffCol;
*line2Ptr++ = buffCol;
*line2Ptr++ = buffCol;
*line2Ptr++ = buffCol;
buffCol = (short)spacerColour;
if (read == x)
buffCol = readColour;
if (write == x)
{
if (buffCol == readColour)
buffCol = collisionColour;
else
buffCol = writeColour;
}
*line00Ptr++ = buffCol;
*line00Ptr++ = buffCol;
*line00Ptr++ = buffCol;
*line00Ptr++ = buffCol;
*line0Ptr++ = buffCol;
*line0Ptr++ = buffCol;
*line0Ptr++ = buffCol;
*line0Ptr++ = buffCol;
}
}
#endif