📄 cdevice.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Module Name:
// CDevice.cpp
// Abstract:
// This file manages the USB devices
//
// CDevice (ADT)
// / \
// CFunction CHub (ADT)
// / \
// CRootHub CExternalHub
//
// Notes:
//
#include "cdevice.hpp"
#include "cpipe.hpp"
#include "chw.hpp"
// address array variables - initially set to have address 0 used
// because it is reserved for the root hub (besides, no real device
// can permanently use addr0, since it is used at set address time)
CritSec_Ex CDevice::m_csAddress0Lock;
CRITICAL_SECTION CDevice::m_csFreeAddressArrayLock;
DWORD CDevice::m_dwFreeAddressArray[4] = { 0x00000001,
0x00000000,
0x00000000,
0x00000000 };
// USBD.dll related variables
HINSTANCE CDevice::m_hUSBDInstance = NULL;
// this procedure is called when new USB devices (functions) are attached
LPUSBD_ATTACH_PROC CDevice::m_pUSBDAttachProc = NULL;
// this procedure is called when USB devices (functions) are detached
LPUSBD_DETACH_PROC CDevice::m_pUSBDDetachProc = NULL;
// OUT param for lpHcdAttachProc call
LPVOID CDevice::m_pvHcdContext = NULL;
// counts detach threads that might be executing in USBD
Countdown CDevice::m_objCountdown;
#ifdef DEBUG
BOOL g_fAlreadyCalled = FALSE;
#endif // DEBUG
// ******************************************************************
BOOL CDevice::Initialize( IN PVOID const pHcd )
//
// Purpose: Initialize any static variables associated with
// CDevice, and establish link to USBD
//
// Parameters: pHcd - pointer to the Host Controller Driver object which
// we pass to USBD
//
// Returns: TRUE
//
// Notes: This function should be called only once from CUhcd::Initialize
// ******************************************************************
{
DEBUGMSG( ZONE_INIT, (TEXT("+CDevice::Initialize\n")));
#ifdef DEBUG
DEBUGCHK( !g_fAlreadyCalled );
g_fAlreadyCalled = TRUE;
#endif // DEBUG
InitializeCriticalSection( &m_csFreeAddressArrayLock );
InitCritSec_Ex( &m_csAddress0Lock );
DEBUGCHK( DWORD(8 * sizeof( m_dwFreeAddressArray )) == DWORD(USB_MAX_ADDRESS + 1) &&
8 * sizeof( m_dwFreeAddressArray[0] ) == 32 &&
m_dwFreeAddressArray[ 0 ] == 0x00000001 &&
m_dwFreeAddressArray[ 1 ] == 0x00000000 &&
m_dwFreeAddressArray[ 2 ] == 0x00000000 &&
m_dwFreeAddressArray[ 3 ] == 0x00000000 );
// establish links to USBD.dll
{
// this procedure is called to establish a link to USBD
LPUSBD_HCD_ATTACH_PROC lpHcdAttachProc = NULL;
// this is defined in uhcddrv.cpp
extern HCD_FUNCS gc_HcdFuncs;
DEBUGCHK( pHcd != NULL &&
m_hUSBDInstance == NULL &&
m_pUSBDDetachProc == NULL &&
m_pUSBDAttachProc == NULL &&
m_pvHcdContext == NULL );
m_hUSBDInstance = LoadDriver(TEXT("USBD.DLL"));
if ( m_hUSBDInstance == NULL ) {
DEBUGMSG(ZONE_ERROR,(TEXT("-CDevice::Initialize - Could not load USBD.DLL\r\n")));
return FALSE;
}
lpHcdAttachProc = (LPUSBD_HCD_ATTACH_PROC) GetProcAddress(m_hUSBDInstance, TEXT("HcdAttach"));
m_pUSBDAttachProc = (LPUSBD_ATTACH_PROC) GetProcAddress(m_hUSBDInstance, TEXT("HcdDeviceAttached"));
m_pUSBDDetachProc = (LPUSBD_DETACH_PROC) GetProcAddress(m_hUSBDInstance, TEXT("HcdDeviceDetached"));
if ( m_pUSBDAttachProc == NULL ||
m_pUSBDDetachProc == NULL ||
lpHcdAttachProc == NULL ||
(*lpHcdAttachProc)(pHcd, &gc_HcdFuncs, &m_pvHcdContext) == FALSE ) {
DEBUGMSG(ZONE_ERROR, (TEXT("-CDevice::Initialize - Could not establish USBD links\n")));
return FALSE;
}
DEBUGCHK( m_pvHcdContext != NULL );
}
// set up the stray-thread counter
InitCountdown(&m_objCountdown, 0);
DEBUGMSG( ZONE_INIT, (TEXT("-CDevice::Initialize, success!\n")));
return TRUE;
}
// ******************************************************************
void CDevice::DeInitialize( )
//
// Purpose: Delete any static variables associated with CDevice
//
// Parameters: None
//
// Returns: Nothing
//
// Notes: This function should be called only once from CUhcd::~CUhcd
// ******************************************************************
{
DEBUGMSG( ZONE_INIT, (TEXT("+CDevice::DeInitialize\n")));
#ifdef DEBUG
DEBUGCHK(g_fAlreadyCalled == TRUE);
g_fAlreadyCalled = FALSE;
#endif // DEBUG
// wait for any stray detach threads
// This can block waiting for a callback into a client driver to return.
// Since callbacks aren't supposed to block this oughtn't cause deadlock,
// but a misbehaving client driver can cause us serious grief.
// Nonetheless, not waiting means we might free USBD.DLL while it's still in use.
DeleteCountdown(&m_objCountdown);
// all devices, and hence all addresses, should have been freed by now
DeleteCriticalSection( &m_csFreeAddressArrayLock );
DeleteCritSec_Ex( &m_csAddress0Lock );
// unload USBD.dll
if ( m_hUSBDInstance ) {
LPUSBD_HCD_DETACH_PROC lpHcdDetachProc;
lpHcdDetachProc = (LPUSBD_HCD_DETACH_PROC) GetProcAddress(m_hUSBDInstance, TEXT("HcdDetach"));
if ( lpHcdDetachProc != NULL ) {
(*lpHcdDetachProc)(m_pvHcdContext);
}
FreeLibrary( m_hUSBDInstance );
m_hUSBDInstance = NULL;
}
m_pUSBDAttachProc = NULL;
m_pUSBDDetachProc = NULL;
m_pvHcdContext = NULL;
m_dwFreeAddressArray[0] = 0x00000001;
m_dwFreeAddressArray[1] = m_dwFreeAddressArray[2] = m_dwFreeAddressArray[3] = 0x00000000;
DEBUGMSG( ZONE_INIT, (TEXT("-CDevice::DeInitialize\n")));
}
// ******************************************************************
BOOL CDevice::ReserveAddress( OUT UCHAR& rAddress )
//
// Purpose: Finds an unused USB address (1-127), marks it as used, and
// returns the address
//
// Parameters: rAddress - OUT parameter, which is set to a free address
//
// Returns: TRUE if rAddress set to a valid free address, else FALSE
//
// Notes: Address 0 is permanently marked as used. This is reserved for
// the root hub.
// ******************************************************************
{
DEBUGMSG( ZONE_ATTACH && ZONE_VERBOSE, (TEXT("+CDevice::ReserveAddress\n")) );
BOOL fSuccess = FALSE;
EnterCriticalSection( &m_csFreeAddressArrayLock );
// the address has 7 bits:
//
// xxyyyyyb
//
// xxb is the index into the m_dwFreeAddressArray (0-3)
// yyyyyb is the bit of the m_dwFreeAddressArray[xxb] DWORD
// that the address corresponds to
// address 0 should always be marked used
DEBUGCHK(m_dwFreeAddressArray[0] & 1 );
for ( UCHAR address = 1; address <= USB_MAX_ADDRESS; address++ ) {
const UCHAR index = (address >> 5); // 5 == log base 2 of 32
const UCHAR bit = address & (32 - 1); // 32 == # of bits in DWORD
if ( (m_dwFreeAddressArray[ index ] & (1 << bit)) == 0 ) {
// this address is free
fSuccess = TRUE;
rAddress = address;
// mark address as used
m_dwFreeAddressArray[ index ] |= (1 << bit);
break;
}
}
LeaveCriticalSection( &m_csFreeAddressArrayLock );
DEBUGMSG( ZONE_ATTACH && ZONE_VERBOSE, (TEXT("-CDevice::ReserveAddress, returning rAddress %d, success = %d\n"), rAddress, fSuccess ) );
return fSuccess;
}
// ******************************************************************
void CDevice::FreeAddress( IN const UCHAR address )
//
// Purpose: Return address to the list of unused USB device addresses
//
// Parameters: address - address to free
//
// Returns: Nothing
//
// Notes:
// ******************************************************************
{
DEBUGMSG( ZONE_ATTACH && ZONE_VERBOSE, (TEXT("+CDevice::FreeAddress - address = %d\n"), address) );
EnterCriticalSection( &m_csFreeAddressArrayLock );
// the address has 7 bits:
//
// xxyyyyyb
//
// xxb is the index into the m_dwFreeAddressArray (0-3)
// yyyyyb is the bit of the m_dwFreeAddressArray[xxb] DWORD
// that the address corresponds to
const UCHAR index = (address >> 5); // 5 == log base 2 of 32
const UCHAR bit = address & (32 - 1); // 32 == # of bits in DWORD
// make sure this address is marked as used
DEBUGCHK( index < 4 &&
(m_dwFreeAddressArray[ index ] & ( 1 << bit )) );
// free this address
m_dwFreeAddressArray[ index ] &= ~(1 << bit);
LeaveCriticalSection( &m_csFreeAddressArrayLock );
DEBUGMSG( ZONE_ATTACH && ZONE_VERBOSE, (TEXT("-CDevice::FreeAddress - address = %d\n"), address) );
}
// ******************************************************************
DWORD CALLBACK CDevice::TransferDoneCallbackSetEvent( PVOID context )
//
// Purpose: This function is a callback for the CPipe class. When a
// transfer completes, and this function was set in the
// lpStartAddress field of IssueTransfer, we will be called
//
// Parameters: context - HANDLE to an event we should signal
//
// Returns: 0
//
// Notes: Calling this function directly is rather useless (it will
// just have the same effect as SetEvent( context ) ), so
// it should only be used as a callback
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -