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 *  IOFireWireLibPhysicalAddressSpace.cpp
24 *  IOFireWireLib
25 *
26 *  Created by NWG on Tue Dec 12 2000.
27 *  Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
28 *
29 */
30
31#import "IOFireWireLibPhysicalAddressSpace.h"
32#import "IOFireWireLibDevice.h"
33#import <exception>
34
35#import <System/libkern/OSCrossEndian.h>
36
37namespace IOFireWireLib {
38
39	// COM
40
41	PhysicalAddressSpace::Interface PhysicalAddressSpace::sInterface =
42	{
43		INTERFACEIMP_INTERFACE,
44		1, 0,	//vers, rev
45		& PhysicalAddressSpace::SGetPhysicalSegments,
46		& PhysicalAddressSpace::SGetPhysicalSegment,
47		& PhysicalAddressSpace::SGetPhysicalAddress,
48
49		SGetFWAddress,
50		SGetBuffer,
51		SGetBufferSize
52	} ;
53
54	HRESULT
55	PhysicalAddressSpace::QueryInterface(REFIID iid, void **ppv)
56	{
57		HRESULT		result = S_OK ;
58		*ppv = nil ;
59
60		CFUUIDRef	interfaceID	= CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, iid) ;
61
62		if ( CFEqual(interfaceID, IUnknownUUID) ||  CFEqual(interfaceID, kIOFireWirePhysicalAddressSpaceInterfaceID) )
63		{
64			*ppv = & GetInterface() ;
65			AddRef() ;
66		}
67		else
68		{
69			*ppv = nil ;
70			result = E_NOINTERFACE ;
71		}
72
73		CFRelease(interfaceID) ;
74		return result ;
75	}
76
77	IUnknownVTbl**
78	PhysicalAddressSpace::Alloc(
79		Device& 	inUserClient,
80		UserObjectHandle		inAddrSpaceRef,
81		UInt32		 					inSize,
82		void* 							inBackingStore,
83		UInt32 							inFlags)
84	{
85		PhysicalAddressSpace* me = nil ;
86		try {
87			me = new PhysicalAddressSpace(inUserClient, inAddrSpaceRef, inSize, inBackingStore, inFlags) ;
88		} catch (...) {
89		}
90
91		return ( nil == me ) ? nil : reinterpret_cast<IUnknownVTbl**>(& me->GetInterface()) ;
92	}
93
94#pragma mark -
95	void
96	PhysicalAddressSpace::SGetPhysicalSegments(
97		IOFireWireLibPhysicalAddressSpaceRef self,
98		UInt32*				ioSegmentCount,
99		IOByteCount			outSegments[],
100		IOPhysicalAddress	outAddresses[])
101	{
102		IOFireWireIUnknown::InterfaceMap<PhysicalAddressSpace>::GetThis(self)->GetPhysicalSegments(ioSegmentCount, outSegments, outAddresses) ;
103	}
104
105	IOPhysicalAddress
106	PhysicalAddressSpace::SGetPhysicalSegment(
107		IOFireWireLibPhysicalAddressSpaceRef self,
108		IOByteCount 		offset,
109		IOByteCount*		length)
110	{
111		return IOFireWireIUnknown::InterfaceMap<PhysicalAddressSpace>::GetThis(self)->GetPhysicalSegment(offset, length) ;
112	}
113
114	IOPhysicalAddress
115	PhysicalAddressSpace::SGetPhysicalAddress(
116		IOFireWireLibPhysicalAddressSpaceRef self)
117	{
118		return IOFireWireIUnknown::InterfaceMap<PhysicalAddressSpace>::GetThis(self)->mSegments[0].location ;
119	}
120
121	void
122	PhysicalAddressSpace::SGetFWAddress(IOFireWireLibPhysicalAddressSpaceRef self, FWAddress* outAddr )
123	{
124		bcopy(& IOFireWireIUnknown::InterfaceMap<PhysicalAddressSpace>::GetThis(self)->mFWAddress, outAddr, sizeof(*outAddr)) ;
125	}
126
127	void*
128	PhysicalAddressSpace::SGetBuffer(IOFireWireLibPhysicalAddressSpaceRef self)
129	{
130		return IOFireWireIUnknown::InterfaceMap<PhysicalAddressSpace>::GetThis(self)->mBackingStore ;
131	}
132
133	const UInt32
134	PhysicalAddressSpace::SGetBufferSize(IOFireWireLibPhysicalAddressSpaceRef self)
135	{
136		return IOFireWireIUnknown::InterfaceMap<PhysicalAddressSpace>::GetThis(self)->mSize ;
137	}
138
139#pragma mark -
140	PhysicalAddressSpace::PhysicalAddressSpace( Device& inUserClient, UserObjectHandle inKernPhysicalAddrSpaceRef,
141				UInt32 inSize, void* inBackingStore, UInt32 inFlags)
142	: IOFireWireIUnknown( reinterpret_cast<const IUnknownVTbl &>( sInterface ) ),
143	  mUserClient(inUserClient),
144	  mKernPhysicalAddrSpaceRef(inKernPhysicalAddrSpaceRef),
145	  mSize(inSize),
146	  mBackingStore(inBackingStore),
147	  mSegments( NULL ),
148	  mSegmentCount(0)
149	{
150		inUserClient.AddRef() ;
151
152		if (!mKernPhysicalAddrSpaceRef)
153			throw kIOReturnNoMemory ;
154
155		uint32_t outputCnt = 1;
156		uint64_t outputVal = 0;
157		IOReturn error = IOConnectCallScalarMethod( mUserClient.GetUserClientConnection(),
158													mUserClient.MakeSelectorWithObject( kPhysicalAddrSpace_GetSegmentCount_d, mKernPhysicalAddrSpaceRef ),
159													NULL,0,
160													&outputVal,&outputCnt);
161		mSegmentCount = outputVal & 0xFFFFFFFF;
162
163		if ( error || mSegmentCount == 0)
164			throw error ;
165
166		mSegments = new FWPhysicalSegment32[mSegmentCount] ;
167		if (!mSegments)
168		{
169			throw kIOReturnNoMemory ;
170		}
171
172		outputCnt = 1;
173		outputVal = 0;
174		const uint64_t inputs[3] = {(const uint64_t)mKernPhysicalAddrSpaceRef, mSegmentCount, (const uint64_t)mSegments};
175		error = IOConnectCallScalarMethod( mUserClient.GetUserClientConnection(),
176										  kPhysicalAddrSpace_GetSegments,
177										  inputs,3,
178										  &outputVal,&outputCnt);
179		mSegmentCount = outputVal & 0xFFFFFFFF;
180
181		if (error)
182		{
183			throw error ;
184		}
185
186#ifndef __LP64__
187		ROSETTA_ONLY(
188			{
189				UInt32 i;
190				for( i = 0; i < mSegmentCount; i++ )
191				{
192					mSegments[i].location = OSSwapInt32( mSegments[i].location );
193					mSegments[i].length = OSSwapInt32( mSegments[i].length );
194				}
195			}
196		);
197#endif
198
199		mFWAddress = FWAddress(0, mSegments[0].location, 0) ;
200	}
201
202	PhysicalAddressSpace::~PhysicalAddressSpace()
203	{
204		// call user client to delete our addr space ref here (if not yet released)
205		uint32_t outputCnt = 0;
206		const uint64_t inputs[1]={(const uint64_t)mKernPhysicalAddrSpaceRef};
207
208		IOConnectCallScalarMethod(mUserClient.GetUserClientConnection(),
209								  kReleaseUserObject,
210								  inputs,1,
211								  NULL,&outputCnt);
212
213		delete[] mSegments ;
214
215		mUserClient.Release() ;
216	}
217
218	void
219	PhysicalAddressSpace::GetPhysicalSegments(
220		UInt32*				ioSegmentCount,
221		IOByteCount			outSegmentLengths[],
222		IOPhysicalAddress	outSegments[])
223	{
224		if ( !outSegments || !outSegmentLengths )
225		{
226			*ioSegmentCount = mSegmentCount ;
227			return ;
228		}
229
230		*ioSegmentCount = MIN( *ioSegmentCount, mSegmentCount ) ;
231
232		for( unsigned index=0; index < *ioSegmentCount; ++index )
233		{
234			outSegments[ index ] = mSegments[ index ].location ;
235			outSegmentLengths[ index ] = mSegments[ index ].length ;
236		}
237	}
238
239	IOPhysicalAddress
240	PhysicalAddressSpace::GetPhysicalSegment(
241		IOByteCount 		offset,
242		IOByteCount*		length)
243	{
244		IOPhysicalAddress result = 0 ;
245
246		if (mSegmentCount > 0)
247		{
248			IOByteCount traversed = mSegments[0].length ;
249			UInt32		currentSegment = 0 ;
250
251			while((traversed <= offset) && (currentSegment < mSegmentCount))
252			{
253				traversed += mSegments[ currentSegment ].length ;
254				++currentSegment ;
255			}
256
257			if ( currentSegment <= mSegmentCount )
258			{
259				*length = mSegments[ currentSegment ].length ;
260				result =  mSegments[ currentSegment ].location ;
261			}
262		}
263
264		return result ;
265	}
266
267}
268