Запись драйвера соединителя USB Type-C

В следующих сценариях необходимо написать драйвер соединителя USB Type-C:

  • Если оборудование USB Type-C имеет возможность обработки конечного автомата доставки питания (PD). В противном случае рассмотрите возможность написания драйвера контроллера порта USB Type-C. Дополнительные сведения см. в статье Запись драйвера контроллера порта USB Type-C.

  • Если оборудование не имеет встроенного контроллера. В противном случае загрузите встроенный драйвер, предоставленный корпорацией Майкрософт, UcmUcsi.sys. (См. раздел Драйвер UCSI) для транспорта ACPI или запись драйвера клиента UCSI для транспорта без ACPI.

Сводка

  • Объект UCM, используемый расширением класса и драйвером клиента
  • Службы, предоставляемые расширением класса UCM
  • Ожидаемое поведение драйвера клиента

Официальные спецификации

Применяется к

  • Windows 10

Версия WDF

  • KMDF версии 1.15
  • UMDF версии 2.15

Важные API

Описывает диспетчер USB-соединителей (UCM), который управляет соединителем USB Type-C и ожидаемым поведением драйвера соединителя.

UCM разработан с использованием модели драйвера расширения-клиента WDF. Расширение класса (UcmCx) — это предоставленный Корпорацией Майкрософт драйвер WDF, предоставляющий интерфейсы, которые драйвер клиента может вызывать для передачи сведений о соединителе. Драйвер клиента UCM использует аппаратные интерфейсы соединителя и держит расширение класса в курсе событий, происходящих в соединителе. И наоборот, расширение класса вызывает функции обратного вызова, реализованные драйвером клиента в ответ на события операционной системы.

Чтобы включить в системе соединитель USB Type-C, необходимо написать драйвер клиента.

диспетчер соединителей USB.

Подготовка к работе

  • Установите последнюю версию пакета драйверов Windows (WDK) на компьютере разработчика. В комплекте есть необходимые файлы заголовков и библиотеки для написания драйвера клиента UCM. В частности, вам потребуется:

    • Библиотека заглушки (UcmCxstub.lib). Библиотека преобразует вызовы, сделанные драйвером клиента, и передает их в UcmCx.

    • Файл заголовка UcmCx.h.

      Вы можете написать драйвер клиента UCM, который выполняется в пользовательском режиме или режиме ядра. В пользовательском режиме он привязывается к библиотеке UMDF 2.x; В режиме ядра используется KMDF 1.15. Интерфейсы программирования идентичны для обоих режимов.

      Конфигурация Visual Studio для ucm.

  • Решите, будет ли драйвер клиента поддерживать расширенные функции соединителя USB Type-C и USB-питания.

    Эта поддержка позволяет создавать устройства Windows с разъемами USB Type-C, док-станциями и аксессуарами USB Type-C, а также зарядными устройствами USB Type-C. Драйвер клиента сообщает о событиях соединителя, которые позволяют операционной системе реализовывать политики по USB и энергопотреблению в системе.

  • Установите Windows 10 для настольных компьютеров (Домашняя, Pro, Корпоративная и для образовательных учреждений) на целевом компьютере или Windows 10 Mobile с соединителем USB Type-C.

  • Ознакомьтесь с UCM и его взаимодействием с другими драйверами Windows. См. раздел Архитектура: проектирование USB Type-C для системы Windows.

  • Ознакомьтесь с Windows Driver Foundation (WDF). Рекомендуемое чтение: Разработка драйверов с помощью Windows Driver Foundation, написанная Пенни Орвик и Гай Смит.

Сводка служб, предоставляемых расширением класса UCM

Расширение класса UCM информирует операционную систему об изменениях в данных и роли питания, уровнях зарядки и согласованном контракте PD. Хотя драйвер клиента взаимодействует с оборудованием, он должен уведомлять расширение класса о таких изменениях. Расширение класса предоставляет набор методов, которые драйвер клиента может использовать для отправки уведомлений (рассматривается в этом разделе). Ниже приведены предоставляемые службы.

Конфигурация роли данных

В системах USB Type-C роль данных (узел или функция) зависит от состояния контактов CC соединителя. Драйвер клиента считывает строку CC (см. раздел Архитектура: проектирование USB Type-C для системы Windows) с контроллера порта, чтобы определить, был ли порт разрешен в вышестоящий порт (UFP) или нижестоящий порт (UFP). Он передает эти сведения в расширение класса, чтобы он смог сообщить о текущей роли драйверам переключения ролей USB.

Примечание

Драйверы переключения ролей USB используются в Windows 10 Mobile системах. На Windows 10 для систем классических выпусков обмен данными между расширением класса и драйверами переключения ролей необязателен. В таких системах может не использоваться контроллер с двойной ролью. В этом случае драйверы переключения ролей не используются.

Роль питания и зарядка

Драйвер клиента считывает текущее объявление USB Type-C или согласовывает контракт на питание PD с соединителем партнера.

  • В системе Windows 10 Mobile решение о выборе соответствующего зарядного устройства осуществляется программным обеспечением. Драйвер клиента передает сведения о контракте в расширение класса, чтобы он смог отправить уровни зарядки драйверу арбитража зарядки (CAD.sys). САПР выбирает текущий уровень для использования и перенаправит сведения об уровне зарядки в подсистему батареи.
  • В системе Windows 10 для настольных компьютеров соответствующее зарядное устройство выбирается оборудованием. Драйвер клиента может получить эти сведения и перенаправить их в расширение класса. Кроме того, эта логика может быть реализована другим драйвером.

Изменения ролей данных и ролей питания

После согласования контракта PD роли данных и роли управления могут измениться. Это изменение может быть инициировано драйвером клиента или соединителем партнера. Драйвер клиента передает эти сведения в расширение класса, чтобы он мог перенастроить все соответствующим образом.

Обновление данных и (или) роли питания

Операционная система может решить, что текущая роль данных является неправильной. В этом случае расширение класса вызывает функцию обратного вызова драйвера для выполнения необходимых операций переключения ролей.

Предоставленный корпорацией Майкрософт диспетчер политик USB Type-C отслеживает действия соединителей USB Type-C. В Windows версии 1809 представлен набор программных интерфейсов, которые можно использовать для записи драйвера клиента в диспетчер политик. Драйвер клиента может участвовать в принятии решений политики для соединителей USB Type-C. С помощью этого набора можно написать драйвер экспорта в режиме ядра или драйвер пользовательского режима. Дополнительные сведения см. в статье Запись драйвера клиента диспетчера политик USB Type-C.

Ожидаемое поведение драйвера клиента

Драйвер клиента отвечает за следующие задачи:

  • Обнаружение изменений в строке CC и определение типа партнера, например UFP, DFP и других. Для этого драйвер должен реализовать полный конечный автомат Type-C, как определено в спецификации USB Type-C.
  • Настройте mux на основе ориентации, обнаруженной в строке CC. Сюда входит включение передатчика или приемника PD, а также обработка сообщений PD и реагирование на них. Для этого драйвер должен реализовать полные устройства с состоянием приемника PD и передатчика, как определено в спецификации USB Power Delivery 2.0.
  • Принимать решения политики PD, такие как переговоры о контракте (в качестве источника или приемника), переключения ролей и другие. Драйвер клиента отвечает за определение наиболее подходящего контракта.
  • Объявление и согласование альтернативных режимов, а также настройка мультиплекса при обнаружении альтернативного режима. Драйвер клиента отвечает за выбор альтернативного режима для согласования.
  • Управление VBus/VConn через соединитель.

1. Инициализация объекта соединителя UCM (UCMCONNECTOR)

Объект соединителя UCM (UCMCONNECTOR) представляет соединитель USB Type-C и является дескриптором main между расширением класса UCM и драйвером клиента. Объект отслеживает режимы работы соединителя и возможности источников энергии.

Ниже приведена сводка последовательности, в которой драйвер клиента получает дескриптор UCMCONNECTOR для соединителя. Выполнение этих задач в драйвере

  1. Вызовите UcmInitializeDevice , передав ссылку на структуру UCM_MANAGER_CONFIG . Драйвер должен вызвать этот метод в функции обратного вызова EVT_WDF_DRIVER_DEVICE_ADD перед вызовом WdfDeviceCreate.

  2. Укажите параметры инициализации для соединителя USB Type-C в структуре UCM_CONNECTOR_TYPEC_CONFIG . Сюда входит режим работы соединителя, будь то подчиненный порт, порт с вышестоящий или с поддержкой двойной роли. Он также указывает текущие уровни USB Type-C, если соединитель является источником питания. Разъем USB Type-C можно спроектировать таким образом, чтобы он действовал как аудиоразъем 3,5 мм. Если оборудование поддерживает эту функцию, объект соединителя должен быть инициализирован соответствующим образом.

    В структуре необходимо также зарегистрировать функцию обратного вызова драйвера клиента для обработки ролей данных.

    Эта функция обратного вызова связана с объектом соединителя, который вызывается расширением класса UCM. Эта функция должна быть реализована драйвером клиента.

    EVT_UCM_CONNECTOR_SET_DATA_ROLE Переключает роль данных соединителя на указанную при подключении к соединителю партнера.

  3. Если драйвер клиента хочет поддерживать PD, то есть обрабатывать аппаратную реализацию соединителя Power Delivery 2.0, необходимо также инициализировать структуру UCM_CONNECTOR_PD_CONFIG , которая задает параметры инициализации PD. Сюда входит поток питания, независимо от того, является ли соединитель приемником питания или источником.

    В структуре необходимо также зарегистрировать функцию обратного вызова драйвера клиента для обработки ролей управления.

    Эта функция обратного вызова связана с объектом соединителя, который вызывается расширением класса UCM. Эта функция должна быть реализована драйвером клиента.

    EVT_UCM_CONNECTOR_SET_POWER_ROLE Устанавливает для роли питания соединителя указанную роль при подключении к соединителю партнера.

  4. Вызовите UcmConnectorCreate и получите дескриптор UCMCONNECTOR для соединителя. Убедитесь, что вы вызываете этот метод после того, как драйвер клиента создал объект устройства платформы, вызвав WdfDeviceCreate. Подходящее место для этого вызова может находиться в EVT_WDF_DEVICE_PREPARE_HARDWARE или EVT_WDF_DEVICE_D0_ENTRY драйвера.

EVT_UCM_CONNECTOR_SET_DATA_ROLE     EvtSetDataRole;

NTSTATUS
EvtDevicePrepareHardware(
    WDFDEVICE Device,
    WDFCMRESLIST ResourcesRaw,
    WDFCMRESLIST ResourcesTranslated
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    PDEVICE_CONTEXT devCtx;
    UCM_MANAGER_CONFIG ucmCfg;
    UCM_CONNECTOR_CONFIG connCfg;
    UCM_CONNECTOR_TYPEC_CONFIG typeCConfig;
    UCM_CONNECTOR_PD_CONFIG pdConfig;
    WDF_OBJECT_ATTRIBUTES attr;
    PCONNECTOR_CONTEXT connCtx;

    UNREFERENCED_PARAMETER(ResourcesRaw);
    UNREFERENCED_PARAMETER(ResourcesTranslated);

    TRACE_FUNC_ENTRY();

    devCtx = GetDeviceContext(Device);

    if (devCtx->Connector)
    {
        goto Exit;
    }

    //
    // Initialize UCM Manager
    //
    UCM_MANAGER_CONFIG_INIT(&ucmCfg);

    status = UcmInitializeDevice(Device, &ucmCfg);
    if (!NT_SUCCESS(status))
    {
        TRACE_ERROR(
            "UcmInitializeDevice failed with %!STATUS!.",
            status);
        goto Exit;
    }

    TRACE_INFO("UcmInitializeDevice() succeeded.");

    //
    // Create a USB Type-C connector #0 with PD
    //
    UCM_CONNECTOR_CONFIG_INIT(&connCfg, 0);

    UCM_CONNECTOR_TYPEC_CONFIG_INIT(
        &typeCConfig,
        UcmTypeCOperatingModeDrp,
        UcmTypeCCurrentDefaultUsb | UcmTypeCCurrent1500mA | UcmTypeCCurrent3000mA);

    typeCConfig.EvtSetDataRole = EvtSetDataRole;

    UCM_CONNECTOR_PD_CONFIG_INIT(&pdConfig, UcmPowerRoleSink | UcmPowerRoleSource);

    connCfg.TypeCConfig = &typeCConfig;
    connCfg.PdConfig = &pdConfig;

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, CONNECTOR_CONTEXT);

    status = UcmConnectorCreate(Device, &connCfg, &attr, &devCtx->Connector);
    if (!NT_SUCCESS(status))
    {
        TRACE_ERROR(
            "UcmConnectorCreate failed with %!STATUS!.",
            status);
        goto Exit;
    }

    connCtx = GetConnectorContext(devCtx->Connector);

    UcmEventInitialize(&connCtx->EventSetDataRole);

    TRACE_INFO("UcmConnectorCreate() succeeded.");

Exit:

    TRACE_FUNC_EXIT();
    return status;
}

2. Сообщите о событии подключения соединителя партнера

Драйвер клиента должен вызывать UcmConnectorTypeCAttach при обнаружении подключения к соединителю партнера. Этот вызов уведомляет расширение класса UCM, которое дополнительно уведомляет операционную систему. На этом этапе система может начать зарядку на уровнях USB Type-C.

Расширение класса UCM также уведомляет usb-драйверы коммутатора ролей (URS). В зависимости от типа партнера URS настраивает контроллер в роли узла или роли функции. Перед вызовом этого метода убедитесь, что mux в вашей системе настроен правильно. В противном случае, если система находится в роли функции, она будет подключаться с неправильной скоростью (высокая скорость вместо SuperSpeed).

        UCM_CONNECTOR_TYPEC_ATTACH_PARAMS attachParams;

        UCM_CONNECTOR_TYPEC_ATTACH_PARAMS_INIT(
            &attachParams,
            UcmTypeCPortStateDfp);
        attachParams.CurrentAdvertisement = UcmTypeCCurrent1500mA;

        status = UcmConnectorTypeCAttach(
                    Connector,
                    &attachParams);
        if (!NT_SUCCESS(status))
        {
            TRACE_ERROR(
                "UcmConnectorTypeCAttach() failed with %!STATUS!.",
                status);
            goto Exit;
        }

        TRACE_INFO("UcmConnectorTypeCAttach() succeeded.");

3. Сообщить об изменениях объявления USB Type-C

В начальном событии присоединения соединитель партнера отправляет текущее объявление. Если в объявлении указан текущий уровень соединителя партнера, если партнер является портом USB Type-C, подключенным к нисходящему потоку. В противном случае объявление указывает текущий уровень локального соединителя, представленный дескриптором UCMCONNECTOR (локальным соединителем). Это начальное объявление может измениться в течение жизненного цикла подключения. Эти изменения должны отслеживаться драйвером клиента.

Если локальный соединитель является приемником питания и текущими изменениями объявления, драйвер клиента должен обнаружить изменения в текущем объявлении и сообщить о них расширению класса. В Windows 10 Mobile системах эта информация используется CAD.sys и подсистемой батареи для настройки объема текущего объема, которое она получает из источника. Чтобы сообщить об изменении текущего уровня расширению класса, драйвер клиента должен вызвать UcmConnectorTypeCCurrentAdChanged.

4. Сообщить о новом согласованном контракте PD

Если соединитель поддерживает PD, после первоначального присоединения между соединителем и его партнерским соединителем передаются сообщения PD. Между обоими партнерами согласовывается контракт PD, который определяет текущие уровни, которые соединитель может нарисовать или позволить партнеру нарисовать. При каждом изменении контракта PD драйвер клиента должен вызывать эти методы, чтобы сообщить об изменении расширению класса.

  • Драйвер клиента должен вызывать эти методы всякий раз, когда получает от партнера объявление о возможностях источника (незапрошенное или иным образом). Локальный соединитель (приемник) получает нежелательное объявление от партнера только в том случае, если партнер является источником. Кроме того, локальный соединитель может явно запрашивать возможности источника у партнера, который может быть источником (даже если партнер в настоящее время является приемником). Обмен осуществляется путем отправки Get_Source_Caps сообщения партнеру.
    • UcmConnectorPdPartnerSourceCaps для отчета об исходных возможностях, объявленных соединителем партнера.
    • UcmConnectorPdConnectionStateChanged для передачи сведений о контракте. Контракт описывается в запросе объекта данных, определенном в спецификации Power Delivery 2.0.
  • И наоборот, драйвер клиента должен вызывать эти методы каждый раз, когда локальный соединитель (источник) объявляет возможности источника партнеру. Кроме того, когда локальный соединитель получает Get_Source_Caps сообщение от партнера, он должен ответить с исходными возможностями локального соединителя.
    • UcmConnectorPdSourceCaps , чтобы сообщить об исходных возможностях, объявленных системой соединителю партнера.
    • UcmConnectorPdConnectionStateChanged для отчета о возможностях подключения для согласованного контракта PD.

5. Отчет о состоянии зарядки батареи

Драйвер клиента может уведомить расширение класса UCM, если уровень зарядки недостаточно. Расширение класса передает эти сведения операционной системе. Система использует эти сведения для отображения уведомления пользователя о том, что зарядное устройство не оптимально заряжается. Состояние зарядки можно сообщить следующими способами:

Эти методы определяют состояние зарядки. Если сообщаемые уровни — UcmChargingStateSlowCharging или UcmChargingStateTrickleCharging (см . UCM_CHARGING_STATE), операционная система отображает уведомление пользователя.

6. Отчет о событиях PR_Swap/DR_Swap

Если соединитель получает от партнера сообщение о переключении роли питания (PR_Swap) или роли данных (DR_Swap), драйвер клиента должен уведомить расширение класса UCM.

  • UcmConnectorDataDirectionChanged

    Вызовите этот метод после обработки сообщения DR_Swap PD. После этого вызова операционная система передает новую роль в URS, которая удаляет существующие драйверы ролей и загружает драйверы для новой роли.

  • UcmConnectorPowerDirectionChanged

    Вызовите этот метод после обработки сообщения PR_Swap PD. После PR_Swap контракт PD необходимо пересмотреть. Драйвер клиента должен сообщить о согласовании контракта PD, вызвав методы, описанные на шаге 4.

7. Реализация функций обратного вызова для обработки запросов на переключение ролей данных и питания

Расширение класса UCM может получать запросы на изменение данных или направления питания соединителя. В этом случае он вызывает реализацию драйвера клиента EVT_UCM_CONNECTOR_SET_DATA_ROLE и EVT_UCM_CONNECTOR_SET_POWER_ROLE функций обратного вызова (если соединитель реализует PD). Драйвер клиента ранее зарегистрировал эти функции в вызове UcmConnectorCreate.

Драйвер клиента выполняет операции переключения ролей с помощью аппаратных интерфейсов.

  • EVT_UCM_CONNECTOR_SET_DATA_ROLE

    В реализации обратного вызова драйвер клиента должен:

    1. Отправьте DR_Swap pd партнеру по портам.
    2. Вызовите UcmConnectorDataDirectionChanged , чтобы уведомить расширение класса о том, что последовательность сообщений успешно или неудачно завершена.
    EVT_UCM_CONNECTOR_SET_DATA_ROLE     EvtSetDataRole;
    
    NTSTATUS
    EvtSetDataRole(
        UCMCONNECTOR  Connector,
        UCM_TYPE_C_PORT_STATE DataRole
        )
    {
        PCONNECTOR_CONTEXT connCtx;
    
        TRACE_INFO("EvtSetDataRole(%!UCM_TYPE_C_PORT_STATE!) Entry", DataRole);
    
        connCtx = GetConnectorContext(Connector);
    
        TRACE_FUNC_EXIT();
    
        return STATUS_SUCCESS;
    }
    
  • EVT_UCM_CONNECTOR_SET_POWER_ROLE

    В реализации обратного вызова драйвер клиента должен:

    1. Отправьте PR_Swap pd партнеру по портам.
    2. Вызовите UcmConnectorPowerDirectionChanged , чтобы уведомить расширение класса о том, что последовательность сообщений успешно или неудачно завершена.
    EVT_UCM_CONNECTOR_SET_POWER_ROLE     EvtSetPowerRole;
    
    NTSTATUS
    EvtSetPowerRole(
        UCMCONNECTOR Connector,
        UCM_POWER_ROLE PowerRole
        )
    {
        PCONNECTOR_CONTEXT connCtx;
    
        TRACE_INFO("EvtSetPowerRole(%!UCM_POWER_ROLE!) Entry", PowerRole);
    
        connCtx = GetConnectorContext(Connector);
    
        //PR_Swap operation.
    
        TRACE_FUNC_EXIT();
    
        return STATUS_SUCCESS;
    }
    

Примечание

Драйвер клиента может вызывать UcmConnectorDataDirectionChanged и UcmConnectorPowerDirectionChanged асинхронно, то есть не из потока обратного вызова. В типичной реализации расширение класса вызывает функции обратного вызова, что приводит к тому, что драйвер клиента инициирует аппаратную транзакцию для отправки сообщения. После завершения транзакции оборудование уведомляет драйвер. Драйвер вызывает эти методы для уведомления расширения класса.

8. Сообщите о событии отключения соединителя партнера

Драйвер клиента должен вызывать UcmConnectorTypeCDetach при завершении подключения к соединителю партнера. Этот вызов уведомляет расширение класса UCM, которое дополнительно уведомляет операционную систему.

Пример использования: мобильное устройство, подключенное к компьютеру

Когда устройство под управлением Windows 10 Mobile подключено к компьютеру с Windows 10 для настольных выпусков через usb Type-C, операционная система гарантирует, что мобильное устройство является вышестоящим портом (UFP), так как MTP работает только в этом направлении. В этом сценарии ниже приведена последовательность для исправления роли данных:

  1. Драйвер клиента, работающий на мобильном устройстве, сообщает о событии присоединения путем вызова UcmConnectorTypeCAttach и сообщает о соединителе партнера в качестве порта нижестоящего подключения (UFP).
  2. Драйвер клиента сообщает о контракте PD, вызывая UcmConnectorPdPartnerSourceCaps и UcmConnectorPdConnectionStateChanged.
  3. Расширение класса UCM уведомляет драйверы на стороне USB-устройства, в результате чего эти драйверы реагируют на перечисление с узла. Обмен данными об операционной системе осуществляется через USB.
  4. Расширение класса UCM UcmCx вызывает функции обратного вызова драйвера клиента для изменения ролей: EVT_UCM_CONNECTOR_SET_DATA_ROLE и EVT_UCM_CONNECTOR_SET_POWER_ROLE.

Примечание

Если два Windows 10 Mobile устройства подключены друг к другу, переключение ролей не выполняется и пользователь получает уведомление о том, что подключение не является допустимым.