Device ID的用处和读取方法

8 篇文章 0 订阅
4 篇文章 0 订阅

DEVICE ID的用途和读取方法

1    用途概述

DEVICE ID可唯一标识一个存储设备,这对于多盘掉电等功能非常重要,因为无论是判定一个盘是否已掉盘还是已上盘都必须知道是哪一个盘。利用这个唯一标识,可以做的事情就很多,包括定位。

一个典型的USB设备的DEVICE ID格式如下:

 

一个典型的SATA设备的DEVICE ID 格式如下:

 

 

 

2    读取的方法

 

//

const std::string CUSBPort::GetDeviceID(U32 _phyDevNO, std::string& _strHubID)

{

    DEVINST devInst = GetDeviceInst(_phyDevNO);

    if (0 == devInst)

    {

        return "";

    }

 

    char szBuff[512] = {0};

    CONFIGRET cr = CM_Get_Device_ID(devInst, szBuff, 512, 0);

    if (cr != CR_SUCCESS)

    {          

        return "";

    }

 

    // 再¨´向¨°上¦?查¨¦找¨°一°?级?即¡ä为aHUBID

    DEVINST hubDevInst = 0;

    cr = CM_Get_Parent(&hubDevInst, devInst, 0);

    if (cr != CR_SUCCESS)

    {          

        return "";

    }

 

    char szHubBuff[512] = {0};

    cr = CM_Get_Device_ID(hubDevInst, szHubBuff, 512, 0);

    if (cr != CR_SUCCESS)

    {          

        return "";

    }

    _strHubID = szHubBuff;

 

    return std::string(szBuff);

}

 

 

U32 CUSBPort::GetDeviceInst(U32 _phyDevNO)

{

    // Get device interface info set handle

    // for all devices attached to system

    GUID* pGUID = (GUID*)&GUID_DEVINTERFACE_DISK;

    HDEVINFO hDevInfo = SetupDiGetClassDevs(pGUID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

    if ( hDevInfo == INVALID_HANDLE_VALUE

    {

        return 0;

    }

    // Retrieve a context structure for a device interface

    // of a device information set.

    U32 dwIndex = 0;

    BOOL bRet = FALSE;

    BYTE bBuff[1024] = {0};

    PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)bBuff;

    SP_DEVICE_INTERFACE_DATA spdid = {0};

    SP_DEVINFO_DATA spdd = {0};

    U32 dwSize = 0;

    spdid.cbSize = sizeof(spdid);

 

    while (TRUE, TRUE)

    {

        bRet = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, pGUID, dwIndex, &spdid);

        if (!bRet)

        {

            break;

        }

 

        dwSize = 0;

        SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL);

 

        if (dwSize!=0 && dwSize<=sizeof(bBuff))

        {

            pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!

 

            ZeroMemory((PVOID)&spdd, sizeof(spdd));

            spdd.cbSize = sizeof(spdd);

 

            bRet = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd, dwSize, &dwSize, &spdd);

            if (bRet)

            {

                //TRACE("DevicePath: %s \n", pspdidd->DevicePath);

                HANDLE hDrive = CreateFile(pspdidd->DevicePath,0,

                    FILE_SHARE_READ | FILE_SHARE_WRITE,

                    NULL, OPEN_EXISTING, 0, NULL);

                if ( hDrive != INVALID_HANDLE_VALUE )

                {

                    STORAGE_DEVICE_NUMBER sdn;

                    U32 dwBytesReturned = 0;

                    bRet = DeviceIoControl(hDrive,

                        IOCTL_STORAGE_GET_DEVICE_NUMBER,

                        NULL, 0, &sdn, sizeof(sdn),

                        &dwBytesReturned, NULL);

                    if (bRet)

                    {

                        if (_phyDevNO == sdn.DeviceNumber)

                        {

                            CloseHandle(hDrive);

                            SetupDiDestroyDeviceInfoList(hDevInfo);

                            return spdd.DevInst;

                        }

                    }

                    CloseHandle(hDrive);

                }

            }

        }

        dwIndex++;

    }

    SetupDiDestroyDeviceInfoList(hDevInfo);

    return 0;

}

 

3    更多方法

    实际上对于SATA盘而言,我们还可以通过SATA端口号来唯一标识一个盘。什么是端口号,可以从intel快速存储技术软件界面中看到例子:

 

 

这个端口号也是唯一不变的,在BUSHOUND中也可以找到,只不过其名字不一样:

 

 

其读取方法如下:

BOOL    CDiskInfo::GetTargetID(int    hDriver,                 //驱y动¡¥器¡Â句?À¨²

    PVOID     pCBD, //CBD指?¢?码?

    DWORD     CBDLen,   //CBD指?¢?码?Ì?长¡è度¨¨ 

    DWORD     DataTransferLength ,     //数ºy据Y传ä?送¨ª长¡è度¨¨

    PVOID     pBuff ,   //数ºy据Y指?针?,ê?无T数ºy据Y为aNULL          

    BYTE      DataIn ,                //数ºy据Y传ä?输º?方¤?向¨° SCSI_IOCTL_DATA_OUT OR SCSI_IOCTL_DATA_IN

    //数ºy据Y由®¨¦¦¨¨备À?ä?输º?Ì?程¨¬序¨°,ê?为aSCSI_IOCTL_DATA_IN

    PDWORD    RetLength             //实º¦Ì际¨º返¤¦Ì回?数ºy据Y的Ì?长¡è度¨¨;ê?

    )

{

    USES_CONVERSION;

    char sFilePath[64]={0};

    sprintf(sFilePath,"\\\\.\\PHYSICALDRIVE%d",hDriver);

 

    HANDLE hFile = INVALID_HANDLE_VALUE;

    hFile = ::CreateFile(sFilePath,

        GENERIC_READ | GENERIC_WRITE,

        FILE_SHARE_READ | FILE_SHARE_WRITE,

        NULL, OPEN_EXISTING,

        0, NULL);

    if (hFile == INVALID_HANDLE_VALUE) return -1;

    DWORD       RetLen;

    PDWORD       pRetLen = NULL;

    if (NULL == RetLength)

    {

        pRetLen = &RetLen;

    }

    else

    {

        pRetLen = RetLength;

    }

    ULONG length = 0;//returned = 0;   

    SCSI_PASS_THROUGH_WITH_BUFFERS  sptwb

    ZeroMemory(&sptwb,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));

    sptwb.spt.Length    = sizeof(SCSI_PASS_THROUGH);   

    sptwb.spt.PathId    = 0;   

    sptwb.spt.TargetId  = 0;

    sptwb.spt.Lun   = 0;   

    sptwb.spt.SenseInfoLength   = 24;  

    sptwb.spt.TimeOutValue  = 10;  

    sptwb.spt.CdbLength = (BYTE)CBDLen;

    sptwb.spt.DataIn    = DataIn;  

    sptwb.spt.DataTransferLength= DataTransferLength;

    memcpy(sptwb.spt.Cdb, pCBD, CBDLen);

 

    if ((SCSI_IOCTL_DATA_OUT == DataIn) && (NULL != pBuff))

    {

        memcpy(sptwb.ucDataBuf , pBuff, DataTransferLength);

    }

 

    sptwb.spt.DataBufferOffset =   offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);   

    sptwb.spt.SenseInfoOffset  =    offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);   

    length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + sptwb.spt.DataTransferLength;  

    bool status = DeviceIoControl

        hFile

        IOCTL_SCSI_PASS_THROUGH,   

        &sptwb,

        sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS),

        &sptwb,

        length,

        pRetLen,   

        NULL);

 

    return sptwb.spt.TargetId;

}

 

 

但在实际操作中并不使用此种方法,因为此方法带有明显的协议性质,USB中并没有这个端口号,PCIE中可能更加没有,而DEVICE ID则不管什么磁盘都有,且目前发现USB连接的设备和SATA设备都可以用相同的函数获取,与协议无关,PCIE应该也可以通过此方法获取DEVICE ID(条件限制还未尝试)。CBD[0] = 0x12是获取TargetID的唯一需要指定的参数信息。

 

 

另外切忌,万不得已的情况下对于SSD盘还可以通过序列号&型号名来唯一标示一个盘,序列号和型号名如下图所示:

但鉴于这两个信息量产时可以任意指定,因此可能会重复,如果两个盘同时进行测试就无法区分。但鉴于重复的概率很小,也不失为一种标识磁盘的备选方式。

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值