Annotation of XNU/iokit/Families/IOUSBBus/IOUSBHub_Ports.cpp, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1998-2000 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:  * Copyright (c) 1998 Apple Computer, Inc.  All rights reserved.
        !            24:  *
        !            25:  * HISTORY
        !            26:  *
        !            27:  */
        !            28: 
        !            29: 
        !            30: #include "IOUSBHub.h"
        !            31: #include <IOKit/usb/IOUSBController.h>
        !            32: 
        !            33: //#define super IOService
        !            34: #define self this
        !            35: #define DEBUGGING_LEVEL 0      // 1 = low; 2 = high; 3 = extreme
        !            36: #define DEBUGLOG kprintf
        !            37: 
        !            38: static portStatusChangeVector defaultPortVectors[kNumChangeHandlers] =
        !            39: {
        !            40:     { 0, kHubPortOverCurrent,  kUSBHubPortOverCurrentChangeFeature },
        !            41:     { 0, kHubPortBeingReset,   kUSBHubPortResetChangeFeature },
        !            42:     { 0, kHubPortSuspend,      kUSBHubPortSuspendChangeFeature },
        !            43:     { 0, kHubPortEnabled,      kUSBHubPortEnableChangeFeature },
        !            44:     { 0, kHubPortConnection,   kUSBHubPortConnectionChangeFeature },
        !            45: };
        !            46: 
        !            47: void IOUSBHubPort::init( IOUSBHub *parent, int portNum, UInt32 powerAvailable )
        !            48: {
        !            49:     _hub               = parent;
        !            50:     _bus               = parent->_bus;
        !            51:     _hubDesc           = &parent->_hubDescriptor;
        !            52:     _portNum           = portNum;
        !            53:     _portDevice                = 0;
        !            54:     _portPowerAvailable        = powerAvailable;
        !            55:     initPortVectors();
        !            56: 
        !            57:     if (!_hub) DEBUGLOG("init: _hub is invalid\n");
        !            58:     if (!_bus) DEBUGLOG("init: _bus is invalid\n");
        !            59:     if (!_hubDesc) DEBUGLOG("init: _hubDesc is invalid\n");
        !            60:     if (portNum < 1 || portNum > 64) DEBUGLOG("init: portNum is invalid\n");
        !            61: }
        !            62: 
        !            63: /*
        !            64:  * start:
        !            65:  * Here we really just need to turn on power to the ports.  The change
        !            66:  * handler will take it from there.  However, we need to check for 2 conditions
        !            67:  * before we exit:
        !            68:  *    1. are there permanent devices connected,
        !            69:  *    2. some hubs don't generate a change connection if the ports are
        !            70:  *       powered on with a device already connected.  
        !            71:  * If either of these exist, then add the port.
        !            72:  */
        !            73: IOReturn IOUSBHubPort::start(void)
        !            74: {
        !            75:     IOReturn   err = kIOReturnSuccess;
        !            76:     IOUSBHubPortStatus status;
        !            77: 
        !            78: 
        !            79:     do
        !            80:     {
        !            81:         /* turn on Power to the port */
        !            82:         if ((err = _hub->SetPortFeature(kUSBHubPortPowerFeature, _portNum)))
        !            83:         {
        !            84:             fatalError(err, "setting port power");
        !            85:             break;
        !            86:         }
        !            87: 
        !            88:         if ((err = _hub->GetPortStatus(&status, _portNum)))
        !            89:         {
        !            90:             fatalError(err, "getting port status (1)");
        !            91:             break;
        !            92:         }
        !            93: 
        !            94: #if (DEBUGGING_LEVEL > 0)
        !            95:         DEBUGLOG("0x%x\t(start) port %d status = %xs/%xc\n", _hub,
        !            96:                  _portNum, status.statusFlags, status.changeFlags);
        !            97: #endif
        !            98: 
        !            99:         // If there is a connection change, then let the handler take it
        !           100:         // from here.  Also, in some cases the hub was in a suspend state
        !           101:         // (rather than a reset state) and does not register a connection
        !           102:         // change when the port is powered.  So also check for a connection
        !           103:        // with no change connection.        
        !           104:         // Is there a change connection OR no connection?
        !           105:         // THEN we're all done for now; int handler will take it from here
        !           106:         //if ((status.changeFlags & kHubPortConnection) ||
        !           107:         //    (status.statusFlags & kHubPortConnection) == 0)
        !           108:             break;
        !           109:         
        !           110:         /* wait for the power on good time */
        !           111:         IOSleep(_hubDesc->powerOnToGood * 2);
        !           112: 
        !           113:         if ((err = _hub->GetPortStatus(&status, _portNum)))
        !           114:         {
        !           115:             fatalError(err, "getting port status (2)");
        !           116:             break;
        !           117:         }
        !           118: 
        !           119: #if (DEBUGGING_LEVEL > 0)
        !           120:         DEBUGLOG("0x%x\t(start) port %d status = %xs/%xc\n", _hub,
        !           121:               _portNum, status.statusFlags, status.changeFlags);
        !           122: #endif
        !           123: 
        !           124:         /* we now have port status */
        !           125:         if (status.changeFlags & kHubPortConnection)
        !           126:         {
        !           127:             if ((err = _hub->ClearPortFeature
        !           128:                                (kUSBHubPortConnectionChangeFeature, _portNum)))
        !           129:             {
        !           130:                 fatalError(err, "clearing port connection change");
        !           131:                 break;
        !           132:             }
        !           133: 
        !           134:             /* We should now be in the disconnected state */
        !           135:             /* Do a port request on current port */
        !           136:             if ((err = _hub->GetPortStatus(&status, _portNum)))
        !           137:             {
        !           138:                 fatalError(err, "getting port status (3)");
        !           139:                 break;
        !           140:             }
        !           141:         }
        !           142: 
        !           143:         if (status.statusFlags & kHubPortConnection)
        !           144:         {
        !           145:             /* We have a connection on this port */
        !           146: #if (DEBUGGING_LEVEL > 0)
        !           147:             DEBUGLOG("0x%x\t(start)device detected @ port %d\n", _hub,
        !           148:                  _portNum);
        !           149: #endif
        !           150:             if ((err = addDevice()))
        !           151:                 fatalError(err, "adding device");
        !           152:         }
        !           153:     } while(false);
        !           154: 
        !           155:     return(err);
        !           156: }
        !           157: 
        !           158: void IOUSBHubPort::stop(void)
        !           159: {
        !           160:     // Ugh.  This could get nasty.  What if stop is called while
        !           161:     // a thread is adding a device?  I think we need to start tracking
        !           162:     // states.  And we might need a flag to tell us where it's because
        !           163:     // the device has been unplugged, or the system is shutting down.
        !           164: 
        !           165:     removeDevice();
        !           166: }
        !           167: 
        !           168: IOReturn IOUSBHubPort::addDevice(void)
        !           169: {
        !           170:     IOReturn           err = kIOReturnSuccess;
        !           171: 
        !           172:     do
        !           173:     {
        !           174:         _devZero = _bus->AcquireDeviceZero() == kIOReturnSuccess;
        !           175:         if (!_devZero)
        !           176:         {
        !           177:             fatalError(/*FIXME*/0, "acquiring device zero");
        !           178:             break;
        !           179:         }
        !           180: 
        !           181:         if ((err = _hub->SetPortFeature(kUSBHubPortResetFeature,
        !           182:                                               _portNum)))
        !           183:         {
        !           184:             fatalError(err, "set feature (resetting port)");
        !           185:             break;
        !           186:         }
        !           187:        {
        !           188:             // Now poll for exit from reset.
        !           189:             IOUSBHubPortStatus status;
        !           190:             int portByte;
        !           191:             UInt8 portMask;
        !           192:             bool waitReset = true;
        !           193:             AbsoluteTime endResetTime, nowTime;
        !           194:             AbsoluteTime_to_scalar(&nowTime) = 0;
        !           195:             portByte = _portNum / 8;
        !           196:             portMask = 1 << (_portNum % 8);
        !           197:             clock_interval_to_deadline(1, kSecondScale, &endResetTime);
        !           198:             do
        !           199:             {
        !           200:                 const UInt8* stat = _hub->getStatusChanged();
        !           201:                 if(stat == NULL)
        !           202:                     break;
        !           203:                 // Check if we've waited long enough!
        !           204:                 if( CMP_ABSOLUTETIME(&nowTime, &endResetTime) > 0) {
        !           205:                     err = kIOReturnTimeout;
        !           206:                     break;
        !           207:                 }
        !           208:                 clock_get_uptime(&nowTime);
        !           209:                if(!stat[portByte] & portMask) {
        !           210:                    IOSleep(2);
        !           211:                     continue;
        !           212:                }
        !           213:                 /* Do a port status request on current port */
        !           214:                 if ((err = _hub->GetPortStatus(&status, _portNum)))
        !           215:                 {
        !           216:                     fatalError(err, "get status (waiting for reset end)");
        !           217:                     break;
        !           218:                 }
        !           219: #if (DEBUGGING_LEVEL > 0)
        !           220:                 DEBUGLOG("0x%x\t(waiting for reset end) port %d status = %xs/%xc\n", _hub,
        !           221:                     _portNum, status.statusFlags, status.changeFlags);
        !           222: #endif
        !           223:                 if(status.changeFlags & kHubPortBeingReset)
        !           224:                 {
        !           225:                     if ((err = _hub->ClearPortFeature(
        !           226:                                kUSBHubPortResetChangeFeature, _portNum)))
        !           227:                     {
        !           228:                         fatalError(err, "clear port vector bit feature");
        !           229:                         break;
        !           230:                     }
        !           231:                     err = addDeviceResetChangeHandler(status.changeFlags);
        !           232:                     waitReset = false;
        !           233:                 }
        !           234:             } while (waitReset);
        !           235:        }
        !           236:     } while(false);
        !           237: 
        !           238:     if (err && _devZero)
        !           239:     {
        !           240:         _bus->ReleaseDeviceZero();
        !           241:         _devZero = false;
        !           242:         
        !           243:         // put it back to the default if there was an error
        !           244: #if (DEBUGGING_LEVEL > 0)
        !           245:         DEBUGLOG("error: setting change handler to default\n");
        !           246: #endif
        !           247:         setPortVector(&IOUSBHubPort::defaultResetChangeHandler,
        !           248:                       kHubPortBeingReset);
        !           249:     }
        !           250: 
        !           251:     return(err);
        !           252: }
        !           253: 
        !           254: void IOUSBHubPort::removeDevice(void)
        !           255: {
        !           256:     bool       ok;
        !           257: 
        !           258:     if (_portDevice) {
        !           259:        ok = _portDevice->terminate(kIOServiceRequired);
        !           260:         if( !ok)
        !           261:             DEBUGLOG("IOUSBHubPort: terminate() failed\n");
        !           262:        _portDevice->release();
        !           263:        _portDevice = 0;
        !           264:     }
        !           265:     initPortVectors();
        !           266: }
        !           267: 
        !           268: IOReturn IOUSBHubPort::resetDevice()
        !           269: {
        !           270:     IOReturn err = kIOReturnSuccess;
        !           271: 
        !           272:     do {
        !           273:         _devZero = _bus->AcquireDeviceZero() == kIOReturnSuccess;
        !           274:         if (!_devZero)
        !           275:         {
        !           276:             fatalError(/*FIXME*/0, "acquiring device zero");
        !           277:             err = kIOReturnCannotLock;
        !           278:             break;
        !           279:         }
        !           280: 
        !           281:         setPortVector(&IOUSBHubPort::handleResetDevice, kHubPortBeingReset);
        !           282: 
        !           283:         err = _hub->SetPortFeature(kUSBHubPortResetFeature, _portNum);
        !           284:         if(err != kIOReturnSuccess)
        !           285:             break;
        !           286: 
        !           287:     } while (false);
        !           288: 
        !           289:     if(err == kIOReturnSuccess)
        !           290:     {
        !           291:         _bus->WaitForReleaseDeviceZero();
        !           292:     }
        !           293:     else if(_devZero)
        !           294:     {
        !           295:         _bus->ReleaseDeviceZero();
        !           296:         _devZero = false;
        !           297:     }
        !           298: 
        !           299:     return err;
        !           300: }
        !           301: 
        !           302: IOReturn IOUSBHubPort::handleResetDevice(UInt16 changeFlags)
        !           303: {
        !           304:     IOReturn err = kIOReturnSuccess;
        !           305: 
        !           306:     setPortVector(&IOUSBHubPort::defaultResetChangeHandler, kHubPortBeingReset);
        !           307:     /* Now address the device */
        !           308:     _bus->ConfigureDeviceZero(_desc.maxPacketSize, _speed);
        !           309:     err = _bus->SetDeviceZeroAddress(_portDevice->address(),
        !           310:                                     _desc.maxPacketSize, _speed);
        !           311: 
        !           312:     _bus->ReleaseDeviceZero();
        !           313:     _devZero = false;
        !           314: 
        !           315:     return err;
        !           316: }
        !           317: 
        !           318: void IOUSBHubPort::fatalError(IOReturn err, char *str)
        !           319: {
        !           320:     DEBUGLOG("IOUSBHubPort: Error 0x%x on port %d: %s\n", err, _portNum, str);
        !           321:     if (_portDevice != 0)
        !           322:     {
        !           323:         DEBUGLOG("IOUSBHubPort: Removing %s from port %d\n",
        !           324:                  _portDevice->getName(), _portNum);
        !           325:         removeDevice();        
        !           326:     }
        !           327: }
        !           328: 
        !           329: 
        !           330: /**********************************************************************
        !           331:  **
        !           332:  ** CHANGE HANDLER FUNCTIONS
        !           333:  **
        !           334:  **********************************************************************/
        !           335: IOReturn IOUSBHubPort::addDeviceResetChangeHandler(UInt16 changeFlags)
        !           336: {
        !           337:     IOReturn           err = kIOReturnSuccess;
        !           338:     IOUSBHubPortStatus status;
        !           339: 
        !           340:     do
        !           341:     {
        !           342:         /* Tell the USB to add the device */
        !           343:         if ((err = _hub->GetPortStatus(&status, _portNum)))
        !           344:         {
        !           345:             fatalError(err, "getting port status (3)");
        !           346:             break;
        !           347:         }
        !           348: 
        !           349:         if (status.statusFlags & kHubPortBeingReset)
        !           350:         {
        !           351:             DEBUGLOG("%s: port not finished resetting, retrying\n", _hub->getName());
        !           352:             // we should never be here, just wait for another status change int
        !           353:             break;
        !           354:         }
        !           355: 
        !           356:         // macally iKey doesn't tell us until now what the device speed is.
        !           357:         _speed = ((status.statusFlags & kHubPortSpeed) != 0);
        !           358: #if (DEBUGGING_LEVEL > 0)
        !           359:                 DEBUGLOG("0x%x\t(reset end) port %d status = %xs/%xc, %s speed\n", _hub,
        !           360:                          _portNum, status.statusFlags, status.changeFlags, _speed ? "low" : "high");
        !           361: #endif
        !           362: 
        !           363:         /* Now wait 10 ms after reset */
        !           364:         IOSleep(10);
        !           365: 
        !           366:         // Configure algorithm:
        !           367:        // * start with maxpacketsize of 8.
        !           368:        // This is the smallest legal maxpacket, and the only legal size for
        !           369:        // low-speed devices. The correct maxpacket size is in byte 8 of the
        !           370:        // device descriptor, so even if the device sends back a bigger packet
        !           371:        // (an overrun error) we should still get the correct value.
        !           372:        // * get device descriptor.
        !           373:        // * if we recieved the whole descriptor AND maxpacketsize is 64,
        !           374:        //   success, so continue on.
        !           375:         // * if descriptor returns with a different maxpacketsize, then
        !           376:        //   reconfigure with the new one and try again.  Otherwise, 
        !           377:        //   reconfigure with 8 and try again.
        !           378:         if ((err = _bus->ConfigureDeviceZero(8, _speed)))
        !           379:         {
        !           380:             fatalError(err, "configuring endpoint zero");
        !           381:             break;
        !           382:         }              
        !           383: 
        !           384:         // Now do a device request to find out what it is
        !           385:         // Some fast devices send back packets > 8 bytes to address 0.
        !           386:         bzero(&_desc, sizeof(_desc));
        !           387:         err = _bus->GetDeviceZeroDescriptor(&_desc);
        !           388: 
        !           389: #if (DEBUGGING_LEVEL > 0)
        !           390:         DEBUGLOG("IOUSBHubPort: getDeviceDescriptor err = 0x%x  max = %d numconf = %d\n", err, _desc.maxPacketSize, _desc.numConf);
        !           391: #endif
        !           392:         // Check for specific conditions here before going on.
        !           393:         // 1) if the pipe cannot handle the default max packet size of 8,
        !           394:         //    then reconfigure the pipe and try again.  If just the size is
        !           395:         //    wrong, it should return at least the correct size if not
        !           396:         //    the whole descriptor.
        !           397:         // 2) If there is still an err, bail out.
        !           398:         if (err || _desc.maxPacketSize != 8)
        !           399:         {
        !           400:             // Reconfigure the pipe if the max packet size is not the default
        !           401:             // of 8, but we explicitly don't want to set it to 0.  It might be
        !           402:             // good to do a little more checking here...later.
        !           403:             if (_desc.maxPacketSize != 0 && _desc.maxPacketSize != 8)
        !           404:             {
        !           405:                 err = _bus->ConfigureDeviceZero(_desc.maxPacketSize, _speed);
        !           406:                 err = _bus->GetDeviceZeroDescriptor(&_desc);
        !           407:             }
        !           408:             // The device really didn't like 8.  Probably got a stall or
        !           409:             // something like that.  As a last ditch effort, try 64.
        !           410:             else if (err)
        !           411:             {
        !           412:                 err = _bus->ConfigureDeviceZero(64, _speed);
        !           413:                 err = _bus->GetDeviceZeroDescriptor(&_desc);
        !           414:             }
        !           415: 
        !           416:             if (err == kIOReturnOverrun)
        !           417:             {
        !           418:                 // Not sure what to do with this error.  It means more data
        !           419:                 // came back than the size of a descriptor.  Hmmm.  For now
        !           420:                 // just ignore it and assume the data that did come back is
        !           421:                 // useful.
        !           422: #if (DEBUGGING_LEVEL > 0)
        !           423:                 DEBUGLOG("%s: overrun error reading device descriptor\n",
        !           424:                       _hub->getName());
        !           425: #endif
        !           426:             }
        !           427: 
        !           428:             if (err)
        !           429:             {
        !           430:                 fatalError(err, "getting full device descriptor");
        !           431:                 continue;
        !           432:             }
        !           433:         }
        !           434: 
        !           435:         /* ERIC FIXME?  what are we doing here?
        !           436:         if ((_hubDescriptor.removablePortFlags[pp->portByte] & pp->portMask))
        !           437:         {
        !           438:             pb->usbOther = powerForCaptive;
        !           439:         }
        !           440:         else
        !           441:         {
        !           442:             pb->usbOther = selfPowerGood?kUSB500mAAvailable:kUSB100mAAvailable;
        !           443:         }
        !           444:         */             
        !           445: 
        !           446:         /* Now create and address the device */
        !           447:         if ((_portDevice = _bus->MakeDevice(&_desc, _speed, _portPowerAvailable)) == 0)
        !           448:         {
        !           449:             _portDevice = 0;
        !           450:             err = kIOReturnDeviceError;
        !           451:             fatalError(err, "setting the device address");
        !           452:             continue;
        !           453:         }
        !           454:         /* Tell the device who it's port is */
        !           455:         _portDevice->setPort(this);
        !           456: 
        !           457:         /* Release */
        !           458:         _bus->ReleaseDeviceZero();
        !           459:         _devZero = false;
        !           460: 
        !           461:         /* Finally use the data gathered */
        !           462:         _portDevice->registerService();
        !           463: 
        !           464:     } while(false);
        !           465: 
        !           466:     // reset the vector back to the default
        !           467: #if (DEBUGGING_LEVEL > 0)
        !           468:     DEBUGLOG("0x%x\t(port %d)setting change handler to default\n", _hub, _portNum);
        !           469: #endif
        !           470:     setPortVector(&IOUSBHubPort::defaultResetChangeHandler, kHubPortBeingReset);
        !           471: 
        !           472:     if (err)
        !           473:     {
        !           474:         if (_devZero)
        !           475:         {
        !           476:             _bus->ReleaseDeviceZero();
        !           477:             _devZero = false;
        !           478:         }
        !           479:     }
        !           480:     return err;
        !           481: }
        !           482: 
        !           483: IOReturn IOUSBHubPort::defaultOverCrntChangeHandler(UInt16 changeFlags)
        !           484: {
        !           485: #if (DEBUGGING_LEVEL > 0)
        !           486:     DEBUGLOG("IOUSBHubPort: over current change notification\n");
        !           487: #endif
        !           488:     return kIOReturnSuccess;
        !           489: }
        !           490: 
        !           491: IOReturn IOUSBHubPort::defaultResetChangeHandler(UInt16 changeFlags)
        !           492: {
        !           493: #if (DEBUGGING_LEVEL > 0)
        !           494:     DEBUGLOG("IOUSBHubPort: reset change notification\n");
        !           495: #endif
        !           496:     return kIOReturnSuccess;
        !           497: }
        !           498: 
        !           499: IOReturn IOUSBHubPort::defaultSuspendChangeHandler(UInt16 changeFlags)
        !           500: {
        !           501: #if (DEBUGGING_LEVEL > 0)
        !           502:     DEBUGLOG("IOUSBHubPort: suspend change notification\n");
        !           503: #endif
        !           504:     return kIOReturnSuccess;
        !           505: }
        !           506: 
        !           507: IOReturn IOUSBHubPort::defaultEnableChangeHandler(UInt16 changeFlags)
        !           508: {
        !           509:     IOReturn           err = kIOReturnSuccess;
        !           510:     IOUSBHubPortStatus status;
        !           511: 
        !           512: #if (DEBUGGING_LEVEL > 0)
        !           513:     DEBUGLOG("IOUSBHubPort: enable change notification\n");
        !           514: #endif
        !           515: 
        !           516:     if ((err = _hub->GetPortStatus(&status, _portNum)))
        !           517:     {
        !           518:         fatalError(err, "getting port status");
        !           519:         return err;
        !           520:     }
        !           521: 
        !           522:     if (!(status.statusFlags & kHubPortEnabled) &&
        !           523:         !(changeFlags & kHubPortConnection))
        !           524:     {
        !           525:         // The hub gave us an enable status change and we're
        !           526:         // now disabled, strange.  Cosmo does this sometimes,
        !           527:         // try Re-enabling the port.
        !           528: #if (DEBUGGING_LEVEL > 0)
        !           529:         DEBUGLOG("IOUSBHubPort: re-enabling dead port %d\n", _portNum);
        !           530: #endif
        !           531:         if ((err = _hub->SetPortFeature(kUSBHubPortEnableFeature, _portNum)))
        !           532:             fatalError(err, "re-enabling dead port");
        !           533:     }
        !           534:     return err;
        !           535: }
        !           536: 
        !           537: IOReturn IOUSBHubPort::defaultConnectionChangeHandler(UInt16 changeFlags)
        !           538: {
        !           539:     IOReturn   err = kIOReturnSuccess;
        !           540:     IOUSBHubPortStatus status;
        !           541: 
        !           542: #if (DEBUGGING_LEVEL > 0)
        !           543:     DEBUGLOG("0x%x\t(port %d)connection change notification\n",  _hub, _portNum);
        !           544: #endif
        !           545: 
        !           546:     do
        !           547:     {
        !           548:         /* wait for the power on good time */
        !           549:         IOSleep(_hubDesc->powerOnToGood * 2);
        !           550: 
        !           551:         // If we get to here, there was a connection change
        !           552:         // if we already have a device it must have been disconnected
        !           553:         // at sometime. We should kill it before servicing a connect event
        !           554:         if (_portDevice != 0)
        !           555:         {      
        !           556: #if (DEBUGGING_LEVEL > 0)
        !           557:             DEBUGLOG("0x%x\t(port %d): removing %s device @ %d\n",
        !           558:                _hub, _portNum, _portDevice->getName(), _portDevice->address());
        !           559: #endif
        !           560: 
        !           561:             removeDevice();    
        !           562:         }
        !           563: 
        !           564:         // BT 23Jul98 Check port again after delay. Get bounced connections
        !           565:         /* Do a port status request on current port */
        !           566:         if ((err = _hub->GetPortStatus(&status, _portNum)))
        !           567:         {
        !           568:             fatalError(err, "getting port status");
        !           569:             break;
        !           570:         }
        !           571: 
        !           572: #if (DEBUGGING_LEVEL > 0)
        !           573:         DEBUGLOG("0x%x\t(conn change) port %d status = %xs/%xc\n", _hub,
        !           574:                  _portNum, status.statusFlags, status.changeFlags);
        !           575: #endif
        !           576: 
        !           577:         if (status.changeFlags & kHubPortConnection)
        !           578:         {
        !           579:             DEBUGLOG("IOUSBHubPort: connection bounce\n");
        !           580:             break;
        !           581:         }
        !           582: 
        !           583:         if (status.statusFlags & kHubPortConnection)
        !           584:         {
        !           585:             /* We have a connection on this port */
        !           586: #if (DEBUGGING_LEVEL > 0)
        !           587:             DEBUGLOG("0x%x\tdevice detected @ port %d\n", _hub, _portNum);
        !           588: #endif
        !           589:             for(int i=0; i<2; i++) {
        !           590:                 err = addDevice();
        !           591:                 if (err == kIOReturnSuccess)
        !           592:                     break;
        !           593:                 err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
        !           594:                 if (err != kIOReturnSuccess)
        !           595:                     fatalError(err, "adding device");
        !           596:             }
        !           597:         }
        !           598:         
        !           599:     } while(false);
        !           600:     return err;
        !           601: }
        !           602: 
        !           603: bool IOUSBHubPort::statusChanged(void)
        !           604: {
        !           605:     IOReturn   err = kIOReturnSuccess;
        !           606:     int        which;
        !           607:     IOUSBHubPortStatus status;
        !           608: 
        !           609:     
        !           610:     do
        !           611:     {
        !           612:         /* Do a port status request on current port */
        !           613:         if ((err = _hub->GetPortStatus(&status, _portNum)))
        !           614:         {
        !           615:             fatalError(err, "get status (first in port status change)");
        !           616:             break;
        !           617:         }
        !           618: 
        !           619: #if (DEBUGGING_LEVEL > 0)
        !           620:         DEBUGLOG("0x%x\t(status changed 1) port %d status = %xs/%xc\n", _hub,
        !           621:               _portNum, status.statusFlags, status.changeFlags);
        !           622: #endif
        !           623: 
        !           624:         // First clear the change condition before we return.  This prevents
        !           625:         // a race condition for handling the change.
        !           626:         for (which = 0; which < kNumChangeHandlers; which++)
        !           627:         {
        !           628:             // sometimes a change is reported but there really is
        !           629:             // no change.  This will catch that.
        !           630:             if (!(status.changeFlags & _changeHandler[which].bit))
        !           631:                 continue;
        !           632: 
        !           633:             if ((err = _hub->ClearPortFeature(
        !           634:                     _changeHandler[which].clearFeature, _portNum)))
        !           635:             {
        !           636:                 fatalError(err, "clear port vector bit feature");
        !           637:                 continue;
        !           638:             }
        !           639:         }
        !           640: 
        !           641:         err = statusChangeHandler(status.changeFlags);
        !           642: 
        !           643:     } while(false);
        !           644: 
        !           645:     return(err == kIOReturnSuccess);
        !           646: }
        !           647: 
        !           648: 
        !           649: IOReturn IOUSBHubPort::statusChangeHandler(UInt16 changeFlags)
        !           650: {
        !           651:     int which;
        !           652:     IOReturn res = kIOReturnSuccess;
        !           653: 
        !           654:     // Handle each change in sequential order.
        !           655:     for (which = 0; which < kNumChangeHandlers; which++)
        !           656:     {
        !           657:         if (!(changeFlags & _changeHandler[which].bit))
        !           658:             continue;
        !           659:         res = (self->*_changeHandler[which].handler)(changeFlags);
        !           660:         if(res != kIOReturnSuccess)
        !           661:             break;
        !           662:     }
        !           663: 
        !           664:     return(res);
        !           665: }
        !           666: 
        !           667: 
        !           668: void IOUSBHubPort::initPortVectors(void)
        !           669: {
        !           670:     int vector;
        !           671:     for (vector = 0; vector < kNumChangeHandlers; vector++)
        !           672:     {
        !           673:         _changeHandler[vector] = defaultPortVectors[vector];
        !           674:         switch (defaultPortVectors[vector].bit)
        !           675:         {
        !           676:             case kHubPortOverCurrent:
        !           677:                 _changeHandler[vector].handler =
        !           678:                 &IOUSBHubPort::defaultOverCrntChangeHandler;
        !           679:                 break;
        !           680:             case kHubPortBeingReset:
        !           681:                 _changeHandler[vector].handler =
        !           682:                 &IOUSBHubPort::defaultResetChangeHandler;
        !           683:                 break;
        !           684:             case kHubPortSuspend:
        !           685:                 _changeHandler[vector].handler =
        !           686:                 &IOUSBHubPort::defaultSuspendChangeHandler;
        !           687:                 break;
        !           688:             case kHubPortEnabled:
        !           689:                 _changeHandler[vector].handler =
        !           690:                 &IOUSBHubPort::defaultEnableChangeHandler;
        !           691:                 break;
        !           692:             case kHubPortConnection:
        !           693:                 _changeHandler[vector].handler =
        !           694:                 &IOUSBHubPort::defaultConnectionChangeHandler;
        !           695:                 break;
        !           696:         }
        !           697:     }
        !           698: }
        !           699: 
        !           700: void IOUSBHubPort::setPortVector(ChangeHandlerFuncPtr  routine,
        !           701:                                  UInt32                        condition)
        !           702: {
        !           703:     int vector;
        !           704:     for(vector = 0; vector < kNumChangeHandlers; vector++)
        !           705:     {
        !           706:         if(condition == _changeHandler[vector].bit)
        !           707:         {
        !           708:             _changeHandler[vector].handler = routine;
        !           709:         }
        !           710:     }
        !           711: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.