1/*
2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1998 Apple Computer, Inc.  All rights reserved.
30 *
31 * HISTORY
32 * 23 Nov 98 sdouglas created.
33 */
34
35#include <IOKit/system.h>
36extern "C" {
37#include <pexpert/pexpert.h>
38}
39
40#include <libkern/c++/OSContainers.h>
41#include <IOKit/IOLib.h>
42#include <IOKit/IODeviceTreeSupport.h>
43#include <IOKit/IODeviceMemory.h>
44#include <IOKit/IOPlatformExpert.h>
45
46#include <IOKit/pci/IOPCIDevice.h>
47
48#include <IOKit/IOBufferMemoryDescriptor.h>
49
50#include <IOKit/platform/AppleMacIO.h>
51
52#include <IOKit/ppc/IODBDMA.h>
53
54#include <IOKit/assert.h>
55
56/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
57
58#define super IOService
59
60OSDefineMetaClassAndAbstractStructors(AppleMacIO, IOService);
61OSMetaClassDefineReservedUnused(AppleMacIO,  0);
62OSMetaClassDefineReservedUnused(AppleMacIO,  1);
63OSMetaClassDefineReservedUnused(AppleMacIO,  2);
64OSMetaClassDefineReservedUnused(AppleMacIO,  3);
65
66/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
67
68bool AppleMacIO::start( IOService * provider )
69{
70    IOPCIDevice *pciNub = (IOPCIDevice *)provider;
71
72    if( !super::start( provider))
73	return( false);
74
75    // Make sure memory space is on.
76    pciNub->setMemoryEnable(true);
77
78    fNub = provider;
79    fMemory = provider->mapDeviceMemoryWithIndex( 0 );
80    if( 0 == fMemory)
81	IOLog("%s: unexpected ranges\n", getName());
82    else if( !selfTest())
83	IOLog("Warning: AppleMacIO self test fails\n");
84    PMinit();		// initialize for power management
85    temporaryPowerClampOn();	// hold power on till we get children
86    return( true);
87}
88
89
90IOService * AppleMacIO::createNub( IORegistryEntry * from )
91{
92    IOService *	nub;
93
94    nub = new AppleMacIODevice;
95
96    if( nub && !nub->init( from, gIODTPlane )) {
97	nub->free();
98	nub = 0;
99    }
100
101    return( nub);
102}
103
104void AppleMacIO::processNub(IOService * /*nub*/)
105{
106}
107
108const char * AppleMacIO::deleteList ( void )
109{
110    return( "('sd', 'st', 'disk', 'tape', 'pram', 'rtc', 'mouse')" );
111}
112
113const char * AppleMacIO::excludeList( void )
114{
115    return( 0 );
116}
117
118void AppleMacIO::publishBelow( IORegistryEntry * root )
119{
120    OSCollectionIterator *	kids;
121    IORegistryEntry *		next;
122    IOService *			nub;
123
124    // infanticide
125    kids = IODTFindMatchingEntries( root, kIODTRecursive, deleteList() );
126    if( kids) {
127	while( (next = (IORegistryEntry *)kids->getNextObject())) {
128	    next->detachAll( gIODTPlane);
129	}
130	kids->release();
131    }
132
133    // publish everything below, minus excludeList
134    kids = IODTFindMatchingEntries( root, kIODTRecursive | kIODTExclusive,
135					excludeList());
136    if( kids) {
137	while( (next = (IORegistryEntry *)kids->getNextObject())) {
138
139            if( 0 == (nub = createNub( next )))
140                continue;
141
142            nub->attach( this );
143
144	    processNub(nub);
145
146            nub->registerService();
147        }
148	kids->release();
149    }
150}
151
152bool AppleMacIO::compareNubName( const IOService * nub,
153				OSString * name, OSString ** matched ) const
154{
155    return( IODTCompareNubName( nub, name, matched )
156	  ||  nub->IORegistryEntry::compareName( name, matched ) );
157}
158
159IOReturn AppleMacIO::getNubResources( IOService * nub )
160{
161    if( nub->getDeviceMemory())
162	return( kIOReturnSuccess );
163
164    IODTResolveAddressing( nub, "reg", fNub->getDeviceMemoryWithIndex(0) );
165
166    return( kIOReturnSuccess);
167}
168
169bool AppleMacIO::selfTest( void )
170{
171    IODBDMADescriptor			*dmaDescriptors;
172    UInt32				dmaDescriptorsPhys;
173    UInt32				i;
174    UInt32				status;
175    IODBDMADescriptor			*dmaDesc;
176    IOBufferMemoryDescriptor		*buffer;
177    volatile IODBDMAChannelRegisters	*ioBaseDMA;
178    bool				ok = false;
179    enum { 				kTestChannel = 0x8000 };
180
181    ioBaseDMA = (volatile IODBDMAChannelRegisters *)
182		(((UInt32)fMemory->getVirtualAddress())
183		+ kTestChannel );
184
185    do {
186	buffer = IOBufferMemoryDescriptor::withCapacity(page_size, kIODirectionOutIn, true);
187	dmaDescriptors = (IODBDMADescriptor*)buffer->getBytesNoCopy();
188
189        if (!dmaDescriptors)
190	    continue;
191
192        if ( (UInt32)dmaDescriptors & (page_size - 1) ) {
193            IOLog("AppleMacIO::%s() - DMA Descriptor memory not page aligned!!", __FUNCTION__);
194	    continue;
195        }
196
197        bzero( dmaDescriptors, page_size );
198
199        IODBDMAReset( ioBaseDMA );
200
201        dmaDesc = dmaDescriptors;
202
203        IOMakeDBDMADescriptor( dmaDesc,
204                            kdbdmaNop,
205                            kdbdmaKeyStream0,
206                            kdbdmaIntNever,
207                            kdbdmaBranchNever,
208                            kdbdmaWaitNever,
209                            0,
210                            0 );
211
212        dmaDesc++;
213
214	dmaDescriptorsPhys = (UInt32) (buffer->getPhysicalSegment(0, NULL, 0));
215
216        IOMakeDBDMADescriptorDep( dmaDesc,
217                                kdbdmaStoreQuad,
218                                kdbdmaKeySystem,
219                                kdbdmaIntNever,
220                                kdbdmaBranchNever,
221                                kdbdmaWaitNever,
222                                4,
223                                dmaDescriptorsPhys+16*sizeof(IODBDMADescriptor),
224                                0x12345678 );
225
226        dmaDesc++;
227
228        IOMakeDBDMADescriptor( dmaDesc,
229                            kdbdmaStop,
230                            kdbdmaKeyStream0,
231                            kdbdmaIntNever,
232                            kdbdmaBranchNever,
233                            kdbdmaWaitNever,
234                            0,
235                            0 );
236
237
238        for ( i = 0; (!ok) && (i < 3); i++ )
239        {
240            dmaDescriptors[16].operation = 0;
241
242            IOSetDBDMACommandPtr( ioBaseDMA, dmaDescriptorsPhys );
243            IODBDMAContinue( ioBaseDMA );
244
245            IODelay( 200 );
246
247            status = IOGetDBDMAChannelStatus( ioBaseDMA );
248
249            if ( ((status & kdbdmaActive) == 0)
250                &&  ((status & kdbdmaDead) == 0)
251                    && (OSReadSwapInt32( &dmaDescriptors[16].operation, 0 ) == 0x12345678 ))
252                ok = true;
253        }
254
255        IODBDMAReset( ioBaseDMA );
256
257    } while (false);
258
259    if (buffer)
260	    buffer->release();
261
262    return ok;
263}
264
265/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
266
267#undef super
268#define super IOService
269
270OSDefineMetaClassAndStructors(AppleMacIODevice, IOService);
271OSMetaClassDefineReservedUnused(AppleMacIODevice,  0);
272OSMetaClassDefineReservedUnused(AppleMacIODevice,  1);
273OSMetaClassDefineReservedUnused(AppleMacIODevice,  2);
274OSMetaClassDefineReservedUnused(AppleMacIODevice,  3);
275
276/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
277
278bool AppleMacIODevice::compareName( OSString * name,
279					OSString ** matched ) const
280{
281  return (IODTCompareNubName(this, name, matched) ||
282	  IORegistryEntry::compareName(name, matched));
283}
284
285IOService * AppleMacIODevice::matchLocation( IOService * /* client */ )
286{
287  return this;
288}
289
290IOReturn AppleMacIODevice::getResources( void )
291{
292  IOService *macIO = this;
293
294  if (getDeviceMemory() != 0) return kIOReturnSuccess;
295
296  while (macIO && ((macIO = macIO->getProvider()) != 0))
297    if (strcmp("mac-io", macIO->getName()) == 0) break;
298
299  if (macIO == 0) return kIOReturnError;
300
301  IODTResolveAddressing(this, "reg", macIO->getDeviceMemoryWithIndex(0));
302
303  return kIOReturnSuccess;
304}
305
306