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

📄 chw.cpp

📁 Latest USB 802.3, HID printer and mass storage divers from Microsoft for Platform Builder 4.2.
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    // this allows us not to have to alert the PDD that the addresses have changed.

    DEBUGCHK( g_fPowerResuming == FALSE );

    // order is important! resuming indicates that the hcd object is temporarily invalid
    // while powerup simply signals that a powerup event has occurred. once the powerup
    // flag is cleared, we will repeat this whole sequence should it get resignalled.
    g_fPowerUpFlag = FALSE;
    g_fPowerResuming = TRUE;

    const PUCHAR pBufVirt = m_pMem->m_pVirtBase, pBufPhys = m_pMem->m_pPhysBase;
    DWORD cb0 = m_pMem->m_cbTotal, cb1 = m_pMem->m_cbHighPri;

    DeviceDeInitialize();
    while (1) {  // breaks out upon successful reinit of the object

        m_pMem->ReInit();
        if (DeviceInitialize())
            break;
        // getting here means we couldn't reinit the HCD object!
        DEBUGMSG(ZONE_ERROR, (TEXT("USB cannot reinit the HCD at CE resume; retrying...\n")));
        DeviceDeInitialize();
        Sleep(15000);
    }

    // the hcd object is valid again. if a power event occurred between the two flag
    // assignments above then the IST will reinitiate this sequence.
    g_fPowerResuming = FALSE;
    if (g_fPowerUpFlag)
        PowerMgmtCallback(TRUE);
    
    return 0;
}
DWORD CHW::UsbInterruptThreadStub( IN PVOID context )
{
    return ((CHW *)context)->UsbInterruptThread();
}

// ******************************************************************
DWORD CHW::UsbInterruptThread( )
//
// Purpose: Main IST to handle interrupts from the USB host controller
//
// Parameters: context - parameter passed in when starting thread,
//                       (currently unused)
//
// Returns: 0 on thread exit.
//
// Notes:
//
//        This function is private
// ******************************************************************
{
    DEBUGMSG(ZONE_INIT && ZONE_VERBOSE, (TEXT("+CHW::Entered USBInterruptThread\n")));

    while ( !m_fUsbInterruptThreadClosing ) {
        WaitForSingleObject(m_hUsbInterruptEvent, INFINITE);
        if ( m_fUsbInterruptThreadClosing ) {
            break;
        }

    #ifdef DEBUG
        USHORT usbsts = Read_USBSTS();
        DWORD dwFrame;
        GetFrameNumber(&dwFrame); // calls UpdateFrameCounter
        DEBUGMSG( ZONE_REGISTERS, (TEXT("!!!interrupt!!!! on frame index + 1 = 0x%08x, USBSTS = 0x%04x\n"), dwFrame, usbsts ) );
    #else
        UpdateFrameCounter();
    #endif // DEBUG

        Clear_USBSTS( );

        // TODO - differentiate between USB interrupts, which are
        // for transfers, and host interrupts (UHCI spec 2.1.2).
        // For the former, we need to call CPipe::SignalCheckForDoneTransfers.
        // For the latter, we need to call whoever will handle
        // resume/error processing.

        // For now, we just notify CPipe so that transfers
        // can be checked for completion

        // This flag gets cleared in the resume thread.
        if(g_fPowerUpFlag)
        {
            if (m_bDoResume) {
                g_fPowerUpFlag=FALSE;
                // UHCI 2.1.1
                WORD wUSBCmd = Read_USBCMD();
                Sleep(20); 
                Write_USBCMD(wUSBCmd & ~UHCD_USBCMD_FORCE_GLOBAL_RESUME);
            }
            else {
                if (g_fPowerResuming) {
                    // this means we've restarted an IST and it's taken an early interrupt;
                    // just pretend it didn't happen for now because we're about to be told to exit again.
                    continue;
                }
                HcdPdd_InitiatePowerUp((DWORD) m_pPddContext);
                HANDLE ht;
                while ((ht = CreateThread(NULL, 0, CeResumeThreadStub, this, 0, NULL)) == NULL) {
                    RETAILMSG(1, (TEXT("HCD IST: cannot spin a new thread to handle CE resume of USB host controller; sleeping.\n")));
                    Sleep(15000);  // 15 seconds later, maybe it'll work.
                }
                CeSetThreadPriority( ht, g_IstThreadPriority );
                CloseHandle(ht);
                
                // The CE resume thread will force this IST to exit so we'll be cooperative proactively.
                break;
            }
        }
        else
            //CPipe::SignalCheckForDoneTransfers( );
            SignalCheckForDoneTransfers( );

        InterruptDone(m_dwSysIntr);
    }

    DEBUGMSG(ZONE_INIT && ZONE_VERBOSE, (TEXT("-CHW::Leaving USBInterruptThread\n")));

    return (0);
}

// ******************************************************************
void CHW::UpdateFrameCounter( void )
//
// Purpose: Updates our internal frame counter
//
// Parameters: None
//
// Returns: Nothing
//
// Notes: The UHCI frame number register is only 11 bits, or 2047
//        long. Thus, the counter will wrap approx. every 2 seconds.
//        That is insufficient for Isoch Transfers, which
//        may need to be scheduled out into the future by more
//        than 2 seconds. So, we maintain an internal 32 bit counter
//        for the frame number, which will wrap in 50 days.
//
//        This function should be called at least once every two seconds,
//        otherwise we will miss frames.
//
// ******************************************************************
{
#ifdef DEBUG
    DWORD dwTickCountLastTime = GetTickCount();
#endif

    EnterCriticalSection( &m_csFrameCounter );

#ifdef DEBUG
    // If this fails, we haven't been called in a long time,
    // so the frame number is no longer accurate
    if (GetTickCount() - dwTickCountLastTime >= 2000 )
        DEBUGMSG(1, (TEXT("!UHCI - CHW::UpdateFrameCounter missed frame count;")
                     TEXT(" isoch packets may have been dropped.\n")));
    dwTickCountLastTime = GetTickCount();
#endif // DEBUG

    // This algorithm is right out of the Win98 uhcd.c code
    USHORT currentFRNUM = Read_FRNUM() & UHCD_FRNUM_MASK;
    // check whether the MSB in m_frameCounterLowPart and currentFRNUM differ
    if ( (m_frameCounterLowPart ^ currentFRNUM) & UHCD_FRNUM_COUNTER_MSB ) {
        // Yes, they are different. Update m_frameCounterHighPart
        m_frameCounterHighPart += (UHCD_FRNUM_COUNTER_MSB << 1) -
                ((currentFRNUM ^ m_frameCounterHighPart) & UHCD_FRNUM_COUNTER_MSB);
    }
    m_frameCounterLowPart = currentFRNUM;

    LeaveCriticalSection( &m_csFrameCounter );
}

// ******************************************************************
BOOL CHW::GetFrameNumber( OUT LPDWORD lpdwFrameNumber )
//
// Purpose: Return the current frame number
//
// Parameters: None
//
// Returns: 32 bit current frame number
//
// Notes: See also comment in UpdateFrameCounter
// ******************************************************************
{
    EnterCriticalSection( &m_csFrameCounter );

    // This algorithm is right out of the Win98 uhcd.c code
    UpdateFrameCounter();
    DWORD frame = ((m_frameCounterLowPart & UHCD_FRNUM_INDEX_MASK) | m_frameCounterHighPart) +
                    ((m_frameCounterLowPart ^ m_frameCounterHighPart) & UHCD_FRNUM_COUNTER_MSB);

    LeaveCriticalSection( &m_csFrameCounter );

    *lpdwFrameNumber=frame;
    return TRUE;
}

// ******************************************************************
BOOL CHW::WaitOneFrame( void )
//
// Purpose: Block the current thread until the HC hardware is
//          no longer processing the current USB frame.
//
// Parameters: None
//
// Returns: TRUE on success, FALSE if the HW is unavailable or not running.
//
// Notes:
// ******************************************************************
{
#ifdef CE_PREv3
    // Use the hardware, Luke!
    // The OS' system clock (used for scheduling) has 25ms granularity
    // which is just too high.
    if ((Read_USBCMD() & UHCD_USBCMD_RUN_STOP) == 0)
        // We check the USBCMD register instead of the USBSTS register because
        // Intel's HC can be stopped without the HCHALTED bit being set.
        return FALSE;

    DWORD frame0 = GetFrameNumber();

    while (GetFrameNumber() == frame0)
        ; // spin

#else // 3.0 and later use 1ms system clock
    // This isn't totally accurate (e.g., when the frame length changes)
    // but it's close enough and keeps us from spinning.
    Sleep(1);

#endif

    return TRUE;
}

// ******************************************************************
BOOL CHW::GetFrameLength( OUT LPUSHORT lpuFrameLength )
//
// Purpose: Return the current frame length in 12 MHz clocks
//          (i.e. 12000 = 1ms)
//
// Parameters: None
//
// Returns: frame length
//
// Notes: Only part of the frame length is stored in the hardware
//        register, so an offset needs to be added.
// ******************************************************************
{
    *lpuFrameLength=(Read_SOFMOD() & UHCD_SOFMOD_MASK) + UHCD_SOFMOD_MINIMUM_LENGTH;
    return TRUE;
}

// ******************************************************************
BOOL CHW::SetFrameLength( IN HANDLE hEvent,
                          IN USHORT uFrameLength )
//
// Purpose: Set the Frame Length in 12 Mhz clocks. i.e. 12000 = 1ms
//
// Parameters:  hEvent - event to set when frame has reached required
//                       length
//
//              uFrameLength - new frame length
//
// Returns: TRUE if frame length changed, else FALSE
//
// Notes:
// ******************************************************************
{
    BOOL fSuccess = FALSE;

    // to prevent multiple threads from simultaneously adjusting the
    // frame length, InterlockedTestExchange is used. This is
    // cheaper than using a critical section.
    if ( FALSE == InterlockedTestExchange( &m_fFrameLengthIsBeingAdjusted,
                                           FALSE, // Test value (Old value)
                                           TRUE ) ) { // New value

        // m_fFrameLengthIsBeingAdjusted was set to TRUE
        // by the InterlockedTestExchange
        if ( uFrameLength >= UHCD_SOFMOD_MINIMUM_LENGTH &&
             uFrameLength <= UHCD_SOFMOD_MAXIMUM_LENGTH &&
             hEvent != NULL ) {

            // ok, all the params are fine
            m_hAdjustDoneCallbackEvent = hEvent;
            m_uNewFrameLength = uFrameLength;
            InterlockedExchange( &m_fStopAdjustingFrameLength, FALSE );

            // the frame length needs to be adjusted over
            // many frames, so we need a separate thread

            HANDLE hWorkerThread = CreateThread( 0, 0, UsbAdjustFrameLengthThreadStub, this, 0, NULL );
            if ( hWorkerThread != NULL ) {
                CeSetThreadPriority( hWorkerThread, g_IstThreadPriority + RELATIVE_PRIO_ADJUST_FRAME );
                CloseHandle( hWorkerThread );
                hWorkerThread = NULL;
                fSuccess = TRUE;
            }
        }
        if ( !fSuccess ) {
            // we didn't succeed, so change m_fFrameLengthIsBeingAdjusted
            // back to FALSE
        #ifdef DEBUG
            LONG oldValue =
        #endif // DEBUG
                InterlockedExchange( &m_fFrameLengthIsBeingAdjusted, FALSE );
            DEBUGCHK( oldValue );
        }
    }
    return fSuccess;
}

// ******************************************************************
BOOL CHW::StopAdjustingFrame( void )
//
// Purpose: Stop modifying the host controller frame length

⌨️ 快捷键说明

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