1: /*
     2:         
     3:         File:			GTDriver.cpp
     4:         Program:		GTDriver
     5: 		Author:			Michael Rossberg
     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 "GTDriver.h" 
    27: #include "GTFirmware.h" 
    28: 
    29: extern "C" {
    30: #include <sys/param.h> 
    31: #include <sys/mbuf.h> 
    32: #include <string.h> 
    33: 
    34: extern mutex_t		*mutex_alloc(
    35: 						unsigned short	tag);
    36: 
    37: extern void			mutex_free(
    38: 						mutex_t		*mutex);
    39: 
    40: extern void			mutex_lock(
    41: 						mutex_t		*mutex);
    42: 
    43: extern void			mutex_unlock(
    44: 						mutex_t		*mutex);
    45: 
    46: extern boolean_t	mutex_try(
    47: 						mutex_t		*mutex);
    48: }
    49: 
    50: #define GT_WRITEDELAY 1 
    51: #define abs(x)  ((x < 0) ? -x : x) 
    52: 
    53: #define super WiFiControllerPCI 
    54: OSDefineMetaClassAndStructors(GTDriver, WiFiControllerPCI)
    55: 
    56: const OSString* GTDriver::newModelString() const {
    57:     return OSString::withCString("Prism GT card");
    58: }
    59: 
    60: #pragma mark - 
    61: 
    62: bool GTDriver::startHardware() {
    63:     int i;
    64:     WLEnter();
    65: 
    66:     _mgmtMutex = mutex_alloc(0);
    67:     _dataMutex = mutex_alloc(0);
    68:     _interruptBusy = false;
    69:     _stalled = false;
    70:     
    71:     if (!_allocQueues()) return false;
    72:     if (!initHardware()) return false;
    73: 
    74:     //wait for intialization
    75:     for(i = 0; i < 1000; i++) {
    76:         if (_initialized) break;
    77:         IOSleep(1);
    78:     }
    79:     
    80:     if (!_updateMACAddress()) return false;
    81:     if (_enabledForNetif) enableHardware();
    82:     else disableHardware();
    83:     
    84:     WLExit();
    85: 
    86:     return true;
    87: }
    88: 
    89: bool GTDriver::initHardware() {
    90:     WLEnter();
    91:     
    92:     _dozing = false;
    93:  
    94:     if (!_uploadFirmware()) return false;
    95:     if (!_initHW()) return false;
    96:     
    97:     WLExit();
    98:     return true;
    99: };
   100: 
   101: bool GTDriver::freeHardware() {
   102:     WLEnter();
   103:     _initialized = false;
   104:     
   105:     disableHardware();
   106:     _freeQueues();
   107: 
   108:     mutex_free(_mgmtMutex);
   109:     mutex_free(_dataMutex);
   110:     WLExit();
   111:     return true;
   112: }
   113: 
   114: bool GTDriver::enableHardware() {
   115:     WLEnter();
   116:     
   117:     //_setValue(OID_CONFIG, INL_CONFIG_MANUALRUN);
   118:     _setValue(OID_MODE, INL_MODE_CLIENT);
   119:     _setValue(OID_MAXFRAMEBURST, DOT11_MAXFRAMEBURST_MIXED_SAFE);
   120:     _setValue(OID_AUTHENABLE, DOT11_AUTH_BOTH);
   121:     
   122:     UInt8 data[4];
   123:     memset(data, 0xFF, 2);
   124:     _setStruc(OID_SCAN, &data, 2);
   125:     
   126:     WLExit();
   127:     
   128:     return true;
   129: }
   130: 
   131: bool GTDriver::disableHardware() {
   132:     //disable the card
   133:     WLEnter();
   134:     
   135:     UInt8 data[4];
   136:     memset(data, 0x0, 2);
   137:     _setStruc(OID_SCAN, &data, 2);
   138: 
   139:     _setValue(OID_MODE, INL_MODE_NONE);
   140:     WLExit();
   141:     return true;
   142: }
   143: 
   144: bool GTDriver::getReadyForSleep() {
   145:     WLEnter();
   146:     
   147:     setRegister(GT_INT_EN_REG, 0);
   148:     setRegister(GT_CTRL_BLOCK, 0);
   149:     _txDataLowPos = _txDataHighPos = _txDataMgmtPos = 0;
   150:     _lastIndex = 0;
   151:     _controlBlock.cb->driver_curr_frag[QUEUE_RX_LOW] = OSSwapHostToLittleInt32(CB_RX_QSIZE);
   152:     _controlBlock.cb->driver_curr_frag[QUEUE_RX_HIGH] = OSSwapHostToLittleInt32(CB_RX_QSIZE);
   153:     _controlBlock.cb->driver_curr_frag[QUEUE_RX_MGMT] = OSSwapHostToLittleInt32(CB_MGMT_QSIZE);
   154: 
   155:     _freeTransmitQueues();
   156:     
   157:     WLExit();
   158:     return true;
   159: }
   160: 
   161: bool GTDriver::handleEjectionHardware() { 
   162:     bool mblocked, dblocked;
   163:     
   164:     if (!_controlBlock.cb) return true;
   165:     
   166:     WLLogDebug(
   167:       "CB drv Qs: [%d][%d][%d][%d][%d][%d]",
   168:       OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[0]),
   169:       OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[1]),
   170:       OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[2]),
   171:       OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[3]),
   172:       OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[4]),
   173:       OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[5])
   174:     );
   175: 
   176:     WLLogDebug(
   177:       "CB dev Qs: [%d][%d][%d][%d][%d][%d]",
   178:       OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[0]),
   179:       OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[1]),
   180:       OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[2]),
   181:       OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[3]),
   182:       OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[4]),
   183:       OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[5])
   184:     );
   185:     
   186:     mblocked = mutex_try(_mgmtMutex);
   187:     dblocked = mutex_try(_dataMutex);
   188:     if (mblocked) mutex_unlock(_mgmtMutex);
   189:     if (dblocked) mutex_unlock(_dataMutex);
   190:     
   191:     WLLogDebug(
   192:         "Allocated Packets: %d Freed Packets: %d Allocated RxPackets: %d Freed RxPackets: %d dataLowPos: %d dataHighPos: %d dataMgmtPos: %d mgmtMutex: %s dataMutex: %s interrupted: %s initalized: %s interruptPoint:%d lastIndex:%d",
   193:         (int)_allocated, (int)_freed, (int)_rxAllocated, (int)_rxFreed, 
   194:         (int)_txDataLowPos, (int)_txDataHighPos, (int)_txDataMgmtPos,
   195:         (!mblocked ? "locked" : "not locked"), (!dblocked ? "locked" : "not locked"),
   196:         (_interruptBusy ? "running" : "not running"),
   197:         (_initialized ? "init" : "not init"),
   198:         _interruptPoint, (int)_lastIndex
   199:     );
   200:     
   201:     return true; 
   202: }
   203: 
   204: typedef struct {
   205: 	UInt16 unk0;		/* = 0x0000 */
   206: 	UInt16 length;		/* = 0x1400 */
   207: 	UInt32 clock;		/* 1MHz clock */
   208: 	volatile UInt8 flags;
   209: 	UInt8 unk1;
   210: 	volatile UInt8 rate;
   211: 	UInt8 unk2;
   212: 	volatile UInt16 freq;
   213: 	UInt16 unk3;
   214: 	volatile UInt8 rssi;
   215: 	UInt8 padding[3];
   216: } rfmonHeader;
   217: 
   218: bool GTDriver::handleInterrupt() {
   219:     UInt32 ident;
   220:     rfmonHeader *rfHead;
   221:     
   222:     //WLEnter();
   223:     
   224:     if (getRegister(GT_CTRL_STAT_REG) & GT_CTRL_STAT_SLEEPMODE) {
   225:         WLLogDebug("Got an interrupt from a sleeping device!");
   226:         return false;
   227:     }
   228:     
   229:     ident = getRegister(GT_INT_IDENT_REG) & GT_INT_SOURCES;
   230:     if (ident==0) {
   231:         WLLogWarn("Got an interrupt which cannot be handled!");
   232:         return false;
   233:     }
   234:     
   235:     //acknowledge the interrupt
   236:     setRegister(GT_INT_ACK_REG, ident);
   237:         
   238:     _dozing = false;
   239:     if (ident & GT_INT_IDENT_INIT) {
   240:         _currentState = stateDisconnected;
   241:         _initialized = true;
   242:     }
   243:     if (ident & GT_INT_IDENT_WAKEUP) {
   244:         setRegister(GT_DEV_INT_REG, GT_DEV_INT_UPDATE);
   245:         _dozing = false;
   246:     }
   247:     if ((ident & GT_INT_IDENT_UPDATE) != 0 && _initialized) {
   248:         
   249:         SInt32 count;
   250:         bool updated = false;
   251:         
   252:         for (count = _inQueue(QUEUE_RX_MGMT); count > 0; count--) {
   253:             updated = true;
   254:             //because we fill our buffers completly, we can get the first message in this way...
   255:             UInt32 frag = OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[QUEUE_RX_MGMT]);
   256:             UInt32 fragMod = frag % CB_MGMT_QSIZE;
   257:             
   258:             _parsePIMFOR(_rxDataMgmt[fragMod]);
   259:             
   260:             _allocPacketForFragment(&_rxDataMgmt[fragMod], &_controlBlock.cb->rx_data_mgmt[fragMod]);
   261:             _controlBlock.cb->driver_curr_frag[QUEUE_RX_MGMT] = OSSwapHostToLittleInt32(++frag);
   262:         }
   263: 
   264:         for (count = _inQueue(QUEUE_RX_HIGH); count > 0; count--) {
   265:             updated = true;
   266:             //because we fill our buffers completly, we can get the first message in this way...
   267:             UInt32 frag = OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[QUEUE_RX_HIGH]);
   268:             UInt32 fragMod = frag % CB_RX_QSIZE;
   269:             
   270:             if (_enabledForNetif) {
   271:                 mbuf_adj(_rxDataHigh[fragMod], 2);
   272:                 _netif->inputPacket(_rxDataHigh[fragMod], OSSwapLittleToHostInt16(_controlBlock.cb->rx_data_high[fragMod].size),
   273:                                    IONetworkInterface::kInputOptionQueuePacket);
   274:                 _netStats->inputPackets++;
   275:                 _rxFreed++;
   276:             } else {
   277:                 freePacket(_rxDataHigh[fragMod]);
   278:                 _rxFreed++;
   279:             }
   280:             
   281:             _allocPacketForFragment(&_rxDataHigh[fragMod], &_controlBlock.cb->rx_data_high[fragMod]);
   282:             _controlBlock.cb->driver_curr_frag[QUEUE_RX_HIGH] = OSSwapHostToLittleInt32(++frag);
   283:         }
   284:                 
   285:         for (count = _inQueue(QUEUE_RX_LOW); count > 0; count--) {
   286:             updated = true;
   287:             //because we fill our buffers completly, we can get the first message in this way...
   288:             UInt32 frag = OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[QUEUE_RX_LOW]);
   289:             UInt32 fragMod = frag % CB_RX_QSIZE;
   290:             
   291:             if (_mode == modeMonitor) {
   292:                 rfHead = (rfmonHeader*)mbuf_data(_rxDataLow[fragMod]);
   293:                 if ((rfHead->flags & 0x01) == 0x0) {
   294:                     if (!_packetQueue->enqueue(mbuf_data(_rxDataLow[fragMod]), OSSwapLittleToHostInt16(_controlBlock.cb->rx_data_low[fragMod].size))) WLLogInfo("packet queue overflow");
   295:                 } else WLLogErr("dropping packet");
   296:                 
   297:                 mbuf_adj(_rxDataLow[fragMod], 20);
   298:                 //_rawNetif->inputPacket(_rxDataLow[fragMod], OSSwapLittleToHostInt16(_controlBlock.cb->rx_data_low[fragMod].size),
   299:                 //                   IONetworkInterface::kInputOptionQueuePacket);
   300:                 freePacket(_rxDataLow[fragMod]);                
   301:             } else if (_enabledForNetif) {
   302:                 mbuf_adj(_rxDataLow[fragMod], 2);
   303:                 _netif->inputPacket(_rxDataLow[fragMod], OSSwapLittleToHostInt16(_controlBlock.cb->rx_data_low[fragMod].size),
   304:                                    IONetworkInterface::kInputOptionQueuePacket);
   305:                 _netStats->inputPackets++;
   306:             } else {
   307:                 freePacket(_rxDataLow[fragMod]);
   308:             }
   309:             
   310:             _allocPacketForFragment(&_rxDataLow[fragMod], &_controlBlock.cb->rx_data_low[fragMod]);
   311:             _controlBlock.cb->driver_curr_frag[QUEUE_RX_LOW] = OSSwapHostToLittleInt32(++frag);
   312:         }
   313:         
   314:         _freeTransmitQueues();
   315: 
   316:         if (updated) { //tickle the device
   317:             setRegister(GT_DEV_INT_REG, GT_DEV_INT_UPDATE);
   318:             if (_enabledForNetif) _netif->flushInputQueue();
   319:         }
   320:     }
   321:     if (ident & GT_INT_IDENT_SLEEP) {
   322:         UInt32 i;
   323:         for (i = QUEUE_RX_LOW; i <= QUEUE_TX_MGMT; i++) {
   324:             if (_inQueue(i)) break;
   325:         }
   326:         if (i > QUEUE_TX_MGMT) {
   327:             WLLogInfo("Going to sleep");
   328:             setRegister(GT_DEV_INT_REG, GT_DEV_INT_SLEEP);
   329:             _dozing = true;
   330:         }
   331:     }
   332:     //WLExit();
   333: 
   334:     return true;
   335: }
   336: 
   337: bool GTDriver::handleTimer() {
   338:     if (_linkSpeed) {
   339:         _getValue(OID_LINKSTATE);
   340:         _getValue(OID_BSSID, 6);
   341:         //_getValue(OID_TXPOWER);
   342:     } else {
   343:         WLLogDebug("NO Link present");
   344:     }
   345:     _getValue(OID_BSS_LIST, sizeof(objBSSList));
   346:     return true;
   347: }
   348: 
   349: IOReturn GTDriver::outputPacketHardware(mbuf_t m) {
   350:     return _transmitInQueue(m, QUEUE_TX_LOW);
   351: }
   352: 
   353: IOReturn GTDriver::setHardwareAddressHardware(UInt8 *addr) { 
   354:     return _setStruc(OID_MACADDRESS, addr, 6) ? kIOReturnSuccess : kIOReturnError; 
   355: }
   356: 
   357: #pragma mark - 
   358: 
   359: UInt32 GTDriver::getLinkSpeed() { 
   360:     return _linkSpeed; 
   361: }
   362: 
   363: bool GTDriver::setSSID(UInt32 length, UInt8* ssid) { 
   364:     UInt8 data[34];
   365:  
   366:     super::setSSID(length, ssid);
   367:        
   368:     memset(data, 0, 34);
   369:     memcpy(&data[1], _ssid, _ssidLength);
   370:     data[0] = _ssidLength;
   371:     
   372:     return _setStruc(OID_SSID, data, 34);
   373: }
   374: 
   375: bool GTDriver::setKey(UInt32 length, UInt8* key) { 
   376:     keyObject k;
   377:     
   378:     length = length > 32 ? 32 : length;
   379:     memset(&k, 0, sizeof(k));
   380:     memcpy(&k.key, key, length);
   381:     k.len = length;
   382:     
   383:     _setStruc(OID_DEFKEY1, &k, sizeof(k));
   384:     _setValue(OID_DEFKEYID, 0);
   385:     _setValue(OID_PRIVACYINVOKED, length ? 1 : 0);
   386:     
   387:     WLLogInfo("Setting hex key with length: %d", (int)length);
   388:     
   389:     return true;
   390: }
   391: 
   392: UInt32 GTDriver::getFrequency() { 
   393:     _getValue(OID_FREQUENCY, 4, true);
   394:     return _currentFrequency; 
   395: };
   396: 
   397: bool GTDriver::setFrequency(UInt32 frequency) { 
   398:     _setValue(OID_FREQUENCY, frequency, true);
   399:     _getValue(OID_FREQUENCY, 4, true);
   400:     return frequency == _currentFrequency;
   401: }
   402: 
   403: bool GTDriver::setMode(wirelessMode mode) { 
   404:     switch(mode) {
   405:         case modeClient:
   406:             _setValue(OID_CONFIG, INL_CONFIG_NOTHING);
   407:             _setValue(OID_MODE, INL_MODE_CLIENT);
   408:             _setValue(OID_BSSTYPE, DOT11_BSSTYPE_INFRA);
   409:             break;
   410:         case modeIBSS:
   411:             _setValue(OID_CONFIG, INL_CONFIG_NOTHING);
   412:             _setValue(OID_MODE, INL_MODE_CLIENT);
   413:             _setValue(OID_BSSTYPE, DOT11_BSSTYPE_IBSS);
   414:             break;
   415:         case modeMonitor:
   416:             WLLogCrit("Enabling monitor mode!");
   417:             _setValue(OID_CONFIG, INL_CONFIG_RXANNEX);
   418:             _setValue(OID_MODE, INL_MODE_PROMISCUOUS);
   419:             break;
   420:         default:
   421:             WLLogErr("Unsupported mode %d", mode);
   422:             return false;
   423:     }
   424:     _mode = mode;
   425:     return true;
   426: }
   427: 
   428: #pragma mark - 
   429: 
   430: bool GTDriver::_updateMACAddress() {
   431:     for (int i = 0; i < 10; i++) //try a couple of times
   432:         if (_getValue(OID_MACADDRESS, 6, true)) return true;
   433: 
   434:     return false;
   435: }
   436: 
   437: bool GTDriver::_uploadFirmware() {
   438:     UInt32 statReg;
   439:     UInt32 firmReg, bcount, length, temp;
   440:     const UInt8 *buf;
   441:     
   442:     WLEnter();
   443:     
   444:     _initialized = false;
   445:     
   446:     /* clear the RAMBoot and the Reset bit */
   447:     statReg = getRegister(GT_CTRL_STAT_REG);
   448:     statReg &= ~GT_CTRL_STAT_RESET;
   449:     statReg &= ~GT_CTRL_STAT_RAMBOOT;
   450:     setRegister(GT_CTRL_STAT_REG, statReg, true, false);
   451:     IODelay(GT_WRITEDELAY);
   452:     
   453:     /* set the Reset bit without reading the register ! */
   454:     statReg |= GT_CTRL_STAT_RESET;
   455:     setRegister(GT_CTRL_STAT_REG, statReg, true, false);
   456:     IODelay(GT_WRITEDELAY);
   457:     
   458:     /* clear the Reset bit */
   459:     statReg &= ~GT_CTRL_STAT_RESET;
   460:     setRegister(GT_CTRL_STAT_REG, statReg, true, false);
   461:     IOSleep(50);
   462:     
   463:     // upload
   464:     // prepare the Direct Memory Base register
   465:     firmReg = GT_DEV_FIRMWARE_ADDRESS;
   466: 
   467:     // enter a loop which reads data blocks from the file and writes them
   468:     // to the Direct Memory Windows
   469:     buf = gtFirmware;
   470:     bcount = gtFirmwareSize;
   471: 
   472:     do {
   473:         // set the cards base address for writting the data
   474:         setRegister(GT_DIR_MEM_BASE_REG, firmReg);
   475:         IODelay(GT_WRITEDELAY);
   476: 
   477:         WLLogDebug("upload firmware... %d bytes left", (int)bcount);
   478:         
   479:         if (bcount > GT_MEMORY_WINDOW_SIZE) {
   480:             length = GT_MEMORY_WINDOW_SIZE;
   481:             bcount -= GT_MEMORY_WINDOW_SIZE;
   482:         } else {
   483:             length = bcount;
   484:             bcount = 0;
   485:         }
   486:         
   487:         // write the data to the Direct Memory Window
   488:         for(temp = 0; temp < length; temp += 4) {
   489:             setRegister(GT_DIRECT_MEM_WIN + temp, *(((UInt32*)buf) + temp/4), false, false);
   490:             //IODelay(GT_WRITEDELAY);
   491:         }
   492: 
   493:         getRegister(GT_INT_EN_REG);
   494: 			
   495:         // increment the write address
   496:         firmReg += GT_MEMORY_WINDOW_SIZE;
   497:         buf += length;
   498:     } while (bcount != 0);
   499:     
   500:     /* now reset the device
   501:      * clear the Reset & ClkRun bit, set the RAMBoot bit */
   502:     statReg = getRegister(GT_CTRL_STAT_REG) & ~GT_CTRL_STAT_RESET;
   503:     setRegister(GT_CTRL_STAT_REG, statReg, true, false);
   504:     IODelay(GT_WRITEDELAY);
   505:     
   506:     statReg |= GT_CTRL_STAT_RAMBOOT;
   507:     statReg &= ~GT_CTRL_STAT_RESET;
   508:     setRegister(GT_CTRL_STAT_REG, statReg, true, false);
   509:     IODelay(GT_WRITEDELAY);
   510:     
   511:     /* set the reset bit latches the host override and RAMBoot bits
   512:      * into the device for operation when the reset bit is reset */
   513:     statReg |= GT_CTRL_STAT_RESET;
   514:     setRegister(GT_CTRL_STAT_REG, statReg, true, false);
   515:     IODelay(GT_WRITEDELAY);
   516:     
   517:     /* clear the reset bit should start the whole circus */
   518:     statReg &= ~GT_CTRL_STAT_RESET;
   519:     setRegister(GT_CTRL_STAT_REG, statReg, true, false);
   520:     IODelay(GT_WRITEDELAY);
   521:     IOSleep(50);
   522:     
   523:     WLExit();
   524:     
   525:     return true;
   526: }
   527: 
   528: bool GTDriver::_initHW() {
   529:     _initialized = false;
   530:     
   531:     setRegister(GT_CTRL_BLOCK, _controlBlock.dmaAddress, true, false);
   532:     IODelay(GT_WRITEDELAY);
   533:     
   534:     setRegister(GT_DEV_INT_REG, GT_DEV_INT_RESET, true, false);
   535:     IODelay(GT_WRITEDELAY);
   536:     
   537:     setRegister(GT_INT_EN_REG, GT_INT_IDENT_INIT | GT_INT_IDENT_UPDATE | GT_INT_IDENT_SLEEP | GT_INT_IDENT_WAKEUP);
   538:     IODelay(GT_WRITEDELAY);
   539: 
   540:     return true;
   541: }
   542: 
   543: IOReturn GTDriver::_transmitInQueue(mbuf_t m, int queue) {
   544:     UInt32 queueSize, driverPos, i, freeFrags, offset, count;
   545:     volatile gt_fragment *f;
   546:     mutex_t *l;
   547:     mbuf_t* q;
   548:     mbuf_t nm = NULL;
   549:     struct IOPhysicalSegment vector[MAX_FRAGMENT_COUNT];
   550:     
   551:     if (_cardGone || _controlBlock.cb == NULL) return kIOReturnOutputDropped;
   552:              
   553:     switch(queue) {
   554:         case QUEUE_TX_LOW:
   555:             l = _dataMutex;
   556:             queueSize = CB_TX_QSIZE;
   557:             f = _controlBlock.cb->tx_data_low;
   558:             q = _txDataLow;
   559:             break;
   560:         case QUEUE_TX_HIGH:
   561:             l = _dataMutex;
   562:             queueSize = CB_TX_QSIZE;
   563:             f = _controlBlock.cb->tx_data_high;
   564:             q = _txDataHigh;
   565:             break;
   566:         case QUEUE_TX_MGMT:
   567:             l = _mgmtMutex;
   568:             queueSize = CB_MGMT_QSIZE;
   569:             f = _controlBlock.cb->tx_data_mgmt;
   570:             q = _txDataMgmt;
   571:             break;
   572:         default:
   573:             WLLogEmerg("Unknown Queue for transmittion. This is a bug!");
   574:             return kIOReturnOutputDropped;
   575:     }
   576:     
   577:     mutex_lock(l);
   578:     
   579:     freeFrags = _freeFragmentsInQueue(queue);
   580:     i = 0;
   581:         
   582:     while (freeFrags == 0) {
   583:         mutex_unlock(l);
   584:         _stalled = true;
   585:         return kIOReturnOutputStall;
   586:     
   587:         _freeTransmitQueues();
   588:         freeFrags = _freeFragmentsInQueue(queue);
   589:         if (freeFrags) break;
   590:         
   591:         IOSleep(1);
   592:         
   593:         if (++i > 1000) {
   594:             WLLogDebug("Queue full queueSize %d device %d", (int)queueSize, OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[queue]));
   595:         
   596:             mutex_unlock(l);
   597:             return kIOReturnOutputDropped;
   598:         }
   599:     }
   600: 
   601:     if (freeFrags > MAX_FRAGMENT_COUNT) freeFrags = MAX_FRAGMENT_COUNT;    //at most 4 fragments in queue
   602:     offset = (4 - ((int)(mbuf_data(m)) & 3)) % 4;    //packet needs to be 4 byte aligned
   603:     driverPos = OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[queue]);
   604:     
   605:     if (offset) { 
   606:         //if the packet is unaligned, make a copy so it is aligned :-O~
   607:         //if (freeFrags == 1) {
   608:             nm = copyPacket(m, 0);
   609:             _allocated++;
   610:             if (!_fillFragment(&f[driverPos % queueSize], nm)) goto fillError;
   611:             freePacket(m);
   612:             _freed++;
   613:             m = nm;
   614:             goto copyDone;
   615:         /*} else { //broken
   616:             //make up more fragments to avoid copying of large buffers
   617:             nm = copyPacket(m, offset);
   618:             WLLogDebug("freeFrags: %d offset: %d nm: 0x%x packet len %d data 0x%x driverPos %d ringPos: %d", freeFrags, offset, nm, nmbuf_len(m), *mtod(nm, int*), driverPos, _txDataLowPos);
   619:             if (!_fillFragment(&f[driverPos % queueSize], nm, FRAGMENT_FLAG_MF)) goto fillError;
   620:             WLLogDebug("fsize: 0x%x flags: 0x%x address:0x%x", f[driverPos % queueSize].size,  f[driverPos % queueSize].flags, OSSwapLittleToHostInt32(f[driverPos % queueSize].address));
   621:             m_adj(m, offset);
   622:             q[driverPos % queueSize] = nm;
   623:             driverPos++;
   624:             freeFrags--;
   625:         }*/
   626:     }
   627: 
   628:     count = _mbufCursor->getPhysicalSegmentsWithCoalesce(m, vector, 1);
   629:     if (count == 0) {
   630:         WLLogEmerg("Could not allocated a nice mbuf!");
   631:         goto genericError;
   632:     }
   633:     
   634:     count--;
   635:     /*for (i = 0; i < count; i--) {
   636:         WLLogDebug("assemble fragment number %d. address 0x%x", count, vector[count].location);
   637:         f[driverPos % queueSize].address = vector[count].location;	// cursor is little-endian
   638:         f[driverPos % queueSize].size = *((UInt16*)(&vector[count].length));
   639:         f[driverPos % queueSize].flags = OSSwapHostToLittleConstInt16(FRAGMENT_FLAG_MF);
   640:         driverPos++;
   641:     }*/
   642:     
   643:     if (OSSwapLittleToHostInt32(vector[count].location) & 3) WLLogDebug("Warning: trying to transmit unaligned packet!");
   644:     f[driverPos % queueSize].address = vector[count].location;	// cursor is little-endian
   645:     f[driverPos % queueSize].size = *((UInt16*)(&vector[count].length));
   646:     f[driverPos % queueSize].flags = 0;
   647: 
   648: copyDone:
   649:     q[driverPos % queueSize] = m;
   650:     _controlBlock.cb->driver_curr_frag[queue] = OSSwapHostToLittleInt32(++driverPos);
   651:     
   652:     mutex_unlock(l);
   653: 
   654:     _allocated++;
   655:     
   656:     if (_dozing) {
   657:         setRegister(GT_DEV_INT_REG, GT_DEV_INT_WAKEUP);
   658:         IODelay(GT_WRITEDELAY);
   659:         WLLogDebug("Try to wakeup the device");
   660:     } else {
   661:         setRegister(GT_DEV_INT_REG, GT_DEV_INT_UPDATE);
   662:         IODelay(GT_WRITEDELAY);
   663:     }
   664:  
   665:     return kIOReturnOutputSuccess;
   666:     
   667: fillError:
   668:     WLLogEmerg("Could not fill fragment for packet!");
   669: 
   670: genericError:
   671:     mutex_unlock(l);
   672:     if (nm) freePacket(nm);
   673:     return kIOReturnOutputDropped;
   674: }
   675: 
   676: #pragma mark - 
   677: 
   678: bool GTDriver::_setStruc(UInt32 oid, void* data, UInt32 len, bool waitForResponse) {
   679:     return _transmitPIM(PIMFOR_OP_SET, oid, len, data, waitForResponse);
   680: }
   681: 
   682: bool GTDriver::_setValue(UInt32 oid, UInt32 value, bool waitForResponse) {
   683:     value = OSSwapHostToLittleInt32(value);
   684:     return _setStruc(oid, &value, 4, waitForResponse);
   685: }
   686: 
   687: bool GTDriver::_getValue(UInt32 oid, UInt32 len, bool waitForResponse) {
   688:     return _transmitPIM(PIMFOR_OP_GET, oid, len, NULL, waitForResponse);
   689: }
   690: 
   691: void GTDriver::_fillPIMFOR(UInt32 operation, UInt32 oid, UInt32 length, pimforHeader *h) {
   692:     h->version = PIMFOR_VERSION;
   693:     h->operation = operation;
   694:     h->device_id = PIMFOR_DEV_ID_MHLI_MIB;
   695:     h->flags = 0;
   696:     h->oid = OSSwapHostToBigInt32(oid);
   697:     h->length = OSSwapHostToBigInt32(length);
   698: }
   699: 
   700: bool GTDriver::_transmitPIM(UInt32 operation, UInt32 oid, UInt32 length, void* data, bool waitForResponse) {
   701:     mbuf_t packet;
   702:     
   703:     //WLEnter();
   704:     _doAsyncIO = waitForResponse;
   705:     
   706:     packet = allocatePacket(length + PIMFOR_HEADER_SIZE);
   707:     if (!packet) {
   708:         WLLogEmerg("Could not allocate Managment frame header!");
   709:         return false;
   710:     }
   711:     
   712:     _fillPIMFOR(operation, oid, length, (pimforHeader*)mbuf_data(packet));
   713:     if ((length>0) && (data!=NULL)) {
   714:         memcpy((UInt8*)mbuf_data(packet) + PIMFOR_HEADER_SIZE, data, length);
   715:     }
   716:     
   717:     if (_transmitInQueue(packet, QUEUE_TX_MGMT) != kIOReturnOutputSuccess) {
   718:         freePacket(packet);
   719:         return false;
   720:     }
   721:     
   722:     if (waitForResponse) {
   723:         int i;
   724:         for (i = 0; i < 10000; i++) {
   725:             if (_doAsyncIO == false) break;
   726:             IOSleep(1);
   727:         }
   728:         if (i == 10000) {
   729:             WLLogInfo("Timeout for PIMFOR with OID 0x%x", (int)oid);
   730:             return false;
   731:         }
   732:     }
   733:     //WLExit();
   734:     
   735:     return true;
   736: }
   737: 
   738: bool GTDriver::_parsePIMFOR(mbuf_t m) {
   739:     bool ret = false;
   740:     pimforHeader *h;
   741:     void *data;
   742:     UInt32 operation, oid, version, linkSpeed;
   743:     UInt32 length;
   744:     objBSSList *bssList;
   745:     //WLEnter();
   746:     
   747:     if (!m) {
   748:         WLLogErr("Got an empty MBUF structure!");
   749:         return false;
   750:     }
   751:     
   752:     do {
   753:         if (mbuf_len(m) < PIMFOR_HEADER_SIZE) {
   754:             WLLogErr("Recieved short PIMFOR message");
   755:             break;
   756:         }
   757:         h = (pimforHeader*)mbuf_data(m);
   758:         
   759:         version = h->version;
   760:         if (version != PIMFOR_VERSION) {
   761:             WLLogErr("Recieved incompatible PIMFOR message. Version %d. mbuf address 0x%x", (int)version, (int)mbuf_data(m));
   762:             break;
   763:         }
   764:         
   765:         length = OSSwapBigToHostInt32(h->length);
   766:         if (length) {
   767:             if (mbuf_len(m) < length + PIMFOR_HEADER_SIZE) break;
   768:             data = (void*)(h + 1);
   769:         } else {
   770:             data = NULL;
   771:         }
   772:  
   773:         operation = h->operation;
   774:         if (operation == PIMFOR_OP_ERROR) {
   775:             WLLogErr("The Card reported an Operation error for OID 0x%x length: %d.", OSSwapBigToHostInt32(h->oid), (int)length);
   776:             break;
   777:         }
   778:         if ((operation != PIMFOR_OP_RESPONSE) && (operation != PIMFOR_OP_TRAP)) {
   779:             WLLogErr("Recieved PIMFOR with invalid operation! operation: 0x%x", (int)operation);
   780:             break;
   781:         }
   782:         
   783:         oid = OSSwapBigToHostInt32(h->oid);
   784:         switch(oid) {
   785:             case OID_MACADDRESS:
   786:                 if (length != 6) {
   787:                     WLLogErr("MAC Address has wrong length! len: 0x%x m_len: 0x%x", (int)length, (int)mbuf_len(m));
   788:                     break;
   789:                 }
   790:                 memcpy(&_myAddress, data, 6);
   791: 
   792:                 WLLogInfo("Set MAC Address...");
   793:                 
   794:                 break;
   795:             case OID_LINKSTATE:
   796:                 if (length != 4) {
   797:                     WLLogErr("LinkState has wrong length! len: 0x%x m_len: 0x%x", (int)length, (int)mbuf_len(m));
   798:                     break;
   799:                 }
   800: 
   801:                 linkSpeed = OSSwapLittleToHostInt32(*((UInt32*)data));
   802:                 if (linkSpeed != _linkSpeed) {
   803:                     _linkSpeed = linkSpeed;
   804:                     setLinkStatus(kIONetworkLinkValid | (_linkSpeed ? kIONetworkLinkActive : 0), _getMediumWithType(MEDIUM_TYPE_AUTO), _linkSpeed * 5000000);
   805:                     if (_linkSpeed == 0) _currentState = stateDisconnected;
   806:                 }
   807:                 break;
   808:             case OID_BSSID:
   809:                 if (length != 6) {
   810:                     WLLogErr("MAC BSSID has wrong length! len: 0x%x m_len: 0x%x", (int)length, (int)mbuf_len(m));
   811:                     break;
   812:                 }
   813:                 
   814:                 memcpy(_currentBSSID, data, 6);
   815:                 break;
   816:             case OID_FREQUENCY:
   817:                 if (length != 4) {
   818:                     WLLogErr("Frequency has wrong length! len: 0x%x m_len: 0x%x", (int)length, (int)mbuf_len(m));
   819:                     break;
   820:                 }
   821:                 
   822:                 _currentFrequency =  OSSwapLittleToHostInt32(*((int*)data));
   823:                 WLLogInfo("Current frequency is %d", (int)_currentFrequency);
   824:                 break;
   825:             case OID_TXPOWER:
   826:                 if (length != 4) {
   827:                     WLLogErr("Tx Power has wrong length! len: 0x%x m_len: 0x%x", (int)length, (int)mbuf_len(m));
   828:                     break;
   829:                 }
   830:                 
   831:                 WLLogInfo("Current TX Power: %u dBm", OSSwapLittleToHostInt32(*((int*)data)) / 4);
   832:                 break;
   833:             case OID_DEAUTHENTICATE:
   834:                 WLLogInfo("Deauthenicated");
   835:                 _currentState = stateDeauthenticated;
   836:                 break;
   837:             case OID_AUTHENTICATE:
   838:                 WLLogInfo("Authenticated");
   839:                 _currentState = stateAuthenicated;
   840:                 break;
   841:             case OID_ASSOCIATE:
   842:                 WLLogInfo("Associated");
   843:                 _currentState = stateAssociated;
   844:                 break;
   845:             case OID_DISASSOCIATE:
   846:                 WLLogInfo("Disassociated");
   847:                 _currentState = stateDisassociated;
   848:                 break;
   849:             case OID_BSS_LIST:
   850:                 if (length < 4) {
   851:                     WLLogErr("BSS list has wrong length! len: 0x%x m_len: 0x%x", (int)length, (int)mbuf_len(m));
   852:                     break;
   853:                 }
   854:                 
   855:                 bssList = (objBSSList*)data;
   856:                 if (OSSwapLittleToHostInt32(bssList->nr) > MAX_BSS_COUNT) {
   857:                     WLLogErr("BSS list is too big! (%d)", (int)bssList->nr);
   858:                     break;
   859:                 }
   860:                 
   861:                 _bssListCount = OSSwapLittleToHostInt32(bssList->nr);
   862:                 for (UInt32 i = 0; i < _bssListCount; i++) {
   863:                     _bssList[i].ssidLength = bssList->bssList[i].ssid[0];
   864:                     memcpy(_bssList[i].ssid, &bssList->bssList[i].ssid[1], _bssList[i].ssidLength > 32 ? 32 : _bssList[i].ssidLength);
   865:                     memcpy(_bssList[i].address, bssList->bssList[i].address, 6);
   866:                     _bssList[i].cap = bssList->bssList[i].capinfo;
   867:                     if (memcmp(_currentBSSID, _bssList[i].address, 6) == 0) _bssList[i].active = 1;
   868:                     else _bssList[i].active = 0;
   869:                 }
   870:                 WLLogInfo("Found %d Networks!", (int)_bssListCount);
   871:                 break;
   872:             default:
   873:                 WLLogInfo("Unhandled PIMFOR OID! OID: 0x%x", (int)oid);
   874:                 break;
   875:         }
   876:     
   877:         ret = true;
   878:     } while(false);
   879:     
   880:     _doAsyncIO = false;
   881:     freePacket(m);
   882:     _rxFreed++;
   883:     
   884:     //WLExit()
   885:     
   886:     return ret;
   887: }
   888: 
   889: #pragma mark - 
   890: 
   891: int GTDriver::_inQueue(int queue) {
   892:     if (!_controlBlock.cb) return 0;
   893:     
   894:     const SInt32 delta = (OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[queue]) -
   895:                             OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[queue]));
   896: 
   897:     /* determine the amount of fragments in the queue depending on the type
   898:      * of the queue, either transmit or receive */
   899:     if (delta < 0) goto realityError;
   900:     
   901:     switch (queue) {
   902:             /* send queues */
   903:     case QUEUE_TX_MGMT:
   904:             if (delta > CB_MGMT_QSIZE) goto realityError;
   905:             return delta;
   906:     case QUEUE_TX_LOW:
   907:     case QUEUE_TX_HIGH:
   908:             if (delta > CB_TX_QSIZE) goto realityError;
   909:             return delta;
   910:             
   911:             /* receive queues */
   912:     case QUEUE_RX_MGMT:
   913:             if (delta > CB_MGMT_QSIZE) goto realityError;
   914:             return CB_MGMT_QSIZE - delta;
   915:     case QUEUE_RX_LOW:
   916:     case QUEUE_RX_HIGH:
   917:             if (delta > CB_RX_QSIZE) goto realityError;
   918:             return CB_RX_QSIZE - delta;
   919:     }
   920: 
   921: realityError:
   922:     WLLogEmerg("In Queue reality error. This is a bug!");
   923:     return 0;
   924: }
   925: 
   926: UInt32 GTDriver::_freeFragmentsInQueue(int queue) {
   927:     UInt32 queueSize, driverPos, devicePos;
   928:     switch(queue) {
   929:         case QUEUE_TX_LOW:
   930:             queueSize = CB_TX_QSIZE;
   931:             devicePos = _txDataLowPos;
   932:             break;
   933:         case QUEUE_TX_HIGH:
   934:             queueSize = CB_TX_QSIZE;
   935:             devicePos = _txDataHighPos;
   936:             break;
   937:         case QUEUE_TX_MGMT:
   938:             queueSize = CB_MGMT_QSIZE;
   939:             devicePos = _txDataMgmtPos;
   940:             break;
   941:         default:
   942:             WLLogEmerg("Unknown Queue for transmittion. This is a bug!");
   943:             return 0;
   944:     }
   945:     
   946:     driverPos = OSSwapLittleToHostInt32(_controlBlock.cb->driver_curr_frag[queue]);
   947:     
   948:     if ((int)(devicePos + queueSize - driverPos) < 0) {
   949:         WLLogEmerg("WARNING txRing %d ran over", queue);
   950:         return 0;
   951:     }
   952:     return  (devicePos + queueSize - driverPos);
   953: }
   954: 
   955: bool GTDriver::_fillFragment(volatile gt_fragment *f, mbuf_t packet, UInt16 flags) {
   956:     struct IOPhysicalSegment vector;
   957:     UInt32 count;
   958: 
   959:     count = _mbufCursor->getPhysicalSegmentsWithCoalesce(packet, &vector, 1);
   960:     if (count == 0) {
   961:         WLLogEmerg("Could not allocated a nice mbuf!");
   962:         return false;
   963:     }
   964:     
   965:     if (OSSwapLittleToHostInt32(vector.location) & 3) {
   966:         WLLogEmerg("Warning trying to transmit unaligned packet!");
   967:     }
   968:     
   969:     f->address = vector.location;	// cursor is little-endian
   970:     f->size = *((UInt16*)(&vector.length));
   971:     f->flags = OSSwapHostToLittleInt16(flags);
   972:     
   973:     return true;
   974: }
   975: 
   976: bool GTDriver::_allocPacketForFragment(mbuf_t *packet, volatile gt_fragment *f) {
   977:     (*packet) = allocatePacket(MAX_FRAGMENT_SIZE);
   978:     if (!(*packet)) {
   979:         WLLogEmerg("Could not alloc Packet for Queue!");
   980:         return false;
   981:     }
   982:     
   983:     return _fillFragment(f, (*packet));
   984: }
   985: 
   986: #pragma mark - 
   987: 
   988: bool GTDriver::_allocQueues() {
   989:     int i;
   990:     
   991:     WLEnter();
   992:     
   993:     _freeQueues();
   994:     
   995:     if (!allocatePageBlock(&_controlBlock.page)) return false;
   996:     _controlBlock.cb = (gt_control_block*) allocateMemoryFrom(&_controlBlock.page, sizeof(gt_control_block), CACHE_ALIGNMENT, &_controlBlock.dmaAddress);
   997:     if (!_controlBlock.cb) return false;
   998:     
   999:     _txDataLowPos = _txDataHighPos = _txDataMgmtPos = 0;
  1000:     
  1001:     for(i = 0; i < CB_RX_QSIZE; i++) {
  1002:         _allocPacketForFragment(&_rxDataLow[i], &_controlBlock.cb->rx_data_low[i]);
  1003:     }
  1004:     _controlBlock.cb->driver_curr_frag[QUEUE_RX_LOW] = OSSwapHostToLittleInt32(CB_RX_QSIZE);
  1005:     _lastIndex = 0;
  1006:     
  1007:     for(i = 0; i < CB_RX_QSIZE; i++) {
  1008:         _allocPacketForFragment(&_rxDataHigh[i], &_controlBlock.cb->rx_data_high[i]);
  1009:     }
  1010:     _controlBlock.cb->driver_curr_frag[QUEUE_RX_HIGH] = OSSwapHostToLittleInt32(CB_RX_QSIZE);
  1011:     
  1012:     for(i = 0; i < CB_MGMT_QSIZE; i++) {
  1013:         _allocPacketForFragment(&_rxDataMgmt[i], &_controlBlock.cb->rx_data_mgmt[i]);
  1014:     }
  1015:     _controlBlock.cb->driver_curr_frag[QUEUE_RX_MGMT] = OSSwapHostToLittleInt32(CB_MGMT_QSIZE);
  1016:   
  1017:     WLExit();
  1018:     
  1019:     return true;
  1020: }
  1021: 
  1022: bool GTDriver::_freePacketForFragment(mbuf_t *packet, volatile gt_fragment *f) {
  1023:     //WLEnter();
  1024:     
  1025:     f->flags = 0;
  1026:     f->size = 0;
  1027:     f->address = 0;
  1028:     
  1029:     if ((*packet) != NULL) {
  1030:         _freed++;
  1031:         freePacket(*packet);
  1032:         (*packet) = NULL;
  1033:     } else {
  1034:         WLLogErr("Could not free mbuf. Packet was NULL");
  1035:     }
  1036:     
  1037:     //WLReturn(true);
  1038:     return true;
  1039: }
  1040: 
  1041: //releases all processed packets for each transmit queue
  1042: bool GTDriver::_freeTransmitQueues() {
  1043:     bool cleaned = false;
  1044:     
  1045:     //WLEnter();
  1046:     
  1047:     for (; (int)(_txDataLowPos - OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[QUEUE_TX_LOW])) < 0; _txDataLowPos++) {
  1048:         _freePacketForFragment(&_txDataLow[_txDataLowPos % CB_TX_QSIZE], &_controlBlock.cb->tx_data_low[_txDataLowPos % CB_TX_QSIZE]);
  1049:         cleaned = true;
  1050:     }
  1051:     for (; (int)(_txDataHighPos - OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[QUEUE_TX_HIGH])) < 0; _txDataHighPos++) {
  1052:         _freePacketForFragment(&_txDataHigh[_txDataHighPos % CB_TX_QSIZE], &_controlBlock.cb->tx_data_high[_txDataHighPos % CB_TX_QSIZE]);
  1053:         cleaned = true;
  1054:     }
  1055:     for (; (int)(_txDataMgmtPos - OSSwapLittleToHostInt32(_controlBlock.cb->device_curr_frag[QUEUE_TX_MGMT])) < 0; _txDataMgmtPos++) {
  1056:         _freePacketForFragment(&_txDataMgmt[_txDataMgmtPos % CB_MGMT_QSIZE], &_controlBlock.cb->tx_data_mgmt[_txDataMgmtPos % CB_MGMT_QSIZE]);
  1057:     }
  1058:     
  1059:     if (cleaned && _stalled) {
  1060:         _stalled = false;
  1061:         _transmitQueue->start();
  1062:     }
  1063:     //WLReturn(true);
  1064:     return true;
  1065: }
  1066: 
  1067: bool GTDriver::_freeQueues() {
  1068:     int i;
  1069:     WLEnter();
  1070:    
  1071:     
  1072:     if (_controlBlock.cb) {
  1073:         if (!_cardGone) {
  1074:             setRegister(GT_INT_EN_REG, 0);
  1075:             setRegister(GT_CTRL_BLOCK, 0);
  1076:         }
  1077:         
  1078:         for(i = 0; i < CB_RX_QSIZE; i++) {
  1079:             _freePacketForFragment(&_rxDataLow[i], &_controlBlock.cb->rx_data_low[i]);
  1080:         }
  1081:         for(i = 0; i < CB_RX_QSIZE; i++) {
  1082:             _freePacketForFragment(&_rxDataHigh[i], &_controlBlock.cb->rx_data_high[i]);
  1083:         }
  1084:         for(i = 0; i < CB_MGMT_QSIZE; i++) {
  1085:             _freePacketForFragment(&_rxDataMgmt[i], &_controlBlock.cb->rx_data_mgmt[i]);
  1086:         }
  1087:         _freeTransmitQueues();
  1088:         
  1089:         //freePageBlock(&_controlBlock.page);
  1090:         _controlBlock.dmaAddress = 0;
  1091:         _controlBlock.cb = NULL;
  1092:     }
  1093:  
  1094:     WLExit();
  1095:     
  1096:     return true;
  1097: }
  1098: }