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


Написание драйвера для разъема 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 для настольных версий (Home, Pro, Enterprise и Education) на вашем целевом компьютере или 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) или нисходящий порт (DFP). Этот процесс передает информацию в расширение класса, чтобы оно смогло сообщить текущую роль драйверам переключения ролей USB.

Примечание.

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

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

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

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

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

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

Обновление данных и/или роли электропитания

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

Диспетчер политик USB Type-C от Microsoft отслеживает действия соединителей 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, таких как переговоры о контракте (источник или приемник), переключение ролей и другие. Драйвер клиента отвечает за определение наиболее подходящего контракта.
  • Рекламируйте и согласовывайте альтернативные режимы, и настраивайте Mux, если обнаружен альтернативный режим. Драйвер клиента отвечает за выбор альтернативного режима для согласования.
  • Управление VBus/VConn через соединитель.

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

Объект соединителя UCM (UCMCONNECTOR) представляет собой USB-коннектор Type-C и является главным элементом управления между расширением класса 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. Если драйвер клиента хочет быть способным к Power Delivery, а именно обработать реализацию оборудования 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 в системе настроен правильно. В противном случае, если система находится в режиме функции, она будет подключаться с неправильной скоростью (High-Speed вместо 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

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

  • UcmConnectorPowerDirectionChanged

    Вызовите этот метод после обработки сообщения PD PR_Swap. После 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. Отправьте сообщение pd DR_Swap партнеру порта.
    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. Отправьте сообщение pd PR_Swap партнеру порта.
    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 подключены друг к другу, переключение ролей не выполняется, и пользователь уведомляется о том, что подключение не является допустимым.