1: /*
     2:         
     3:         File:			WiFiControllerPCI.cpp
     4:         Program:		GTDriver
     5: 	Author:			Michael Ro├čberg
     6: 				mick@binaervarianz.de
     7: 	Description:		GTDriver is a free driver for PrismGT based cards under OS X.
     8:                 
     9:         This file is part of GTDriver.
    10: 
    11:     GTDriver is free software; you can redistribute it and/or modify
    12:     it under the terms of the GNU General Public License as published by
    13:     the Free Software Foundation; either version 2 of the License, or
    14:     (at your option) any later version.
    15: 
    16:     GTDriver is distributed in the hope that it will be useful,
    17:     but WITHOUT ANY WARRANTY; without even the implied warranty of
    18:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19:     GNU General Public License for more details.
    20: 
    21:     You should have received a copy of the GNU General Public License
    22:     along with GTDriver; if not, write to the Free Software
    23:     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    24: */
    25: 
    26: #include "WiFiControllerPCI.h" 
    27: 
    28: #define super WiFiController 
    29: OSDefineMetaClassAndStructors(WiFiControllerPCI, WiFiController)
    30: 
    31: //---------------------------------------------------------------------------
    32: // Function: pciConfigInit
    33: //
    34: // Update PCI command register to enable the memory-mapped range,
    35: // and bus-master interface.
    36: 
    37: bool WiFiControllerPCI::pciConfigInit(IOPCIDevice * provider) {
    38:     #define kPCIPMCSR                   (_pmPCICapPtr + 4)
    39:     UInt16 reg16;
    40: 
    41:     reg16 = provider->configRead16(kIOPCIConfigCommand);
    42: 
    43:     reg16 |= (kIOPCICommandBusMaster      |
    44:               kIOPCICommandMemorySpace    |
    45:               kIOPCICommandMemWrInvalidate);
    46: 
    47:     reg16 &= ~kIOPCICommandIOSpace;  // disable I/O space
    48: 
    49:     //provider->configWrite16(kIOPCIConfigCommand, reg16);
    50: 
    51:     // To allow the device to use the PCI Memory Write and Invalidate
    52:     // command, it must know the correct cache line size. The only
    53:     // supported cache line sizes are 8 and 16 Dwords.
    54:     //
    55:     // Do not modify the cache line size register. Leave this up
    56:     // to the platform's firmware.
    57:     // provider->configWrite8( kIOPCIConfigCacheLineSize, 8 );
    58: 
    59:     // Locate the PM register block of this device in its PCI config space.
    60: 
    61:     /*provider->findPCICapability(kIOPCIPowerManagementCapability,
    62:                                  &_pmPCICapPtr);
    63:     if (_pmPCICapPtr) {
    64:         // Clear PME# and set power state to D0.
    65:         provider->configWrite16(kPCIPMCSR, 0x8000);
    66:         IOSleep(10);
    67:     }*/
    68: 
    69:     return true;
    70: }
    71: 
    72: #pragma mark provicer specific functions 
    73: 
    74: bool WiFiControllerPCI::startProvider(IOService *provider) {
    75:     bool ret = false;
    76:     
    77:     do {
    78:         // Cache our provider to an instance variable.
    79:         _nub = OSDynamicCast(IOPCIDevice, provider);
    80:         if (_nub == 0) break;
    81: 
    82:         // Retain provider, released in free().
    83:         _nub->retain();
    84: 
    85:         // Open our provider.
    86:         if (_nub->open(this) == false) break;
    87: 
    88:         // Request domain power.
    89:         // Without this, the PCIDevice may be in state 0, and the
    90:         // PCI config space may be invalid if the machine has been
    91:         // sleeping.
    92:         if (_nub->requestPowerDomainState(
    93:         /* power flags */ kIOPMPowerOn,
    94:         /* connection  */ (IOPowerConnection *) getParentEntry(gIOPowerPlane),
    95:         /* spec        */ IOPMLowestState ) != IOPMNoErr ) {
    96:             break;
    97:         }
    98:         
    99:         // Get the virtual address mapping of CSR registers located at
   100:         // Base Address Range 0 (0x10). The size of this range is 4K.
   101:         // This was changed to 32 bytes in 82558 A-Step, though only
   102:         // the first 32 bytes should be accessed, and the other bytes
   103:         // are considered reserved.
   104:         _map = _nub->mapDeviceMemoryWithRegister(kIOPCIConfigBaseAddress0);
   105:         if (_map == 0) break;
   106:         
   107:         _ioBase = _map->getVirtualAddress();
   108: 
   109:         // Setup our PCI config space.
   110:         if (pciConfigInit(_nub) == false) break;
   111: 
   112:     	_mbufCursor = IOMbufLittleMemoryCursor::withSpecification(MAX_FRAGMENT_SIZE, 1);
   113:         if (!_mbufCursor) break;
   114:         
   115:         ret = true;
   116:     } while(false);
   117:     
   118:     return ret;
   119: }
   120: 
   121: bool WiFiControllerPCI::openProvider() {
   122:     if ((_nub == NULL) || (_nub->open(this) == false)) {
   123:         return false;
   124:     }
   125:     
   126:     return true;
   127: }
   128: 
   129: bool WiFiControllerPCI::closeProvider() {
   130:     if (_nub) _nub->close(this);
   131:     
   132:     return true;
   133: }
   134: 
   135: bool WiFiControllerPCI::freeProvider() {
   136:     #define RELEASE(x) do { if(x) { (x)->release(); (x) = 0; } } while(0)
   137:     
   138:     RELEASE(_mbufCursor);
   139:     RELEASE(_map);
   140:     RELEASE(_nub);
   141:     
   142:     return true;
   143: }
   144: 
   145: #pragma mark memory allocation 
   146: 
   147: //---------------------------------------------------------------------------
   148: // Function: allocatePageBlock
   149: //
   150: // Purpose:
   151: //   Allocate a page of memory.
   152: 
   153: bool WiFiControllerPCI::allocatePageBlock(pageBlock_t * p) {
   154:     UInt32 size = PAGE_SIZE;
   155: 
   156:     p->memory = IOBufferMemoryDescriptor::withOptions(kIOMemoryUnshared,
   157:                                                       size, PAGE_SIZE);
   158: 
   159:     if (p->memory == 0) return false;
   160: 
   161:     if (p->memory->prepare() != kIOReturnSuccess)
   162:     {
   163:         p->memory->release();
   164:         p->memory = 0;
   165:         return false;
   166:     }
   167: 
   168:     p->freeStart = p->memory->getBytesNoCopy();
   169:     p->freeBytes = p->memory->getCapacity();
   170:     bzero(p->freeStart, p->freeBytes);
   171:     
   172:     return true;
   173: }
   174: 
   175: //---------------------------------------------------------------------------
   176: // Function: freePageBlock
   177: //
   178: // Purpose:
   179: //   Deallocate a page of memory.
   180: //
   181: void WiFiControllerPCI::freePageBlock(pageBlock_t * p) {
   182:     if (p->memory) {
   183:         p->memory->complete();
   184:         p->memory->release();
   185:         p->memory = 0;
   186:     }
   187: }
   188: 
   189: //---------------------------------------------------------------------------
   190: // Function: allocateMemoryFrom
   191: //
   192: // Purpose:
   193: //   Allocate the next aligned chunk of memory in a page block.
   194: 
   195: void * WiFiControllerPCI::allocateMemoryFrom( pageBlock_t *       p,
   196:                                        UInt32              size,
   197:                                        UInt32              align,
   198:                                        IOPhysicalAddress * paddr ) {
   199:     void *      allocPtr;
   200:     IOByteCount segLength;
   201: 
   202:     if (align == 0)
   203:             return 0;
   204: 
   205:     // Locate next alignment boundary.
   206:     allocPtr = (void *)(((UInt32)p->freeStart + (align - 1)) & ~(align - 1));
   207: 
   208:     // Add alignment padding to the allocation size.
   209:     size += (UInt32) allocPtr - (UInt32) p->freeStart;
   210: 
   211:     if (size > p->freeBytes)
   212: 		return 0;
   213: 
   214:     p->freeStart  = (void *)((UInt32) p->freeStart + size);
   215:     p->freeBytes -= size;
   216: 
   217:     if (paddr) {
   218:         *paddr = p->memory->getPhysicalSegment(
   219:                  (UInt32) allocPtr - (UInt32) p->memory->getBytesNoCopy(),
   220:                  &segLength);
   221:     }
   222: 
   223:     return allocPtr;
   224: }
   225: 
   226: //---------------------------------------------------------------------------
   227: // Function: getPhysAddress
   228: //
   229: // Purpose:
   230: //   Get the physical address for a location described by a pageBlock.
   231: //
   232: bool WiFiControllerPCI::getPhysAddress( pageBlock_t *       pageBlock,
   233:                                         void *              virtAddress,
   234:                                         IOPhysicalAddress * physAddress ) {
   235:     IOPhysicalAddress paddr = 0;
   236:     IOByteCount       segLength;
   237: 
   238:     if (pageBlock && pageBlock->memory) {
   239:         paddr = pageBlock->memory->getPhysicalSegment(
   240:                     (UInt32) virtAddress -
   241:                     (UInt32) pageBlock->memory->getBytesNoCopy(),
   242:                     &segLength);
   243:     }
   244: 
   245:     *physAddress = paddr;
   246: 
   247:     return (paddr != 0);
   248: }
   249: