Windows 和 Linux 系统下,如何区分相同PID VID 的USB-HID设备

发布于:2022-12-30 ⋅ 阅读:(296) ⋅ 点赞:(0)

一、前言

最近项目中,再次使用到USB设备,而项目需要是在系统中,也就是一台电脑同时使用两个USB涉设备。这两个USB设备,底层固件一模一样,因此,两个设备在系统中枚举出来的 PID 和 VID 是一样的。由于以前项目上,一般都是使用一个设备,在使用代码查找目标HID 设备时,都是只使用PID 和 VID 。因此,如何解决,在一个操作系统中,怎么区分相同PID 和 VID 两个设备,并同时与其通讯,由此,写下这篇文章记录。

二、关于USB-HID设备

可以查看我之前的文章,已经分享很多篇,这里不再赘述。

三、在系统中如何区分相同PIV 和 VID 的USB-HID 设备

1. 在windows 使用 USB-TreeView 软件查看,usb 设备的详细信息,

2. 根据USB规范的定义,所有的USB设备都用供应商ID(VID)和产品识别码(PID),主机通过不同的VID和PID来区别不同的设备,VID和PID都是两个字节长,其中,VID由供应商向USB执行论坛申请,每个供应商的VID是唯一的,PID由供应商自行决定,理论上来说,不同的产品、相同产品的不同型号、相同型号的不同设计的产品最好采用不同的PID,以便区别相同厂家的不同设备。

3. 但是呢, 在实际上由于设备厂家为了方便,一般相同型号的设备,PID 和 VID 都是一样的,很少会去给每个设备分配不同的ID。并且,同款产品,每个设备要保证PID 和 VID 不同,是非常困难的一件事情,并且成本高。

4. 在实际更多的厂家中,为了方便管理,不同型号的usb设备,其设备的PID 和 VID 都是一样。

这样子操作对于开发者都是非常方便。

5. 当有多个vid,pid相同的usb设备一起插入到电脑上,他们在系统的USB是通用串行总线上都是可以识别出来的。因此当一个usb 设备插入总线上会自动分配一个地址给该设备,每个设备都具有唯一的地址。

因此,当上面,提到当有多个vid,pid相同的usb设备一起插入到电脑上,usb 设备总线,也会分别给它们在分配一个地址,这个地址在总线上是唯一的,不会重复。

7. 根据上面所述,可以的得出,假设,有多个vid,pid相同的usb设备一起插入到电脑上,如何来区分到底是哪一个usb设备?可以根部不同设备在USB总线上地址来区分。

四、在Windows上

1. 使用Win API 寻找USB设备,在获读取设备的信息,可以看到返回设备的地址,如图

这个是设备在系统中唯一的地址,具体代码如下,

 当遇到,目标设备的PID 和 VID 保存对应的strtDetailData->DevicePath, 即可,后续使用时,直接调用CreateFile(), 打开设备记录。 

strtDetailData->DevicePath 每个设备不一样,可以确保操作的是目标设备。

五,在Linux 系统上

在linux操作,一般使用的是libusb, 使用libusb 库中的testlibusb 例程,调用打印可以发现

将相同USB-HID设备插入,可以找到相同的PID 和 VID 设备,同时会输出它们的 在USB设备总线上的地址。

在查找时,需要保存这些设备的bus 和 addr, 后后续操作中,根据这连个就可以区分出来。代码如下:

  // 2. 打开设备
    ret = libusb_open(dev, &handle);
    if (ret != LIBUSB_SUCCESS)
    {
        PrintError(ret);
        return -999;
    }

    // 3. 查看设备PID , VID 是否为目标的PIV 和 VID
    if (desc.idVendor != cmpVID || desc.idProduct != cmpPID)
    {
        //不是目标设备,退出
        ret = -999;
        goto Finish;
    }

    // 3.1 保存ID
    usbDeviceInfo->idVendor = desc.idVendor;
    usbDeviceInfo->idProduct = desc.idProduct;

    // 4. 发现目标设备, 保存设备描述符
    memset(&usbDeviceInfo->deviceDescriptor, 0, sizeof(libusb_device_descriptor));
    memcpy(&usbDeviceInfo->deviceDescriptor, &desc, sizeof(libusb_device_descriptor));

    // 4.1 保存设备路径
    bus = libusb_get_bus_number(dev);
    address = libusb_get_device_address(dev);

    //保存总线位置
    usbDeviceInfo->bus = bus;
    usbDeviceInfo->address = address;

    // 4.2 路径
    memset(usbDeviceInfo->devicePath, 0, sizeof(usbDeviceInfo->devicePath));
    snprintf(usbDeviceInfo->devicePath, sizeof(usbDeviceInfo->devicePath), ": /?/USB#VID_%.4X&PID_%.4X#%d&%d#{bus-%.3d-address-%.3d}#(GUID_DEVINTERFACE_USB_DEVICE)", desc.idVendor, desc.idProduct, bus, address, bus, address);

    // 5. 获取设备序列号
    if (desc.iSerialNumber)
    {
        ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (unsigned char *)stringBuffer, sizeof(stringBuffer));
        if (ret > 0)
        {
            //保存序列号
            memset(usbDeviceInfo->serialNumber, 0, sizeof(usbDeviceInfo->serialNumber));
            strcpy(usbDeviceInfo->serialNumber, stringBuffer);
        }
        else
        {
            //失败
            PrintError(ret);

            ret = -1;
            goto Finish;
        }
    }

综上,根据上述,将多个USB-HID设备插入,相同的PID 和 VID 设备,如何区分,并找到目标设备。

终于完成记录,一个月之前说要写,拖到今天。。。。。。。。。。。

/**
 *         ┏┓   ┏┓+ +
 *        ┏┛┻━━━┛┻┓ + +
 *        ┃       ┃
 *        ┃   ━   ┃ ++ + + +
 *        ████━████ ┃+
 *        ┃       ┃ +
 *        ┃   ┻   ┃
 *        ┃       ┃ + +
 *        ┗━┓   ┏━┛
 *          ┃   ┃
 *          ┃   ┃ + + + +
 *          ┃   ┃    Code is far away from bug with the animal protecting
 *          ┃   ┃ +    神兽保佑,代码无bug
 *          ┃   ┃
 *          ┃   ┃  +
 *          ┃    ┗━━━┓ + +
 *          ┃        ┣┓
 *          ┃        ┏┛
 *          ┗┓┓┏━┳┓┏┛ + + + +
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛+ + + +
 *
 * @author chenxi
 * @date 2022年9月4日12:10:293
 */
————————————————
 

本文含有隐藏内容,请 开通VIP 后查看