Condividi tramite


Scrivere un driver per il connettore USB Type-C

È necessario scrivere un driver connettore USB Type-C in questi scenari:

  • Se l'hardware Type-C USB ha la possibilità di gestire la macchina a stati di Power Delivery (PD). In caso contrario, considerare di scrivere un driver per il controller della porta USB Type-C. Per altre informazioni, vedere Scrivere un driver del controller di porta USB Type-C.

  • Se l'hardware non dispone di un controller incorporato. In caso contrario, caricare il driver integrato fornito da Microsoft, UcmUcsi.sys. (Vedere driver UCSI) per trasporti ACPI o scrivere un driver client UCSI per trasporti diversi da ACPI.

Sommario

  • Oggetto UCM usato dall'estensione della classe e dal driver client
  • Servizi forniti dall'estensione della classe UCM
  • Comportamento previsto del client driver

Specifiche ufficiali

Si applica a:

  • Windows 10

Versione di WDF

  • KMDF versione 1.15
  • UMDF versione 2.15

API importanti

Descrive la gestione connettori USB (UCM) che gestisce un connettore USB Type-C e il comportamento previsto di un driver del connettore.

UCM è progettato usando il modello di driver client di estensione della classe WDF. L'estensione di classe (UcmCx) è un driver WDF fornito da Microsoft che fornisce interfacce che il driver client può chiamare per segnalare informazioni sul connettore. Il driver client UCM usa le interfacce hardware del connettore e mantiene l'estensione della classe consapevole degli eventi che si verificano nel connettore. Viceversa, l'estensione della classe richiama le funzioni di callback implementate dal driver client in risposta agli eventi del sistema operativo.

Per abilitare un connettore USB Type-C in un sistema, è necessario scrivere il driver client.

gestore di connettori USB.

Prima di iniziare

  • Installare la versione più recente di Windows Driver Kit (WDK) nel computer di sviluppo. Il kit include i file di intestazione e le librerie necessari per la scrittura di un driver client UCM, in particolare, è necessario:

    • La libreria stub, (UcmCxstub.lib). La libreria converte le chiamate effettuate dal driver client e le passa a UcmCx.

    • File di intestazione, UcmCx.h.

      È possibile scrivere un driver client UCM eseguito in modalità utente o in modalità kernel. Per la modalità utente, viene associato alla libreria UMDF 2.x; per la modalità kernel è KMDF 1.15. Le interfacce di programmazione sono identiche per entrambe le modalità.

      Configurazione di Visual Studio per ucm.

  • Decidere se il driver client supporterà le funzionalità avanzate del connettore USB Type-C e della distribuzione di alimentazione USB.

    Questo supporto consente di creare dispositivi Windows con connettori USB Type-C, dock usb Type-C e accessori e caricabatterie USB Type-C. Il driver client segnala gli eventi del connettore che consentono al sistema operativo di implementare criteri relativi a USB e consumo di energia nel sistema.

  • Installare Windows 10 per le edizioni desktop (Home, Pro, Enterprise ed Education) nel computer di destinazione o Windows 10 Mobile con un connettore USB Type-C.

  • Acquisire familiarità con UCM e come interagisce con altri driver di Windows. Vedi Architettura: progettazione di Type-C USB per un sistema Windows.

  • Acquisire familiarità con Windows Driver Foundation (WDF). Lettura consigliata: Sviluppo di driver con Windows Driver Foundation, scritto da Penny Orwick e Guy Smith.

Riepilogo dei servizi forniti dall'estensione della classe UCM

L'estensione della classe UCM mantiene il sistema operativo informato sulle modifiche apportate ai dati e al ruolo di alimentazione, ai livelli di ricarica e al contratto PD negoziato. Mentre il driver client interagisce con l'hardware, deve notificare all'estensione della classe quando si verificano tali modifiche. L'estensione della classe fornisce un set di metodi che il driver client può usare per inviare le notifiche (descritte in questo argomento). Ecco i servizi forniti:

Configurazione del ruolo dati

Nei sistemi USB Type-C, il ruolo dati (host o funzione) dipende dallo stato dei pin CC del connettore. Il driver client legge la linea CC (vedere Architettura: progettazione USB Type-C per un sistema Windows) dal controller di porta per determinare se la porta è stata risolta in una porta UFP (Upstream Facing Port) o DFP (Downstream Facing Port). Segnala le informazioni all'estensione della classe in modo che possa segnalare il ruolo corrente ai driver del commutatore di ruolo USB.

Nota

I driver del commutatore di ruolo USB vengono usati nei sistemi Windows 10 Mobile. Nei sistemi Windows 10 per le edizioni desktop, la comunicazione tra l'estensione della classe e i driver del cambio di ruolo è facoltativa. Tali sistemi potrebbero non usare un controller a doppio ruolo, nel qual caso i driver del cambio di ruolo non vengono usati.

Ruolo di alimentazione e ricarica

Il driver client legge l'annuncio corrente USB Type-C o negozia un contratto di alimentazione Power Delivery (PD) con il partner connettore.

  • In un sistema Windows 10 Mobile, la decisione di scegliere il caricabatterie appropriato è assistita da software. Il driver client segnala le informazioni sul contratto all'estensione della classe per poter inviare i livelli di carica al driver di arbitrato di ricarica (CAD.sys). CAD seleziona il livello corrente da usare e inoltra le informazioni sul livello di ricarica al sottosistema della batteria.
  • In un sistema windows 10 per le edizioni desktop, il caricabatterie appropriato è selezionato dall'hardware. Il driver client può scegliere di ottenere tali informazioni e inoltrarlo all'estensione della classe. In alternativa, tale logica può essere implementata da un driver diverso.

Modifiche ai dati e al ruolo di potenza

Dopo la negoziazione di un contratto PD, i ruoli dati e i ruoli di potenza potrebbero cambiare. Tale modifica potrebbe essere avviata dal driver client o dal connettore partner. Il driver client segnala le informazioni all'estensione della classe, in modo che possa riconfigurare gli elementi di conseguenza.

Aggiornamento dei dati e/o del ruolo di alimentazione

Il sistema operativo potrebbe decidere che il ruolo dei dati corrente non è corretto. In tal caso, l'estensione della classe chiama la funzione di callback del driver per eseguire le operazioni di scambio dei ruoli necessarie.

Il Gestore delle Politiche USB Type-C fornito da Microsoft monitora le attività dei connettori USB Type-C. Windows, versione 1809, introduce un set di interfacce di programmazione che è possibile usare per scrivere un driver client in Gestione criteri. Il driver client può partecipare alle decisioni relative ai criteri per i connettori usb Type-C. Con questo set, è possibile scegliere di scrivere un driver di esportazione in modalità kernel o un driver in modalità utente. Per ulteriori informazioni, vedere Creare un driver client USB Type-C Policy Manager.

Comportamento previsto del driver client

Il driver client è responsabile di queste attività:

  • Rilevare le modifiche nella riga CC e determinare il tipo di partner, ad esempio UFP, DFP e altri. A tale scopo, il driver deve implementare la macchina a stati Type-C completa, come definito nella specifica USB Type-C.
  • Configurare il mux in base all'orientamento rilevato nella riga CC. Ciò include l'attivazione del trasmettitore/ricevitore PD e la gestione e la risposta ai messaggi PD. A tale scopo, il driver deve implementare le macchine a stati complete del ricevitore e del trasmettitore PD, come definito nella specifica USB Power Delivery 2.0.
  • Prendere decisioni relative ai criteri PD, ad esempio negoziare un contratto (come origine o sink), scambi di ruoli e altri. Il driver client è responsabile della determinazione del contratto più appropriato.
  • Annunciare e negoziare modalità alternative e configurare il Mux se viene rilevata una modalità alternativa. Il driver client è responsabile di decidere quale modalità alternativa negoziare.
  • Controllo di VBus/VConn sul connettore.

1. Inizializzare l'oggetto connettore UCM (UCMCONNECTOR)

L'oggetto connettore UCM (UCMCONNECTOR) rappresenta il connettore USB Type-C ed è l'handle principale tra l'estensione della classe UCM e il driver client. L'oggetto tiene traccia delle modalità operative del connettore e delle capacità di alimentazione.

Ecco il riepilogo della sequenza in cui il driver client recupera un handle UCMCONNECTOR per il connettore. Eseguire queste attività nel tuo ruolo di conducente

  1. Chiamare UcmInitializeDevice passando il riferimento a una struttura UCM_MANAGER_CONFIG . Il driver deve chiamare questo metodo nella funzione di callback EVT_WDF_DRIVER_DEVICE_ADD prima di chiamare WdfDeviceCreate.

  2. Specificare i parametri di inizializzazione per il connettore USB Type-C in una struttura UCM_CONNECTOR_TYPEC_CONFIG . Ciò include la modalità operativa del connettore, sia che si tratti di una porta rivolta a valle, di una porta rivolta verso l'alto o di una porta con doppio ruolo. Specifica inoltre i livelli correnti di Type-C USB quando il connettore è una fonte di alimentazione. Un connettore usb Type-C può essere progettato in modo che possa agire un jack audio da 3,5 mm. Se l'hardware supporta la funzionalità, l'oggetto connettore deve essere inizializzato di conseguenza.

    Nella struttura è anche necessario registrare la funzione di callback del driver client per la gestione dei ruoli relativi ai dati.

    Questa funzione di callback è associata all'oggetto connettore, richiamato dall'estensione della classe UCM. Questa funzione deve essere implementata dal driver client.

    EVT_UCM_CONNECTOR_SET_DATA_ROLE Scambia il ruolo dati del connettore con il ruolo specificato quando è collegato a un connettore partner.

  3. Se il driver client vuole supportare PD, ovvero gestire l'implementazione hardware di Power Delivery 2.0 del connettore, è necessario inizializzare anche una struttura UCM_CONNECTOR_PD_CONFIG che specifica i parametri di inizializzazione PD. Ciò include il flusso di alimentazione, indipendentemente dal fatto che il connettore sia un assorbitore di alimentazione o una fonte.

    Nella struttura del codice è necessario registrare anche la funzione di callback del driver client per la gestione dei ruoli di alimentazione.

    Questa funzione di callback è associata all'oggetto connettore, richiamato dall'estensione della classe UCM. Questa funzione deve essere implementata dal driver client.

    EVT_UCM_CONNECTOR_SET_POWER_ROLE Imposta il ruolo di alimentazione del connettore sul ruolo specificato quando è collegato a un connettore partner.

  4. Chiamare UcmConnectorCreate e recuperare un handle UCMCONNECTOR per il connettore. Assicurarsi di chiamare questo metodo dopo che il driver client ha creato l'oggetto dispositivo framework chiamando WdfDeviceCreate. Una posizione appropriata per questa chiamata può essere nel EVT_WDF_DEVICE_PREPARE_HARDWARE o EVT_WDF_DEVICE_D0_ENTRY del driver.

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. Segnalare l'evento di connessione del connettore partner

Il driver client deve chiamare UcmConnectorTypeCAttach quando viene rilevata una connessione a un connettore partner. Questa chiamata notifica all'estensione della classe UCM, che a sua volta notifica il sistema operativo. A questo punto il sistema può iniziare a ricaricare a livelli di Type-C USB.

L'estensione della classe UCM notifica anche i driver del commutatore di ruolo USB (URS). In base al tipo di partner, URS configura il controller nel ruolo host o nel ruolo della funzione. Prima di chiamare questo metodo, assicurarsi che il Mux nel sistema sia configurato correttamente. In caso contrario, se il sistema è in modalità funzione, si connetterà a una velocità sbagliata (ad alta velocità anziché 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. Segnala delle modifiche alla pubblicità USB Type-C

Nell'evento di collegamento iniziale, il connettore partner invia un annuncio corrente. Se l'annuncio specifica il livello corrente del connettore partner quando il partner è una porta USB Type-C verso il basso. In caso contrario, l'annuncio specifica il livello corrente del connettore locale, rappresentato dall'handle UCMCONNECTOR (connettore locale). Questo annuncio iniziale potrebbe cambiare durante la durata della connessione. Tali modifiche devono essere monitorate dal driver client.

Se il connettore locale è il sink di alimentazione e l'annuncio corrente cambia, il driver client deve rilevare le modifiche nell'annuncio corrente e segnalarle all'estensione della classe. Nei sistemi Windows 10 Mobile, tali informazioni vengono usate da CAD.sys e dal sottosistema della batteria per regolare la quantità di corrente che sta prelevando dalla fonte. Per segnalare la modifica del livello corrente all'estensione della classe, il driver client deve chiamare UcmConnectorTypeCCurrentAdChanged.

4. Segnalare il nuovo contratto PD negoziato

Se il connettore supporta PD, dopo l'evento di collegamento iniziale, sono presenti messaggi PD trasferiti tra il connettore e il connettore partner. Tra entrambi i partner viene negoziato un contratto PD che determina i livelli correnti che il connettore può disegnare o consentire al partner di disegnare. Ogni volta che il contratto PD cambia, il driver client deve chiamare questi metodi per segnalare la modifica all'estensione della classe.

  • Il driver client deve chiamare questi metodi ogni volta che riceve una comunicazione riguardante le capacità della sorgente, sia essa non sollecitata o di altro tipo, dal partner. Il connettore locale (sink) ottiene un annuncio non richiesto dal partner solo quando il partner è l'origine. Inoltre, il connettore locale può richiedere in modo esplicito le funzionalità di origine dal partner in grado di essere l'origine (anche quando il partner è attualmente il sink). Tale scambio viene eseguito inviando un messaggio di Get_Source_Caps al partner.
  • Al contrario, il driver client deve chiamare questi metodi ogni volta che il connettore locale (origine) annuncia le funzionalità di origine al partner. Inoltre, quando il connettore locale riceve un messaggio di Get_Source_Caps dal partner, deve rispondere con le funzionalità di origine del connettore locale.

5. Segnala lo stato di ricarica della batteria

Il driver client può notificare l'estensione della classe UCM se il livello di ricarica non è adeguato. L'estensione della classe segnala queste informazioni al sistema operativo. Il sistema utilizza tali informazioni per mostrare una notifica dell'utente che il caricabatterie non carica in modo ottimale il sistema. Lo stato di ricarica può essere segnalato da questi metodi:

Questi metodi specificano lo stato di ricarica. Se i livelli segnalati sono UcmChargingStateSlowCharging o UcmChargingStateTrickleCharging (vedere UCM_CHARGING_STATE), il sistema operativo visualizza la notifica dell'utente.

6. Segnalare eventi PR_Swap/DR_Swap

Se il connettore riceve un messaggio di scambio del ruolo di alimentazione (PR_Swap) o del ruolo dati (DR_Swap) dal partner, il driver client deve inviare una notifica all'estensione della classe UCM.

  • UcmConnectorDataDirectionChanged

    Chiamare questo metodo dopo l'elaborazione di un messaggio di DR_Swap PD. Dopo questa chiamata, il sistema operativo segnala il nuovo ruolo a URS, che rimuove i driver di ruolo esistenti e carica i driver per il nuovo ruolo.

  • UcmConnectorPowerDirectionChanged

    Chiamare questo metodo dopo l'elaborazione di un messaggio di PR_Swap PD. Dopo un PR_Swap, il contratto PD deve essere rinegoziato. Il driver client deve segnalare che la negoziazione del contratto PD avviene chiamando i metodi descritti nel passaggio 4.

7. Implementare funzioni di callback per gestire le richieste di scambio di ruoli di alimentazione e dati

L'estensione della classe UCM potrebbe ricevere richieste per modificare i dati o la direzione dell'alimentazione del connettore. In tal caso, richiama le funzioni di callback del driver client di EVT_UCM_CONNECTOR_SET_DATA_ROLE e EVT_UCM_CONNECTOR_SET_POWER_ROLE (se il connettore supporta PD). Il driver client ha registrato in precedenza tali funzioni nella chiamata a UcmConnectorCreate.

Il driver client esegue operazioni di scambio dei ruoli usando interfacce hardware.

  • EVT_UCM_CONNECTOR_SET_DATA_ROLE

    Nell'implementazione del callback, ci si aspetta che il driver client esegua:

    1. Invia un messaggio PD DR_Swap al partner di porta.
    2. Chiamare UcmConnectorDataDirectionChanged per notificare all'estensione della classe che la sequenza di messaggi è stata completata correttamente o in modo non riuscito.
    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

    Nell'implementazione del callback, si prevede che il driver cliente:

    1. Inviare un messaggio PD PR_Swap al porta-partner.
    2. Chiamare UcmConnectorPowerDirectionChanged per notificare all'estensione della classe che la sequenza di messaggi è stata completata correttamente o in modo non riuscito.
    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;
    }
    

Nota

Il driver client può chiamare UcmConnectorDataDirectionChanged e UcmConnectorPowerDirectionChanged in modo asincrono, che non proviene dal thread di callback. In un'implementazione tipica, l'estensione della classe richiama le funzioni di callback che causano l'avvio di una transazione hardware da parte del driver client per l'invio del messaggio. Al termine della transazione, l'hardware invia una notifica al driver. Il driver chiama quei metodi per notificare l'estensione della classe.

8. Segnalare l'evento di scollegamento del connettore partner

Il driver client deve chiamare UcmConnectorTypeCDetach al termine della connessione a un connettore partner. Questa chiamata notifica all'estensione della classe UCM, che a sua volta notifica il sistema operativo.

Esempio di caso d'uso: Dispositivo mobile connesso a un PC

Quando un dispositivo che esegue Windows 10 Mobile è connesso a un PC che esegue Windows 10 per le edizioni desktop tramite una connessione USB Type-C, il sistema operativo assicura che il dispositivo mobile sia la porta UFP (Upstream Facing Port) perché MTP è funzionale solo in tale direzione. In questo scenario, ecco la sequenza per la correzione del ruolo dei dati.

  1. Il driver client, in esecuzione nel dispositivo mobile, segnala un evento di collegamento chiamando UcmConnectorTypeCAttach e segnala il connettore partner come porta UFP (Downstream Facing Port).
  2. Il driver del client segnala il contratto PD chiamando UcmConnectorPdPartnerSourceCaps e UcmConnectorPdConnectionStateChanged.
  3. L'estensione della classe UCM notifica ai driver del lato dispositivo USB, inducendo tali driver a rispondere all'enumerazione dall'host. Le informazioni del sistema operativo vengono scambiate tramite USB.
  4. L'estensione della classe UcmCx richiama le funzioni di callback del driver client per modificare i ruoli: EVT_UCM_CONNECTOR_SET_DATA_ROLE e EVT_UCM_CONNECTOR_SET_POWER_ROLE.

Nota

Se due dispositivi Windows 10 Mobile sono connessi tra loro, non viene eseguito uno scambio di ruoli e l'utente riceve una notifica che indica che la connessione non è valida.