1/*
2 * Copyright (c) 1998-2001 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 <stdlib.h>
24#include <stdio.h>
25#include <CoreFoundation/CoreFoundation.h>
26
27#include <IOKit/avc/IOFireWireAVCLib.h>
28#include "IOFireWireAVCUserClientCommon.h"
29#include <IOKit/avc/IOFireWireAVCConsts.h>
30
31#include <mach/mach_port.h>
32
33#import <System/libkern/OSCrossEndian.h>
34
35#include <syslog.h>	// Debug messages
36
37__BEGIN_DECLS
38#include <IOKit/iokitmig.h>
39__END_DECLS
40
41#define FWLOG printf
42
43struct _AVCProtocol;
44typedef struct _InterfaceMap
45{
46    IUnknownVTbl *pseudoVTable;
47    struct _AVCProtocol *obj;
48} InterfaceMap;
49
50typedef struct _AVCProtocol
51{
52
53	//////////////////////////////////////
54	// cf plugin interfaces
55
56	InterfaceMap 			   				fIOCFPlugInInterface;
57	InterfaceMap							fIOFireWireAVCLibProtocolInterface;
58
59	//////////////////////////////////////
60	// cf plugin ref counting
61
62	CFUUIDRef 	fFactoryId;
63	UInt32 		fRefCount;
64
65	//////////////////////////////////////
66	// user client connection
67
68	io_service_t 	fService;
69	io_connect_t 	fConnection;
70
71	//////////////////////////////////////
72	// async callbacks
73
74    mach_port_t				fAsyncPort;
75	CFRunLoopRef			fCFRunLoop;
76	CFRunLoopSourceRef		fCFRunLoopSource;
77    CFMachPortRef			fCFAsyncPort;
78    IONotificationPortRef	fNotifyPort;
79    io_object_t				fNotification;
80	IOFWAVCMessageCallback	fMessageCallbackRoutine;
81	void *					fMessageCallbackRefCon;
82
83	//////////////////////////////////////
84	// Lump 'o stuff for handling AVC requests
85	IOFWAVCRequestCallback	fAVCRequestCallbackRoutine;
86	void *					fAVCRequestCallbackRefCon;
87
88    UInt32					fCmdLen;
89    UInt32					fCmdGeneration;
90    UInt32					fCmdSource;
91    UInt8					fCommand[512];
92	IOFWAVCCommandHandlerCallback userCallBack;
93	void 					*userRefCon;
94	IOFWSpeed 				speed;
95	UInt32 					handlerSearchIndex;
96} AVCProtocol;
97
98	// utility function to get "this" pointer from interface
99#define getThis( self ) \
100        (((InterfaceMap *) self)->obj)
101
102static IOReturn stop( void * self );
103static void removeIODispatcherFromRunLoop( void * self );
104static IOReturn sendAVCResponse(void *self,
105								UInt32 generation,
106								UInt16 nodeID,
107								const char *response,
108								UInt32 responseLen);
109IOReturn setSubunitPlugSignalFormat(void *self,
110									UInt32 subunitTypeAndID,
111									IOFWAVCPlugTypes plugType,
112									UInt32 plugNum,
113									UInt32 signalFormat);
114
115//////////////////////////////////////////////////////////////////
116// callback static methods
117//
118
119// messageCallback
120//
121//
122
123static void messageCallback(void * refcon, io_service_t service,
124                          natural_t messageType, void *messageArgument)
125{
126	//printf("DEBUG: AVCProtocol::messageCallback\n");
127
128	AVCProtocol *me = (AVCProtocol *)refcon;
129
130	if( me->fMessageCallbackRoutine != NULL )
131		(me->fMessageCallbackRoutine)( me->fMessageCallbackRefCon, messageType, messageArgument );
132}
133
134static void avcCommandHandlerCallback( void *refcon, IOReturn result, io_user_reference_t *args, int numArgs)
135{
136    AVCProtocol *me = (AVCProtocol *)refcon;
137    UInt32 pos;
138    UInt32 len;
139    const UInt8* src;
140	UInt32 fixedArgs[kMaxAsyncArgs];
141	UInt32 i;
142	uint64_t inArg[4];
143	uint32_t outputScalarCnt = 0;
144	size_t outputStructSize = 0;
145
146	//printf("DEBUG: AVCProtocol::avcCommandHandlerCallback\n");
147
148	// First copy all the args with endian byte-swapping. Note that only
149	// the args that contain command-bytes need this, but doing them all
150	// here simplifies the logic below.
151	IF_ROSETTA()
152	{
153		// Note: This code assumes ROSETTA only happens for in 32-bit mode!
154		for (i=0;i<numArgs;i++)
155			fixedArgs[i] = (OSSwapInt32(args[i]) & 0xFFFFFFFF);
156	}
157	else
158	{
159		for (i=0;i<numArgs;i++)
160			fixedArgs[i] = (args[i] & 0xFFFFFFFF);
161	}
162
163    pos = args[0] & 0xFFFFFFFF;
164    len = args[1] & 0xFFFFFFFF;
165    src = (const UInt8*)(fixedArgs+2);
166    if(pos == 0)
167	{
168        me->fCmdGeneration = args[2] & 0xFFFFFFFF;
169        me->fCmdSource = args[3] & 0xFFFFFFFF;;
170        me->fCmdLen = args[4] & 0xFFFFFFFF;
171		me->userCallBack = (IOFWAVCCommandHandlerCallback) ((unsigned long)args[5]);
172		me->userRefCon = (void*) ((unsigned long)args[6]);
173		me->speed = (IOFWSpeed) args[7] & 0xFFFFFFFF;
174		me->handlerSearchIndex = args[8] & 0xFFFFFFFF;
175		src = (const UInt8*)(fixedArgs+9);
176    }
177
178	bcopy(src, me->fCommand+pos, len);
179    if(pos+len == me->fCmdLen)
180	{
181        IOReturn status;
182		status = me->userCallBack(me->userRefCon, me->fCmdGeneration, me->fCmdSource, me->speed, me->fCommand , me->fCmdLen);
183
184		// See if application handled command or not
185		if (status != kIOReturnSuccess)
186		{
187			inArg[0] = me->fCmdGeneration;
188			inArg[1] = me->fCmdSource;
189			inArg[2] = me->speed;
190			inArg[3] = me->handlerSearchIndex;
191
192			// Pass this command back to the kernel to possibly
193			// find another handler, or to respond not implemented
194			IOConnectCallMethod(me->fConnection,
195								kIOFWAVCProtocolUserClientAVCRequestNotHandled,
196								inArg,
197								4,
198								me->fCommand,
199								me->fCmdLen,
200								NULL,
201								&outputScalarCnt,
202								NULL,
203								&outputStructSize);
204		}
205    }
206}
207
208static void subunitPlugHandlerCallback( void *refcon, IOReturn result, io_user_reference_t *args, int numArgs)
209{
210	AVCProtocol *me = (AVCProtocol *)refcon;
211	IOFWAVCSubunitPlugHandlerCallback userCallBack;
212	void *userRefCon;
213	IOReturn status;
214	IOFWAVCSubunitPlugMessages plugMessage = (IOFWAVCSubunitPlugMessages)args[3];
215	UInt32 generation = args[7] & 0xFFFFFFFF;
216	UInt32 nodeID = args[8] & 0xFFFFFFFF;
217	UInt8 response[8];
218	IOFWAVCPlugTypes plugType = (IOFWAVCPlugTypes) args[1] & 0xFFFFFFFF;
219	UInt32 plugNum = args[2] & 0xFFFFFFFF;
220	UInt32 msgParams = args[4] & 0xFFFFFFFF;
221	UInt32 subunitTypeAndID = args[0] & 0xFFFFFFFF;
222
223	//printf("DEBUG: AVCProtocol::subunitPlugHandlerCallback\n");
224
225	userCallBack = (IOFWAVCSubunitPlugHandlerCallback) ((unsigned long)args[5]);
226	userRefCon = (void*) ((unsigned long)args[6]);
227
228	// Callback the user
229	status = userCallBack(userRefCon,subunitTypeAndID,plugType,plugNum,plugMessage,msgParams);
230
231	// For the message kIOFWAVCSubunitPlugMsgSignalFormatModified
232	// send a response to the plug signal format control command
233	if (plugMessage == kIOFWAVCSubunitPlugMsgSignalFormatModified)
234	{
235		response[kAVCCommandResponse] = (status == kIOReturnSuccess) ? kAVCAcceptedStatus : kAVCRejectedStatus;
236		response[kAVCAddress] = kAVCUnitAddress;
237		response[kAVCOpcode] = (plugType == IOFWAVCPlugSubunitSourceType) ? kAVCOutputPlugSignalFormatOpcode : kAVCInputPlugSignalFormatOpcode;
238		response[kAVCOperand0] = plugNum;
239		response[kAVCOperand1] = ((msgParams & 0xFF000000) >> 24);
240		response[kAVCOperand2] = ((msgParams & 0x00FF0000) >> 16);
241		response[kAVCOperand3] = ((msgParams & 0x0000FF00) >> 8);
242		response[kAVCOperand4] = (msgParams & 0x000000FF);
243
244		sendAVCResponse(me,generation,(UInt16) nodeID,(const char *)response,8);
245
246		// If we accepted the control command, we need to set this
247		// signal format as the current signal format
248		if (status == kIOReturnSuccess)
249			setSubunitPlugSignalFormat(me,subunitTypeAndID,plugType,plugNum,msgParams);
250	}
251	return;
252}
253
254static void pcrWriteCallback( void *refcon, IOReturn result, io_user_reference_t *args, int numArgs)
255{
256    IOFWAVCPCRCallback func;
257
258	//printf("DEBUG: AVCProtocol::pcrWriteCallback\n");
259
260	func = (IOFWAVCPCRCallback) ((unsigned long)args[0]);
261    func(refcon, (UInt32)args[1], (UInt16)args[2], (UInt32)args[3], (UInt32)args[4], (UInt32)args[5]);
262}
263
264static UInt32 addRef( void * self )
265{
266	//printf("DEBUG: AVCProtocol::addRef\n");
267
268	AVCProtocol *me = getThis(self);
269	me->fRefCount++;
270	return me->fRefCount;
271}
272
273static UInt32 release( void * self )
274{
275    AVCProtocol *me = getThis(self);
276	UInt32 retVal = me->fRefCount;
277
278	//printf("DEBUG: AVCProtocol::release\n");
279
280	if( 1 == me->fRefCount-- )
281	{
282        removeIODispatcherFromRunLoop(self);
283        stop(self);
284        CFPlugInRemoveInstanceForFactory( me->fFactoryId );
285        CFRelease( me->fFactoryId );
286		free(me);
287    }
288    else if( me->fRefCount < 0 )
289	{
290        me->fRefCount = 0;
291	}
292
293	return retVal;
294}
295
296
297static HRESULT queryInterface( void * self, REFIID iid, void **ppv )
298{
299    CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid);
300    HRESULT result = S_OK;
301    AVCProtocol *me = getThis(self);
302
303	//printf("DEBUG: AVCProtocol::queryInterface\n");
304
305	if( CFEqual(uuid, IUnknownUUID) ||  CFEqual(uuid, kIOCFPlugInInterfaceID) )
306	{
307        *ppv = &me->fIOCFPlugInInterface;
308        addRef(self);
309    }
310	else if( CFEqual(uuid, kIOFireWireAVCLibProtocolInterfaceID) )
311	{
312        *ppv = &me->fIOFireWireAVCLibProtocolInterface;
313        addRef(self);
314    }
315    else
316        *ppv = 0;
317
318    if( !*ppv )
319        result = E_NOINTERFACE;
320
321    CFRelease( uuid );
322
323    return result;
324}
325
326//////////////////////////////////////////////////////////////////
327// IOCFPlugInInterface methods
328//
329
330// probe
331//
332//
333
334static IOReturn probe( void * self, CFDictionaryRef propertyTable,
335											io_service_t service, SInt32 *order )
336{
337
338	//printf("DEBUG: AVCProtocol::probe\n");
339
340	// only load against local FireWire node
341    if( !service || !IOObjectConformsTo(service, "IOFireWireLocalNode") )
342        return kIOReturnBadArgument;
343
344	return kIOReturnSuccess;
345}
346
347// start
348//
349//
350
351static IOReturn start( void * self, CFDictionaryRef propertyTable,
352											io_service_t service )
353{
354	IOReturn status = kIOReturnSuccess;
355    CFNumberRef guidDesc = 0;
356    io_iterator_t	enumerator = 0;
357    io_object_t device = 0;
358    mach_port_t		masterDevicePort;
359    AVCProtocol *me = getThis(self);
360    CFMutableDictionaryRef	dict;
361    CFMutableDictionaryRef	dict2;
362
363	//printf("DEBUG: AVCProtocol::start\n");
364
365	me->fService = service;
366
367    // Conjure up our user client
368    do {
369        dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
370            &kCFTypeDictionaryKeyCallBacks,
371            &kCFTypeDictionaryValueCallBacks);
372
373        if(!dict)
374            continue;
375        dict2 = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
376            &kCFTypeDictionaryKeyCallBacks,
377            &kCFTypeDictionaryValueCallBacks);
378
379        if(!dict2)
380            continue;
381        CFDictionarySetValue( dict2, CFSTR("IODesiredChild"), CFSTR("IOFireWireAVCProtocolUserClient") );
382        CFDictionarySetValue( dict, CFSTR("SummonNub"), dict2 );
383
384        status = IORegistryEntrySetCFProperties(service, dict );
385        CFRelease( dict );
386        CFRelease( dict2 );
387
388        // Now find it - has same GUID as the IOFireWireLocalNode
389        guidDesc = (CFNumberRef)IORegistryEntryCreateCFProperty(service, CFSTR("GUID"), kCFAllocatorDefault, 0);
390
391        dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
392            &kCFTypeDictionaryKeyCallBacks,
393            &kCFTypeDictionaryValueCallBacks);
394
395        if(!dict)
396            break;
397
398        CFDictionarySetValue( dict, CFSTR(kIOProviderClassKey), CFSTR("IOFireWireAVCProtocolUserClient"));
399        //CFDictionarySetValue( dict, CFSTR("GUID"), guidDesc);
400        // get mach master port
401        status = IOMasterPort(bootstrap_port, & masterDevicePort) ;
402        if ( status != kIOReturnSuccess ) {
403            break;
404        }
405
406        status = IOServiceGetMatchingServices(
407                    masterDevicePort,
408                    dict,
409                    & enumerator );
410
411        if( kIOReturnSuccess != status ) {
412            break;
413        }
414
415        // Find an unused user client
416        while(device = IOIteratorNext(enumerator)) {
417            status = IOServiceOpen( device, mach_task_self(),
418                            kIOFireWireAVCLibConnection, &me->fConnection );
419            IOObjectRelease(device);
420            if(kIOReturnSuccess == status)
421                break;
422        }
423    } while(0);
424
425    if(guidDesc)
426        CFRelease(guidDesc);
427    if (enumerator)
428        IOObjectRelease(enumerator) ;
429
430	if( !me->fConnection )
431		status = kIOReturnNoDevice;
432
433	if( status == kIOReturnSuccess )
434	{
435	    status = IOCreateReceivePort( kOSAsyncCompleteMessageID, &me->fAsyncPort );
436	}
437
438	return status;
439}
440
441// stop
442//
443//
444
445static IOReturn stop( void * self )
446{
447    AVCProtocol *me = getThis(self);
448
449	//printf("DEBUG: AVCProtocol::stop\n");
450
451	if( me->fConnection )
452	{
453        IOServiceClose( me->fConnection );
454        me->fConnection = MACH_PORT_NULL;
455    }
456
457	if( me->fAsyncPort != MACH_PORT_NULL )
458	{
459        mach_port_destroy( mach_task_self(), me->fAsyncPort);
460		me->fAsyncPort = MACH_PORT_NULL;
461	}
462
463	return kIOReturnSuccess;
464}
465
466//////////////////////////////////////////////////////////////////
467// IOFireWireAVCLibProtocol methods
468//
469
470// addIODispatcherToRunLoop
471//
472//
473
474static IOReturn addIODispatcherToRunLoop( void *self, CFRunLoopRef cfRunLoopRef )
475{
476    AVCProtocol *me = getThis(self);
477	IOReturn 				status = kIOReturnSuccess;
478    mach_port_t masterDevicePort;
479	IONotificationPortRef notifyPort;
480	CFRunLoopSourceRef cfSource;
481
482	//printf("DEBUG: AVCProtocol::addIODispatcherToRunLoop\n");
483
484	if( !me->fConnection )
485		return kIOReturnNoDevice;
486
487	// get mach master port
488	status = IOMasterPort(bootstrap_port, &masterDevicePort) ;
489
490    notifyPort = IONotificationPortCreate(masterDevicePort);
491    cfSource = IONotificationPortGetRunLoopSource(notifyPort);
492    CFRunLoopAddSource(cfRunLoopRef, cfSource, kCFRunLoopDefaultMode);
493// Get messages from device
494    status = IOServiceAddInterestNotification(notifyPort, me->fService,
495                                kIOGeneralInterest, messageCallback, me,
496                                &me->fNotification);
497
498    me->fCFRunLoop = cfRunLoopRef;
499    me->fNotifyPort = notifyPort;
500
501
502	if( status == kIOReturnSuccess )
503	{
504		CFMachPortContext context;
505		Boolean	shouldFreeInfo; // zzz what's this for? I think it's set to true if the create failed.
506
507		context.version = 1;
508		context.info = me;
509		context.retain = NULL;
510		context.release = NULL;
511		context.copyDescription = NULL;
512
513		me->fCFAsyncPort = CFMachPortCreateWithPort( kCFAllocatorDefault, me->fAsyncPort,
514							(CFMachPortCallBack) IODispatchCalloutFromMessage,
515							&context, &shouldFreeInfo );
516		if( !me->fCFAsyncPort )
517			status = kIOReturnNoMemory;
518	}
519
520	if( status == kIOReturnSuccess )
521	{
522		me->fCFRunLoopSource = CFMachPortCreateRunLoopSource( kCFAllocatorDefault, me->fCFAsyncPort, 0 );
523		if( !me->fCFRunLoopSource )
524			status = kIOReturnNoMemory;
525	}
526
527	if( status == kIOReturnSuccess )
528	{
529		CFRunLoopAddSource(cfRunLoopRef, me->fCFRunLoopSource, kCFRunLoopDefaultMode );
530	}
531
532	return status;
533}
534
535// removeIODispatcherFromRunLoop
536//
537//
538
539static void removeIODispatcherFromRunLoop( void * self )
540{
541    AVCProtocol *me = getThis(self);
542
543	//printf("DEBUG: AVCProtocol::removeIODispatcherFromRunLoop\n");
544
545    if( me->fNotification )
546    {
547        IOObjectRelease(me->fNotification);
548        me->fNotification = (io_object_t)0;
549    }
550	if( me->fNotifyPort )
551	{
552		CFRunLoopRemoveSource( me->fCFRunLoop,
553            IONotificationPortGetRunLoopSource(me->fNotifyPort), kCFRunLoopDefaultMode );
554        IONotificationPortDestroy(me->fNotifyPort);
555		me->fNotifyPort = NULL;
556	}
557
558    if(me->fCFRunLoopSource) {
559		CFRunLoopRemoveSource( me->fCFRunLoop,
560            me->fCFRunLoopSource, kCFRunLoopDefaultMode );
561        CFRelease(me->fCFRunLoopSource);
562        me->fCFRunLoopSource = NULL;
563    }
564
565	if( me->fCFAsyncPort != NULL ) {
566        CFMachPortInvalidate(me->fCFAsyncPort);
567		CFRelease( me->fCFAsyncPort );
568        me->fCFAsyncPort = NULL;
569    }
570}
571
572// setMessageCallback
573//
574//
575
576static void setMessageCallback( void * self, void * refCon,
577													IOFWAVCMessageCallback callback )
578{
579    AVCProtocol *me = getThis(self);
580
581	//printf("DEBUG: AVCProtocol::setMessageCallback\n");
582
583	me->fMessageCallbackRoutine = callback;
584	me->fMessageCallbackRefCon = refCon;
585}
586
587// setAVCRequestCallback
588//
589//
590
591static IOReturn setAVCRequestCallback( void *self, UInt32 subUnitType, UInt32 subUnitID,
592                                                void *refCon, IOFWAVCRequestCallback callback)
593{
594	// This function has been deprecated!
595    return kIOReturnUnsupported;
596}
597
598static IOReturn allocateInputPlug( void *self, void *refcon, IOFWAVCPCRCallback func, UInt32 *plug)
599{
600    AVCProtocol *me = getThis(self);
601    uint64_t params;
602    IOReturn status;
603	uint64_t refrncData[kOSAsyncRef64Count];
604	uint32_t outputCnt = 1;
605	uint64_t returnVal;
606
607	//printf("DEBUG: AVCProtocol::allocateInputPlug\n");
608
609    refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t)&pcrWriteCallback;
610    refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)refcon;
611    params = (unsigned long)func;
612	const uint64_t inputs[1]={(const uint64_t)params};
613
614	status = IOConnectCallAsyncScalarMethod(me->fConnection,
615											kIOFWAVCProtocolUserClientAllocateInputPlug,
616											me->fAsyncPort,
617											refrncData,kOSAsyncRef64Count,
618											inputs, 1,
619											&returnVal,&outputCnt);
620	*plug = returnVal & 0xFFFFFFFF;
621
622	return status;
623}
624
625static void freeInputPlug( void *self, UInt32 plug)
626{
627    AVCProtocol *me = getThis(self);
628	uint32_t outputCnt = 0;
629	const uint64_t inArg = plug;
630	const uint64_t inputs[1]={(const uint64_t)inArg};
631
632
633	//printf("DEBUG: AVCProtocol::freeInputPlug\n");
634
635	IOConnectCallScalarMethod(me->fConnection,
636							kIOFWAVCProtocolUserClientFreeInputPlug,
637							inputs,
638							1,
639							NULL,
640							&outputCnt);
641}
642
643static UInt32 readInputPlug( void *self, UInt32 plug)
644{
645    AVCProtocol *me = getThis(self);
646	UInt32 val;
647	const uint64_t inArg = plug;
648	uint32_t outputCnt = 1;
649	uint64_t outputVal = 0;
650	const uint64_t inputs[1]={(const uint64_t)inArg};
651
652	//printf("DEBUG: AVCProtocol::readInputPlug\n");
653
654	IOConnectCallScalarMethod(me->fConnection,
655							kIOFWAVCProtocolUserClientReadInputPlug,
656							inputs,
657							1,
658							&outputVal,
659							&outputCnt);
660
661	val = outputVal & 0xFFFFFFFF;
662
663    return val;
664}
665
666static IOReturn updateInputPlug( void *self, UInt32 plug, UInt32 oldVal, UInt32 newVal)
667{
668    AVCProtocol *me = getThis(self);
669	uint64_t inArg[3];
670	uint32_t outputCnt = 0;
671
672	inArg[0] = plug;
673	inArg[1] = oldVal;
674	inArg[2] = newVal;
675
676	//printf("DEBUG: AVCProtocol::updateInputPlug\n");
677
678	return IOConnectCallScalarMethod(me->fConnection,
679							kIOFWAVCProtocolUserClientUpdateInputPlug,
680							inArg,
681							3,
682							NULL,
683							&outputCnt);
684}
685
686static IOReturn allocateOutputPlug( void *self, void *refcon, IOFWAVCPCRCallback func, UInt32 *plug)
687{
688	AVCProtocol *me = getThis(self);
689    uint64_t params;
690    IOReturn status;
691	uint64_t refrncData[kOSAsyncRef64Count];
692	uint32_t outputCnt = 1;
693	uint64_t returnVal;
694
695	//printf("DEBUG: AVCProtocol::allocateOutputPlug\n");
696
697	refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t)pcrWriteCallback;
698    refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)refcon;
699    params = (unsigned long)func;
700	const uint64_t inputs[1]={(const uint64_t)params};
701
702	status = IOConnectCallAsyncScalarMethod(me->fConnection,
703											kIOFWAVCProtocolUserClientAllocateOutputPlug,
704											me->fAsyncPort,
705											refrncData,kOSAsyncRef64Count,
706											inputs, 1,
707											&returnVal,&outputCnt);
708
709	*plug = returnVal & 0xFFFFFFFF;
710
711	return status;
712}
713
714static void freeOutputPlug( void *self, UInt32 plug)
715{
716    AVCProtocol *me = getThis(self);
717	uint32_t outputCnt = 0;
718	const uint64_t inArg = plug;
719	const uint64_t inputs[1]={(const uint64_t)inArg};
720
721	//printf("DEBUG: AVCProtocol::freeOutputPlug\n");
722
723	IOConnectCallScalarMethod(me->fConnection,
724							kIOFWAVCProtocolUserClientFreeOutputPlug,
725							inputs,
726							1,
727							NULL,
728							&outputCnt);
729}
730
731static UInt32 readOutputPlug( void *self, UInt32 plug)
732{
733    AVCProtocol *me = getThis(self);
734    UInt32 val;
735	const uint64_t inArg = plug;
736	uint32_t outputCnt = 1;
737	uint64_t outputVal = 0;
738	const uint64_t inputs[1]={(const uint64_t)inArg};
739
740	//printf("DEBUG: AVCProtocol::readOutputPlug\n");
741
742	IOConnectCallScalarMethod(me->fConnection,
743							kIOFWAVCProtocolUserClientReadOutputPlug,
744							inputs,
745							1,
746							&outputVal,
747							&outputCnt);
748
749	val = outputVal & 0xFFFFFFFF;
750
751    return val;
752}
753
754static IOReturn updateOutputPlug( void *self, UInt32 plug, UInt32 oldVal, UInt32 newVal)
755{
756    AVCProtocol *me = getThis(self);
757	uint64_t inArg[3];
758	uint32_t outputCnt = 0;
759
760	inArg[0] = plug;
761	inArg[1] = oldVal;
762	inArg[2] = newVal;
763
764	//printf("DEBUG: AVCProtocol::updateOutputPlug\n");
765
766	return IOConnectCallScalarMethod(me->fConnection,
767								kIOFWAVCProtocolUserClientUpdateOutputPlug,
768								inArg,
769								3,
770								NULL,
771								&outputCnt);
772}
773
774static UInt32 readOutputMasterPlug( void *self)
775{
776    AVCProtocol *me = getThis(self);
777    UInt32 val;
778	uint32_t outputCnt = 1;
779	uint64_t outputVal = 0;
780
781	//printf("DEBUG: AVCProtocol::readOutputMasterPlug\n");
782
783	IOConnectCallScalarMethod(me->fConnection,
784							kIOFWAVCProtocolUserClientReadOutputMasterPlug,
785							NULL,
786							0,
787							&outputVal,
788							&outputCnt);
789
790	val = outputVal & 0xFFFFFFFF;
791
792    return val;
793}
794
795static IOReturn updateOutputMasterPlug( void *self, UInt32 oldVal, UInt32 newVal)
796{
797    AVCProtocol *me = getThis(self);
798	uint64_t inArg[2];
799	uint32_t outputCnt = 0;
800
801	inArg[0] = oldVal;
802	inArg[1] = newVal;
803
804	//printf("DEBUG: AVCProtocol::updateOutputMasterPlug\n");
805
806	return IOConnectCallScalarMethod(me->fConnection,
807								kIOFWAVCProtocolUserClientUpdateOutputMasterPlug,
808								inArg,
809								2,
810								NULL,
811								&outputCnt);
812}
813
814static UInt32 readInputMasterPlug( void *self)
815{
816    AVCProtocol *me = getThis(self);
817    UInt32 val;
818	uint32_t outputCnt = 1;
819	uint64_t outputVal = 0;
820
821	//printf("DEBUG: AVCProtocol::readInputMasterPlug\n");
822
823	IOConnectCallScalarMethod(me->fConnection,
824							kIOFWAVCProtocolUserClientReadInputMasterPlug,
825							NULL,
826							0,
827							&outputVal,
828							&outputCnt);
829
830	val = outputVal & 0xFFFFFFFF;
831
832    return val;
833}
834
835static IOReturn updateInputMasterPlug( void *self, UInt32 oldVal, UInt32 newVal)
836{
837    AVCProtocol *me = getThis(self);
838	uint64_t inArg[2];
839	uint32_t outputCnt = 0;
840
841	inArg[0] = oldVal;
842	inArg[1] = newVal;
843
844	//printf("DEBUG: AVCProtocol::updateInputMasterPlug\n");
845
846	return IOConnectCallScalarMethod(me->fConnection,
847									kIOFWAVCProtocolUserClientUpdateInputMasterPlug,
848									inArg,
849									2,
850									NULL,
851									&outputCnt);
852}
853
854static IOReturn publishAVCUnitDirectory(void *self)
855{
856    AVCProtocol *me = getThis(self);
857	uint32_t outputCnt = 0;
858
859	//printf("DEBUG: AVCProtocol::publishAVCUnitDirectory\n");
860
861	IOConnectCallScalarMethod(me->fConnection,
862							kIOFWAVCProtocolUserClientPublishAVCUnitDirectory,
863							NULL,
864							0,
865							NULL,
866							&outputCnt);
867
868    return kIOReturnSuccess;
869}
870
871static IOReturn installAVCCommandHandler(void *self,
872											UInt32 subUnitTypeAndID,
873											UInt32 opCode,
874											void *refCon,
875											IOFWAVCCommandHandlerCallback callback)
876{
877    AVCProtocol *me = getThis(self);
878    IOReturn status = kIOReturnSuccess;
879	uint64_t params[4];
880	uint64_t refrncData[kOSAsyncRef64Count];
881	uint32_t outputCnt = 0;
882
883
884	//printf("DEBUG: AVCProtocol::installAVCCommandHandler\n");
885
886    refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t)avcCommandHandlerCallback;
887    refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)me;
888    params[0]	= subUnitTypeAndID;
889    params[1]	= opCode;
890	params[2]	= (unsigned long)callback;
891    params[3]	= (unsigned long)refCon;
892
893	status = IOConnectCallAsyncScalarMethod(me->fConnection,
894											kIOFWAVCProtocolUserClientInstallAVCCommandHandler,
895											me->fAsyncPort,
896											refrncData,kOSAsyncRef64Count,
897											params, 4,
898											NULL,&outputCnt);
899
900	return status;
901}
902
903static IOReturn sendAVCResponse(void *self,
904							UInt32 generation,
905							UInt16 nodeID,
906							const char *response,
907							UInt32 responseLen)
908{
909    AVCProtocol *me = getThis(self);
910	uint64_t inArg[2];
911	uint32_t outputScalarCnt = 0;
912	size_t outputStructSize = 0;
913
914	inArg[0] = generation;
915	inArg[1] = nodeID;
916
917	return IOConnectCallMethod(me->fConnection,
918								kIOFWAVCProtocolUserClientSendAVCResponse,
919								inArg,
920								2,
921								response,
922								responseLen,
923								NULL,
924								&outputScalarCnt,
925								NULL,
926								&outputStructSize);
927
928
929}
930
931IOReturn addSubunit(void *self,
932					UInt32 subunitType,
933					UInt32 numSourcePlugs,
934					UInt32 numDestPlugs,
935					void *refCon,
936					IOFWAVCSubunitPlugHandlerCallback callback,
937					UInt32 *pSubunitTypeAndID)
938{
939    AVCProtocol *me = getThis(self);
940    IOReturn status = kIOReturnSuccess;
941	uint64_t params[5];
942	uint64_t refrncData[kOSAsyncRef64Count];
943	uint32_t outputCnt = 1;
944	uint64_t returnVal;
945
946	//printf("DEBUG: AVCProtocol::addSubunit\n");
947
948    refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t)subunitPlugHandlerCallback;
949    refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long)me;
950    params[0]	= subunitType;
951    params[1]	= numSourcePlugs;
952    params[2]	= numDestPlugs;
953	params[3]	= (unsigned long)callback;
954    params[4]	= (unsigned long)refCon;
955
956	status = IOConnectCallAsyncScalarMethod(me->fConnection,
957											kIOFWAVCProtocolUserClientAddSubunit,
958											me->fAsyncPort,
959											refrncData,kOSAsyncRef64Count,
960											params, 5,
961											&returnVal,&outputCnt);
962
963	*pSubunitTypeAndID = returnVal & 0xFFFFFFFF;
964
965    return status;
966}
967
968IOReturn setSubunitPlugSignalFormat(void *self,
969									   UInt32 subunitTypeAndID,
970									   IOFWAVCPlugTypes plugType,
971									   UInt32 plugNum,
972									   UInt32 signalFormat)
973{
974    AVCProtocol *me = getThis(self);
975	uint64_t inArg[4];
976	uint32_t outputCnt = 0;
977
978	inArg[0] = subunitTypeAndID;
979	inArg[1] = plugType;
980	inArg[2] = plugNum;
981	inArg[3] = signalFormat;
982
983	//printf("DEBUG: AVCProtocol::setSubunitPlugSignalFormat\n");
984
985	return IOConnectCallScalarMethod(me->fConnection,
986									kIOFWAVCProtocolUserClientSetSubunitPlugSignalFormat,
987									inArg,
988									4,
989									NULL,
990									&outputCnt);
991}
992
993
994IOReturn getSubunitPlugSignalFormat(void *self,
995									   UInt32 subunitTypeAndID,
996									   IOFWAVCPlugTypes plugType,
997									   UInt32 plugNum,
998									   UInt32 *pSignalFormat)
999{
1000    AVCProtocol *me = getThis(self);
1001	IOReturn status = kIOReturnSuccess;
1002	uint32_t outputCnt = 1;
1003	uint64_t outputVal = 0;
1004	uint64_t inArg[3];
1005
1006	inArg[0] = subunitTypeAndID;
1007	inArg[1] = plugType;
1008	inArg[2] = plugNum;
1009
1010	//printf("DEBUG: AVCProtocol::getSubunitPlugSignalFormat\n");
1011
1012	status =  IOConnectCallScalarMethod(me->fConnection,
1013									kIOFWAVCProtocolUserClientGetSubunitPlugSignalFormat,
1014									inArg,
1015									3,
1016									&outputVal,
1017									&outputCnt);
1018
1019	*pSignalFormat = outputVal & 0xFFFFFFFF;
1020	return status;
1021}
1022
1023IOReturn connectTargetPlugs(void *self,
1024							   UInt32 sourceSubunitTypeAndID,
1025							   IOFWAVCPlugTypes sourcePlugType,
1026							   UInt32 *pSourcePlugNum,
1027							   UInt32 destSubunitTypeAndID,
1028							   IOFWAVCPlugTypes destPlugType,
1029							   UInt32 *pDestPlugNum,
1030							   bool lockConnection,
1031							   bool permConnection)
1032{
1033    AVCProtocol *me = getThis(self);
1034	IOReturn status = kIOReturnSuccess;
1035	AVCConnectTargetPlugsInParams inParams;
1036	AVCConnectTargetPlugsOutParams outParams;
1037	size_t outputCnt = sizeof(AVCConnectTargetPlugsOutParams);
1038
1039	//printf("DEBUG: AVCProtocol::connectTargetPlugs\n");
1040
1041	inParams.sourceSubunitTypeAndID = sourceSubunitTypeAndID;
1042	inParams.sourcePlugType = sourcePlugType;
1043	inParams.sourcePlugNum = *pSourcePlugNum;
1044	inParams.destSubunitTypeAndID = destSubunitTypeAndID;
1045	inParams.destPlugType = destPlugType;
1046	inParams.destPlugNum = *pDestPlugNum;
1047	inParams.lockConnection = lockConnection;
1048	inParams.permConnection = permConnection;
1049
1050	ROSETTA_ONLY(
1051		{
1052			inParams.sourceSubunitTypeAndID = OSSwapInt32(inParams.sourceSubunitTypeAndID);
1053			inParams.sourcePlugType = OSSwapInt32(inParams.sourcePlugType);
1054			inParams.sourcePlugNum = OSSwapInt32(inParams.sourcePlugNum);
1055			inParams.destSubunitTypeAndID = OSSwapInt32(inParams.destSubunitTypeAndID);
1056			inParams.destPlugType = OSSwapInt32(inParams.destPlugType);
1057			inParams.destPlugNum = OSSwapInt32(inParams.destPlugNum);
1058		}
1059	);
1060
1061	status = IOConnectCallStructMethod(me->fConnection,
1062										kIOFWAVCProtocolUserClientConnectTargetPlugs,
1063										&inParams,
1064										sizeof(AVCConnectTargetPlugsInParams),
1065										&outParams,
1066										&outputCnt);
1067
1068	ROSETTA_ONLY(
1069		{
1070			outParams.sourcePlugNum = OSSwapInt32(outParams.sourcePlugNum);
1071			outParams.destPlugNum = OSSwapInt32(outParams.destPlugNum);
1072		}
1073	);
1074
1075	*pSourcePlugNum = outParams.sourcePlugNum;
1076	*pDestPlugNum = outParams.destPlugNum;
1077	return status;
1078}
1079
1080IOReturn disconnectTargetPlugs(void *self,
1081								  UInt32 sourceSubunitTypeAndID,
1082								  IOFWAVCPlugTypes sourcePlugType,
1083								  UInt32 sourcePlugNum,
1084								  UInt32 destSubunitTypeAndID,
1085								  IOFWAVCPlugTypes destPlugType,
1086								  UInt32 destPlugNum)
1087{
1088    AVCProtocol *me = getThis(self);
1089	uint32_t outputCnt = 0;
1090	uint64_t inArg[6];
1091
1092	inArg[0] = sourceSubunitTypeAndID;
1093	inArg[1] = sourcePlugType;
1094	inArg[2] = sourcePlugNum;
1095	inArg[3] = destSubunitTypeAndID;
1096	inArg[4] = destPlugType;
1097	inArg[5] = destPlugNum;
1098
1099	//printf("DEBUG: AVCProtocol::disconnectTargetPlugs\n");
1100
1101	return IOConnectCallScalarMethod(me->fConnection,
1102									kIOFWAVCProtocolUserClientDisconnectTargetPlugs,
1103									inArg,
1104									6,
1105									NULL,
1106									&outputCnt);
1107}
1108
1109IOReturn getTargetPlugConnection(void *self,
1110									UInt32 subunitTypeAndID,
1111									IOFWAVCPlugTypes plugType,
1112									UInt32 plugNum,
1113									UInt32 *pConnectedSubunitTypeAndID,
1114									IOFWAVCPlugTypes *pConnectedPlugType,
1115									UInt32 *pConnectedPlugNum,
1116									bool *pLockConnection,
1117									bool *pPermConnection)
1118{
1119    AVCProtocol *me = getThis(self);
1120	IOReturn status = kIOReturnSuccess;
1121	AVCGetTargetPlugConnectionInParams inParams;
1122	AVCGetTargetPlugConnectionOutParams outParams;
1123	size_t outputCnt = sizeof(AVCGetTargetPlugConnectionInParams);
1124
1125	//printf("DEBUG: AVCProtocol::getTargetPlugConnection\n");
1126
1127	inParams.subunitTypeAndID = subunitTypeAndID;
1128	inParams.plugType = plugType;
1129	inParams.plugNum = plugNum;
1130
1131	ROSETTA_ONLY(
1132		{
1133			inParams.subunitTypeAndID = OSSwapInt32(inParams.subunitTypeAndID);
1134			inParams.plugType = OSSwapInt32(inParams.plugType);
1135			inParams.plugNum = OSSwapInt32(inParams.plugNum);
1136		}
1137	);
1138
1139	status = IOConnectCallStructMethod(me->fConnection,
1140									kIOFWAVCProtocolUserClientGetTargetPlugConnection,
1141									&inParams,
1142									sizeof(AVCConnectTargetPlugsInParams),
1143									&outParams,
1144									&outputCnt);
1145
1146	ROSETTA_ONLY(
1147		{
1148			outParams.connectedSubunitTypeAndID = OSSwapInt32(outParams.connectedSubunitTypeAndID);
1149			outParams.connectedPlugType = OSSwapInt32(outParams.connectedPlugType);
1150			outParams.connectedPlugNum = OSSwapInt32(outParams.connectedPlugNum);
1151		}
1152	);
1153
1154	*pConnectedSubunitTypeAndID = outParams.connectedSubunitTypeAndID;
1155	*pConnectedPlugType = outParams.connectedPlugType;
1156	*pConnectedPlugNum = outParams.connectedPlugNum;
1157	*pLockConnection = outParams.lockConnection;
1158	*pPermConnection = outParams.permConnection;
1159
1160	return status;
1161}
1162
1163
1164// static interface table for IOCFPlugInInterface
1165//
1166
1167static IOCFPlugInInterface sIOCFPlugInInterface =
1168{
1169    0,
1170	&queryInterface,
1171	&addRef,
1172	&release,
1173	1, 0, // version/revision
1174	&probe,
1175	&start,
1176	&stop
1177};
1178
1179//
1180// static interface table for IOFireWireAVCLibProtocolInterface
1181//
1182
1183static IOFireWireAVCLibProtocolInterface sProtocolInterface =
1184{
1185    0,
1186	&queryInterface,
1187	&addRef,
1188	&release,
1189	2, 0, // version/revision
1190	&addIODispatcherToRunLoop,
1191	&removeIODispatcherFromRunLoop,
1192	&setMessageCallback,
1193    &setAVCRequestCallback,
1194    &allocateInputPlug,
1195    &freeInputPlug,
1196    &readInputPlug,
1197    &updateInputPlug,
1198    &allocateOutputPlug,
1199    &freeOutputPlug,
1200    &readOutputPlug,
1201    &updateOutputPlug,
1202    &readOutputMasterPlug,
1203    &updateOutputMasterPlug,
1204    &readInputMasterPlug,
1205    &updateInputMasterPlug,
1206	&publishAVCUnitDirectory,
1207	&installAVCCommandHandler,
1208	&sendAVCResponse,
1209	&addSubunit,
1210	&setSubunitPlugSignalFormat,
1211	&getSubunitPlugSignalFormat,
1212	&connectTargetPlugs,
1213	&disconnectTargetPlugs,
1214	&getTargetPlugConnection
1215};
1216
1217// IOFireWireAVCLibProtocolFactory
1218
1219// alloc
1220//
1221// static allocator, called by factory method
1222
1223static IOCFPlugInInterface ** alloc()
1224{
1225	IOCFPlugInInterface ** 	interface = NULL;
1226    AVCProtocol *	me;
1227
1228	//printf("DEBUG: AVCProtocol::alloc\n");
1229
1230    me = (AVCProtocol *)malloc(sizeof(AVCProtocol));
1231    if( me )
1232	{
1233        bzero(me, sizeof(AVCProtocol));
1234		// we return an interface here. queryInterface will not be called. set refs to 1
1235        // init cf plugin ref counting
1236        me->fRefCount = 1;
1237
1238        // init user client connection
1239        me->fConnection = MACH_PORT_NULL;
1240        me->fService = MACH_PORT_NULL;
1241
1242        // create plugin interface map
1243        me->fIOCFPlugInInterface.pseudoVTable = (IUnknownVTbl *) &sIOCFPlugInInterface;
1244        me->fIOCFPlugInInterface.obj = me;
1245
1246        // create test driver interface map
1247        me->fIOFireWireAVCLibProtocolInterface.pseudoVTable
1248                                    = (IUnknownVTbl *) &sProtocolInterface;
1249        me->fIOFireWireAVCLibProtocolInterface.obj = me;
1250
1251        me->fFactoryId = kIOFireWireAVCLibProtocolFactoryID;
1252        CFRetain( me->fFactoryId );
1253        CFPlugInAddInstanceForFactory( me->fFactoryId );
1254        interface = (IOCFPlugInInterface **) &me->fIOCFPlugInInterface.pseudoVTable;
1255    }
1256	return interface;
1257}
1258
1259//
1260// factory method (only exported symbol)
1261
1262void *IOFireWireAVCLibProtocolFactory( CFAllocatorRef allocator, CFUUIDRef typeID )
1263{
1264
1265	//printf("DEBUG: AVCProtocol::IOFireWireAVCLibProtocolFactory\n");
1266
1267	if( CFEqual(typeID, kIOFireWireAVCLibProtocolTypeID) )
1268        return (void *) alloc();
1269    else
1270        return NULL;
1271}
1272
1273