⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chw.cpp

📁 嵌入式操作系统WINCE5.0下的USB驱动程序
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// Parameters: port - 0 for the hub itself, otherwise the hub port number
//
// Returns: TRUE if status changed, else FALSE
//
// Notes:
// ******************************************************************
{
    // port == specifies root hub itself, whose status never changes
    if ( port > 0 ) {
        PORTSC portSC=Read_PORTSC(port);
        // We have to determine routine the device here if there is new attached device.
        if (portSC.bit.Power && portSC.bit.Owner==0) {
            if (portSC.bit.ConnectStatus == 0 ) { // If device not present now. just return status changes.
                return (portSC.bit.ConnectStatusChange!=0 || portSC.bit.EnableChange != 0 || portSC.bit.OverCurrentChange!=0);
            }
            else
            if (portSC.bit.ConnectStatusChange) {
                // This success if there is HighSpeed device. Otherwise it will route to companiou chip
                if (ResetAndEnablePort(port)) { 
                    DisablePort(port);
                    return TRUE;
                }
                else
                    return FALSE;
            }
            else
                return (portSC.bit.EnableChange != 0 || portSC.bit.OverCurrentChange!=0 || portSC.bit.ForcePortResume!=0) ;
        }
/* This is down by hardware.
        else 
        if (portSC.bit.ConnectStatus==0) { // There is no device . Set default route to this HC
            portSC.bit.Power=1;
            portSC.bit.Owner=0;
            // Do not touch write to clean register
            portSC.bit.ConnectStatusChange=0;
            portSC.bit.EnableChange=0;
            portSC.bit.OverCurrentChange=0;
            Write_PORTSC(port, portSC);
        }
*/
    }
    return FALSE;
}
// ******************************************************************
BOOL CHW::GetPortStatus( IN const UCHAR port,
                         OUT USB_HUB_AND_PORT_STATUS& rStatus )
//
// Purpose: This function will return the current root hub port
//          status in a non-hardware specific format
//
// Parameters: port - 0 for the hub itself, otherwise the hub port number
//
//             rStatus - reference to USB_HUB_AND_PORT_STATUS to get the
//                       status
//
// Returns: TRUE
//
// Notes:
// ******************************************************************
{
    memset( &rStatus, 0, sizeof( USB_HUB_AND_PORT_STATUS ) );
    if ( port > 0 ) {
        // request refers to a root hub port

        // read the port status register
        PORTSC portSC = Read_PORTSC( port );
        if (portSC.bit.Power && portSC.bit.Owner==0) {
            // Now fill in the USB_HUB_AND_PORT_STATUS structure
            rStatus.change.port.ConnectStatusChange = portSC.bit.ConnectStatusChange;
            rStatus.change.port.PortEnableChange = portSC.bit.EnableChange;
            rStatus.change.port.OverCurrentChange = portSC.bit.OverCurrentChange;
            // for root hub, we don't set any of these change bits:
            DEBUGCHK( rStatus.change.port.SuspendChange == 0 );
            DEBUGCHK( rStatus.change.port.ResetChange == 0 );
            rStatus.status.port.DeviceIsLowSpeed = 0;
            rStatus.status.port.DeviceIsHighSpeed = 1 ;
            rStatus.status.port.PortConnected = portSC.bit.ConnectStatus;
            rStatus.status.port.PortEnabled =  portSC.bit.Enabled;
            rStatus.status.port.PortOverCurrent = portSC.bit.OverCurrentActive ;
            // root hub ports are always powered
            rStatus.status.port.PortPower = 1;
            rStatus.status.port.PortReset = portSC.bit.Reset;
            rStatus.status.port.PortSuspended =  portSC.bit.Suspend;
            if (portSC.bit.ForcePortResume) { // Auto Resume Status special code.
                
                rStatus.change.port.SuspendChange=1;
                rStatus.status.port.PortSuspended=0;
                
                portSC.bit.ConnectStatusChange=0;
                portSC.bit.EnableChange=0;
                portSC.bit.OverCurrentChange=0;        

                portSC.bit.ForcePortResume =0;
                portSC.bit.Suspend=0;
                Write_PORTSC(port,portSC);
            }
        }
    }
#ifdef DEBUG
    else {
        // request is to Hub. rStatus was already memset to 0 above.
        DEBUGCHK( port == 0 );
        // local power supply good
        DEBUGCHK( rStatus.status.hub.LocalPowerStatus == 0 );
        // no over current condition
        DEBUGCHK( rStatus.status.hub.OverCurrentIndicator == 0 );
        // no change in power supply status
        DEBUGCHK( rStatus.change.hub.LocalPowerChange == 0 );
        // no change in over current status
        DEBUGCHK( rStatus.change.hub.OverCurrentIndicatorChange == 0 );
    }
#endif // DEBUG

    return TRUE;
}

// ******************************************************************
BOOL CHW::RootHubFeature( IN const UCHAR port,
                          IN const UCHAR setOrClearFeature,
                          IN const USHORT feature )
//
// Purpose: This function clears all the status change bits associated with
//          the specified root hub port.
//
// Parameters: port - 0 for the hub itself, otherwise the hub port number
//
// Returns: TRUE iff the requested operation is valid, FALSE otherwise.
//
// Notes: Assume that caller has already verified the parameters from a USB
//        perspective. The HC hardware may only support a subset of that
//        (which is indeed the case for UHCI).
// ******************************************************************
{
    if (port == 0) {
        // request is to Hub but...
        // uhci has no way to tweak features for the root hub.
        return FALSE;
    }

    // mask the change bits because we write 1 to them to clear them //
    PORTSC portSC= Read_PORTSC( port );
    if ( portSC.bit.Power && portSC.bit.Owner==0) {
        portSC.bit.ConnectStatusChange=0;
        portSC.bit.EnableChange=0;
        portSC.bit.OverCurrentChange=0;
        if (setOrClearFeature == USB_REQUEST_SET_FEATURE)
            switch (feature) {
              case USB_HUB_FEATURE_PORT_RESET:              portSC.bit.Reset=1;break;
              case USB_HUB_FEATURE_PORT_SUSPEND:            portSC.bit.Suspend=1; break;
              case USB_HUB_FEATURE_PORT_POWER:              portSC.bit.Power=1;break;
              default: return FALSE;
            }
        else
            switch (feature) {
              case USB_HUB_FEATURE_PORT_ENABLE:             portSC.bit.Enabled=0; break;
              case USB_HUB_FEATURE_PORT_SUSPEND:            // EHCI 2.3.9
                if (portSC.bit.Suspend !=0 ) {
                    portSC.bit.ForcePortResume=1; 
                    Write_PORTSC( port, portSC );
                    Sleep(20);
                    portSC.bit.ForcePortResume=0;
                }
                break;
              case USB_HUB_FEATURE_C_PORT_CONNECTION:       portSC.bit.ConnectStatusChange=1;break;
              case USB_HUB_FEATURE_C_PORT_ENABLE:           portSC.bit.EnableChange=1; break;
              case USB_HUB_FEATURE_C_PORT_RESET:            
              case USB_HUB_FEATURE_C_PORT_SUSPEND:
              case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
              case USB_HUB_FEATURE_PORT_POWER:
              default: return FALSE;
            }

        Write_PORTSC( port, portSC );
        return TRUE;
    }
    else
        return FALSE;
}


// ******************************************************************
BOOL CHW::ResetAndEnablePort( IN const UCHAR port )
//
// Purpose: reset/enable device on the given port so that when this
//          function completes, the device is listening on address 0
//
// Parameters: port - root hub port # to reset/enable
//
// Returns: TRUE if port reset and enabled, else FALSE
//
// Notes: This function takes approx 60 ms to complete, and assumes
//        that the caller is handling any critical section issues
//        so that two different ports (i.e. root hub or otherwise)
//        are not reset at the same time. please refer 4.2.2 for detail
// ******************************************************************
{
    BOOL fSuccess = FALSE;

    PORTSC portSC=Read_PORTSC(port);
    // no point reset/enabling the port unless something is attached
    if ( portSC.bit.Power && portSC.bit.Owner==0 && portSC.bit.ConnectStatus ) {
        // Do not touch Write to Clear Bit.
        portSC.bit.ConnectStatusChange=0;
        portSC.bit.EnableChange=0;
        portSC.bit.OverCurrentChange=0;
        
        // turn on reset bit
        portSC.bit.Reset =1 ;
        portSC.bit.Enabled=0;
        Write_PORTSC( port, portSC );
        // Note - Win98 waited 10 ms here. But, the new USB 1.1 spec
        // section 7.1.7.3 recommends 50ms for root hub ports
        Sleep( 50 );

        // Clear the reset bit
        portSC.bit.Reset =0 ;
        Write_PORTSC( port, portSC );
        for (DWORD dwIndex=0; dwIndex<10 && Read_PORTSC(port).bit.Reset!=0 ; dwIndex++)
            Sleep(10);
        
        portSC = Read_PORTSC( port );
        if ( portSC.bit.Enabled && portSC.bit.Reset == 0 ) {
            // port is enabled
            fSuccess = TRUE;
        }
        //
        // clear port connect & enable change bits
        //
        if (fSuccess) {
            portSC.bit.ConnectStatusChange=0; // Do not clean ConnectStatusChange.
            portSC.bit.EnableChange=1;
        }
        else  // Turn Off the OwnerShip. EHCI 4.2.2 
            portSC.bit.Owner=1;
        Write_PORTSC( port, portSC );
            
        // USB 1.1 spec, 7.1.7.3 - device may take up to 10 ms
        // to recover after reset is removed
        Sleep( 10 );
    }

    DEBUGMSG( ZONE_REGISTERS, (TEXT("Root hub, after reset & enable, port %d portsc = 0x%04x\n"), port, Read_PORTSC( port ) ) );
    return fSuccess;
}
// ******************************************************************
void CHW::DisablePort( IN const UCHAR port )
//
// Purpose: disable the given root hub port
//
// Parameters: port - port # to disable
//
// Returns: nothing
//
// Notes: This function will take about 10ms to complete
// ******************************************************************
{
    PORTSC portSC=Read_PORTSC(port);;
    // no point doing any work unless the port is enabled
    if ( portSC.bit.Power && portSC.bit.Owner==0 && portSC.bit.Enabled ) {
        // clear port enabled bit and enabled change bit,
        // but don't alter the connect status change bit,
        // which is write-clear.
        portSC.bit.Enabled=0;
        portSC.bit.ConnectStatusChange=0;
        portSC.bit.EnableChange=1;
        portSC.bit.OverCurrentChange=0;        
        Write_PORTSC( port, portSC );

        // disable port can take some time to act, because
        // a USB request may have been in progress on the port.
        Sleep( 10 );
    }
}
BOOL CHW::WaitForPortStatusChange (HANDLE m_hHubChanged)
{
    if (m_hUsbHubChangeEvent) {
        if (m_hHubChanged!=NULL) {
            HANDLE hArray[2];
            hArray[0]=m_hHubChanged;
            hArray[1]=m_hUsbHubChangeEvent;
            WaitForMultipleObjects(2,hArray,FALSE,INFINITE);
        }
        else
            WaitForSingleObject(m_hUsbHubChangeEvent,INFINITE);
        return TRUE;
    }
    return FALSE;
}

// ******************************************************************
VOID CHW::PowerMgmtCallback( IN BOOL fOff )
//
// Purpose: System power handler - called when device goes into/out of
//          suspend.
//
// Parameters:  fOff - if TRUE indicates that we're entering suspend,
//                     else signifies resume
//
// Returns: Nothing
//
// Notes: This needs to be implemented for HCDI
// ******************************************************************
{
    if ( fOff )
    {
        if ((GetCapability() & HCD_SUSPEND_RESUME)!= 0) {
            m_bDoResume=TRUE;
            SuspendHostController();
        }
        else {
            m_bDoResume=FALSE;;
            CHW::StopHostController();
        }
    }
    else
    {   // resuming...
        g_fPowerUpFlag = TRUE;
        if (m_bDoResume)
            ResumeHostController();
        if (!g_fPowerResuming)
            // can't use member data while `this' is invalid
            SetInterruptEvent(m_dwSysIntr);
    }
    return;
}
VOID CHW::SuspendHostController()
{
    if ( m_portBase != 0 ) {
        // initialize interrupt register - set only RESUME interrupts to enabled
        USBCMD usbcmd=Read_USBCMD();
        usbcmd.bit.RunStop=0;
        Write_USBCMD(usbcmd);
        // EHCI do not have group suspend. But. We can suspend each port.
        for (UINT port =1; port <= m_NumOfPort; port ++) {
            PORTSC portSC=Read_PORTSC(port);;
            // no point doing any work unless the port is enabled
            if ( portSC.bit.Power && portSC.bit.Owner==0 && portSC.bit.Enabled ) {
                portSC.bit.ConnectStatusChange=0;
                portSC.bit.EnableChange=0;
                portSC.bit.OverCurrentChange=0;        
                //
                portSC.bit.ForcePortResume =0;
                portSC.bit.Suspend=1;
                portSC.bit.WakeOnConnect = 1;
                portSC.bit.WakeOnDisconnect =1;
                portSC.bit.WakeOnOverCurrent =1;
                Write_PORTSC( port, portSC );
            }
        }

    }
}
VOID CHW:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -