コード例 #1
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));
}
コード例 #2
0
//================================================================================================
//
//   DozeController
//
//================================================================================================
//
IOReturn
AppleUSBUHCI::DozeController(void)
{
    UInt16				cmd;
	int				i;
	bool			portsBeingResumed = false;

	USBTrace( kUSBTUHCI, KTPUHCIDozeController, (uintptr_t)this, 0, 0, 0);
	
	USBLog(6, "AppleUSBUHCI[%p]::DozeController", this);
	
    for (i=0; i<kUHCI_NUM_PORTS; i++) 
	{
		if (_rhPortBeingResumed[i])
		{
			USBLog(1, "AppleUSBUHCI[%p]::DozeController - port (%d) is being resumed. not stopping the controller", this, i+1);
			portsBeingResumed = true;
		}
	}
	
	if (!portsBeingResumed)
	{
		showRegisters(7, "+DozeController -  stopping controller");
		Run(false);
		
		// In order to get a Resume Detected interrupt, the controller needs to be in Global suspend mode, so we will do that even when "dozing".
		
		USBLog(6, "AppleUSBUHCI[%p]::DozeController  Globally suspending", this);
		// 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);
		
	}

	return kIOReturnSuccess;
}
コード例 #3
0
//================================================================================================
//
//   EnableInterruptsFromController
//
//================================================================================================
//
IOReturn
AppleUSBUHCI::EnableInterruptsFromController(bool enable)
{
	USBTrace( kUSBTUHCI, KTPUHCIEnableInterrupts, (uintptr_t)this, enable, 0, 0);
	if (enable)
	{
		USBLog(5, "AppleUSBUHCI[%p]::EnableInterruptsFromController - enabling interrupts, USBIntr(%p) _savedUSBIntr(%p)", this, (void*)ioRead16(kUHCI_INTR), (void*)_saveInterrupts);
		ioWrite16(kUHCI_INTR, _saveInterrupts);
		_saveInterrupts = 0;
		EnableUSBInterrupt(true);
	}
	else
	{
		_saveInterrupts = ioRead16(kUHCI_INTR);
		ioWrite16(kUHCI_INTR, 0);
		EnableUSBInterrupt(false);
		USBLog(5, "AppleUSBUHCI[%p]::EnableInterruptsFromController - interrupts disabled, _saveInterrupts(%p)", this, (void*)_saveInterrupts);
	}
	
	return kIOReturnSuccess;
}
コード例 #4
0
//================================================================================================
//
// ResetControllerState
//
//================================================================================================
//
IOReturn
AppleUSBUHCI::ResetControllerState(void)
{
	UInt32				value;
	int					i;

	USBTrace( kUSBTUHCI, KTPUHCIResetControllerState, (uintptr_t)this, 0, 0, 0);
	USBLog(5, "AppleUSBUHCI[%p]::+ResetControllerState", this);

	// reset the controller
    Command(kUHCI_CMD_HCRESET);
    for(i=0; (i < kUHCI_RESET_DELAY) && (ioRead16(kUHCI_CMD) & kUHCI_CMD_HCRESET); i++) 
	{
        IOSleep(1);
    }
    if (i >= kUHCI_RESET_DELAY) 
	{
        USBError(1, "AppleUSBUHCI::ResetControllerStatecontroller - reset failed");
        return kIOReturnTimeout;
    }
    USBLog(5, "AppleUSBUHCI[%p]::ResetControllerStatecontroller - reset done after %d spins", this, i);

	// restore the frame list register
    if (_framesPaddr != NULL) 
	{
        ioWrite32(kUHCI_FRBASEADDR, _framesPaddr);
	}
	
	for (i = 0; i < kUHCI_NUM_PORTS; i++)
	{
		_lastPortStatus[i] = 0;
	}
	
	// Use 64-byte packets, and mark controller as configured
	Command(kUHCI_CMD_MAXP | kUHCI_CMD_CF);

    USBLog(5, "AppleUSBUHCI[%p]::-ResetControllerState", this);
	return kIOReturnSuccess;
}
コード例 #5
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;
}
コード例 #6
0
//================================================================================================
//
//   RestartControllerFromReset
//
//================================================================================================
//
IOReturn
AppleUSBUHCI::RestartControllerFromReset(void)
{
	USBTrace( kUSBTUHCI, KTPUHCIRestartControllerFromReset, (uintptr_t)this, 0, 0, 0);
	USBLog(5, "AppleUSBUHCI[%p]::RestartControllerFromReset - _myBusState(%d) CMD(%p) STS(%p) FRBASEADDR(%p) IOPCIConfigCommand(%p)", this, (int)_myBusState, (void*)ioRead16(kUHCI_CMD), (void*)ioRead16(kUHCI_STS), (void*)ioRead32(kUHCI_FRBASEADDR), (void*)_device->configRead16(kIOPCIConfigCommand));

	Run(true);

	// prepare the _saveInterrupts variable for later enabling
	_saveInterrupts = kUHCI_INTR_TIE | kUHCI_INTR_RIE | kUHCI_INTR_IOCE | kUHCI_INTR_SPIE;
	USBLog(5, "AppleUSBUHCI[%p]::RestartControllerFromReset - I set _saveInterrupts to (%p)", this, (void*)_saveInterrupts);
			
	return kIOReturnSuccess;
}
コード例 #7
0
//================================================================================================
//
//   ResumeController
//
//================================================================================================
//
void			
AppleUSBUHCI::ResumeController(void)
{
    UInt16			cmd;
	int				i;
    
	USBTrace( kUSBTUHCI, KTPUHCIResumeController , (uintptr_t)this, 0, 0, 0);
	showRegisters(7, "+ResumeController");
	
	cmd = ioRead16(kUHCI_CMD);
	if (cmd & kUHCI_CMD_RS)
	{
		USBLog(3, "AppleUSBUHCI[%p]::ResumeController - already running - returning", this);
		return;
	}
	
	// I need to save the existing frame list before I turn on processing so I can send SOF only for 10ms after we turn the controller on
	for (i=0;i < kUHCI_NVFRAMES; i++)
	{
		_frameList[i] |= HostToUSBLong(kUHCI_FRAME_T);
	}
			
	if (cmd & kUHCI_CMD_EGSM)
	{
		USBLog(5, "AppleUSBUHCI[%p]::ResumeController controller is globally suspended - forcing resume", this);
		cmd |= kUHCI_CMD_FGR;
		ioWrite16(kUHCI_CMD, cmd);
		cmd = ioRead16(kUHCI_CMD);
		USBLog(5, "AppleUSBUHCI[%p]::ResumeController after EGSM->FGR, cmd is[%p]", this, (void*)cmd);
	}
    
	if (cmd & kUHCI_CMD_FGR)
	{
		// this could either be because the remote wwakeup caused this state or because we did above
		// need to wait 20ms
		IOSleep(20);
		cmd &= ~kUHCI_CMD_FGR;
		cmd &= ~kUHCI_CMD_EGSM;
		ioWrite16(kUHCI_CMD, cmd);
	}
	if ((cmd & (kUHCI_CMD_MAXP | kUHCI_CMD_CF)) != (kUHCI_CMD_MAXP | kUHCI_CMD_CF))
	{
		USBLog(5, "AppleUSBUHCI[%p]::ResumeController marking MAXP and CF", this);
		cmd |= (kUHCI_CMD_MAXP | kUHCI_CMD_CF);
		ioWrite16(kUHCI_CMD, cmd);
	}
	
	// restore the frame list register
    if (_framesPaddr != NULL) 
	{
		USBLog(5, "AppleUSBUHCI[%p]::ResumeController setting FRBASEADDR[%p]", this, (void*)_framesPaddr);
        ioWrite32(kUHCI_FRBASEADDR, _framesPaddr);
	}
	
	USBLog(5, "AppleUSBUHCI[%p]::ResumeController starting controller", this);
	Run(true);
	
	// wait 10 ms for the device to recover
	IOSleep(10);
	
	// restore the list
	for (i=0;i < kUHCI_NVFRAMES; i++)
	{
		_frameList[i] &= ~HostToUSBLong(kUHCI_FRAME_T);
	}
    
	USBLog(7, "AppleUSBUHCI[%p]::ResumeController resume done, cmd %x, status %x ports[%p, %p]", this, ioRead16(kUHCI_CMD), ioRead16(kUHCI_STS),(void*)ReadPortStatus(0), (void*)ReadPortStatus(1));
	showRegisters(7, "-ResumeController");
}
コード例 #8
0
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;
}
コード例 #9
0
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);
}
コード例 #10
0
// Called at software interrupt time
void
AppleUSBUHCI::HandleInterrupt(void)
{
	UInt16					status;
	UInt32					intrStatus;
	bool					needReset = false;
		
	status = ioRead16(kUHCI_STS);

	USBTrace_Start( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt,  (uintptr_t)this, 0, 0, 0);

	if (_hostControllerProcessInterrupt & kUHCI_STS_HCPE)
	{
		_hostControllerProcessInterrupt = 0;
		USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller process error", this);
		USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 1 );
		needReset = true;
	}
	if (_hostSystemErrorInterrupt & kUHCI_STS_HSE)
	{
		_hostSystemErrorInterrupt = 0;
		USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller system error(CMD:%p STS:%p INTR:%p PORTSC1:%p PORTSC2:%p FRBASEADDR:%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*)_device->configRead16(kIOPCIConfigCommand));
		USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, ioRead16(kUHCI_CMD), 0, 2  );
		USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsHandleInterrupt, ioRead16(kUHCI_STS), ioRead16(kUHCI_INTR), ioRead16(kUHCI_PORTSC1), 3  );
		USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsHandleInterrupt, ioRead16(kUHCI_PORTSC2), ioRead32(kUHCI_FRBASEADDR), _device->configRead16(kIOPCIConfigCommand), 4 );
		needReset = true;
	}
	if (_resumeDetectInterrupt & kUHCI_STS_RD) 
	{
		_resumeDetectInterrupt = 0;
		USBLog(2, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller resume detected - calling EnsureUsability", this);
		USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 6);
		EnsureUsability();		
	}
	if (_usbErrorInterrupt & kUHCI_STS_EI) 
	{
		_usbErrorInterrupt = 0;
		USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 7);
		USBLog(6, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller error interrupt", this);
	}
	if (_usbCompletionInterrupt & kUHCI_STS_INT)
	{
		_usbCompletionInterrupt = 0;
		
		// USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 8);
		// updates hardware interrupt time from shadow vars that are se in the real irq handler
		UpdateFrameNumberWithTime();

		USBLog(7, "AppleUSBUHCI[%p]::HandleInterrupt - Normal interrupt", this);
		if (_consumerCount != _producerCount)
		{	
			USBLog(7, "AppleUSBUHCI[%p]::HandleInterrupt - Isoch was handled", this);
		}
	}
	
	// this code probably doesn't work
	if (needReset) 
	{
		IOSleep(1000);
		USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Resetting controller due to errors detected at interrupt time (0x%x)", this, status);
		USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, status, needReset, 5 );
		Reset(true);
		Run(true);
	}

	if (_myPowerState == kUSBPowerStateOn)
	{
		USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, status, 0, 9);
		ProcessCompletedTransactions();
	
		// Check for root hub status change
		RHCheckStatus();
	}
	else
	{
		USBLog(2, "AppleUSBUHCI[%p]::HandleInterrupt - deferring further processing until we are running again", this);
		USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 10);
	}
	USBTrace_End( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt,  (uintptr_t)this, 0, 0, 0);
}
コード例 #11
0
// Called at hardware interrupt time
bool
AppleUSBUHCI::FilterInterrupt(void)
{
	UInt16						activeInterrupts;
    Boolean						needSignal = false;
	UInt64						currentFrame;
	uint64_t					timeStamp;
	
	// we leave all interrupts enabled, so see which ones are active
	activeInterrupts = ioRead16(kUHCI_STS) & kUHCI_STS_INTR_MASK;
	
	if (activeInterrupts != 0) 
	{
		USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsFilterInterrupt , (uintptr_t)this, activeInterrupts, 0, 3 );

		if (activeInterrupts & kUHCI_STS_HCPE)
		{
			// Host Controller Process Error - usually a bad data structure on the list
			_hostControllerProcessInterrupt = kUHCI_STS_HCPE;
			ioWrite16(kUHCI_STS, kUHCI_STS_HCPE);
			needSignal = true;
			//USBLog(1, "AppleUSBUHCI[%p]::FilterInterrupt - HCPE error - legacy reg = %p", this, (void*)_device->configRead16(kUHCI_PCI_LEGKEY));
			USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsFilterInterrupt, (uintptr_t)this, _hostControllerProcessInterrupt, _device->configRead16(kUHCI_PCI_LEGKEY), 1 );
		}
		if (activeInterrupts & kUHCI_STS_HSE)
		{
			// Host System Error - usually a PCI issue
			_hostSystemErrorInterrupt = kUHCI_STS_HSE;
			ioWrite16(kUHCI_STS, kUHCI_STS_HSE);
			needSignal = true;
			//USBLog(1, "AppleUSBUHCI[%p]::FilterInterrupt - HSE error - legacy reg = %p", this, (void*)_device->configRead16(kUHCI_PCI_LEGKEY));
			USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsFilterInterrupt, (uintptr_t)this, _hostSystemErrorInterrupt, _device->configRead16(kUHCI_PCI_LEGKEY), 2 );
		}
		if (activeInterrupts & kUHCI_STS_RD)
		{
			// Resume Detect - remote wakeup
			_resumeDetectInterrupt = kUHCI_STS_RD;
			ioWrite16(kUHCI_STS, kUHCI_STS_RD);
			needSignal = true;
		}
		if (activeInterrupts & kUHCI_STS_EI)
		{
			// USB Error Interrupt - transaction error (CRC, timeout, etc)
			_usbErrorInterrupt = kUHCI_STS_EI;
			ioWrite16(kUHCI_STS, kUHCI_STS_EI);
			needSignal = true;
		}
		if (activeInterrupts & kUHCI_STS_INT)
		{
			// Normal IOC interrupt - we need to check out low latency Isoch as well
			timeStamp = mach_absolute_time();
			ioWrite16(kUHCI_STS, kUHCI_STS_INT);
			needSignal = true;
						
			// This function will give us the current frame number and check for rollover at the same time
			// since we are calling from filterInterrupts we will not be preempted, it will also update the 
			// cached copy of the frame_number_with_time 
			GetFrameNumberInternal();
			
			// we need to check the periodic list to see if there are any Isoch TDs which need to come off
			// and potentially have their frame lists updated (for Low Latency) we will place them in reverse
			// order on a "done queue" which will be looked at by the isoch scavanger
			// only do this if the periodic schedule is enabled
			if (!_inAbortIsochEP  && (_outSlot < kUHCI_NVFRAMES))
			{
				AppleUHCIIsochTransferDescriptor	*cachedHead;
				UInt32								cachedProducer;
				UInt16								curSlot, testSlot, nextSlot;
				
				curSlot = (ReadFrameNumber() & kUHCI_NVFRAMES_MASK);
				
				cachedHead = (AppleUHCIIsochTransferDescriptor*)_savedDoneQueueHead;
				cachedProducer = _producerCount;
				testSlot = _outSlot;
				
				while (testSlot != curSlot)
				{
					IOUSBControllerListElement				*thing, *nextThing;
					AppleUHCIIsochTransferDescriptor		*isochTD;
					
					nextSlot = (testSlot+1) & kUHCI_NVFRAMES_MASK;
					thing = _logicalFrameList[testSlot];
					while (thing != NULL)
					{
						nextThing = thing->_logicalNext;
						isochTD = OSDynamicCast(AppleUHCIIsochTransferDescriptor, thing);
						
						if (!isochTD)
							break;						// only care about Isoch in this list - if we get here we are at the interrupt TDs
												
						// need to unlink this TD
						_logicalFrameList[testSlot] = nextThing;
						_frameList[testSlot] = HostToUSBLong(thing->GetPhysicalLink());
						
						if (isochTD->_lowLatency)
							isochTD->frStatus = isochTD->UpdateFrameList(*(AbsoluteTime*)&timeStamp);
						// place this guy on the backward done queue
						// the reason that we do not use the _logicalNext link is that the done queue is not a null terminated list
						// and the element linked "last" in the list might not be a true link - trust me
						isochTD->_doneQueueLink = cachedHead;
						cachedHead = isochTD;
						cachedProducer++;
						if (isochTD->_pEndpoint)
						{
							isochTD->_pEndpoint->onProducerQ++;
							OSDecrementAtomic( &(isochTD->_pEndpoint->scheduledTDs));
						}
						
						thing = nextThing;
					}
					testSlot = nextSlot;
					_outSlot = testSlot;
				}
				IOSimpleLockLock( _wdhLock );
				
				_savedDoneQueueHead = cachedHead;	// updates the shadow head
				_producerCount = cachedProducer;	// Validates _producerCount;
				
				IOSimpleLockUnlock( _wdhLock );

			}
		
			// 8394970:  Make sure we set the flag AFTER we have incremented our producer count.
			_usbCompletionInterrupt = kUHCI_STS_INT;
		}
	}
	
	// We will return false from this filter routine,
	// but will indicate that there the action routine should be called
	// by calling _filterInterruptSource->signalInterrupt(). 
	// This is needed because IOKit will disable interrupts for a level interrupt
	// after the filter interrupt is run, until the action interrupt is called.
	// We want to be able to have our filter interrupt routine called
	// before the action routine runs, if needed.  That is what will enable
	// low latency isoch transfers to work, as when the
	// system is under heavy load, the action routine can be delayed for tens of ms.
	//
	if (needSignal)
		_interruptSource->signalInterrupt();
	
	return false;
}
コード例 #12
0
//
// This is similar to the code in GetFrameNumber that is only called at hw irq time.  It uses separate vars since it can preempt the 
// real GetFrameNumber function.  It does not use the _frameLock mutex because filterinterrupt cannot be preempted.
//
UInt64
AppleUSBUHCI::GetFrameNumberInternal(void)
{
    UInt32				lastIrqFrameLow;
	UInt32				currentIrqFrameLow;
    UInt64				lastIrqFrameHi;
	UInt64              currentFrame;
	
	//	
	// ** only call this function from FilterInterrupt or if the UHCI interrupts are disabled ** 
	//
	// This code attempts to record the time of the SOF. According to the UHCI 1.1 spec
	// the IRQ happens at EOF (end of frame) time but we will treat this like SOF time for our purposes.  
	//
	// *NOTE: debug log messages are disabled. The debug messages can only be enabled if we are using kprintf or some 
	// logging feature that is safe to call at FilterInterrupt time.

	// If the controller is halted, then we should just bail out
	if (ioRead16(kUHCI_STS) & kUHCI_STS_HCH)
	{
		if (_myPowerState == kUSBPowerStateOn)
		{
			// do not use USBLog from here, since this method can be called in interrupt context
			// USBLog(1, "AppleUSBUHCI[%p]::GetFrameNumber called but controller is halted",  this);
			USBTrace( kUSBTUHCIInterrupts,  kTPUHCIInterruptsGetFrameNumberInternal, (uintptr_t)this, kUHCI_STS_HCH, 0, 0);
		}
		return 0;
	}
	
	//USBLog(7, "AppleUSBUHCI[%p]::GetFrameNumberInternal - check frame number", this);
	
	// _lastIrqFrame preserves the last 64 bit frame number we recorded
	lastIrqFrameLow = _lastIrqFrameLow;
	lastIrqFrameHi = _lastIrqFrame & ~0x7ff;
	
	currentIrqFrameLow = ReadFrameNumberRegister();
	
	// check for overflow bit(10) change
	if (currentIrqFrameLow <= lastIrqFrameLow) 
	{
		uint64_t		tempTime;
		
		// 11 bit overflow (bit 10 changed)
		// bump high part
			
		lastIrqFrameHi += 0x800;
		
		//
		// if the frame list rolled over or we don't have a value yet then update our cached copy of frame_with_time
		// the frame counter is 11 bits wide, bit 10 will change every 1000ms (1 sec). 
		//
		// note: we may make an extra update if we happen to take an interrupt when the 64 bit value rolls over but 
		// this is once in a blue moon and won't cause a problem. 
		//
		
		currentFrame = lastIrqFrameHi + ((UInt64) currentIrqFrameLow);
			
		_tempAnchorFrame = currentFrame;
		tempTime = mach_absolute_time();
		_tempAnchorTime = *(AbsoluteTime*)&tempTime;

	} else 
	{
		currentFrame = lastIrqFrameHi + ((UInt64) currentIrqFrameLow);
	}
	
	_lastIrqFrameLow = currentIrqFrameLow;
	_lastIrqFrame = currentFrame;
		
    // USBLog(7, "AppleUSBUHCI[%p]:: GetFrameNumberInternal - frame number is %qx (%qd) %qd .sec", this, currentFrame, currentFrame, currentFrame/1000);
	
    return (currentFrame);
}