行動寬頻裝置韌體更新
本文提供行動寬頻(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 提供的韌體升級驅動程式。
- 當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;
}