Aracılığıyla paylaş


Bir UCSI istemci sürücüsü yazın

USB Type-C Bağlayıcı Sistemi Yazılım Arabirimi (UCSI) sürücüsü, ekli denetleyiciye (EC) sahip bir USB Type-C sisteminin denetleyici sürücüsü olarak görev alır.

Platform İlkesi Yöneticisi'ni (PPM), UCSI belirtiminde açıklandığı şekilde, sisteme bağlı bir EC üzerinden uygulayan sisteminiz:

  • ACPI aktarımı için sürücü yazmanız gerekmez . Microsoft tarafından sağlanan yerleşik sürücüyü (UcmUcsiCx.sys ve UcmUcsiAcpiClient.sys) yükleyin. (Bkz . UCSI sürücüsü).

  • USB, PCI, I2C veya UART gibi ACPI olmayan bir aktarım, denetleyici için bir istemci sürücüsü yazmanız gerekir.

Uyarı

USB Type-C donanımınız güç teslimi (PD) durum makinesini işleme özelliğine sahip değilse usb Type-C bağlantı noktası denetleyicisi sürücüsü yazmayı göz önünde bulundurun. Daha fazla bilgi için bkz. USB Type-C bağlantı noktası denetleyicisi sürücüsü yazma.

Windows 10, sürüm 1809'dan başlayarak, UCSI belirtimini aktarım belirsiz bir şekilde uygulayan UCSI (UcmUcsiCx.sys) için yeni bir sınıf uzantısı eklendi. Minimum miktarda kodla, UcmUcsiCx istemcisi olan sürücünüz ACPI olmayan aktarım üzerinden USB Type-C donanımıyla iletişim kurabilir. Bu konuda, UCSI sınıf uzantısı tarafından sağlanan hizmetler ve istemci sürücüsünün beklenen davranışı açıklanmaktadır.

Resmi belirtimler

Şunlar için geçerlidir:

  • Windows 10, sürüm 1809

WDF sürümü

  • KMDF sürüm 1.27

Önemli API'ler

UcmUcsiCx sınıf uzantıları başvurusu

Örnek

UcmUcsiCx istemci sürücüsü örneği

ACPI bölümlerini gereken otobüs için uygulamanızla değiştirin.

UCSI sınıf uzantı mimarisi

UCSI sınıf uzantısı UcmUcsiCx, ACPI dışı aktarım kullanarak katıştırılmış denetleyicisiyle iletişim kuran bir sürücü yazmanızı sağlar. Denetleyici sürücüsü, UcmUcsiCx için bir istemci sürücüsüdür. UcmUcsiCx, usb bağlayıcı yöneticisine (UCM) bir istemcidir. Bu nedenle, UcmUcsiCx kendi ilke kararlarını vermez. Bunun yerine, UCM tarafından sağlanan ilkeleri uygular. UcmUcsiCx, istemci sürücüsünden Platform İlkesi Yöneticisi (PPM) bildirimlerini işlemek için durum makineleri uygular ve UCM ilke kararlarını uygulamak için komutlar gönderir ve daha güvenilir bir sorun algılama ve hata işleme sağlar.

UCSI sınıf uzantısı mimarisi.

İşletim Sistemi İlke Yöneticisi (OPM)

İşletim Sistemi İlkesi Yöneticisi (OPM), UCSI belirtiminde açıklandığı gibi PPM ile etkileşime geçmek için mantığı uygular. OPM şu görevden sorumludur:

  • UCM ilkelerini UCSI komutlarına ve UCSI bildirimlerini UCM bildirimlerine dönüştürme.
  • PPM'yi başlatmak, hatayı algılamak ve kurtarma mekanizmaları için gereken UCSI komutlarını gönderme.

UCSI komutlarını işleme

Tipik bir işlem, UCSI uyumlu donanım tarafından tamamlanacak çeşitli komutları içerir. Örneğin, GET_CONNECTOR_STATUS komutunu düşünelim.

  1. PPM üretici yazılımı UcmUcsiCx/istemci sürücüsüne bir bağlantı değişikliği bildirimi gönderir.
  2. Yanıt olarak, UcmUcsiCx/istemci sürücüsü PPM üretici yazılımına bir GET_CONNECTOR_STATUS komutu gönderir.
  3. PPM üretici yazılımı GET_CONNECTOR_STATUS yürütür ve zaman uyumsuz olarak UcmUcsiCx/istemci sürücüsüne bir komut tamamlama bildirimi gönderir. Bu bildirim, gerçek bağlantı durumuyla ilgili veriler içerir.
  4. UcmUcsiCx/istemci sürücüsü bu durum bilgilerini işler ve PPM üretici yazılımına bir ACK_CC_CI gönderir.
  5. PPM üretici yazılımı ACK_CC_CI yürütür ve zaman uyumsuz olarak UcmUcsiCx/client sürücüsüne bir komut tamamlama bildirimi gönderir.
  6. UcmUcsiCx/client sürücüsü, GET_CONNECTOR_STATUS komutunun tamamlanmasını dikkate alır.

Platform İlkesi Yöneticisi (PPM) ile iletişim

UcmUcsiCx, UCSI komutlarını OPM'den PPM üretici yazılımına gönderme ve PPM üretici yazılımından bildirim alma ayrıntılarını özetler. PPM komutlarını WDFREQUEST nesnelerine dönüştürür ve istemci sürücüsüne iletir.

  • PPM Bildirimleri

    İstemci sürücüsü, donanım yazılımından PPM bildirimleri hakkında UcmUcsiCx'e bildirimde bulunur. Sürücü, CCI içeren UCSI veri bloğunu sağlar. UcmUcsiCx, OPM ve verilere göre uygun eylemleri gerçekleştiren diğer bileşenlere bildirimleri iletir.

  • İstemci sürücüsüne IOCTL komutları

    UcmUcsiCx, PPM üretici yazılımına göndermek için istemci sürücüsüne UCSI komutlarını (IOCTL istekleri aracılığıyla) gönderir. Sürücü, üretici yazılımına UCSI komutunu gönderdikten sonra isteği tamamlamaktan sorumludur.

Güç geçişlerini işleme

İstemci sürücüsü güç ilkesi sahibidir.

İstemci sürücüsü S0-Idle nedeniyle Dx durumuna girerse, UcmUcsiCx, istemci sürücüsünün güç ile yönetilen kuyruğuna UCSI komutu içeren bir IOCTL gönderdiğinde WDF sürücüyü D0'ye getirir. S0-Idle'da PPM bildirimleri hala etkin olduğundan üretici yazılımından PPM bildirimi olduğunda S0-Idle istemci sürücüsü güçlendirilmiş bir durumuna geri dönmelidir.

Başlamadan önce

  • Donanımınızın veya üretici yazılımınızın PD durum makinesini ve taşımayı uygulayıp uygulamadığına bağlı olarak yazmanız gereken sürücü türünü belirleyin.

    Doğru sınıf uzantısını seçme kararı. Daha fazla bilgi için bkz. USB Type-C bağlayıcıları için Windows sürücüleri geliştirme.

  • Masaüstü sürümleri (Home, Pro, Enterprise ve Education) için Windows 10'u yükleyin.

  • Geliştirme bilgisayarınıza en son Windows Sürücü Seti'ni (WDK) yükleyin. Set, istemci sürücüsünü yazmak için gerekli üst bilgi dosyalarına ve kitaplıklarına sahiptir; özellikle şunları yapmanız gerekir:

    • Saplama kitaplığı( UcmUcsiCxStub.lib). Kitaplık, istemci sürücüsü tarafından yapılan çağrıları çevirir ve sınıf uzantısına geçirir.
    • Başlık dosyası, Ucmucsicx.h.
    • İstemci sürücüsü çekirdek modunda çalışır ve KMDF 1.27 kitaplığına bağlanır.
  • Windows Driver Foundation (WDF) hakkında bilgi sahibi olun. Önerilen okuma: Penny Orwick ve Guy Smith tarafından yazılan Windows Driver Foundation ile Sürücü Geliştirme .

1. İstemci sürücünüzü UcmUcsiCx ile kaydedin

EVT_WDF_DRIVER_DEVICE_ADD uygulamanızda.

  1. Tak ve Kullan ve güç yönetimi olay geri çağırma işlevlerini (WdfDeviceInitSetPnpPowerEventCallbacks) ayarladıktan sonra, WDFDEVICE_INIT opak yapısını başlatmak için UcmUcsiDeviceInitInitialize'ı çağırın. çağrısı, istemci sürücüsünü çerçeveyle ilişkilendirir.

  2. Çerçeve cihaz nesnesini (WDFDEVICE) oluşturduktan sonra, istemci dalıcısını UcmUcsiCx'e kaydetmek için UcmUcsiDeviceInitialize çağrısı yapın.

2. UcmUcsiCx ile PPM nesnesi oluşturma

EVT_WDF_DEVICE_PREPARE_HARDWARE uygulamanızda ham ve çevrilmiş kaynakların listesini aldıktan sonra, donanımı hazırlamak için kaynakları kullanın. Örneğin, aktarım I2C ise, iletişim kanalı açmak için donanım kaynaklarını okuyun. Ardından bir PPM nesnesi oluşturun. Nesneyi oluşturmak için belirli yapılandırma seçeneklerini ayarlamanız gerekir.

  1. Cihazdaki bağlayıcı koleksiyonuna bir tanıtıcı sağlayın.

    1. UcmUcsiConnectorCollectionCreate çağrısı yaparak bağlayıcı koleksiyonunu oluşturun.

    2. UcmUcsiConnectorCollectionAddConnector çağrısı yaparak cihazdaki bağlayıcıları numaralandırın ve koleksiyona ekleyin

      // Create the connector collection.
      
      UCMUCSI_CONNECTOR_COLLECTION* ConnectorCollectionHandle;
      
      status = UcmUcsiConnectorCollectionCreate(Device, //WDFDevice
               WDF_NO_OBJECT_ATTRIBUTES,
               ConnectorCollectionHandle);
      
      // Enumerate the connectors on the device.
      // ConnectorId of 0 is reserved for the parent device.
      // In this example, we assume the parent has no children connectors.
      
      UCMUCSI_CONNECTOR_INFO_INIT(&connectorInfo);
      connectorInfo.ConnectorId = 0;
      
      status = UcmUcsiConnectorCollectionAddConnector ( &ConnectorCollectionHandle,
                   &connectorInfo);
      
  2. Cihaz denetleyicisini etkinleştirmek isteyip istemediğinize karar verin.

  3. PPM nesnesini yapılandırın ve oluşturun.

    1. 1. adımda oluşturduğunuz bağlayıcı tutamacını sağlayarak bir UCMUCSI_PPM_CONFIG yapısını başlatın.

    2. UsbDeviceControllerEnabled üyesini 2. adımda belirlenen boole değerine ayarlayın.

    3. WDF_OBJECT_ATTRIBUTES'da olay geri çağırmalarınızı ayarlayın.

    4. Yapılandırılan tüm yapıları geçirerek UcmUcsiPpmCreate öğesini çağırın.

      UCMUCSIPPM ppmObject = WDF_NO_HANDLE;
      PUCMUCSI_PPM_CONFIG UcsiPpmConfig;
      WDF_OBJECT_ATTRIBUTES attrib;
      
      UCMUCSI_PPM_CONFIG_INIT(UcsiPpmConfig, ConnectorCollectionHandle);
      
      UcsiPpmConfig->UsbDeviceControllerEnabled = TRUE;
      
      WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrib, Ppm);
      attrib->EvtDestroyCallback = &EvtObjectContextDestroy;
      
      status = UcmUcsiPpmCreate(wdfDevice, UcsiPpmConfig, &attrib, &ppmObject);
      

3. IO kuyruklarını ayarlama

UcmUcsiCx, PPM üretici yazılımına göndermek için istemci sürücüsüne UCSI komutları gönderir. Komutlar bir WDF kuyruğunda bu IOCTL istekleri biçiminde gönderilir.

İstemci sürücüsü, UcmUcsiPpmSetUcsiCommandRequestQueue çağrısı yaparak bu kuyruğu oluşturmak ve UcmUcsiCx'e kaydetmekten sorumludur. Kuyruk güç ile yönetilmelidir.

UcmUcsiCx, WDF kuyruğunda en fazla bir bekleyen istek olabileceğini garanti eder. İstemci sürücüsü, üretici yazılımına UCSI komutunu gönderdikten sonra WDF isteğini tamamlamaktan da sorumludur.

Genellikle sürücü , EVT_WDF_DEVICE_PREPARE_HARDWARE uygulamasında kuyrukları ayarlar.

WDFQUEUE UcsiCommandRequestQueue = WDF_NO_HANDLE;
WDF_OBJECT_ATTRIBUTES attrib;
WDF_IO_QUEUE_CONFIG queueConfig;

WDF_OBJECT_ATTRIBUTES_INIT(&attrib);
attrib.ParentObject = GetObjectHandle();

// In this example, even though the driver creates a sequential queue,
// UcmUcsiCx guarantees that will not send another request
// until the previous one has been completed.


WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchSequential);

// The queue must be power-managed.

queueConfig.PowerManaged = WdfTrue;
queueConfig.EvtIoDeviceControl = EvtIoDeviceControl;

status = WdfIoQueueCreate(device, &queueConfig, &attrib, &UcsiCommandRequestQueue);

UcmUcsiPpmSetUcsiCommandRequestQueue(ppmObject, UcsiCommandRequestQueue);

Ayrıca istemci sürücüsünün ayrıca UcmUcsiPpmStart'ı çağırarak sürücünün IOCTL isteklerini almaya hazır olduğunu UcmUcsiCx'e bildirmesi gerekir. UcmUcsiPpmSetUcsiCommandRequestQueue aracılığıyla UCSI komutlarını almak için WDFQUEUE tanıtıcısını oluşturduktan sonra EVT_WDF_DEVICE_PREPARE_HARDWARE içinde bu çağrıyı yapmanızı öneririz. Buna karşılık, sürücü daha fazla istek işlemek istemediğinde UcmUcsiPpmStop çağrısı yapmalıdır. Bunu EVT_WDF_DEVICE_RELEASE_HARDWARE uygulamanızda yapın.

4. IOCTL isteklerini işleme

Bir USB Type-C iş ortağı bir bağlayıcıya eklendiğinde gerçekleşen olayların bu örnek sırasını göz önünde bulundurun.

  1. PPM üretici yazılımı bir ekleme olayı belirler ve istemci sürücüsüne bir bildirim gönderir.
  2. İstemci sürücüsü UcmUcsiPpmNotification'ı çağırarak bu bildirimi UcmUcsiCx'e gönderir.
  3. UcmUcsiCx, OPM durum makinesine bildirir ve UcmUcsiCx'e Bir Bağlayıcı Durumu Al komutu gönderir.
  4. UcmUcsiCx bir istek oluşturur ve istemci sürücüsüne IOCTL_UCMUCSI_PPM_SEND_UCSI_DATA_BLOCK gönderir.
  5. İstemci sürücüsü bu isteği işler ve komutu PPM üretici yazılımına gönderir. Sürücü bu isteği zaman uyumsuz olarak tamamlar ve UcmUcsiCx'e başka bir bildirim gönderir.
  6. Başarılı komut tamamlama bildiriminde OPM durum makinesi yükü okur (bağlayıcı durum bilgilerini içerir) ve Type-C ekleme olayını UCM'ye bildirir.

Bu örnekte kapsam, gömülü yazılım ile port ortağı arasındaki güç teslim müzakeresi durumundaki değişikliğin başarılı olduğunu da göstermektedir. OPM durum makinesi başka bir UCSI komutu gönderir: PDA'ları alma. Bağlayıcı Durumunu Al komutuna benzer şekilde, PPO'ları Al komutu başarıyla tamamlandığında OPM durum makinesi UCM'ye bu olayı bildirir.

İstemci sürücüsünün EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL işleyicisi bu örnek koda benzer. İstekleri işleme hakkında bilgi için bkz. İstek İşleyicileri

void EvtIoDeviceControl(
    _In_ WDFREQUEST Request,
    _In_ ULONG IoControlCode
    )
{
...
    switch (IoControlCode)
    {
    case IOCTL_UCMUCSI_PPM_SEND_UCSI_DATA_BLOCK:
        EvtSendData(Request);
        break;

    case IOCTL_UCMUCSI_PPM_GET_UCSI_DATA_BLOCK:
        EvtReceiveData(Request);
        break;

    default:
        status = STATUS_NOT_SUPPORTED;
        goto Exit;
    }

    status = STATUS_SUCCESS;

Exit:

    if (!NT_SUCCESS(status))
    {
        WdfRequestComplete(Request, status);
    }

}

VOID EvtSendData(
    WDFREQUEST Request
    )
{
    NTSTATUS status;
    PUCMUCSI_PPM_SEND_UCSI_DATA_BLOCK_IN_PARAMS inParams;

    status = WdfRequestRetrieveInputBuffer(Request, sizeof(*inParams),
        reinterpret_cast<PVOID*>(&inParams), nullptr);
    if (!NT_SUCCESS(status))
    {
        goto Exit;
    }

    // Build a UCSI command request and send to the PPM firmware.

Exit:
    WdfRequestComplete(Request, status);
}

VOID EvtReceiveData(
    WDFREQUEST Request
    )
{

    NTSTATUS status;

    PUCMUCSI_PPM_GET_UCSI_DATA_BLOCK_IN_PARAMS inParams;
    PUCMUCSI_PPM_GET_UCSI_DATA_BLOCK_OUT_PARAMS outParams;

    status = WdfRequestRetrieveInputBuffer(Request, sizeof(*inParams),
        reinterpret_cast<PVOID*>(&inParams), nullptr);
    if (!NT_SUCCESS(status))
    {
        goto Exit;
    }

    status = WdfRequestRetrieveOutputBuffer(Request, sizeof(*outParams),
        reinterpret_cast<PVOID*>(&outParams), nullptr);
    if (!NT_SUCCESS(status))
    {
        goto Exit;
    }

    // Receive data from the PPM firmware.
    if (!NT_SUCCESS(status))
    {
        goto Exit;
    }
    WdfRequestSetInformation(Request, sizeof(*outParams));

Exit:
    WdfRequestComplete(Request, status);
}