Share via


모바일 광대역 디바이스 펌웨어 업데이트

이 항목에서는 WU(Windows 업데이트)를 통해 펌웨어 업그레이드 디바이스를 지원하려는 MB(모바일 광대역) 모듈 제조업체에 대한 지침을 제공합니다. 디바이스는 USB-IF 디바이스 작업 그룹에서 릴리스한 USB NCM MBIM(모바일 광대역 인터페이스 모델) V1.0 사양 을 준수해야 합니다.

이 항목의 정보는 다음에 적용됩니다.

  • Windows 8/Windows 10/Windows 11

디바이스 요구 사항

Windows 업데이트 사용하여 모바일 광대역에서 펌웨어 업데이트를 지원하려면 모듈 또는 디바이스 제조업체가 다음 요구 사항을 준수해야 합니다.

  • INF 파일 및 펌웨어 페이로드와 함께 패키지된 모듈 또는 디바이스 제조업체에서 개발한 UMDF(사용자 모드 드라이버 프레임워크) 기반 드라이버입니다. 샘플 INF 파일 및 세부 정보는 이 문서의 뒷부분에 나와 있습니다.
  • 다음 기능을 구현하는 디바이스 펌웨어:
    • FID(펌웨어 ID 디바이스 서비스). 자세한 내용은 FID 디바이스 서비스를 참조하세요.
    • 펌웨어 업데이트 디바이스 서비스를 지원하는 펌웨어입니다. UMDF 드라이버가 펌웨어 페이로드를 호출 및 실행/다운로드하고 펌웨어 업데이트 프로세스를 시작할 수 있는 기능을 제공하는 디바이스 제조업체별 디바이스 서비스입니다.

운영 개요

다음 다이어그램은 MBIM 디바이스, Windows 8 운영 체제 및 IHV 제공 펌웨어 업그레이드 드라이버와 관련된 세 가지 구성 요소 간의 높은 수준의 디자인과 상호 작용을 보여 줍니다.

MBIM 디바이스, Windows 8 OS 및 IHV 제공 펌웨어 업그레이드 드라이버 간의 상호 작용을 보여 주는 다이어그램

  • WWAN 서비스에서 새 MB 디바이스의 도착을 감지하면 디바이스가 FID(펌웨어 ID) 디바이스 서비스를 지원하는지 검사. 있는 경우 GUID로 정의된 FID를 검색합니다. IHV가 디바이스에서 지원하는 데 필요한 펌웨어 디바이스 서비스 사양은 아래에 설명되어 있습니다.
  • WWAN 서비스(Windows OS)는 위에서 가져온 FID를 디바이스 하드웨어 ID로 사용하여 "소프트 디바이스 노드"를 생성합니다. 위의 다이어그램에서 "소프트 개발 노드"라고 합니다. 개발 노드를 만들면 가장 일치하는 드라이버를 찾기 위해 시작 PnP 하위 시스템(Windows OS)이 시작됩니다. Windows 8 PnP 시스템은 먼저 로컬 저장소에서 드라이버를 설치하려고 시도합니다(사용 가능한 경우). 병렬 OS는 WU에서 더 일치하는 드라이버를 가져오려고 시도합니다. "드라이버를 찾을 수 없음" 문제를 제거하기 위해 더 나은 일치 드라이버를 사용할 수 없는 경우 받은 편지함 NULL 드라이버가 기본값으로 사용됩니다.
  • FID 일치를 기반으로 하는 IHV WU 패키지가 컴퓨터로 끌어와 설치됩니다. FID는 고유한 펌웨어 SKU를 나타냅니다(여기서 고유성은 조합 디바이스 VID/PID/REV 및 MNO로 정의됨). WU 패키지에는 IHV 작성 UMDF 드라이버와 펌웨어 페이로드가 포함됩니다.
  • IHV UMDF가 소프트 개발 노드에 로드되면 펌웨어 업데이트 흐름을 제어해야 합니다. 소프트 개발 노드의 수명 시간은 MBIM 디바이스의 물리적 존재와 관련이 있습니다. UMDF 드라이버는 펌웨어 업데이트를 수행하기 위해 다음 단계를 수행해야 합니다.
    • 펌웨어 업데이트 프로세스 중에 디바이스를 여러 번 다시 부팅하는 것이 허용되지만 UMDF 드라이버가 언로드/다시 로드됩니다.
    • 재부팅을 포함한 전체 펌웨어 업그레이드 프로세스는 60초 이내로 진행되어야 합니다.
    • 펌웨어 업데이트가 완료되고 디바이스가 MBIM 모드로 되돌려지면 Windows에 알림이 표시됩니다. 이 작업은 이전에 설정한 DEVPKEY_Device_PostInstallInProgress 속성을 지워서 수행됩니다. IWDFUnifiedPropertyStore 인터페이스는 dev-node에서 속성을 설정하는 방법을 설명합니다. DEVPROP_TYPE_EMPTY 사용하여 이전에 설정된 속성을 지울 수 있습니다.
    • OnPrepareHardware UMDF 콜백 중에 디바이스의 펌웨어를 업데이트해야 하는 경우 UMDF 드라이버는 검사 합니다. 이 작업은 디바이스의 펌웨어 버전을 Windows 업데이트 통해 들어온 버전과 비교하여 수행됩니다. 문서의 뒷부분에서 펌웨어 이진 파일의 배치 위치에 대한 추가 지침이 제공됩니다. 펌웨어 업데이트가 필요한 경우 UMDF 드라이버는 다음을 수행해야 합니다.
      • 작업 항목을 예약합니다. 실제 펌웨어 업그레이드는 작업 항목의 컨텍스트에서 발생합니다.
      • 작업 항목이 성공적으로 예약되면 펌웨어 업데이트 시작에 대해 Windows에 알립니다. OnPrepareHardware UMDF 콜백 컨텍스트의 소프트 개발 노드에서 DEVPKEY_Device_PostInstallInProgress 속성을 설정하여 수행됩니다.
      • 펌웨어 업데이트가 진행되는 동안 OnPrepareHardware 콜백을 차단하지 않는 것이 중요합니다. OnPrepareHardware 콜백은 최대 1~2초 내에 완료될 것으로 예상됩니다.

WU 패키지에 대한 샘플 INF 파일

이 섹션에서는 WU 패키지의 일부인 샘플 INF를 제공합니다. INF 파일에서 주목해야 할 핵심 사항은 다음과 같습니다.

  • 펌웨어 이진 파일은 UMDF 드라이버와 독립적입니다.
  • 펌웨어 이진 파일은 운영 체제에 의해 결정되고 DIRID 13을 사용하여 INF에서 참조되는 경로인 driverstore 디렉터리에 있습니다. 이진 파일은 PE/COFF 헤더를 포함하는 실행 파일일 수 없습니다.
  • %13%\<UniqueBinaryName>.bin
  • INF 파일은 이 위치를 레지스트리에 저장하고 UMDF 드라이버는 레지스트리 값을 읽어 이진 위치를 검색합니다.
  • 아래 샘플 INF 템플릿에는 IHV로 채워야 하는 항목이 강조 표시되어 있습니다.
[Version]
Signature       = "$WINDOWS NT$"
Class           = Firmware
ClassGuid       = {f2e7dd72-6468-4e36-b6f1-6488f42c1b52}
Provider        = %Provider%
DriverVer       = 06/21/2006,6.2.8303.0
CatalogFile     = MBFWDriver.cat
PnpLockdown     = 1

[Manufacturer]
%Mfg%           = Firmware,NTx86

[Firmware.NTx86]
%DeviceDesc%    = Firmware_Install,MBFW\{FirmwareID}    ; From Device Service
;%DeviceDesc%    = Firmware_Install,MBFW\{2B13DD42-649C-3442-9E08-D85B26D7825C}

[Firmware_Install.NT]
CopyFiles       = FirmwareDriver_CopyFiles,FirmwareImage_CopyFiles

[Firmware_Install.NT.HW]
AddReg          = Device_AddReg

[Device_AddReg]
HKR,,FirmwareBinary,,"%13%\MBIHVFirmware-XYZ-1.0.bin"

[Firmware_Install.NT.Services]
AddService      = WUDFRd,0x000001fa,WUDFRD_ServiceInstall

[WUDFRD_ServiceInstall]
DisplayName     = %WudfRdDisplayName%
ServiceType     = 1
StartType       = 3
ErrorControl    = 1
ServiceBinary   = %12%\WUDFRd.sys
LoadOrderGroup  = Base

[Firmware_Install.NT.CoInstallers]
CopyFiles       = WudfCoInstaller_CopyFiles

[WudfCoInstaller_AddReg]
HKR,,CoInstallers32,0x00010000,"WUDFCoinstaller.dll"

[Firmware_Install.NT.Wdf]
UmdfService      = MBIHVFirmwareDriver,MBIHVFirmwareDriver_Install
UmdfServiceOrder = MBIHVFirmwareDriver

[MBIHVFirmwareDriver_Install]
UmdfLibraryVersion  = 1.11
ServiceBinary       = %12%\UMDF\MBFWDriver.dll
DriverCLSID         = {<DriverClassGuid>} ; From UMDF driver

[FirmwareImage_CopyFiles]
MBIHVFirmware-XYZ-1.0.bin   ; Firmware Image

[FirmwareDriver_CopyFiles]
MBFWDriver.dll          ; UMDF driver for SoftDevNode

[DestinationDirs]
FirmwareImage_CopyFiles  = 13      ; Driver Store
FirmwareDriver_CopyFiles = 12,UMDF ;%SystemRoot%\System32\drivers\UMDF

[SourceDisksFiles]
MBIHVFirmware-XYZ-1.0.bin = 1

[SourceDisksNames]
1 = %DiskName%

; ================== Generic ==================================

[Strings]
Provider        = "MBIHV"
Mfg             = "MBIHV"
DeviceDesc      = "MBIHV Mobile Broadband Firmware Device"
DiskName        = "Firmware Driver Installation Media"

FID 디바이스 서비스(펌웨어 식별 디바이스 서비스)

MBIM 규격 디바이스는 CID_MBIM_DEVICE_SERVICES 쿼리할 때 다음 디바이스 서비스를 구현하고 보고합니다. 기존의 잘 알려진 서비스는 섹션 10.1의 NCM MBIM 사양에 정의되어 있습니다. Microsoft Corporation은 다음 서비스를 정의하기 위해 이를 확장합니다.

서비스 이름 = Microsoft 펌웨어 ID

UUID = UUID UUID_MSFWID

값 = e9f7dea2-feaf-4009-93ce-90a3694103b6

특히 다음 CID는 UUID_MSFWID 디바이스 서비스에 대해 정의됩니다.

CID = CID_MBIM_MSFWID_FIRMWAREID

명령 코드 = 1

쿼리 =

Set = No

이벤트 = 아니요

InformationBuffer 페이로드 설정 = N/A

Query InformationBuffer 페이로드 = N/A

완료 정보 버퍼 페이로드 = UUID

CID_MBIM_MSFWID_FIRMWAREID

명령은 디바이스에 대해 MNO 또는 IHV 할당 펌웨어 ID를 반환합니다. UUID는 MBIM 사양의 지침에 따라 인코딩됩니다.

쿼리 = MBIM_COMMAND_MSG InformationBuffer가 사용되지 않습니다. InformationBuffer MBIM_COMMAND_DONE 반환된 UUID입니다.

Set = 지원되지 않음

원치 않는 이벤트 = 지원되지 않음

UMDF 드라이버의 동작에 대한 코드 조각

앞에서 설명한 대로 UMDF 드라이버는 펌웨어 업그레이드를 시작하고 완료할 때 Windows에 표시해야 합니다. 이 섹션에서는 드라이버가 이러한 이벤트를 Windows에 알리는 방법을 보여 주는 코드 조각을 제공합니다.

/**
 * This is the IPnpCallbackHardware*:OnPrepareHardware handler 
 * in the UMDF driver. This is called every time the firmware 
 * update is device is started. Since this handler should be 
 * blocked from returning actual the firmware update process 
 * should be done in a workitem 
 */
HRESULT
CMyDevice::OnPrepareHardware(IWDFDevice* pDevice)
{
    HRESULT hr = S_OK;
    BOOL bFirmwareUpdateInProgress = FALSE;
    BOOL bFirmwareUpdateNeeded = FALSE;
    BOOL bFirmwareUpdateIsDone = FALSE;

    //
    // The snippets below demonstrates the steps for firmware 
    // update against a MB device that loads the updated firmware 
    // on device boot. So the firmware update driver needs to
    // send the new firmware down to the device and then tell 
    // the device to initiate a stop/start. Once the device has
    // reappeared, it would have automatically loaded the 
    // new firmware
    // 


    //
    // First, determine if firmware update is in progress. This 
    // can be based on some registry key that is saved when
    // firmware update is started
    //

    // Assuming this status is returned in bFirmwareUpdateInProgress
    if (bFirmwareUpdateInProgress)
    {
        //
        // If firmware update is in progress, check if its done. For
        // this it may be necessary to access the MB device. Note that 
        // if the MB device (& hence the Firmware update device) needs
        // multiple stop/starts to do the firmware update. In that case
        // it will be marked as done at the end of the process
        //

        // Assuming this status is returned in bFirmwareUpdateIsDone
        if (bFirmwareUpdateIsDone)
        {
            //
            // Signal the completion of the firmware update
            // process.
            //
            SignalFirmwareUpdateComplete(pDevice);
        }
        else
        {
            //
            // Take appropriate steps to get notified when
            // firmware update is done. Call SignalFirmwareUpdateComplete
            // when that notification is received
            //
        }
    }
    else
    {
        //
        // Determine if firmware update is needed. This can be 
        // based on checking state in the registry of the last
        // firmware version set on the device to the firmware
        // version associated with this driver
        //
        
        // Assuming this status is returned in bFirmwareUpdateNeeded
        if (bFirmwareUpdateNeeded)
        {
            // 
            // Create and queue a workitem to perform the firmware
            // update process. IWDFWorkItem can be used for this
            //
            
            // Assuming the creation/enquing status
            // is returned in hr
            
            if (SUCCEEDED(hr))
            {
                //
                // Work item queued. It will do the firmware update
                // Tell the OS that firmware update is in progress
                //
                SignalFirmwareUpdateInProgress(pDevice);
            }
        }
    }

    //
    // If we have a failure, we clear the firmware update
    // in progress state
    //
    if (FAILED(hr))
    {
        SignalFirmwareUpdateComplete(pDevice);
    }
    return S_OK;
}

/**
 * This function tells the OS that firmware update is in progress.
 * It should be called from the firmware update UMDF driver's 
 * IPnpCallbackHardware*:OnPrepareHardware handler after it has
 * successfully queued a workitem to perform the firmware update
 */
HRESULT
CMyDevice::SignalFirmwareUpdateInProgress(
    __in IWDFDevice* pDevice
    )
{
    HRESULT hr = S_OK;    
    IWDFUnifiedPropertyStoreFactory* spPropertyStoreFactory = NULL;
    IWDFUnifiedPropertyStore* spPropStore = NULL;
    WDF_PROPERTY_STORE_ROOT wdfPropRoot = { sizeof(WDF_PROPERTY_STORE_ROOT), WdfPropertyStoreRootClassHardwareKey };
    DEVPROP_BOOLEAN boolValue = DEVPROP_TRUE;
    
    do
    {
       
        hr = pDevice->QueryInterface(IID_PPV_ARGS(&spPropertyStoreFactory));
        if (FAILED(hr))
        {
            Trace(TRACE_LEVEL_ERROR, "Failed to query for property store factory. Error = 0x%x", hr);
            break;

        }
        
        hr = spPropertyStoreFactory->RetrieveUnifiedDevicePropertyStore(
            &wdfPropRoot,
            &spPropStore
            );
        if (FAILED(hr))
        {
            Trace(TRACE_LEVEL_ERROR, "Failed to query for device property store. Error = 0x%x", hr);
            break;
        }

        // Set the OS flag
        hr = spPropStore->SetPropertyData(
            reinterpret_cast<const DEVPROPKEY*>(&DEVPKEY_Device_PostInstallInProgress),
            0, // this property is language neutral
            0,
            DEVPROP_TYPE_BOOLEAN,
            sizeof(DEVPROP_BOOLEAN),
            &boolValue
            );
        if (FAILED(hr))
        {
            Trace(TRACE_LEVEL_ERROR, "Failed to set device property for PostInstallInProgress. Error = 0x%x", hr);
            break;
        }

        //
        // Save some state so that we know we are in the process
        // of firmware update
        //
    } while (FALSE);        

    if (spPropStore)
    {
        spPropStore->Release();
    }

    if (spPropertyStoreFactory)
    {
        spPropertyStoreFactory->Release();
    }

    return hr;
}


/**
 * This function tells the OS that firmware update is done
 * It should be called only after the full firmware update process
 * (including any MB device stop/start) has finished
 */
HRESULT
CMyDevice::SignalFirmwareUpdateComplete(
    __in IWDFDevice* pDevice
    )
{
    HRESULT hr = S_OK;    
    IWDFUnifiedPropertyStoreFactory* spPropertyStoreFactory = NULL;
    IWDFUnifiedPropertyStore* spPropStore = NULL;
    WDF_PROPERTY_STORE_ROOT wdfPropRoot = { sizeof(WDF_PROPERTY_STORE_ROOT), WdfPropertyStoreRootClassHardwareKey };
    
    do
    {
        hr = pDevice->QueryInterface(IID_PPV_ARGS(&spPropertyStoreFactory));
        if (FAILED(hr))
        {
            Trace(TRACE_LEVEL_ERROR, "Failed to query for property store factory. Error = 0x%x", hr);
            break;

        }

        hr = spPropertyStoreFactory->RetrieveUnifiedDevicePropertyStore(
            &wdfPropRoot,
            &spPropStore
            );
        if (FAILED(hr))
        {
            Trace(TRACE_LEVEL_ERROR, "Failed to query for device property store. Error = 0x%x", hr);
            break;
        }

        hr = spPropStore->SetPropertyData(
            reinterpret_cast<const DEVPROPKEY*>(&DEVPKEY_Device_PostInstallInProgress),
            0, // this property is language neutral
            0,
            DEVPROP_TYPE_BOOLEAN,
            0,
            NULL
            );
        if (FAILED(hr))
        {
            Trace(TRACE_LEVEL_ERROR, "Failed to clear device property for PostInstallInProgress. Error = 0x%x", hr);
            break;
        }

        //
        // Save some state so that we can do quick check on 
        // whether firmware update is needed or not
        //

    } while (FALSE);        

    if (spPropStore)
    {
        spPropStore->Release();
    }

    if (spPropertyStoreFactory)
    {
        spPropertyStoreFactory->Release();
    }

    return hr;
}