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 *	IOFWUserClientPsdAddrSpace.cpp
24 *	IOFireWireFamily
25 *
26 *	Created by NWG on Wed Dec 06 2000.
27 *	Copyright (c) 2000-2002 Apple, Inc. All rights reserved.
28 *
29 */
30/*
31	$Log: IOFWUserPseudoAddressSpace.cpp,v $
32	Revision 1.25  2010/05/20 22:49:43  calderon
33	Fixes issues with offset argument of pseudo address space read handler being wrong.
34
35	Revision 1.24  2009/10/16 23:59:06  calderon
36	<rdar://problem/7046489> 10A402 AsyncTester results in Error-Server verified Incorrect number of bytes
37	<rdar://problem/7111060> PanicTracer: 3 panics at IOFireWireFamily : IOFWUserPseudoAddressSpace::doPacket
38
39	And some help for:
40	<rdar://problem/7116134> PanicTracer: 3 panics at com.apple.iokit.IOFireWireFamily
41
42	Revision 1.23  2008/09/12 23:44:05  calderon
43	<rdar://5971979/> PseudoAddressSpace skips/mangles packets
44	<rdar://5708169/> FireWire synchronous commands' headerdoc missing callback info
45
46	Revision 1.22  2008/05/06 03:26:57  collin
47	more K64
48
49	Revision 1.21  2008/04/11 00:52:37  collin
50	some K64 changes
51
52	Revision 1.20  2007/02/16 19:03:43  arulchan
53	*** empty log message ***
54
55	Revision 1.19  2007/02/14 21:58:29  collin
56	*** empty log message ***
57
58	Revision 1.18  2007/02/07 06:35:20  collin
59	*** empty log message ***
60
61	Revision 1.17  2007/01/24 04:10:13  collin
62	*** empty log message ***
63
64	Revision 1.16  2007/01/18 01:07:32  collin
65	*** empty log message ***
66
67	Revision 1.15  2007/01/17 03:46:26  collin
68	*** empty log message ***
69
70	Revision 1.14  2006/12/21 21:17:44  ayanowit
71	More changes necessary to eventually get support for 64-bit apps working (4222965).
72
73	Revision 1.13  2006/12/06 00:01:07  arulchan
74	Isoch Channel 31 Generic Receiver
75
76	Revision 1.12  2005/02/18 03:19:03  niels
77	fix isight
78
79	Revision 1.11  2003/09/20 00:54:17  collin
80	*** empty log message ***
81
82	Revision 1.10  2003/08/30 00:16:44  collin
83	*** empty log message ***
84
85	Revision 1.9  2003/08/20 23:33:37  niels
86	*** empty log message ***
87
88	Revision 1.8  2003/08/19 01:48:54  niels
89	*** empty log message ***
90
91	Revision 1.7  2003/07/24 06:30:58  collin
92	*** empty log message ***
93
94	Revision 1.6  2003/07/21 06:52:59  niels
95	merge isoch to TOT
96
97	Revision 1.4.4.2  2003/07/21 06:44:44  niels
98	*** empty log message ***
99
100	Revision 1.4.4.1  2003/07/01 20:54:07  niels
101	isoch merge
102
103	Revision 1.4  2003/04/18 20:32:06  collin
104	*** empty log message ***
105
106	Revision 1.3  2002/10/22 00:34:25  collin
107	fix user space lock transactions, publish GUID = 0 property in objects in the IOFireWire plane
108
109	Revision 1.2  2002/10/18 23:29:43  collin
110	fix includes, fix cast which fails on new compiler
111
112	Revision 1.1  2002/09/25 00:27:22  niels
113	flip your world upside-down
114
115	Revision 1.21  2002/08/06 21:10:06  wgulland
116	Add IOfireWireBus::isCompleteRequest(reqrefcon)
117
118	Revision 1.20  2002/08/06 19:44:57  niels
119	*** empty log message ***
120
121	Revision 1.19  2002/08/06 19:42:54  niels
122	now send conflict response if user pseudo address space can't receive a write because the queue is full in cases where the hardware has not already responded 'ack complete'
123
124*/
125
126#ifndef __IOFWUserClientPseuAddrSpace_H__
127#define __IOFWUserClientPseuAddrSpace_H__
128
129#import <IOKit/firewire/IOFireWireNub.h>
130#import <IOKit/firewire/IOFireWireController.h>
131//#import <IOKit/firewire/FireLog.h>
132
133// protected
134#import <IOKit/firewire/IOFireWireLink.h>
135
136// private
137#import "IOFireWireUserClient.h"
138#import "IOFireWireLib.h"
139#import "IOFWUserPseudoAddressSpace.h"
140#import "IOFWRingBufferQ.h"
141
142// system
143#import <IOKit/assert.h>
144#import <IOKit/IOLib.h>
145#import <IOKit/IOWorkLoop.h>
146#import <IOKit/IOTypes.h>
147#import <IOKit/IOMessage.h>
148#import <IOKit/IOUserClient.h>
149
150// ============================================================
151//
152// IOFWPacketHeader
153//
154// ============================================================
155
156IOFWPacketHeader_t::IOFWPacketHeader_t()
157{
158	CommonHeader.type			= IOFWPacketHeader::kFree ;
159	CommonHeader.next			= this ;
160	IOFWPacketHeaderGetSize(this)	= 0 ;
161	IOFWPacketHeaderGetOffset(this) = 0 ;
162}
163
164io_user_reference_t& IOFWPacketHeaderGetSize(IOFWPacketHeader_t* hdr)
165{
166	if( hdr->CommonHeader.type == IOFWPacketHeader::kSkippedPacket )
167		return hdr->CommonHeader.headerSize;
168	else
169		return hdr->CommonHeader.args[1] ;
170}
171
172io_user_reference_t& IOFWPacketHeaderGetOffset(IOFWPacketHeader_t* hdr)
173{
174	if( hdr->CommonHeader.type == IOFWPacketHeader::kSkippedPacket )
175		return hdr->CommonHeader.headerOffset;
176	else
177		return hdr->CommonHeader.args[2] ;
178}
179
180void InitIncomingPacketHeader(
181	IOFWPacketHeader_t*				header,
182	IOFWPacketHeader_t*				next,
183	const IOByteCount				len,
184	const IOByteCount				offset,
185	OSAsyncReference64*				ref,
186	UInt16							nodeID,
187	const IOFWSpeed&   				speed,
188	const FWAddress&				addr,
189	const bool						isLock)
190{
191	header->CommonHeader.type				= IOFWPacketHeader::kIncomingPacket ;
192	header->CommonHeader.next				= next ;
193	IOFWPacketHeaderGetSize(header)			= len ;
194	IOFWPacketHeaderGetOffset(header)		= offset ;
195	header->CommonHeader.whichAsyncRef		= ref ;
196	header->CommonHeader.argCount			= 8;
197
198	header->IncomingPacket.commandID		= (io_user_reference_t) header ;
199	header->IncomingPacket.nodeID			= nodeID ;
200	header->IncomingPacket.speed			= speed ;
201	header->IncomingPacket.addrHi			= addr.addressHi;
202	header->IncomingPacket.addrLo			= addr.addressLo;
203	header->IncomingPacket.isLock			= isLock ;
204}
205
206void InitSkippedPacketHeader(
207	IOFWPacketHeader*				header,
208	IOFWPacketHeader*				next,
209	const IOByteCount				offset,
210	OSAsyncReference64*				ref)
211{
212	header->CommonHeader.type 				= IOFWPacketHeader::kSkippedPacket ;
213	header->CommonHeader.next				= next ;
214	IOFWPacketHeaderGetSize(header)			= 0;
215	IOFWPacketHeaderGetOffset(header)		= offset ;
216	header->CommonHeader.whichAsyncRef		= ref ;
217	header->CommonHeader.argCount			= 2;
218
219	header->SkippedPacket.commandID			= (io_user_reference_t) header ;
220	header->SkippedPacket.skippedPacketCount= 1;
221}
222
223void InitReadPacketHeader(
224	IOFWPacketHeader*				header,
225	IOFWPacketHeader*				next,
226	IOByteCount						len,
227	IOByteCount						offset,
228	OSAsyncReference64*				ref,
229	IOFWRequestRefCon				reqrefcon,
230	UInt16							nodeID,
231	IOFWSpeed&						speed,
232	FWAddress						addr,
233	UInt32							generation)
234{
235	header->CommonHeader.type			= IOFWPacketHeader::kReadPacket ;
236	header->CommonHeader.next			= next ;
237	IOFWPacketHeaderGetSize(header)		= len ;
238	IOFWPacketHeaderGetOffset(header)	= offset ;
239	header->CommonHeader.whichAsyncRef	= ref ;
240	header->CommonHeader.argCount		= 7 ;
241
242	header->ReadPacket.commandID		= (io_user_reference_t) header ;
243	header->ReadPacket.nodeID			= nodeID ;
244	header->ReadPacket.speed			= speed ;
245	header->ReadPacket.addrHi   		= addr.addressHi ;
246	header->ReadPacket.addrLo			= addr.addressLo ;
247	header->ReadPacket.reqrefcon		= (io_user_reference_t)reqrefcon ;
248	header->ReadPacket.generation		= generation ;
249}
250
251void InitLockPacketHeader(
252	IOFWPacketHeader*				header,
253	IOFWPacketHeader*				next,
254	IOByteCount						len,
255	IOByteCount						offset,
256	OSAsyncReference64*				ref,
257	UInt16							nodeID,
258	IOFWSpeed&						speed,
259	FWAddress						addr,
260	const UInt32					generation,
261	IOFWRequestRefCon				reqrefcon)
262{
263	InitIncomingPacketHeader( header, next, len, offset, ref, nodeID, speed, addr, true ) ;
264	header->IncomingPacket.type			= IOFWPacketHeader::kLockPacket ;
265	header->IncomingPacket.generation	= generation ;
266	header->IncomingPacket.reqrefcon 	= (io_user_reference_t)reqrefcon;
267}
268
269Boolean IsSkippedPacketHeader(
270	IOFWPacketHeader*				header)
271{
272	return header->CommonHeader.type == IOFWPacketHeader::kSkippedPacket ;
273}
274
275Boolean IsFreePacketHeader(
276	IOFWPacketHeader*				header)
277{
278	return header->CommonHeader.type == IOFWPacketHeader::kFree ;
279}
280
281// ============================================================
282//	IOFWUserPseudoAddressSpace methods
283// ============================================================
284
285OSDefineMetaClassAndStructors( IOFWUserPseudoAddressSpace, IOFWPseudoAddressSpace ) ;
286
287#if IOFIREWIREUSERCLIENTDEBUG > 0
288
289bool
290IOFWUserPseudoAddressSpace::serialize(OSSerialize *s) const
291{
292	if (s->previouslySerialized(this))
293		return true ;
294
295	char temp[256] ;
296
297	snprintf(temp, sizeof(temp), "addr=%x:%08x", fAddress.addressHi, (uint32_t)fAddress.addressLo) ;
298
299#ifdef __LP64__
300	snprintf(temp+strlen(temp), sizeof(temp), ", backing-store-bytes=%llud",
301			fDesc ? fDesc->getLength() : 0) ;
302#else
303	snprintf(temp+strlen(temp), sizeof(temp), ", backing-store-bytes=%lud",
304			 fDesc ? fDesc->getLength() : 0) ;
305#endif
306
307	if ( fFlags )
308	{
309		snprintf(temp+strlen(temp), sizeof(temp), ", flags:") ;
310		if (fFlags & kFWAddressSpaceNoWriteAccess)
311			snprintf(temp+strlen(temp), sizeof(temp), " no-write") ;
312		if (fFlags & kFWAddressSpaceNoReadAccess)
313			snprintf(temp+strlen(temp), sizeof(temp), " no-read") ;
314		if (fFlags & kFWAddressSpaceAutoWriteReply)
315			snprintf(temp+strlen(temp), sizeof(temp), " auto-write") ;
316		if (fFlags & kFWAddressSpaceAutoReadReply)
317			snprintf(temp+strlen(temp), sizeof(temp), " auto-read") ;
318		if (fFlags & kFWAddressSpaceAutoCopyOnWrite)
319			snprintf(temp+strlen(temp), sizeof(temp), " copy-on-write") ;
320		if (fFlags & kFWAddressSpaceShareIfExists)
321			snprintf(temp+strlen(temp), sizeof(temp), " shared") ;
322		if (fFlags & kFWAddressSpaceExclusive)
323			snprintf(temp+strlen(temp), sizeof(temp), " exclusive") ;
324	}
325	else
326	{
327		snprintf(temp+strlen(temp), sizeof(temp), ", no flags") ;
328	}
329
330	OSString*	string = OSString::withCString(temp) ;
331	if (!string)
332		return false ;
333
334	bool result =  string->serialize(s) ;
335	string->release() ;
336
337	return result ;
338}
339
340#endif
341
342void
343IOFWUserPseudoAddressSpace::free()
344{
345	if ( fPacketQueue )
346	{
347		fPacketQueue->release();
348		fPacketQueue = NULL;
349	}
350
351	if ( fBackingStorePrepared )
352		fDesc->complete() ;
353
354	delete fLastWrittenHeader ;
355
356	if( fLock )
357	{
358		IOLockFree( fLock );
359		fLock = NULL;
360	}
361
362	IOFWPseudoAddressSpace::free() ;
363}
364
365// exporterCleanup
366//
367//
368
369void
370IOFWUserPseudoAddressSpace::exporterCleanup( const OSObject * self )
371{
372	IOFWUserPseudoAddressSpace * me = (IOFWUserPseudoAddressSpace*)self;
373
374	DebugLog("IOFWUserPseudoAddressSpace::exporterCleanup\n");
375
376	me->deactivate();
377}
378
379void
380IOFWUserPseudoAddressSpace::deactivate()
381{
382	IOFWPseudoAddressSpace::deactivate() ;
383
384	IOLockLock(fLock) ;
385
386	fLastReadHeader = NULL ;
387
388	IOFWPacketHeader*	firstHeader = fLastWrittenHeader ;
389	IOFWPacketHeader*	tempHeader ;
390
391	if (fLastWrittenHeader)
392	{
393		while (fLastWrittenHeader->CommonHeader.next != firstHeader)
394		{
395			tempHeader = fLastWrittenHeader->CommonHeader.next ;
396			delete fLastWrittenHeader ;
397			fLastWrittenHeader = tempHeader ;
398		}
399
400	}
401
402	if ( fBackingStorePrepared )
403	{
404		fDesc->complete() ;
405		fBackingStorePrepared = false ;
406	}
407
408	fWaitingForUserCompletion = false ;
409
410	IOLockUnlock(fLock) ;
411}
412
413bool
414IOFWUserPseudoAddressSpace::completeInit( IOFireWireUserClient* userclient, AddressSpaceCreateParams* params )
415{
416	Boolean	status = true ;
417
418	fUserRefCon					= params->refCon ;
419	fFlags						= params->flags ;
420	fWaitingForUserCompletion	= false ;
421
422	// set user client
423	fUserClient = userclient ;
424
425	// see if user specified a packet queue and queue size
426	if ( !params->queueBuffer && ( !(fFlags & kFWAddressSpaceAutoWriteReply) || !(fFlags & kFWAddressSpaceAutoReadReply) ) )
427	{
428		DebugLog("IOFWUserPseudoAddressSpace::initAll: address space without queue buffer must have both auto-write and auto-read set\n") ;
429		status = false ;
430	}
431
432	// make packet queue
433	if ( status )
434	{
435		if ( params->queueBuffer )
436		{
437			fPacketQueue = IOFWRingBufferQ::withAddressRange( params->queueBuffer, params->queueSize, kIODirectionOutIn, fUserClient->getOwningTask() ) ;
438
439			if ( !fPacketQueue )
440			{
441				DebugLog("%s %u: couldn't make fPacketQueue memory descriptor\n", __FILE__, __LINE__) ;
442				status = false ;
443			}
444			else
445			{
446				fPacketQueuePrepared = status ;
447			}
448		}
449	}
450
451	if ( status )
452	{
453		// init the easy vars
454		fLastReadHeader 			= new IOFWPacketHeader ;
455		fLastWrittenHeader			= fLastReadHeader ;
456		bzero(fLastWrittenHeader, sizeof(fLastWrittenHeader));
457
458		// get a lock for the packet queue
459		fLock = IOLockAlloc() ;
460
461		if ( !fLock )
462		{
463			DebugLog("%s %u: couldn't allocate lock\n", __FILE__, __LINE__) ;
464			status = false ;
465		}
466	}
467
468	// get a backing store if needed
469	if ( status )
470		if ( NULL != params->backingStore )
471		{
472			// Note: even though the memory descriptor is created with the size of the address space,
473			// rather than the size of the backingstore, this creation should fail if the size is outside
474			// of the task's allocation. Any bad read or writes will only affect the task. Furthermore,
475			// the backingstore is required to be the same size as the address space, per documentation.
476			fDesc = IOMemoryDescriptor::withAddressRange(	params->backingStore,
477															params->size,
478															kIODirectionOutIn,
479															userclient->getOwningTask() ) ;
480			if (!fDesc)
481			{
482				DebugLog("%s %u: failed to make backing store memory descriptor\n", __FILE__, __LINE__) ;
483				status = false ;
484			}
485
486			if ( status )
487				status = ( kIOReturnSuccess == fDesc->prepare() ) ;
488
489			fBackingStorePrepared = status ;
490		}
491
492	// set reader and writer callbacks based on access flags and user callback flags
493	if (status)
494	{
495		if (!(params->flags & kFWAddressSpaceNoWriteAccess))
496		{
497			if (params->flags & kFWAddressSpaceAutoWriteReply)
498			{
499				if (params->backingStore)
500					fWriter = & IOFWUserPseudoAddressSpace::simpleWriter ;
501				else
502				{	// this macro needs braces
503					DebugLog("IOFireWireUserClient::allocateAddressSpace(): can't create auto-write address space w/o backing store!\n") ;
504				}
505			}
506			else
507			{
508				fWriter = & IOFWUserPseudoAddressSpace::pseudoAddrSpaceWriter ;
509				fUserLocks = true ;
510			}
511		}
512
513		if (!(params->flags & kFWAddressSpaceNoReadAccess))
514		{
515			if (params->flags & kFWAddressSpaceAutoReadReply)
516			{
517				if (params->backingStore)
518					fReader = & IOFWUserPseudoAddressSpace::simpleReader ;
519				else
520				{	// this macro needs braces
521					DebugLog("IOFireWireUserClient::allocateAddressSpace(): can't create auto-read address space w/o backing store!\n") ;
522				}
523			}
524			else
525			{
526				fReader = & IOFWUserPseudoAddressSpace::pseudoAddrSpaceReader ;
527				fUserLocks &= true ;	// &=, only set to true if true already
528			}
529		}
530
531	}
532
533	return status ;
534}
535
536bool
537IOFWUserPseudoAddressSpace::initPseudo(
538	IOFireWireUserClient*		userclient,
539	IOFireWireLib::AddressSpaceCreateParams* 	params)
540{
541	if ( !IOFWPseudoAddressSpace::initAll( userclient->getOwner()->getController(), & fAddress, params->size, NULL, NULL, this ))
542	{
543		DebugLog("IOFWUserPseudoAddressSpace::initPseudo: IOFWPseudoAddressSpace::initAll failed\n") ;
544		return false ;
545	}
546
547	bool result = completeInit( userclient, params ) ;
548
549	return result ;
550}
551
552bool
553IOFWUserPseudoAddressSpace::initFixed(
554	IOFireWireUserClient*		userclient,
555	IOFireWireLib::AddressSpaceCreateParams*	params )
556{
557	IOFWAddressSpace*	addrSpace = userclient->getOwner()->getController()->getAddressSpace( FWAddress( kCSRRegisterSpaceBaseAddressHi, params->addressLo ) ) ;
558
559	fAddress = FWAddress( kCSRRegisterSpaceBaseAddressHi, params->addressLo ) ;
560
561	if ( addrSpace && !(params->flags & kFWAddressSpaceShareIfExists ) )
562		return false ;
563
564	if ( !IOFWPseudoAddressSpace::initFixed( userclient->getOwner()->getController(), fAddress, params->size, NULL, NULL, this ))
565		return false ;
566
567	// mark this address space as exclusve
568	// it will fail in activate if there's a conflict
569	if( params->flags & kFWAddressSpaceExclusive )
570	{
571		setExclusive( true );
572	}
573
574	return completeInit( userclient, params ) ;
575}
576
577UInt32 IOFWUserPseudoAddressSpace::doLock(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 inLen,
578                        const UInt32 *newVal, UInt32 &outLen, UInt32 *oldVal, UInt32 type,
579                          IOFWRequestRefCon refcon)
580{
581	if ( fUserLocks )
582	{
583	    if(addr.addressHi != fBase.addressHi)
584			return kFWResponseAddressError;
585		if(addr.addressLo < fBase.addressLo)
586			return kFWResponseAddressError;
587		if(addr.addressLo + inLen > fBase.addressLo+fLen)
588			return kFWResponseAddressError;
589		if(!fReader)
590			return kFWResponseTypeError;
591
592		return doPacket( nodeID, speed, addr, inLen, newVal, refcon, IOFWPacketHeader::kLockPacket, oldVal ) ;
593	}
594
595	return IOFWPseudoAddressSpace::doLock( nodeID, speed, addr, inLen, newVal, outLen, oldVal, type, refcon ) ;
596}
597
598UInt32
599IOFWUserPseudoAddressSpace::doPacket(
600	UInt16							nodeID,
601	IOFWSpeed&						speed,
602	FWAddress						addr,
603	UInt32							len,
604	const void*						buf,
605	IOFWRequestRefCon				reqrefcon,
606	IOFWPacketHeader::QueueTag		tag,
607	UInt32*							oldVal)	// oldVal only used in lock case
608{
609	IOByteCount		destOffset	= 0 ;
610	bool			skip		= false ;
611	UInt32			response	= kFWResponseComplete ;
612
613	IOLockLock(fLock) ;
614
615	// Process:
616	// 1. Is there enough space in queue for packet payload?
617	// 2. No? Create/reuse skip packet header, init, and notify
618	// 3. Create/reuse packet header
619	// 4. Init packet header
620	// 5. Write packet payload to queue
621	// 6. Send notification of next packet ???
622	// ...
623	// 7. When client complete, mark header free and send notification for next packet ???
624
625	DebugLog("doPacket\n");
626
627	if ( !fPacketQueue ) DebugLog("\tdP fPacketQueue is invalid!\n");
628
629	if ( tag == IOFWPacketHeader::kIncomingPacket || tag == IOFWPacketHeader::kLockPacket ) {
630		skip = !(fPacketQueue->isSpaceAvailable(len, &destOffset));
631	}
632
633	DebugLog("\tdP Packet will %s fit. Length: %lu Available: %lu Payload: 0x%lx\n", skip ? "NOT" : " ", len, fPacketQueue->spaceAvailable(), *((UInt32 *)buf));
634
635	IOFWPacketHeader * currentHeader = fLastWrittenHeader;
636
637	IOFireWireNub * owner = NULL;
638	IOFireWireController * controller = NULL;
639	if ( fUserClient )
640	{
641		owner = fUserClient->getOwner();
642		if ( owner )
643			controller = owner->getController();
644	}
645
646	if ( !controller )
647	{
648		// userclient is terminating?
649		response = kFWResponseAddressError;
650	}
651	else
652	{
653		if ( skip )
654		{
655			// create a skipped packet header if last one wasn't a skipped pkt,
656			// otherwise, bump count and reuse header
657
658			if (IsSkippedPacketHeader(fLastWrittenHeader))
659				++(fLastWrittenHeader->SkippedPacket.skippedPacketCount) ;
660			else
661			{
662				if (!IsFreePacketHeader(fLastWrittenHeader))
663				{
664					if ( !IsFreePacketHeader(fLastWrittenHeader->CommonHeader.next) )
665					{
666						IOFWPacketHeader*	newHeader = new IOFWPacketHeader ;
667						newHeader->CommonHeader.next = fLastWrittenHeader->CommonHeader.next ;
668						fLastWrittenHeader->CommonHeader.next = newHeader ;
669					}
670
671					currentHeader = fLastWrittenHeader->CommonHeader.next ;
672
673				}
674
675				InitSkippedPacketHeader(
676						currentHeader,
677						currentHeader->CommonHeader.next,
678						destOffset,
679						& fSkippedPacketAsyncNotificationRef ) ;
680
681				fLastWrittenHeader = currentHeader ;
682			}
683
684			// if we can't handle the packet, and the hardware hasn't already responded,
685			// send kFWResponseConflictError
686			if ( ! controller->isCompleteRequest( reqrefcon ) )
687				response = kFWResponseConflictError ;
688		}
689		else
690		{
691			if (!IsFreePacketHeader(fLastWrittenHeader))
692			{
693				if ( !IsFreePacketHeader(fLastWrittenHeader->CommonHeader.next) )
694				{
695					IOFWPacketHeader*	newHeader		= new IOFWPacketHeader ;
696					newHeader->CommonHeader.next		= fLastWrittenHeader->CommonHeader.next ;
697					fLastWrittenHeader->CommonHeader.next	= newHeader ;
698				}
699
700			}
701
702			currentHeader = fLastWrittenHeader->CommonHeader.next ;
703			bool enqueued = false;
704
705			switch(tag)
706			{
707				case IOFWPacketHeader::kIncomingPacket:
708					// save info in header
709					InitIncomingPacketHeader(
710							currentHeader,
711							currentHeader->CommonHeader.next,
712							len,
713							destOffset,
714							& fPacketAsyncNotificationRef,
715							nodeID,
716							speed,
717							addr) ;
718
719					// zzz this write should probably be eliminated when kFWAddressSpaceAutoCopyOnWrite is set..
720					enqueued = fPacketQueue->enqueueBytes((void *)buf, len);
721
722					DebugLog("\tdP Write: Copy cmd ID: 0x%llx %s\n", currentHeader->IncomingPacket.commandID, enqueued ? "succeeded" : "failed");
723
724					break ;
725
726				case IOFWPacketHeader::kLockPacket:
727
728					// save info in header
729					InitLockPacketHeader(
730								currentHeader,
731								currentHeader->CommonHeader.next,
732								len,
733								destOffset,
734								& fPacketAsyncNotificationRef,
735								nodeID,
736								speed,
737								addr,
738								controller->getGeneration(),
739								reqrefcon ) ;
740
741					// copy data to queue
742					enqueued = fPacketQueue->enqueueBytes((void *)buf, len);
743					response = kFWResponsePending ;
744
745					DebugLog("\tdP Lock: Copy cmd ID: 0x%llx %s\n", currentHeader->IncomingPacket.commandID, enqueued ? "succeeded" : "failed");
746
747					break ;
748
749				case IOFWPacketHeader::kReadPacket:
750
751					InitReadPacketHeader(
752										 currentHeader,
753										 currentHeader->CommonHeader.next,
754										 len,
755										 addr.addressLo - fAddress.addressLo,
756										 & fReadAsyncNotificationRef,
757										 reqrefcon,
758										 nodeID,
759										 speed,
760										 addr,
761										 controller->getGeneration() ) ;
762
763					response = kFWResponsePending ;
764
765					DebugLog("\tdP Read: Proces cmd ID: 0x%llx\n", currentHeader->IncomingPacket.commandID);
766
767					break ;
768
769				default:
770					ErrorLog("%s %u: internal error: doPacket called with improper type\n", __FILE__, __LINE__) ;
771					break ;
772			}
773
774			fLastWrittenHeader = currentHeader ;
775		}
776
777		if( currentHeader->CommonHeader.type != IOFWPacketHeader::kFree )
778			sendPacketNotification(currentHeader) ;
779	}
780
781	IOLockUnlock(fLock) ;
782
783	return response ;
784}
785
786UInt32
787IOFWUserPseudoAddressSpace::pseudoAddrSpaceReader(
788	void*					refCon,
789	UInt16					nodeID,
790	IOFWSpeed&				speed,
791	FWAddress				addr,
792	UInt32					len,
793	IOMemoryDescriptor**	buf,
794	IOByteCount*			outOffset,
795	IOFWRequestRefCon		reqrefcon)
796{
797	IOFWUserPseudoAddressSpace*	me = (IOFWUserPseudoAddressSpace*)refCon ;
798
799	if ( 0 == me->fReadAsyncNotificationRef[0] )
800		return kFWResponseTypeError ;
801
802	return me->doPacket( nodeID, speed, addr, len, buf, reqrefcon, IOFWPacketHeader::kReadPacket) ;
803}
804
805UInt32
806IOFWUserPseudoAddressSpace::pseudoAddrSpaceWriter(
807	void*					refCon,
808	UInt16					nodeID,
809	IOFWSpeed&				speed,
810	FWAddress				addr,
811	UInt32					len,
812	const void*				buf,
813	IOFWRequestRefCon		reqrefcon)
814{
815	IOFWUserPseudoAddressSpace*	me = (IOFWUserPseudoAddressSpace*)refCon ;
816
817	return me->doPacket( nodeID, speed, addr, len, buf, reqrefcon, IOFWPacketHeader::kIncomingPacket ) ;
818}
819
820void
821IOFWUserPseudoAddressSpace::setAsyncRef_Packet(
822	OSAsyncReference64	asyncRef)
823{
824	bcopy(asyncRef, fPacketAsyncNotificationRef, sizeof(OSAsyncReference64)) ;
825}
826
827void
828IOFWUserPseudoAddressSpace::setAsyncRef_SkippedPacket(
829	OSAsyncReference64	asyncRef)
830{
831	bcopy(asyncRef, fSkippedPacketAsyncNotificationRef, sizeof(OSAsyncReference64)) ;
832}
833
834void
835IOFWUserPseudoAddressSpace::setAsyncRef_Read(
836	OSAsyncReference64	asyncRef)
837{
838	bcopy(asyncRef, fReadAsyncNotificationRef, sizeof(OSAsyncReference64)) ;
839}
840
841void
842IOFWUserPseudoAddressSpace::clientCommandIsComplete(
843	FWClientCommandID 	inCommandID,
844	IOReturn			inResult)
845{
846	IOLockLock(fLock) ;
847
848	if ( fWaitingForUserCompletion )
849	{
850		IOFWPacketHeader*			oldHeader 	= fLastReadHeader ;
851		IOFWPacketHeader::QueueTag	type 		= oldHeader->CommonHeader.type ;
852		fLastReadHeader = fLastReadHeader->CommonHeader.next ;
853
854		DebugLog("Cplt cmdID: 0x%llx\n", oldHeader->IncomingPacket.commandID);
855
856		switch(type)
857		{
858			case IOFWPacketHeader::kLockPacket:
859			{
860				DebugLog("\tCplt lock\n");
861				fUserClient->getOwner()->getController()->asyncLockResponse( oldHeader->IncomingPacket.generation,
862																			oldHeader->IncomingPacket.nodeID,
863																			oldHeader->IncomingPacket.speed,
864																			fDesc,//fBackingStore
865																			oldHeader->IncomingPacket.addrLo - fAddress.addressLo,
866																			oldHeader->IncomingPacket.packetSize >> 1,
867																			(void*)oldHeader->IncomingPacket.reqrefcon ) ;
868			}
869			// fall through
870
871			case IOFWPacketHeader::kIncomingPacket:
872			{
873				DebugLog("\tCplt write\n");
874				fPacketQueue->dequeueBytes(oldHeader->IncomingPacket.packetSize);
875				break ;
876			}
877
878			case IOFWPacketHeader::kReadPacket:
879			{
880				DebugLog("\tCplt read\n");
881                    fUserClient->getOwner()->getController()->asyncReadResponse( oldHeader->ReadPacket.generation,
882                                                                                oldHeader->ReadPacket.nodeID,
883                                                                                oldHeader->ReadPacket.speed,
884                                                                                fDesc,//fBackingStore
885                                                                                oldHeader->ReadPacket.addrLo - fAddress.addressLo,
886                                                                                oldHeader->ReadPacket.packetSize,
887                                                                                (void*)oldHeader->ReadPacket.reqrefcon ) ;
888				break;
889			}
890
891			default:
892				// nothing...
893				DebugLog("\tCplt type %u\n", type);
894				break ;
895		}
896
897		oldHeader->CommonHeader.type = IOFWPacketHeader::kFree ;
898		fWaitingForUserCompletion = false ;
899
900		// send *next* packet notification
901		if ( fLastReadHeader->CommonHeader.type != IOFWPacketHeader::kFree )
902		{
903			DebugLog("\tCplt sending next packet notification\n");
904			sendPacketNotification(fLastReadHeader) ;
905		}
906	}
907
908	IOLockUnlock(fLock) ;
909}
910
911void
912IOFWUserPseudoAddressSpace::sendPacketNotification(
913	IOFWPacketHeader*	inPacketHeader)
914{
915	if (!fWaitingForUserCompletion)
916	{
917		if ( inPacketHeader->CommonHeader.type == IOFWPacketHeader::kIncomingPacket and (fFlags & kFWAddressSpaceAutoCopyOnWrite) != 0 )
918		{
919			IOByteCount len = IOFWPacketHeaderGetSize(inPacketHeader) ;
920			void * bytes = IOMalloc( len );
921
922			fPacketQueue->readBytes( IOFWPacketHeaderGetOffset( inPacketHeader ), bytes, len );
923
924			fDesc->writeBytes(	inPacketHeader->IncomingPacket.addrLo - fAddress.addressLo,
925								bytes,
926								len ) ;
927
928			IOFree( bytes, len );
929		}
930
931		if (inPacketHeader->CommonHeader.whichAsyncRef[0])
932		{
933			DebugLog("sPN cmdID 0x%llx\n", inPacketHeader->IncomingPacket.commandID);
934			#if 0	// debug logging
935			io_user_reference_t hdrSize = IOFWPacketHeaderGetSize(inPacketHeader);
936			io_user_reference_t hdrOffset = IOFWPacketHeaderGetOffset(inPacketHeader);
937			FireLog("\tsPN hdr: %p off %llu size %llu %s\n", inPacketHeader, hdrOffset, hdrSize, inPacketHeader->CommonHeader.type == IOFWPacketHeader::kSkippedPacket ? "SkippedPkt" : "");
938
939			IOByteCount len = IOFWPacketHeaderGetSize(inPacketHeader) ;
940			void * bytes = IOMalloc( len );
941
942			if ( inPacketHeader->CommonHeader.type == IOFWPacketHeader::kIncomingPacket || inPacketHeader->CommonHeader.type == IOFWPacketHeader::kLockPacket )
943			{
944				fPacketQueue->readBytes( IOFWPacketHeaderGetOffset( inPacketHeader ), bytes, len );
945				FireLog("\tsPN %lu 0x%x\n", len, *((UInt32 *)bytes));
946			}
947
948			IOFree( bytes, len );
949			#endif
950
951			IOFireWireUserClient::sendAsyncResult64(*(inPacketHeader->CommonHeader.whichAsyncRef),
952							kIOReturnSuccess,
953							(io_user_reference_t*)inPacketHeader->CommonHeader.args,
954							inPacketHeader->CommonHeader.argCount) ;
955			fWaitingForUserCompletion = true ;
956		}
957	}
958}
959
960#endif //__IOFWUserClientPseuAddrSpace_H__
961