Scrivere un driver client del controller di funzione

Questo articolo descrive le varie attività eseguite da un driver client del controller di funzione durante l'interazione con l'estensione del controller di funzione USB (UFX).

API importanti

Descrive le varie attività eseguite da un driver client del controller di funzione durante l'interazione con l'estensione del controller di funzione USB (UFX). UFX e il driver client comunicano tra loro usando metodi di esportazione e funzioni di callback degli eventi. I metodi di esportazione (denominati UfxDeviceXxx o UfxEndpointXxx) vengono esportati da UFX e richiamati dal driver client. Le funzioni di callback (denominate EVT_UFX_Xxx) vengono implementate nel driver client e richiamate da UFX.

UFX chiama in modo asincrono tutte le funzioni di callback del driver client e un callback alla volta per oggetto. Ad esempio, è presente un oggetto dispositivo USB e tre oggetti endpoint. Al massimo quattro funzioni di callback (una per il dispositivo e una per ogni endpoint) possono essere chiamate alla volta. Per ogni metodo di callback, UFX attende fino a quando il driver client chiama UfxDeviceEventComplete per indicare che il driver ha completato la richiesta. L'unico altro metodo di esportazione che UFX rimane in ascolto durante l'attesa di queste esportazioni è UfxDeviceNotifyHardwareFailure. Molte funzioni di callback client sono facoltative. Le funzioni obbligatorie sono le seguenti:

Inizializzazione

  1. Il driver client del controller di funzione avvia il processo di inizializzazione quando Windows Driver Foundation (WDF) richiama l'implementazione del driver client del EVT_WDF_DRIVER_DEVICE_ADD callback. In tale implementazione, il driver client deve chiamare UfxFdoInit e quindi creare l'oggetto dispositivo chiamando WdfDeviceCreate.
  2. Il driver client chiama UfxDeviceCreate per creare l'oggetto dispositivo USB e recuperare l'handle UFXDEVICE.
  3. Il driver client chiama UfxDeviceNotifyHardwareReady per indicare a UFX che ora può richiamare le funzioni di callback del driver client.
  4. UFX esegue attività di inizializzazione come:

Notifica del driver di classe

Per ricevere una notifica dei pacchetti di installazione e dello stato del bus, un driver di classe deve inviare una richiesta di IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS . UFX accoda queste richieste in code di notifica specifiche del driver di classe. Quando riceve una notifica relativa a un evento bus dal driver client, UFX viene visualizzato da ogni coda appropriata e completa la richiesta. Per impedire ai driver di classe di ricevere notifiche mancanti, UFX mantiene una coda fissa di notifiche per il driver di classe.

Eventi di collegamento e scollegamento del dispositivo

UFX presuppone che il dispositivo venga scollegato fino a quando il driver client del controller della funzione chiama UfxDeviceNotifyAttach.

Dopo tale chiamata, UFX imposta lo stato del dispositivo su Powered come definito nella specifica USB. Per notificare al driver client la modifica dello stato, UFX richiama l'implementazione EVT_UFX_DEVICE_USB_STATE_CHANGE del driver client.

UFX invia una notifica al driver del caricatore (Cad.sys) per facilitare la ricarica del dispositivo. UFX notifica anche i driver di classe completando IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION richieste inviate in precedenza dai driver di classe.

Il driver client deve chiamare UfxDeviceNotifyDetach quando il bus viene scollegato. Il client deve chiamare detach una sola volta dopo ogni chiamata a UfxDeviceNotifyAttach. Dopo la chiamata di UfxDeviceNotifyDetach , UFX chiama EVT_UFX_DEVICE_HOST_DISCONNECT (se non si tratta di una modifica dell'interfaccia). UFX procede quindi con tutte le attività di pulizia, ad esempio l'eliminazione di tutte le code di endpoint e l'avvio della coda endpoint predefinita. UFX chiama EVT_UFX_DEVICE_USB_STATE_CHANGE e invia una notifica ai driver di classe completando IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION richieste.

Errore hardware

Se si verifica un errore hardware, è previsto che il driver client chiami UfxDeviceNotifyHardwareFailure. In risposta, UFX elimina lo stack di dispositivi e potrebbe tentare di eseguire il ripristino da questa situazione chiamando il driver client EVT_UFX_DEVICE_CONTROLLER_RESET. Il client deve reimpostare lo stato iniziale del controller. Se si verifica un altro errore hardware, il client deve chiamare nuovamente UfxDeviceNotifyHardwareFailure. Nella seconda chiamata, UFX registrerà lo stato e il controllo dei bug.

Rilevamento delle porte

Il rilevamento delle porte viene eseguito da UFX. Chiama il driver client del controller di funzione EVT_UFX_DEVICE_PORT_DETECT funzione di callback per determinare il tipo di porta a cui è collegato il dispositivo. Il client risponde chiamando UfxDevicePortDetectComplete o UfxDevicePortDetectCompleteEx con uno dei tipi di porta definiti in USBFN_PORT_TYPE.

Se il client non è in grado di determinare il tipo di porta, il client deve segnalare UsbfnUnknownPort. Se la porta è sconosciuta o una porta downstream, UFX chiama la funzione di EVT_UFX_DEVICE_HOST_CONNECT del driver client. UFX ascolta l'autobus per qualche tempo. Se la porta è sconosciuta, ma esiste traffico, ad esempio un pacchetto di installazione, UFX assumerà UsbfnStandardDownstreamPort. In caso contrario, UFX assegna la porta come UsbfnInvalidDedicatedChargingPort. Dopo aver determinato un tipo di porta, UFX notifica Cad.sys e chiama la funzione EVT_UFX_DEVICE_PORT_CHANGE del driver client. Nella funzione il driver client deve modificare lo stato dell'hardware in modo che corrisponda al tipo di porta UFX.

Creazione di endpoint

UFX crea l'endpoint predefinito (endpoint 0) chiamando il EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD del driver client in modo che possa gestire i pacchetti di installazione inviati dall'host. UFX crea altri endpoint chiamando EVT_UFX_DEVICE_ENDPOINT_ADD. UFX crea endpoint solo dopo che il driver client chiama UfxDeviceNotifyHardwareReady. In queste funzioni di callback, il driver client deve chiamare UfxEndpointCreate all'oggetto endpoint e ottenere il relativo handle UFXENDPOINT. UFX imposta l'elemento padre sul pdO del driver di classe associato all'interfaccia a cui appartiene l'endpoint. L'elemento padre dell'endpoint predefinito è l'oggetto dispositivo USB. Un endpoint contiene due oggetti coda del framework: una coda di trasferimento e una coda di comandi, entrambi accessibili solo quando il dispositivo si trova nello stato Configurato (ad eccezione dell'endpoint 0, accessibile dopo le chiamate UFX EVT_UFX_DEVICE_HOST_CONNECT).

Enumerazione del dispositivo

Il driver client non deve consentire le connessioni a un host prima che UFX chiami il EVT_UFX_DEVICE_HOST_CONNECT del driver. L'enumerazione del dispositivo inizia quando il driver client chiama UfxDeviceNotifyReset. Nello stato predefinito , UFX gestisce i pacchetti di installazione standard.

Reset

UFX elimina tutte le code degli endpoint e invia una richiesta di IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE al driver client per aggiornare wMaxPacketSize dell'endpoint 0. UFX avvia la coda dell'endpoint predefinito e imposta lo stato su Predefinito.

Default

UFX chiama la funzione EVT_UFX_DEVICE_USB_STATE_CHANGE del driver client. Notifica anche i driver di classe dello stato. Dopo che UFX riceve il SET_ADDRESS pacchetto di installazione standard, UFX imposta lo stato su Indirizzato.

Affrontato

UFX chiama la funzione EVT_UFX_DEVICE_ADDRESSED del driver client per indicare al client quale indirizzo deve usare. - Se l'indirizzo è 0, UFX imposta nuovamente lo stato su Default e chiama EVT_UFX_DEVICE_USB_STATE_CHANGE e invia una notifica ai driver di classe. Quando si riceve il pacchetto di installazione standard SET_CONFIGURATION, UFX imposta lo stato su Configurato.

Configurato

Se la configurazione selezionata è 0, UFX elimina gli endpoint dell'interfaccia e imposta lo stato su Indirizzato. UFX invia una richiesta di IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE al driver client per aggiornare wMaxPacketSize degli endpoint dell'interfaccia. UFX assicura che tutte le code degli endpoint dell'interfaccia abbiano terminato l'eliminazione e l'avvio delle code degli endpoint dell'interfaccia. Se il tipo di porta non è UsbfnStandardDownstreamPort o UsbfnChargingDownstreamPort, UFX modifica il tipo di porta in UsbfnStandardDownstreamPort e informa Cad.sys; il driver client chiamando EVT_UFX_DEVICE_PORT_CHANGE e EVT_UFX_DEVICE_USB_STATE_CHANGE per aggiornare lo stato; i driver di classe dello stato configurato.

Trasferimenti di controllo standard

UFX può gestire i trasferimenti di controllo sull'endpoint predefinito in qualsiasi momento dopo aver chiamato EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD, in cui il driver client crea l'endpoint predefinito usando. Tutti i trasferimenti di controllo iniziano con un pacchetto di installazione a 8 byte. Per inviare un pacchetto di installazione all'host, il driver client deve chiamare UfxEndpointNotifySetup. I trasferimenti di controllo standard vengono completati da UFX. Se sono presenti dati associati al trasferimento del controllo, UFX legge e scrive nell'endpoint di controllo predefinito in base alle esigenze.

Trasferimenti di controlli non standard

Se UFX non è in grado di gestire un trasferimento di controllo, il trasferimento viene inoltrato al driver di classe appropriato completando una richiesta di IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION . I trasferimenti di controllo possono verificarsi in qualsiasi endpoint definito come endpoint di controllo nel descrittore dell'endpoint. I trasferimenti di controllo sugli endpoint diversi dall'endpoint di controllo predefinito sono sempre trasferimenti di controllo non standard. Se l'endpoint di controllo è l'endpoint di controllo predefinito, UFX invia una notifica ai driver di classe dei pacchetti di installazione contrassegnati come richieste di classe per tale driver di classe. Se l'endpoint di controllo appartiene a un'interfaccia, UFX invia una notifica al driver di classe associato a tale interfaccia. Se necessario, i driver di classe devono leggere e scrivere nell'endpoint di controllo.

Trasferimenti di dati

I trasferimenti di dati vengono avviati dai driver di classe inviando richieste di IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT o IOCTL_INTERNAL_USBFN_TRANSFER_OUT . Dopo aver convalidato ognuna di queste richieste, UFX lo inoltra alla coda dell'endpoint appropriata per essere gestita dal driver client. Si prevede che il driver client esegua una convalida aggiuntiva. Il driver client riceve le richieste di trasferimento nelle code degli endpoint. Il driver client può recuperare il numero di richieste da questa coda necessarie per ottimizzare l'utilizzo del bus. Il driver client deve completare le richieste riuscite con STATUS_SUCCESS. Il driver deve eseguire un tentativo ottimale di annullare le richieste e completare le richieste annullate con STATUS_CANCELLED se annullato. Se vengono passati parametri non validi, il driver client completa la richiesta con STATUS_INVALID_PARAMETER.

Controllare i trasferimenti

I trasferimenti di controllo iniziano con un pacchetto di installazione a 8 byte. Per inviare un pacchetto di installazione all'host, il driver client deve chiamare UfxEndpointNotifySetup. UFX notifica ai driver di classe i trasferimenti di controlli non standard completando le richieste di notifica. Sia i client che UFX usano IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT o IOCTL_INTERNAL_USBFN_TRANSFER_OUT per leggere e scrivere nell'endpoint di controllo predefinito. Tuttavia, un'interfaccia può definire altri endpoint di controllo, che possono essere usati solo dal driver di classe corrispondente. Gli endpoint di controllo possono essere bloccati in risposta a un pacchetto di installazione. I driver di classe inviano la richiesta di IOCTL_INTERNAL_USBFN_SET_PIPE_STATE di bloccare l'endpoint. L'hardware o il driver client dovrebbe riprendere immediatamente il traffico sull'endpoint dopo l'invio dello stallo. Gli endpoint di controllo possono anche inviare e ricevere pacchetti di lunghezza zero (ZLP) senza dati precedenti. Il driver client e UFX possono eseguire questa operazione usando IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_IN e IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT.

Trasferimenti bulk e interrupt

I trasferimenti in blocco garantiscono il recapito dei dati e vengono usati per inviare grandi quantità di dati. I trasferimenti possono essere inviati in un endpoint in blocco usando IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT o IOCTL_INTERNAL_USBFN_TRANSFER_OUT. Gli endpoint in blocco possono essere bloccati in modo analogo agli endpoint di controllo usando IOCTL_INTERNAL_USBFN_SET_PIPE_STATE. Si prevede che il driver client invii un pacchetto STALL in risposta a tutte le richieste host e contenga le richieste IOCTL. A differenza degli endpoint di controllo, un endpoint in blocco rimane bloccato fino a quando lo stato di stallo non viene cancellato in modo esplicito.

I trasferimenti di interruzione dei trasferimenti sono come i trasferimenti in blocco, ma hanno una latenza garantita. I trasferimenti di interrupt hanno la stessa interfaccia dei trasferimenti in blocco, ma non hanno funzionalità di streaming.

Trasferimenti isocroni

Il driver client non deve supportare trasferimenti isocroni in questa versione.

Risparmio energia

Il driver client possiede tutti gli aspetti del risparmio energia. Poiché le funzioni di callback sono asincrone, il driver client dovrebbe tornare a uno stato di alimentazione appropriato e completare la richiesta prima di chiamare la funzione di esportazione completa dell'evento appropriata, ad esempio UfxDeviceEventComplete.

UFX si trova in uno stato Working se lo stato del dispositivo (definito in USBFN_DEVICE_STATE) è UsbfnDeviceStateSuspended e UsbfnDeviceStateAttached e non ha segnalato un tipo di porta. In alternativa, UFX ha segnalato il tipo di porta (definito in USBFN_PORT_TYPE) UsbfnStandardDownstreamPort o UsbfnChargingDownstreamPort.

UFX entra ed esce da uno stato working chiamando EVT_UFX_DEVICE_USB_STATE_CHANGE o implementazioni di EVT_UFX_DEVICE_PORT_CHANGE . La transizione verso o da uno stato Working viene completata quando il driver client chiama UfxDeviceEventComplete.

In uno stato working, UFX può chiamare qualsiasi callback. Anche se non nello stato Working, UFX chiama solo EVT_UFX_DEVICE_USB_STATE_CHANGE per entrare in uno stato di lavoro; EVT_UFX_DEVICE_REMOTE_WAKEUP_SIGNAL per eseguire una riattivazione remota durante la sospensione (se supportato).

Sospensione del dispositivo

La sospensione del dispositivo si verifica quando non è presente traffico sull'autobus per 3 millisecondi. In questo caso, il driver client deve informare UFX quando rileva la sospensione e la ripresa chiamando UfxDeviceNotifySuspend e UfxDeviceNotifyResume. Alla ricezione di tali chiamate, UFX chiama EVT_UFX_DEVICE_USB_STATE_CHANGE e notifica i driver di classe completando IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION richieste. Se la riattivazione remota è supportata dal dispositivo e abilitata dall'host, UFX può chiamare le chiamate EVT_UFX_DEVICE_USB_STATE_CHANGE durante la sospensione per emettere un segnale di riattivazione remota.