1/*
2* Copyright (c) 1998-2000 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*  IOFireWireLibCommand.cpp
24*  IOFireWireLib
25*
26*  Created on Fri Dec 15 2000.
27*  Copyright (c) 2000-2002 Apple, Inc. All rights reserved.
28*
29*/
30
31// public
32#import <IOKit/firewire/IOFireWireLib.h>
33
34// private
35#import "IOFireWireLibCommand.h"
36#import "IOFireWireLibDevice.h"
37#import "IOFireWireLibPriv.h"
38
39// system
40#import <assert.h>
41#import <IOKit/IOKitLib.h>
42#import <IOKit/iokitmig.h>
43#import <System/libkern/OSCrossEndian.h>
44
45#define IOFIREWIRELIBCOMMANDIMP_INTERFACE \
46	&Cmd::SGetStatus,	\
47	&Cmd::SGetTransferredBytes,	\
48	&Cmd::SGetTargetAddress,	\
49	&Cmd::SSetTarget,	\
50	&Cmd::SSetGeneration,	\
51	&Cmd::SSetCallback,	\
52	&Cmd::SSetRefCon,	\
53	&Cmd::SIsExecuting,	\
54	&Cmd::SSubmit,	\
55	&Cmd::SSubmitWithRefconAndCallback, \
56	&Cmd::SCancel
57
58#define IOFIREWIRELIBCOMMANDIMP_INTERFACE_v2	\
59	&Cmd::SSetBuffer,	\
60	&Cmd::SGetBuffer,	\
61	&Cmd::SSetMaxPacket,	\
62	&Cmd::SSetFlags
63
64#define IOFIREWIRELIBCOMMANDIMP_INTERFACE_v3	\
65	&Cmd::SSetTimeoutDuration,	\
66	&Cmd::SSetMaxRetryCount,	\
67	&Cmd::SGetAckCode,		\
68	&Cmd::SGetResponseCode,		\
69	&Cmd::SSetMaxPacketSpeed,	\
70	&Cmd::SGetRefCon
71
72namespace IOFireWireLib {
73
74	ReadCmd::Interface ReadCmd::sInterface =
75	{
76		INTERFACEIMP_INTERFACE,
77		1, 1, // version/revision
78
79		IOFIREWIRELIBCOMMANDIMP_INTERFACE,
80		IOFIREWIRELIBCOMMANDIMP_INTERFACE_v2,
81		IOFIREWIRELIBCOMMANDIMP_INTERFACE_v3
82	} ;
83
84	ReadQuadCmd::Interface ReadQuadCmd::sInterface =
85	{
86		INTERFACEIMP_INTERFACE,
87		1, 0, // version/revision
88
89		IOFIREWIRELIBCOMMANDIMP_INTERFACE,
90
91		& ReadQuadCmd::SSetQuads
92	} ;
93
94	WriteCmd::Interface WriteCmd::sInterface =
95	{
96		INTERFACEIMP_INTERFACE,
97		1, 1, // version/revision
98
99		IOFIREWIRELIBCOMMANDIMP_INTERFACE,
100		IOFIREWIRELIBCOMMANDIMP_INTERFACE_v2,
101		IOFIREWIRELIBCOMMANDIMP_INTERFACE_v3
102	} ;
103
104	WriteQuadCmd::Interface WriteQuadCmd::sInterface =
105	{
106		INTERFACEIMP_INTERFACE,
107		1, 0, // version/revision
108		IOFIREWIRELIBCOMMANDIMP_INTERFACE,
109
110		& WriteQuadCmd::SSetQuads
111	} ;
112
113	CompareSwapCmd::Interface CompareSwapCmd::sInterface =
114	{
115		INTERFACEIMP_INTERFACE,
116		2, 0, // version/revision
117		IOFIREWIRELIBCOMMANDIMP_INTERFACE,
118
119		// --- v1
120		& CompareSwapCmd::SSetValues,
121
122		// --- v2
123		& CompareSwapCmd::SSetValues64,
124		& CompareSwapCmd::SDidLock,
125		& CompareSwapCmd::SLocked,
126		& CompareSwapCmd::SLocked64,
127		& CompareSwapCmd::SSetFlags
128
129	} ;
130
131	CompareSwapCmd::Interface_v3 CompareSwapCmd::sInterface_v3 =
132	{
133		INTERFACEIMP_INTERFACE,
134		2, 0, // version/revision
135		IOFIREWIRELIBCOMMANDIMP_INTERFACE,
136		IOFIREWIRELIBCOMMANDIMP_INTERFACE_v2,
137		IOFIREWIRELIBCOMMANDIMP_INTERFACE_v3,
138
139		// --- v1
140		(void (*)(IOFireWireLibCompareSwapCommandV3Ref, UInt32, UInt32)) &CompareSwapCmd::SSetValues,
141
142		// --- v2
143		(void (*)(IOFireWireLibCompareSwapCommandV3Ref, UInt64, UInt64)) &CompareSwapCmd::SSetValues64,
144		(Boolean (*)(IOFireWireLibCompareSwapCommandV3Ref)) &CompareSwapCmd::SDidLock,
145		(IOReturn (*)(IOFireWireLibCompareSwapCommandV3Ref, UInt32 *)) &CompareSwapCmd::SLocked,
146		(IOReturn (*)(IOFireWireLibCompareSwapCommandV3Ref, UInt64 *)) &CompareSwapCmd::SLocked64
147	} ;
148
149	PHYCmd::Interface PHYCmd::sInterface =
150	{
151		INTERFACEIMP_INTERFACE,
152		1, 0, // version/revision
153
154		IOFIREWIRELIBCOMMANDIMP_INTERFACE,
155		IOFIREWIRELIBCOMMANDIMP_INTERFACE_v2,
156		IOFIREWIRELIBCOMMANDIMP_INTERFACE_v3,
157		&PHYCmd::S_SetDataQuads
158	};
159
160	AsyncStreamCmd::Interface AsyncStreamCmd::sInterface =
161	{
162		INTERFACEIMP_INTERFACE,
163		1, 0, // version/revision
164
165		IOFIREWIRELIBCOMMANDIMP_INTERFACE,
166		IOFIREWIRELIBCOMMANDIMP_INTERFACE_v2,
167		IOFIREWIRELIBCOMMANDIMP_INTERFACE_v3,
168		&AsyncStreamCmd::S_SetChannel,
169		&AsyncStreamCmd::S_SetSyncBits,
170		&AsyncStreamCmd::S_SetTagBits
171	};
172
173	// ==================================
174	// virtual members
175	// ==================================
176#pragma mark -
177	IOFireWireCommandInterface 	Cmd::sInterface =
178	{
179		INTERFACEIMP_INTERFACE,
180		1, 0, 									// version/revision
181		IOFIREWIRELIBCOMMANDIMP_INTERFACE,
182		0, 0, 0, 0,
183		0, 0, 0, 0, 0, 0
184	} ;
185
186	Cmd::Cmd( const IUnknownVTbl & vtable, Device& userClient, io_object_t device,
187					const FWAddress& inAddr, CommandCallback inCallback,
188					const bool inFailOnReset, const UInt32 inGeneration, void* inRefCon,
189					CommandSubmitParams* params )
190	:	IOFireWireIUnknown( vtable ),
191		mUserClient( userClient ),
192		mDevice( device ),
193		mBytesTransferred( 0 ),
194		mIsExecuting( false ),
195		mStatus( kIOReturnSuccess ),
196		mRefCon( inRefCon ),
197		mCallback( 0 ),
198		mParams(params)
199	{
200		mUserClient.AddRef() ;
201		bzero(mParams, sizeof(*mParams)) ;
202
203		mParams->callback		= (mach_vm_address_t)&CommandCompletionHandler;
204		mParams->refCon			= (mach_vm_address_t)this;
205		SetTarget(inAddr) ;
206		SetGeneration(inGeneration) ;
207		mParams->staleFlags 	= kFireWireCommandStale + kFireWireCommandStale_Buffer ;
208		if (0==device)
209			mParams->flags |= kFireWireCommandAbsolute ;
210		mParams->newFailOnReset = inFailOnReset ;
211		SetCallback(inCallback) ;
212	}
213
214	Cmd::~Cmd()
215	{
216		if (mParams)
217		{
218			if (mParams->kernCommandRef)
219			{
220				IOReturn result = kIOReturnSuccess;
221
222				uint32_t outputCnt = 0;
223				const uint64_t inputs[1]={(const uint64_t)mParams->kernCommandRef};
224				result = IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
225												   kReleaseUserObject,
226												   inputs,1,
227												   NULL,&outputCnt);
228
229				DebugLogCond( result, "Cmd::~Cmd: command release returned 0x%08x\n", result) ;
230			}
231
232			delete mParams ;
233		}
234
235		mUserClient.Release() ;
236	}
237
238	HRESULT
239	Cmd::QueryInterface(REFIID iid, LPVOID* ppv)
240	{
241		HRESULT		result = S_OK ;
242		*ppv = nil ;
243
244		CFUUIDRef	interfaceID	= CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
245
246		if (CFEqual(interfaceID, IUnknownUUID) || CFEqual(interfaceID, kIOFireWireCommandInterfaceID) )
247		{
248			*ppv = & GetInterface() ;
249			AddRef() ;
250		}
251		else
252		{
253			*ppv = nil ;
254			result = E_NOINTERFACE ;
255		}
256
257		CFRelease(interfaceID) ;
258		return result ;
259	}
260
261	// --- setters -----------------------
262	void
263	Cmd::SetTarget(
264		const FWAddress&	addr)
265	{
266		mParams->newTarget = addr.addressLo;
267		mParams->newTarget |= (((UInt64)addr.addressHi) << 32);
268		mParams->newTarget |= (((UInt64)addr.nodeID) << 48);
269
270//		mParams->staleFlags |= kFireWireCommandStale ;
271	}
272
273	void
274	Cmd::SetGeneration(
275		UInt32				inGeneration)
276	{
277		mParams->newGeneration = inGeneration ;
278//		mParams->staleFlags |= kFireWireCommandStale ;
279	}
280
281	void
282	Cmd::SetCallback(
283		CommandCallback inCallback)
284	{
285		mCallback = inCallback ;
286
287		if (!mCallback)
288			mParams->flags |= kFWCommandInterfaceSyncExecute ;
289		else
290			mParams->flags &= ~kFWCommandInterfaceSyncExecute ;
291	}
292
293	IOReturn
294	Cmd::PrepareForVectorSubmit( CommandSubmitParams * submit_params )
295	{
296		IOReturn status = kIOReturnSuccess;
297
298		// can't prep the vector if a command is still inflight
299		if( mIsExecuting )
300		{
301			status = kIOReturnBusy;
302		}
303
304		// we're not supporting synchronous operations
305		// or inline data when using vectors
306
307		if( status == kIOReturnSuccess )
308		{
309			if( (mParams->flags & kFWCommandInterfaceSyncExecute) ||
310				(mParams->flags & kFireWireCommandUseCopy) )
311			{
312				status = kIOReturnBadArgument;
313			}
314		}
315
316		// we're only supportting read and write operations on vectors
317
318		if( status == kIOReturnSuccess )
319		{
320			if( (mParams->type != kFireWireCommandType_Read) &&
321				(mParams->type != kFireWireCommandType_Write) &&
322				(mParams->type != kFireWireCommandType_PHY) )
323			{
324				status = kIOReturnBadArgument;
325			}
326		}
327
328		if( status == kIOReturnSuccess )
329		{
330			// if we don't yet have kernel command for this command,  make it now
331			if( !mParams->kernCommandRef )
332			{
333				// async ref data
334				uint64_t async_ref[kOSAsyncRef64Count];
335				async_ref[kIOAsyncCalloutFuncIndex] = (uint64_t)0;
336				async_ref[kIOAsyncCalloutRefconIndex] = (unsigned long)0;
337
338				// input data
339				CommandSubmitParams create_params;
340				bcopy( mParams, &create_params, sizeof(CommandSubmitParams) );
341
342				// swap for Rosetta
343		#ifndef __LP64__
344				ROSETTA_ONLY(
345					{
346						//create_params.kernCommandRef = create_params.kernCommandRef;  // no swap
347						create_params.type = (IOFireWireCommandType)OSSwapInt32(create_params.type);
348						create_params.callback = (mach_vm_address_t)OSSwapInt64( (UInt64)create_params.callback );
349						create_params.refCon = (mach_vm_address_t)OSSwapInt64( (UInt64)create_params.refCon );
350						create_params.flags = OSSwapInt32( create_params.flags );
351						create_params.staleFlags = OSSwapInt32( create_params.staleFlags );
352						create_params.newTarget = OSSwapInt64( create_params.newTarget );
353						create_params.newBuffer = (mach_vm_address_t)OSSwapInt64( (UInt64)create_params.newBuffer);
354						create_params.newBufferSize = OSSwapInt32( create_params.newBufferSize );
355						//create_params.newFailOnReset = create_params.newFailOnReset;
356						create_params.newGeneration = OSSwapInt32( create_params.newGeneration );
357						create_params.newMaxPacket = OSSwapInt32( create_params.newMaxPacket );
358
359						create_params.timeoutDuration = OSSwapInt32( create_params.timeoutDuration );
360						create_params.retryCount = OSSwapInt32( create_params.retryCount );
361						create_params.maxPacketSpeed = OSSwapInt32( create_params.maxPacketSpeed );
362					}
363				);
364		#endif
365
366				// output data
367				UInt32	kernel_ref = 0;
368				size_t outputStructCnt = sizeof(kernel_ref);
369
370				// send it down
371				status = IOConnectCallAsyncStructMethod(	mUserClient.GetUserClientConnection(),
372															kCommandCreateAsync,
373															mUserClient.GetAsyncPort(),
374															async_ref, kOSAsyncRef64Count,
375															&create_params, sizeof(CommandSubmitParams),
376															&kernel_ref, &outputStructCnt );
377				if( status == kIOReturnSuccess )
378				{
379					mParams->kernCommandRef = kernel_ref;
380				}
381			}
382		}
383
384		if( status == kIOReturnSuccess )
385		{
386			// staleFlags will be reset to 0 on each Submit() call,
387			// so we set kFireWireCommandStale_MaxPacket before we submit
388			if (mParams->newMaxPacket > 0)
389				mParams->staleFlags |= kFireWireCommandStale_MaxPacket;
390
391			// copy params into vector
392			bcopy( mParams, submit_params, sizeof(CommandSubmitParams) );
393
394			// swap for Rosetta
395	#ifndef __LP64__
396			ROSETTA_ONLY(
397				{
398					//submit_params->kernCommandRef = submit_params->kernCommandRef;  // no swap
399					submit_params->type = (IOFireWireCommandType)OSSwapInt32(submit_params->type);
400					submit_params->callback = (mach_vm_address_t)OSSwapInt64( (UInt64)submit_params->callback );
401					submit_params->refCon = (mach_vm_address_t)OSSwapInt64( (UInt64)submit_params->refCon );
402					submit_params->flags = OSSwapInt32( submit_params->flags );
403					submit_params->staleFlags = OSSwapInt32( submit_params->staleFlags );
404					submit_params->newTarget = OSSwapInt64( submit_params->newTarget );
405					submit_params->newBuffer = (mach_vm_address_t)OSSwapInt64( (UInt64)submit_params->newBuffer);
406					submit_params->newBufferSize = OSSwapInt32( submit_params->newBufferSize );
407					//submit_params->newFailOnReset = submit_params->newFailOnReset;
408					submit_params->newGeneration = OSSwapInt32( submit_params->newGeneration );
409					submit_params->newMaxPacket = OSSwapInt32( submit_params->newMaxPacket );
410
411					submit_params->timeoutDuration = OSSwapInt32( submit_params->timeoutDuration );
412					submit_params->retryCount = OSSwapInt32( submit_params->retryCount );
413					submit_params->maxPacketSpeed = OSSwapInt32( submit_params->maxPacketSpeed );
414				}
415			);
416	#endif
417
418		}
419
420		//	printf( "Cmd::PrepareForVectorSubmit - status = 0x%08lx\n", status );
421
422		return status;
423	}
424
425	void
426	Cmd::VectorIsExecuting( void )
427	{
428		mIsExecuting = true ;
429		mParams->staleFlags = 0;
430	}
431
432	IOReturn
433	Cmd::Submit(
434		CommandSubmitParams*		params,
435		mach_msg_type_number_t		paramsSize,
436		CommandSubmitResult*		submitResult,
437		mach_msg_type_number_t*		submitResultSize)
438	{
439		// staleFlags will be reset to 0 on each Submit() call,
440		// so we set kFireWireCommandStale_MaxPacket before we submit
441		if (mParams->newMaxPacket > 0)
442			mParams->staleFlags |= kFireWireCommandStale_MaxPacket;
443
444		CommandSubmitParams	* submit_params = params;
445
446		IOReturn 			err = 0;
447		vm_address_t vm_address = 0;
448#ifndef __LP64__
449		ROSETTA_ONLY(
450			{
451				err = vm_allocate( mach_task_self(), &vm_address, paramsSize, true /*anywhere*/ );
452				if( vm_address == 0 )
453				{
454					err = kIOReturnNoMemory;
455				}
456
457				if( !err )
458				{
459					submit_params = (CommandSubmitParams*)vm_address;
460					bcopy( params, submit_params, paramsSize );
461
462					//submit_params->kernCommandRef = submit_params->kernCommandRef;  // no swap
463					submit_params->type = (IOFireWireCommandType)OSSwapInt32(submit_params->type);
464					submit_params->callback = (mach_vm_address_t)OSSwapInt64( (UInt64)submit_params->callback );
465					submit_params->refCon = (mach_vm_address_t)OSSwapInt64( (UInt64)submit_params->refCon );
466					submit_params->flags = OSSwapInt32( submit_params->flags );
467					submit_params->staleFlags = OSSwapInt32( submit_params->staleFlags );
468					submit_params->newTarget = OSSwapInt64( submit_params->newTarget );
469					submit_params->newBuffer = (mach_vm_address_t)OSSwapInt64( (UInt64)submit_params->newBuffer);
470					submit_params->newBufferSize = OSSwapInt32( submit_params->newBufferSize );
471					//submit_params->newFailOnReset = submit_params->newFailOnReset;
472					submit_params->newGeneration = OSSwapInt32( submit_params->newGeneration );
473					submit_params->newMaxPacket = OSSwapInt32( submit_params->newMaxPacket );
474
475					submit_params->timeoutDuration = OSSwapInt32( submit_params->timeoutDuration );
476					submit_params->retryCount = OSSwapInt32( submit_params->retryCount );
477					submit_params->maxPacketSpeed = OSSwapInt32( submit_params->maxPacketSpeed );
478
479				}
480			}
481		);
482#endif
483
484		if( !err )
485		{
486			uint64_t refrncData[kOSAsyncRef64Count];
487			refrncData[kIOAsyncCalloutFuncIndex] = (uint64_t) 0;
488			refrncData[kIOAsyncCalloutRefconIndex] = (unsigned long) 0;
489			size_t outputStructCnt = *submitResultSize;
490
491			err = IOConnectCallAsyncStructMethod(mUserClient.GetUserClientConnection(),
492												 kCommand_Submit,
493												 mUserClient.GetAsyncPort(),
494												 refrncData,kOSAsyncRef64Count,
495												 submit_params,paramsSize,
496												 submitResult,&outputStructCnt);
497			*submitResultSize = outputStructCnt;
498		}
499
500
501		if ( !err )
502		{
503#ifndef __LP64__
504			ROSETTA_ONLY(
505				{
506			//		submitResult->kernCommandRef = submitResult->kernCommandRef;
507					submitResult->result = OSSwapInt32( submitResult->result );
508					submitResult->bytesTransferred = OSSwapInt32( submitResult->bytesTransferred );
509					submitResult->ackCode = OSSwapInt32( submitResult->ackCode );
510					submitResult->responseCode = OSSwapInt32( submitResult->responseCode );
511				}
512			);
513#endif
514			if (mParams->flags & kFWCommandInterfaceSyncExecute)
515			{
516				mStatus = submitResult->result ;
517				mBytesTransferred = submitResult->bytesTransferred ;
518				mAckCode = submitResult->ackCode;
519				mResponseCode = submitResult->responseCode;
520
521				// the kernel has to pass success to get submit results, set err to the proper err here
522				err = mStatus;
523			}
524			else
525				mIsExecuting = true ;
526
527			mParams->staleFlags = 0 ;
528			if (!mParams->kernCommandRef)
529				mParams->kernCommandRef = submitResult->kernCommandRef ;
530		}
531
532		if( vm_address )
533		{
534			vm_deallocate( mach_task_self(), vm_address, paramsSize );
535		}
536
537		return err ;
538	}
539
540	IOReturn
541	Cmd::SubmitWithRefconAndCallback(
542		void*	inRefCon,
543		CommandCallback	inCallback)
544	{
545		if (mIsExecuting)
546			return kIOReturnBusy ;
547
548		mRefCon = inRefCon ;
549		SetCallback(inCallback) ;
550
551		return Submit() ;
552	}
553
554	IOReturn
555	Cmd::Cancel(
556		IOReturn	reason)
557	{
558		if (!mIsExecuting)
559			return kIOReturnSuccess ;
560
561		uint32_t outputCnt = 0;
562		return IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
563										 mUserClient.MakeSelectorWithObject( kCommand_Cancel_d, mParams->kernCommandRef ),
564										 NULL,0,
565										 NULL,&outputCnt);
566	}
567
568	void
569	Cmd::SetBuffer(
570		UInt32				inSize,
571		void*				inBuffer)
572	{
573		mParams->newBufferSize = inSize ;
574		mParams->newBuffer = (mach_vm_address_t)inBuffer ;
575		mParams->staleFlags |= kFireWireCommandStale_Buffer ;
576	}
577
578	void
579	Cmd::GetBuffer(
580		UInt32*				outSize,
581		void**				outBuf)
582	{
583		*outSize = mParams->newBufferSize ;
584		*outBuf	= (void*)mParams->newBuffer ;
585	}
586
587	IOReturn
588	Cmd::SetMaxPacket(
589		IOByteCount				inMaxBytes)
590	{
591		mParams->newMaxPacket = inMaxBytes ;
592		// staleFlags will be reset to 0 on each Submit() call,
593		// so we set kFireWireCommandStale_MaxPacket before we submit
594
595//		mParams->staleFlags |= kFireWireCommandStale_MaxPacket;
596		return kIOReturnSuccess ;
597	}
598
599	void
600	Cmd::SetFlags(
601		UInt32					inFlags)
602	{
603		if (mParams->flags & ~kFireWireCommandUserFlagsMask)
604		{
605#ifdef __LP64__
606			DebugLog("Invalid flags %x passed to SetFlags!\n", inFlags) ;
607#else
608			DebugLog("Invalid flags %lx passed to SetFlags!\n", inFlags) ;
609#endif
610		}
611
612		mParams->flags &= ~kFireWireCommandUserFlagsMask ;
613		mParams->flags |= (inFlags & kFireWireCommandUserFlagsMask) ;
614
615		if (mParams->flags & kFWCommandInterfaceForceCopyAlways)
616			mParams->flags |= kFireWireCommandUseCopy ;
617		if (mParams->flags & kFWCommandInterfaceForceNoCopy)
618			mParams->flags &= ~kFireWireCommandUseCopy ;
619		if (mParams->flags & kFWCommandInterfaceAbsolute )
620			mParams->flags |= kFireWireCommandAbsolute ;
621	}
622
623	void Cmd::SetTimeoutDuration(
624		UInt32 duration )
625	{
626		mParams->timeoutDuration = duration;
627		mParams->staleFlags |= kFireWireCommandStale_Timeout;
628	}
629
630	void
631	Cmd::SetMaxRetryCount(
632		UInt32 count )
633	{
634		mParams->retryCount = count;
635		mParams->staleFlags |= kFireWireCommandStale_Retries;
636	}
637
638	UInt32
639	Cmd::GetAckCode()
640	{
641		return mAckCode;
642	}
643
644	UInt32
645	Cmd::GetResponseCode()
646	{
647		return mResponseCode;
648	}
649
650	void
651	Cmd::SetMaxPacketSpeed( IOFWSpeed speed )
652	{
653		mParams->maxPacketSpeed = speed;
654		mParams->staleFlags |= kFireWireCommandStale_Speed;
655	}
656
657	void
658	Cmd::CommandCompletionHandler(
659		void*				refcon,
660		IOReturn			result,
661		void*				quads[],
662		UInt32				numQuads )
663	{
664		Cmd*	me = (Cmd*)refcon ;
665
666		me->mStatus 			= result ;
667		me->mBytesTransferred 	= (unsigned long)quads[0] ;
668		me->mAckCode			= (unsigned long)quads[1];
669		me->mResponseCode		= (unsigned long)quads[2];
670		me->mIsExecuting 		= false ;
671
672		if (me->mCallback)
673			(*(me->mCallback))(me->mRefCon, me->mStatus) ;
674	}
675
676	// --- getters -----------------------
677	IOReturn
678	Cmd::SGetStatus(
679		IOFireWireLibCommandRef	self)
680	{
681		return IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->mStatus ;
682	}
683
684	UInt32
685	Cmd::SGetTransferredBytes(
686		IOFireWireLibCommandRef	self)
687	{
688		return IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->mBytesTransferred ;
689	}
690
691	void
692	Cmd::SGetTargetAddress(
693		IOFireWireLibCommandRef	self,
694		FWAddress*				outAddr)
695	{
696		*outAddr = IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->mParams->newTarget ;
697	}
698
699	// --- setters -----------------------
700	void
701	Cmd::SSetTarget(
702		IOFireWireLibCommandRef	self,
703		const FWAddress*	inAddr)
704	{
705		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SetTarget(*inAddr) ;
706	}
707
708	void
709	Cmd::SSetGeneration(
710		IOFireWireLibCommandRef	self,
711		UInt32					inGeneration)
712	{
713		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SetGeneration(inGeneration) ;
714	}
715
716	void
717	Cmd::SSetCallback(
718		IOFireWireLibCommandRef			self,
719		CommandCallback	inCallback)
720	{
721		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SetCallback(inCallback) ;
722	}
723
724	void
725	Cmd::SSetRefCon(
726		IOFireWireLibCommandRef	self,
727		void*					refCon)
728	{
729		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->mRefCon = refCon ;
730	}
731
732	void *
733	Cmd::SGetRefCon(
734		IOFireWireLibCommandRef	self )
735	{
736		return IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->mRefCon;
737	}
738
739	const Boolean
740	Cmd::SIsExecuting(
741		IOFireWireLibCommandRef	self)
742	{
743		return IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->mIsExecuting;
744	}
745
746	IOReturn
747	Cmd::SSubmit(
748		IOFireWireLibCommandRef	self)
749	{
750		return IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->Submit() ;
751	}
752
753	IOReturn
754	Cmd::SSubmitWithRefconAndCallback(
755		IOFireWireLibCommandRef	self,
756		void*					inRefCon,
757		CommandCallback inCallback)
758	{
759		return IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SubmitWithRefconAndCallback(inRefCon, inCallback) ;
760	}
761
762	IOReturn
763	Cmd::SCancel(
764		IOFireWireLibCommandRef	self,
765		IOReturn				reason)
766	{
767		return IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->Cancel(reason) ;
768	}
769
770	void
771	Cmd::SSetBuffer(
772		IOFireWireLibCommandRef		self,
773		UInt32						inSize,
774		void*						inBuf)
775	{
776		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SetBuffer(inSize, inBuf) ;
777	}
778
779	void
780	Cmd::SGetBuffer(
781		IOFireWireLibCommandRef		self,
782		UInt32*						outSize,
783		void**						outBuf)
784	{
785		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->GetBuffer(outSize, outBuf) ;
786	}
787
788	IOReturn
789	Cmd::SSetMaxPacket(
790		IOFireWireLibCommandRef self,
791		IOByteCount				inMaxBytes)
792	{
793		return IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SetMaxPacket(inMaxBytes) ;
794	}
795
796	void
797	Cmd::SSetFlags(
798		IOFireWireLibCommandRef	self,
799		UInt32					inFlags)
800	{
801		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SetFlags(inFlags) ;
802	}
803
804	void
805	Cmd::SSetTimeoutDuration(
806		IOFireWireLibCommandRef self,
807		UInt32 duration )
808	{
809		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SetTimeoutDuration( duration );
810	}
811
812	void
813	Cmd::SSetMaxRetryCount(
814		IOFireWireLibCommandRef self,
815		UInt32 count )
816	{
817		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SetMaxRetryCount( count );
818	}
819
820	UInt32
821	Cmd::SGetAckCode( IOFireWireLibCommandRef self )
822	{
823		return IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->GetAckCode();
824	}
825
826	UInt32
827	Cmd::SGetResponseCode( IOFireWireLibCommandRef self )
828	{
829		return IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->GetResponseCode();
830	}
831
832	void
833	Cmd::SSetMaxPacketSpeed( IOFireWireLibCommandRef self, IOFWSpeed speed )
834	{
835		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SetMaxPacketSpeed( speed );
836	}
837
838	// ============================================================
839	//
840	// ReadCmd methods
841	//
842	// ============================================================
843#pragma mark -
844	ReadCmd::ReadCmd( Device& userclient, io_object_t device, const FWAddress& addr, void* buf,
845							UInt32 size, CommandCallback callback, bool failOnReset,
846							UInt32 generation, void* refcon )
847	: Cmd( reinterpret_cast<const IUnknownVTbl &>( sInterface ), userclient, device, addr, callback,
848				failOnReset, generation, refcon,
849				reinterpret_cast<CommandSubmitParams*>(new UInt8[sizeof(CommandSubmitParams)]) )
850	{
851		mParams->type			 = kFireWireCommandType_Read ;
852		mParams->newBuffer		 = (mach_vm_address_t)buf ;
853		mParams->newBufferSize	 = size ;
854		mParams->staleFlags 	|= kFireWireCommandStale_Buffer ;
855	}
856
857	HRESULT
858	ReadCmd::QueryInterface(REFIID iid, LPVOID* ppv)
859	{
860		HRESULT		result = S_OK ;
861		*ppv = nil ;
862
863		CFUUIDRef	interfaceID	= CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
864
865		if ( CFEqual( interfaceID, IUnknownUUID )
866			|| CFEqual( interfaceID, kIOFireWireCommandInterfaceID)
867			|| CFEqual( interfaceID, kIOFireWireReadCommandInterfaceID)
868			|| CFEqual( interfaceID, kIOFireWireReadCommandInterfaceID_v2)
869			|| CFEqual( interfaceID, kIOFireWireReadCommandInterfaceID_v3) )
870		{
871			*ppv = & GetInterface() ;
872			AddRef() ;
873		}
874		else
875		{
876			*ppv = nil ;
877			result = E_NOINTERFACE ;
878		}
879
880		CFRelease(interfaceID) ;
881		return result ;
882	}
883
884	IUnknownVTbl**
885	ReadCmd::Alloc(
886		Device& 			userclient,
887		io_object_t			device,
888		const FWAddress&	addr,
889		void*				buf,
890		UInt32				size,
891		CommandCallback callback,
892		bool				failOnReset,
893		UInt32				generation,
894		void*				inRefCon)
895	{
896		ReadCmd*	me = new ReadCmd( userclient, device, addr, buf, size, callback, failOnReset, generation, inRefCon ) ;
897		if (!me)
898			return nil ;
899
900		return reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
901	}
902
903	IOReturn
904	ReadCmd::Submit()
905	{
906		if ( mIsExecuting )
907			return kIOReturnBusy ;
908
909		IOReturn					result 				= kIOReturnSuccess ;
910		UInt8						submitResultExtra[ sizeof(CommandSubmitResult) + kFWUserCommandSubmitWithCopyMaxBufferBytes ] ;
911		CommandSubmitResult*		submitResult 		= (CommandSubmitResult*) submitResultExtra ;
912		mach_msg_type_number_t		submitResultSize ;
913
914		if (mParams->flags & kFireWireCommandUseCopy)
915			submitResultSize = sizeof(*submitResult) + mParams->newBufferSize ;
916		else
917			submitResultSize = sizeof(*submitResult) ;
918
919		result = Cmd::Submit(mParams, sizeof(*mParams), submitResult, & submitResultSize) ;
920
921		if ((mParams->flags & kFWCommandInterfaceSyncExecute) &&
922			(mParams->flags & kFireWireCommandUseCopy) &&
923			(kIOReturnSuccess == result))
924		{
925			bcopy(submitResult + 1, (void*)mParams->newBuffer, mBytesTransferred) ;
926		}
927
928		return result ;
929	}
930
931	// ============================================================
932	//
933	// ReadQuadCmd methods
934	//
935	// ============================================================
936#pragma mark -
937	ReadQuadCmd::ReadQuadCmd(	Device& 						userclient,
938								io_object_t						device,
939								const FWAddress &				addr,
940								UInt32							quads[],
941								UInt32							numQuads,
942								CommandCallback 	callback,
943								Boolean							failOnReset,
944								UInt32							generation,
945								void*							refcon)
946	: Cmd( reinterpret_cast<const IUnknownVTbl &>( sInterface ), userclient, device, addr, callback,
947				failOnReset, generation, refcon,
948				reinterpret_cast<CommandSubmitParams*>(new UInt8[sizeof(CommandSubmitParams)]) )
949	{
950		mParams->callback		= (mach_vm_address_t)&CommandCompletionHandler;
951		mParams->type			= kFireWireCommandType_ReadQuadlet ;
952		mParams->newBuffer		= (mach_vm_address_t)quads ;
953		mParams->newBufferSize	= numQuads << 2 ;	// x * 4
954		mParams->staleFlags 	|= kFireWireCommandStale_Buffer ;
955		mParams->flags			|= kFireWireCommandUseCopy ;
956	}
957
958	IUnknownVTbl**
959	ReadQuadCmd::Alloc( Device& inUserClient, io_object_t device, const FWAddress& addr, UInt32 quads[], UInt32 numQuads,
960								CommandCallback callback, Boolean failOnReset, UInt32 generation, void* refcon)
961	{
962		ReadQuadCmd*	me = new ReadQuadCmd(inUserClient, device, addr, quads, numQuads, callback, failOnReset, generation, refcon) ;
963		if (!me)
964			return nil ;
965
966		return reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
967	}
968
969	HRESULT
970	ReadQuadCmd::QueryInterface(REFIID iid, LPVOID* ppv)
971	{
972		HRESULT		result = S_OK ;
973		*ppv = nil ;
974
975		CFUUIDRef	interfaceID	= CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
976
977		if (CFEqual(interfaceID, IUnknownUUID) || CFEqual(interfaceID, kIOFireWireCommandInterfaceID) || CFEqual(interfaceID, kIOFireWireReadQuadletCommandInterfaceID) )
978		{
979			*ppv = & GetInterface() ;
980			AddRef() ;
981		}
982		else
983		{
984			*ppv = nil ;
985			result = E_NOINTERFACE ;
986		}
987
988		CFRelease(interfaceID) ;
989		return result ;
990	}
991
992	void
993	ReadQuadCmd::SetFlags(
994		UInt32					inFlags)
995	{
996		Cmd::SetFlags(inFlags) ;
997
998		// force always copy:
999		mParams->flags |= kFireWireCommandUseCopy ;
1000	}
1001
1002	void
1003	ReadQuadCmd::SetQuads(
1004		UInt32				inQuads[],
1005		UInt32				inNumQuads)
1006	{
1007		mParams->newBufferSize = inNumQuads << 2; // * 4
1008		mParams->newBuffer = (mach_vm_address_t) inQuads ;
1009		mNumQuads = inNumQuads ;
1010
1011		mParams->staleFlags |= kFireWireCommandStale_Buffer ;
1012	}
1013
1014	IOReturn
1015	ReadQuadCmd::Submit()
1016	{
1017		if (mIsExecuting)
1018			return kIOReturnBusy ;
1019
1020		IOReturn 					result 			= kIOReturnSuccess ;
1021		Boolean						syncFlag = mParams->flags & kFWCommandInterfaceSyncExecute ;
1022		UInt8						submitResultExtra[sizeof(CommandSubmitResult) + (syncFlag ? mParams->newBufferSize : 0)] ;
1023		mach_msg_type_number_t		submitResultSize = sizeof(submitResultExtra) ;
1024		CommandSubmitResult*		submitResult = reinterpret_cast<CommandSubmitResult*>(submitResultExtra) ;
1025
1026		result = Cmd::Submit(mParams, sizeof(*mParams), submitResult, & submitResultSize) ;
1027
1028		if (kIOReturnSuccess == result && syncFlag)
1029		{
1030
1031			bcopy(submitResult + 1, (void*)mParams->newBuffer, mBytesTransferred) ;
1032		}
1033
1034		return result ;
1035	}
1036
1037	void
1038	ReadQuadCmd::CommandCompletionHandler(
1039		void*				refcon,
1040		IOReturn			result,
1041		void*				quads[],
1042		UInt32				numQuads)
1043	{
1044		numQuads -= 2 ;	// number increased by 2 to make
1045						// sendAsyncResult64 always send args as a pointer
1046						// instead of inline...
1047
1048		ReadQuadCmd*	me = (ReadQuadCmd*)refcon ;
1049
1050		me->mStatus 			= result ;
1051		me->mBytesTransferred 	= (numQuads *4) + 2;
1052		me->mAckCode			= (unsigned long)quads[2];
1053		me->mResponseCode		= (unsigned long)quads[1];
1054		me->mIsExecuting 		= false;
1055
1056		//zzz this copy is going to have to change for 64 bit
1057		bcopy( quads + 2, (void*)me->mParams->newBuffer, me->mBytesTransferred );
1058
1059#ifndef __LP64__
1060		ROSETTA_ONLY(
1061			{
1062				// async results get auto swapped on 32 bit boundaries
1063				// unswap what shouldn't have been swapped
1064
1065				UInt32 * buffer_quads = (UInt32*)me->mParams->newBuffer;
1066
1067				for( unsigned i = 0; i < numQuads; i++ )
1068				{
1069					buffer_quads[i] = OSSwapInt32( buffer_quads[i] );
1070				}
1071			}
1072		);
1073#endif
1074
1075		if (me->mCallback)
1076			(*(me->mCallback))(me->mRefCon, me->mStatus) ;
1077	}
1078
1079	void
1080	ReadQuadCmd::SSetQuads(
1081		IOFireWireLibReadQuadletCommandRef self,
1082		UInt32				inQuads[],
1083		UInt32				inNumQuads)
1084	{
1085		IOFireWireIUnknown::InterfaceMap<ReadQuadCmd>::GetThis(self)->SetQuads(inQuads, inNumQuads) ;
1086	}
1087
1088	// ============================================================
1089	//
1090	// WriteCmd methods
1091	//
1092	// ============================================================
1093#pragma mark -
1094	WriteCmd::WriteCmd( Device& userclient, io_object_t device, const FWAddress& addr, void* buf, UInt32 size,
1095								CommandCallback callback, bool failOnReset, UInt32 generation, void* refcon )
1096	: Cmd( reinterpret_cast<const IUnknownVTbl &>( sInterface), userclient, device, addr, callback,
1097				failOnReset, generation, refcon,
1098				reinterpret_cast<CommandSubmitParams*>(new UInt8[sizeof(CommandSubmitParams)]) )
1099	{
1100		mParams->type			= kFireWireCommandType_Write ;
1101		mParams->newBuffer		= (mach_vm_address_t)buf ;
1102		mParams->newBufferSize	= size ;
1103		mParams->staleFlags |= kFireWireCommandStale_Buffer ;
1104	}
1105
1106	IUnknownVTbl**
1107	WriteCmd::Alloc( Device& userclient, io_object_t device, const FWAddress& addr, void* buf, UInt32 size,
1108							CommandCallback callback, bool failOnReset, UInt32 generation, void* refcon)
1109	{
1110		WriteCmd*	me = new WriteCmd( userclient, device, addr, buf, size, callback, failOnReset, generation, refcon ) ;
1111
1112		if (!me)
1113			return nil ;
1114
1115		return reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
1116	}
1117
1118	HRESULT
1119	WriteCmd::QueryInterface(REFIID iid, LPVOID* ppv)
1120	{
1121		HRESULT		result = S_OK ;
1122		*ppv = nil ;
1123
1124		CFUUIDRef	interfaceID	= CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
1125
1126		if ( CFEqual(interfaceID, IUnknownUUID)
1127			|| CFEqual(interfaceID, kIOFireWireCommandInterfaceID)
1128			|| CFEqual(interfaceID, kIOFireWireWriteCommandInterfaceID)
1129			|| CFEqual(interfaceID, kIOFireWireWriteCommandInterfaceID_v2)
1130			|| CFEqual(interfaceID, kIOFireWireWriteCommandInterfaceID_v3) )
1131		{
1132			*ppv = & GetInterface() ;
1133			AddRef() ;
1134		}
1135		else
1136		{
1137			*ppv = nil ;
1138			result = E_NOINTERFACE ;
1139		}
1140
1141		CFRelease(interfaceID) ;
1142		return result ;
1143	}
1144
1145	IOReturn
1146	WriteCmd::Submit()
1147	{
1148		if (mIsExecuting)
1149			return kIOReturnBusy ;
1150
1151		CommandSubmitResult			submitResult ;
1152		mach_msg_type_number_t		submitResultSize = sizeof(submitResult) ;
1153		UInt32						paramsSize ;
1154
1155		if (mParams->flags & kFireWireCommandUseCopy)
1156			paramsSize = sizeof(*mParams) + mParams->newBufferSize ;
1157		else
1158			paramsSize = sizeof(*mParams) ;
1159
1160		return Cmd::Submit(mParams, paramsSize, & submitResult, & submitResultSize) ;
1161	}
1162
1163	// ============================================================
1164	//
1165	// PHYCmd methods
1166	//
1167	// ============================================================
1168#pragma mark -
1169	PHYCmd::PHYCmd( Device& userclient, UInt32 data1, UInt32 data2,
1170								CommandCallback callback, bool failOnReset, UInt32 generation, void* refcon )
1171	: Cmd( reinterpret_cast<const IUnknownVTbl &>( sInterface), userclient, NULL, FWAddress(), callback,
1172				failOnReset, generation, refcon,
1173				reinterpret_cast<CommandSubmitParams*>(new UInt8[sizeof(CommandSubmitParams)]) )
1174	{
1175		mParams->type			= kFireWireCommandType_PHY ;
1176		mParams->newBuffer		= 0;
1177		mParams->newBufferSize	= 0;
1178	//	mParams->staleFlags |= kFireWireCommandStale_Buffer ;
1179		mParams->data1			= data1;
1180		mParams->data2			= data2;
1181	}
1182
1183	IUnknownVTbl**
1184	PHYCmd::Alloc( Device& userclient, UInt32 data1, UInt32 data2,
1185							CommandCallback callback, bool failOnReset, UInt32 generation, void* refcon)
1186	{
1187		PHYCmd*	me = new PHYCmd( userclient, data1, data2, callback, failOnReset, generation, refcon );
1188
1189		if (!me)
1190			return nil;
1191
1192		return reinterpret_cast<IUnknownVTbl**>(& me->GetInterface());
1193	}
1194
1195	HRESULT
1196	PHYCmd::QueryInterface( REFIID iid, LPVOID* ppv )
1197	{
1198		HRESULT		result = S_OK ;
1199		*ppv = nil ;
1200
1201		CFUUIDRef	interfaceID	= CFUUIDCreateFromUUIDBytes( kCFAllocatorDefault, iid );
1202
1203		if ( CFEqual(interfaceID, IUnknownUUID)
1204			|| CFEqual(interfaceID, kIOFireWireCommandInterfaceID)
1205			|| CFEqual(interfaceID, kIOFireWirePHYCommandInterfaceID)
1206			)
1207		{
1208			*ppv = & GetInterface() ;
1209			AddRef() ;
1210		}
1211		else
1212		{
1213			*ppv = nil ;
1214			result = E_NOINTERFACE ;
1215		}
1216
1217		CFRelease(interfaceID) ;
1218		return result ;
1219	}
1220
1221	IOReturn
1222	PHYCmd::Submit()
1223	{
1224		if (mIsExecuting)
1225			return kIOReturnBusy ;
1226
1227		CommandSubmitResult			submitResult ;
1228		mach_msg_type_number_t		submitResultSize = sizeof(submitResult) ;
1229		UInt32						paramsSize ;
1230
1231		paramsSize = sizeof(*mParams) ;
1232
1233		return Cmd::Submit(mParams, paramsSize, & submitResult, & submitResultSize) ;
1234	}
1235
1236	void PHYCmd::S_SetDataQuads(	IOFireWireLibPHYCommandRef	self,
1237									UInt32						data1,
1238									UInt32						data2 )
1239	{
1240		PHYCmd * phy_cmd = IOFireWireIUnknown::InterfaceMap<PHYCmd>::GetThis(self);
1241
1242		phy_cmd->mParams->data1 = data1;
1243		phy_cmd->mParams->data2 = data2;
1244	}
1245
1246	// ============================================================
1247	//
1248	// WriteQuadCmd methods
1249	//
1250	// ============================================================
1251#pragma mark -
1252	WriteQuadCmd::WriteQuadCmd( Device& userclient, io_object_t device, const FWAddress& addr, UInt32 quads[], UInt32 numQuads,
1253										CommandCallback callback, bool failOnReset, UInt32 generation, void* refcon )
1254	: Cmd( reinterpret_cast<const IUnknownVTbl &>( sInterface ), userclient, device, addr, callback, failOnReset, generation, refcon,
1255				reinterpret_cast<CommandSubmitParams*>(new UInt8[sizeof(CommandSubmitParams) + numQuads << 2]) ),
1256	mParamsExtra( reinterpret_cast<UInt8*>(mParams) )
1257	{
1258		mParams->type			= kFireWireCommandType_WriteQuadlet ;
1259		mParams->newBuffer 		= (mach_vm_address_t)(mParams+1);//(void*) quads ;
1260		mParams->newBufferSize 	= numQuads << 2 ; // * 4
1261		mParams->staleFlags 	|= kFireWireCommandStale_Buffer ;
1262		mParams->flags			|= kFireWireCommandUseCopy ;
1263
1264		bcopy(quads, mParams+1, mParams->newBufferSize) ;
1265	}
1266
1267	WriteQuadCmd::~WriteQuadCmd()
1268	{
1269		delete[] mParamsExtra ;
1270		mParamsExtra = nil ;
1271		mParams = nil ;
1272	}
1273
1274	HRESULT
1275	WriteQuadCmd::QueryInterface(REFIID iid, LPVOID* ppv)
1276	{
1277		HRESULT		result = S_OK ;
1278		*ppv = nil ;
1279
1280		CFUUIDRef	interfaceID	= CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
1281
1282		if (CFEqual(interfaceID, IUnknownUUID) || CFEqual(interfaceID, kIOFireWireCommandInterfaceID) || CFEqual(interfaceID, kIOFireWireWriteQuadletCommandInterfaceID) )
1283		{
1284			*ppv = & GetInterface() ;
1285			AddRef() ;
1286		}
1287		else
1288		{
1289			*ppv = nil ;
1290			result = E_NOINTERFACE ;
1291		}
1292
1293		CFRelease(interfaceID) ;
1294		return result ;
1295	}
1296
1297	IUnknownVTbl**
1298	WriteQuadCmd::Alloc(
1299		Device& 			userclient,
1300		io_object_t			device,
1301		const FWAddress &	addr,
1302		UInt32				quads[],
1303		UInt32				numQuads,
1304		CommandCallback callback,
1305		bool				failOnReset,
1306		UInt32				generation,
1307		void*				refcon)
1308	{
1309		WriteQuadCmd*	me = new WriteQuadCmd( userclient, device, addr, quads, numQuads, callback, failOnReset, generation, refcon ) ;
1310		if (!me)
1311			return nil ;
1312
1313		return reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
1314	}
1315
1316	void
1317	WriteQuadCmd::SetFlags(
1318		UInt32					inFlags)
1319	{
1320		Cmd::SetFlags(inFlags) ;
1321
1322		// force always copy:
1323		mParams->flags |= kFireWireCommandUseCopy ;
1324	}
1325
1326	void
1327	WriteQuadCmd::SetQuads(
1328		UInt32				inQuads[],
1329		UInt32				inNumQuads)
1330	{
1331		UInt32	newSize = inNumQuads << 2 ;
1332		if (newSize > mParams->newBufferSize)
1333		{
1334			// we're going to need more room to hold user's quads:
1335			// set our size to the new size
1336			mParams->newBufferSize = newSize ;
1337
1338			// allocate a new submit params + quad storage area:
1339			UInt8* newParamsExtra = new UInt8[sizeof(CommandSubmitParams) + newSize] ;
1340
1341			DebugLogCond( !newParamsExtra, "warning: WriteQuadCmd::SetQuads: out of memory!\n" ) ;
1342
1343			// copy the old params to the new param block (which is at the beginning of ParamsExtra):
1344			bcopy(mParams, newParamsExtra+0, sizeof(*mParams)) ;
1345
1346			// delete the old storage
1347			delete[] mParamsExtra ;
1348
1349			// assign the new storage to the command object:
1350			mParams			= (CommandSubmitParams*) newParamsExtra ;
1351			mParamsExtra 	= newParamsExtra ;
1352		}
1353
1354		// copy users quads to storage area (just past end of params...)
1355		// this allows us to submit the params and quads to the kernel in one
1356		// operation
1357		bcopy(inQuads, mParams + 1, mParams->newBufferSize) ;
1358
1359		// let kernel know that buffer has changed. (but may not be strictly
1360		// necessary for write quad commands...)
1361		mParams->staleFlags |= kFireWireCommandStale_Buffer ;
1362	}
1363
1364	IOReturn
1365	WriteQuadCmd::Submit()
1366	{
1367		if (mIsExecuting)
1368			return kIOReturnBusy ;
1369
1370		CommandSubmitResult			submitResult ;
1371		mach_msg_type_number_t		submitResultSize = sizeof(submitResult) ;
1372
1373		return Cmd::Submit(mParams, sizeof(*mParams)+mParams->newBufferSize, & submitResult, & submitResultSize) ;
1374	}
1375
1376	void
1377	WriteQuadCmd::SSetQuads(
1378		CmdRef self,
1379		UInt32				inQuads[],
1380		UInt32				inNumQuads)
1381	{
1382		IOFireWireIUnknown::InterfaceMap<WriteQuadCmd>::GetThis(self)->SetQuads(inQuads, inNumQuads) ;
1383	}
1384
1385	// ============================================================
1386	//
1387	// CompareSwapCmd methods
1388	//
1389	// ============================================================
1390#pragma mark -
1391	CompareSwapCmd::CompareSwapCmd(	Device& userclient, io_object_t device, const FWAddress& addr, UInt64 cmpVal, UInt64 newVal,
1392											unsigned int quads, CommandCallback callback, bool failOnReset,
1393											UInt32 generation, void* refcon )
1394	: Cmd( reinterpret_cast<const IUnknownVTbl &>( sInterface ), userclient, device, addr, callback,
1395			failOnReset, generation, refcon,
1396			reinterpret_cast<CommandSubmitParams*>( new UInt8[sizeof(CommandSubmitParams) + sizeof(UInt64) * 2] ) ),	// 8 bytes/UInt16 * 2 values/cmd
1397	mParamsExtra( reinterpret_cast<UInt8*>(mParams) ),
1398	mInterface_v3( reinterpret_cast<const IUnknownVTbl &>( sInterface_v3 ), this )
1399	{
1400		mParams->callback		= (mach_vm_address_t)&CommandCompletionHandler;
1401		mParams->type			= kFireWireCommandType_CompareSwap ;
1402		mParams->newBufferSize 	= quads * sizeof(UInt32) ;
1403		mParams->flags			|= kFireWireCommandUseCopy ;	// compare swap always does in-line submits
1404
1405		if (quads == 1)
1406		{
1407			((UInt32*)(mParams+1))[0] = cmpVal ;
1408			((UInt32*)(mParams+1))[2] = newVal ;
1409		}
1410		else
1411		{
1412			((UInt64*)(mParams+1))[0] = cmpVal ;
1413			((UInt64*)(mParams+1))[1] = newVal ;
1414		}
1415	}
1416
1417	CompareSwapCmd::~CompareSwapCmd()
1418	{
1419		delete[] mParamsExtra ;
1420		mParamsExtra = nil ;
1421		mParams = nil ;
1422	}
1423
1424	IUnknownVTbl**
1425	CompareSwapCmd::Alloc(
1426		Device& 			userclient,
1427		io_object_t			device,
1428		const FWAddress &	addr,
1429		UInt64				cmpVal,
1430		UInt64				newVal,
1431		unsigned int		quads,
1432		CommandCallback		callback,
1433		bool				failOnReset,
1434		UInt32				generation,
1435		void*				refcon)
1436	{
1437		CompareSwapCmd*	me = new CompareSwapCmd( userclient, device, addr, cmpVal, newVal, quads,
1438														callback, failOnReset, generation, refcon ) ;
1439		if (!me)
1440			return nil ;
1441
1442		return reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
1443	}
1444
1445	HRESULT
1446	CompareSwapCmd::QueryInterface(REFIID iid, LPVOID* ppv)
1447	{
1448		HRESULT		result = S_OK ;
1449		*ppv = nil ;
1450
1451		CFUUIDRef	interfaceID	= CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
1452
1453		if ( CFEqual(interfaceID, IUnknownUUID)
1454				|| CFEqual(interfaceID, kIOFireWireCommandInterfaceID)
1455				|| CFEqual(interfaceID, kIOFireWireCompareSwapCommandInterfaceID)
1456			// v2
1457				|| CFEqual(interfaceID, kIOFireWireCompareSwapCommandInterfaceID_v2 ) )
1458		{
1459			*ppv = & GetInterface() ;
1460			AddRef() ;
1461		}
1462		else if ( CFEqual(interfaceID, kIOFireWireCompareSwapCommandInterfaceID_v3) )
1463		{
1464			*ppv = &mInterface_v3;
1465			AddRef() ;
1466		}
1467		else
1468		{
1469			*ppv = nil ;
1470			result = E_NOINTERFACE ;
1471		}
1472
1473		CFRelease(interfaceID) ;
1474		return result ;
1475	}
1476
1477	void
1478	CompareSwapCmd::SetFlags(
1479		UInt32					inFlags)
1480	{
1481		Cmd::SetFlags(inFlags) ;
1482
1483		// force always copy:
1484		mParams->flags |= kFireWireCommandUseCopy ;
1485	}
1486
1487	IOReturn
1488	CompareSwapCmd::SetMaxPacket(
1489		IOByteCount				inMaxBytes)
1490	{
1491		return kIOReturnUnsupported ;
1492	}
1493
1494	void
1495	CompareSwapCmd::SetValues(
1496		UInt32				cmpVal,
1497		UInt32				newVal)
1498	{
1499		mParams->newBufferSize = sizeof(UInt32) ;	// 1 quadlet
1500		((UInt32*)(mParams+1))[0] 	= cmpVal ;
1501		((UInt32*)(mParams+1))[2] 	= newVal ;
1502		mParams->staleFlags |= kFireWireCommandStale ;
1503	}
1504
1505	void
1506	CompareSwapCmd::SetValues(
1507		UInt64 				cmpVal,
1508		UInt64 				newVal)
1509	{
1510		mParams->newBufferSize = sizeof(UInt64) ;	// 1 quadlet
1511		((UInt64*)(mParams+1))[0] 	= cmpVal ;
1512		((UInt64*)(mParams+1))[1] 	= newVal ;
1513		mParams->staleFlags |= kFireWireCommandStale ;
1514	}
1515
1516	IOReturn
1517	CompareSwapCmd::Submit()
1518	{
1519		if (mIsExecuting)
1520			return kIOReturnBusy ;
1521
1522		IOReturn error = kIOReturnSuccess ;
1523
1524		CompareSwapSubmitResult			submitResult ;
1525		mach_msg_type_number_t			submitResultSize = sizeof(submitResult) ;
1526
1527		error = Cmd::Submit(mParams, (mach_msg_type_number_t)(sizeof(*mParams)+2*sizeof(UInt64)),
1528												reinterpret_cast<CommandSubmitResult*>(& submitResult), & submitResultSize) ;
1529
1530		if ( not error )
1531		{
1532			if( mParams->flags & kFWCommandInterfaceSyncExecute )
1533			{
1534				mStatus = submitResult.result ;
1535				mBytesTransferred = submitResult.bytesTransferred ;
1536				bcopy( & submitResult, & mSubmitResult, sizeof(mSubmitResult)) ;
1537			}
1538			else
1539				mIsExecuting = true ;
1540
1541			mParams->staleFlags = 0 ;
1542			if (!mParams->kernCommandRef)
1543				mParams->kernCommandRef = submitResult.kernCommandRef ;
1544		}
1545
1546		return error ;
1547	}
1548
1549	Boolean
1550	CompareSwapCmd::DidLock()
1551	{
1552		return mSubmitResult.lockInfo.didLock ;
1553	}
1554
1555	IOReturn
1556	CompareSwapCmd::Locked(
1557		UInt32* 			oldValue)
1558	{
1559		if (mIsExecuting)
1560			return kIOReturnBusy ;
1561		if (!mParams->kernCommandRef)
1562			return kIOReturnError ;
1563		if (mParams->newBufferSize != sizeof(UInt32))
1564			return kIOReturnBadArgument ;
1565
1566		*oldValue = mSubmitResult.lockInfo.value[0];
1567		return kIOReturnSuccess ;
1568	}
1569
1570	IOReturn
1571	CompareSwapCmd::Locked64(
1572		UInt64* 			oldValue)
1573	{
1574		if (mIsExecuting)
1575			return kIOReturnBusy ;
1576		if (!mParams->kernCommandRef)
1577			return kIOReturnError ;
1578		if (mParams->newBufferSize != sizeof(UInt64))
1579			return kIOReturnBadArgument ;
1580
1581		*oldValue = *(UInt64*)mSubmitResult.lockInfo.value;
1582		return kIOReturnSuccess ;
1583	}
1584
1585	void
1586	CompareSwapCmd::SSetValues(
1587		CmdRef				self,
1588		UInt32				cmpVal,
1589		UInt32				newVal)
1590	{
1591		IOFireWireIUnknown::InterfaceMap<CompareSwapCmd>::GetThis(self)->SetValues(cmpVal, newVal ) ;
1592	}
1593
1594	void
1595	CompareSwapCmd::SSetValues64(
1596		CmdRef			 	self,
1597		UInt64 				cmpVal,
1598		UInt64 				newVal)
1599	{
1600		IOFireWireIUnknown::InterfaceMap<CompareSwapCmd>::GetThis(self)->SetValues( cmpVal, newVal ) ;
1601	}
1602
1603	Boolean
1604	CompareSwapCmd::SDidLock(
1605		CmdRef				self)
1606	{
1607		return GetThis(self)->DidLock() ;
1608	}
1609
1610	IOReturn
1611	CompareSwapCmd::SLocked(
1612		CmdRef 				self,
1613		UInt32* 			oldValue)
1614	{
1615		return GetThis(self)->Locked(oldValue) ;
1616	}
1617
1618	IOReturn
1619	CompareSwapCmd::SLocked64(
1620		CmdRef				self,
1621		UInt64* 			oldValue)
1622	{
1623		return GetThis(self)->Locked64(oldValue) ;
1624	}
1625
1626	void
1627	CompareSwapCmd::SSetFlags( CmdRef self, UInt32 inFlags )
1628	{
1629		IOFireWireIUnknown::InterfaceMap<Cmd>::GetThis(self)->SetFlags(inFlags) ;
1630	}
1631
1632	void
1633	CompareSwapCmd::CommandCompletionHandler(
1634		void*					refcon,
1635		IOReturn				result,
1636		io_user_reference_t		quads[],
1637		UInt32					numQuads)
1638	{
1639		CompareSwapCmd * me = reinterpret_cast<CompareSwapCmd*>(refcon) ;
1640
1641	#if 0
1642		int i = 0;
1643		for( i = 0; i < 7; i++ )
1644		{
1645		#ifdef __LP64__
1646			printf( "CompareSwapCmd::CommandCompletionHandler - quads[%d] - %llx\n", i, quads[i] );
1647		#else
1648			printf( "CompareSwapCmd::CommandCompletionHandler - quads[%d] - %x\n", i, quads[i] );
1649		#endif
1650		}
1651	#endif
1652
1653		IF_ROSETTA()
1654		{
1655			#ifndef __LP64__
1656				me->mSubmitResult.result = (UserObjectHandle)OSSwapInt32((UInt32)quads[0]);
1657				me->mSubmitResult.bytesTransferred = (IOByteCount)OSSwapInt32((UInt32)quads[1]);
1658				me->mSubmitResult.ackCode = (UInt32)OSSwapInt32((UInt32)quads[2]);
1659				me->mSubmitResult.responseCode = (UserObjectHandle)OSSwapInt32((UInt32)quads[3]);
1660				me->mSubmitResult.lockInfo.didLock = (UserObjectHandle)OSSwapInt32((UInt32)quads[4]);
1661				me->mSubmitResult.lockInfo.value[0] = OSSwapInt32((UInt32)quads[5]);
1662				me->mSubmitResult.lockInfo.value[1] = OSSwapInt32((UInt32)quads[6]);
1663			#endif
1664		}
1665		else
1666		{
1667			me->mSubmitResult.result = (UserObjectHandle)quads[0];
1668			me->mSubmitResult.bytesTransferred = (IOByteCount)quads[1];
1669			me->mSubmitResult.ackCode = (UInt32)quads[2];
1670			me->mSubmitResult.responseCode = (UserObjectHandle)quads[3];
1671			me->mSubmitResult.lockInfo.didLock = (UserObjectHandle)quads[4];
1672			me->mSubmitResult.lockInfo.value[0] = (UInt32)quads[5];
1673			me->mSubmitResult.lockInfo.value[1] = (UInt32)quads[6];
1674		}
1675
1676#if 0
1677			bcopy((CompareSwapSubmitResult*)quads, & me->mSubmitResult, sizeof(me->mSubmitResult)) ;
1678
1679#ifndef __LP64__
1680		ROSETTA_ONLY(
1681			{
1682				// async results get auto swapped on 32 bit boundaries
1683				// unswap what shouldn't have been swapped
1684
1685				// no one uses kernCommandRef currently
1686				me->mSubmitResult.kernCommandRef = (UserObjectHandle)OSSwapInt32( (UInt32)me->mSubmitResult.kernCommandRef );
1687				me->mSubmitResult.lockInfo.didLock = OSSwapInt32( me->mSubmitResult.lockInfo.didLock );
1688
1689				UInt32 * value_quads = (UInt32*)&me->mSubmitResult.lockInfo.value;
1690				value_quads[0] = OSSwapInt32( value_quads[0] );
1691				value_quads[1] = OSSwapInt32( value_quads[1] );
1692			}
1693		);
1694#endif
1695#endif
1696
1697		me->mStatus 			= result ;
1698		me->mBytesTransferred	= me->mSubmitResult.bytesTransferred ;
1699		me->mAckCode			= me->mSubmitResult.ackCode;
1700		me->mResponseCode		= me->mSubmitResult.responseCode;
1701		me->mIsExecuting 		= false ;
1702
1703		if (me->mCallback)
1704			(*(me->mCallback))(me->mRefCon, me->mStatus) ;
1705
1706	}
1707
1708	// ============================================================
1709	//
1710	// AsyncStreamCmd methods
1711	//
1712	// ============================================================
1713#pragma mark -
1714	AsyncStreamCmd::AsyncStreamCmd(Device& 	userclient, UInt32 channel, UInt32 sync, UInt32 tag, void*	buf, UInt32	size, CommandCallback callback, Boolean	failOnReset, UInt32 generation, void*	inRefCon )
1715				: Cmd( reinterpret_cast<const IUnknownVTbl &>( sInterface), userclient, NULL, FWAddress(), callback, failOnReset, generation, inRefCon,
1716				reinterpret_cast<CommandSubmitParams*>(new UInt8[sizeof(CommandSubmitParams)]) )
1717	{
1718		mParams->type			= kFireWireCommandType_AsyncStream ;
1719		mParams->newBuffer		= (mach_vm_address_t)buf ;
1720		mParams->newBufferSize	= size ;
1721		mParams->staleFlags		|= kFireWireCommandStale_Buffer ;
1722		mParams->data1			= channel;
1723		mParams->tag			= tag;
1724		mParams->sync			= sync;
1725		mParams->newFailOnReset	= failOnReset;
1726	}
1727
1728	IUnknownVTbl**
1729	AsyncStreamCmd::Alloc( Device& 	userclient, UInt32 channel, UInt32 sync, UInt32 tag, void*	buf, UInt32	size, CommandCallback callback, Boolean	failOnReset, UInt32 generation, void*	inRefCon)
1730	{
1731		AsyncStreamCmd*	me = new AsyncStreamCmd( userclient, channel, sync, tag, buf, size, callback, failOnReset, generation, inRefCon ) ;
1732
1733		if (!me)
1734			return nil ;
1735
1736		return reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
1737	}
1738
1739	HRESULT
1740	AsyncStreamCmd::QueryInterface(REFIID iid, LPVOID* ppv)
1741	{
1742		HRESULT		result = S_OK ;
1743		*ppv = nil ;
1744
1745		CFUUIDRef	interfaceID	= CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
1746
1747		if ( CFEqual(interfaceID, IUnknownUUID)
1748			|| CFEqual(interfaceID, kIOFireWireCommandInterfaceID)
1749			|| CFEqual(interfaceID, kIOFireWireAsyncStreamCommandInterfaceID) )
1750		{
1751			*ppv = & GetInterface() ;
1752			AddRef() ;
1753		}
1754		else
1755		{
1756			*ppv = nil ;
1757			result = E_NOINTERFACE ;
1758		}
1759
1760		CFRelease(interfaceID) ;
1761		return result ;
1762	}
1763
1764	IOReturn
1765	AsyncStreamCmd::Submit()
1766	{
1767		if (mIsExecuting)
1768			return kIOReturnBusy ;
1769
1770		CommandSubmitResult			submitResult ;
1771		mach_msg_type_number_t		submitResultSize = sizeof(submitResult) ;
1772		UInt32						paramsSize ;
1773
1774		if (mParams->flags & kFireWireCommandUseCopy)
1775			paramsSize = sizeof(*mParams) + mParams->newBufferSize ;
1776		else
1777			paramsSize = sizeof(*mParams) ;
1778
1779		return Cmd::Submit(mParams, paramsSize, & submitResult, & submitResultSize) ;
1780	}
1781
1782	void
1783	AsyncStreamCmd::S_SetChannel( IOFireWireLibAsyncStreamCommandRef self, UInt32 channel )
1784	{
1785		AsyncStreamCmd * asyncStream_cmd = IOFireWireIUnknown::InterfaceMap<AsyncStreamCmd>::GetThis(self);
1786
1787		asyncStream_cmd->mParams->data1 = channel;
1788	}
1789
1790	void
1791	AsyncStreamCmd::S_SetSyncBits( IOFireWireLibAsyncStreamCommandRef self, UInt16 sync )
1792	{
1793		AsyncStreamCmd * asyncStream_cmd = IOFireWireIUnknown::InterfaceMap<AsyncStreamCmd>::GetThis(self);
1794
1795		asyncStream_cmd->mParams->sync = sync;
1796	}
1797
1798	void
1799	AsyncStreamCmd::S_SetTagBits( IOFireWireLibAsyncStreamCommandRef self, UInt16 tag )
1800	{
1801		AsyncStreamCmd * asyncStream_cmd = IOFireWireIUnknown::InterfaceMap<AsyncStreamCmd>::GetThis(self);
1802
1803		asyncStream_cmd->mParams->tag = tag;
1804	}
1805
1806}	// namespace IOFireWireLib
1807
1808