モバイル ブロードバンド デバイス ファームウェアの更新
この記事では、Windows Update (WU) 経由でファームウェア アップグレード デバイスをサポートすることを予定しているモバイル ブロードバンド (MB) モジュール製造元向けにガイダンスを示しています。 デバイスは、USB-IF デバイス作業グループがリリースした USB NCM モバイル ブロードバンド インターフェイス モデル (MBIM) V1.0 仕様に準拠している必要があります。
この記事の情報は、次の場合に適用されます。
- Windows 8/Windows 10/Windows 11
デバイスの要件
Windows Update を使用してモバイル ブロードバンドでファームウェア更新プログラムをサポートするには、モジュールまたはデバイスの製造元は次の要件を満たす必要があります。
- モジュールまたはデバイスの製造元によって開発された UMDF (ユーザー モード ドライバー フレームワーク) ベースのドライバー。INF ファイルおよびファームウェア ペイロードと一緒に共にパッケージ化します。 INF ファイルのサンプルと詳細については、このドキュメントの後半で説明します
- 次の機能を実装するためのデバイス ファームウェア:
- ファームウェア ID デバイス サービス (FID)。 詳しくは、「FID デバイス サービス」を参照してください。
- ファームウェア更新デバイス サービスをサポートするファームウェア。 これは、デバイス メーカー固有のデバイス サービスであり、UMDF ドライバーがファームウェア ペイロードを呼び出して実行/ダウンロードし、ファームウェア更新プロセスを開始できるようにします。
運用の概要
次の図は、関連する 3 つのコンポーネント (MBIM デバイス、Windows 8 オペレーティング システム、IHV 提供のファームウェア アップグレード ドライバー) の大まかな設計と相互作用を示しています。
- WWAN サービスは、新しい MB デバイスの到着を検出すると、デバイスがファームウェア ID (FID) デバイス サービスをサポートしているかどうかを確認します。 FID が利用可能な場合、このサービスは GUID として定義されている FID を取得します。 IHV がデバイスのサポートに必要なファームウェア デバイス サービスの仕様を以下に示します。
- WWAN サービス (Windows OS) は、上記で取得した FID をデバイス ハードウェア ID として使用して "ソフト デバイスノード" を生成します。これは、上の図では "Soft Dev Node" と表記されています。 このデバイスノードが作成されると 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 コールバックは、最大でも 1、2 秒以内に完了するように設計されています。
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 ファームウェア ID
UUID = UUID_MSFWID UUID
Value = e9f7dea2-feaf-4009-93ce-90a3694103b6
具体的には、UUID_MSFWID デバイス サービスに対して次の CID が定義されています。
CID = CID_MBIM_MSFWID_FIRMWAREID
コマンド コード = 1
クエリ = はい
セット = いいえ
イベント = いいえ
セット InformationBuffer ペイロード = N/A
クエリ InformationBuffer ペイロード = N/A
完了 InformationBuffer payload = UUID
CID_MBIM_MSFWID_FIRMWAREID
このコマンドは、デバイスの MNO または IHV に割り当てられたファームウェア ID を返します。 UUID は、MBIM 仕様のガイドラインに基づいてエンコードされます。
クエリ = InformationBuffer on MBIM_COMMAND_MSG は使用されません。UUID は InformationBuffer MBIM_COMMAND_DONE で返されます。
セット = サポート対象外
要求されていないイベント = サポート対象外
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;
}