usb device enumeration error,sometimes can not enumerate the usb device

hi,my dear friends:
I have a problem on usb camera device enumerate,my usb device usually run well.but when my usb device is running,and

then i disconnect the usb line, then i plug into usb line again,at this time ,the camera also can run.but when I turn off

the camera application pragram,and then I run the application pragram again,at this time I can not enumerate the camera

device,but I check in the device manager,find the device correctly.

and this also happened when the application suddenly have a mistake,in this time ,i turn off the application program,and

then i run the application program again, and i can not enumerate the camera device,but in device manager,I can see the

camera device.

the method for my camera enumeration as follows, firstly ,I use SetupDiGetClassDevs to get the device information,and

then use SetupDiEnumDeviceInterfaces to get the device path, at last time ,i use it to compare with my device PID and VID,

if it is equal, it shows the device is our enumerate device.
but when it can not enumerate,I find the function SetupDiEnumDeviceInterfaces return flase,but I the device correctly in

the windows device manager.I don’t know what causes this. is it the method of my enumeration have some bug? is there any

other mothod to enumerate device? thank you.
my code of enumeration as follows:

Device_ERROR CDevice::GetDevice(DWORD instance,
PTCHAR pVID_PID,
PTCHAR pPath,
DWORD dwLen,
PDWORD pLength)
{
if(pLength != NULL)*pLength = 0; // Initialization

HDEVINFO info = SetupDiGetClassDevs((LPGUID)&ClassGuid,
NULL,
NULL,
DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);

if(info==INVALID_HANDLE_VALUE)
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_NO_INFO;
}

// Get interface data for the requested instance
SP_DEVICE_INTERFACE_DATA intf_data;
intf_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

if(!SetupDiEnumDeviceInterfaces(info,
NULL,
(LPGUID)&ClassGuid,
instance,
&intf_data))
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_INVALID_INST;
}

// Get size of symbolic link
DWORD ReqLen;
SetupDiGetDeviceInterfaceDetail(info, &intf_data, NULL, 0, &ReqLen, NULL);

PSP_DEVICE_INTERFACE_DETAIL_DATA intf_detail = \
(PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[ReqLen]);

if( intf_detail == NULL)
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_DEV_NO_INFO;
}

// Get symbolic link name
intf_detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

if(!SetupDiGetDeviceInterfaceDetail(info,
&intf_data,
intf_detail,
ReqLen,
NULL,
NULL))
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_DEV_NO_INFO;
}

// Check for a valid VID&PID - if argument is not null)
if(pVID_PID != NULL)
{
if(IsVidPidEqual(intf_detail->DevicePath,pVID_PID) == E_FALSE)
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_DEV_VIDPID_NOT_FOUND;
}
}

// Set the length of the path string
if(pLength != NULL)
*pLength = (DWORD)strlen(intf_detail->DevicePath);

// Copy output string path to buffer pointed to by pPath
if(pPath != NULL)
{
// Check that input buffer has enough room…
// Use > not >= because strlen does not include null

if(dwLen > strlen(intf_detail->DevicePath))
strcpy(pPath, intf_detail->DevicePath);
else
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_FALSE;
}
}
// Clean up
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_OK;
}

thank you very much indeed.

zhonghong200@163.com wrote:

I have a problem on usb camera device enumerate,my usb device usually run well.but when my usb device is running,and then i disconnect the usb line, then i plug into usb line again,at this time ,the camera also can run.but when I turn off the camera application pragram,and then I run the application pragram again,at this time I can not enumerate the camera device,but I check in the device manager,find the device correctly.

What are you using for ClassGuid in this code? What you’re doing here
is a bit unusual. You don’t usually enumerate a video camera with
SetupDi. Instead, you use CLSID_SystemDeviceEnum, which eventually gets
you an IBaseFilter to use in DirectShow.

and this also happened when the application suddenly have a mistake,in this time ,i turn off the application program,and then i run the application program again, and i can not enumerate the camera device,but in device manager,I can see the camera device.

the method for my camera enumeration as follows, firstly ,I use SetupDiGetClassDevs to get the device information,and then use SetupDiEnumDeviceInterfaces to get the device path,

That’s not the right strategy. That returns information about the
device INTERFACE, not about the devices that implement that interface.
After calling SetupDiGetClassDevs, you should be calling
SetupDiEnumDeviceInfo.

Remember, if you have opened a handle to a device, and then the hardware
is unplugged, the device cannot be removed until the last handle
closes. During that time, there will be multiple instances of our driver.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

thank you Tim Roberts, yes ,I use device interface class GUID in the function of SetupDiGetClassDevs,

and you say “if you have opened a handle to a device, and then the hardware
is unplugged, the device cannot be removed until the last handle closes. During that time, there will be multiple instances of our driver.”

how to solve this problem,is there another mothod to enumerate the device.

thank you ,all my friends.

Tim Roberts,thank you for you answer,you tell me the difference between SetupDiEnumDeviceInfo and SetupDiEnumDeviceInterfaces, may i use SetupDiEnumDeviceInfo instand of SetupDiEnumDeviceInterfaces.

Tim Roberts, After calling SetupDiGetClassDevs, I call SetupDiEnumDeviceInfo,but the problem can not solve,the code as follows:

Device_ERROR CDevice::GetDevice(DWORD instance,
PTCHAR pVID_PID,
PTCHAR pPath,
DWORD dwLen,
PDWORD pLength)
{
if(pLength != NULL)*pLength = 0; // Initialization

HDEVINFO info = SetupDiGetClassDevs((LPGUID)&ClassGuid,
NULL,
NULL,
DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);

if(info==INVALID_HANDLE_VALUE)
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_NO_INFO;
}

// Get interface data for the requested instance

SP_DEVINFO_DATA DeviceInfoData;
memset(&DeviceInfoData, 0 , sizeof(DeviceInfoData));
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(info,instance,&DeviceInfoData))
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_INVALID_INST;
}

SP_DEVICE_INTERFACE_DATA intf_data;
intf_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

if(!SetupDiEnumDeviceInterfaces(info,
,&DeviceInfoData,
(LPGUID)&ClassGuid,
instance,
&intf_data))
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_INVALID_INST;
}

// Get size of symbolic link
DWORD ReqLen;
SetupDiGetDeviceInterfaceDetail(info, &intf_data, NULL, 0, &ReqLen, NULL);

PSP_DEVICE_INTERFACE_DETAIL_DATA intf_detail = \
(PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[ReqLen]);

if( intf_detail == NULL)
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_DEV_NO_INFO;
}

// Get symbolic link name
intf_detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

if(!SetupDiGetDeviceInterfaceDetail(info,
&intf_data,
intf_detail,
ReqLen,
NULL,
NULL))
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_DEV_NO_INFO;
}

// Check for a valid VID&PID - if argument is not null)
if(pVID_PID != NULL)
{
if(IsVidPidEqual(intf_detail->DevicePath,pVID_PID) == E_FALSE)
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_DEV_VIDPID_NOT_FOUND;
}
}

// Set the length of the path string
if(pLength != NULL)
*pLength = (DWORD)strlen(intf_detail->DevicePath);

// Copy output string path to buffer pointed to by pPath
if(pPath != NULL)
{
// Check that input buffer has enough room…
// Use > not >= because strlen does not include null

if(dwLen > strlen(intf_detail->DevicePath))
strcpy(pPath, intf_detail->DevicePath);
else
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_FALSE;
}
}
// Clean up
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_OK;
}

GetLastError return 259 == NO_OTHER_ITEMS

One problem in the newest code I can currently see in this thread is here:


SP_DEVICE_INTERFACE_DATA intf_data;
intf_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

if(!SetupDiEnumDeviceInterfaces(info,
,&DeviceInfoData,
(LPGUID)&ClassGuid,
instance, <== specifically this- the purpose of this API is to enumerate the interfaces reported by your device.
&intf_data))
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_INVALID_INST;
}

If you know each device only has a single instance of the interface, and no other interfaces, then replacing “instance” on that line by the constant “0” will probably solve your problem. As it is, you are retrieving the first interface of the first device, the second interface of the second , the third of the third, etc. Which almost certainly does not reflect reality.

You don’t say where you get ERROR_NO_MORE_ITEMS, but this bug would certainly cause it to be there error here. Most of the time there will be just one interface, which is why I suggest 0.

zhonghong200@163.com wrote:

Tim Roberts,thank you for you answer,you tell me the difference between SetupDiEnumDeviceInfo and SetupDiEnumDeviceInterfaces, may i use SetupDiEnumDeviceInfo instand of SetupDiEnumDeviceInterfaces.

The difference should be obvious from the names. First, GetClassDevs
returns to you a “device information set”, which contains information
about devices. In your case, since you asked for information about a
single device interface, that set will contain all of the devices that
support that device interface.

SetupDiEnumDeviceInterfaces returns information about the device
interfaces those devices support. The devices you asked for might
support more than one device interface. EnumDeviceInterfaces will tell
you about all of them.

What YOU want is information about the devices themselves, not the
interfaces they support. That’s what EnumDeviceInfo does.

Tim Roberts, After calling SetupDiGetClassDevs, I call SetupDiEnumDeviceInfo,but the problem can not solve,the code as follows:

I, certainly, have lost track of what the actual issue is. Perhaps you
should go over it again.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

zhonghong200@163.com wrote:

and you say “if you have opened a handle to a device, and then the hardware
is unplugged, the device cannot be removed until the last handle closes. During that time, there will be multiple instances of our driver.”

how to solve this problem,is there another mothod to enumerate the device.

The correct way to solve this problem is to have your applications close
their handles when the device goes away. If you always have a request
outstanding, your driver can fail that request when the device is
unplugged, and the application can check for that error. If not, then
you’ll need to use RegisterDeviceNotification to get notified when there
is some change in the plug-and-play tree.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

i use RegisterDeviceNotification to get notified and find when the usb device plug and unplugged ,the application program can find it ,but it can not solve my problem.

because of my question is :
when my usb device is running,and then i disconnect the usb line, then i plug into usb line again,at this time ,the camera also can run.but when I turn off the camera application pragram,and then I run the application pragram again,at his time I can not enumerate the camera device,but I check in the device manager,find the device correctly.

i don’t know how to use RegisterDeviceNotification to solve this problem. thank you Tim Roberts.

zhonghong200@163.com wrote:

because of my question is :
when my usb device is running,and then i disconnect the usb line, then i plug into usb line again,at this time ,the camera also can run.but when I turn off the camera application pragram,and then I run the application pragram again,at his time I can not enumerate the camera device,but I check in the device manager,find the device correctly.

How are you enumerating the camera? Are you using
CLSID_SystemDeviceEnum, or are you looking for your own symbolic link?

If you use your own symbolic link, here’s one common way this kind of
scenario can happen. Say you plug your device in, and you create
\DosDevices\MyDevice0. You open that from your application. When you
unplug, that device cannot be closed because you still have a handle.
You plug in again, and now the driver creates \DosDevices\MyDevice1.
Now, you kill your first app and start a second one. If your
application tries to open \DosDevices\MyDevice0, it’s going to fail,
because that device is now gone.

The same kind of thing can happen with the device enumerator, if you
assume that your device is the only one on the list, or is always first
on the list. You should try each one in turn until you succeed.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

to Tim Roberts

How are you enumerating the camera? Are you using CLSID_SystemDeviceEnum, or are you looking for your own symbolic link?

I enumerate my camera device through compare pid and vid ,if equal ,it is my device.

int Camera_GetDeviceCount(void ) {
TCHAR pVidPid[18];
DWORD count; // Number of USB device with matching VID & PID
count = 0;
wsprintf(pVidPid, TEXT(“vid_%04x&pid_%04x”), VID, PID);
for(int i = 0; i < MAX_NUM_USB_DEV; i++)
{
if(GetDevice(i,pVidPid,NULL,NULL,NULL) == E_OK)
count++;
}
return count;
}

thank you ,Tim Roberts

You say ?You should try each one in turn until you succeed.??but i can not get any device,in my function, count =0, and return zero device.

I don’t use symbolic link to enumerate camera device ,i use device interface GUID to get the Device Path ,for example,it my fuction the device pach is “intf_detail->DevicePath”. then i use device path to judge the VID PID , if it equal to our device , it enumerate success.

i did not use direct show,so i don’t use CLSID_SystemDeviceEnum .

zhonghong200@163.com wrote:

How are you enumerating the camera? Are you using CLSID_SystemDeviceEnum, or are you looking for your own symbolic link?

I enumerate my camera device through compare pid and vid ,if equal ,it is my device.

You didn’t answer my question at all.

if(GetDevice(i,pVidPid,NULL,NULL,NULL) == E_OK)

What does GetDevice do? How does it search? That was my question.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

zhonghong200@163.com wrote:

I don’t use symbolic link to enumerate camera device ,i use device interface GUID to get the Device Path ,for example,it my fuction the device pach is “intf_detail->DevicePath”. then i use device path to judge the VID PID , if it equal to our device , it enumerate success.

Then it sounds like you have a bug. Perhaps you should show us your
GetDevice code, so we can see whether you’re doing the enumeration
properly. You also need to do some tracing in your driver to make sure
that your second instance is actually enabling the device interface
while the first one still lives…


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

thank you ,Tim Roberts, GetDevice code as follows:

Device_ERROR CDevice::GetDevice(DWORD instance,
PTCHAR pVID_PID,
PTCHAR pPath,
DWORD dwLen,
PDWORD pLength)
{
if(pLength != NULL)*pLength = 0; // Initialization

HDEVINFO info = SetupDiGetClassDevs((LPGUID)&ClassGuid,
NULL,
NULL,
DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);

if(info==INVALID_HANDLE_VALUE)
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_NO_INFO;
}

// Get interface data for the requested instance

SP_DEVINFO_DATA DeviceInfoData;
memset(&DeviceInfoData, 0 , sizeof(DeviceInfoData));
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(info,instance,&DeviceInfoData))
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_INVALID_INST;
}

SP_DEVICE_INTERFACE_DATA intf_data;
intf_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

if(!SetupDiEnumDeviceInterfaces(info,
,&DeviceInfoData,
(LPGUID)&ClassGuid,
instance,
&intf_data))
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_INVALID_INST;
}

// Get size of symbolic link
DWORD ReqLen;
SetupDiGetDeviceInterfaceDetail(info, &intf_data, NULL, 0, &ReqLen, NULL);

PSP_DEVICE_INTERFACE_DETAIL_DATA intf_detail = \
(PSP_DEVICE_INTERFACE_DETAIL_DATA)(new char[ReqLen]);

if( intf_detail == NULL)
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_DEV_NO_INFO;
}

// Get symbolic link name
intf_detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

if(!SetupDiGetDeviceInterfaceDetail(info,
&intf_data,
intf_detail,
ReqLen,
NULL,
NULL))
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_DEV_NO_INFO;
}

// Check for a valid VID&PID - if argument is not null)
if(pVID_PID != NULL)
{
if(IsVidPidEqual(intf_detail->DevicePath,pVID_PID) == E_FALSE)
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_DEV_VIDPID_NOT_FOUND;
}
}

// Set the length of the path string
if(pLength != NULL)
*pLength = (DWORD)strlen(intf_detail->DevicePath);

// Copy output string path to buffer pointed to by pPath
if(pPath != NULL)
{
// Check that input buffer has enough room…
// Use > not >= because strlen does not include null

if(dwLen > strlen(intf_detail->DevicePath))
strcpy(pPath, intf_detail->DevicePath);
else
{
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_FALSE;
}
}
// Clean up
SetupDiDestroyDeviceInfoList(info);
delete intf_detail;
return E_OK;
}

when the problem happen, i debug it ,find SetupDiEnumDeviceInfo function return Zero(false),thank you

zhonghong200@163.com wrote:

thank you ,Tim Roberts, GetDevice code as follows:

Device_ERROR CDevice::GetDevice(DWORD instance,
PTCHAR pVID_PID,
PTCHAR pPath,
DWORD dwLen,
PDWORD pLength)
{
if(pLength != NULL)*pLength = 0; // Initialization

HDEVINFO info = SetupDiGetClassDevs((LPGUID)&ClassGuid,
NULL,
NULL,
DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);

That case to (LPGUID) should not be necessary. ClassGuid should already
be a GUID, in which case &ClassGuid is automatically an LPGUID.

if(info==INVALID_HANDLE_VALUE)
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_NO_INFO;
}

If “info” is invalid, then there is nothing to destroy. You should get
rid of the DestroyDeviceInfoList call here.

// Get interface data for the requested instance

SP_DEVINFO_DATA DeviceInfoData;
memset(&DeviceInfoData, 0 , sizeof(DeviceInfoData));
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(info,instance,&DeviceInfoData))
{
SetupDiDestroyDeviceInfoList(info);
return E_DEV_INVALID_INST;
}

OK, now you have one device out of all of the devices that support your
interface. If you just want the hardware ID of this device, call either
CM_Get_Device_ID or SetupDiGetDeviceInstanceId. You shouldn’t need to
do anything else.

If you do need the path, then here’s the problem:

SP_DEVICE_INTERFACE_DATA intf_data;
intf_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

if(!SetupDiEnumDeviceInterfaces(info,
,&DeviceInfoData,
(LPGUID)&ClassGuid,
instance,
&intf_data))

This enumerates the device INTERFACES supported by the devices in the
information set. Your device supports exactly one interface. When your
function is called with instance==1, you are trying to fetch the second
interface from the second device, and that’s going to fail. You should
pass 0 here, instead of instance.

when the problem happen, i debug it ,find SetupDiEnumDeviceInfo function return Zero(false),thank you

Have you used the debugger to make sure your kernel driver is enabling
the device interface correctly when this happens?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.