IOReturn
AppleUSBUHCI::ClearRootHubPortFeature(UInt16 wValue, UInt16 port)
{
    UInt16 value;
    USBLog(5, "AppleUSBUHCI[%p]::ClearRootHubPortFeature %d %d", this, wValue, port);

    switch(wValue)
    {
        case kUSBHubPortEnableFeature :
            USBLog(5, "AppleUSBUHCI[%p]: Clear port enable", this);
            RHEnablePort(port, false);
            break;
            
        case kUSBHubPortConnectionChangeFeature :
            USBLog(5, "AppleUSBUHCI[%p]: Clear connection change", this);
            value = ReadPortStatus(port-1) & kUHCI_PORTSC_MASK;
            WritePortStatus(port-1, value | kUHCI_PORTSC_CSC);
            break;
            
        case kUSBHubPortEnableChangeFeature :
            USBLog(5, "AppleUSBUHCI[%p]: Clear port enable change", this);
            value = ReadPortStatus(port-1) & kUHCI_PORTSC_MASK;
            WritePortStatus(port-1, value | kUHCI_PORTSC_PEDC);
            break;
            
        case kUSBHubPortResetChangeFeature :
            USBLog(5, "AppleUSBUHCI[%p]: Clear port reset change", this);
            _portWasReset[port-1] = false;
            break;
            
        case kUSBHubPortSuspendFeature :
            RHSuspendPort(port, false);
            break;
            
        case kUSBHubPortSuspendChangeFeature :
            USBLog(5, "AppleUSBUHCI[%p]: Clear port suspend change", this);
            _portSuspendChange[port-1] = false;
            break;
            
#if 0
            // These will all fall through to return unsupported.
        case kUSBHubPortOverCurrentChangeFeature :
            RHResetOverCurrentChange(port);
            break;
            
        case kUSBHubPortPowerFeature :
            //status = RHPortPort(port, false);
            break;
#endif
            
        default:
            USBLog(5,"AppleUSBUHCI[%p]: clear unknown feature %d", this, wValue);
            break;
    }
    return kIOReturnSuccess;
}
IOReturn			
AppleUSBUHCI::RHResumePortCompletion(UInt32 port)
{
	UInt16			value;
	
	USBLog(5, "AppleUSBUHCI[%p]::RHResumePortCompletion - finishing resume on port %d", this, (int)port);
	if (!_rhPortBeingResumed[port-1])
	{
		USBLog(1, "AppleUSBUHCI[%p]::RHResumePortCompletion - port %d does not appear to be resuming!", this, (int)port);
		USBTrace( kUSBTUHCI, kTPUHCIRHResumePortCompletion, (uintptr_t)this, (int)port, 0, kIOReturnInternalError );
		return kIOReturnInternalError;
	}
	
	if (!_controllerAvailable)
	{
		USBLog(5, "AppleUSBEHCI[%p]::RHResumePortCompletion - cannot finish resume on port %d because the controller is unavailable", this, (int)port);
		_rhPortBeingResumed[port-1] = false;
		return kIOReturnInternalError;
	}
	
	value = ReadPortStatus(port-1) & kUHCI_PORTSC_MASK;
	value &= ~(kUHCI_PORTSC_RD | kUHCI_PORTSC_SUSPEND);
	USBLog(5, "AppleUSBUHCI[%p]: de-asserting resume signal by writing (%p)", this, (void*)value);
	WritePortStatus(port-1, value);
	IOSync();
	IOSleep(2);																	// allow it to kick in

	_rhPortBeingResumed[port-1] = false;
	_portSuspendChange[port-1] = true;
	EnsureUsability();
	return kIOReturnSuccess;
}
示例#3
0
//================================================================================================
//
//   SuspendController
//
//================================================================================================
//
void			
AppleUSBUHCI::SuspendController(void)
{
    UInt16				cmd, value;
	int					i;
    
	USBTrace( kUSBTUHCI, kTPUHCISuspendController, (uintptr_t)this, 0, 0, 1 );
	USBLog(5, "AppleUSBUHCI[%p]::SuspendController",  this);
    USBLog(5, "AppleUSBUHCI[%p]: cmd state %x, status %x",  this, ioRead16(kUHCI_CMD), ioRead16(kUHCI_STS));

    // Stop the controller
    Run(false);
    
	for (i=0; i< 2; i++)
	{
		value = ReadPortStatus(i) & kUHCI_PORTSC_MASK;
		if (value & kUHCI_PORTSC_PED)
		{
			if (value & kUHCI_PORTSC_SUSPEND)
			{
				USBLog(5, "AppleUSBUHCI[%p]::SuspendController - port[%d] is suspended [%p]", this, i, (void*)value);
			}
			else
			{
				USBLog(5, "AppleUSBUHCI[%p]::SuspendController - port[%d] is enabled but not suspended [%p]", this, i, (void*)value);
			}
		}
		else
		{
			USBLog(5, "AppleUSBUHCI[%p]::SuspendController - port[%d] is not enabled [%p]", this, i, (void*)value);
		}
		
		// only do this for controllers with overcurrent additions.
		if ((_ERRATA64BITS & kErrataUHCISupportsOvercurrent) && (value & kUHCI_PORTSC_OCI))  // Is the latched Overcurrent set?
		{
			// if so, clear it or we won't suspend.
			USBLog(1, "AppleUSBUHCI[%p]::SuspendController - port[%d] had the overcurrent bit set.  Clearing it", this, i);
			USBTrace( kUSBTUHCI, kTPUHCISuspendController, (uintptr_t)this, i, 0, 2 );
			WritePortStatus(i, kUHCI_PORTSC_OCI); // clear overcurrent indicator
		}
	}
    // Put the controller in Global Suspend
    cmd = ioRead16(kUHCI_CMD) & ~kUHCI_CMD_FGR;
    cmd |= kUHCI_CMD_EGSM;
    ioWrite16(kUHCI_CMD, cmd);
	_myBusState = kUSBBusStateSuspended;   
    IOSleep(3);
    USBLog(5, "AppleUSBUHCI[%p]: suspend done, cmd %x, status %x",  this, ioRead16(kUHCI_CMD), ioRead16(kUHCI_STS));
}
// Reset and enable the port
IOReturn
AppleUSBUHCI::RHHoldPortReset(int port)
{
    UInt16 value;
    int i;
    
    USBLog(1, "AppleUSBUHCI[%p]::RHHoldPortReset %d", this, port);
	USBTrace( kUSBTUHCI, kTPUHCIRHHoldPortReset, (uintptr_t)this, (int)port, 0, 0);
	
    port--; // convert 1-based to 0-based.

    value = ReadPortStatus(port) & kUHCI_PORTSC_MASK;
    WritePortStatus(port, value | kUHCI_PORTSC_RESET);
    
    return kIOReturnSuccess;
}
void
AppleUSBUHCI::RHEnablePort(int port, bool enable)
{
    UInt16 value;

    // USBLog(5, "AppleUSBUHCI[%p]::RHEnablePort %d %d", this, port, enable);
    port--; // convert 1-based to 0-based.
    value = ReadPortStatus(port) & kUHCI_PORTSC_MASK;
    USBLog(3, "AppleUSBUHCI[%p]::RHEnablePort port: %d enable: %d PortSC: 0x%x", this, port+1, enable, value);
	USBLog(2, "AppleUSBUHCI[%p]::RHEnablePort  (CMD:%p STS:%p INTR:%p PORTSC1:%p PORTSC2:%p FRBASEADDR:%p FRNUM:%p, SOFMOD:%p, ConfigCMD:%p)", this, (void*)ioRead16(kUHCI_CMD), (void*)ioRead16(kUHCI_STS), (void*)ioRead16(kUHCI_INTR), (void*)ioRead16(kUHCI_PORTSC1), (void*)ioRead16(kUHCI_PORTSC2), (void*)ioRead32(kUHCI_FRBASEADDR),  
		   (void*)ioRead32(kUHCI_FRNUM),  (void*)ioRead32(kUHCI_SOFMOD), (void*)_device->configRead16(kIOPCIConfigCommand));
   if (enable) 
	{
        value |= kUHCI_PORTSC_PED;
    } else 
	{
        value &= ~kUHCI_PORTSC_PED;
    }
    WritePortStatus(port, value);
}
示例#6
0
//================================================================================================
//
//   WakeControllerFromDoze
//
//================================================================================================
//
IOReturn				
AppleUSBUHCI::WakeControllerFromDoze(void)
{
    UInt16				cmd;
	int					i;
	bool				portHasRD[kUHCI_NUM_PORTS];
    UInt16				status;

	USBTrace( kUSBTUHCI, KTPUHCIWakeFromDoze, (uintptr_t)this, 0, 0, 0);
	// First, see if we have any ports that have the RD bit set.  If they do, then we can go ahead and clear it after we waited the 20ms for the
	// Global resume
	for (i=0; i<kUHCI_NUM_PORTS; i++) 
	{
		status = ReadPortStatus(i);
		if (status & kUHCI_PORTSC_RD) 
		{
			USBLog(6, "AppleUSBUHCI[%p]::WakeControllerFromDoze controller port %d has kUHCI_PORTSC_RD set", this, i+1);
			portHasRD[i] = true;
		}
		else
		{
			portHasRD[i] = false;
		}
    }
	
	// If we are in Global Suspend mode, we need to resume the controller.   We will wait 20ms with the gate held.  However, since we only
	// get into this mode if all devices are suspended, then delaying while holding the wl will not prevent any completions from happening, since
	// there aren't any.
	cmd = ioRead16(kUHCI_CMD);

	if (cmd & kUHCI_CMD_EGSM)
	{
		USBLog(6, "AppleUSBUHCI[%p]::WakeControllerFromDoze controller is globally suspended - forcing resume", this);
		cmd |= kUHCI_CMD_FGR;
		ioWrite16(kUHCI_CMD, cmd);
		cmd = ioRead16(kUHCI_CMD);
		USBLog(6, "AppleUSBUHCI[%p]::WakeControllerFromDoze after EGSM->FGR, cmd is[%p], sleeping 20ms", this, (void*)cmd);
		IOSleep(20);
		cmd &= ~kUHCI_CMD_FGR;
		cmd &= ~kUHCI_CMD_EGSM;
		ioWrite16(kUHCI_CMD, cmd);
		
		// Clear any RD bits in the port if they were set, now that we have waited 20ms
		for (i=0; i<kUHCI_NUM_PORTS; i++) 
		{
			if (portHasRD[i] )
			{
				status = ReadPortStatus(i) & kUHCI_PORTSC_MASK;
				status &= ~(kUHCI_PORTSC_RD | kUHCI_PORTSC_SUSPEND);
				USBLog(6, "AppleUSBUHCI[%p]::WakeControllerFromDoze  de-asserting resume signal for port %d by writing (%p)", this, i+1, (void*)status);
				WritePortStatus(i, status);
				IOSync();
				IOSleep(2);																	// allow it to kick in
			}
		}
	}

	USBLog(6, "AppleUSBUHCI[%p]::WakeControllerFromDoze calling Run(true)", this);
	Run(true);
	_myBusState = kUSBBusStateRunning;
	showRegisters(7, "-WakeControllerFromDoze");
	return kIOReturnSuccess;
}
// Reset and enable the port
IOReturn
AppleUSBUHCI::RHResetPort(int port)
{
    UInt16 value;
    int i;
    
    USBLog(3, "AppleUSBUHCI[%p]::RHResetPort %d", this, port);
    port--; // convert 1-based to 0-based.

    value = ReadPortStatus(port) & kUHCI_PORTSC_MASK;
    WritePortStatus(port, value | kUHCI_PORTSC_RESET);
    
    /* Assert RESET for 50ms */
    IOSleep(50);
    
    value = ReadPortStatus(port) & kUHCI_PORTSC_MASK;
    WritePortStatus(port, value & ~kUHCI_PORTSC_RESET);
    
    IODelay(10);
    
    value = ReadPortStatus(port) & kUHCI_PORTSC_MASK;
    WritePortStatus(port, value | kUHCI_PORTSC_PED);
    
    for (i=10; i>0; i--) 
	{
        IOSleep(10);
        
        value = ReadPortStatus(port);
        
        if ((value & kUHCI_PORTSC_CCS) == 0) 
		{
            /* No device connected; don't enter reset state. */
            //USBLog(5, "%s[%p]: no device connected, not entering reset state");
            return kIOReturnNotResponding;
            break;
        }
        
        if (value & (kUHCI_PORTSC_PEDC | kUHCI_PORTSC_CSC)) 
		{
            /* Change bits detected. Clear them and continue waiting. */
            WritePortStatus(port, (value & kUHCI_PORTSC_MASK) | (kUHCI_PORTSC_PEDC | kUHCI_PORTSC_CSC));
            continue;
        }
        
        if (value & kUHCI_PORTSC_PED) 
		{
            /* Port successfully enabled. */
            break;
        }
        
    }
    
    if (i == 0) 
	{
        USBLog(5, "AppleUSBUHCI[%p]: reset port FAILED", this);
        return kIOReturnNotResponding;
    }
    
    // Remember that we were reset
    _portWasReset[port] = true;
    
    USBLog(5, "AppleUSBUHCI[%p]: reset port succeeded", this);
    return kIOReturnSuccess;
}
IOReturn
AppleUSBUHCI::RHSuspendPort(int port, bool suspended)
{
    UInt16 cmd, value;
    
    USBLog(3, "AppleUSBUHCI[%p]::RHSuspendPort %d (%s) _rhPortBeingResumed[%d](%s)", this, port, suspended ? "SUSPEND" : "RESUME", (int)port-1, _rhPortBeingResumed[port-1] ? "true" : "false");
	showRegisters(7, "RHSuspendPort");
    port--; // convert 1-based to 0-based.

	if (_rhPortBeingResumed[port])
	{
		if (!suspended)
		{
			USBLog(3, "AppleUSBUHCI[%p]::RHSuspendPort - resume on port (%d) already being resumed - gracefully ignoring", this, (int)port+1);
			return kIOReturnSuccess;
		}
		USBLog(1, "AppleUSBUHCI[%p]::RHSuspendPort - trying to suspend port (%d) which is being resumed - UNEXPECTED", this, (int)port+1);
		USBTrace( kUSBTUHCI, kTPUHCIRHSuspendPort, (uintptr_t)this, (int)port+1, 0, 0);
	}
	
    cmd = ioRead16(kUHCI_CMD);
    value = ReadPortStatus(port) & kUHCI_PORTSC_MASK;
    
    if (suspended) 
	{
        value |= kUHCI_PORTSC_SUSPEND;
        value &= ~kUHCI_PORTSC_RD;
    } else 
	{
        if (cmd & kUHCI_CMD_EGSM) 
		{
            /* Can't un-suspend a port during global suspend. */
            USBError(1, "AppleUSBUHCI[%p]: attempt to resume during global suspend", this);
            return kIOReturnError;
        }
        value |= (kUHCI_PORTSC_SUSPEND | kUHCI_PORTSC_RD);
    }
    // Always enable the port also.
    value |= kUHCI_PORTSC_PED;

    USBLog(5, "AppleUSBUHCI[%p]: writing (%p) to port control", this, (void*)value);
    
    WritePortStatus(port, value);
    
    if (suspended) 
	{
        /* Suspending.
         * Sleep for 3ms to ensure nothing goes out on the bus
         * until devices are suspended.
         */
        IOSleep(3);
        
    } else 
	{
        // Resuming
		USBLog(5,"AppleUSBUHCI[%p]::RHSuspendPort - resuming port %d, calling out to timer", this, (int)port+1);
		_rhPortBeingResumed[port] = true;
		thread_call_enter1(_rhResumePortTimerThread[port], (void*)(port+1));
    }

    USBLog(5, "AppleUSBUHCI[%p]::RHSuspendPort %d (%s) calling UIMRootHubStatusChange", this, port+1, suspended ? "SUSPEND" : "RESUME");

    UIMRootHubStatusChange();        
    
    USBLog(5, "AppleUSBUHCI[%p]::RHSuspendPort %d (%s) DONE", this, port+1, suspended ? "SUSPEND" : "RESUME");

    return kIOReturnSuccess;
}
IOReturn
AppleUSBUHCI::GetRootHubPortStatus(IOUSBHubPortStatus *status, UInt16 port)
{
    UInt16 p_status;
    UInt16 r_status, r_change;
    
    USBLog(7, "AppleUSBUHCI[%p]::GetRootHubPortStatus on port %d", this, port+1);
    RHDumpPortStatus(port);
    
	// no longer do this, as the root hub can be queried even when we are suspended
	//if (_myBusState == kUSBBusStateSuspended) 
	//{
    //    return kIOReturnNotResponding;
    //}

    port--; // convert to 0-based
    if (port >= kUHCI_NUM_PORTS) 
	{
        return kIOReturnBadArgument;
    }
    p_status = ReadPortStatus(port);
	
	// check to see if suspend is on and connect is off - if so, clear the suspend
	if ((p_status & kUHCI_PORTSC_SUSPEND) && !(p_status & kUHCI_PORTSC_CCS))
	{
		USBLog(7, "AppleUSBUHCI[%p]::GetRootHubPortStatus - clearing suspend on disconnected port status[%p]", this, (void*)p_status);
		p_status &= kUHCI_PORTSC_MASK;				// make sure not to clear the change bits
		p_status &= ~kUHCI_PORTSC_SUSPEND;			// clear suspend
		WritePortStatus(port, p_status);			// this does a sync and a delay
		p_status = ReadPortStatus(port);			// reload
		USBLog(7, "AppleUSBUHCI[%p]::GetRootHubPortStatus - new port status[%p]", this, (void*)p_status);
	}
    
    /* Power is always turned on. */
    r_status = kHubPortPower;
    
    if (p_status & kUHCI_PORTSC_SUSPEND)
        r_status |= kHubPortSuspend;
    if (p_status & kUHCI_PORTSC_RESET)
        r_status |= kHubPortBeingReset;
    if (p_status & kUHCI_PORTSC_LS)
        r_status |= kHubPortLowSpeed;
    if (p_status & kUHCI_PORTSC_PED)
        r_status |= kHubPortEnabled;
    if (p_status & kUHCI_PORTSC_CCS)
        r_status |= kHubPortConnection;
    
    status->statusFlags = HostToUSBWord(r_status);
    
    /* Synthesize the change bits that are not
     * in the hardware.
     */
    r_change = r_status ^ _lastPortStatus[port];
    
    
    if (p_status & kUHCI_PORTSC_PEDC) 
	{
        r_change |= kHubPortEnabled;
    } else 
	{
        r_change &= ~kHubPortEnabled;
    }
    
    if (p_status & kUHCI_PORTSC_CSC) 
	{
        r_change |= kHubPortConnection;
    } else 
	{
        r_change &= ~kHubPortConnection;
    }
    
    /* Suspend change is only when suspend changes
        * from true to false.  It persists until
        * reset.
        */
    if ((_lastPortStatus[port] & kHubPortSuspend) && !(r_status & kHubPortSuspend)) 
	{
        USBLog(5, "AppleUSBUHCI[%p]::GetRootHubPortStatus - Turning on suspend change bit", this);
        _portSuspendChange[port] = true;
    }
    if (_portSuspendChange[port]) 
	{
        r_change |= kHubPortSuspend;
    } else {
        r_change &= ~kHubPortSuspend;
    }

    /* Synthetic reset bit. */
    if (_portWasReset[port]) 
	{
        r_change |= kHubPortBeingReset;
    }
    
    status->changeFlags = HostToUSBWord(r_change);
	if (status->changeFlags)
	{
		USBLog(5, "AppleUSBUHCI[%p]::GetRootHubPortStatus for port(%d) returned status is (%x,%x)", this, (int)port+1, r_status, r_change);
		RHDumpHubPortStatus(status);
	}
                                                                       
    _lastPortStatus[port] = r_status;
    
    return kIOReturnSuccess;
}