共用方式為


行動寬頻裝置韌體更新

本文提供行動寬頻(MB)模組製造商的指引,這些製造商打算透過Windows Update (WU) 支援韌體升級裝置。 裝置必須符合 USB-IF 裝置工作組所發行的 USB NCM 行動寬頻介面模型 (MBIM) V1.0 規格

本文中的資訊適用於:

  • Windows 8/Windows 10/Windows 11

裝置需求

若要使用 Windows Update 支援行動寬頻上的韌體更新,模組或裝置製造商必須符合下列需求:

  • 由模組或裝置製造商開發的 UMDF(使用者模式驅動程式架構)型驅動程式,連同 INF 檔案和韌體承載一起封裝。 本檔的稍後部分會提供範例 INF 檔案和詳細數據
  • 實作下列功能的裝置韌體:
    • 韌體標識符裝置服務(FID)。 如需詳細資訊,請參閱 FID 裝置服務
    • 支援韌體更新裝置服務的韌體。 這是裝置製造商特定的裝置服務,可讓UMDF驅動程式呼叫並執行/下載韌體承載並啟動韌體更新程式。

操作概觀

下圖顯示涉及的三個元件之間的高階設計和互動:MBIM 裝置、Windows 8 操作系統和 IHV 提供的韌體升級驅動程式。

此圖顯示 MBIM 裝置、Windows 8 OS 和 IHV 提供的韌體升級驅動程式之間的互動。

  • 當WAN服務偵測到新 MB 裝置的抵達時,它會檢查裝置是否支援韌體識別碼 (FID) 裝置服務。 如果存在,它會擷取定義為 GUID 的 FID。 以下是 IHV 需要支援裝置的韌體裝置服務規格。
  • WWAN 服務 (Windows OS) 會使用上述取得的 FID 作為裝置硬體識別碼來產生「軟式裝置節點」。這稱為上圖中的「軟體開發節點」。 建立開發節點將會啟動 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 介面描述如何在開發節點上設定屬性。 使用 DEVPROP_TYPE_EMPTY 可以清除先前設定的屬性。
    • 在 OnPrepareHardware UMDF 回呼期間,UMDF 驅動程式應該檢查裝置上的韌體是否需要更新。 這是藉由比較裝置上的韌體版本與透過 Windows Update 傳入的韌體版本來完成。 稍後會在檔中提供關於韌體二進位檔放置位置的其他指引。 如果需要韌體更新,UMDF 驅動程式應該:
      • 排程工作專案。 實際韌體升級發生在工作項目的內容中。
      • 成功排程工作項目之後,請通知 Windows 韌體更新的開始。 其方式是在 OnPrepareHardware UMDF 回呼的內容中,於軟開發節點上設定 DEVPKEY_Device_PostInstallInProgress 屬性。
      • 請務必不要在韌體更新進行時封鎖 OnPrepareHardware 回呼。 預計 OnPrepareHardware 回呼最多會在一兩秒內完成。

WU 套件的範例 INF 檔案

本節提供屬於 WU 套件的範例 INF。 INF 檔案中要注意的重點是:

  • 韌體二進位檔與UMDF驅動程序無關。
  • 韌體二進位檔位於驅動程式存放區目錄中,這是操作系統所決定的路徑,並使用 DIRID 13 在 INF 中參考。 二進位檔不能是包含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韌體識別符

UUID = UUID_MSFWID UUID

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

具體來說,下列 CID 是針對UUID_MSFWID裝置服務所定義:

CID = CID_MBIM_MSFWID_FIRMWAREID

命令程式代碼 = 1

查詢 =

Set = No

事件 =

設定 InformationBuffer 承載 = N/A

查詢資訊Buffer 承載 = N/A

完成資訊Buffer 承載 = UUID

CID_MBIM_MSFWID_FIRMWAREID

此命令會傳回裝置的 MNO 或 IHV 指派韌體識別碼。 UUID 會根據 MBIM 規格中的指導方針進行編碼。

查詢 = 未使用MBIM_COMMAND_MSG資訊Buffer。InformationBuffer MBIM_COMMAND_DONE中傳回的 UUID。

Set = Unsupported

未請求的事件 = 不支援

UMDF 驅動程式行為的代碼段

如先前所述,UMDF 驅動程式應該在 Windows 啟動時向 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;
}