Scrivere un driver del connettore USB Type-C

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

  • Se l'hardware USB Type-C ha la capacità di gestire il computer di stato di alimentazione (PD). In caso contrario, prendere in considerazione la scrittura di un driver del controller di porta USB Type-C. Per altre informazioni, vedere Scrivere un driver del controller di porta USB Type-C.

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

Riepilogo

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

Specifiche ufficiali

Si applica a

  • Windows 10

Versione WDF

  • KMDF versione 1.15
  • UMDF versione 2.15

API importanti

Descrive la gestione del connettore 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 della 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. Al contrario, 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.

Gestione connettore usb.

Prima di iniziare

  • Installare windows Driver Kit (WDK) più recente 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:

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

    • File di intestazione, UcmCx.h.

      È possibile scrivere un driver client UCM che viene eseguito in modalità utente o in modalità kernel. Per la modalità utente, associa la 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 supporta funzionalità avanzate del connettore USB Type-C e usb Power Delivery.

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

  • Installare Windows 10 per le edizioni desktop (Home, Pro, Enterprise e 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. Vedere Architettura: progettazione USB Type-C 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 inviare una notifica 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 (illustrate 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 riga 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 con connessione upstream (UFP) o porta con connessione downstream (UFP). Segnala che le informazioni all'estensione della classe in modo che possano 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. In Windows 10 per i sistemi desktop, la comunicazione tra l'estensione della classe e i driver del commutatore di ruolo è facoltativa. Tali sistemi potrebbero non usare un controller a doppio ruolo, nel qual caso i driver del commutatore di ruolo non vengono usati.

Ruolo di alimentazione e ricarica

Il driver client legge l'annuncio corrente del tipo USB-C oppure negozia un contratto di alimentazione PD con il connettore partner.

  • In un sistema Windows 10 Mobile, la decisione di scegliere il caricatore appropriato è assistito dal software. Il driver client segnala le informazioni sul contratto all'estensione della classe in modo che possa inviare i livelli di ricarica 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 di Windows 10 per le edizioni desktop, il caricatore appropriato viene 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 alimentazione

Dopo che un contratto PD è stato negoziato, i ruoli dati e i ruoli di alimentazione 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 di conseguenza le cose.

Aggiornamento dei dati e/o del ruolo di alimentazione

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

Microsoft ha fornito USB Type-C Policy Manager 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 Policy Manager. Il driver client può partecipare alle decisioni dei 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 altre informazioni, vedere Scrivere 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 il computer con stato Type-C completo, come definito nella specifica USB Type-C.
  • Configurare Mux in base all'orientamento rilevato nella riga CC. Ciò include l'attivazione del trasmettitore PD/ricevitore e la gestione e la risposta ai messaggi PD. A tale scopo, il driver deve implementare il ricevitore PD completo e i computer di stato del trasmettitore, come definito nella specifica USB Power Delivery 2.0.
  • Prendere decisioni di 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.
  • Pubblicizzare e negoziare modalità alternative e configurare mux se viene rilevata una modalità alternativa. Il driver client è responsabile della scelta della modalità alternativa da 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 funzionalità di alimentazione.

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

  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, indipendentemente dal fatto che si tratti di una porta rivolta a valle, di una porta rivolta a monte o che sia in grado di supportare due ruoli. Specifica anche i livelli correnti USB Type-C quando il connettore è una fonte di alimentazione. Un connettore USB Type-C può essere progettato in modo da poter 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 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 è associato 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 sink di alimentazione o un'origine.

    Nella struttura è anche necessario registrare 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 è associato 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ò trovarsi nel EVT_WDF_DEVICE_PREPARE_HARDWARE o nel 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 collegamento 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 notifica ulteriormente il sistema operativo. A questo punto il sistema può avviare la ricarica a livelli USB Type-C.

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 di funzione. Prima di chiamare questo metodo, assicurarsi che Mux nel sistema sia configurato correttamente. In caso contrario, se il sistema è in funzione, si connetterà a una velocità non corretta (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. Segnalare modifiche all'annuncio di tipo USB-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 a valle di tipo USB Type-C. 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 utilizzate da CAD.sys e dal sottosistema della batteria per regolare la quantità di corrente che sta disegnando dall'origine. 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, vengono trasferiti messaggi PD 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 un annuncio di funzionalità di origine (non richiesto o altrimenti) 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 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. Segnalare lo stato di ricarica della batteria

Il driver client può inviare una notifica all'estensione della classe UCM se il livello di ricarica non è adeguato. L'estensione della classe segnala queste informazioni al sistema operativo. Il sistema usa tali informazioni per mostrare a un utente la notifica che il caricatore 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 ruolo di alimentazione (PR_Swap) o un messaggio di scambio 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 pd DR_Swap. 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 pd PR_Swap. Dopo un PR_Swap, il contratto PD deve essere rinegoziato. Il driver client deve segnalare che la negoziazione del contratto PD 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 l'implementazione del driver client di EVT_UCM_CONNECTOR_SET_DATA_ROLE e EVT_UCM_CONNECTOR_SET_POWER_ROLE funzioni di callback (se il connettore implementa 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, è previsto che il driver client:

    1. Inviare un messaggio pd DR_Swap al partner porta.
    2. Chiamare UcmConnectorDataDirectionChanged per notificare all'estensione della classe che la sequenza di messaggi è stata completata correttamente o non è riuscita.
    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, è previsto che il driver client:

    1. Inviare un messaggio pd PR_Swap al partner porta.
    2. Chiamare UcmConnectorPowerDirectionChanged per notificare all'estensione della classe che la sequenza di messaggi è stata completata correttamente o non è riuscita.
    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 tali metodi per notificare all'estensione della classe.

8. Segnalare l'evento di scollegamento del connettore partner

Il driver client deve chiamare UcmConnectorTypeCDetach quando termina la connessione a un connettore partner. Questa chiamata notifica all'estensione della classe UCM, che notifica ulteriormente 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 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 client segnala il contratto PD chiamando UcmConnectorPdPartnerSourceCaps e UcmConnectorPdConnectionStateChanged.
  3. L'estensione della classe UCM notifica ai driver lato dispositivo USB che causano la risposta di tali driver 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 Windows 10 Mobile dispositivi sono connessi l'uno all'altro, lo scambio di ruoli non viene eseguito e l'utente riceve una notifica che la connessione non è una connessione valida.