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

Необходимо написать драйвер контроллера порта USB Type-C, если оборудование USB Type-C реализует физический уровень USB-C или power delivery (PD), но не реализует конечные компьютеры, необходимые для доставки питания.

В Windows 10 версии 1703 архитектура USB Type-C была улучшена для поддержки аппаратных конструкций, которые реализуют физический уровень USB-C или Power Delivery (PD), но не имеют соответствующей реализации политики PD или уровня протокола. Для этих проектов Windows 10 версии 1703 предоставляет программный модуль политики PD и диспетчер политик устройств с помощью нового расширения класса " Usb Connector Manager Type-C Port Controller Interface Interface Interface Interface Extension" (UcmTcpciCx). Драйвер клиента, написанный IHV или OEM/ODM, взаимодействует с UcmTcpciCx для предоставления сведений об аппаратных событиях, необходимых для работы обработчика политик PD и диспетчера политик устройств в UcmTcpciCx. Эта связь включается с помощью набора программных интерфейсов, описанных в этой статье и в справочном разделе.

Схема диспетчера USB-соединителей.

Расширение класса UcmTcpciCx само по себе является клиентским драйвером UcmCx. Политики, касающиеся контрактов питания и ролей данных, принимаются в UcmCx и перенаправляются в UcmTcpciCx. UcmTcpciCx реализует эти политики и управляет компьютерами состояний Type-C и PD, используя интерфейс контроллера порта, предоставляемый драйвером клиента UcmTcpciCx.

Сводка

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

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

Важные API

Справочник по расширениям класса драйвера интерфейса контроллера порта USB Type-C

Шаблон драйвера клиента UcmTcpciCx

Шаблон драйвера клиента UcmTcpciCx

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

  • Определите тип драйвера, необходимого для записи, в зависимости от того, реализует ли ваш аппаратный или встроенное ПО конечный автомат PD. Дополнительные сведения см. в статье Разработка драйверов Windows для соединителей USB Type-C.

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

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

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

    Драйвер клиента работает в режиме ядра и привязывается к библиотеке KMDF 1.15.

    Снимок экрана: конфигурация Visual Studio для UCM.

  • Решите, поддерживает ли драйвер клиента оповещения.

  • Контроллер порта не обязательно должен быть совместим с TCPCI. Интерфейс фиксирует возможности любого контроллера порта Type-C. Написание клиентского драйвера UcmTcpciCx для оборудования, не совместимого с TCPCI, включает сопоставление значений регистров и команд в спецификации TCPCI с значениями оборудования.

  • Большинство контроллеров TCPCI подключены к I2C. Драйвер клиента использует ресурс подключения последовательной периферийной шины (SPB) и линию прерывания для связи с оборудованием. Драйвер использует программный интерфейс расширения SPB Framework (SpbCx). Ознакомьтесь с SpbCx, прочитав следующие статьи:

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

Поведение расширения класса UcmTcpci

  • В рамках выполнения конечного автомата UcmTcpciCx отправляет запросы IOCTL на контроллер порта. Например, при обмене сообщениями с PD он отправляет IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_TRANSMIT_BUFFER запрос на настройку буфера передачи. Этот запрос (TRANSMIT_BUFFER) передается драйверу клиента. Затем драйвер задает буфер передачи со сведениями, предоставленными расширением класса.

  • UcmTcpciCx реализует политики о контрактах питания, ролях данных и т. д.

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

Ожидается, что драйвер клиента для UcmTcpciCx:

  • Быть владельцем политики управления питанием. UcmTcpciCx не участвует в управлении питанием контроллера порта.

  • Преобразуйте запросы, полученные от UcmTcpciCx, в аппаратные команды чтения или записи. Команды должны быть асинхронными, так как DPM не может блокировать ожидание завершения передачи оборудования.

  • Укажите объект очереди платформы, содержащий объекты запроса платформы. Для каждого запроса, который расширение класса UcmTcpci хочет отправить драйверу клиента, расширение добавляет объект запроса в объект очереди драйвера. Когда драйвер завершает обработку запроса, он вызывает WdfRequestComplete. Ответственность за своевременное выполнение запросов лежит на драйвере клиента.

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

    Хранилище возможностей

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

    Отделяя описание возможностей системы от драйвера клиента для контроллеров портов, конструкция позволяет использовать драйвер в разных системах с различными возможностями. UcmCx, а не UcmTcpciCx, взаимодействует с хранилищем возможностей. UcmTcpciCx (или его клиентский драйвер) не взаимодействует с хранилищем возможностей.

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

  • Уведомите UcmTcpciCx всеми соответствующими данными, связанными с оповещениями.

  • Необязательный элемент. Выполните дополнительную обработку после ввода или выхода из альтернативного режима. Драйвер информируется об этих состояниях расширением класса через запросы IOCTL.

Регистрация драйвера клиента с помощью UcmTcpciCx

Пример справки: см. EvtPrepareHardware в Device.cpp.

  1. В реализации EVT_WDF_DRIVER_DEVICE_ADD вызовите UcmTcpciDeviceInitInitialize, чтобы инициализировать WDFDEVICE_INIT непрозрачную структуру. Вызов связывает драйвер клиента с платформой.

  2. После создания объекта устройства платформы (WDFDEVICE) вызовите UcmTcpciDeviceInitialize, чтобы зарегистрировать делитель клиента в UcmTcpciCx.

Инициализация канала связи I2C с оборудованием контроллера порта

Пример справки: см. EvtCreateDevice в Device.cpp.

В реализации EVT_WDF_DEVICE_PREPARE_HARDWARE ознакомьтесь с аппаратными ресурсами, чтобы открыть коммуникационный канал. Это необходимо для получения возможностей PD и получения уведомлений об оповещениях.

Большинство контроллеров TCPCI подключены к I2C. В эталонном примере драйвер клиента открывает канал I2 с помощью программного интерфейса расширения SPB Framework (SpbCx).

Драйвер клиента перечисляет аппаратные ресурсы, вызывая WdfCmResourceListGetDescriptor.

Оповещения принимаются в виде прерываний. Таким образом, драйвер создает объект прерывания платформы и регистрирует ISR, обрабатывающий оповещения. ISR выполняет аппаратные операции чтения и записи, которые блокируются до завершения доступа к оборудованию. Поскольку ожидание в DIRQL неприемлемо, драйвер выполняет ISR на PASSIVE_LEVEL.

Инициализация возможностей type-C и PD контроллера порта

Пример справки: см. EvtDeviceD0Entry в Device.cpp.

В реализации EVT_WDF_DEVICE_D0_EXIT:

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

  2. Инициализируйте UCMTCPCI_PORT_CONTROLLER_IDENTIFICATION и UCMTCPCI_PORT_CONTROLLER_CAPABILITIES с помощью полученных сведений.

  3. Инициализируйте UCMTCPCI_PORT_CONTROLLER_CONFIG структуру с приведенными выше сведениями, передавая инициализированные структуры в UCMTCPCI_PORT_CONTROLLER_CONFIG_INIT.

  4. Вызовите UcmTcpciPortControllerCreate, чтобы создать объект контроллера порта и получить дескриптор UCMTCPCIPORTCONTROLLER.

Настройка объекта очереди платформы для получения запросов от UcmTcpciCx

Пример справки: см. EvtDeviceD0Entry в Device.cpp и HardwareRequestQueueInitialize в Queue.cpp.

  1. В реализации EVT_WDF_DEVICE_D0_EXIT создайте объект очереди платформы, вызвав WdfIoQueueCreate. В этом вызове необходимо зарегистрировать реализацию обратного вызова для обработки запросов IOCTL, отправленных UcmTpciCx. Драйвер клиента может использовать управляемую питанием очередь.

    Во время выполнения конечных машин Type-C и PD UcmTpciCx отправляет команды драйверу клиента для выполнения. UcmTcpciCx гарантирует не более одного запроса контроллера порта в любой момент времени.

  2. Вызовите UcmTcpciPortControllerSetHardwareRequestQueue, чтобы зарегистрировать новый объект очереди платформы в UcmTpciCx. После успешного вызова UcmTcpciCx помещает объекты очереди платформы (WDFREQUEST) в эту очередь, когда требуется действие от драйвера.

  3. Реализуйте функцию обратного вызова EvtIoDeviceControl для обработки этих ioCTL.

Код элемента управления Описание
IOCTL_UCMTCPCI_PORT_CONTROLLER_GET_STATUS Возвращает значения всех регистров состояния в спецификации интерфейса контроллера порта Универсальной последовательной шины типа C. Драйвер клиента должен получить значения регистров CC_STATUS, POWER_STATUS и FAULT_STATUS.
IOCTL_UCMTCPCI_PORT_CONTROLLER_GET_CONTROL Возвращает значения всех регистров элементов управления, определенных в соответствии со спецификацией интерфейса контроллера порта Типа C универсальной последовательной шины.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_CONTROL Задает значение регистра элемента управления, определенного в соответствии со спецификацией интерфейса контроллера порта Универсальной последовательной шины типа C.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_TRANSMIT Задает регистр ПЕРЕДАЧи, определенный в соответствии со спецификацией интерфейса контроллера порта универсальной последовательной шины типа C.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_TRANSMIT_BUFFER Задает регистр TRANSMIT_BUFER, определенный в соответствии со спецификацией интерфейса контроллера порта Типа C универсальной последовательной шины.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_RECEIVE_DETECT Задает регистр RECEIVE_DETECT, определенный в соответствии со спецификацией интерфейса контроллера порта Универсальной последовательной шины типа C.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_CONFIG_STANDARD_OUTPUT Задает регистр CONFIG_STANDARD_OUTPUT, определенный в соответствии со спецификацией интерфейса контроллера порта Типа C универсальной последовательной шины.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_COMMAND Задает значение регистра команд, определенное в соответствии со спецификацией интерфейса контроллера порта Универсальной последовательной шины типа C.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_MESSAGE_HEADER_INFO Задает значение MESSAGE_HEADER_INFO Register, определенное в соответствии со спецификацией интерфейса контроллера порта Типа C универсальной последовательной шины.
IOCTL_UCMTCPCI_PORT_CONTROLLER_ALTERNATE_MODE_ENTERED Уведомляет драйвер клиента о том, что введен альтернативный режим, чтобы драйвер смог выполнять другие задачи.
IOCTL_UCMTCPCI_PORT_CONTROLLER_ALTERNATE_MODE_EXITED Уведомляет драйвер клиента о выходе из альтернативного режима, чтобы драйвер смог выполнять другие задачи.
IOCTL_UCMTCPCI_PORT_CONTROLLER_DISPLAYPORT_CONFIGURED Уведомляет драйвер клиента о том, что альтернативный режим DisplayPort на устройстве партнера настроен с назначением контактов, чтобы драйвер смог выполнять другие задачи.
IOCTL_UCMTCPCI_PORT_CONTROLLER_DISPLAYPORT_HPD_STATUS_CHANGED Уведомляет драйвер клиента о том, что состояние обнаружения с горячей заменой подключения DisplayPort изменилось, чтобы драйвер смог выполнять другие задачи.
  1. Вызовите UcmTcpciPortControllerStart, чтобы указать UcmTcpciCx запустить контроллер порта. UcmTcpciCx предполагает управление USB Type-C и питанием. После запуска контроллера порта UcmTcpciCx может начать помещать запросы в очередь запросов оборудования.

Обработка оповещений с оборудования контроллера порта

Пример справочника: см. ProcessAndSendAlerts в Alert.cpp

Драйвер клиента должен обрабатывать оповещения (или события), полученные от оборудования контроллера портов, и отправлять их в UcmTcpciCx с данными, связанными с событием.

При возникновении аппаратного оповещения контроллер порта обеспечивает высокий уровень пин-кода ALERT. Это приводит к вызову ISR драйвера клиента (зарегистрированного на шаге 2). Обычное обслуживание аппаратного прерывания на PASSIVE_LEVEL. Подпрограмма определяет, является ли прерывание оповещением от оборудования контроллера порта; Если да, он завершает обработку оповещения и уведомляет UcmTcpciCx путем вызова UcmTcpciPortControllerAlert.

Перед вызовом UcmTcpciPortControllerAlert клиент отвечает за включение всех соответствующих данных, связанных с оповещением, в структуру UCMTCPCI_PORT_CONTROLLER_ALERT_DATA. Клиент предоставляет массив всех активных оповещений, так как существует вероятность того, что оборудование может одновременно утверждать несколько оповещений.

Ниже приведен пример потока задач для отчета об изменениях в статусе CC.

  1. Клиент получает оповещение оборудования.

  2. Клиент считывает регистр ALERT и определяет активные типы оповещений.

  3. Клиент считывает регистр CC STATUS и описывает содержимое регистра CC STATUS в UCMTCPCI_PORT_CONTROLLER_ALERT_DATA. Драйвер задает для элемента AlertType значение UcmTcpciPortControllerAlertCCStatus и ccStatus, являющегося членом регистра.

  4. Клиент вызывает UcmPortControllerAlert для отправки оповещений оборудования массива в UcmTcpciCx.

  5. Клиент очищает оповещение (это может произойти в любое время после получения клиентом сведений об оповещении).

Обработка запросов, полученных от UcmTcpciCx

Пример справочника: см. раздел PortControllerInterface.cpp

В рамках выполнения конечного автомата UcmTcpciCx должен отправлять запросы на контроллер порта. Например, необходимо задать TRANSMIT_BUFFER. Этот запрос передается драйверу клиента. Драйвер задает буфер передачи со сведениями, предоставленными UcmTcpciCx. Большинство этих запросов преобразуются в аппаратное чтение или запись клиентским драйвером. Команды должны быть асинхронными, так как DPM не может блокировать ожидание завершения передачи оборудования.

UcmTcpciCx отправляет команды в виде управляющего кода ввода-вывода, описывающего операцию get/set, необходимую драйвером клиента. При настройке очереди драйвера клиента драйвер зарегистрировал свою очередь с помощью UcmTcpciCx. UcmTcpciCx начинает размещать объекты запросов платформы в очереди, требуемой от драйвера. Коды элементов управления вводом-выводом перечислены в таблице на шаге 4.

Ответственность за своевременное выполнение запросов лежит на драйвере клиента.

Драйвер клиента вызывает WdfRequestComplete для объекта запроса платформы с состоянием завершения после завершения запрошенной операции.

Драйверу клиента может потребоваться отправить запрос ввода-вывода другому драйверу для выполнения аппаратной операции. Например, в примере драйвер отправляет запрос SPB контроллеру порта, подключенного к I2C. В этом случае драйвер не может переслать объект запроса платформы, полученный из UcmTcpciCx, так как объект запроса может иметь неправильное количество расположений стека в WDM IRP. Драйвер клиента должен создать другой объект запроса платформы и перенаправить его другому драйверу. Драйвер клиента может предварительно выделить объекты запроса, необходимые ему во время инициализации, а не создавать каждый раз, когда получает запрос от UcmTcpciCx. Это возможно, так как UcmTcpciCx гарантирует, что в любой момент времени будет не выполнен только один запрос.

См. также: