1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <IOKit/IOLib.h>
24#include <IOKit/firewire/IOFireWireController.h>
25#include <IOKit/firewire/IOLocalConfigDirectory.h>
26
27#include <IOKit/avc/IOFireWireAVCConsts.h>
28#include <IOKit/avc/IOFireWireAVCTargetSpace.h>
29
30#define AVCTARGETMUTEX_LOCK fController->closeGate()
31#define AVCTARGETMUTEX_UNLOCK fController->openGate()
32
33// Local Prototypes
34static void AVCTargetSendAVCResponseComplete(void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd);
35
36OSDefineMetaClassAndStructors(AVCCommandHandlerInfo, OSObject)
37OSDefineMetaClassAndStructors(AVCSubunitInfo, OSObject)
38OSDefineMetaClassAndStructors(UCInfo, OSObject)
39OSDefineMetaClassAndStructors(AVCConnectionRecord, OSObject)
40
41//////////////////////////////////////////////////////
42// AVCSubunitInfo::create
43//////////////////////////////////////////////////////
44AVCSubunitInfo *AVCSubunitInfo::create()
45{
46	AVCSubunitInfo * subUnitInfo;
47
48	subUnitInfo = new AVCSubunitInfo;
49
50    if( subUnitInfo != NULL && !subUnitInfo->init())
51	{
52        subUnitInfo->release();
53        subUnitInfo = NULL;
54    }
55
56    return subUnitInfo;
57}
58
59//////////////////////////////////////////////////////
60// AVCSubunitInfo::init
61//////////////////////////////////////////////////////
62bool AVCSubunitInfo::init()
63{
64	bool success = true;
65
66	//IOLog( "AVCSubunitInfo::init (0x%08X)\n",(int) this);
67
68	// init super
69    if( !OSObject::init() )
70        success = false;
71
72	if( success )
73	{
74		// Initialize this object
75	}
76
77	return success;
78}
79
80//////////////////////////////////////////////////////
81// AVCSubunitInfo::free
82//////////////////////////////////////////////////////
83void AVCSubunitInfo::free()
84{
85    //IOLog( "AVCSubunitInfo::free (0x%08X)\n",(int) this);
86
87	if (sourcePlugRecords)
88		delete[] sourcePlugRecords;
89
90	if (destPlugRecords)
91		delete[] destPlugRecords;
92
93	OSObject::free();
94}
95
96OSDefineMetaClassAndStructors(IOFireWireAVCTargetSpace, IOFWPseudoAddressSpace)
97OSMetaClassDefineReservedUnused(IOFireWireAVCTargetSpace, 0);
98OSMetaClassDefineReservedUnused(IOFireWireAVCTargetSpace, 1);
99OSMetaClassDefineReservedUnused(IOFireWireAVCTargetSpace, 2);
100OSMetaClassDefineReservedUnused(IOFireWireAVCTargetSpace, 3);
101
102//////////////////////////////////////////////////////
103// AVCTargetSendAVCResponseComplete
104//////////////////////////////////////////////////////
105void AVCTargetSendAVCResponseComplete(void *refcon, IOReturn status, IOFireWireNub *device, IOFWCommand *fwCmd)
106{
107	//IOLog( "AVCTargetSendAVCResponseComplete Command=0x%08X  Status=0x%08X\n",(int)fwCmd,status);
108
109	IOBufferMemoryDescriptor *pBufMemDesc = (IOBufferMemoryDescriptor*) refcon;
110
111	// Free the command and the associated memory descriptor
112    if(fwCmd)
113        fwCmd->release();
114	if(pBufMemDesc)
115		pBufMemDesc->release();
116}
117
118//////////////////////////////////////////////////////
119// IOFireWireAVCTargetSpace::init
120//////////////////////////////////////////////////////
121bool IOFireWireAVCTargetSpace::init(IOFireWireController *controller)
122{
123    //IOLog( "IOFireWireAVCTargetSpace::init (0x%08X)\n",(int) this);
124
125
126    if(!IOFWPseudoAddressSpace::initFixed(controller,
127										  FWAddress(kCSRRegisterSpaceBaseAddressHi, kFCPCommandAddress),
128										  512, NULL, NULL, this))
129		return false;
130
131	// Save the pointer to the bus
132	fController = controller;
133
134    return true;
135}
136
137//////////////////////////////////////////////////////
138// IOFireWireAVCTargetSpace::getAVCTargetSpace
139//////////////////////////////////////////////////////
140IOFireWireAVCTargetSpace * IOFireWireAVCTargetSpace::getAVCTargetSpace(IOFireWireController *controller)
141{
142    IOFWAddressSpace *existing;
143    IOFireWireAVCTargetSpace *space;
144
145	//IOLog( "IOFireWireAVCTargetSpace::getAVCTargetSpace\n");
146
147    existing = controller->getAddressSpace(FWAddress(kCSRRegisterSpaceBaseAddressHi, kFCPCommandAddress));
148    if(existing && OSDynamicCast(IOFireWireAVCTargetSpace, existing)) {
149        existing->retain();
150        return OSDynamicCast(IOFireWireAVCTargetSpace, existing);
151    }
152    space = new IOFireWireAVCTargetSpace;
153    if(space) {
154        if(!space->init(controller)) {
155            space->release();
156            space = NULL;
157        }
158    }
159    return space;
160}
161
162//////////////////////////////////////////////////////
163// IOFireWireAVCTargetSpace::doWrite
164//////////////////////////////////////////////////////
165UInt32 IOFireWireAVCTargetSpace::doWrite(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
166								   const void *buf, IOFWRequestRefCon refcon)
167{
168	UInt32 generation = fController->getGeneration();
169	UInt8 cts;
170	UInt8 *pBuf = (UInt8*) buf;
171
172	//IOLog( "IOFireWireAVCTargetSpace::doWrite (0x%08X)\n",(int) this);
173
174	if(addr.addressHi != kCSRRegisterSpaceBaseAddressHi)
175        return kFWResponseAddressError;
176    if(addr.addressLo != kFCPCommandAddress)
177        return kFWResponseAddressError;
178
179	// Make sure this is an AVC command (CTS is 0)
180	cts =  ((pBuf[0] & 0xF0) >> 4);
181	if (cts != 0)
182        return kFWResponseAddressError;
183
184	// Find a handler for this command, or send not implemented response
185	findAVCRequestHandler(NULL,generation,nodeID,speed,0xFFFFFFFF,(const char *) pBuf,len);
186
187	return kFWResponseComplete;
188}
189
190//////////////////////////////////////////////////////
191// IOFireWireAVCTargetSpace::findAVCRequestHandler
192//////////////////////////////////////////////////////
193IOReturn IOFireWireAVCTargetSpace::findAVCRequestHandler(IOFireWireAVCProtocolUserClient *userClient,
194														UInt32 generation,
195														UInt16 nodeID,
196														IOFWSpeed speed,
197														UInt32 handlerSearchIndex,
198														const char *pCmdBuf,
199														UInt32 cmdLen)
200{
201	UInt32 currentGeneration = fController->getGeneration();
202	UInt8 subUnit;
203	UInt8 opCode;
204	UInt8 *pResponse;
205	bool handled = false;
206	IOBufferMemoryDescriptor *pBufMemDesc = NULL;
207	int i;
208	int firstIndex;
209
210	// Parse the command a bit
211	subUnit = pCmdBuf[1];
212	opCode = pCmdBuf[2];
213
214	//IOLog( "IOFireWireAVCTargetSpace::findAVCRequestHandler (0x%08X) subUnit=%02X  opCode=%02X\n",(int) this,subUnit,opCode);
215
216	// See if we are still in the same bus generation as the command
217	if (currentGeneration != generation)
218		return kIOFireWireBusReset;
219
220	AVCTARGETMUTEX_LOCK;
221
222	if (handlerSearchIndex == 0xFFFFFFFF)
223		firstIndex = (fCommandHandlers->getCount()-1);
224	else
225	{
226		firstIndex = handlerSearchIndex - 1;
227
228		// Make sure that we don't index to a command handler record that doesn't exist
229		if (firstIndex >= (int) fCommandHandlers->getCount())
230			firstIndex = (fCommandHandlers->getCount()-1);
231	}
232
233	// First, search the array of registered command handlers
234	for (i=firstIndex;i>=0;i--)
235	{
236		AVCCommandHandlerInfo *cmdInfo;
237		cmdInfo = (AVCCommandHandlerInfo*) fCommandHandlers->getObject(i);
238
239		if ( ((cmdInfo->subUnitTypeAndID == subUnit) && (cmdInfo->opCode == opCode)) ||
240	   ((cmdInfo->subUnitTypeAndID == subUnit) && (cmdInfo->opCode == kAVCAllOpcodes)) ||
241	   ((cmdInfo->subUnitTypeAndID == kAVCAllSubunitsAndUnit) && (cmdInfo->opCode == opCode)) ||
242	   ((cmdInfo->subUnitTypeAndID == kAVCAllSubunitsAndUnit) && (cmdInfo->opCode == kAVCAllOpcodes)))
243		{
244			// Call back the command's handler to pass the command up to user space
245			cmdInfo->callBack(cmdInfo,generation,nodeID,pCmdBuf,cmdLen,speed,i);
246			handled = true;
247			break;
248		}
249	}
250
251	// If not hadled by registered handler, try and Find an Internall Command Handler for this command
252	if ((!handled) && (subUnit == 0xFF))
253	{
254		// See if we have an internal unit command handler for this opcode
255		switch (opCode)
256		{
257			case kAVCUnitInfoOpcode:
258				if (handleUnitInfoCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
259					handled = true;
260				break;
261
262			case kAVCSubunitInfoOpcode:
263				if (handleSubUnitInfoCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
264					handled = true;
265				break;
266
267			case kAVCPowerOpcode:
268				if (handlePowerCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
269					handled = true;
270				break;
271
272			case kAVCConnectOpcode:
273				if (handleConnectCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
274					handled = true;
275				break;
276
277			case kAVCDisconnectOpcode:
278				if (handleDisconnectCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
279					handled = true;
280				break;
281
282			case kAVCInputPlugSignalFormatOpcode:
283				if (handleInputPlugSignalFormatCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
284					handled = true;
285				break;
286
287			case kAVCOutputPlugSignalFormatOpcode:
288				if (handleOutputPlugSignalFormatCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
289					handled = true;
290				break;
291
292			case kAVCConnectionsOpcode:
293				if (handleConnectionsCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
294					handled = true;
295				break;
296
297			case kAVCSignalSourceOpcode:
298				if (handleSignalSourceCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
299					handled = true;
300				break;
301
302			default:
303				break;
304		};
305	}
306
307	if ((!handled) && (opCode == kAVCPlugInfoOpcode))
308	{
309		// Internally handle the Plug Info command for the unit and all subunits
310		if (handlePlugInfoCommand(nodeID, generation, pCmdBuf, cmdLen) == kIOReturnSuccess)
311			handled = true;
312	}
313
314	// If not handled, send a Not Implemented Response
315	if (!handled)
316	{
317		//IOLog("DEBUG: findAVCRequestHandler found no handler for command!\n");
318        pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(cmdLen, kIODirectionOutIn);
319        if(!pBufMemDesc)
320		{
321			AVCTARGETMUTEX_UNLOCK;
322			return kFWResponseDataError;
323		}
324		pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
325		bcopy(pCmdBuf,pResponse,cmdLen);
326		pResponse[kAVCCommandResponse] = kAVCNotImplementedStatus;	// Not Implemented
327		targetSendAVCResponse(generation, nodeID, pBufMemDesc, cmdLen);
328	}
329
330	AVCTARGETMUTEX_UNLOCK;
331
332	return kIOReturnSuccess;
333}
334
335//////////////////////////////////////////////////////
336// IOFireWireAVCTargetSpace::activateWithUserClient
337//////////////////////////////////////////////////////
338IOReturn IOFireWireAVCTargetSpace::activateWithUserClient(IOFireWireAVCProtocolUserClient *userClient)
339{
340    IOReturn res = kIOReturnSuccess;
341	UCInfo *uc;
342	UInt32 i;
343
344	//IOLog( "IOFireWireAVCTargetSpace::activateWithUserClient (0x%08X)\n",(int) this);
345
346	if(!fActivations++)
347	{
348		fUserClients = OSArray::withCapacity(1);
349		fCommandHandlers = OSArray::withCapacity(1);
350		fSubunits = OSArray::withCapacity(1);
351		fConnectionRecords = OSArray::withCapacity(1);
352
353		// Setup Unit plug management
354		fUnitPlugs.numIsochInPlugs = kAVCMaxNumPlugs;
355		fUnitPlugs.numIsochOutPlugs = kAVCMaxNumPlugs;
356		fUnitPlugs.numExternalInPlugs = kAVCMaxNumPlugs;
357		fUnitPlugs.numExternalOutPlugs = kAVCMaxNumPlugs;
358		for (i=0;i<kAVCMaxNumPlugs;i++)
359		{
360			fUnitPlugs.isochInPlugRecord[i].connectionCount = 0;
361			fUnitPlugs.isochOutPlugRecord[i].connectionCount = 0;
362			fUnitPlugs.externalInPlugRecord[i].connectionCount = 0;
363			fUnitPlugs.externalOutPlugRecord[i].connectionCount = 0;
364		}
365
366#if 0
367		// Create the lock to protect data structures
368		fLock = IORecursiveLockAlloc();
369#endif
370
371		res = IOFWAddressSpace::activate();
372	}
373
374	// Save User Client pointer in array
375	uc = new UCInfo;
376    if(!uc)
377        return kIOReturnNoMemory;
378	uc->fUserClient = userClient;
379	if(!fUserClients->setObject(uc))
380        return kIOReturnNoMemory;
381	uc->release();
382	//IOLog( "DEBUG: activateWithUserClient added client to array (0x%08X)\n",(int) userClient);
383
384
385    return res;
386}
387
388//////////////////////////////////////////////////////
389// IOFireWireAVCTargetSpace::deactivateWithUserClient
390//////////////////////////////////////////////////////
391void IOFireWireAVCTargetSpace::deactivateWithUserClient(IOFireWireAVCProtocolUserClient *userClient)
392{
393    IOReturn res = kIOReturnSuccess;
394	int i,j;
395	UCInfo *uc;
396	AVCConnectionRecord *connection;
397	AVCSubunitInfo *subUnitInfo;
398	AVCSubunitInfo *connectedSubUnitInfo;
399	bool avcResourcesFreed = false;
400	UInt32 subunitTypeAndID;
401
402	//IOLog( "IOFireWireAVCTargetSpace::deactivateWithUserClient (0x%08X)\n",(int) this);
403
404	AVCTARGETMUTEX_LOCK;
405
406	// Free any allocated command handlers for this user client
407	for (i=(fCommandHandlers->getCount()-1);i>=0;i--)
408	{
409		AVCCommandHandlerInfo *cmdInfo;
410		cmdInfo = (AVCCommandHandlerInfo*) fCommandHandlers->getObject(i);
411        if(cmdInfo->userClient == userClient)
412		{
413			fCommandHandlers->removeObject(i);
414			//IOLog( "DEBUG: deactivateWithUserClient found cmd handler to remove (0x%08X)\n",(int) userClient);
415		}
416	}
417
418	// Free any allocated subunits for this user client
419	for (i=(fSubunits->getCount()-1);i>=0;i--)
420	{
421		subUnitInfo = (AVCSubunitInfo*) fSubunits->getObject(i);
422		if(subUnitInfo->userClient == userClient)
423		{
424			subunitTypeAndID = subUnitInfo->subunitTypeAndID;
425
426			// Disconnect all plugs on this subunit
427			for (j=(fConnectionRecords->getCount()-1);j>=0;j--)
428			{
429				connection = (AVCConnectionRecord*) fConnectionRecords->getObject(j);
430
431				// See if this connection record is for this subunit
432				if ((connection->sourceSubunitTypeAndID == subunitTypeAndID) ||
433		(connection->destSubunitTypeAndID == subunitTypeAndID))
434				{
435					if (connection->sourceSubunitTypeAndID != subunitTypeAndID)
436					{
437						switch (connection->sourcePlugType)
438						{
439							case IOFWAVCPlugIsochInputType:
440								fUnitPlugs.isochInPlugRecord[connection->sourcePlugNum].connectionCount--;
441								break;
442							case IOFWAVCPlugExternalInputType:
443								fUnitPlugs.externalInPlugRecord[connection->sourcePlugNum - 0x80].connectionCount--;
444								break;
445							case IOFWAVCPlugSubunitSourceType:
446								connectedSubUnitInfo = getSubunitInfo(connection->sourceSubunitTypeAndID);
447								if (connectedSubUnitInfo)
448								{
449									connectedSubUnitInfo->sourcePlugRecords[connection->sourcePlugNum].connectionCount--;
450
451									// If the connected plug is a subunit plug, and this
452									// user client doesn't own that subunit, notify the owner
453									// of the plug's disconnection
454									if (connectedSubUnitInfo->userClient != userClient)
455										connectedSubUnitInfo->callBack(connectedSubUnitInfo,
456										 kIOFWAVCSubunitPlugMsgDisconnected,
457										 connection->sourcePlugType,
458										 connection->sourcePlugNum,
459										 ((connection->destSubunitTypeAndID << 16) + (connection->destPlugType << 8) + connection->destPlugNum),
460										 0,0);
461								}
462								break;
463							default:
464								break;
465						};
466
467					}
468
469					if (connection->destSubunitTypeAndID != subunitTypeAndID)
470					{
471						switch (connection->destPlugType)
472						{
473							case IOFWAVCPlugIsochOutputType:
474								fUnitPlugs.isochOutPlugRecord[connection->destPlugNum].connectionCount--;
475								break;
476							case IOFWAVCPlugExternalOutputType:
477								fUnitPlugs.externalOutPlugRecord[connection->destPlugNum - 0x80].connectionCount--;
478								break;
479							case IOFWAVCPlugSubunitDestType:
480								connectedSubUnitInfo = getSubunitInfo(connection->destSubunitTypeAndID);
481								if (connectedSubUnitInfo)
482								{
483									connectedSubUnitInfo->destPlugRecords[connection->destPlugNum].connectionCount--;
484
485									// If the connected plug is a subunit plug, and this
486									// user client doesn't own that subunit, notify the owner
487									// of the plug's disconnection
488									if (connectedSubUnitInfo->userClient != userClient)
489										connectedSubUnitInfo->callBack(connectedSubUnitInfo,
490										 kIOFWAVCSubunitPlugMsgDisconnected,
491										 connection->destPlugType,
492										 connection->destPlugNum,
493										 ((connection->sourceSubunitTypeAndID << 16) + (connection->sourcePlugType << 8) + connection->sourcePlugNum),
494										 0,0);
495								}
496								break;
497							default:
498								break;
499						};
500					}
501
502					// Remove this connection record
503					fConnectionRecords->removeObject(j);
504				}
505			}
506
507			fSubunits->removeObject(i);
508			//IOLog( "DEBUG: deactivateWithUserClient found subunit to remove (0x%08X)\n",(int) userClient);
509
510			avcResourcesFreed = true;
511		}
512	}
513
514	// Find this user client in the user client array, and remove it
515	for (i=(fUserClients->getCount()-1);i>=0;i--)
516	{
517        uc = (UCInfo *)fUserClients->getObject(i);
518        if(uc->fUserClient == userClient)
519		{
520			fUserClients->removeObject(i);
521			//IOLog( "DEBUG: deactivateWithUserClient found client to remove (0x%08X)\n",(int) userClient);
522		}
523	}
524
525	// Decrement activations count
526	fActivations -= 1;
527
528	// If there is only one activation left, get the user-client info for it.
529	if (fActivations == 1)
530        uc = (UCInfo *)fUserClients->getObject(0);
531
532	AVCTARGETMUTEX_UNLOCK;
533
534	// If we are down to no activations, or if we have one remaining activation
535	// and it is the IOFireWirePCRSpace's activation, remove the AVC unit
536	// directory, if it exists.
537	if ((fActivations == 0) || ((fActivations == 1) && (uc->fUserClient == (IOFireWireAVCProtocolUserClient*)0xFFFFFFFF)))
538	{
539		// If we've published an AVC Unit directory, now's the time to remove it
540		if (fAVCLocalConfigDirectory)
541		{
542			res = fController->RemoveUnitDirectory(fAVCLocalConfigDirectory) ;
543
544			// Release the fAVCLocalConfigDirectory object
545			fAVCLocalConfigDirectory->release();
546			fAVCLocalConfigDirectory = NULL;
547		}
548	}
549	else if (avcResourcesFreed == true)
550		fController->resetBus();
551
552	if (fActivations == 0)
553	{
554
555#if 0
556		// Release the lock
557		if (fLock)
558			IORecursiveLockFree(fLock);
559#endif
560
561		// Release the OSArrays
562		fUserClients->release();
563		fCommandHandlers->release();
564		fSubunits->release();
565		fConnectionRecords->release();
566
567		IOFWAddressSpace::deactivate();
568	}
569}
570
571//////////////////////////////////////////////////////
572// IOFireWireAVCTargetSpace::publishAVCUnitDirectory
573//////////////////////////////////////////////////////
574IOReturn IOFireWireAVCTargetSpace::publishAVCUnitDirectory(void)
575{
576	//IOLog( "IOFireWireAVCTargetSpace::publishAVCUnitDirectory (0x%08X)\n",(int) this);
577
578    IOReturn res = kIOReturnSuccess;
579
580	AVCTARGETMUTEX_LOCK;
581
582	// Only do this once.
583	if (!fAVCLocalConfigDirectory)
584	{
585		// Create entries for UnitSpecID and UnitSwVersion
586		fAVCLocalConfigDirectory = IOLocalConfigDirectory::create();
587
588		if (!fAVCLocalConfigDirectory)
589		{
590			res =  kIOReturnError;
591		}
592
593		AVCTARGETMUTEX_UNLOCK;
594
595		if(res == kIOReturnSuccess)
596			res = fAVCLocalConfigDirectory->addEntry(0x12,0xA02D) ;
597
598		if(res == kIOReturnSuccess)
599			res = fAVCLocalConfigDirectory->addEntry(0x13,0x10001) ;
600
601		// lets publish it
602		if(res == kIOReturnSuccess)
603			res = fController->AddUnitDirectory(fAVCLocalConfigDirectory) ;
604	}
605	else
606	{
607		AVCTARGETMUTEX_UNLOCK;
608
609		// The AVC Unit directory already exists, so just do a bus reset now.
610		fController->resetBus();
611	}
612
613	// end of unit directory addition
614    return res;
615}
616
617//////////////////////////////////////////////////////
618// IOFireWireAVCTargetSpace::targetSendAVCResponse
619//////////////////////////////////////////////////////
620IOReturn
621IOFireWireAVCTargetSpace::targetSendAVCResponse(UInt32 generation, UInt16 nodeID, IOBufferMemoryDescriptor *pBufMemDesc, UInt32 size)
622{
623	//IOLog( "IOFireWireAVCTargetSpace::targetSendAVCResponse (0x%08X)\n",(int) this);
624
625    IOFWWriteCommand *cmd = NULL;
626    IOReturn status;
627    do {
628        cmd = new IOFWWriteCommand;
629        if(!cmd) {
630            status = kIOReturnNoMemory;
631            break;
632        }
633        if(!cmd->initAll(fController, generation,
634						 FWAddress(kCSRRegisterSpaceBaseAddressHi, kFCPResponseAddress, nodeID),
635						 pBufMemDesc, AVCTargetSendAVCResponseComplete, pBufMemDesc)) {
636            status = kIOReturnNoMemory;
637            break;
638        }
639        status = cmd->submit(true);
640    } while (false);
641
642    return status;
643}
644
645//////////////////////////////////////////////////////
646// IOFireWireAVCTargetSpace::installAVCCommandHandler
647//////////////////////////////////////////////////////
648IOReturn IOFireWireAVCTargetSpace::installAVCCommandHandler(IOFireWireAVCProtocolUserClient *userClient,
649															IOFireWireAVCTargetCommandHandlerCallback callBack,
650															OSAsyncReference64 asyncRef,
651															UInt32 subUnitTypeAndID,
652															UInt32 opCode,
653															uint64_t userCallBack,
654															uint64_t userRefCon)
655{
656    IOReturn res = kIOReturnSuccess;
657	AVCCommandHandlerInfo *cmdInfo;
658
659	//IOLog( "IOFireWireAVCTargetSpace::installAVCCommandHandler (0x%08X)\n",(int) this);
660
661	cmdInfo = new AVCCommandHandlerInfo;
662    if(!cmdInfo)
663        return kIOReturnNoMemory;
664
665	cmdInfo->userClient = userClient;
666	cmdInfo->callBack = callBack;
667	bcopy(asyncRef, cmdInfo->asyncRef, sizeof(OSAsyncReference64));
668	cmdInfo->subUnitTypeAndID = subUnitTypeAndID;
669	cmdInfo->opCode = opCode;
670	cmdInfo->userCallBack = userCallBack;
671	cmdInfo->userRefCon = userRefCon;
672
673	AVCTARGETMUTEX_LOCK;
674
675	// Save command handler info in array
676	if(!fCommandHandlers->setObject(cmdInfo))
677        res = kIOReturnNoMemory;
678	else
679	{
680		//IOLog( "DEBUG: installAVCCommandHandler added cmd handler to array (0x%08X)\n",(int) userClient);
681	}
682
683	AVCTARGETMUTEX_UNLOCK;
684
685	cmdInfo->release();
686
687	return res;
688}
689
690//////////////////////////////////////////////////////
691// IOFireWireAVCTargetSpace::addSubunit
692//////////////////////////////////////////////////////
693IOReturn IOFireWireAVCTargetSpace::addSubunit(IOFireWireAVCProtocolUserClient *userClient,
694											  IOFireWireAVCSubunitPlugHandlerCallback callBack,
695											  OSAsyncReference64 asyncRef,
696											  UInt32 subunitType,
697											  UInt32 numSourcePlugs,
698											  UInt32 numDestPlugs,
699											  uint64_t userCallBack,
700											  uint64_t userRefCon,
701											  UInt32 *subUnitID)
702{
703    IOReturn res = kIOReturnSuccess;
704	AVCSubunitInfo *subUnitInfo;
705	UInt32 count;
706	UInt32 i;
707
708	//IOLog( "IOFireWireAVCTargetSpace::addSubunit (0x%08X)\n",(int) this);
709
710	AVCTARGETMUTEX_LOCK;
711
712	// Make sure that we don't have too many
713	// subunits already, or too many of the specified type
714	if (fSubunits->getCount() >= 32)
715		res = kIOReturnNoResources;
716	count = subUnitOfTypeCount(subunitType);
717	if (count >= 4)
718		res = kIOReturnNoResources;
719
720	// Create a new subunit info object
721	if (res == kIOReturnSuccess)
722	{
723		subUnitInfo = AVCSubunitInfo::create();
724		if(!subUnitInfo)
725			res = kIOReturnNoMemory;
726		else
727		{
728			// Initialize the new object's parameters
729			subUnitInfo->userClient = userClient;
730			subUnitInfo->callBack = callBack;
731			bcopy(asyncRef, subUnitInfo->asyncRef, sizeof(OSAsyncReference64));
732			subUnitInfo->numSourcePlugs = numSourcePlugs;
733			subUnitInfo->numDestPlugs = numDestPlugs;
734			subUnitInfo->userCallBack = userCallBack;
735			subUnitInfo->userRefCon = userRefCon;
736
737			// Allocate the plug records for the source plugs
738			if (numSourcePlugs)
739			{
740				subUnitInfo->sourcePlugRecords = new AVCSubunitPlugRecord[numSourcePlugs];
741				for (i=0;i<numSourcePlugs;i++)
742				{
743					subUnitInfo->sourcePlugRecords[i].connectionCount = 0;
744					subUnitInfo->sourcePlugRecords[i].plugSignalFormat = kAVCPlugSignalFormatNTSCDV;
745				}
746			}
747			else
748				subUnitInfo->sourcePlugRecords = NULL;
749
750			// Allocate the plug records for the destination plugs
751			if (numDestPlugs)
752			{
753				subUnitInfo->destPlugRecords = new AVCSubunitPlugRecord[numDestPlugs];
754				for (i=0;i<numDestPlugs;i++)
755				{
756					subUnitInfo->destPlugRecords[i].connectionCount = 0;
757					subUnitInfo->destPlugRecords[i].plugSignalFormat = kAVCPlugSignalFormatNTSCDV;
758				}
759			}
760			else
761				subUnitInfo->destPlugRecords = NULL;
762
763			// Determine the ID for this subunit
764			subUnitInfo->subunitTypeAndID = (subunitType << 3) + count;
765
766			// Save command handler info in array
767			if(!fSubunits->setObject(subUnitInfo))
768				res = kIOReturnNoMemory;
769			else
770			{
771				//IOLog( "DEBUG: addSubunit added subunit to array (0x%08X)\n",(int) userClient);
772			}
773		}
774
775		*subUnitID  = subUnitInfo->subunitTypeAndID;
776		subUnitInfo->release();
777	}
778
779	AVCTARGETMUTEX_UNLOCK;
780
781	return res;
782}
783
784//////////////////////////////////////////////////////
785// IOFireWireAVCTargetSpace::setSubunitPlugSignalFormat
786//////////////////////////////////////////////////////
787IOReturn IOFireWireAVCTargetSpace::setSubunitPlugSignalFormat(IOFireWireAVCProtocolUserClient *userClient,
788															  UInt32 subunitTypeAndID,
789															  IOFWAVCPlugTypes plugType,
790															  UInt32 plugNum,
791															  UInt32 signalFormat)
792{
793	IOReturn res = kIOReturnBadArgument;	// Preinitialize with an error
794	AVCSubunitInfo *subUnitInfo;
795
796	//IOLog( "IOFireWireAVCTargetSpace::setSubunitPlugSignalFormat (0x%08X)\n",(int) this);
797
798	AVCTARGETMUTEX_LOCK;
799
800	// See if this subunit exists
801	subUnitInfo = getSubunitInfo(subunitTypeAndID);
802	if (subUnitInfo)
803		res = kIOReturnSuccess;
804
805	// See if the caller owns this subunit
806	if ((res == kIOReturnSuccess) && (userClient != subUnitInfo->userClient))
807			res = kIOReturnBadArgument;
808
809	// If this is a valid plug, set its signal format
810	if (res == kIOReturnSuccess)
811	{
812		if ((plugType == IOFWAVCPlugSubunitSourceType) && (plugNum < subUnitInfo->numSourcePlugs))
813			subUnitInfo->sourcePlugRecords[plugNum].plugSignalFormat = signalFormat;
814		else if ((plugType == IOFWAVCPlugSubunitDestType) && (plugNum < subUnitInfo->numDestPlugs))
815			subUnitInfo->destPlugRecords[plugNum].plugSignalFormat = signalFormat;
816		else
817			res = kIOReturnBadArgument;
818	}
819
820	AVCTARGETMUTEX_UNLOCK;
821
822	return res;
823}
824
825//////////////////////////////////////////////////////
826// IOFireWireAVCTargetSpace::getSubunitPlugSignalFormat
827//////////////////////////////////////////////////////
828IOReturn IOFireWireAVCTargetSpace::getSubunitPlugSignalFormat(IOFireWireAVCProtocolUserClient *userClient,
829											UInt32 subunitTypeAndID,
830											IOFWAVCPlugTypes plugType,
831											UInt32 plugNum,
832											UInt32 *pSignalFormat)
833{
834	IOReturn res = kIOReturnBadArgument;	// Preinitialize with an error
835	AVCSubunitInfo *subUnitInfo;
836
837	//IOLog( "IOFireWireAVCTargetSpace::getSubunitPlugSignalFormat (0x%08X)\n",(int) this);
838
839	AVCTARGETMUTEX_LOCK;
840
841	// Special Handling for unit plugs
842	if (subunitTypeAndID == kAVCUnitAddress)
843	{
844		// TODO: For unit commands, find connected subunit plug (if exists)
845		// and return its signal format. For now just return an error!
846		res = kIOReturnBadArgument;
847	}
848	else
849	{
850		// See if this subunit exists
851		subUnitInfo = getSubunitInfo(subunitTypeAndID);
852		if (subUnitInfo)
853			res = kIOReturnSuccess;
854
855		// If this is a valid plug, get its signal format
856		if (res == kIOReturnSuccess)
857		{
858			if ((plugType == IOFWAVCPlugSubunitSourceType) && (plugNum < subUnitInfo->numSourcePlugs))
859				*pSignalFormat = subUnitInfo->sourcePlugRecords[plugNum].plugSignalFormat;
860			else if ((plugType == IOFWAVCPlugSubunitDestType) && (plugNum < subUnitInfo->numDestPlugs))
861				*pSignalFormat = subUnitInfo->destPlugRecords[plugNum].plugSignalFormat;
862			else
863				res = kIOReturnBadArgument;
864		}
865	}
866
867	AVCTARGETMUTEX_UNLOCK;
868
869	return res;
870}
871
872//////////////////////////////////////////////////////
873// IOFireWireAVCTargetSpace::connectTargetPlugs
874//////////////////////////////////////////////////////
875IOReturn IOFireWireAVCTargetSpace::connectTargetPlugs(IOFireWireAVCProtocolUserClient *userClient,
876													  AVCConnectTargetPlugsInParams *inParams,
877													  AVCConnectTargetPlugsOutParams *outParams)
878{
879	IOReturn res = kIOReturnSuccess;
880	AVCSubunitInfo *sourceSubUnitInfo = NULL;
881	AVCSubunitInfo *destSubUnitInfo = NULL;
882	UInt32 sourcePlugIndex;
883	UInt32 destPlugIndex;
884	UInt32 sourcePlugNum;
885	UInt32 destPlugNum;
886	int i;
887	bool found;
888	bool plugFound;
889	AVCConnectionRecord *connection;
890	UInt32 actualPlug;
891
892	//IOLog( "IOFireWireAVCTargetSpace::connectTargetPlugs (0x%08X)\n",(int) this);
893
894	AVCTARGETMUTEX_LOCK;
895
896	// See if this connection already exists
897	for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
898	{
899		connection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
900		if ((inParams->sourceSubunitTypeAndID == connection->sourceSubunitTypeAndID) &&
901	  (inParams->sourcePlugType == connection->sourcePlugType) &&
902	  (inParams->sourcePlugNum == connection->sourcePlugNum) &&
903	  (inParams->destSubunitTypeAndID == connection->destSubunitTypeAndID) &&
904	  (inParams->destPlugType == connection->destPlugType) &&
905	  (inParams->destPlugNum == connection->destPlugNum))
906		{
907			// Connection exists. Set lock and/or perm
908			// if specified, and return success
909
910			if (inParams->lockConnection == true)
911				connection->lockConnection = true;
912
913			if (inParams->permConnection == true)
914				connection->permConnection = true;
915
916			outParams->sourcePlugNum = connection->sourcePlugNum;
917			outParams->destPlugNum = connection->destPlugNum;
918
919			AVCTARGETMUTEX_UNLOCK;
920			return res;
921		}
922	}
923
924	// Identify Source Plug for Connection
925	if (inParams->sourceSubunitTypeAndID == kAVCUnitAddress)
926	{
927		switch (inParams->sourcePlugType)
928		{
929			case IOFWAVCPlugIsochInputType:
930				if (inParams->sourcePlugNum == kAVCAnyAvailableIsochPlug)
931				{
932					// Search for an unconnected plug first,
933					// then, if all connected, overlay a connection.
934					plugFound = false;
935					for (i=0;i<kAVCMaxNumPlugs;i++)
936					{
937						if (fUnitPlugs.isochInPlugRecord[i].connectionCount == 0)
938						{
939							sourcePlugIndex=i;
940							sourcePlugNum=i;
941							plugFound = true;
942							break;
943						}
944					}
945					if (!plugFound)
946					{
947						// No available plugs, just overlay on first plug.
948						sourcePlugIndex=0;
949						sourcePlugNum=0;
950					}
951				}
952				else if (inParams->sourcePlugNum < kAVCMaxNumPlugs)
953				{
954					sourcePlugIndex = inParams->sourcePlugNum;
955					sourcePlugNum = sourcePlugIndex;
956				}
957				else
958					res = kIOReturnBadArgument;
959				break;
960
961			case IOFWAVCPlugExternalInputType:
962				if (inParams->sourcePlugNum == kAVCAnyAvailableExternalPlug)
963				{
964					// Search for an unconnected plug first,
965					// then, if all connected, overlay a connection.
966					plugFound = false;
967					for (i=0;i<kAVCMaxNumPlugs;i++)
968					{
969						if (fUnitPlugs.externalInPlugRecord[i].connectionCount == 0)
970						{
971							sourcePlugIndex=i;
972							sourcePlugNum= 0x80 + i;
973							plugFound = true;
974							break;
975						}
976					}
977					if (!plugFound)
978					{
979						// No available plugs, just overlay on first plug.
980						sourcePlugIndex=0;
981						sourcePlugNum = 0x80;
982					}
983				}
984				else if ((inParams->sourcePlugNum >= 0x80) && (inParams->sourcePlugNum < 0x9F))
985				{
986					sourcePlugIndex = inParams->sourcePlugNum - 0x80;
987					sourcePlugNum = inParams->sourcePlugNum;
988				}
989				else
990					res = kIOReturnBadArgument;
991				break;
992
993			default:
994				res = kIOReturnBadArgument;
995				break;
996		};
997	}
998	else
999	{
1000		found = false;
1001		for (i=(fSubunits->getCount()-1);i>=0;i--)
1002		{
1003			sourceSubUnitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
1004			if (inParams->sourceSubunitTypeAndID == sourceSubUnitInfo->subunitTypeAndID)
1005			{
1006				found = true;
1007				break;
1008			}
1009		}
1010		if (found == false)
1011			res = kIOReturnBadArgument;
1012
1013		// For internally initiated connection, verify that the userClient owns this subunit
1014		if ((res == kIOReturnSuccess) && (userClient != NULL) && (sourceSubUnitInfo->userClient != userClient))
1015			res = kIOReturnBadArgument;
1016
1017		if (res == kIOReturnSuccess)
1018		{
1019			switch (inParams->sourcePlugType)
1020			{
1021				case IOFWAVCPlugSubunitSourceType:
1022					if ((inParams->sourcePlugNum == kAVCAnyAvailableSubunitPlug) && (sourceSubUnitInfo->numSourcePlugs > 0))
1023					{
1024						// Search for an unconnected plug first,
1025						// then, if all connected, overlay a connection.
1026						plugFound = false;
1027						for (i=0;i<(int)sourceSubUnitInfo->numSourcePlugs;i++)
1028						{
1029							if (sourceSubUnitInfo->sourcePlugRecords[i].connectionCount == 0)
1030							{
1031								sourcePlugIndex=i;
1032								sourcePlugNum=i;
1033								plugFound = true;
1034								break;
1035							}
1036						}
1037						if (!plugFound)
1038						{
1039							// No available plugs, just overlay on first plug.
1040							sourcePlugIndex=0;
1041							sourcePlugNum=0;
1042						}
1043					}
1044					else if (inParams->sourcePlugNum < sourceSubUnitInfo->numSourcePlugs)
1045					{
1046						sourcePlugIndex = inParams->sourcePlugNum;
1047						sourcePlugNum = sourcePlugIndex;
1048					}
1049					else
1050						res = kIOReturnBadArgument;
1051					break;
1052
1053				default:
1054					res = kIOReturnBadArgument;
1055					break;
1056			};
1057		}
1058	}
1059
1060	// Identify Destination Plug for Connection
1061	if (res == kIOReturnSuccess)
1062	{
1063		if (inParams->destSubunitTypeAndID == kAVCUnitAddress)
1064		{
1065			switch (inParams->destPlugType)
1066			{
1067				case IOFWAVCPlugIsochOutputType:
1068					if (inParams->destPlugNum == kAVCAnyAvailableIsochPlug)
1069					{
1070						// Search for an unconnected plug first
1071						plugFound = false;
1072						for (i=0;i<kAVCMaxNumPlugs;i++)
1073						{
1074							if (fUnitPlugs.isochOutPlugRecord[i].connectionCount == 0)
1075							{
1076								destPlugIndex=i;
1077								destPlugNum=i;
1078								plugFound = true;
1079								break;
1080							}
1081						}
1082						if (!plugFound)
1083						{
1084							// We had no unconnected plugs available, so
1085							// next, we need to see if we can find a non-locked,
1086							// non-permanent connection to an isoch output plug,
1087							// and if so, disconnect it and use that isoch out
1088							// plug for this new connection.
1089							actualPlug = kAVCInvalidPlug;
1090							if (canConnectDestPlug(kAVCUnitAddress,
1091							  IOFWAVCPlugIsochOutputType,
1092							  &actualPlug))
1093							{
1094								destPlugIndex = actualPlug;
1095								destPlugNum = destPlugIndex;
1096							}
1097							else
1098								res = kIOReturnBadArgument;
1099						}
1100					}
1101					else if (inParams->destPlugNum < kAVCMaxNumPlugs)
1102					{
1103						if (canConnectDestPlug(kAVCUnitAddress,
1104							 IOFWAVCPlugIsochOutputType,
1105							 &inParams->destPlugNum))
1106						{
1107							destPlugIndex = inParams->destPlugNum;
1108							destPlugNum = destPlugIndex;
1109						}
1110						else
1111							res = kIOReturnBadArgument;
1112					}
1113					else
1114						res = kIOReturnBadArgument;
1115					break;
1116
1117				case IOFWAVCPlugExternalOutputType:
1118					if (inParams->destPlugNum == kAVCAnyAvailableExternalPlug)
1119					{
1120						// Search for an unconnected plug first
1121						plugFound = false;
1122						for (i=0;i<kAVCMaxNumPlugs;i++)
1123						{
1124							if (fUnitPlugs.externalOutPlugRecord[i].connectionCount == 0)
1125							{
1126								destPlugIndex=i;
1127								destPlugNum= 0x80 + i;
1128								plugFound = true;
1129								break;
1130							}
1131						}
1132						if (!plugFound)
1133						{
1134							// We had no unconnected plugs available, so
1135							// next, we need to see if we can find a non-locked,
1136							// non-permanent connection to an external output plug,
1137							// and if so, disconnect it and use that extern out
1138							// plug for this new connection.
1139							actualPlug = kAVCInvalidPlug;
1140							if (canConnectDestPlug(kAVCUnitAddress,
1141							  IOFWAVCPlugExternalOutputType,
1142							  &actualPlug))
1143							{
1144								destPlugIndex = actualPlug - 0x80;
1145								destPlugNum = actualPlug;
1146							}
1147							else
1148								res = kIOReturnBadArgument;
1149						}
1150					}
1151					else if ((inParams->destPlugNum >= 0x80) && (inParams->destPlugNum < 0x9F))
1152					{
1153						if (canConnectDestPlug(kAVCUnitAddress,
1154							 IOFWAVCPlugExternalOutputType,
1155							 &inParams->destPlugNum))
1156						{
1157							destPlugIndex = inParams->destPlugNum - 0x80;
1158							destPlugNum = inParams->destPlugNum;
1159						}
1160						else
1161							res = kIOReturnBadArgument;
1162					}
1163					else
1164						res = kIOReturnBadArgument;
1165					break;
1166
1167				default:
1168					res = kIOReturnBadArgument;
1169					break;
1170			};
1171		}
1172		else
1173		{
1174			found = false;
1175			for (i=(fSubunits->getCount()-1);i>=0;i--)
1176			{
1177				destSubUnitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
1178				if (inParams->destSubunitTypeAndID == destSubUnitInfo->subunitTypeAndID)
1179				{
1180					found = true;
1181					break;
1182				}
1183			}
1184			if (found == false)
1185				res = kIOReturnBadArgument;
1186
1187			// For internally initiated connection, verify that the userClient owns this subunit
1188			if ((res == kIOReturnSuccess) && (userClient != NULL) && (destSubUnitInfo->userClient != userClient))
1189				res = kIOReturnBadArgument;
1190
1191			if (res == kIOReturnSuccess)
1192			{
1193				switch (inParams->destPlugType)
1194				{
1195					case IOFWAVCPlugSubunitDestType:
1196						if ((inParams->destPlugNum == kAVCAnyAvailableSubunitPlug) && (destSubUnitInfo->numDestPlugs > 0))
1197						{
1198							// Search for an unconnected plug first
1199							plugFound = false;
1200							for (i=0;i<(int)destSubUnitInfo->numDestPlugs;i++)
1201							{
1202								if (destSubUnitInfo->destPlugRecords[i].connectionCount == 0)
1203								{
1204									destPlugIndex =i;
1205									destPlugNum =i;
1206									plugFound = true;
1207									break;
1208								}
1209							}
1210							if (!plugFound)
1211							{
1212								// We had no unconnected plugs available, so
1213								// next, we need to see if we can find a non-locked,
1214								// non-permanent connection to one of this subunits dest plugs,
1215								// and if so, disconnect it and use that
1216								// plug for this new connection.
1217								actualPlug = kAVCInvalidPlug;
1218								if (canConnectDestPlug(destSubUnitInfo->subunitTypeAndID,
1219							   IOFWAVCPlugSubunitDestType,
1220							   &actualPlug))
1221								{
1222									destPlugIndex = actualPlug;
1223									destPlugNum = destPlugIndex;
1224								}
1225								else
1226									res = kIOReturnBadArgument;
1227							}
1228						}
1229						else if (inParams->destPlugNum < destSubUnitInfo->numDestPlugs)
1230						{
1231							if (canConnectDestPlug(destSubUnitInfo->subunitTypeAndID,
1232							  IOFWAVCPlugSubunitDestType,
1233							  &inParams->destPlugNum))
1234							{
1235								destPlugIndex = inParams->destPlugNum;
1236								destPlugNum = destPlugIndex;
1237							}
1238							else
1239								res = kIOReturnBadArgument;
1240						}
1241						else
1242							res = kIOReturnBadArgument;
1243						break;
1244
1245					default:
1246						res = kIOReturnBadArgument;
1247						break;
1248				};
1249			}
1250		}
1251	}
1252
1253	// Here, we know that we have a valid source and
1254	// destination plug, so make the connection
1255	if (res == kIOReturnSuccess)
1256	{
1257		connection = new AVCConnectionRecord;
1258		if(!connection)
1259			res = kIOReturnNoMemory;
1260
1261		if (res == kIOReturnSuccess)
1262		{
1263			// Update connection record parameters
1264			connection->sourceSubunitTypeAndID = inParams->sourceSubunitTypeAndID;
1265			connection->sourcePlugType = inParams->sourcePlugType;
1266			connection->sourcePlugNum = sourcePlugNum;
1267			connection->destSubunitTypeAndID = inParams->destSubunitTypeAndID;
1268			connection->destPlugType = inParams->destPlugType;
1269			connection->destPlugNum = destPlugNum;
1270			connection->lockConnection = inParams->lockConnection;
1271			connection->permConnection = inParams->permConnection;
1272
1273			if(!fConnectionRecords->setObject(connection))
1274				res = kIOReturnNoMemory;
1275			connection->release();
1276			//IOLog( "DEBUG: connectTargetPlugs added connection record to array (0x%08X)\n",(int) userClient);
1277
1278			// Update plug records in subunit/unit
1279			if (res == kIOReturnSuccess)
1280			{
1281				switch (inParams->sourcePlugType)
1282				{
1283					case IOFWAVCPlugIsochInputType:
1284						fUnitPlugs.isochInPlugRecord[sourcePlugIndex].connectionCount++;
1285						break;
1286					case IOFWAVCPlugExternalInputType:
1287						fUnitPlugs.externalInPlugRecord[sourcePlugIndex].connectionCount++;
1288						break;
1289					case IOFWAVCPlugSubunitSourceType:
1290						sourceSubUnitInfo->sourcePlugRecords[sourcePlugIndex].connectionCount++;
1291						break;
1292					default:
1293						break;
1294				};
1295				switch (inParams->destPlugType)
1296				{
1297					case IOFWAVCPlugIsochOutputType:
1298						fUnitPlugs.isochOutPlugRecord[destPlugIndex].connectionCount++;
1299						break;
1300					case IOFWAVCPlugExternalOutputType:
1301						fUnitPlugs.externalOutPlugRecord[destPlugIndex].connectionCount++;
1302						break;
1303					case IOFWAVCPlugSubunitDestType:
1304						destSubUnitInfo->destPlugRecords[destPlugIndex].connectionCount++;
1305						break;
1306					default:
1307						break;
1308				};
1309			}
1310
1311			// If source is a subunit, notify source plug owner of new connection
1312			if ((res == kIOReturnSuccess) && (sourceSubUnitInfo))
1313				sourceSubUnitInfo->callBack(sourceSubUnitInfo,
1314								kIOFWAVCSubunitPlugMsgConnected,
1315								inParams->sourcePlugType,
1316								sourcePlugNum,
1317								((inParams->destSubunitTypeAndID << 16) + (inParams->destPlugType << 8) + destPlugNum),
1318								0,0);
1319
1320			// If dest is a subunit, notify dest plug owner of new connection
1321			if ((res == kIOReturnSuccess) && (destSubUnitInfo))
1322				destSubUnitInfo->callBack(destSubUnitInfo,
1323							  kIOFWAVCSubunitPlugMsgConnected,
1324							  inParams->destPlugType,
1325							  destPlugNum,
1326							  ((inParams->sourceSubunitTypeAndID << 16) + (inParams->sourcePlugType << 8) + sourcePlugNum),
1327							  0,0);
1328
1329			// Update the out Params
1330			if (res == kIOReturnSuccess)
1331			{
1332				outParams->sourcePlugNum = sourcePlugNum;
1333				outParams->destPlugNum = destPlugNum;
1334			}
1335		}
1336	}
1337
1338	AVCTARGETMUTEX_UNLOCK;
1339
1340	return res;
1341}
1342
1343//////////////////////////////////////////////////////
1344// IOFireWireAVCTargetSpace::disconnectTargetPlugs
1345//////////////////////////////////////////////////////
1346IOReturn IOFireWireAVCTargetSpace::disconnectTargetPlugs(IOFireWireAVCProtocolUserClient *userClient,
1347									   UInt32 sourceSubunitTypeAndID,
1348									   IOFWAVCPlugTypes sourcePlugType,
1349									   UInt32 sourcePlugNum,
1350									   UInt32 destSubunitTypeAndID,
1351									   IOFWAVCPlugTypes destPlugType,
1352									   UInt32 destPlugNum)
1353{
1354	int i;
1355	AVCConnectionRecord *connection;
1356	AVCSubunitInfo *sourceSubUnitInfo = NULL;
1357	AVCSubunitInfo *destSubUnitInfo = NULL;
1358	bool found = false;
1359
1360	//IOLog( "IOFireWireAVCTargetSpace::disconnectTargetPlugs (0x%08X)\n",(int) this);
1361
1362	AVCTARGETMUTEX_LOCK;
1363
1364	// Search connection records for this source plug
1365	for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
1366	{
1367		connection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
1368		if ((sourceSubunitTypeAndID == connection->sourceSubunitTypeAndID) &&
1369	  (sourcePlugType == connection->sourcePlugType) &&
1370	  (sourcePlugNum == connection->sourcePlugNum) &&
1371	  (connection->permConnection == false))
1372		{
1373			// Find the info for the source and dest subunits (if not a unit)
1374			if (connection->sourceSubunitTypeAndID != kAVCUnitAddress)
1375				sourceSubUnitInfo = getSubunitInfo(connection->sourceSubunitTypeAndID);
1376			if (connection->destSubunitTypeAndID != kAVCUnitAddress)
1377				destSubUnitInfo = getSubunitInfo(connection->destSubunitTypeAndID);
1378
1379			// Update connection counts in plug records in subunit/unit
1380			switch (connection->sourcePlugType)
1381			{
1382				case IOFWAVCPlugIsochInputType:
1383					fUnitPlugs.isochInPlugRecord[connection->sourcePlugNum].connectionCount--;
1384					break;
1385				case IOFWAVCPlugExternalInputType:
1386					fUnitPlugs.externalInPlugRecord[connection->sourcePlugNum - 0x80].connectionCount--;
1387					break;
1388				case IOFWAVCPlugSubunitSourceType:
1389					if (sourceSubUnitInfo)
1390						sourceSubUnitInfo->sourcePlugRecords[connection->sourcePlugNum].connectionCount--;
1391					break;
1392				default:
1393					break;
1394			};
1395			switch (connection->destPlugType)
1396			{
1397				case IOFWAVCPlugIsochOutputType:
1398					fUnitPlugs.isochOutPlugRecord[connection->destPlugNum].connectionCount--;
1399					break;
1400				case IOFWAVCPlugExternalOutputType:
1401					fUnitPlugs.externalOutPlugRecord[connection->destPlugNum - 0x80].connectionCount--;
1402					break;
1403				case IOFWAVCPlugSubunitDestType:
1404					if (destSubUnitInfo)
1405						destSubUnitInfo->destPlugRecords[connection->destPlugNum].connectionCount--;
1406					break;
1407				default:
1408					break;
1409			};
1410
1411			// If source is a subunit, notify source plug owner of disconnection
1412			if (sourceSubUnitInfo)
1413				sourceSubUnitInfo->callBack(sourceSubUnitInfo,
1414								kIOFWAVCSubunitPlugMsgDisconnected,
1415								connection->sourcePlugType,
1416								connection->sourcePlugNum,
1417								((connection->destSubunitTypeAndID << 16) + (connection->destPlugType << 8) + connection->destPlugNum),
1418								0,0);
1419
1420			// If dest is a subunit, notify dest plug owner of disconnection
1421			if (destSubUnitInfo)
1422				destSubUnitInfo->callBack(destSubUnitInfo,
1423							  kIOFWAVCSubunitPlugMsgDisconnected,
1424							  connection->destPlugType,
1425							  connection->destPlugNum,
1426							  ((connection->sourceSubunitTypeAndID << 16) + (connection->sourcePlugType << 8) + connection->sourcePlugNum),
1427							  0,0);
1428
1429			// Remove the plug connection record from the array
1430			fConnectionRecords->removeObject(i);
1431			found = true;
1432		}
1433	}
1434
1435	AVCTARGETMUTEX_UNLOCK;
1436
1437	if (found)
1438		return kIOReturnSuccess;
1439	else
1440		return kIOReturnBadArgument;
1441}
1442
1443//////////////////////////////////////////////////////
1444// IOFireWireAVCTargetSpace::getTargetPlugConnection
1445//////////////////////////////////////////////////////
1446IOReturn IOFireWireAVCTargetSpace::getTargetPlugConnection(IOFireWireAVCProtocolUserClient *userClient,
1447														   AVCGetTargetPlugConnectionInParams *inParams,
1448														   AVCGetTargetPlugConnectionOutParams *outParams)
1449{
1450	IOReturn res;
1451	int i;
1452	AVCConnectionRecord *connection;
1453	UInt32 count = 0;
1454
1455	//IOLog( "IOFireWireAVCTargetSpace::getTargetPlugConnection (0x%08X)\n",(int) this);
1456
1457	AVCTARGETMUTEX_LOCK;
1458
1459	// Search connection records for this source plug
1460	for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
1461	{
1462		connection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
1463
1464		switch (inParams->plugType)
1465		{
1466			case IOFWAVCPlugSubunitSourceType:
1467			case IOFWAVCPlugIsochOutputType:
1468			case IOFWAVCPlugExternalOutputType:
1469				if ((inParams->subunitTypeAndID == connection->sourceSubunitTypeAndID) &&
1470		(inParams->plugType == connection->sourcePlugType) &&
1471		(inParams->plugNum == connection->sourcePlugNum))
1472				{
1473					outParams->connectedSubunitTypeAndID = connection->destSubunitTypeAndID;
1474					outParams->connectedPlugType = connection->destPlugType;
1475					outParams->connectedPlugNum = connection->destPlugNum;
1476					outParams->lockConnection = connection->lockConnection;
1477					outParams->permConnection = connection->permConnection;
1478					count += 1;
1479				}
1480				break;
1481
1482			case IOFWAVCPlugSubunitDestType:
1483			case IOFWAVCPlugIsochInputType:
1484			case IOFWAVCPlugExternalInputType:
1485				if ((inParams->subunitTypeAndID == connection->destSubunitTypeAndID) &&
1486		(inParams->plugType == connection->destPlugType) &&
1487		(inParams->plugNum == connection->destPlugNum))
1488				{
1489					outParams->connectedSubunitTypeAndID = connection->sourceSubunitTypeAndID;
1490					outParams->connectedPlugType = connection->sourcePlugType;
1491					outParams->connectedPlugNum = connection->sourcePlugNum;
1492					outParams->lockConnection = connection->lockConnection;
1493					outParams->permConnection = connection->permConnection;
1494					count += 1;
1495				}
1496				break;
1497
1498			default:
1499				break;
1500		};
1501	}
1502
1503	if (count == 0)
1504		res = kIOReturnBadArgument;
1505	else
1506	{
1507		res = kIOReturnSuccess;
1508		if (count > 1)
1509			outParams->connectedPlugNum = kAVCMultiplePlugs;
1510	}
1511
1512	AVCTARGETMUTEX_UNLOCK;
1513
1514	return res;
1515}
1516
1517//////////////////////////////////////////////////////
1518// IOFireWireAVCTargetSpace::handleUnitInfoCommand
1519//////////////////////////////////////////////////////
1520IOReturn IOFireWireAVCTargetSpace::handleUnitInfoCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
1521{
1522	UInt8 *pResponse;
1523	UInt8 *pBuf = (UInt8*) buf;
1524	UInt8 cType;
1525	IOBufferMemoryDescriptor *pBufMemDesc = NULL;
1526	AVCSubunitInfo *subUnitInfo;
1527
1528	//IOLog( "IOFireWireAVCTargetSpace::handleUnitInfoCommand (0x%08X)\n",(int) this);
1529
1530	// Check the length of the command. Don't handle command if wrong.
1531	if (len != 8)
1532		return kIOReturnError;
1533
1534	// Parse the command buf
1535	cType = pBuf[0] & 0x0F;
1536
1537	// Check the cType.  Don't handle command if not a status type.
1538	if (cType != kAVCStatusInquiryCommand)
1539		return kIOReturnError;
1540
1541	// Check the operands.  Don't handle command if not properly initialized.
1542	if ((pBuf[kAVCOperand0] != 0xFF) ||
1543	 (pBuf[kAVCOperand1] != 0xFF) ||
1544	 (pBuf[kAVCOperand2] != 0xFF) ||
1545	 (pBuf[kAVCOperand3] != 0xFF) ||
1546	 (pBuf[kAVCOperand4] != 0xFF))
1547		return kIOReturnError;
1548
1549	// All tests passed. Handle the command
1550	pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
1551	if(!pBufMemDesc)
1552		return kFWResponseDataError;
1553	pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
1554
1555	// Initialize the response
1556	pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
1557	pResponse[kAVCAddress] = pBuf[kAVCAddress];
1558	pResponse[kAVCOpcode] = pBuf[kAVCOpcode];
1559	pResponse[kAVCOperand0] = 0x07;
1560
1561	AVCTARGETMUTEX_LOCK;
1562
1563	// This is the unit type field. Set to value of first subunit
1564	// in subunit info list if it exists
1565	if (fSubunits->getCount() > 0)
1566	{
1567		subUnitInfo = (AVCSubunitInfo*) fSubunits->getObject(0);
1568		pResponse[kAVCOperand1] = subUnitInfo->subunitTypeAndID;
1569	}
1570	else
1571		pResponse[kAVCOperand1] = 0xFF;
1572
1573	// Add Apple's OUI to the company_ID field of the response
1574	pResponse[kAVCOperand2] = 0x00;
1575	pResponse[kAVCOperand3] = 0x03;
1576	pResponse[kAVCOperand4] = 0x93;
1577
1578	targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
1579
1580	AVCTARGETMUTEX_UNLOCK;
1581
1582	return kIOReturnSuccess;
1583}
1584
1585//////////////////////////////////////////////////////
1586// IOFireWireAVCTargetSpace::handleSubUnitInfoCommand
1587//////////////////////////////////////////////////////
1588IOReturn IOFireWireAVCTargetSpace::handleSubUnitInfoCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
1589{
1590	UInt8 *pResponse;
1591	UInt8 *pBuf = (UInt8*) buf;
1592	UInt8 cType;
1593	UInt8 page;
1594	IOBufferMemoryDescriptor *pBufMemDesc = NULL;
1595	int i;
1596	AVCSubunitInfo *subUnitInfo;
1597	UInt32 subUnitType;
1598	UInt8 count[32];
1599	UInt32 uniqueSubUnitCount = 0;
1600	UInt32 countArrayIndex;
1601	int skipped;
1602
1603	//IOLog( "IOFireWireAVCTargetSpace::handleSubUnitInfoCommand (0x%08X)\n",(int) this);
1604
1605	// Check the length of the command. Don't handle command if wrong.
1606	if (len != 8)
1607		return kIOReturnError;
1608
1609	// Parse the command buf
1610	cType = pBuf[0] & 0x0F;
1611
1612	// Check the cType.  Don't handle command if not a status type.
1613	if (cType != kAVCStatusInquiryCommand)
1614		return kIOReturnError;
1615
1616	// Check the operands.  Don't handle command if not properly initialized.
1617	if (((pBuf[kAVCOperand0] & 0x8F) != 0x07) ||
1618	 (pBuf[kAVCOperand1] != 0xFF) ||
1619	 (pBuf[kAVCOperand2] != 0xFF) ||
1620	 (pBuf[kAVCOperand3] != 0xFF) ||
1621	 (pBuf[kAVCOperand4] != 0xFF))
1622		return kIOReturnError;
1623
1624	AVCTARGETMUTEX_LOCK;
1625
1626	// Initialize the count array
1627	for (i=0;i<32;i++)
1628		count[i] = 0;
1629
1630	// Parse the subunit list
1631	for (i=(fSubunits->getCount()-1);i>=0;i--)
1632	{
1633		subUnitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
1634		subUnitType = ((subUnitInfo->subunitTypeAndID & 0xF8) >> 3);
1635		if (count[subUnitType] == 0)
1636			uniqueSubUnitCount += 1;
1637		count[subUnitType] += 1;
1638    }
1639
1640	// Check the page to see if valid
1641	page = ((pBuf[kAVCOperand0] & 0x70) >> 4);
1642	if (page > uniqueSubUnitCount/4)
1643	{
1644		AVCTARGETMUTEX_UNLOCK;
1645		return kIOReturnError;	// Spec says empty page should result in NOT_IMPLEMENTED response
1646	}
1647
1648	// All tests passed. Handle the command
1649	pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
1650	if(!pBufMemDesc)
1651	{
1652		AVCTARGETMUTEX_UNLOCK;
1653		return kFWResponseDataError;
1654	}
1655	pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
1656
1657	// Initialize the response
1658	pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
1659	pResponse[kAVCAddress] = pBuf[kAVCAddress];
1660	pResponse[kAVCOpcode] = pBuf[kAVCOpcode];
1661	pResponse[kAVCOperand0] = pBuf[kAVCOperand0];
1662
1663	// Fill in subunit info page data
1664	for (i=0;i<4;i++)
1665	{
1666		if (((page*4)+i) < (int) uniqueSubUnitCount)
1667		{
1668			// Reset the skipped count
1669			skipped = 0;
1670
1671			// Find the ((page*4)+i) non-zero entry in the count array. It's index is the subunit type, and it's value is the number
1672			// of that type of subunit. Note: We've already confirmed that this entry does indeed exist, so no failsafe code needed here.
1673			for (countArrayIndex = 0; countArrayIndex < 32; countArrayIndex++)
1674			{
1675				if (count[countArrayIndex] != 0)
1676				{
1677					// Found a non-zero entry, is this the one we're looking for?
1678					if (skipped != ((page*4)+i))
1679					{
1680						// This is not the one we're looking for
1681						skipped += 1;
1682					}
1683					else
1684					{
1685						// This is the one we're looking for. The subunit's max ID for the response packet is the count - 1
1686						pResponse[kAVCOperand1+i]  = ((countArrayIndex << 3) | (count[countArrayIndex] > 8 ? 7 : (count[countArrayIndex]-1)));
1687						break;
1688					}
1689				}
1690			}
1691		}
1692		else
1693			pResponse[kAVCOperand1+i]  = 0xFF;
1694	}
1695
1696	targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
1697
1698	AVCTARGETMUTEX_UNLOCK;
1699
1700	return kIOReturnSuccess;
1701}
1702
1703//////////////////////////////////////////////////////
1704// IOFireWireAVCTargetSpace::handlePlugInfoCommand
1705//////////////////////////////////////////////////////
1706IOReturn IOFireWireAVCTargetSpace::handlePlugInfoCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
1707{
1708	UInt8 *pResponse;
1709	UInt8 *pBuf = (UInt8*) buf;
1710	UInt8 cType;
1711	IOBufferMemoryDescriptor *pBufMemDesc = NULL;
1712	int i;
1713	AVCSubunitInfo *subUnitInfo;
1714	bool found = false;
1715
1716	//IOLog( "IOFireWireAVCTargetSpace::handlePlugInfoCommand (0x%08X)\n",(int) this);
1717
1718	// Check the length of the command. Don't handle command if wrong.
1719	if (len != 8)
1720		return kIOReturnError;
1721
1722	// Parse the command buf
1723	cType = pBuf[0] & 0x0F;
1724
1725	// Check the cType.  Don't handle command if not a status type.
1726	if (cType != kAVCStatusInquiryCommand)
1727		return kIOReturnError;
1728
1729	// Check the operands.  Don't handle command if not properly initialized.
1730	if ((pBuf[kAVCOperand1] != 0xFF) ||
1731	 (pBuf[kAVCOperand2] != 0xFF) ||
1732	 (pBuf[kAVCOperand3] != 0xFF) ||
1733	 (pBuf[kAVCOperand4] != 0xFF))
1734		return kIOReturnError;
1735
1736	// Currently, we only support subfunction 0
1737	if (pBuf[kAVCOperand0] != 0x00)
1738		return kIOReturnError;
1739
1740	// All tests passed. Handle the command
1741	pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
1742	if(!pBufMemDesc)
1743		return kFWResponseDataError;
1744	pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
1745	bcopy(buf,pResponse,len);
1746
1747	if (pBuf[kAVCAddress] == kAVCUnitAddress)
1748	{
1749		// Fill in the response values
1750		pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
1751		pResponse[kAVCOperand1] = 31;  // Currently this matches the iMPR/oMPR. Changes will be
1752		pResponse[kAVCOperand2] = 31;  // needed here if we reduce the number of allocated plugs
1753	}
1754	else
1755	{
1756		// This command is addressed to a subunit. See if it's a valid subunit address,
1757		// and, if so, report its dest and source plug count.
1758
1759		AVCTARGETMUTEX_LOCK;
1760
1761		for (i=(fSubunits->getCount()-1);i>=0;i--)
1762		{
1763			subUnitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
1764			if (subUnitInfo->subunitTypeAndID == pBuf[kAVCAddress])
1765			{
1766				pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
1767				pResponse[kAVCOperand1] = subUnitInfo->numDestPlugs;
1768				pResponse[kAVCOperand2] = subUnitInfo->numSourcePlugs;
1769				found = true;
1770				break;
1771			}
1772		}
1773		if (!found)
1774		{
1775			pResponse[kAVCCommandResponse] = kAVCNotImplementedStatus;
1776		}
1777
1778		AVCTARGETMUTEX_UNLOCK;
1779	}
1780
1781	targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
1782
1783	return kIOReturnSuccess;
1784}
1785
1786//////////////////////////////////////////////////////
1787// IOFireWireAVCTargetSpace::handlePowerCommand
1788//////////////////////////////////////////////////////
1789IOReturn IOFireWireAVCTargetSpace::handlePowerCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
1790{
1791	UInt8 *pResponse;
1792	UInt8 *pBuf = (UInt8*) buf;
1793	UInt8 cType;
1794	IOBufferMemoryDescriptor *pBufMemDesc = NULL;
1795
1796	//IOLog( "IOFireWireAVCTargetSpace::handlePowerCommand (0x%08X)\n",(int) this);
1797
1798	// Check the length of the command. Don't handle command if wrong.
1799	if (len != 4)
1800		return kIOReturnError;
1801
1802	// Parse the command buf
1803	cType = pBuf[0] & 0x0F;
1804
1805	// Further check the request packet parameters
1806	switch (cType)
1807	{
1808		case kAVCStatusInquiryCommand:
1809			if (pBuf[kAVCOperand0] != 0x7F)
1810				return kIOReturnError;
1811			break;
1812
1813		case kAVCControlCommand:
1814			if ((pBuf[kAVCOperand0] != 0x60) && (pBuf[kAVCOperand0] != 0x70))
1815				return kIOReturnError;
1816			break;
1817
1818		default:
1819			return kIOReturnError;
1820	};
1821
1822	// All tests passed. Handle the command
1823	pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
1824	if(!pBufMemDesc)
1825		return kFWResponseDataError;
1826	pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
1827	bcopy(buf,pResponse,len);
1828
1829	// Fill in the response values
1830	pResponse[kAVCCommandResponse] = (cType == kAVCStatusInquiryCommand) ? kAVCImplementedStatus : kAVCAcceptedStatus;
1831	pResponse[kAVCOperand0] = (cType == kAVCStatusInquiryCommand) ? 0x70 : pBuf[kAVCOperand0];
1832
1833	targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
1834
1835	return kIOReturnSuccess;
1836}
1837
1838//////////////////////////////////////////////////////
1839// IOFireWireAVCTargetSpace::handleConnectCommand
1840//////////////////////////////////////////////////////
1841IOReturn IOFireWireAVCTargetSpace::handleConnectCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
1842{
1843	UInt8 *pResponse;
1844	UInt8 *pBuf = (UInt8*) buf;
1845	UInt8 cType;
1846	IOBufferMemoryDescriptor *pBufMemDesc = NULL;
1847	int i;
1848	AVCConnectTargetPlugsInParams inParams;
1849	AVCConnectTargetPlugsOutParams outParams;
1850	AVCConnectionRecord *pConnection;
1851	UInt32 connCount = 0;
1852
1853	//IOLog( "IOFireWireAVCTargetSpace::handleConnectCommand (0x%08X)\n",(int) this);
1854
1855	// Check the length of the command. Don't handle command if wrong.
1856	if (len != 8)
1857		return kIOReturnError;
1858
1859	// Parse the command buf
1860	cType = pBuf[0] & 0x0F;
1861
1862	// Further check the request packet parameters
1863	switch (cType)
1864	{
1865		case kAVCStatusInquiryCommand:
1866			if ((pBuf[kAVCOperand0] & 0xFF) != 0xFF)
1867				return kIOReturnError;
1868			break;
1869
1870		case kAVCControlCommand:
1871			if ((pBuf[kAVCOperand0] & 0xFC) != 0xFC)
1872				return kIOReturnError;
1873			break;
1874
1875		default:
1876			return kIOReturnError;
1877	};
1878
1879	// Prepare the connect parameters struct
1880	inParams.sourceSubunitTypeAndID = pBuf[kAVCOperand1];
1881	inParams.sourcePlugNum = pBuf[kAVCOperand2];
1882	inParams.destSubunitTypeAndID = pBuf[kAVCOperand3];
1883	inParams.destPlugNum = pBuf[kAVCOperand4];
1884	inParams.lockConnection = ((pBuf[kAVCOperand0] & 0x02) == 0x02) ? true : false;
1885	inParams.permConnection = false;
1886
1887	// Determine the type of each the source plug
1888	if (inParams.sourceSubunitTypeAndID == kAVCUnitAddress)
1889	{
1890		if ((inParams.sourcePlugNum < kAVCMaxNumPlugs) || (inParams.sourcePlugNum == kAVCAnyAvailableIsochPlug))
1891			inParams.sourcePlugType = IOFWAVCPlugIsochInputType;
1892		else if (((inParams.sourcePlugNum >= 0x80) && (inParams.sourcePlugNum <= 0x9E)) || (inParams.sourcePlugNum == kAVCAnyAvailableExternalPlug))
1893			inParams.sourcePlugType = IOFWAVCPlugExternalInputType;
1894		else if ((cType == kAVCStatusInquiryCommand) && (inParams.sourcePlugNum = kAVCInvalidPlug))
1895			inParams.sourcePlugType = IOFWAVCPlugIsochInputType;
1896		else
1897			return kIOReturnError;
1898	}
1899	else
1900		inParams.sourcePlugType = IOFWAVCPlugSubunitSourceType;
1901
1902	// Determine the type of each the dest plug
1903	if (inParams.destSubunitTypeAndID == kAVCUnitAddress)
1904	{
1905		if ((inParams.destPlugNum < kAVCMaxNumPlugs) || (inParams.destPlugNum == kAVCAnyAvailableIsochPlug))
1906			inParams.destPlugType = IOFWAVCPlugIsochOutputType;
1907		else if (((inParams.destPlugNum >= 0x80) && (inParams.destPlugNum <= 0x9E)) || (inParams.destPlugNum == kAVCAnyAvailableExternalPlug))
1908			inParams.destPlugType = IOFWAVCPlugExternalOutputType;
1909		else if ((cType == kAVCStatusInquiryCommand) && (inParams.destPlugNum = kAVCInvalidPlug))
1910			inParams.destPlugType = IOFWAVCPlugIsochOutputType;
1911		else
1912			return kIOReturnError;
1913	}
1914	else
1915		inParams.destPlugType = IOFWAVCPlugSubunitDestType;
1916
1917	// All tests passed. Handle the command
1918	pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
1919	if(!pBufMemDesc)
1920		return kFWResponseDataError;
1921	pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
1922	bcopy(buf,pResponse,len);
1923
1924	if (cType == kAVCStatusInquiryCommand)
1925	{
1926		AVCTARGETMUTEX_LOCK;
1927
1928		// Initialize response
1929		pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
1930
1931		if ((inParams.sourceSubunitTypeAndID == 0xFF) && (inParams.sourcePlugNum == 0xFE))
1932		{
1933			// We're searching for a destination plug's connections
1934			for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
1935			{
1936				pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
1937				if ((pConnection->destSubunitTypeAndID == inParams.destSubunitTypeAndID) &&
1938		(pConnection->destPlugNum == inParams.destPlugNum))
1939				{
1940					connCount++;
1941					pResponse[kAVCOperand1] = pConnection->sourceSubunitTypeAndID;
1942					pResponse[kAVCOperand2] = pConnection->sourcePlugNum;
1943					if (pConnection->lockConnection == false)
1944					{
1945						pResponse[kAVCOperand0] &= 0xFD;	// Clear bit 1
1946					}
1947					if (pConnection->permConnection == false)
1948					{
1949						pResponse[kAVCOperand0] &= 0xFE;	// Clear bit 0
1950					}
1951				}
1952			}
1953			if (connCount == 0)
1954			{
1955				pResponse[kAVCOperand2] = kAVCInvalidPlug;
1956			}
1957			else if (connCount > 1)
1958			{
1959				pResponse[kAVCOperand1] = kAVCUnitAddress;
1960				pResponse[kAVCOperand2] = kAVCMultiplePlugs;
1961				pResponse[kAVCOperand0] |= 0x03;	// Set bits 0 and 1
1962
1963			}
1964		}
1965		else if ((inParams.destSubunitTypeAndID == 0xFF) && (inParams.destPlugNum == 0xFE))
1966
1967		{
1968			// We're searching for a source plug's connections
1969			for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
1970			{
1971				pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
1972				if ((pConnection->sourceSubunitTypeAndID == inParams.sourceSubunitTypeAndID) &&
1973		(pConnection->sourcePlugNum == inParams.sourcePlugNum))
1974				{
1975					connCount++;
1976					pResponse[kAVCOperand3] = pConnection->destSubunitTypeAndID;
1977					pResponse[kAVCOperand4] = pConnection->destPlugNum;
1978					if (pConnection->lockConnection == false)
1979					{
1980						pResponse[kAVCOperand0] &= 0xFD;	// Clear bit 1
1981					}
1982					if (pConnection->permConnection == false)
1983					{
1984						pResponse[kAVCOperand0] &= 0xFE;	// Clear bit 0
1985					}
1986				}
1987			}
1988			if (connCount == 0)
1989			{
1990				pResponse[kAVCOperand4] = kAVCInvalidPlug;
1991			}
1992			else if (connCount > 1)
1993			{
1994				pResponse[kAVCOperand3] = kAVCUnitAddress;
1995				pResponse[kAVCOperand4] = kAVCMultiplePlugs;
1996				pResponse[kAVCOperand0] |= 0x03;	// Set bits 0 and 1
1997			}
1998		}
1999		else
2000		{
2001			// Parameter error, return not implemented response
2002			pResponse[kAVCCommandResponse] = kAVCNotImplementedStatus;
2003		}
2004	}
2005	else
2006	{
2007		// Initialize response
2008		pResponse[kAVCCommandResponse] = kAVCAcceptedStatus;
2009
2010		// Try and connect the plugs
2011		if (connectTargetPlugs(NULL,&inParams,&outParams) == kIOReturnSuccess)
2012		{
2013			// Update the plug num fields in the response
2014			pResponse[kAVCOperand2] = outParams.sourcePlugNum;
2015			pResponse[kAVCOperand4] = outParams.destPlugNum;
2016		}
2017		else
2018		{
2019			// Set rejected status in response
2020			pResponse[kAVCCommandResponse] = kAVCRejectedStatus;
2021		}
2022	}
2023
2024	AVCTARGETMUTEX_UNLOCK;
2025
2026	// Send the response
2027	targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
2028
2029	return kIOReturnSuccess;
2030}
2031
2032//////////////////////////////////////////////////////
2033// IOFireWireAVCTargetSpace::handleDisconnectCommand
2034//////////////////////////////////////////////////////
2035IOReturn IOFireWireAVCTargetSpace::handleDisconnectCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
2036{
2037	UInt8 *pResponse;
2038	UInt8 *pBuf = (UInt8*) buf;
2039	UInt8 cType;
2040	IOBufferMemoryDescriptor *pBufMemDesc = NULL;
2041	IOReturn res;
2042	IOFWAVCPlugTypes sourcePlugType;
2043	IOFWAVCPlugTypes destPlugType;
2044
2045	//IOLog( "IOFireWireAVCTargetSpace::handleDisconnectCommand (0x%08X)\n",(int) this);
2046
2047	// Check the length of the command. Don't handle command if wrong.
2048	if (len != 8)
2049		return kIOReturnError;
2050
2051	// Get the cType. Only control type accepted
2052	cType = pBuf[kAVCCommandResponse] & 0x0F;
2053	if (cType != kAVCControlCommand)
2054		return kIOReturnError;
2055
2056	// Further check the request packet parameters
2057	if (pBuf[kAVCOperand0] != 0xFF)
2058		return kIOReturnError;
2059
2060	// Determine type of source plug
2061	if (pBuf[kAVCOperand1] != kAVCUnitAddress)
2062	{
2063		if (pBuf[kAVCOperand2] < kAVCMaxNumPlugs)
2064			sourcePlugType = IOFWAVCPlugSubunitSourceType;
2065		else
2066			return kIOReturnError;
2067	}
2068	else
2069	{
2070		if (pBuf[kAVCOperand2] < kAVCMaxNumPlugs)
2071			sourcePlugType = IOFWAVCPlugIsochInputType;
2072		else if ((pBuf[kAVCOperand2] >= 0x80) && (pBuf[kAVCOperand2] <= 0x9E))
2073				sourcePlugType = IOFWAVCPlugExternalInputType;
2074		else
2075			return kIOReturnError;
2076	}
2077
2078	// Determine type of dest plug
2079	if (pBuf[kAVCOperand3] != kAVCUnitAddress)
2080	{
2081		if ((pBuf[kAVCOperand4] < kAVCMaxNumPlugs) || (pBuf[kAVCOperand4] == kAVCAnyAvailableSubunitPlug))
2082			destPlugType = IOFWAVCPlugSubunitDestType;
2083		else
2084			return kIOReturnError;
2085	}
2086	else
2087	{
2088		if ((pBuf[kAVCOperand4] < kAVCMaxNumPlugs) || (pBuf[kAVCOperand4] == kAVCAnyAvailableIsochPlug))
2089			destPlugType = IOFWAVCPlugIsochOutputType;
2090		else if (((pBuf[kAVCOperand4] >= 0x80) && (pBuf[kAVCOperand4] <= 0x9E)) || (pBuf[kAVCOperand4] == kAVCAnyAvailableExternalPlug))
2091			destPlugType = IOFWAVCPlugExternalOutputType;
2092		else
2093			return kIOReturnError;
2094	}
2095
2096	// All tests passed. Handle the command
2097	pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
2098	if(!pBufMemDesc)
2099		return kFWResponseDataError;
2100	pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
2101	bcopy(buf,pResponse,len);
2102
2103	AVCTARGETMUTEX_LOCK;
2104
2105	// Attempt to disconnect the plugs
2106	res = disconnectTargetPlugs(NULL,
2107							 pBuf[kAVCOperand1],
2108							 sourcePlugType,
2109							 pBuf[kAVCOperand2],
2110							 pBuf[kAVCOperand3],
2111							 destPlugType,
2112							 pBuf[kAVCOperand4]);
2113
2114	if (res == kIOReturnSuccess)
2115		pResponse[kAVCCommandResponse] = kAVCAcceptedStatus;
2116	else
2117		pResponse[kAVCCommandResponse] = kAVCRejectedStatus;
2118
2119	AVCTARGETMUTEX_UNLOCK;
2120
2121	targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
2122
2123	return kIOReturnSuccess;
2124}
2125
2126//////////////////////////////////////////////////////
2127// IOFireWireAVCTargetSpace::handleInputPlugSignalFormatCommand
2128//////////////////////////////////////////////////////
2129IOReturn IOFireWireAVCTargetSpace::handleInputPlugSignalFormatCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
2130{
2131	UInt8 *pResponse;
2132	IOBufferMemoryDescriptor *pBufMemDesc = NULL;
2133	UInt8 *pBuf = (UInt8*) buf;
2134	UInt8 cType;
2135	UInt32 plug;
2136	int i;
2137	AVCConnectionRecord *pConnection;
2138	bool found = false;
2139	AVCSubunitInfo *subUnitInfo;
2140	UInt32 signalFormat;
2141
2142	//IOLog( "IOFireWireAVCTargetSpace::handleInputPlugSignalFormatCommand (0x%08X)\n",(int) this);
2143
2144	// Check the length of the command. Don't handle command if wrong.
2145	if (len != 8)
2146		return kIOReturnError;
2147
2148	// Parse the command buf
2149	cType = pBuf[0] & 0x0F;
2150	plug = pBuf[kAVCOperand0];
2151	signalFormat = (((UInt32)pBuf[kAVCOperand1] << 24) +
2152				 ((UInt32)pBuf[kAVCOperand2] << 16) +
2153				 ((UInt32)pBuf[kAVCOperand3] << 8) +
2154				 (UInt32)pBuf[kAVCOperand4]);
2155
2156	// Further check the request packet parameters
2157	if (plug > (kAVCMaxNumPlugs-1))
2158		return kIOReturnError;
2159	switch (cType)
2160	{
2161		case kAVCStatusInquiryCommand:
2162			if ((pBuf[kAVCOperand1] != 0xFF) ||
2163	   (pBuf[kAVCOperand2] != 0xFF) ||
2164	   (pBuf[kAVCOperand3] != 0xFF) ||
2165	   (pBuf[kAVCOperand4] != 0xFF))
2166				return kIOReturnError;
2167			break;
2168
2169		case kAVCControlCommand:
2170			if ((pBuf[kAVCOperand1] & 0xC0) != 0x80)
2171				return kIOReturnError;
2172			break;
2173
2174		default:
2175			return kIOReturnError;
2176	};
2177
2178	AVCTARGETMUTEX_LOCK;
2179
2180	// Search connection records for a subunit dest plug connection to this plug
2181	for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
2182	{
2183		pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
2184		if ((pConnection->sourceSubunitTypeAndID == kAVCUnitAddress) &&
2185	  (pConnection->sourcePlugNum == plug) &&
2186	  (pConnection->destSubunitTypeAndID != kAVCUnitAddress))
2187		{
2188			subUnitInfo = getSubunitInfo(pConnection->destSubunitTypeAndID);
2189			if (subUnitInfo)
2190			{
2191				found = true;
2192				break;
2193			}
2194		}
2195	}
2196
2197	if ((found == true) && (cType == kAVCControlCommand))
2198	{
2199		// Send callback to user client
2200		subUnitInfo->callBack(subUnitInfo,
2201						kIOFWAVCSubunitPlugMsgSignalFormatModified,
2202						IOFWAVCPlugSubunitDestType,
2203						pConnection->destPlugNum,
2204						signalFormat,
2205						generation,
2206						nodeID);
2207
2208		// Were done for now. User client will send response packet
2209		AVCTARGETMUTEX_UNLOCK;
2210		return kIOReturnSuccess;
2211	}
2212
2213	// We will send a response to handle the command
2214	pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
2215	if(!pBufMemDesc)
2216	{
2217		AVCTARGETMUTEX_UNLOCK;
2218		return kFWResponseDataError;
2219	}
2220	pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
2221	bcopy(buf,pResponse,len);
2222
2223	if (cType == kAVCStatusInquiryCommand)
2224	{
2225		pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
2226
2227		// See if this plug has a connection
2228		if (found == true)
2229		{
2230			signalFormat = subUnitInfo->destPlugRecords[pConnection->destPlugNum].plugSignalFormat;
2231			pResponse[kAVCOperand1] = ((signalFormat & 0xFF000000) >> 24);
2232			pResponse[kAVCOperand2] = ((signalFormat & 0x00FF0000) >> 16);
2233			pResponse[kAVCOperand3] = ((signalFormat & 0x0000FF00) >> 8);
2234			pResponse[kAVCOperand4] = (signalFormat & 0x000000FF);
2235		}
2236		else
2237		{
2238			// If no connections, default plug signal type to NTSC-DV
2239			pResponse[kAVCOperand1] = ((kAVCPlugSignalFormatNTSCDV & 0xFF000000) >> 24);
2240			pResponse[kAVCOperand2] = ((kAVCPlugSignalFormatNTSCDV & 0x00FF0000) >> 16);
2241			pResponse[kAVCOperand3] = ((kAVCPlugSignalFormatNTSCDV & 0x0000FF00) >> 8);
2242			pResponse[kAVCOperand4] = (kAVCPlugSignalFormatNTSCDV & 0x000000FF);
2243		}
2244	}
2245	else
2246	{
2247		// This is a control type command to
2248		// a isoch output plug with no internal connection.
2249		// TODO: Today we just accept and ignore. But should we
2250		// maintain signal format for unconnected plugs?
2251		pResponse[kAVCCommandResponse] = kAVCAcceptedStatus;
2252	}
2253
2254	AVCTARGETMUTEX_UNLOCK;
2255
2256	targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
2257
2258	return kIOReturnSuccess;
2259}
2260
2261//////////////////////////////////////////////////////
2262// IOFireWireAVCTargetSpace::handleOutputPlugSignalFormatCommand
2263//////////////////////////////////////////////////////
2264IOReturn IOFireWireAVCTargetSpace::handleOutputPlugSignalFormatCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
2265{
2266	UInt8 *pResponse;
2267	IOBufferMemoryDescriptor *pBufMemDesc = NULL;
2268	UInt8 *pBuf = (UInt8*) buf;
2269	UInt8 cType;
2270	UInt32 plug;
2271	int i;
2272	AVCConnectionRecord *pConnection;
2273	bool found = false;
2274	AVCSubunitInfo *subUnitInfo;
2275	UInt32 signalFormat;
2276
2277	//IOLog( "IOFireWireAVCTargetSpace::handleOutputPlugSignalFormatCommand (0x%08X)\n",(int) this);
2278
2279	// Check the length of the command. Don't handle command if wrong.
2280	if (len != 8)
2281		return kIOReturnError;
2282
2283	// Parse the command buf
2284	cType = pBuf[0] & 0x0F;
2285	plug = pBuf[kAVCOperand0];
2286	signalFormat = (((UInt32)pBuf[kAVCOperand1] << 24) +
2287				 ((UInt32)pBuf[kAVCOperand2] << 16) +
2288				 ((UInt32)pBuf[kAVCOperand3] << 8) +
2289				 (UInt32)pBuf[kAVCOperand4]);
2290
2291	// Further check the request packet parameters
2292	if (plug > (kAVCMaxNumPlugs-1))
2293	 return kIOReturnError;
2294	switch (cType)
2295	{
2296		case kAVCStatusInquiryCommand:
2297			if ((pBuf[kAVCOperand1] != 0xFF) ||
2298	   (pBuf[kAVCOperand2] != 0xFF) ||
2299	   (pBuf[kAVCOperand3] != 0xFF) ||
2300	   (pBuf[kAVCOperand4] != 0xFF))
2301				return kIOReturnError;
2302			break;
2303
2304		case kAVCControlCommand:
2305			if ((pBuf[kAVCOperand1] & 0xC0) != 0x80)
2306				return kIOReturnError;
2307			break;
2308
2309		default:
2310			return kIOReturnError;
2311	};
2312
2313	AVCTARGETMUTEX_LOCK;
2314
2315	// Search connection records for a subunit source plug connection to this plug
2316	for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
2317	{
2318		pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
2319		if ((pConnection->destSubunitTypeAndID == kAVCUnitAddress) &&
2320	  (pConnection->destPlugNum == plug) &&
2321	  (pConnection->sourceSubunitTypeAndID != kAVCUnitAddress))
2322		{
2323			subUnitInfo = getSubunitInfo(pConnection->sourceSubunitTypeAndID);
2324			if (subUnitInfo)
2325			{
2326				found = true;
2327				break;
2328			}
2329		}
2330	}
2331
2332	if ((found == true) && (cType == kAVCControlCommand))
2333	{
2334		// Send callback to user client
2335		subUnitInfo->callBack(subUnitInfo,
2336						kIOFWAVCSubunitPlugMsgSignalFormatModified,
2337						IOFWAVCPlugSubunitSourceType,
2338						pConnection->sourcePlugNum,
2339						signalFormat,
2340						generation,
2341						nodeID);
2342
2343		// Were done for now. User client will send response packet
2344		AVCTARGETMUTEX_UNLOCK;
2345		return kIOReturnSuccess;
2346	}
2347
2348	// We will send a response to handle the command
2349	pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(len, kIODirectionOutIn);
2350	if(!pBufMemDesc)
2351	{
2352		AVCTARGETMUTEX_UNLOCK;
2353		return kFWResponseDataError;
2354	}
2355	pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
2356	bcopy(buf,pResponse,len);
2357
2358	if (cType == kAVCStatusInquiryCommand)
2359	{
2360		pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
2361
2362		// See if this plug has a connection
2363		if (found == true)
2364		{
2365			signalFormat = subUnitInfo->sourcePlugRecords[pConnection->sourcePlugNum].plugSignalFormat;
2366			pResponse[kAVCOperand1] = ((signalFormat & 0xFF000000) >> 24);
2367			pResponse[kAVCOperand2] = ((signalFormat & 0x00FF0000) >> 16);
2368			pResponse[kAVCOperand3] = ((signalFormat & 0x0000FF00) >> 8);
2369			pResponse[kAVCOperand4] = (signalFormat & 0x000000FF);
2370		}
2371		else
2372		{
2373			// If no connections, default plug signal type to NTSC-DV
2374			pResponse[kAVCOperand1] = ((kAVCPlugSignalFormatNTSCDV & 0xFF000000) >> 24);
2375			pResponse[kAVCOperand2] = ((kAVCPlugSignalFormatNTSCDV & 0x00FF0000) >> 16);
2376			pResponse[kAVCOperand3] = ((kAVCPlugSignalFormatNTSCDV & 0x0000FF00) >> 8);
2377			pResponse[kAVCOperand4] = (kAVCPlugSignalFormatNTSCDV & 0x000000FF);
2378		}
2379	}
2380	else
2381	{
2382		// This is a control type command to
2383		// a isoch output plug with no internal connection.
2384		// TODO: Today we just accept and ignore. But should we
2385		// maintain signal format for unconnected plugs?
2386		pResponse[kAVCCommandResponse] = kAVCAcceptedStatus;
2387	}
2388
2389	AVCTARGETMUTEX_UNLOCK;
2390
2391	targetSendAVCResponse(generation, nodeID, pBufMemDesc, len);
2392
2393	return kIOReturnSuccess;
2394}
2395
2396//////////////////////////////////////////////////////
2397// IOFireWireAVCTargetSpace::handleConnectionsCommand
2398//////////////////////////////////////////////////////
2399IOReturn IOFireWireAVCTargetSpace::handleConnectionsCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
2400{
2401	UInt8 cType;
2402	UInt8 connectionCount;
2403	UInt32 responseLen;
2404	UInt8 *pBuf = (UInt8*) buf;
2405	UInt8 *pResponse;
2406	IOBufferMemoryDescriptor *pBufMemDesc = NULL;
2407	int i;
2408	AVCConnectionRecord *pConnection;
2409	UInt8 respIndex;
2410	UInt8 connectionType;
2411
2412	//IOLog( "IOFireWireAVCTargetSpace::handleConnectionsCommand (0x%08X)\n",(int) this);
2413
2414	// Check the length of the command. Don't handle command if wrong.
2415	if (len != 4)
2416		return kIOReturnError;
2417
2418	// Parse the command buf
2419	cType = pBuf[0] & 0x0F;
2420
2421	// Check the cType.  Don't handle command if not a status type.
2422	if (cType != kAVCStatusInquiryCommand)
2423		return kIOReturnError;
2424
2425	if (pBuf[kAVCOperand0] != 0xFF)
2426		return kIOReturnError;
2427
2428	AVCTARGETMUTEX_LOCK;
2429
2430	connectionCount = (UInt8) (fConnectionRecords->getCount() & 0x000000FF);
2431
2432	// Limit this command to only include up to 100 connection records in
2433	// the response, to prevent going beyond the max AVC response packet size
2434	if (connectionCount > 100)
2435		connectionCount = 100;
2436
2437	responseLen = 4 + (connectionCount*5);
2438
2439	// We will send a response to handle the command
2440	pBufMemDesc = IOBufferMemoryDescriptor::withCapacity(responseLen, kIODirectionOutIn);
2441	if(!pBufMemDesc)
2442	{
2443		AVCTARGETMUTEX_UNLOCK;
2444		return kFWResponseDataError;
2445	}
2446	pResponse = (UInt8 *) pBufMemDesc->getBytesNoCopy();
2447
2448	pResponse[kAVCCommandResponse] = kAVCImplementedStatus;
2449	pResponse[kAVCAddress] = 0xFF;
2450	pResponse[kAVCOpcode] = 0x22;
2451	pResponse[kAVCOperand0] = connectionCount;
2452
2453	respIndex = 4;
2454
2455	for (i=(connectionCount-1);i>=0;i--)
2456	{
2457		pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
2458
2459		connectionType = 0xFC;
2460		if (pConnection->lockConnection)
2461			connectionType += 2;
2462		if (pConnection->permConnection)
2463			connectionType += 1;
2464
2465		pResponse[respIndex++] = connectionType;
2466		pResponse[respIndex++] = pConnection->sourceSubunitTypeAndID;
2467		pResponse[respIndex++] = pConnection->sourcePlugNum;
2468		pResponse[respIndex++] = pConnection->destSubunitTypeAndID;
2469		pResponse[respIndex++] = pConnection->destPlugNum;
2470	}
2471
2472	AVCTARGETMUTEX_UNLOCK;
2473
2474	targetSendAVCResponse(generation, nodeID, pBufMemDesc, responseLen);
2475
2476	return kIOReturnSuccess;
2477}
2478
2479//////////////////////////////////////////////////////
2480// IOFireWireAVCTargetSpace::handleSignalSourceCommand
2481//////////////////////////////////////////////////////
2482IOReturn IOFireWireAVCTargetSpace::handleSignalSourceCommand(UInt16 nodeID, UInt32 generation, const char *buf, UInt32 len)
2483{
2484	//IOLog( "IOFireWireAVCTargetSpace::handleSignalSourceCommand (0x%08X)\n",(int) this);
2485
2486	// TODO: Not yet Handled!
2487	return kIOReturnError;
2488}
2489
2490//////////////////////////////////////////////////////
2491// IOFireWireAVCTargetSpace::pcrModified
2492//////////////////////////////////////////////////////
2493void IOFireWireAVCTargetSpace::pcrModified(IOFWAVCPlugTypes plugType,
2494										   UInt32 plugNum,
2495										   UInt32 newValue)
2496{
2497	AVCConnectionRecord *pConnection;
2498	AVCSubunitInfo *subUnitInfo;
2499	int i;
2500
2501	//IOLog( "IOFireWireAVCTargetSpace::pcrModified (0x%08X)\n",(int) this);
2502
2503	AVCTARGETMUTEX_LOCK;
2504
2505	// Search through all the connection records to find subunit(s) connected
2506	// to this plug, and alert the subunit owner of the plug value modification
2507	for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
2508	{
2509		pConnection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
2510
2511		switch (plugType)
2512		{
2513			case IOFWAVCPlugIsochInputType:
2514				if ((pConnection->sourceSubunitTypeAndID == kAVCUnitAddress) &&
2515		(pConnection->sourcePlugNum == plugNum) &&
2516		(pConnection->destSubunitTypeAndID != kAVCUnitAddress) )
2517				{
2518					subUnitInfo = getSubunitInfo(pConnection->destSubunitTypeAndID);
2519					if (subUnitInfo)
2520						subUnitInfo->callBack(subUnitInfo,
2521							kIOFWAVCSubunitPlugMsgConnectedPlugModified,
2522							IOFWAVCPlugSubunitDestType,
2523							pConnection->destPlugNum,
2524							newValue,
2525							0,0);
2526				}
2527				break;
2528
2529			case IOFWAVCPlugIsochOutputType:
2530				if ((pConnection->destSubunitTypeAndID == kAVCUnitAddress) &&
2531		(pConnection->destPlugNum == plugNum) &&
2532		(pConnection->sourceSubunitTypeAndID != kAVCUnitAddress))
2533				{
2534					subUnitInfo = getSubunitInfo(pConnection->sourceSubunitTypeAndID);
2535					if (subUnitInfo)
2536						subUnitInfo->callBack(subUnitInfo,
2537							kIOFWAVCSubunitPlugMsgConnectedPlugModified,
2538							IOFWAVCPlugSubunitSourceType,
2539							pConnection->sourcePlugNum,
2540							newValue,
2541							0,0);
2542				}
2543				break;
2544
2545			default:
2546				break;
2547		};
2548	}
2549
2550	AVCTARGETMUTEX_UNLOCK;
2551
2552	return;
2553}
2554
2555//////////////////////////////////////////////////////
2556// IOFireWireAVCTargetSpace::getSubunitInfo
2557//////////////////////////////////////////////////////
2558AVCSubunitInfo *IOFireWireAVCTargetSpace::getSubunitInfo(UInt32 subunitTypeAndID)
2559{
2560	AVCSubunitInfo *subunitInfo = NULL;
2561	int i;
2562	bool found = false;
2563
2564	//IOLog( "IOFireWireAVCTargetSpace::getSubunitInfo (0x%08X)\n",(int) this);
2565
2566	AVCTARGETMUTEX_LOCK;
2567
2568	// Find the subunit in the list
2569	for (i=(fSubunits->getCount()-1);i>=0;i--)
2570	{
2571		subunitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
2572		if (subunitInfo->subunitTypeAndID == subunitTypeAndID)
2573		{
2574			found = true;
2575			break;
2576		}
2577	}
2578
2579	AVCTARGETMUTEX_UNLOCK;
2580
2581	if (found == true)
2582		return subunitInfo;
2583	else
2584		return NULL;
2585}
2586
2587//////////////////////////////////////////////////////
2588// IOFireWireAVCTargetSpace::subUnitOfTypeCount
2589//////////////////////////////////////////////////////
2590UInt32 IOFireWireAVCTargetSpace::subUnitOfTypeCount(UInt32 type)
2591{
2592	UInt32 cnt = 0;
2593	UInt32 subUnitType;
2594	AVCSubunitInfo *subUnitInfo;
2595	int i;
2596
2597	//IOLog( "IOFireWireAVCTargetSpace::subUnitOfTypeCount (0x%08X)\n",(int) this);
2598
2599	AVCTARGETMUTEX_LOCK;
2600
2601	for (i=(fSubunits->getCount()-1);i>=0;i--)
2602	{
2603		subUnitInfo = (AVCSubunitInfo *) fSubunits->getObject(i);
2604		subUnitType = ((subUnitInfo->subunitTypeAndID & 0xF8) >> 3);
2605		if (subUnitType == type)
2606			cnt+= 1;
2607    }
2608
2609	AVCTARGETMUTEX_UNLOCK;
2610
2611	return cnt;
2612}
2613
2614//////////////////////////////////////////////////////
2615// IOFireWireAVCTargetSpace::canConnectDestPlug
2616//////////////////////////////////////////////////////
2617bool IOFireWireAVCTargetSpace::canConnectDestPlug(UInt32 destSubunitTypeAndID,
2618													 IOFWAVCPlugTypes destPlugType,
2619													 UInt32 *destPlugNum)
2620{
2621	bool res=true;
2622	int i;
2623	AVCConnectionRecord *connection;
2624	UInt32 actualPlugNumber = *destPlugNum;
2625
2626	// Search the connection records for a connection with this dest plug.
2627	// If we find one (and there can be at most one), check the lock and
2628	// perm bits. If both clear, disconnect the connection,
2629	// then return true, if either is set return false.
2630	// If no connection is found, return true.
2631	// If this dest plug is kAVCInvalidPlug, look for any connection, with
2632	// a dest plug matching this subunit/type, that can be disconnected.
2633	// AVCTARGETMUTEX_LOCK assumed already set!!!
2634
2635	for (i=(fConnectionRecords->getCount()-1);i>=0;i--)
2636	{
2637		connection = (AVCConnectionRecord *) fConnectionRecords->getObject(i);
2638
2639		if ((connection->destSubunitTypeAndID == destSubunitTypeAndID) &&
2640			(connection->destPlugType == destPlugType))
2641		{
2642			if ((actualPlugNumber == kAVCInvalidPlug) || (connection->destPlugNum == *destPlugNum))
2643			{
2644				if ((connection->lockConnection == false) && (connection->permConnection == false))
2645				{
2646					actualPlugNumber = connection->destPlugNum;
2647
2648					// Disconnect this connection
2649					disconnectTargetPlugs(NULL,
2650						   connection->sourceSubunitTypeAndID,
2651						   connection->sourcePlugType,
2652						   connection->sourcePlugNum,
2653						   connection->destSubunitTypeAndID,
2654						   connection->destPlugType,
2655						   connection->destPlugNum);
2656
2657					break;	// No need to look anymore
2658				}
2659				else if (connection->destPlugNum == *destPlugNum)
2660				{
2661					res = false;
2662					break;	// No need to look anymore
2663				}
2664			}
2665		}
2666	}
2667
2668	if (actualPlugNumber == kAVCInvalidPlug)
2669	{
2670		res = false;
2671	}
2672	else
2673	{
2674		*destPlugNum = actualPlugNumber;
2675	}
2676
2677	return res;
2678}
2679