windows-nt/Source/XPSP1/NT/shell/osshell/cpls/usb/usbitem.cpp
2020-09-26 16:20:57 +08:00

853 lines
23 KiB
C++

/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORP., 1993-1995
* TITLE: USBITEM.CPP
* VERSION: 1.0
* AUTHOR: jsenior
* DATE: 10/28/1998
*
********************************************************************************
*
* CHANGE LOG:
*
* DATE REV DESCRIPTION
* ---------- ------- ----------------------------------------------------------
* 10/28/1998 jsenior Original implementation.
*
*******************************************************************************/
#include "UsbItem.h"
#include "resource.h"
// From root\wdm10\usb\hcd\uhcd\bandwdth.c
#define HCD_BW_PER_FRAME ((ULONG)12000) // bits/ms
#define HCD_TOTAL_USB_BW ((ULONG)12000*32)
// From root\wdm10\usb\inc\hcdi.h
#define USB_ISO_OVERHEAD_BYTES 9
#define USB_INTERRUPT_OVERHEAD_BYTES 13
#include "debug.h"
extern HINSTANCE gHInst;
UsbItem::~UsbItem()
{
if (configInfo) {
DeleteChunk(configInfo);
delete configInfo;
}
if (deviceInfo) {
DeleteChunk(deviceInfo);
delete deviceInfo;
}
DeleteChunk(sibling);
delete sibling;
DeleteChunk(child);
delete child;
}
UsbItem *
UsbItem::AddLeaf(UsbItem* Parent,
UsbDeviceInfo* DeviceInfo,
UsbItemType Type,
UsbConfigInfo* ConfigInfo,
UsbImageList *ClassImageList)
{
//
// Fill in the parent's Child field
//
// If it's not null, walk the chain of children of this parent and add
// this node to the end of the chain.
//
if (Parent != 0) {
//
// Create a new USBMGR_TVITEM
//
UsbItem *lastSibling = 0, *item = 0;
item = new UsbItem();
AddChunk(item);
if (0 == item)
{
USBERROR((_T("Out of Memory\n")));
return FALSE;
}
if (Parent->child != 0) {
//
// This parent already has a child. Look for the end of the chain of
// children.
//
lastSibling = Parent->child;
while (0 != lastSibling->sibling) {
lastSibling = lastSibling->sibling;
}
//
// Found the last sibling for this parent
//
lastSibling->sibling = item;
}
else {
//
// No children for this parent yet
//
Parent->child = item;
}
item->parent = Parent;
item->deviceInfo = DeviceInfo;
item->configInfo = ConfigInfo;
item->itemType = Type;
item->GetClassImageIndex(ClassImageList);
return item;
}
else { // This item is the root (no parent)
deviceInfo = DeviceInfo;
configInfo = ConfigInfo;
itemType = Type;
GetClassImageIndex(ClassImageList);
return this;
}
}
void
UsbItem::GetClassImageIndex(UsbImageList *ClassImageList)
{
if (!configInfo ||
!configInfo->deviceClass.size()) {
//
// No device class, so assign the default USB class
//
ClassImageList->GetClassImageIndex(TEXT("USB"), &imageIndex);
} else {
if (_tcsicmp(configInfo->deviceClass.c_str(), USBHID) == 0) {
//
// This device is HID, so find out what its child is for the
// appropriate icon
//
CONFIGRET cr;
DEVINST childDI;
TCHAR buf[MAX_PATH];
ULONG len;
cr = CM_Get_Child(&childDI,
configInfo->devInst,
0);
USBINFO( (_T("Found HID device: %s, devInst: %x\n"),
configInfo->deviceDesc.c_str(),
configInfo->devInst));
if (cr == CR_SUCCESS) {
len = sizeof(buf);
cr = CM_Get_DevNode_Registry_Property(childDI,
CM_DRP_CLASS,
NULL,
buf,
&len,
0);
if (cr == CR_SUCCESS) {
configInfo->deviceClass = buf;
USBINFO( (_T("New class: %s\n"), buf));
}
len = sizeof(buf);
cr = CM_Get_DevNode_Registry_Property(childDI,
CM_DRP_DEVICEDESC,
NULL,
buf,
&len,
0);
if (cr == CR_SUCCESS) {
configInfo->deviceDesc = buf;
USBINFO( (_T("New name: %s\n"), configInfo->deviceDesc.c_str()));
}
}
}
ClassImageList->GetClassImageIndex(configInfo->deviceClass.c_str(),
&imageIndex);
}
}
UINT
UsbItem::EndpointBandwidth(
ULONG MaxPacketSize,
UCHAR EndpointType,
BOOLEAN LowSpeed
)
/*++
Return Value:
banwidth consumed in bits/ms, returns 0 for bulk
and control endpoints
--*/
{
ULONG bw = 0;
//
// control, iso, bulk, interrupt
//
ULONG overhead[4] = {
0,
USB_ISO_OVERHEAD_BYTES,
0,
USB_INTERRUPT_OVERHEAD_BYTES
};
// return zero for control or bulk
if (!overhead[EndpointType]) {
return 0;
}
//
// Calculate bandwidth for endpoint. We will use the
// approximation: (overhead bytes plus MaxPacket bytes)
// times 8 bits/byte times worst case bitstuffing overhead.
// This gives bit times, for low speed endpoints we multiply
// by 8 again to convert to full speed bits.
//
//
// Figure out how many bits are required for the transfer.
// (multiply by 7/6 because, in the worst case you might
// have a bit-stuff every six bits requiring 7 bit times to
// transmit 6 bits of data.)
//
// overhead(bytes) * maxpacket(bytes/ms) * 8
// (bits/byte) * bitstuff(7/6) = bits/ms
bw = ((overhead[EndpointType]+MaxPacketSize) * 8 * 7) / 6;
if (LowSpeed) {
bw *= 8;
}
return bw;
}
inline ULONG
UsbItem::CalculateBWPercent(ULONG bw) { return (bw*100) / HCD_BW_PER_FRAME; }
int
UsbItem::CalculateTotalBandwidth(
ULONG NumPipes,
BOOLEAN LowSpeed,
USB_PIPE_INFO *PipeInfo
)
{
ULONG i = 0, bwConsumed, bwTotal = 0;
PUSB_ENDPOINT_DESCRIPTOR epd = 0;
for (i = 0; i < NumPipes; i++) {
epd = &PipeInfo[i].EndpointDescriptor;
//
// We only take into account iso BW. Interrupt bw is accounted for
// in another way.
//
if (USB_ENDPOINT_TYPE_ISOCHRONOUS ==
(epd->bmAttributes & USB_ENDPOINT_TYPE_MASK)) {
bwConsumed = EndpointBandwidth(epd->wMaxPacketSize,
(UCHAR)(epd->bmAttributes & USB_ENDPOINT_TYPE_MASK),
LowSpeed);
bwTotal += bwConsumed;
}
}
bwTotal = CalculateBWPercent(bwTotal);
return bwTotal;
}
BOOL
UsbItem::ComputeBandwidth()
{
bandwidth = 0;
if (deviceInfo && deviceInfo->connectionInfo &&
!deviceInfo->connectionInfo->DeviceIsHub) {
if (deviceInfo->connectionInfo->NumberOfOpenPipes > 0) {
if (0 != (bandwidth = CalculateTotalBandwidth(
deviceInfo->connectionInfo->NumberOfOpenPipes,
deviceInfo->connectionInfo->LowSpeed,
deviceInfo->connectionInfo->PipeList))) {
return TRUE;
}
} else { // Device is not consuming any bandwidth
USBTRACE((_T("%s has no open pipes\n"),
configInfo->deviceDesc.c_str()));
}
}
return FALSE;
}
BOOL
UsbItem::ComputePower()
{
power = 0;
if (IsHub()) {
if (PortPower() == 100) {
//
// Hub that is bus powered requires one unit of power for itself
// plus one unit for each of its ports
//
power = (1 + NumPorts()) > 4 ? 500 : 100 * (1 + NumPorts());
} else {
//
// Self-powered hubs don't require any power from upstream
//
power = 0;
}
return TRUE;
}
if (deviceInfo && deviceInfo->configDesc) {
power = deviceInfo->configDesc->MaxPower*2;
return TRUE;
}
return FALSE;
}
BOOL
UsbItem::IsController()
{
if (itemType == HCD) {
return TRUE;
}
return FALSE;
}
BOOL
UsbItem::IsHub()
{
if (itemType == RootHub || itemType == Hub)
return TRUE;
if (deviceInfo) {
if (deviceInfo->isHub)
return TRUE;
if (deviceInfo->connectionInfo && deviceInfo->connectionInfo->DeviceIsHub)
return TRUE;
}
return FALSE;
}
ULONG UsbItem::UsbVersion()
{
if (deviceInfo) {
if (deviceInfo->connectionInfo) {
return deviceInfo->connectionInfo->DeviceDescriptor.bcdUSB;
#ifdef HUB_CAPS
} else if(hubCaps.HubIs2xCapable) { // Probably the root hub, check hub capabilities
return 0x200;
#endif
}
#if 0
else {
return 0x200;
}
#endif
}
return 0x100;
}
BOOL UsbItem::IsDescriptionValidDevice()
{
if (!IsUnusedPort() &&
configInfo &&
configInfo->deviceDesc.c_str()) {
return TRUE;
}
return FALSE;
}
ULONG UsbItem::NumChildren()
{
UsbItem *item;
ULONG i = 0;
for (item = child; item != NULL; item = item->sibling) {
if (item->IsDescriptionValidDevice()) {
i++;
}
}
return i;
}
ULONG UsbItem::NumPorts()
{
UsbItem *item;
ULONG i = 0;
if (IsHub()) {
for (item = child; item != NULL; item = item->sibling) {
i++;
}
}
return i;
}
ULONG UsbItem::PortPower()
{
if (IsHub()) {
if (deviceInfo->hubInfo.u.HubInformation.HubIsBusPowered)
return 100;
else
return 500;
} else {
return 0;
}
}
BOOL
UsbItem::Walk(UsbItemAction& Action)
{
if (sibling) {
if (!sibling->Walk(Action))
return FALSE;
}
if (child) {
if (!child->Walk(Action))
return FALSE;
}
return Action(this);
}
BOOL
UsbItem::ShallowWalk(UsbItemAction& Action)
{
if (sibling) {
if (!sibling->ShallowWalk(Action))
return FALSE;
}
return Action(this);
}
BOOL
UsbItem::GetDeviceInfo( String &HubName,
ULONG index)
{
HANDLE hHubDevice;
PUSB_NODE_CONNECTION_INFORMATION connectionInfo = 0;
String driverKeyName;
TCHAR buf[MAX_PATH];
//
// Try to open the hub device
//
hHubDevice = GetHandleForDevice(HubName);
if (hHubDevice == INVALID_HANDLE_VALUE) {
goto GetDeviceInfoError;
}
if (!GetPortAttributes(hHubDevice, &cxnAttributes, index)) {
USBERROR( (_T("Couldn't get node connection attributes\n")));
goto GetDeviceInfoError;
}
if (NULL == (connectionInfo = GetConnectionInformation(hHubDevice, index))) {
USBERROR( (_T("Couldn't get node connection information\n")));
goto GetDeviceInfoError;
}
//
// Allocate configuration information structure
//
configInfo = new UsbConfigInfo();
AddChunk(configInfo);
if (configInfo == 0) {
goto GetDeviceInfoError;
}
//
// If there is a device connected, get the Device Description
//
if (connectionInfo->ConnectionStatus != NoDeviceConnected) {
driverKeyName = GetDriverKeyName(hHubDevice,index);
if (!driverKeyName.empty()) {
GetConfigMgrInfo(driverKeyName, configInfo);
}
if (configInfo->deviceDesc.empty()) {
if (connectionInfo->DeviceIsHub) {
if (connectionInfo->DeviceDescriptor.bcdUSB >= 0x200) {
LoadString(gHInst, IDS_UNKNOWN20HUB, buf, MAX_PATH);
} else {
LoadString(gHInst, IDS_UNKNOWNHUB, buf, MAX_PATH);
}
} else {
LoadString(gHInst, IDS_UNKNOWNDEVICE, buf, MAX_PATH);
}
configInfo->deviceDesc = buf;
}
if (configInfo->deviceClass.empty()) {
configInfo->deviceClass = connectionInfo->DeviceIsHub ?
TEXT("USB") : TEXT("Unknown");
}
itemType = connectionInfo->DeviceIsHub ? UsbItem::UsbItemType::Hub :
UsbItem::UsbItemType::Device;
//
// Allocate some space for a USBDEVICEINFO structure to hold the
// info for this device.
//
deviceInfo = new UsbDeviceInfo();
AddChunk(deviceInfo);
if (deviceInfo == 0) {
goto GetDeviceInfoError;
}
if (NULL != (deviceInfo->configDescReq =
GetConfigDescriptor(hHubDevice, index))) {
deviceInfo->configDesc =
(PUSB_CONFIGURATION_DESCRIPTOR)(deviceInfo->configDescReq+1);
}
deviceInfo->connectionInfo = connectionInfo;
}
else {
//
// Empty port. Add "Port n"
//
LocalFree(connectionInfo);
itemType = UsbItem::UsbItemType::Empty;
LoadString(gHInst, IDS_UNUSEDPORT, buf, MAX_PATH);
configInfo->deviceDesc = buf;
UnusedPort = TRUE;
configInfo->deviceClass = TEXT("USB");
}
CloseHandle(hHubDevice);
return TRUE;
GetDeviceInfoError:
//
// Clean up any stuff that got allocated
//
if (hHubDevice != INVALID_HANDLE_VALUE)
{
CloseHandle(hHubDevice);
hHubDevice = INVALID_HANDLE_VALUE;
}
if (deviceInfo) {
DeleteChunk(deviceInfo);
delete deviceInfo;
}
if (connectionInfo)
{
LocalFree(connectionInfo);
}
if (configInfo) {
DeleteChunk(configInfo);
delete configInfo;
}
return FALSE;
}
//
// Recursively inserts items appropriately into a treeview
//
BOOL
UsbItem::InsertTreeItem (HWND hWndTree,
UsbItem *usbItem,
HTREEITEM hParent,
LPTV_INSERTSTRUCT item,
PUsbItemActionIsValid IsValid,
PUsbItemActionIsValid IsBold,
PUsbItemActionIsValid IsExpanded)
{
if (!usbItem || !item) {
return FALSE;
}
if (IsValid(usbItem)) {
HTREEITEM hItem;
ZeroMemory(item, sizeof(TV_INSERTSTRUCT));
// Get the image index
item->hParent = hParent;
item->hInsertAfter = TVI_LAST;
item->item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE; // TVIF_CHILDREN
if (IsBold(usbItem)) {
item->itemex.state = TVIS_BOLD;
}
if (IsExpanded(usbItem)) {
item->itemex.state |= TVIS_EXPANDED;
}
item->itemex.stateMask = (UINT)~(TVIS_STATEIMAGEMASK | TVIS_OVERLAYMASK);
item->itemex.pszText = (LPTSTR) usbItem->configInfo->deviceDesc.c_str();
item->itemex.cchTextMax = _tcsclen(usbItem->configInfo->deviceDesc.c_str());
item->itemex.iImage = usbItem->imageIndex;
item->itemex.iSelectedImage = usbItem->imageIndex;
if (usbItem->child) {
item->itemex.cChildren = 1;
}
item->itemex.lParam = (USBLONG_PTR) usbItem;
if (NULL == (hItem = TreeView_InsertItem(hWndTree,
item))) {
int i = GetLastError();
return FALSE;
}
if (usbItem->child) {
if (!InsertTreeItem(hWndTree,
usbItem->child,
hItem,
item,
IsValid,
IsBold,
IsExpanded)) {
return FALSE;
}
}
}
if (usbItem->sibling) {
if (!InsertTreeItem(hWndTree,
usbItem->sibling,
hParent,
item,
IsValid,
IsBold,
IsExpanded)) {
return FALSE;
}
}
return TRUE;
}
BOOL
UsbTreeView_DeleteAllItems(HWND hTreeDevices)
{
HTREEITEM hTreeRoot;
//
// Select the root and delete so as to delete whole tree.
// There is a paint bug in tree view that if you delete all when the
// root isn't selected, then it will paint badly.
//
if (NULL == (hTreeRoot = (HTREEITEM) SendMessage(hTreeDevices,
TVM_GETNEXTITEM,
(WPARAM)TVGN_ROOT,
(LPARAM)NULL))) {
// Nothing to delete; successful
return TRUE;
}
if (!SendMessage(hTreeDevices,
TVM_SELECTITEM,
(WPARAM)TVGN_CARET,
(LPARAM)hTreeRoot)) {
// Can't select the root; YIKES!
return FALSE;
}
//
// deleteAllOk = TreeView_DeleteAllItems(hTreeDevices);
//
return (BOOL) SendMessage(hTreeDevices,
TVM_DELETEITEM,
0,
(LPARAM)TVI_ROOT);
}
HTREEITEM
TreeView_FindItem(HWND hWndTree,
LPCTSTR text)
{
HTREEITEM hItemPrev, hItemNext;
TCHAR buf[MAX_PATH];
TVITEM tvItem;
tvItem.mask = TVIF_TEXT | TVIF_HANDLE;
tvItem.pszText = buf;
tvItem.cchTextMax = MAX_PATH;
if (NULL == (hItemNext = TreeView_GetRoot(hWndTree))) {
return NULL;
}
hItemPrev = hItemNext;
while (hItemPrev) {
//
// Drill all the way down, checking the nodes along the way.
//
while (hItemNext) {
//
// Check this leaf
//
tvItem.hItem = hItemNext;
if (TreeView_GetItem(hWndTree, &tvItem)) {
if (!_tcscmp(tvItem.pszText, text)) {
return hItemNext;
}
}
//
// Get the next child
//
hItemPrev = hItemNext;
hItemNext = TreeView_GetNextItem(hWndTree,
hItemPrev,
TVGN_CHILD);
}
//
// Find the first sibling on the way back up the tree
//
while (!hItemNext && hItemPrev) {
//
// Get the sibling
//
hItemNext = TreeView_GetNextItem(hWndTree,
hItemPrev,
TVGN_NEXT);
if (!hItemNext) {
//
// Get the parent
//
hItemPrev = TreeView_GetNextItem(hWndTree,
hItemPrev,
TVGN_PARENT);
}
}
}
return NULL;
}
HANDLE
UsbCreateFileA(
IN LPCWSTR lpFileName,
IN DWORD dwDesiredAccess,
IN DWORD dwShareMode,
IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
IN DWORD dwCreationDisposition,
IN DWORD dwFlagsAndAttributes,
IN HANDLE hTemplateFile)
{
CHAR usbDeviceName[MAX_PATH];
if (!WideCharToMultiByte(CP_ACP,
WC_NO_BEST_FIT_CHARS,
lpFileName,
-1,
usbDeviceName,
MAX_PATH,
NULL,
NULL)) {
return INVALID_HANDLE_VALUE;
}
return CreateFileA (usbDeviceName,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile);
}
//
// Get the index into the ImageList for this device's icon
//
BOOL
UsbImageList::GetClassImageIndex(LPCTSTR DeviceClass,
PINT ImageIndex)
{
#ifndef WINNT
IconItem *iconItem;
BOOL found = FALSE;
int i = 0;
for (iconItem = iconTable.begin();
iconItem;
iconItem = iconTable.next(), i++) {
if (_tcsicmp(DeviceClass, iconItem->szClassName) == 0) {
*ImageIndex = iconItem->imageIndex;
return TRUE;
}
}
#endif // ~WINNT
GUID classGuid;
DWORD listSize;
if(SetupDiClassGuidsFromName(DeviceClass,
&classGuid,
1,
&listSize)) {
return SetupDiGetClassImageIndex(&ClassImageList, &classGuid, ImageIndex);
}
return FALSE;
}
BOOL
UsbImageList::GetClassImageList()
{
ZeroMemory(&ClassImageList, sizeof(SP_CLASSIMAGELIST_DATA));
ClassImageList.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
if (!SetupDiGetClassImageList(&ClassImageList)) {
USBERROR((TEXT("Failed to get imagelist, error %x"), GetLastError()));
return FALSE;
}
#ifndef WINNT
HICON hIcon;
IconItem iconItem;
HIMAGELIST imageList = ClassImageList.ImageList;
iconTable.clear();
hIcon = LoadIcon(gHInst, MAKEINTRESOURCE(IDI_IMAGE));
iconItem.imageIndex = ImageList_AddIcon(imageList, hIcon);
iconItem.szClassName = TEXT("Image");
iconTable.push_back(iconItem);
hIcon = LoadIcon(gHInst, MAKEINTRESOURCE(IDI_MODEM));
iconItem.imageIndex = ImageList_AddIcon(imageList, hIcon);
iconItem.szClassName = TEXT("Modem");
iconTable.push_back(iconItem);
hIcon = LoadIcon(gHInst, MAKEINTRESOURCE(IDI_INFRARED));
iconItem.imageIndex = ImageList_AddIcon(imageList, hIcon);
iconItem.szClassName = TEXT("Infrared");
iconTable.push_back(iconItem);
hIcon = LoadIcon(gHInst, MAKEINTRESOURCE(IDI_CDROM));
iconItem.imageIndex = ImageList_AddIcon(imageList, hIcon);
iconItem.szClassName = TEXT("CDROM");
iconTable.push_back(iconItem);
hIcon = LoadIcon(gHInst, MAKEINTRESOURCE(IDI_FLOPPY));
iconItem.imageIndex = ImageList_AddIcon(imageList, hIcon);
iconItem.szClassName = TEXT("DiskDrive");
iconTable.push_back(iconItem);
hIcon = LoadIcon(gHInst, MAKEINTRESOURCE(IDI_MEDIA));
iconItem.imageIndex = ImageList_AddIcon(imageList, hIcon);
iconItem.szClassName = TEXT("MEDIA");
iconTable.push_back(iconItem);
#endif // ~WINNT
return TRUE;
}