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

📄 chw.cpp

📁 Latest USB 802.3, HID printer and mass storage divers from Microsoft for Platform Builder 4.2.
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//
// Parameters: None
//
// Returns: TRUE
//
// Notes:
// ******************************************************************
{
    InterlockedExchange( &m_fStopAdjustingFrameLength, TRUE );
    return TRUE;
}
DWORD CHW::UsbAdjustFrameLengthThreadStub(IN PVOID context )
{
    return ((CHW *)context)->UsbAdjustFrameLengthThread();
}
// ******************************************************************
DWORD CHW::UsbAdjustFrameLengthThread( )
//
// Purpose: Worker thread to handle frame length adjustment
//
// Parameters: context - parameter passed in when starting thread,
//                       (currently unused)
//
// Returns: 0 on thread exit.
//
// Notes:
//
//        This function is private
// ******************************************************************
{
    DEBUGMSG(ZONE_REGISTERS && ZONE_VERBOSE, (TEXT("+CHW::Entered UsbAdjustFrameLengthThread\n")));

    DEBUGCHK( m_fFrameLengthIsBeingAdjusted &&
              !m_fStopAdjustingFrameLength &&
              m_hAdjustDoneCallbackEvent != NULL &&
              m_uNewFrameLength >= UHCD_SOFMOD_MINIMUM_LENGTH &&
              m_uNewFrameLength <= UHCD_SOFMOD_MAXIMUM_LENGTH );

    const UCHAR uRequiredSOFMOD = UCHAR( m_uNewFrameLength - UHCD_SOFMOD_MINIMUM_LENGTH );

    // if the interrupt thread is closing, or we're signaled
    // to stop adjusting the frame length, stop!
    while ( !m_fStopAdjustingFrameLength &&
            !m_fUsbInterruptThreadClosing ) {

        UCHAR uCurrentSOFMOD = Read_SOFMOD() & UHCD_SOFMOD_MASK;
        DEBUGMSG(ZONE_REGISTERS, (TEXT("CHW::UsbAdjustFrameLengthThread, current length = %d, required = %d\n"), UHCD_SOFMOD_MINIMUM_LENGTH + uCurrentSOFMOD, UHCD_SOFMOD_MINIMUM_LENGTH + uRequiredSOFMOD ));
        if ( uCurrentSOFMOD == uRequiredSOFMOD ) {
            // ok, we're done
            __try {
                SetEvent( m_hAdjustDoneCallbackEvent );
            } __except(EXCEPTION_EXECUTE_HANDLER) {
            }
            break;
        } else if ( uCurrentSOFMOD > uRequiredSOFMOD ) {
            uCurrentSOFMOD--;
        } else {
            DEBUGCHK( uCurrentSOFMOD < uRequiredSOFMOD );
            uCurrentSOFMOD++;
        }
        // USB spec 1.1, section 7.1.12 says we can't adjust
        // the frame length by more than 1 bit every 6 frames.
        // Assuming a maximum frame length of 12063 bits, plus
        // 15 bits error, that totals 6.039ms. So, just to
        // be safe, we'll sleep 7 ms before adjusting the length.
        Sleep( 7 );

        Write_SOFMOD( uCurrentSOFMOD );
    }
    // set m_fFrameLengthIsBeingAdjusted to FALSE
    InterlockedExchange( &m_fFrameLengthIsBeingAdjusted, FALSE );

    DEBUGMSG(ZONE_REGISTERS, (TEXT("-CHW::UsbAdjustFrameLengthThread\n")));

    return (0);
}

// ******************************************************************
BOOL CHW::DidPortStatusChange( IN const UCHAR port )
//
// Purpose: Determine whether the status of root hub port # "port" changed
//
// 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
    BOOL fChanged = FALSE;
    if ( port > 0 ) {
        fChanged = Read_PORTSC( port ) & (UHCD_PORTSC_CONNECT_STATUS_CHANGE | UHCD_PORTSC_PORT_ENABLE_CHANGE);
    }
    return !!fChanged;
}

// ******************************************************************
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
        const USHORT portsc = Read_PORTSC( port );

        // Now fill in the USB_HUB_AND_PORT_STATUS structure
        rStatus.change.port.ConnectStatusChange = !!(portsc & UHCD_PORTSC_CONNECT_STATUS_CHANGE);
        rStatus.change.port.PortEnableChange = !!(portsc & UHCD_PORTSC_PORT_ENABLE_CHANGE);
        // for root hub, we don't set any of these change bits:
        DEBUGCHK( rStatus.change.port.OverCurrentChange == 0 );
        DEBUGCHK( rStatus.change.port.SuspendChange == 0 );
        DEBUGCHK( rStatus.change.port.ResetChange == 0 );
        rStatus.status.port.DeviceIsLowSpeed = !!(portsc & UHCD_PORTSC_LOW_SPEED_DEVICE);
        rStatus.status.port.PortConnected = !!(portsc & UHCD_PORTSC_CONNECT_STATUS);
        rStatus.status.port.PortEnabled = !!(portsc & UHCD_PORTSC_PORT_ENABLED);
        // no root port over current indicators in UHCI
        DEBUGCHK( rStatus.status.port.PortOverCurrent == 0 );
        // root hub ports are always powered
        rStatus.status.port.PortPower = 1;
        rStatus.status.port.PortReset = !!(portsc & UHCD_PORTSC_PORT_RESET);
        rStatus.status.port.PortSuspended = !!(portsc & UHCD_PORTSC_SUSPEND);
    }
#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 //
    USHORT bmStatus = Read_PORTSC( port );
    bmStatus &= ~(UHCD_PORTSC_CONNECT_STATUS_CHANGE | UHCD_PORTSC_PORT_ENABLE_CHANGE);

    if (setOrClearFeature == USB_REQUEST_SET_FEATURE)
        switch (feature) {
          case USB_HUB_FEATURE_PORT_RESET:              bmStatus |= UHCD_PORTSC_PORT_RESET; break;
          case USB_HUB_FEATURE_PORT_SUSPEND:            bmStatus |= UHCD_PORTSC_SUSPEND; break;
          case USB_HUB_FEATURE_PORT_POWER:              // not supported by UHCI //
          default: return FALSE;
        }
    else
        switch (feature) {
          case USB_HUB_FEATURE_PORT_ENABLE:     bmStatus &= ~UHCD_PORTSC_PORT_ENABLED; break;
          case USB_HUB_FEATURE_PORT_SUSPEND:        bmStatus &= ~UHCD_PORTSC_SUSPEND; break;
          case USB_HUB_FEATURE_C_PORT_CONNECTION:       bmStatus |= UHCD_PORTSC_CONNECT_STATUS_CHANGE; break;
          case USB_HUB_FEATURE_C_PORT_ENABLE:           bmStatus |= UHCD_PORTSC_PORT_ENABLE_CHANGE; break;
          case USB_HUB_FEATURE_C_PORT_RESET:            // not supported by UHCI //
          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, bmStatus );
    return TRUE;
}

// ******************************************************************
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.
// ******************************************************************
{
    BOOL fSuccess = FALSE;

    USHORT portsc = Read_PORTSC( port );
    // no point reset/enabling the port unless something is attached
    if ( portsc & UHCD_PORTSC_CONNECT_STATUS ) {
        // turn on reset bit
        portsc |= UHCD_PORTSC_PORT_RESET;
        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 = Read_PORTSC( port );
        portsc &= ~UHCD_PORTSC_PORT_RESET;
        Write_PORTSC( port, portsc );

        // Reset is complete, enable the port
        //
        // What I used to do - clear the reset bit, wait 10ms,
        // set the enabled bit, wait 10 ms. This worked with
        // the MS mouse, NEC hub and Andromeda hub. However,
        // with the Peracom hub, it wouldn't!! SetAddress would
        // fail on the Peracom hub for some weird reason. I lucked out
        // by finding the following in the Win98 uhcd code. It is
        // very strange, but this loop fixes the problem! More
        // strange is that every device seems to execute the
        // loop 3-5 times. Perhaps the ENABLED bit is flaky
        // during the period just after reset?? I would have expected
        // to just set the ENABLED bit and have it stick, but
        // apparently the hardware is not that nice.
        //
        // In the Win98 code, this loop was marked with the comment:
        // "BUGBUG not sure why we need this loop
        // original code from intel has this"
        for ( UCHAR i = 1; i < 10; i++ ) {
            portsc = Read_PORTSC( port );
            if ( portsc & UHCD_PORTSC_PORT_ENABLED ) {
                // port is enabled
                fSuccess = TRUE;
                break;
            }
            // enable the port
            portsc |= UHCD_PORTSC_PORT_ENABLED;
            Write_PORTSC( port, portsc );
        }
        //
        // clear port connect & enable change bits
        //
        // the process of reset/enable has somehow set the connect
        // change bit again. If we don't clear it, we'll be attaching
        // this device infinitely many times. (note these bits are
        // write-clear).
        //
        portsc |= UHCD_PORTSC_CONNECT_STATUS_CHANGE | UHCD_PORTSC_PORT_ENABLE_CHANGE;
        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
// ******************************************************************
{
    USHORT portsc = Read_PORTSC( port );
    // no point doing any work unless the port is enabled
    if ( portsc & UHCD_PORTSC_PORT_ENABLED ) {
        // clear port enabled bit and enabled change bit,
        // but don't alter the connect status change bit,
        // which is write-clear.
        portsc &= ~(UHCD_PORTSC_PORT_ENABLED | UHCD_PORTSC_CONNECT_STATUS_CHANGE);
        portsc |= UHCD_PORTSC_PORT_ENABLE_CHANGE;

        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 );

⌨️ 快捷键说明

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