1/*
2 * Copyright (c) 2008 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#include <IOKit/firewire/IOFireWireController.h>
24#include <IOKit/firewire/IOFireWireMultiIsochReceive.h>
25///////////////////////////////////////////////////////////////////////////////////
26//
27// Definition of objects used by the Multi-Isoch Receiver
28//
29///////////////////////////////////////////////////////////////////////////////////
30OSDefineMetaClassAndStructors(IOFireWireMultiIsochReceiveListener, OSObject)
31OSDefineMetaClassAndStructors(IOFireWireMultiIsochReceivePacket, OSObject)
32
33///////////////////////////////////////////////////////////////////////////////////
34// IOFireWireMultiIsochReceiveListener::init
35///////////////////////////////////////////////////////////////////////////////////
36bool IOFireWireMultiIsochReceiveListener::init(IOFireWireController *fwController,
37											   UInt32 receiveChannel,
38											   FWMultiIsochReceiveListenerCallback callback,
39											   void *pCallbackRefCon,
40											   FWMultiIsochReceiveListenerParams *pListenerParams)
41{
42	bool success = true;
43
44	//IOLog( "IOFireWireMultiIsochReceiveListener::init (0x%08X)\n",(int) this);
45
46	// init super
47    if( !OSObject::init() )
48        success = false;
49
50	if( success )
51	{
52		// Initialize this object
53		fControl = fwController;
54		fChannel = receiveChannel;
55		fClientCallback = callback;
56		fClientCallbackRefCon = pCallbackRefCon;
57		fActivated = false;
58
59		if (pListenerParams)
60		{
61			fListenerParams = new FWMultiIsochReceiveListenerParams;
62			if (fListenerParams)
63			{
64				// copy over the parameters specified by the client.
65				fListenerParams->maxLatencyInFireWireCycles = pListenerParams->maxLatencyInFireWireCycles;
66				fListenerParams->expectedStreamBitRate = pListenerParams->expectedStreamBitRate;
67				fListenerParams->clientPacketReturnLatencyInFireWireCycles = pListenerParams->clientPacketReturnLatencyInFireWireCycles;
68			}
69		}
70		else
71			fListenerParams = NULL;
72	}
73
74	return success;
75}
76
77///////////////////////////////////////////////////////////////////////////////////
78// IOFireWireMultiIsochReceiveListener::free
79///////////////////////////////////////////////////////////////////////////////////
80void IOFireWireMultiIsochReceiveListener::free()
81{
82	if (fListenerParams)
83	{
84		delete fListenerParams;
85		fListenerParams = NULL;
86	}
87
88	OSObject::free();
89}
90
91///////////////////////////////////////////////////////////////////////////////////
92// IOFireWireMultiIsochReceiveListener::create
93///////////////////////////////////////////////////////////////////////////////////
94IOFireWireMultiIsochReceiveListener * IOFireWireMultiIsochReceiveListener::create(IOFireWireController *fwController,
95																				  UInt32 channel,
96																				  FWMultiIsochReceiveListenerCallback callback,
97																				  void *pCallbackRefCon,
98																				  FWMultiIsochReceiveListenerParams *pListenerParams)
99{
100	IOFireWireMultiIsochReceiveListener * listener;
101
102	listener = OSTypeAlloc( IOFireWireMultiIsochReceiveListener );
103
104    if( listener != NULL && !listener->init(fwController,
105											channel,
106											callback,
107											pCallbackRefCon,
108											pListenerParams))
109	{
110        listener->release();
111        listener = NULL;
112    }
113
114    return listener;
115}
116
117///////////////////////////////////////////////////////////////////////////////////
118// IOFireWireMultiIsochReceiveListener::Activate
119///////////////////////////////////////////////////////////////////////////////////
120IOReturn IOFireWireMultiIsochReceiveListener::Activate()
121{
122	return fControl->activateMultiIsochReceiveListener(this);
123}
124
125///////////////////////////////////////////////////////////////////////////////////
126// IOFireWireMultiIsochReceiveListener::Deactivate
127///////////////////////////////////////////////////////////////////////////////////
128IOReturn IOFireWireMultiIsochReceiveListener::Deactivate()
129{
130	return fControl->deactivateMultiIsochReceiveListener(this);
131}
132
133///////////////////////////////////////////////////////////////////////////////////
134// IOFireWireMultiIsochReceiveListener::SetCallback
135///////////////////////////////////////////////////////////////////////////////////
136IOReturn IOFireWireMultiIsochReceiveListener::SetCallback(FWMultiIsochReceiveListenerCallback callback,
137														  void *pCallbackRefCon)
138{
139	if (!fActivated)
140	{
141		fClientCallback = callback;
142		fClientCallbackRefCon = pCallbackRefCon;
143		return kIOReturnSuccess;
144	}
145	else
146		return kIOReturnNotPermitted;
147}
148
149///////////////////////////////////////////////////////////////////////////////////
150// IOFireWireMultiIsochReceivePacket::init
151///////////////////////////////////////////////////////////////////////////////////
152bool IOFireWireMultiIsochReceivePacket::init(IOFireWireController *fwController)
153{
154	bool success = true;
155
156	//IOLog( "IOFireWireMultiIsochReceivePacket::init (0x%08X)\n",(int) this);
157
158	// init super
159    if( !OSObject::init() )
160        success = false;
161
162	if( success )
163	{
164		// Initialize this object
165		fControl = fwController;
166		numRanges = 0;
167		numClientReferences = 0;
168	}
169
170	return success;
171}
172
173///////////////////////////////////////////////////////////////////////////////////
174// IOFireWireMultiIsochReceivePacket::free
175///////////////////////////////////////////////////////////////////////////////////
176void IOFireWireMultiIsochReceivePacket::free()
177{
178	OSObject::free();
179}
180
181///////////////////////////////////////////////////////////////////////////////////
182// IOFireWireMultiIsochReceivePacket::create
183///////////////////////////////////////////////////////////////////////////////////
184IOFireWireMultiIsochReceivePacket * IOFireWireMultiIsochReceivePacket::create( IOFireWireController *fwController )
185{
186	IOFireWireMultiIsochReceivePacket * packet;
187
188	packet = OSTypeAlloc( IOFireWireMultiIsochReceivePacket );
189
190    if( packet != NULL && !packet->init(fwController))
191	{
192        packet->release();
193        packet = NULL;
194    }
195
196    return packet;
197}
198
199///////////////////////////////////////////////////////////////////////////////////
200// IOFireWireMultiIsochReceivePacket::clientDone
201///////////////////////////////////////////////////////////////////////////////////
202void IOFireWireMultiIsochReceivePacket::clientDone( void )
203{
204	fControl->clientDoneWithMultiIsochReceivePacket(this);
205}
206
207///////////////////////////////////////////////////////////////////////////////////
208// IOFireWireMultiIsochReceivePacket::isochChannel
209///////////////////////////////////////////////////////////////////////////////////
210UInt32
211IOFireWireMultiIsochReceivePacket::isochChannel(void)
212{
213	// The isoch channel number is in the first quad,
214	// which is guarranted to be in the first range.
215
216	UInt32 *pIsochPacketHeader = (UInt32*)  ranges[0].address;
217	UInt32 isochPacketHeader = OSSwapLittleToHostInt32(*pIsochPacketHeader);
218	return ((isochPacketHeader & 0x00003F00) >> 8);
219}
220
221///////////////////////////////////////////////////////////////////////////////////
222// IOFireWireMultiIsochReceivePacket::isochPayloadSize
223///////////////////////////////////////////////////////////////////////////////////
224UInt32
225IOFireWireMultiIsochReceivePacket::isochPayloadSize(void)
226{
227	// The isoch payload size is in the first quad,
228	// which is guarranted to be in the first range.
229
230	UInt32 *pIsochPacketHeader = (UInt32*)  ranges[0].address;
231	UInt32 isochPacketHeader = OSSwapLittleToHostInt32(*pIsochPacketHeader);
232	return ((isochPacketHeader & 0xFFFF0000) >> 16);
233}
234
235///////////////////////////////////////////////////////////////////////////////////
236// IOFireWireMultiIsochReceivePacket::packetReceiveTime
237///////////////////////////////////////////////////////////////////////////////////
238UInt32
239IOFireWireMultiIsochReceivePacket::packetReceiveTime(void)
240{
241	// The isoch timestamp is in the last quad,
242	// which is guarranted to be in the last range.
243
244	UInt32 *pIsochPacketTrailer = (UInt32*) ranges[numRanges-1].address;
245	pIsochPacketTrailer += ((ranges[numRanges-1].length/4)-1);	// Bump to the last quadlet in the range
246	UInt32 isochPacketTrailer = OSSwapLittleToHostInt32(*pIsochPacketTrailer);
247
248	// We shift the 16-bit time-stamp into the normal 7:13:12 FireWire cycle-time format!
249	return ((isochPacketTrailer & 0x0000FFFF) << 12);
250}
251
252///////////////////////////////////////////////////////////////////////////////////
253// IOFireWireMultiIsochReceivePacket::createMemoryDescriptorForRanges
254///////////////////////////////////////////////////////////////////////////////////
255IOMemoryDescriptor*
256IOFireWireMultiIsochReceivePacket::createMemoryDescriptorForRanges(void)
257{
258	IOMemoryDescriptor * bufferDesc = NULL ;
259	IOReturn error;
260
261	bufferDesc = IOMemoryDescriptor::withAddressRanges (ranges, numRanges, kIODirectionOut, kernel_task) ;
262	if ( ! bufferDesc )
263	{
264		error = kIOReturnNoMemory ;
265	}
266	else
267	{
268		error = bufferDesc->prepare() ;
269		if (error != kIOReturnSuccess)
270		{
271			bufferDesc->release();
272			bufferDesc = NULL;
273		}
274	}
275
276	return bufferDesc;
277}
278