1/*
2 *  IOFireWireLibAsyncStreamListener.cpp
3 *  IOFireWireFamily
4 *
5 *  Created by Arul on Thu Sep 28 2006.
6 *  Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
7 *
8 *	$ Log:IOFireWireLibAsyncStreamListener.cpp,v $
9 */
10
11#import "IOFireWireLibAsyncStreamListener.h"
12#import "IOFireWireLibDevice.h"
13#import "IOFireWireLibPriv.h"
14
15#import <IOKit/iokitmig.h>
16
17namespace IOFireWireLib {
18
19#pragma mark AsyncStreamListener -
20
21	// ============================================================
22	// AsyncStreamListener
23	// ============================================================
24	AsyncStreamListener::AsyncStreamListener( const IUnknownVTbl&		interface,
25													Device&				userclient,
26													UserObjectHandle	inKernAddrSpaceRef,
27													void*				inBuffer,
28													UInt32				inBufferSize,
29													void*				inCallBack,
30													void*				inRefCon	)
31	: IOFireWireIUnknown( interface ),
32		mUserClient(userclient),
33		mKernAsyncStreamListenerRef(inKernAddrSpaceRef),
34		mBuffer((char*)inBuffer),
35		mNotifyIsOn(false),
36		mUserRefCon(inRefCon),
37		mBufferSize(inBufferSize),
38		mListener( (AsyncStreamListenerHandler) inCallBack ),
39		mSkippedPacketHandler( nil ),
40		mRefInterface( reinterpret_cast<AsyncStreamListenerRef>( & GetInterface() ) )
41	{
42		userclient.AddRef() ;
43	}
44
45
46	AsyncStreamListener::~AsyncStreamListener()
47	{
48		uint32_t outputCnt = 0;
49		const uint64_t inputs[1]={(const uint64_t)mKernAsyncStreamListenerRef};
50
51		IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
52								  kReleaseUserObject,
53								  inputs,1,
54								  NULL,&outputCnt);
55
56		if( mBuffer and mBufferSize > 0 )
57		{
58			delete[] mBuffer;
59			mBuffer		= 0;
60			mBufferSize = 0;
61		}
62
63		mUserClient.Release() ;
64	}
65
66	const IOFWAsyncStreamListenerHandler
67	AsyncStreamListener::SetListenerHandler ( AsyncStreamListenerRef		self,
68											  AsyncStreamListenerHandler	inReceiver )
69	{
70		AsyncStreamListenerHandler oldListener = mListener ;
71		mListener = inReceiver ;
72
73		return oldListener ;
74	}
75
76	const IOFWAsyncStreamListenerSkippedPacketHandler
77	AsyncStreamListener::SetSkippedPacketHandler( AsyncStreamListenerRef	self,
78												  AsyncStreamSkippedPacketHandler		inHandler )
79	{
80		AsyncStreamSkippedPacketHandler oldHandler = mSkippedPacketHandler;
81		mSkippedPacketHandler = inHandler;
82
83		return oldHandler;
84	}
85
86	Boolean
87	AsyncStreamListener::NotificationIsOn ( AsyncStreamListenerRef self )
88	{
89		return mNotifyIsOn ;
90	}
91
92	Boolean
93	AsyncStreamListener::TurnOnNotification ( AsyncStreamListenerRef self )
94	{
95		IOReturn				err					= kIOReturnSuccess ;
96		io_connect_t			connection			= mUserClient.GetUserClientConnection() ;
97
98		// if notification is already on, skip out.
99		if (mNotifyIsOn)
100			return true ;
101
102		if (!connection)
103			err = kIOReturnNoDevice ;
104
105		if ( kIOReturnSuccess == err )
106		{
107			uint64_t refrncData[kOSAsyncRef64Count];
108			refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0;
109			refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long) 0;
110			const uint64_t inputs[3] = {(const uint64_t)mKernAsyncStreamListenerRef,(const uint64_t)& Listener,(const uint64_t)self};
111			uint32_t outputCnt = 0;
112			err = IOConnectCallAsyncScalarMethod(connection,
113												 kSetAsyncStreamRef_Packet,
114												 mUserClient.GetIsochAsyncPort(),
115												 refrncData,kOSAsyncRef64Count,
116												 inputs,3,
117												 NULL,&outputCnt);
118		}
119
120		if ( kIOReturnSuccess == err)
121		{
122
123			uint64_t refrncData[kOSAsyncRef64Count];
124			refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0;
125			refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long) 0;
126			const uint64_t inputs[3] = {(const uint64_t)mKernAsyncStreamListenerRef,(const uint64_t)& SkippedPacket,(const uint64_t)self};
127			uint32_t outputCnt = 0;
128			err = IOConnectCallAsyncScalarMethod(connection,
129												 kSetAsyncStreamRef_SkippedPacket,
130												 mUserClient.GetIsochAsyncPort(),
131												 refrncData,kOSAsyncRef64Count,
132												 inputs,3,
133												 NULL,&outputCnt);
134		}
135
136		if ( kIOReturnSuccess == err )
137		{
138			uint32_t outputCnt = 0;
139			const uint64_t inputs[1]={(const uint64_t)mKernAsyncStreamListenerRef};
140
141			err = IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
142											kAsyncStreamListener_TurnOnNotification,
143											inputs,1,
144											NULL,&outputCnt);
145		}
146
147
148		if ( kIOReturnSuccess == err )
149			mNotifyIsOn = true ;
150
151		return ( kIOReturnSuccess == err ) ;
152	}
153
154	void
155	AsyncStreamListener::TurnOffNotification ( AsyncStreamListenerRef self )
156	{
157		IOReturn				err			= kIOReturnSuccess ;
158		io_connect_t			connection	= mUserClient.GetUserClientConnection() ;
159
160		// if notification isn't on, skip out.
161		if (!mNotifyIsOn)
162			return ;
163
164		if (!connection)
165			err = kIOReturnNoDevice ;
166
167		if ( kIOReturnSuccess == err )
168		{
169			uint64_t refrncData[kOSAsyncRef64Count];
170			refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0;
171			refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long) 0;
172			const uint64_t inputs[3] = {(const uint64_t)mKernAsyncStreamListenerRef,0,(const uint64_t)self};
173			uint32_t outputCnt = 0;
174
175			// set callback for writes to 0
176			err = IOConnectCallAsyncScalarMethod(connection,
177												 kSetAsyncStreamRef_Packet,
178												 mUserClient.GetIsochAsyncPort(),
179												 refrncData,kOSAsyncRef64Count,
180												 inputs,3,
181												 NULL,&outputCnt);
182
183			outputCnt = 0;
184			// set callback for skipped packets to 0
185			err = IOConnectCallAsyncScalarMethod(connection,
186												 kSetAsyncStreamRef_SkippedPacket,
187												 mUserClient.GetIsochAsyncPort(),
188												 refrncData,kOSAsyncRef64Count,
189												 inputs,3,
190												 NULL,&outputCnt);
191		}
192
193		if ( kIOReturnSuccess == err )
194		{
195			uint32_t outputCnt = 0;
196			const uint64_t inputs[1]={(const uint64_t)mKernAsyncStreamListenerRef};
197
198			err = IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
199											kAsyncStreamListener_TurnOffNotification,
200											inputs,1,
201											NULL,&outputCnt);
202		}
203
204		mNotifyIsOn = false ;
205	}
206
207	void
208	AsyncStreamListener::ClientCommandIsComplete ( AsyncStreamListenerRef	self,
209												   FWClientCommandID		commandID )
210	{
211		uint32_t		outputCnt = 0;
212		const uint64_t	inputs[2] = {(const uint64_t)mKernAsyncStreamListenerRef, (const uint64_t)commandID};
213
214		#if IOFIREWIREUSERCLIENTDEBUG > 0
215		OSStatus err =
216		#endif
217
218		IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
219													kAsyncStreamListener_ClientCommandIsComplete,
220													inputs,2,
221													NULL,&outputCnt);
222
223#ifdef __LP64__
224		DebugLogCond( err, "AsyncStreamListener::ClientCommandIsComplete: err=0x%08X\n", err ) ;
225#else
226		DebugLogCond( err, "AsyncStreamListener::ClientCommandIsComplete: err=0x%08lX\n", err ) ;
227#endif
228	}
229
230	void*
231	AsyncStreamListener::GetRefCon	( AsyncStreamListenerRef self )
232	{
233		return mUserRefCon;
234	}
235
236	void
237	AsyncStreamListener::SetFlags ( AsyncStreamListenerRef		self,
238									UInt32						flags )
239	{
240		uint32_t outputCnt = 0;
241		const uint64_t inputs[2] = {(const uint64_t)mKernAsyncStreamListenerRef, flags};
242		IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
243								  kAsyncStreamListener_SetFlags,
244								  inputs,2,
245								  NULL,&outputCnt);
246
247		mFlags = flags;
248	}
249
250	UInt32
251	AsyncStreamListener::GetFlags ( AsyncStreamListenerRef	self )
252	{
253		uint32_t outputCnt = 1;
254		uint64_t outputVal = 0;
255		const uint64_t inputs[1]={(const uint64_t)mKernAsyncStreamListenerRef};
256
257		IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
258								  kAsyncStreamListener_GetFlags,
259								  inputs,1,
260								  &outputVal,&outputCnt);
261		mFlags = outputVal & 0xFFFFFFFF;
262
263		return mFlags;
264	}
265
266	UInt32
267	AsyncStreamListener::GetOverrunCounter ( AsyncStreamListenerRef	self )
268	{
269		UInt32 counter = 0;
270		uint32_t outputCnt = 1;
271		uint64_t outputVal = 0;
272		const uint64_t inputs[1]={(const uint64_t)mKernAsyncStreamListenerRef};
273
274		IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
275								  kAsyncStreamListener_GetOverrunCounter,
276								  inputs,1,
277								  &outputVal,&outputCnt);
278		counter = outputVal & 0xFFFFFFFF;
279		return counter;
280	}
281
282	void
283	AsyncStreamListener::Listener( AsyncStreamListenerRef refcon, IOReturn result, void** args, int numArgs)
284	{
285		AsyncStreamListener* me = IOFireWireIUnknown::InterfaceMap<AsyncStreamListener>::GetThis(refcon) ;
286
287		if ( ! me->mListener )
288		{
289			me->ClientCommandIsComplete( (AsyncStreamListenerRef) refcon, args[0] ) ;
290			return ;
291		}
292		else
293		{
294			(me->mListener)(
295				(AsyncStreamListenerRef) refcon,
296				(FWClientCommandID) args[0],						// commandID,
297				(unsigned long)(args[1]),									// size
298				me->mBuffer + (unsigned long)(args[2]),					// packet
299				(void*) me->mUserRefCon) ;								// refcon
300		}
301	}
302
303	void
304	AsyncStreamListener::SkippedPacket( AsyncStreamListenerRef refcon, IOReturn result, FWClientCommandID commandID, UInt32 packetCount)
305	{
306		AsyncStreamListener* me = IOFireWireIUnknown::InterfaceMap<AsyncStreamListener>::GetThis(refcon) ;
307
308		if (me->mSkippedPacketHandler)
309			(me->mSkippedPacketHandler)( refcon, commandID, packetCount) ;
310		else
311			me->ClientCommandIsComplete( refcon, commandID ) ;
312	}
313
314
315#pragma mark AsyncStreamListenerCOM -
316
317	AsyncStreamListenerCOM::Interface AsyncStreamListenerCOM::sInterface =
318	{
319		INTERFACEIMP_INTERFACE,
320		1, 0,
321
322		&AsyncStreamListenerCOM::SSetListenerHandler,
323		&AsyncStreamListenerCOM::SSetSkippedPacketHandler,
324		&AsyncStreamListenerCOM::SNotificationIsOn,
325		&AsyncStreamListenerCOM::STurnOnNotification,
326		&AsyncStreamListenerCOM::STurnOffNotification,
327		&AsyncStreamListenerCOM::SClientCommandIsComplete,
328		&AsyncStreamListenerCOM::SGetRefCon,
329		&AsyncStreamListenerCOM::SSetFlags,
330		&AsyncStreamListenerCOM::SGetFlags,
331		&AsyncStreamListenerCOM::SGetOverrunCounter
332	} ;
333
334	//
335	// --- ctor/dtor -----------------------
336	//
337
338	AsyncStreamListenerCOM::AsyncStreamListenerCOM( Device&				userclient,
339													UserObjectHandle	inKernAddrSpaceRef,
340													void*				inBuffer,
341													UInt32				inBufferSize,
342													void*				inCallBack,
343													void*				inRefCon )
344	: AsyncStreamListener( reinterpret_cast<const IUnknownVTbl &>( sInterface ), userclient, inKernAddrSpaceRef, inBuffer,
345										inBufferSize, inCallBack, inRefCon )
346	{
347	}
348
349	AsyncStreamListenerCOM::~AsyncStreamListenerCOM()
350	{
351	}
352
353	//
354	// --- IUNKNOWN support ----------------
355	//
356
357	IUnknownVTbl**
358	AsyncStreamListenerCOM::Alloc(	Device&				userclient,
359									UserObjectHandle	inKernAddrSpaceRef,
360									void*				inBuffer,
361									UInt32				inBufferSize,
362									void*				inCallBack,
363									void*				inRefCon )
364	{
365		AsyncStreamListenerCOM*	me = nil ;
366
367		try {
368			me = new AsyncStreamListenerCOM( userclient, inKernAddrSpaceRef, inBuffer, inBufferSize, inCallBack, inRefCon ) ;
369		} catch(...) {
370		}
371
372		return ( nil == me ) ? nil : reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
373	}
374
375	HRESULT
376	AsyncStreamListenerCOM::QueryInterface(REFIID iid, void ** ppv )
377	{
378		HRESULT		result = S_OK ;
379		*ppv = nil ;
380
381		CFUUIDRef	interfaceID	= CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
382
383		if ( CFEqual(interfaceID, IUnknownUUID) ||  CFEqual(interfaceID, kIOFireWireAsyncStreamListenerInterfaceID) )
384		{
385			*ppv = & GetInterface() ;
386			AddRef() ;
387		}
388		else
389		{
390			*ppv = nil ;
391			result = E_NOINTERFACE ;
392		}
393
394		CFRelease(interfaceID) ;
395		return result ;
396	}
397
398	//
399	// --- static methods ------------------
400	//
401	const IOFWAsyncStreamListenerHandler
402	AsyncStreamListenerCOM::SSetListenerHandler ( AsyncStreamListenerRef		self,
403												  AsyncStreamListenerHandler	inReceiver )
404	{
405		return IOFireWireIUnknown::InterfaceMap<AsyncStreamListenerCOM>::GetThis(self)->SetListenerHandler( self, inReceiver ) ;
406	}
407
408	const IOFWAsyncStreamListenerSkippedPacketHandler
409	AsyncStreamListenerCOM::SSetSkippedPacketHandler( AsyncStreamListenerRef	self,
410													  AsyncStreamSkippedPacketHandler		inHandler )
411	{
412		return IOFireWireIUnknown::InterfaceMap<AsyncStreamListenerCOM>::GetThis(self)->SetSkippedPacketHandler( self, inHandler ) ;
413	}
414
415	Boolean
416	AsyncStreamListenerCOM::SNotificationIsOn ( AsyncStreamListenerRef self )
417	{
418		return IOFireWireIUnknown::InterfaceMap<AsyncStreamListenerCOM>::GetThis(self)->NotificationIsOn( self ) ;
419	}
420
421	Boolean
422	AsyncStreamListenerCOM::STurnOnNotification ( AsyncStreamListenerRef self )
423	{
424		return IOFireWireIUnknown::InterfaceMap<AsyncStreamListenerCOM>::GetThis(self)->TurnOnNotification( self ) ;
425	}
426
427	void
428	AsyncStreamListenerCOM::STurnOffNotification ( AsyncStreamListenerRef self )
429	{
430		return IOFireWireIUnknown::InterfaceMap<AsyncStreamListenerCOM>::GetThis(self)->TurnOffNotification( self ) ;
431	}
432
433	void
434	AsyncStreamListenerCOM::SClientCommandIsComplete ( AsyncStreamListenerRef	self,
435													   FWClientCommandID		commandID,
436													   IOReturn					status )
437	{
438		IOFireWireIUnknown::InterfaceMap<AsyncStreamListenerCOM>::GetThis(self)->ClientCommandIsComplete( self, commandID ) ;
439	}
440
441	void*
442	AsyncStreamListenerCOM::SGetRefCon	( AsyncStreamListenerRef self )
443	{
444		return IOFireWireIUnknown::InterfaceMap<AsyncStreamListenerCOM>::GetThis(self)->GetRefCon( self );
445	}
446
447	void
448	AsyncStreamListenerCOM::SSetFlags ( AsyncStreamListenerRef		self,
449										 UInt32						flags )
450	{
451		IOFireWireIUnknown::InterfaceMap<AsyncStreamListenerCOM>::GetThis(self)->SetFlags( self, flags );
452	}
453
454	UInt32
455	AsyncStreamListenerCOM::SGetFlags ( AsyncStreamListenerRef	self )
456	{
457		return IOFireWireIUnknown::InterfaceMap<AsyncStreamListenerCOM>::GetThis(self)->GetFlags( self );
458	}
459
460	UInt32
461	AsyncStreamListenerCOM::SGetOverrunCounter ( AsyncStreamListenerRef		self )
462	{
463		return IOFireWireIUnknown::InterfaceMap<AsyncStreamListenerCOM>::GetThis(self)->GetOverrunCounter( self );
464	}
465}
466