1/*
2 * Copyright (c) 2001 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/IOLib.h>
24#include <IOKit/firewire/IOFireWireController.h>
25#include <IOKit/firewire/IOFireWireLocalNode.h>
26#include <IOKit/avc/IOFireWireAVCConsts.h>
27#include <IOKit/avc/IOFireWirePCRSpace.h>
28
29OSDefineMetaClassAndStructors(IOFireWirePCRSpace, IOFWPseudoAddressSpace)
30OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 0);
31OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 1);
32OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 2);
33OSMetaClassDefineReservedUnused(IOFireWirePCRSpace, 3);
34
35static IOReturn MyServiceInterestHandler( void * target,
36										void * refCon,
37										UInt32 messageType,
38										IOService * provider,
39										void * messageArgument,
40										vm_size_t argSize )
41{
42    IOReturn res = kIOReturnUnsupported;
43	IOFireWirePCRSpace *pPCRSpace = (IOFireWirePCRSpace*) target;
44
45	//IOLog( "IOFireWirePCRSpace received MyServiceInterestHandler (message = 0x%08X)\n",(int) messageType);
46
47	switch (messageType)
48	{
49		case kIOMessageServiceIsTerminated:
50		case kIOMessageServiceIsRequestingClose:
51		case kIOMessageServiceIsResumed:
52			res = kIOReturnSuccess;
53			break;
54
55		// This message is received when a bus-reset start happens!
56		case kIOMessageServiceIsSuspended:
57			res = kIOReturnSuccess;
58			if (pPCRSpace)
59				pPCRSpace->clearAllP2PConnections();
60			break;
61
62		default:
63			break;
64	}
65
66    return res;
67}
68
69bool IOFireWirePCRSpace::init(IOFireWireBus *bus)
70{
71    //IOLog( "IOFireWirePCRSpace::init (0x%08X)\n",(int) this);
72
73	if(!IOFWPseudoAddressSpace::initFixed(bus,
74            FWAddress(kCSRRegisterSpaceBaseAddressHi, kPCRBaseAddress),
75            sizeof(fBuf), simpleReader, NULL, this))
76        return false;
77
78    fDesc = IOMemoryDescriptor::withAddress(fBuf, sizeof(fBuf), kIODirectionOutIn);
79    if (fDesc == NULL) {
80        return false;
81    }
82
83	IOReturn status = fDesc->prepare();
84	if( status != kIOReturnSuccess )
85	{
86		fDesc->release();
87		fDesc = NULL;
88		return false;
89	}
90
91	// Output Master Control - 400 Mbit, broadcast channel base 63, 31 output plugs
92    fBuf[0] = OSSwapHostToBigInt32((2 << kIOFWPCRDataRatePhase) |
93                (63 << kIOFWPCRBroadcastBasePhase) |
94                (0xff << kIOFWPCRExtensionPhase) |
95                (31 << kIOFWPCRNumPlugsPhase));
96
97	// Input Master Control - 400 Mbit, 31 output plugs
98    fBuf[32] = OSSwapHostToBigInt32((2 << kIOFWPCRDataRatePhase) |
99                (0xff << kIOFWPCRExtensionPhase) |
100                (31 << kIOFWPCRNumPlugsPhase));
101
102	fAVCTargetSpace = NULL;
103
104	// Register for messages from IOFireWireLocalNode to detect bus-resets!
105	IOFireWireController *pFireWireController = OSDynamicCast(IOFireWireController, bus);
106	if (pFireWireController)
107	{
108		IOFireWireLocalNode *pFireWireLocalNode = (pFireWireController)->getLocalNode(pFireWireController);
109		if (pFireWireLocalNode)
110		{
111			// Register with the IOFireWireBus for messages
112			fNotifier = pFireWireLocalNode->registerInterest(gIOGeneralInterest,MyServiceInterestHandler,this,this);
113		}
114	}
115
116	// Get the pointert to the IOFireWireAVCTargetSpace
117	// Note: This will create it, if it doesn't already exist.
118	fAVCTargetSpace = IOFireWireAVCTargetSpace::getAVCTargetSpace((IOFireWireController*)bus);
119	if(fAVCTargetSpace)
120		fAVCTargetSpace->activateWithUserClient((IOFireWireAVCProtocolUserClient*)0xFFFFFFFF);
121
122	return true;
123}
124
125IOFireWirePCRSpace * IOFireWirePCRSpace::getPCRAddressSpace(IOFireWireBus *bus)
126{
127    IOFWAddressSpace *existing;
128    IOFireWirePCRSpace *space;
129
130	//IOLog( "IOFireWirePCRSpace::getPCRAddressSpace\n");
131
132    existing = bus->getAddressSpace(FWAddress(kCSRRegisterSpaceBaseAddressHi, kPCRBaseAddress));
133    if(existing && OSDynamicCast(IOFireWirePCRSpace, existing)) {
134        existing->retain();
135        return OSDynamicCast(IOFireWirePCRSpace, existing);
136    }
137    space = new IOFireWirePCRSpace;
138    if(space) {
139        if(!space->init(bus)) {
140            space->release();
141            space = NULL;
142        }
143    }
144    return space;
145}
146
147
148UInt32 IOFireWirePCRSpace::doWrite(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
149                           const void *buf, IOFWRequestRefCon refcon)
150{
151	//IOLog( "IOFireWirePCRSpace::doWrite (0x%08X)\n",(int) this);
152
153    if(addr.addressHi != kCSRRegisterSpaceBaseAddressHi)
154        return kFWResponseAddressError;
155    if((addr.addressLo < kPCRBaseAddress) || (addr.addressLo + len > kPCRBaseAddress + 64*4))
156        return kFWResponseAddressError;
157
158    //IOLog("PCRSpace write, addr %x len %d\n", addr.addressLo, len);
159    // Writes to Plug Control registers not allowed.
160    if(!fControl->isLockRequest(refcon))
161        return kFWResponseTypeError;
162
163    // Only allow update of one register.
164    if(len != 4 || (addr.addressLo & 3))
165        return kFWResponseTypeError;
166
167    UInt32 newVal = *(const UInt32 *)buf;
168    UInt32 offset = (addr.addressLo - kPCRBaseAddress)/4;
169    UInt32 oldVal = OSSwapBigToHostInt32(fBuf[offset]);
170
171    fBuf[offset] = newVal;
172    if(fClients[offset].func)
173        (fClients[offset].func)(fClients[offset].refcon, nodeID, (offset-1) & 31, oldVal, OSSwapBigToHostInt32(newVal));
174
175	// Notify target space object of plug value modification
176	if ((fAVCTargetSpace) && (offset > 0) && (offset < 32))
177		fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochOutputType,(offset-1),OSSwapBigToHostInt32(newVal));
178	else if ((fAVCTargetSpace) && (offset > 32) && (offset < 64))
179		fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochInputType,(offset-33),OSSwapBigToHostInt32(newVal));
180
181    return kFWResponseComplete;
182}
183
184IOReturn IOFireWirePCRSpace::activate()
185{
186    IOReturn res = kIOReturnSuccess;
187
188	//IOLog( "IOFireWirePCRSpace::activate (0x%08X)\n",(int) this);
189
190    if(!fActivations++)
191        res = IOFWAddressSpace::activate();
192
193    return res;
194}
195
196void IOFireWirePCRSpace::deactivate()
197{
198	//IOLog( "IOFireWirePCRSpace::deactivate (0x%08X)\n",(int) this);
199
200    if(!--fActivations)
201	{
202        IOFWAddressSpace::deactivate();
203
204		// If we successfully registered for notifications, remove it now!
205		if (fNotifier)
206			fNotifier->remove();
207		fNotifier = NULL;
208	}
209}
210
211IOReturn IOFireWirePCRSpace::allocatePlug(void *refcon, IOFireWirePCRCallback func, UInt32 &plug, Client* head)
212{
213    UInt32 i;
214    IOReturn res = kIOReturnNoResources;
215
216	//IOLog( "IOFireWirePCRSpace::allocatePlug (0x%08X)\n",(int) this);
217
218    fControl->closeGate();
219    for(i=0; i<32; i++) {
220        if(!head[i].func) {
221            head[i].func = func;
222            head[i].refcon = refcon;
223            plug = i;
224            res = kIOReturnSuccess;
225            break;
226        }
227    }
228    fControl->openGate();
229    return res;
230}
231
232void IOFireWirePCRSpace::freePlug(UInt32 plug, Client* client)
233{
234	//IOLog( "IOFireWirePCRSpace::freePlug (0x%08X)\n",(int) this);
235
236    fControl->closeGate();
237    client->func = NULL;
238    fBuf[plug] = 0;
239    fControl->openGate();
240}
241
242UInt32 IOFireWirePCRSpace::readPlug(UInt32 plug)
243{
244	//IOLog( "IOFireWirePCRSpace::readPlug (0x%08X)\n",(int) this);
245
246    UInt32 val;
247    fControl->closeGate();
248    val = OSSwapBigToHostInt32(fBuf[plug]);
249    fControl->openGate();
250    return val;
251}
252
253
254IOReturn IOFireWirePCRSpace::updatePlug(UInt32 plug, UInt32 oldVal, UInt32 newVal)
255{
256	//IOLog( "IOFireWirePCRSpace::updatePlug (0x%08X)\n",(int) this);
257
258	IOReturn res;
259    fControl->closeGate();
260    if(oldVal == OSSwapBigToHostInt32(fBuf[plug])) {
261        fBuf[plug] = OSSwapHostToBigInt32(newVal);
262        res = kIOReturnSuccess;
263
264		// Notify target space object of plug value modification
265		if ((fAVCTargetSpace) && (plug > 0) && (plug < 32))
266			fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochOutputType,(plug-1),newVal);
267		else if ((fAVCTargetSpace) && (plug > 32) && (plug < 64))
268			fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochInputType,(plug-33),newVal);
269    }
270    else
271        res = kIOReturnCannotLock;
272    fControl->openGate();
273    return res;
274}
275
276IOReturn IOFireWirePCRSpace::allocateInputPlug(void *refcon, IOFireWirePCRCallback func, UInt32 &plug)
277{
278	//IOLog( "IOFireWirePCRSpace::allocateInputPlug (0x%08X)\n",(int) this);
279
280    return allocatePlug(refcon, func, plug, fClients+33);
281}
282
283void IOFireWirePCRSpace::freeInputPlug(UInt32 plug)
284{
285	//IOLog( "IOFireWirePCRSpace::freeInputPlug (0x%08X)\n",(int) this);
286
287    freePlug(plug+33, fClients+plug+33);
288}
289
290
291UInt32 IOFireWirePCRSpace::readInputPlug(UInt32 plug)
292{
293	//IOLog( "IOFireWirePCRSpace::readInputPlug (0x%08X)\n",(int) this);
294
295    return readPlug(plug+33);
296}
297
298
299IOReturn IOFireWirePCRSpace::updateInputPlug(UInt32 plug, UInt32 oldVal, UInt32 newVal)
300{
301	//IOLog( "IOFireWirePCRSpace::updateInputPlug (0x%08X)\n",(int) this);
302
303    return updatePlug(plug+33, oldVal, newVal);
304}
305
306IOReturn IOFireWirePCRSpace::allocateOutputPlug(void *refcon, IOFireWirePCRCallback func, UInt32 &plug)
307{
308    IOReturn result;
309
310	//IOLog( "IOFireWirePCRSpace::allocateOutputPlug (0x%08X)\n",(int) this);
311
312    result = allocatePlug(refcon, func, plug, fClients+1);
313    return result;
314}
315
316void IOFireWirePCRSpace::freeOutputPlug(UInt32 plug)
317{
318	//IOLog( "IOFireWirePCRSpace::freeOutputPlug (0x%08X)\n",(int) this);
319
320    freePlug(plug+1, fClients+plug+1);
321}
322
323
324UInt32 IOFireWirePCRSpace::readOutputPlug(UInt32 plug)
325{
326	//IOLog( "IOFireWirePCRSpace::readOutputPlug (0x%08X)\n",(int) this);
327
328    return readPlug(plug+1);
329}
330
331
332IOReturn IOFireWirePCRSpace::updateOutputPlug(UInt32 plug, UInt32 oldVal, UInt32 newVal)
333{
334	//IOLog( "IOFireWirePCRSpace::updateOutputPlug (0x%08X)\n",(int) this);
335
336    return updatePlug(plug+1, oldVal, newVal);
337}
338
339UInt32 IOFireWirePCRSpace::readOutputMasterPlug()
340{
341	//IOLog( "IOFireWirePCRSpace::readOutputMasterPlug (0x%08X)\n",(int) this);
342
343    return readPlug(0);
344}
345
346
347IOReturn IOFireWirePCRSpace::updateOutputMasterPlug(UInt32 oldVal, UInt32 newVal)
348{
349	//IOLog( "IOFireWirePCRSpace::updateOutputMasterPlug (0x%08X)\n",(int) this);
350
351    return updatePlug(0, oldVal, newVal);
352}
353
354UInt32 IOFireWirePCRSpace::readInputMasterPlug()
355{
356	//IOLog( "IOFireWirePCRSpace::readInputMasterPlug (0x%08X)\n",(int) this);
357
358    return readPlug(32);
359}
360
361
362IOReturn IOFireWirePCRSpace::updateInputMasterPlug(UInt32 oldVal, UInt32 newVal)
363{
364	//IOLog( "IOFireWirePCRSpace::updateInputMasterPlug (0x%08X)\n",(int) this);
365
366    return updatePlug(32, oldVal, newVal);
367}
368
369void IOFireWirePCRSpace::setAVCTargetSpacePointer(IOFireWireAVCTargetSpace *pAVCTargetSpace)
370{
371	//IOLog( "IOFireWirePCRSpace::setAVCTargetSpacePointer (0x%08X)\n",(int) this);
372
373	// NOTE: This function no longer does anything, since the relationship
374	// between the IOFireWirePCRSpace, and the IOFireWireAVCTargetSpace
375	// is now established in IOFireWirePCRSpace::init(...).
376
377	// fAVCTargetSpace = pAVCTargetSpace;
378	return;
379}
380
381void IOFireWirePCRSpace::clearAllP2PConnections(void)
382{
383	int i;
384	UInt32 oldVal;
385
386	//IOLog( "IOFireWirePCRSpace::clearAllP2PConnections (0x%08X)\n",(int) this);
387
388	// Handle oPCRs
389    for(i=0; i<32; i++)
390	{
391		fControl->closeGate();
392		oldVal = OSSwapBigToHostInt32(fBuf[i+1]);
393		if ((oldVal & 0x3F000000) != 0)
394		{
395			fBuf[i+1] &= OSSwapHostToBigInt32(0xC0FFFFFF);	// Clear P2P field
396
397			// If this plug has a client, notify it
398			if(fClients[i+1].func)
399				(fClients[i+1].func)(fClients[i+1].refcon, 0xFFFF, i, oldVal, OSSwapBigToHostInt32(fBuf[i+1]));
400
401			// Notify the AVC Target Space Object of the change
402			if (fAVCTargetSpace)
403				fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochOutputType,i,OSSwapBigToHostInt32(fBuf[i+1]));
404		}
405		fControl->openGate();
406	}
407
408	// Handle iPCRs
409    for(i=0; i<32; i++)
410	{
411		fControl->closeGate();
412		oldVal = OSSwapBigToHostInt32(fBuf[i+33]);
413		if ((oldVal & 0x3F000000) != 0)
414		{
415			fBuf[i+33] &= OSSwapHostToBigInt32(0xC0FFFFFF);	// Clear P2P field
416
417			// If this plug has a client, notify it
418			if(fClients[i+33].func)
419				(fClients[i+33].func)(fClients[i+33].refcon, 0xFFFF, i, oldVal, OSSwapBigToHostInt32(fBuf[i+33]));
420
421			// Notify the AVC Target Space Object of the change
422			if (fAVCTargetSpace)
423				fAVCTargetSpace->pcrModified(IOFWAVCPlugIsochInputType,i,OSSwapBigToHostInt32(fBuf[i+33]));
424		}
425		fControl->openGate();
426	}
427
428	return;
429}
430