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#include <IOKit/firewire/IOFWAddressSpace.h>
24#include <IOKit/firewire/IOFireWireController.h>
25
26#include "FWDebugging.h"
27
28OSData *IOFWPseudoAddressSpace::allocatedAddresses = NULL;  // unused
29
30OSDefineMetaClassAndStructors(IOFWPseudoAddressSpaceAux, IOFWAddressSpaceAux);
31
32OSMetaClassDefineReservedUsed(IOFWPseudoAddressSpaceAux, 0);
33OSMetaClassDefineReservedUsed(IOFWPseudoAddressSpaceAux, 1);
34OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 2);
35OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 3);
36OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 4);
37OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 5);
38OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 6);
39OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 7);
40OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 8);
41OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpaceAux, 9);
42
43#pragma mark -
44
45// init
46//
47//
48
49bool IOFWPseudoAddressSpaceAux::init( IOFWAddressSpace * primary )
50{
51	bool success = true;		// assume success
52
53	// init super
54
55    success = IOFWAddressSpaceAux::init( primary );
56
57	// create member variables
58
59	if( success )
60	{
61		success = createMemberVariables();
62	}
63
64	return success;
65}
66
67// free
68//
69//
70
71void IOFWPseudoAddressSpaceAux::free()
72{
73	destroyMemberVariables();
74
75	IOFWAddressSpaceAux::free();
76}
77
78// createMemberVariables
79//
80//
81
82bool IOFWPseudoAddressSpaceAux::createMemberVariables( void )
83{
84	bool success = true;
85
86	if( fMembers == NULL )
87	{
88		// create member variables
89
90		if( success )
91		{
92			fMembers = (MemberVariables*)IOMalloc( sizeof(MemberVariables) );
93			if( fMembers == NULL )
94				success = false;
95		}
96
97		// zero member variables
98
99		if( success )
100		{
101			bzero( fMembers, sizeof(MemberVariables) );
102		}
103
104		// clean up on failure
105
106		if( !success )
107		{
108			destroyMemberVariables();
109		}
110	}
111
112	return success;
113}
114
115// destroyMemberVariables
116//
117//
118
119void IOFWPseudoAddressSpaceAux::destroyMemberVariables( void )
120{
121	if( fMembers != NULL )
122	{
123		IOFree( fMembers, sizeof(MemberVariables) );
124		fMembers = NULL;
125	}
126}
127
128// handleARxReqIntComplete
129//
130//
131
132void IOFWPseudoAddressSpaceAux::handleARxReqIntComplete( void )
133{
134	if( fMembers->fARxReqIntCompleteHandler != NULL )
135	{
136		(*fMembers->fARxReqIntCompleteHandler)( fMembers->fARxReqIntCompleteHandlerRefcon );
137	}
138}
139
140// setARxReqIntCompleteHandler
141//
142//
143
144void IOFWPseudoAddressSpaceAux::setARxReqIntCompleteHandler( void * refcon, IOFWARxReqIntCompleteHandler handler )
145{
146	fMembers->fARxReqIntCompleteHandler = handler;
147	fMembers->fARxReqIntCompleteHandlerRefcon = refcon;
148}
149
150// intersects
151//
152//
153
154bool IOFWPseudoAddressSpaceAux::intersects( IOFWAddressSpace * space )
155{
156	bool intersects = false;
157
158	IOFWPseudoAddressSpace * pseudo_space = OSDynamicCast( IOFWPseudoAddressSpace, space );
159
160	if( pseudo_space )
161	{
162		// do we contain the start of the other space?
163		FWAddress address = pseudo_space->fBase;
164		intersects = (fPrimary->contains( address ) > 0);
165
166		// do we contain the end of the other space?
167		// because of how we allocate address spaces we can ignore the roll over into addressHi
168		if( pseudo_space->fLen > 0 )
169		{
170			address.addressLo += pseudo_space->fLen - 1;
171		}
172		intersects |= (fPrimary->contains( address ) > 0);
173	}
174
175	return intersects;
176}
177
178#pragma mark -
179
180/*
181 * Pseudo firewire addresses usually represent emulated registers of some kind.
182 * Accesses to these addresses will result in the owner being notified.
183 *
184 * Virtual addresses should not have zero as the top 16 bits of the 48 bit local address,
185 * since that may look like a physical address to hardware (eg. OHCI).
186 * if reader is NULL then reads will not be allowed.
187 * if writer is NULL then writes will not be allowed.
188 * if either is NULL then lock requests will not be allowed.
189 * refcon is passed back as the first argument of read and write callbacks.
190 */
191
192OSDefineMetaClassAndStructors(IOFWPseudoAddressSpace, IOFWAddressSpace)
193OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpace, 0);
194OSMetaClassDefineReservedUnused(IOFWPseudoAddressSpace, 1);
195
196#pragma mark -
197
198// allocateAddress
199//
200//
201
202IOReturn IOFWPseudoAddressSpace::allocateAddress(FWAddress *addr, UInt32 lenDummy)
203{
204	return fControl->allocatePseudoAddress( addr, lenDummy );
205}
206
207// freeAddress
208//
209//
210
211void IOFWPseudoAddressSpace::freeAddress(FWAddress addr, UInt32 lenDummy)
212{
213    fControl->freePseudoAddress( addr, lenDummy );
214}
215
216// simpleReader
217//
218//
219
220UInt32 IOFWPseudoAddressSpace::simpleReader(void *refcon, UInt16 nodeID, IOFWSpeed &speed,
221					FWAddress addr, UInt32 len, IOMemoryDescriptor **buf,
222                        IOByteCount * offset, IOFWRequestRefCon reqrefcon)
223{
224    IOFWPseudoAddressSpace * space = (IOFWPseudoAddressSpace *)refcon;
225
226    *buf = space->fDesc;
227    *offset = addr.addressLo - space->fBase.addressLo;
228
229    return kFWResponseComplete;
230}
231
232// simpleWriter
233//
234//
235
236UInt32 IOFWPseudoAddressSpace::simpleWriter(void *refcon, UInt16 nodeID, IOFWSpeed &speed,
237                    FWAddress addr, UInt32 len, const void *buf, IOFWRequestRefCon reqrefcon)
238{
239    IOFWPseudoAddressSpace * space = (IOFWPseudoAddressSpace *)refcon;
240
241    space->fDesc->writeBytes(addr.addressLo - space->fBase.addressLo, buf, len);
242
243    return kFWResponseComplete;
244}
245
246// simpleRead
247//
248//
249
250IOFWPseudoAddressSpace *
251IOFWPseudoAddressSpace::simpleRead(IOFireWireBus *control,
252                                   FWAddress *addr, UInt32 len, const void *data)
253{
254    IOFWPseudoAddressSpace * me = OSTypeAlloc( IOFWPseudoAddressSpace );
255    do
256	{
257        if(!me)
258            break;
259
260		if(!me->initAll(control, addr, len, simpleReader, NULL, (void *)me))
261		{
262            me->release();
263            me = NULL;
264            break;
265        }
266
267		me->fDesc = IOMemoryDescriptor::withAddress((void *)data, len, kIODirectionOut);
268        if(!me->fDesc)
269		{
270            me->release();
271            me = NULL;
272        }
273
274    } while(false);
275
276    return me;
277}
278
279// simpleReadFixed
280//
281//
282
283IOFWPseudoAddressSpace *
284IOFWPseudoAddressSpace::simpleReadFixed(IOFireWireBus *control,
285                                   FWAddress addr, UInt32 len, const void *data)
286{
287    IOFWPseudoAddressSpace * me = OSTypeAlloc( IOFWPseudoAddressSpace );
288    do
289	{
290        if(!me)
291            break;
292
293		if(!me->initFixed(control, addr, len, simpleReader, NULL, (void *)me))
294		{
295            me->release();
296            me = NULL;
297            break;
298        }
299
300		me->fDesc = IOMemoryDescriptor::withAddress((void *)data, len, kIODirectionOut);
301        if(!me->fDesc)
302		{
303            me->release();
304            me = NULL;
305        }
306
307    } while(false);
308
309    return me;
310}
311
312// simpleReadFixed
313//
314//
315
316IOFWPseudoAddressSpace *
317IOFWPseudoAddressSpace::simpleRWFixed(IOFireWireBus *control,
318                                      FWAddress addr, UInt32 len, const void *data)
319{
320    IOFWPseudoAddressSpace * me = OSTypeAlloc( IOFWPseudoAddressSpace );
321    do
322	{
323        if(!me)
324            break;
325
326		if(!me->initFixed(control, addr, len, simpleReader, simpleWriter, (void *)me))
327		{
328            me->release();
329            me = NULL;
330            break;
331        }
332
333		me->fDesc = IOMemoryDescriptor::withAddress((void *)data, len, kIODirectionOutIn);
334        if(!me->fDesc)
335		{
336            me->release();
337            me = NULL;
338        }
339
340    } while(false);
341
342    return me;
343}
344
345
346// simpleRW
347//
348//
349
350IOFWPseudoAddressSpace *IOFWPseudoAddressSpace::simpleRW(IOFireWireBus *control,
351                                                         FWAddress *addr, UInt32 len, void *data)
352{
353    IOFWPseudoAddressSpace * me = OSTypeAlloc( IOFWPseudoAddressSpace );
354    do
355	{
356        if(!me)
357            break;
358
359		if(!me->initAll(control, addr, len, simpleReader, simpleWriter, (void *)me))
360		{
361            me->release();
362            me = NULL;
363            break;
364        }
365
366		me->fDesc = IOMemoryDescriptor::withAddress(data, len, kIODirectionOutIn);
367        if(!me->fDesc)
368		{
369            me->release();
370            me = NULL;
371        }
372
373    } while(false);
374
375    return me;
376}
377
378// simpleRW
379//
380//
381
382IOFWPseudoAddressSpace *IOFWPseudoAddressSpace::simpleRW(IOFireWireBus *control,
383								FWAddress *addr, IOMemoryDescriptor * data)
384{
385    IOFWPseudoAddressSpace * me = OSTypeAlloc( IOFWPseudoAddressSpace );
386	do
387	{
388        if(!me)
389            break;
390
391		if(!me->initAll(control, addr, data->getLength(), simpleReader, simpleWriter, (void *)me))
392		{
393            me->release();
394            me = NULL;
395            break;
396        }
397
398		data->retain();
399        me->fDesc = data;
400
401	} while(false);
402
403    return me;
404}
405
406// initAll
407//
408//
409
410bool IOFWPseudoAddressSpace::initAll(IOFireWireBus *control, FWAddress *addr, UInt32 len,
411		FWReadCallback reader, FWWriteCallback writer, void *refCon)
412{
413    if(!IOFWAddressSpace::init(control))
414		return false;
415
416    if(allocateAddress(addr, len) != kIOReturnSuccess)
417        return false;
418
419    fBase = *addr;
420    fBase.addressHi &= 0xFFFF;	// Mask off nodeID part.
421    fLen = len;
422    fDesc = NULL;	// Only used by simpleRead case.
423    fRefCon = refCon;
424    fReader = reader;
425    fWriter = writer;
426
427    return true;
428}
429
430// initFixed
431//
432//
433
434bool IOFWPseudoAddressSpace::initFixed(IOFireWireBus *control, FWAddress addr, UInt32 len,
435		FWReadCallback reader, FWWriteCallback writer, void *refCon)
436{
437    if( !IOFWAddressSpace::init(control) )
438        return false;
439
440    // Only allow fixed addresses at top of address space
441    if( addr.addressHi != kCSRRegisterSpaceBaseAddressHi )
442        return false;
443
444    fBase = addr;
445    fLen = len;
446    fDesc = NULL;	// Only used by simpleRead case.
447    fRefCon = refCon;
448    fReader = reader;
449    fWriter = writer;
450
451    return true;
452}
453
454// createAuxiliary
455//
456// virtual method for creating auxiliary object.  subclasses needing to subclass
457// the auxiliary object can override this.
458
459IOFWAddressSpaceAux * IOFWPseudoAddressSpace::createAuxiliary( void )
460{
461	IOFWPseudoAddressSpaceAux * auxiliary;
462
463	auxiliary = OSTypeAlloc( IOFWPseudoAddressSpaceAux );
464
465    if( auxiliary != NULL && !auxiliary->init(this) )
466	{
467        auxiliary->release();
468        auxiliary = NULL;
469    }
470
471    return auxiliary;
472}
473
474// free
475//
476//
477
478void IOFWPseudoAddressSpace::free()
479{
480    if(fDesc)
481		fDesc->release();
482
483	if(fBase.addressHi != kCSRRegisterSpaceBaseAddressHi)
484        freeAddress(fBase, fLen);
485
486	IOFWAddressSpace::free();
487}
488
489// doRead
490//
491//
492
493UInt32 IOFWPseudoAddressSpace::doRead( UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
494			IOMemoryDescriptor **buf, IOByteCount * offset, IOFWRequestRefCon refcon)
495{
496	if( !isTrustedNode( nodeID ) )
497		return kFWResponseAddressError;
498
499    if(addr.addressHi != fBase.addressHi)
500		return kFWResponseAddressError;
501
502	if(addr.addressLo < fBase.addressLo)
503		return kFWResponseAddressError;
504
505	if(addr.addressLo + len > fBase.addressLo+fLen)
506		return kFWResponseAddressError;
507
508	if(!fReader)
509        return kFWResponseTypeError;
510
511    return fReader(fRefCon, nodeID, speed, addr, len, buf, offset, refcon);
512}
513
514// doWrite
515//
516//
517
518UInt32 IOFWPseudoAddressSpace::doWrite(UInt16 nodeID, IOFWSpeed &speed, FWAddress addr, UInt32 len,
519                                       const void *buf, IOFWRequestRefCon refcon)
520{
521	if( !isTrustedNode( nodeID ) )
522		return kFWResponseAddressError;
523
524   if(addr.addressHi != fBase.addressHi)
525		return kFWResponseAddressError;
526
527	if(addr.addressLo < fBase.addressLo)
528		return kFWResponseAddressError;
529
530	if(addr.addressLo + len > fBase.addressLo+fLen)
531		return kFWResponseAddressError;
532
533	if(!fWriter)
534        return kFWResponseTypeError;
535
536    return fWriter(fRefCon, nodeID, speed, addr, len, buf, refcon);
537}
538
539// contains
540//
541//
542
543UInt32 IOFWPseudoAddressSpace::contains(FWAddress addr)
544{
545    UInt32 offset;
546
547	if(addr.addressHi != fBase.addressHi)
548        return 0;
549
550	if(addr.addressLo < fBase.addressLo)
551        return 0;
552
553	offset = addr.addressLo - fBase.addressLo;
554    if(offset > fLen)
555        return 0;
556
557	return fLen - offset;
558}