移动宽带设备固件更新
本文向移动宽带 (MB) 模块制造商提供指导,这些模块制造商旨在通过 Windows Update (WU) 支持固件升级设备。 设备必须符合 USB-IF 设备工作组发布的 USB NCM 移动宽带接口模型 (MBIM) V1.0 规范。
本文中的信息适用于:
- Windows 8/Windows 10/Windows 11
设备要求
若要支持使用 Windows Update 的移动宽带上的固件更新,模块或设备制造商需要满足以下要求:
- 由模块或设备制造商开发并与 INF 文件和固件有效负载一起打包的基于 UMDF(用户模式驱动程序框架)的驱动程序。 本文档后面部分提供了示例 INF 文件和详细信息
- 用于实施以下功能的设备固件:
- 固件 ID 设备服务 (FID)。 有关详细信息,请参阅 FID 设备服务。
- 用于支持固件更新设备服务的固件。 这是一项特定于设备制造商的设备服务,将使 UMDF 驱动程序能够调用并执行/下载固件有效负载并启动固件更新过程。
操作概述
下图显示了涉及的三个组件之间的简要设计和交互:MBIM 设备、Windows 8 操作系统和 IHV 提供的固件升级驱动程序。
- 当 WWAN 服务检测到新 MB 设备到达时,它会检查设备是否支持固件 ID (FID) 设备服务。 如果存在,它将检索定义为 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 接口介绍如何在开发节点上设置属性。 可以使用 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 设备服务)
通过 CID_MBIM_DEVICE_SERVICES 查询时,MBIM 兼容设备将实施并报告以下设备服务。 现有已知服务在部分 10.1 的 NCM MBIM 规范中定义。 Microsoft Corporation 将扩展此项来定义以下服务。
服务名称 = Microsoft 固件 ID
UUID = UUID_MSFWID UUID
值 = e9f7dea2-feaf-4009-93ce-90a3694103b6
具体而言,为 UUID_MSFWID 设备服务定义了以下 CID:
CID = CID_MBIM_MSFWID_FIRMWAREID
命令代码 = 1
查询 = 是
设置 = 否
事件 = 否
设置 InformationBuffer 有效负载 = 不适用
查询 InformationBuffer 有效负载 = 不适用
完成 InformationBuffer 有效负载 = UUID
CID_MBIM_MSFWID_FIRMWAREID
该命令将返回 MNO 或 IHV 为设备分配的固件 ID。 UUID 将根据 MBIM 规范中的准则进行编码。
查询 = 未使用的 MBIM_COMMAND_MSG 上的 InformationBuffer。在 InformationBuffer MBIM_COMMAND_DONE 中返回的 UUID。
设置 = 不受支持
未经请求的事件 = 不受支持
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;
}