1/*
2 * Copyright (c) 1998-2002 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//#define IOASSERT 1	// Set to 1 to activate assert()
24
25// public
26#include <IOKit/firewire/IOFWCommand.h>
27#include <IOKit/firewire/IOFireWireController.h>
28#include <IOKit/firewire/IOFireWireNub.h>
29#include <IOKit/firewire/IOLocalConfigDirectory.h>
30
31// system
32#include <IOKit/assert.h>
33#include <IOKit/IOWorkLoop.h>
34#include <IOKit/IOCommand.h>
35
36#pragma mark -
37
38OSDefineMetaClassAndStructors(IOFWAsyncStreamCommand, IOFWCommand)
39OSMetaClassDefineReservedUnused(IOFWAsyncStreamCommand, 0);
40OSMetaClassDefineReservedUnused(IOFWAsyncStreamCommand, 1);
41
42#pragma mark -
43
44// initAll
45//
46//
47
48bool IOFWAsyncStreamCommand::initAll(
49    							IOFireWireController 	* control,
50                                UInt32 					generation,
51                                UInt32 					channel,
52                                UInt32 					sync,
53                                UInt32 					tag,
54                                IOMemoryDescriptor 		* hostMem,
55                                UInt32					size,
56                                int						speed,
57                                FWAsyncStreamCallback 	completion,
58                                void 					* refcon)
59{
60	return initAll( control, generation, channel, sync, tag, hostMem, size, speed, completion, refcon, false);
61}
62
63bool IOFWAsyncStreamCommand::initAll(
64    							IOFireWireController 	* control,
65                                UInt32 					generation,
66                                UInt32 					channel,
67                                UInt32 					sync,
68                                UInt32 					tag,
69                                IOMemoryDescriptor 		* hostMem,
70                                UInt32					size,
71                                int						speed,
72                                FWAsyncStreamCallback 	completion,
73                                void 					* refcon,
74								bool					failOnReset)
75{
76	bool success = true;
77
78	success = IOFWCommand::initWithController(control);
79
80	if( success )
81	{
82		fMaxRetries = kFWCmdDefaultRetries;
83		fCurRetries = fMaxRetries;
84		fMemDesc = hostMem;
85		fComplete = completion;
86		fSync = completion == NULL;
87		fRefCon = refcon;
88		fTimeout = 1000*125;	// 1000 frames, 125mSec
89		if(hostMem)
90			fSize = hostMem->getLength();
91
92		fGeneration = generation;
93		fChannel = channel;
94		fSyncBits = sync;
95		fTag = tag;
96		fSpeed = speed;
97		fSize = size;
98		fFailOnReset = failOnReset;
99    }
100
101	return success;
102}
103
104
105// free
106//
107//
108
109void IOFWAsyncStreamCommand::free()
110{
111	IOFWCommand::free();
112}
113
114
115// reinit
116//
117//
118
119IOReturn IOFWAsyncStreamCommand::reinit(
120								UInt32 					generation,
121                                UInt32 					channel,
122                                UInt32 					sync,
123                                UInt32 					tag,
124                                IOMemoryDescriptor 		* hostMem,
125                                UInt32					size,
126                                int						speed,
127                                FWAsyncStreamCallback 	completion,
128                                void 					* refcon)
129{
130    if(fStatus == kIOReturnBusy || fStatus == kIOFireWirePending)
131	return fStatus;
132
133    fComplete = completion;
134    fRefCon = refcon;
135    fMemDesc=hostMem;
136    if(fMemDesc)
137        fSize=fMemDesc->getLength();
138    fSync = completion == NULL;
139    fCurRetries = fMaxRetries;
140
141    fGeneration = generation;
142    fChannel = channel;
143    fSyncBits = sync;
144    fTag = tag;
145    fSpeed = speed;
146    fSize = size;
147    return fStatus = kIOReturnSuccess;
148}
149
150IOReturn IOFWAsyncStreamCommand::reinit(
151								UInt32 					generation,
152                                UInt32 					channel,
153                                UInt32 					sync,
154                                UInt32 					tag,
155                                IOMemoryDescriptor 		* hostMem,
156                                UInt32					size,
157                                int						speed,
158                                FWAsyncStreamCallback 	completion,
159                                void 					* refcon,
160								bool					failOnReset)
161{
162	if(fStatus == kIOReturnBusy || fStatus == kIOFireWirePending)
163		return fStatus;
164
165	fFailOnReset = failOnReset;
166
167	return reinit( generation, channel, sync, tag, hostMem, size, speed, completion, refcon );
168}
169
170// complete
171//
172//
173
174IOReturn IOFWAsyncStreamCommand::complete(IOReturn status)
175{
176	// latch the most recent completion status
177	IOFWCommand::fMembers->fCompletionStatus = status;
178
179	if( fStatus == kIOFireWireCompleting )
180	{
181		// prevent double completion
182		return kIOReturnSuccess;
183	}
184
185	// tell the fwim we're completing
186	// this could cause this routine to be reentered, hence the protection above
187
188	fStatus = kIOFireWireCompleting;
189	fControl->handleAsyncCompletion( this, status );
190
191	// we're back - actually complete the command
192	IOReturn completion_status = IOFWCommand::fMembers->fCompletionStatus;
193
194    removeFromQ();	// Remove from current queue
195
196    // If we're in the middle of processing a bus reset and
197    // the command should be retried after a bus reset, put it on the
198    // 'after reset queue'
199    // If we aren't still scanning the bus, and we're supposed to retry after bus resets, turn it into device offline
200    if( (completion_status == kIOFireWireBusReset) && !fFailOnReset)
201	{
202        if(fControl->scanningBus())
203		{
204            setHead(fControl->getAfterResetHandledQ());
205            return fStatus = kIOFireWirePending;	// On a queue waiting to execute
206        }
207    }
208    fStatus = completion_status;
209    if(fSync)
210        fSyncWakeup->signal(completion_status);
211    else if(fComplete)
212		(*fComplete)(fRefCon, completion_status, fControl, this);
213
214    return completion_status;
215}
216
217// gotAck
218//
219//
220
221void IOFWAsyncStreamCommand::gotAck(int ackCode)
222{
223    if (ackCode == kFWAckComplete )
224    	complete( kIOReturnSuccess );
225    else
226    	complete( kIOReturnTimeout );
227}
228
229// execute
230//
231//
232
233IOReturn IOFWAsyncStreamCommand::execute()
234{
235    IOReturn result = kIOReturnBadArgument;
236
237    fStatus = kIOReturnBusy;
238
239    if( !fFailOnReset )
240	{
241        // Update generation
242        fGeneration = fControl->getGeneration();
243    }
244
245	fSpeed = min((int)fControl->getBroadcastSpeed(), fSpeed) ;
246
247	if( fSize < ( 1 << 9+fControl->getBroadcastSpeed() ) and ( fChannel >= 0 and fChannel < 64) )
248	{
249		result = fControl->asyncStreamWrite(fGeneration,
250											fSpeed, fTag, fSyncBits, fChannel,fMemDesc,0,fSize, this);
251	}
252
253	// complete could release us so protect fStatus with retain and release
254	IOReturn status = fStatus;
255    if(result != kIOReturnSuccess)
256	{
257		retain();
258        complete(result);
259		status = fStatus;
260		release();
261	}
262	return status;
263}
264