Поделиться через


Обновление встроенного ПО мобильных широкополосных устройств

В этой статье приводятся рекомендации по изготовителям модулей мобильного широкополосного подключения (МБ) для поддержки устройств обновления встроенного ПО с помощью Обновл. Windows (WU). Устройства должны соответствовать спецификации модели мобильного широкополосного интерфейса USB NCM версии 1.0 версии 1.0, выпущенной рабочей группой устройств USB-IF.

Сведения, приведенные в этой статье, относятся к следующим:

  • Windows 8/Windows 10/Windows 11

Требования к устройству

Для поддержки обновлений встроенного ПО на мобильных широкополосных устройствах с помощью Обновл. Windows, модулей или производителей устройств необходимо соблюдать следующие требования:

  • Драйвер на основе UMDF (User Mode Driver Framework), разработанный производителем модуля или устройства, упаковаемым вместе с INF-файлом и полезными данными встроенного ПО. Пример INF-файла и сведений приведены в более поздней части этого документа.
  • Встроенное ПО устройства для реализации следующих функций:
    • Служба устройств идентификатора встроенного ПО (FID). Дополнительные сведения см. в разделе "Служба устройств FID".
    • Встроенное ПО для поддержки службы обновления встроенного ПО устройства. Это конкретная служба устройств производителя устройств, которая позволяет драйверу UMDF вызывать и загружать полезные данные встроенного ПО и запускать процесс обновления встроенного ПО.

Обзор операций

На следующей схеме показан высокий уровень проектирования и взаимодействия между тремя компонентами: устройство MBIM, операционная система Windows 8 и драйвер обновления встроенного ПО IHV.

Схема взаимодействия между устройством MBIM, ОС Windows 8 и IHV, предоставленным драйвером обновления встроенного ПО.

  • Когда служба WWAN обнаруживает прибытие нового устройства в МБ, она проверяет, поддерживает ли служба устройств идентификатор встроенного ПО (FID). Если он присутствует, он извлекает FID, который определяется как GUID. Спецификация службы устройств встроенного ПО, которую IHV должна поддерживать на устройстве, описана ниже.
  • Служба WWAN (ОС Windows) создает "обратимое устройство-узел" с помощью FID, полученного выше в качестве идентификатора оборудования устройства. Это называется "Soft Dev Node" на приведенной выше схеме. Создание узла разработки приведет к запуску подсистемы PnP (ОС Windows), чтобы найти наиболее подходящий драйвер. В Windows 8 система PnP сначала попытается установить драйвер из локального хранилища, если он доступен, и параллельно ОС попытается получить более подходящий драйвер из WU. Драйвер входящие ЗНАЧЕНИЯ NULL будет использоваться в качестве значения по умолчанию, если драйвер лучшего соответствия недоступен для устранения проблемы "Драйвер не найден".
  • Пакет WU IHV, основанный на совпадении FID, вытягивается на компьютер и устанавливается. Ожидается, что FID представляет уникальный номер SKU встроенного ПО (уникальность, определяемая сочетанием устройства VID/PID/REV и MNO). Пакет WU будет содержать драйвер UMDF, созданный IHV, а также полезные данные встроенного ПО.
  • После загрузки IHV UMDF на мягкий узел разработки он отвечает за управление потоком обновления встроенного ПО. Следует отметить, что время жизни обратимого узла разработки привязано к физическому присутствию устройства MBIM. Драйвер UMDF должен выполнить следующие действия для выполнения обновлений встроенного ПО
    • Устройство может перезагрузиться несколько раз во время процесса обновления встроенного ПО, но приведет к тому, что драйвер UMDF будет выгружен или перезагружен.
    • Весь процесс обновления встроенного ПО, включая перезагрузки, должен выполняться не более 60 секунд.
    • После завершения обновления встроенного ПО и изменения режима MBIM устройство должно быть уведомлено о том, что Windows должна быть уведомлена. Это делается путем очистки ранее заданного свойства DEVPKEY_Device_PostInstallInProgress. Интерфейс IWDFUnifiedPropertyStore описывает, как задать свойство на узле разработки. Ранее заданное свойство можно очистить с помощью DEVPROP_TYPE_EMPTY.
    • Во время обратного вызова OnPrepareHardware UMDF драйвер UMDF должен проверить, нужно ли обновить встроенное ПО на устройстве. Это делается путем сравнения версии встроенного ПО на устройстве с тем, который поступил через Обновл. Windows. Дополнительные рекомендации приведены далее в документе о расположении размещения двоичного файла встроенного ПО. Если требуется обновление встроенного ПО, драйвер UMDF должен:
      • Планирование рабочего элемента. Фактическое обновление встроенного ПО происходит в контексте рабочего элемента.
      • После успешного планирования рабочего элемента уведомите Windows о начале обновления встроенного ПО. Для этого необходимо задать свойство DEVPKEY_Device_PostInstallInProgress на обратимом узле разработки в контексте обратного вызова OnPrepareHardware UMDF.
      • Важно не блокировать обратный вызов OnPrepareHardware, пока обновление встроенного ПО выполняется. Ожидается, что обратный вызов OnPrepareHardware завершается в течение второго или двух в большей степени.

Пример INF-файла для пакета WU

В этом разделе представлен пример INF, который является частью пакета WU. Основные моменты, которые следует отметить в INF-файле:

  • Двоичные файлы встроенного ПО не зависят от драйвера UMDF.
  • Двоичные файлы встроенного ПО находятся в каталоге driverstore, пути, определяемого операционной системой и на который ссылается INF с помощью DIRID 13. Двоичные файлы не могут быть исполняемыми файлами, содержащими заголовки 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. Существующие известные службы определены в спецификации NCM MBIM в разделе 10.1. Корпорация Майкрософт расширяет это, чтобы определить следующую службу.

Имя службы = идентификатор встроенного ПО Майкрософт

UUID = UUID_MSFWID UUID

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

В частности, для службы устройств UUID_MSFWID определен следующий идентификатор CID:

CID = CID_MBIM_MSFWID_FIRMWAREID

Командный код = 1

Query = Да

Set = No

Событие = Нет

Установка полезных данных InformationBuffer = N/A

Полезные данные Query InformationBuffer = N/A

Полезные данные Завершения InformationBuffer = UUID

CID_MBIM_MSFWID_FIRMWAREID

Команда возвращает идентификатор встроенного ПО MNO или IHV для устройства. Идентификатор UUID закодирован на основе рекомендаций в спецификации MBIM.

Query = InformationBuffer на MBIM_COMMAND_MSG не используется. UUID, возвращенный в MBIM_COMMAND_DONE InformationBuffer.

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;
}