A driver has enumerated two child PDO's that returned identical Device ID's - ndis

I have a kmdf bus driver PCI\VEN_XXXX&DEV_XXXX that creates two statically enumerated PDOs with serial numbers: 217 and 218; one for each Ethernet port. The PDO hardware id is ROOT\MY_NIC_PORT so I can install a NDIS Miniport driver on them.
The bus driver passes SDV and Verifier; but, on reboot two more PDOs get enumerated. On the next reboot I get a duplicate pdo crash.
The toaster example used the device class guid as part of the hardware id. When I tried that my NIC ports no longer showed up in device manager.
Any debug suggestion or work around idea would be appreciated?
pnpCaps.LockSupported = WdfFalse;
pnpCaps.EjectSupported = WdfTrue;
pnpCaps.Removable = WdfTrue;
pnpCaps.DockDevice = WdfFalse;
pnpCaps.UniqueID = WdfTrue;
pnpCaps.SilentInstall = WdfTrue;
pnpCaps.SurpriseRemovalOK = WdfTrue;
pnpCaps.HardwareDisabled = WdfFalse;
pnpCaps.NoDisplayInUI = WdfFalse;
pnpCaps.Address = SerialNo;
pnpCaps.UINumber = SerialNo;
************************************************************
Driver Verifier detected violation:
A driver has enumerated two child PDO's that returned identical Device
ID's.
CulpritAddress = FFFFF8025ED309C4, DeviceObject1 = FFFFE3882FB2F300,
DeviceObject2 = FFFFE3882EBF88D0.
************************************************************

There are a few versions of the toaster bus sample -- assuming you started with this one, then note that it saves its list of child PDOs in the registry. My guess is that your driver is both loading PDOs from the registry, and trying to dynamically create some too.
Set a breakpoint on your driver's version of Bus_PlugInDevice, and see how often it's getting called. Make sure it's never getting called 2x with the same Instance ID.
To clear up a bit of the naming thing: a device setup class is a GUID that is totally unrelated to its hardware ID. For NICs that want to interoperate with the OS's networking stack, you must use the NET setup class, {4d36e972-e325-11ce-bfc1-08002be10318}. You can put anything you want into your hardware ID. I don't really encourage you to put "ROOT\" in there, since that could be confused with a root-enumerated device (which your devices are not). Instead, you can use "yourcompany_yourdevice\port1" as a hardware ID.
While you're thinking about naming things, there are a few things to note about hardware IDs:
Once you assign a HWID, it's rather difficult to change it in a future driver update, without breaking customers who had already installed your device. So get it right the first time.
Once you assign an Instance ID, don't change or reuse it for the lifetime of the device. Otherwise you'll cause this bugcheck, or cause IP addresses to bounce around / get reset. The OS ultimately uses the Instance ID to figure out which NIC port to bind an IP address to.
Think about what happens if someone plugs 2 of your device into a system. Make sure your Instance ID is unique across all ports. You can do this by encoding into the Instance ID the PCI device serial number (if it has one) or by falling back to the PCI bus:device:function.
Don't lump together different types of hardware under the same hardware ID. For example, if the deluxe version of your device supports checksum offload, but the regular version does not -- you should use 2 different hardware IDs for these two different devices. Otherwise it gets difficult to write a single INF that has keywords for both.

Related

How to identify a HID after it's moved to a different port on Windows

I'm on Windows and am trying to store calibration data for game controllers connected via USB and am trying to find a value which uniquely identifies them in a port independent way.
There is the HidD_GetSerialNumberString function but i've read here that it's uncommon for devices to have serial numbers and indeed when i try to read one f.e. from a PS4 controller HidD_GetSerialNumberString returns FALSE and GetLastError returns ERROR_INVALID_PARAMETER.
Is there any other data available which can be accessed to achieve this?
You can try to use instance ID for your HID device (call CM_Get_Device_Interface_Property with device interface path and DEVPKEY_Device_InstanceId property and use string after last & char). It should be unique and persistent per system restarts. But it is not guaranteed if serial number is not provided (in this case instance ID will be different if device is plugged into different usb port)...
More info on this here: https://stackoverflow.com/a/56885175/1795050

Why is my USB device sometimes creating another entry in the windows (7&10) registry?

What can cause a USB device to have double entries for the same device in the registry?
How are the numbers following the "9&" derived (see below), i.e., 3406C40F and 2D6B958A, in case this is a hint to what is causing this problem.
My guess is that possibly the device reports itself differently during enumeration, possibly a different configuration and/or device descriptor.
Details of the test that causes this problem:
I am running a USB plug/unplug enumeration test where every time I plug in the device I verify various things to make sure that the enumeration is correct. This cycle is repeated 1000's of times. This a development test.
Upon enumeration, the test uses devcon.exe to verify some things about the collections. For some unknown reason, after some number of enumerations, the numbers associated with the collections is changing. Further investigation shows what appears to be two entries in the registry for the same device with these same numbers.
\9&3406C40F is the number at the beginning of the test associated with each collection
and some time later after several hundred enumerations it changes, in this case to
\9&2D6B958A
initial enumeration
2020-09-18 16:09:22,066 main INFO =========> devcon.exe "find HID"\vid_047F* <=========
HID\VID_047F&PID_015D&MI_03&COL05\9&3406C40F&0&0004 : HID-compliant device
HID\VID_047F&PID_015D&MI_03&COL01\9&3406C40F&0&0000 : HID-compliant device
HID\VID_047F&PID_015D&MI_03&COL02\9&3406C40F&0&0001 : HID-compliant device
HID\VID_047F&PID_015D&MI_03&COL03\9&3406C40F&0&0002 : HID-compliant consumer control device
HID\VID_047F&PID_015D&MI_03&COL04\9&3406C40F&0&0003 : HID-compliant device
several hundred enumerations later,
HID\VID_047F&PID_015D&MI_03&COL01\9&2D6B958A&0&0000 :HID-compliant device
HID\VID_047F&PID_015D&MI_03&COL02\9&2D6B958A&0&0001 :HID-compliant device
HID\VID_047F&PID_015D&MI_03&COL03\9&2D6B958A&0&0002 :HID-compliant consumer control device
HID\VID_047F&PID_015D&MI_03&COL04\9&2D6B958A&0&0003 :HID-compliant device
HID\VID_047F&PID_015D&MI_03&COL05\9&2D6B958A&0&0004 :HID-compliant device
I've run this test for millions of cycles on other devices but I have never seen this problem before. It is happening on win7 and win10.
Any help would be very appreciated! thx!
It's a device bug. The device is intermittently not reporting it's serial number so the OS creates a new entry with a different LUID (locally unique ID).

how to parse USB Device Instance ID (DIID)?

I want to know how "Device Instance ID" is made or how to parse it.
Take the following string as an example:
USB\VID_093A&PID_2700&MI_00\6&2703A67B&0&0000
As per my knowledge:
USB tells that this is a USB device
VID_093A indicates its vendor ID
similarly, PID_2700 is the product ID
However, I don't know about the rest.
MI is for multiple interfaces. A composite device has several interfaces.
6&2703A67B&0&0000 is the Instance ID.
The 6 at the beginning corresponds to the device node depth.
0 are root devices (e.g. volmgr, acpi_hal, they have Root\ prefix)
1 are acpi_hal devices (e.g. acpi (uses PNP0C08\0 instead of vid/pid/1), they have ACPI_HAL\ prefix)
2 are acpi devices (e.g. root pci bus controller (uses PNP0A08\0 instead of vid/pid/2), they have ACPI\ prefix)
3 are pci devices (e.g. xhci controller, they have PCI\ prefix)
4 are xhci devices (e.g. root hub, they have IUSB3\ prefix)
5+ are hub devices (e.g. usbccgp FDOs for composite devices, ubstor for storage etc., they have USB\ prefix)
6+ are usbstor devices (disk FDOs, USBSTOR\ prefix) or usbccgp composite interfaces (e.g. hidusb FDOs for input devices, USB\ prefix and have an MI)
7+ are endpoints (kbdhid FDOs for keyboards, mouhid FDOs for mice, HID\ prefix and have an MI)
The ID 2703A67B is an ID assigned by the parent. The xhci controller assigns the same one to all its root hubs; the separate hubs are identified by the value after the final ampersand, which is a simple incremental value. The root hub gives its child devices an ID that is the same across all devices and reboots; the separate devices are identified by the value after the final ampersand, again an incremental value. A composite device gives its children an ID that changes based on what hub/port it is plugged into; the separate interfaces are identified by the value after the final ampersand. An interface gives its children endpoints an ID that changes based on what hub/port it is plugged into; the separate endpoints are identified by the value after the final ampersand.
I can confirm that the ID that a hub assigns to its children changes if the hub is plugged into a different port on the root hub or a different hub altogether. I wrote '+' to indicate the presence of possible nested hubs. The PCI bus could also be nested and have a child bus (via PCIe to PCI bridge or PCIe root port aka. a PCIe to PCIe bridge), but I decided to leave that out. A root port is just a PCI device, basically a bridge/controller to a bus with only one slot (or more slots if the lanes are configured on the port to be split up), with a PCI\ prefix, and the child device will also have a PCI\ prefix.
By that token, the ID that the xHCI controller assigns probably depends on the PCI slot, and the ID the PCI bus controller assigns is probably dependent on what port the subordinate bus controller is connected to or whether it is the root controller.
This is why it installs drivers again when you insert a device into another port (unless it has a serial number). The drivers are considered installed when there is a registry entry for the DIID. The USB device will have a separate entry for each port and root hub combination they're plugged into. The composite device interfaces will have a separate entry for each port and root hub as well, as will the endpoints.
If the device has a serial number, which is uncommon, then the instance ID will be the serial number, and this will be the same regardless of where it is plugged into the system. If a composite device has a serial number instance ID then its interfaces probably have the same instance ID as that because the MI in the Device ID tells them apart. The endpoints are unlikely to have their own serial numbers and probably use the regular instance ID scheme.
Well, you really cant. This is the response from Microsoft regarding the same..
the device instance ID should be treated as opaque. if you want the VID/PID, query for the hardware and/or compa IDs and parse those. the hardware IDs are not considered opaque (but you still have to assume new hardware IDs will show up, so you need to detect the pattern you want to parse and have proactive code that handles other types of formats).
source: http://social.msdn.microsoft.com/Forums/en-US/4ff692bc-97c9-4943-b1ee-ec4f098e3b14/how-to-detect-sim-card-change-or-imsi-change-programatically-in-windows-phone-8?forum=wpdevelop
The Microsoft Device Instance ID page explains well how a Device Instance ID string is composed.
This page explains how a USB Identifier string (which composes the Device ID part of a Device Instance ID) is created.
Specifically, for your example:
USB\VID_093A&PID_2700&MI_00 is the Device ID, and
6&2703A67B&0&0000 is the Instance ID
Moreover, the Device ID tells you that:
USB\: this is a device under the USB enumerator
VID_093A: Pixart, Inc. manufactured this USB Device (you can find the USB Vendor ID list here)
PID_2700: this is the Product ID
MI_00: This is a Multiple Interface USB Device

How to identify PC (motherboard) in win32 api? [duplicate]

How to uniquely identify computer (mainboard) using C#(.Net/Mono, local application)?
Edition. We can identify mainboard in .Net using something like this (see Get Unique System Identifiers in C#):
using System.Management;
...
ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_MotherboardDevice");
...
But unfortunately Mono does not support System.Management. How to do it under Mono for Linux? - I don't know :(
Write a function that takes a few unique hardware parameters as input and generates a hash out of them.
For example, Windows activation looks at the following hardware characteristics:
Display Adapter
SCSI Adapter
IDE Adapter (effectively the motherboard)
Network Adapter (NIC) and its MAC Address
RAM Amount Range (i.e., 0-64mb, 64-128mb, etc.)
Processor Type
Processor Serial Number
Hard Drive Device
Hard Drive Volume Serial Number (VSN)
CD-ROM / CD-RW / DVD-ROM
You can pick up a few of them to generate your unique computer identifier.
Please see: Get Unique System Identifiers in C#
You realistically have MotherboardID, CPUID, Disk Serial and MAC address, from experience none of them are 100%.
Our stats show
Disk serial Is missing 0.1 %
MAC Is missing 1.3 %
Motherboard ID Is missing 30 %
CPUID Is missing 99 %
0.04% of machines tested yielded no information, we couldn't even read the computer name. It maybe that these were some kind of virtual PC, HyperV or VMWare instance, or maybe just very locked down? In any case your design has to be able to cope with these cases.
Disk serial is the most reliable, but easy to change, mac can be changed and depending on the filtering applied when reading it can change if device drivers are added (hyperv, wireshark etc).
Motherboard and CPUID sometimes return values that are invalid "NONE", "AAAA..", "XXXX..." etc.
You should also note that these functions can be very slow to call (they may take a few seconds even on a fast PC), so it may be worth kicking them off on a background thread as early as possible, you ideally don't want to be blocking on them.
Try this:
http://carso-owen.blogspot.com/2007/02/how-to-get-my-motherboard-serial-number.html
Personally though, I'd go with hard drive serial number. If a mainboard dies and is replaced, that PC isn't valid any more. If the HDD drive is replaced, it doesn't matter too much because the software was on it.
Of course, on the other hand, if the HDD is just moved elsewhere, the information goes with it, so you might want to look at a combination of serial numbers, depending what you want it for.
How about the MAC address of the network card?

How linux drive many network cards with the same driver?

I am learning linux network driver recently, and I wonder that if I have many network cards in same type on my board, how does the kernel drive them? Does the kernel need to load the same driver many times? I think it's not possible, insmod won't do that, so how can I make all same kind cards work at same time?
regards
The state of every card (I/O addresses, IRQs, ...) is stored into a driver-specific structure that is passed (directly or indirectly) to every entry point of the driver which can this way differenciate the cards. That way the very same code can control different cards (which means that yes, the kernel only keeps one instance of a driver's module no matter the number of devices it controls).
For instance, have a look at drivers/video/backlight/platform_lcd.c, which is a very simple LCD power driver. It contains a structure called platform_lcd that is private to this file and stores the state of the LCD (whether it is powered, and whether it is suspended). One instance of this structure is allocated in the probe function of the driver through kzalloc - that is, one per LCD device - and stored into the platform device representing the LCD using platform_set_drvdata. The instance that has been allocated for this device is then fetched back at the beginning of all other driver functions so that it knows which instance it is working on:
struct platform_lcd *plcd = to_our_lcd(lcd);
to_our_lcd expands to lcd_get_data which itself expands to dev_get_drvdata (a counterpart of platform_set_drvdata) if you look at include/linux/lcd.h. The function can then know the state of the device is has been invoked for.
This is a very simple example, and the platform_lcd driver does not directly control any device (this is deferred to a function pointer in the platform data), but add hardware-specific parameters (IRQ, I/O base, etc.) and you get how 99% of the drivers in Linux work.
The driver code is only loaded once, but it allocates a separate context structure for each card. Typically you will see a struct pci_driver with a .probe function pointer. The probe function is called once for each card by the PCI support code, and it calls alloc_etherdev to allocate a network interface with space for whatever private context it needs.

Resources