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
36OSDefineMetaClassAndStructors(IOFWReadQuadCommand, IOFWAsyncCommand)
37OSMetaClassDefineReservedUnused(IOFWReadQuadCommand, 0);
38OSMetaClassDefineReservedUnused(IOFWReadQuadCommand, 1);
39
40#pragma mark -
41
42// gotPacket
43//
44//
45
46void IOFWReadQuadCommand::gotPacket(int rcode, const void* data, int size)
47{
48	setResponseCode( rcode );
49
50    if(rcode != kFWResponseComplete) {
51		// Sony CRX1600XL responses address error to breads to ROM
52        if( (rcode == kFWResponseTypeError || rcode == kFWResponseAddressError) && fMaxPack > 4) {
53            // try reading a quad at a time
54            fMaxPack = 4;
55            size = 0;
56        }
57        else {
58            complete(kIOFireWireResponseBase+rcode);
59            return;
60        }
61    }
62    else {
63        int i;
64        UInt32 *src = (UInt32 *)data;
65        for(i=0; i<size/4; i++)
66        {
67			*fQuads++ = *src++;
68        }
69        fSize -= size;
70
71		// nwg: should update bytes transferred count
72		fBytesTransferred += size ;
73    }
74
75    if(fSize > 0) {
76        fAddressLo += size;
77        updateTimer();
78        fCurRetries = fMaxRetries;
79        fControl->freeTrans(fTrans);  // Free old tcode
80
81        execute();
82    }
83    else {
84        complete(kIOReturnSuccess);
85    }
86}
87
88// initAll
89//
90//
91
92bool IOFWReadQuadCommand::initAll(IOFireWireNub *device, FWAddress devAddress,
93	UInt32 *quads, int numQuads, FWDeviceCallback completion,
94	void *refcon, bool failOnReset)
95{
96	bool success = true;
97
98    success = IOFWAsyncCommand::initAll(device, devAddress,
99										NULL, completion, refcon, failOnReset);
100
101	// create member variables
102
103	if( success )
104	{
105		fSize = 4*numQuads;
106		fQuads = quads;
107
108		success = createMemberVariables();
109	}
110
111	return success;
112}
113
114// initAll
115//
116//
117
118bool IOFWReadQuadCommand::initAll(IOFireWireController *control,
119                                  UInt32 generation, FWAddress devAddress,
120        UInt32 *quads, int numQuads, FWDeviceCallback completion,
121        void *refcon)
122{	bool success = true;
123
124    success = IOFWAsyncCommand::initAll(control, generation, devAddress,
125										NULL, completion, refcon);
126
127	// create member variables
128
129	if( success )
130	{
131		fSize = 4*numQuads;
132		fQuads = quads;
133
134		success = createMemberVariables();
135	}
136
137	return success;
138}
139
140// createMemberVariables
141//
142//
143
144bool IOFWReadQuadCommand::createMemberVariables( void )
145{
146	bool success = true;
147
148	if( fMembers == NULL )
149	{
150		success = IOFWAsyncCommand::createMemberVariables();
151	}
152
153	if( fMembers )
154	{
155		if( success )
156		{
157			fMembers->fSubclassMembers = IOMalloc( sizeof(MemberVariables) );
158			if( fMembers->fSubclassMembers == NULL )
159				success = false;
160		}
161
162		// zero member variables
163
164		if( success )
165		{
166			bzero( fMembers->fSubclassMembers, sizeof(MemberVariables) );
167		}
168
169		// clean up on failure
170
171		if( !success )
172		{
173			destroyMemberVariables();
174		}
175	}
176
177	return success;
178}
179
180// destroyMemberVariables
181//
182//
183
184void IOFWReadQuadCommand::destroyMemberVariables( void )
185{
186	if( fMembers->fSubclassMembers != NULL )
187	{
188		// free member variables
189
190		IOFree( fMembers->fSubclassMembers, sizeof(MemberVariables) );
191		fMembers->fSubclassMembers = NULL;
192	}
193}
194
195// free
196//
197//
198
199void IOFWReadQuadCommand::free()
200{
201	destroyMemberVariables();
202
203	IOFWAsyncCommand::free();
204}
205
206
207// reinit
208//
209//
210
211IOReturn IOFWReadQuadCommand::reinit(FWAddress devAddress,
212	UInt32 *quads, int numQuads, FWDeviceCallback completion,
213					void *refcon, bool failOnReset)
214{
215    IOReturn res;
216    res = IOFWAsyncCommand::reinit(devAddress,
217	NULL, completion, refcon, failOnReset);
218    if(res != kIOReturnSuccess)
219	return res;
220
221    fSize = 4*numQuads;
222    fQuads = quads;
223    return res;
224}
225
226// reinit
227//
228//
229
230IOReturn IOFWReadQuadCommand::reinit(UInt32 generation, FWAddress devAddress,
231        UInt32 *quads, int numQuads, FWDeviceCallback completion, void *refcon)
232{
233    IOReturn res;
234    res = IOFWAsyncCommand::reinit(generation, devAddress,
235        NULL, completion, refcon);
236    if(res != kIOReturnSuccess)
237        return res;
238
239    fSize = 4*numQuads;
240    fQuads = quads;
241    return res;
242}
243
244// execute
245//
246//
247
248IOReturn IOFWReadQuadCommand::execute()
249{
250    IOReturn result;
251    int transfer;
252
253    fStatus = kIOReturnBusy;
254
255    if(!fFailOnReset) {
256        // Update nodeID and generation
257        fDevice->getNodeIDGeneration(fGeneration, fNodeID);
258		fSpeed = fControl->FWSpeed( fNodeID );
259		if( fMembers->fMaxSpeed < fSpeed )
260		{
261			fSpeed = fMembers->fMaxSpeed;
262		}
263    }
264
265    transfer = fSize;
266    if(transfer > fMaxPack)
267	{
268		transfer = fMaxPack;
269	}
270
271	int maxPack = (1 << fControl->maxPackLog(fWrite, fNodeID));
272	if( maxPack < transfer )
273	{
274		transfer = maxPack;
275	}
276
277	UInt32 flags = kIOFWReadFlagsNone;
278
279	if( fMembers )
280	{
281		if( ((IOFWAsyncCommand::MemberVariables*)fMembers)->fForceBlockRequests )
282		{
283			flags |= kIOFWReadBlockRequest;
284		}
285
286		if( ((MemberVariables*)fMembers->fSubclassMembers)->fPingTime )
287		{
288			flags |= kIOFWReadPingTime;
289		}
290	}
291
292    // Do this when we're in execute, not before,
293    // so that Reset handling knows which commands are waiting a response.
294    fTrans = fControl->allocTrans(this);
295    if(fTrans) {
296        result = fControl->asyncRead(fGeneration, fNodeID, fAddressHi,
297                        fAddressLo, fSpeed, fTrans->fTCode, transfer, this, (IOFWReadFlags)flags );
298    }
299    else {
300	//	IOLog("IOFWReadCommand::execute: Out of tLabels?\n");
301        result = kIOFireWireOutOfTLabels;
302    }
303
304	// complete could release us so protect fStatus with retain and release
305	IOReturn status = fStatus;
306    if(result != kIOReturnSuccess)
307	{
308		retain();
309        complete(result);
310		status = fStatus;
311		release();
312	}
313	return status;
314}
315