/*
File: DCFireWireDV.cp
Contains: Device Control component for DV on Firewire.
Copyright: й 1997-1999 by Apple Computer, Inc., all rights reserved.
File Ownership:
DRI: Kevin Williams
Writers:
(jkl) Jay Lloyd
(RS) Richard Sepulveda
(GDW) George D. Wilson Jr.
Change History (most recent first):
<13> 8/6/99 jkl Got rid of DVFamily.h stuff.
<12> 8/3/99 RS Returned device disconnected error when appropriate.
<11> 7/28/99 jkl Used atomic operation to check commandObjectInUse flag for a
little more safety.
<10> 7/27/99 jkl Added command object in use flag to DoAVCTransaction to make
sure it is not reentered.
<9> 7/13/99 jkl Moved setting asynch command object payload from
DoAVCTransaction to constructor.
<8> 7/12/99 RS Change'd component instance storage back to application heap
because close is handled correctly in the isoch component now.
<7> 7/8/99 RS Allocating instance storage using NewPtrSysClear() instead of
NewPtr() because this component needs to stay open across app
launches at times.
<6> 7/5/99 RS Allocating fCommandObjectID in the constructor and deleting in
destructor to avoid any non-task allocation problems.
<5> 7/5/99 jkl Changed to set max payload for command object, not client. Moved
client max payload to isoch component.
<4> 7/5/99 jkl Set max payload for FCP command object to 512. The default is 4
bytes and was causing failures on device control commands larger
than 4 bytes.
<3> 6/21/99 RS fDeviceEnable wasn't being initialized in the constructor.
Caused spurious bug during enable.
<2> 6/18/99 GDW Changed things.
<1> 6/15/99 KW Created
*/
// DCFireWireDV headers.
#include "DCFireWireDV.h"
#include "DCFireWireDVVersionAndRezIDs.h" // Version constants and Rez IDs
// MacOS headers.
#include <FireWire.h>
#include <Gestalt.h>
#include <IsochronousDataHandler.h>
// Standard C++ Library headers.
//#include <cstddef>
//
// -------- DCFireWireDV --------
//
#pragma mark ееееееееее Constructor & Destructor ееееееееее
//
// DCFireWireDV()
//
// Constructor.
//
DCFireWireDV::DCFireWireDV(ComponentInstance self, Boolean *success)
: fSelf(self),
fRegistered(false),
fTarget(0),
fClientID(0),
fDeviceEnable(false)
{
*success = true;
OSErr error = FWAllocateFCPCommandObject(&fCommandObjectID);
if (error)
*success = false;
else
{
// max packet for s100
FWSetAsynchCommandMaxPayloadSize(fCommandObjectID, 512);
}
}
//
// ~DCFireWireDV()
//
// Destructor.
//
DCFireWireDV::~DCFireWireDV()
{
if( fCommandObjectID)
FWDeallocateFWCommandObject(fCommandObjectID);
}
//====================================================================================
//
// DCFireWireDV operator new()
// This allocates the memory for the DCFireWireDV object data members.
// Though the global operator new could probably be used safely, this version will
// be used so that it is not affected by potential changes in the runtime libraries
// implementation of the global operator new.
//
//====================================================================================
void* DCFireWireDV::operator new(size_t size)
{
return (void*) NewPtrClear(size);
}
//====================================================================================
//
// DCFireWireDV operator delete()
// Dispose of the object storage. Global operator delete is not being used since
// global operator new isn't.
//
//====================================================================================
void DCFireWireDV::operator delete(void* ptr)
{
if (NULL != ptr)
DisposePtr((Ptr) ptr);
}
#pragma mark -
#pragma mark ееееееееее Default Component Calls ееееееееее
//====================================================================================
//
// Open()
// The Component Manager issues an 'open' request whenever a client tries to open a
// connection to the component by calling the Open[Default]Component() function.
//
// Since each ComponentInstance has a separate DCFireWireDV object instance
// associated with it, the state of each ComponentInstance can be independently
// maintained. Any information that needs to be shared between ComponentInstances
// will be accessible through the ComponentRefcon.
//
//====================================================================================
pascal ComponentResult DCFireWireDV::Open(
DCFireWireDV* unused,
ComponentInstance self)
{
Boolean success;
// Attempt to construct a DCFireWireDV object.
DCFireWireDV* dc = new DCFireWireDV(self, &success);
if (NULL == dc || success == false)
return memFullErr; // Unable to make new DCFireWireDV
// DCFireWireDV was successfully instantiated. Set this ComponentInstance's storage
// to be a pointer to the DCFireWireDV object. This will allow subsequent calls
// easy access to the DCFireWireDV that was created for this ComponentInstance
// since the pointer will be passed in automatically by the dispatch routine.
SetComponentInstanceStorage(dc->fSelf, reinterpret_cast<char**>(dc));
// Check the ComponentRefcon to see if this 'Open' request is part of the
// registering process (Open, Register, Close) or a true 'Open'.
// By convention in DeviceControl, the ComponentRefcon is used to convey
// Registration information and to point to a structure of items that are shared
// by component instances as shown below:
//
// NULL
// The component has NOT been successfully registered.
//
// 0xFFFFFFFF
// The component has been successfully registered, but NO shared data
// has been allocated or initialized.
//
// Other Value
// Any other value means that the component has been successfully
// registered. Additionally, it points to the data that is shared
// between ComponentInstances.
SInt32 refcon = GetComponentRefcon(reinterpret_cast<Component>(dc->fSelf));
if (NULL == refcon)
return (noErr); // Haven't been registered, so simply return
// Component had been successfully registered, so this is a true 'Open' request.
dc->fRegistered = true;
// Make sure that the appropriate version of QuickTime is around. Only versions
// 4.0 or greater are supported.
enum { kMinimumQuickTimeVersion = 0x0400 };
SInt32 gestaltResult;
OSErr osErr = Gestalt(gestaltQuickTimeVersion, &gestaltResult);
if ((noErr != osErr) || (kMinimumQuickTimeVersion > (gestaltResult >> 16)))
return qtParamErr;
return noErr;
}
//====================================================================================
//
// Close()
// The Component Manager issues a 'close' request whenever a client closes its
// connection to the component by calling the CloseComponent() function.
//
// As noted on page 6-21 of "IM More Macintosh Toolbox", the Component Manager will
// issue a close request even if the open request failed.
//
//====================================================================================
pascal ComponentResult DCFireWireDV::Close(
DCFireWireDV* dc,
ComponentInstance self)
{
// Make sure that the DCFireWireDV* is non-NULL. If will be NULL only if the
// constructor failed in Open().
if (NULL == dc)
return noErr;
// See if the last component instance is being closed. If so, deallocate any
// shared data (if appropriate) and set the ComponentRefcon to NULL to signify
// that no shared data is allocated.
SInt32 instanceCount = CountComponentInstances((Component) dc->fSelf);
// Last instance is being closed?
if (1 == instanceCount)
{
if (!dc->fRegistered)
{
// The component has been unregistered, so set the ComponentRefcon to
// NULL to signify that.
SetComponentRefcon((Component) dc->fSelf, NULL);
}
}
// Since this instance is being closed, it's storage will never be referenced
// again, so set it to NULL (just being paranoid), and delete the DCFireWireDV
// object.
SetComponentInstanceStorage(dc->fSelf, reinterpret_cast<char**>(0));
delete dc;
return noErr;
}
//====================================================================================
//
// Version()
// The Component Manager issues a 'version' request when a client calls the
// GetComponentVersion() function to retrieve the component's version number.
//
// <- ComponentResult
// The version number. The high-order 16 bits represents the major version
// (the component specification level), and the low-order 16 bits represent the
// minor version (implementation level).
//
//====================================================================================
pascal ComponentResult DCFireWireDV::Version(DCFireWireDV* dc)
{
return ((kDCFireWireDVInterfaceVersion << 16) | (kDCFireWireDVCodeVersion));
}
//====================================================================================
//
// Register()
// The Component Manager issues a 'register' request when the component is registered.
// This gives the component an opportunity to determine whether it can operate in the
// current environment. System resources should not normally be allocated in
// response to a register request.
//
// When the Component Manager is attempting to register a component, it will send it
// the following request sequence: open, register, close.
//
// <- ComponentResult
// If the component should be registered, return 'noErr', otherwise return a
// qtParamErr.
//
//====================================================================================
pascal ComponentResult DCFireWireDV::Register(DCFireWireDV* dc)
{
// Everything necessary for a successful registration has occurred.
// Therefore, following IDH conventions, set the component refCon to 0xFFFFFFFF
// to signify that and set fRegistered to 'true'
dc->fRegistered = true;
SetComponentRefcon((Component) dc->fSelf, (long) 0xFFFFFFFF);
return noErr;
}
//====================================================================================
//
// Target()
// The Component Manager issues a 'target' request to inform the component that it
// has been targeted by another component. After being targeted, the targeted
// component should call the component that targeted it whenever it would normally
// have called itself.
//
// -> parentComponent ComponentInstance to pass calls on to.
//
//====================================================================================
pascal ComponentResult DCFireWireDV::Target(
DCFireWireDV* dc,
ComponentInstance parentComponent)
{
dc->fTarget = parentComponent;
// CallComponentTarget needs to be called does it not?
return noErr;
}
//====================================================================================
//
// Unregister()
// The Component Manager issues an 'unregister' request when the component is
// unregistered. This gives the component an opportunity to perform any clean up
// operations, such as resetting the hardware. An 'unregister' request will be sent
// to the component even if no clients opened the client.
//
//====================================================================================
pascal ComponentResult DCFireWireDV::Unregister(DCFireWireDV* dc)
{
// Set the fRegistered data member to 'false' so that the subsequent Close() will
// know to set the ComponentRefcon to NULL to signify that the component is no
// longer registered.
dc->fRegistered = false;
return noErr;
}
#pragma mark -
#pragma mark ееееееееее Public Device Control Calls ееееееееее
//====================================================================================
//
// DoAVCTransaction()
//
// ToDo:
//====================================================================================
pascal ComponentResult DCFireWireDV::DoAVCTransaction(
DCFireWireDV* dc,
DVCTransactionParams* inTransaction)
{
ComponentResult result = noErr;
if ( dc->fClientID == (FWClientID) kIDHInvalidDeviceID )
return(kIDHErrInvalidDeviceID);
if ( !dc->fDeviceEnable )
return(kIDHErrDeviceDisconnected);
if( dc->fCommandObjectID == nil)
return kIDHErrInvalidDeviceID;
if (CompareAndSwap(0, 1, &dc->fCommandObjectInUse))
{
// Set up FCP command params to tell camera to do something.
result = FWSetFWCommandParams( dc->fCommandObjectID, // objectID
dc->fClientID, // ref ID
kFWCommandSyncFlag, // cmd flags
nil, // completion proc
0); // completion data
result = FWSetFCPCommandParams( dc->fCommandObjectID, // objectID
inTransaction->commandBufferPtr, // cmd buffer
inTransaction->commandLength, // cmd length
inTransaction->responseBufferPtr, // response buffer
inTransaction->responseBufferSize, // response size
100 * durationMillisecond, // timeout
8, // max retries
0, // transfer flags
nil ); // response handler
// send the FCP command
result = FWSendFCPCommand(dc->fCommandObjectID);
dc->fCommandObjectInUse = 0;
}
else
result = kIDHErrDeviceBusy;
return result;
}
#pragma mark -
#pragma mark ееееееееее FWDVCodec Private Dispatch Calls ееееееееее
//====================================================================================
//
// EnableAVCTransactions()
//
//
//====================================================================================
pascal ComponentResult DCFireWireDV::EnableAVCTransactions(
DCFireWireDV* dc)
{
ComponentResult result = noErr;
if ( dc->fClientID != (FWClientID) kIDHInvalidDeviceID )
dc->fDeviceEnable = true;
else
result = kIDHErrDeviceNotOpened;
return result ;
}
//====================================================================================
//
// DisableAVCTransactions()
//
//
//====================================================================================
pascal ComponentResult DCFireWireDV::DisableAVCTransactions(
DCFireWireDV* dc)
{
ComponentResult result = noErr;
dc->fDeviceEnable = false;
return result ;
}
//====================================================================================
//
// SetDeviceConnectionID()
//
//
//====================================================================================
pascal ComponentResult DCFireWireDV::SetDeviceConnectionID(
DCFireWireDV* dc, DeviceConnectionID connectionID)
{
ComponentResult result = noErr;
if ( dc->fDeviceEnable )
result = kIDHErrDeviceInUse;
else
dc->fClientID = reinterpret_cast<FWClientID>(connectionID);
return result;
}
//====================================================================================
//
// GetDeviceConnectionID()
//
//
//====================================================================================
pascal ComponentResult DCFireWireDV::GetDeviceConnectionID(
DCFireWireDV* dc, DeviceConnectionID* connectionID)
{
ComponentResult result = noErr;
*connectionID = reinterpret_cast<DeviceConnectionID>(dc->fClientID);
return result ;
}
#pragma mark -
#pragma mark ееееееееее Static Callback Routines еееееее
#pragma mark -
#pragma mark ееееееееее Utility Routines for DCFireWireDV еееееее
#pragma mark -
#pragma mark ееееееееее Static Utility Routines for DCFireWireDV еееееее