Opzioni di talk isochronous per dispositivi IEEE 1394
Esistono tre modi per organizzare i dati di output nelle operazioni di talk isochronous: i pacchetti senza intestazioni, pacchetti di dati di dimensioni fisse con intestazioni e pacchetti di dati di dimensioni variabili con intestazioni e intestazioni.
Pacchetti senza intestazioni
Per impostazione predefinita, il controller host invia i dati nei buffer collegati, indicati dal membro Mdl della struttura ISOCH_DESCRIPTOR , nell'ordine in cui sono stati collegati i buffer. Nel caso predefinito, il controller host suddivide automaticamente il buffer in pacchetti di dimensioni non maggiori di quello specificato nel membro nMaxBytesPerFrame della struttura ISOCH_DESCRIPTOR del buffer.
Ad esempio, il driver per un dispositivo che prevede di ricevere i dati in 512 pacchetti di byte includerà quanto segue nella dichiarazione dell'ISOCH_DESCRIPTOR del buffer:
/* elsewhere, the buffer has declared: */
/* ISOCH_DESCRIPTOR isoch_descriptor; */
isoch_descriptor->nMaxBytesPerFrame = 512;
Pacchetti di dati di dimensioni fisse con intestazioni
Alcuni dispositivi richiedono che alcune informazioni sull'intestazione vengano prependate a ogni pacchetto ricevuto dal dispositivo. Queste informazioni sull'intestazione verranno inserite prima dei dati, ma dopo l'intestazione del pacchetto isochronous standard IEEE 1394. In questa istanza, i driver possono assemblare un buffer di intestazioni e un buffer di dati e avere automaticamente il controller host prependò un'intestazione ai pacchetti di dati inviati al dispositivo. Il driver indica che un buffer contiene un elenco di intestazioni specificando il flag di DESCRIPTOR_HEADER_SCATTER_GATHER nella struttura ISOCH_DESCRIPTOR del buffer. Esistono due tipi di intestazioni che possono essere prependate a un pacchetto di dati: dimensioni fisse e dimensioni variabili.
Con intestazioni di dimensioni fisse, il driver specifica le dimensioni dell'intestazione nel membro nMaxBytesPerFrame della struttura ISOCH_DESCRIPTOR. Il controller host considera questo buffer e il buffer successivo come coppia: un buffer di intestazione e un buffer di dati. Quando assembla i pacchetti di dati, accetta un frame dal buffer di intestazione e un frame dal buffer di dati e li associa per formare il pacchetto successivo inviato al dispositivo.
Si supponga, ad esempio, che il dispositivo si aspetta che ogni buffer di dati di 512 byte venga preceduto da un'intestazione di 8 byte. Il driver potrebbe dichiarare una coppia di strutture ISOCH_DESCRIPTOR come segue:
/* elsewhere, the buffer has declared: */
/* ISOCH_DESCRIPTOR isoch_descriptor_1, isoch_descriptor_2; */
/* #define NUM_HEADERS to be the number of headers included in */
/* the first buffer */
isoch_descriptor_1->fulFlags = DESCRIPTOR_HEADER_SCATTER_GATHER;
isoch_descriptor_1->ulLength = 8 * NUM_HEADERS;
isoch_descriptor_1->nMaxBytesPerFrame = 8;
.
.
.
isoch_descriptor_2->ulLength = 512 * NUM_HEADERS;
isoch_descriptor_2->nMaxBytesPerFrame = 512;
Non tutti i controller host supportano il flag di DESCRIPTOR_HEADER_SCATTER_GATHER. Per determinare se il controller host lo supporta, eseguire una query sul driver del bus con la richiesta di REQUEST_GET_LOCAL_HOST_INFO , con nLevel = GET_HOST_CAPABILITIES. Il driver del bus imposta il flag HOST_INFO_SUPPORTS_ISO_HDR_INSERTION del membro HostCapabilities della struttura GET_LOCAL_HOST_INFO2 restituita.
Pacchetti di dati di dimensioni variabili con intestazioni
Questo caso è simile al caso del pacchetto di dimensioni fisse. Come nel caso predefinito, il driver deve impostare il flag di DESCRIPTOR_HEADER_SCATTER_GATHER nella struttura di ISOCH_DESCRIPTOR del buffer di intestazione come indicato di seguito:
isoch_descriptor_1->fulFlags = DESCRIPTOR_HEADER_SCATTER_GATHER;
Tuttavia, per il caso di dimensione variabile, il driver deve anche impostare il flag di RESOURCE_VARIABLE_ISOCH_PAYLOAD nella classe u.IsochAllocateResources.fulFlags del membro IRB quando alloca le risorse con una richiesta di REQUEST_ISOCH_ALLOCATE_RESOURCES .
Inoltre, nel caso di pacchetti di dati di dimensioni variabili, il driver deve assemblare un buffer di intestazioni come nel caso di dimensioni fisse. Tuttavia, con pacchetti di dimensioni variabili, a differenza dei pacchetti di dimensioni fisse, il driver deve registrare le dimensioni di ogni pacchetto in un elemento di intestazione di dispersione/raccolta che prepende a ogni intestazione.
Gli elementi di intestazione sono definiti dalla struttura seguente trovata in 1394.h:
typedef struct _IEEE1394_SCATTER_GATHER_HEADER {
USHORT HeaderLength;
USHORT DataLength;
UCHAR HeaderData;
} IEEE1394_SCATTER_GATHER_HEADER, *PIEEE1394_SCATTER_GATHER_HEADER;
L'elemento intestazione indica sia la lunghezza dell'intestazione che la lunghezza dei dati. Pertanto, con pacchetti di dati di dimensioni variabili, il membro nMaxSizeBytesPerFrame del descrittore di dati non indica più le dimensioni di un singolo pacchetto di dati. Ogni pacchetto di dati può avere dimensioni diverse indicate nell'elemento di intestazione corrispondente. Il membro nMaxSizeBytesPerFrame del descrittore di intestazione è definito come indicato di seguito.
IsochDescriptor->nMaxBytesPerFrame = MAX_HEADER_DATA_SIZE+FIELD_OFFSET(HeaderElement,HeaderData)
dove MAX_HEADER_DATA_SIZE indica la dimensione dell'intestazione da prependare a ogni pacchetto di dati e FIELD_OFFSET(HeaderElement,HeaderData) indica la lunghezza dell'elemento di intestazione inserito immediatamente prima di ogni intestazione.
Si dovrebbe essere consapevoli di una sottilezza per quanto riguarda la definizione di nMaxBytesPerFrame ogni volta che il driver trasmette pacchetti di dimensioni variabili in "modalità di dialogo". Esistono due casi in cui un driver deve definire nMaxBytesPerFrame e, in entrambi i casi, il driver del controller host interpreta il valore assegnato a nMaxBytesPerFrame come dimensione minima del frame, anziché un valore massimo, se il driver trasmette fotogrammi di dimensione variabile.
Durante una richiesta di REQUEST_ISOCH_ALLOCATE_RESOURCES, il driver deve indicare le dimensioni del frame nel membro U.IsochAllocateResources.nMaxBytesPerFrame di IRB.
Durante una richiesta di REQUEST_ISOCH_ATTACH_BUFFERS, il driver deve indicare le dimensioni del frame nel membro nMaxBytesPerFrame di ISOCH_DESCRIPTOR.
Il frame più piccolo, più fotogrammi il driver del controller host può adattarsi al buffer di trasmissione. Poiché ogni frame richiede risorse di sistema, ad esempio timestamp e informazioni sullo stato, i frame più piccoli usano le risorse di sistema più rapidamente. Il driver del controller host calcola il numero di fotogrammi che si adattano al buffer e al numero di risorse necessarie per tali frame, in base al valore in nMaxBytesPerFrame. Se sono presenti fotogrammi inferiori alle dimensioni indicate in nMaxBytesPerFrame, il numero di fotogrammi che richiedono risorse sarà maggiore del valore calcolato dal driver del controller host e potrebbe causare un errore.
Queste considerazioni non si applicano quando il driver riceve i dati, solo quando il driver trasmette fotogrammi di dimensioni variabili in modalità "talk". I driver specificano il tipo di trasmissione dati associata a un canale specifico quando si ottiene un handle di risorse per il canale con una richiesta di REQUEST_ISOCH_ALLOCATE_RESOURCES . Il driver imposta il flag di RESOURCE_VARIABLE_ISOCH_PAYLOAD in u.IsochAllocateResources.fulFlags durante questa richiesta per indicare che trasmetterà fotogrammi di dimensioni variabili. Il driver imposta il flag di RESOURCE_USED_IN_TALKING in u.IsochAllocateResources.fulFlags per indicare che userà il canale per trasmettere anziché ricevere dati. Solo quando il driver imposta entrambi questi flag durante la richiesta di allocazione delle risorse, il driver del controller host interpreterà nMaxBytesPerFrame come minimo anziché un valore massimo.
Si noti che il membro u.IsochAllocateResources.nMaxBufferSize di IRB è sempre un massimo.
I driver possono ora trasmettere pacchetti di dati solo intestazione impostando semplicemente il membro DataLength di un elemento di intestazione su zero:
HeaderElement->DataLength = 0
La lunghezza totale del buffer descrittore dell'intestazione è indicata nel modo consueto tramite il membro ulLength del descrittore. Deve essere un numero intero multiplo del numero di elementi di dispersione/raccolta dell'intestazione:
IsochDescriptor->ulLength = IsochDescriptor->nMaxBytesPerFrame * NUMBER_OF_PACKETS;
dove NUMBER_OF_PACKETS è il numero di pacchetti da trasmettere (inclusi pacchetti di sola intestazione).
Il terzo membro della struttura dell'elemento intestazione HeaderData è semplicemente un segnaposto che indica dove iniziano i dati dell'intestazione. Il diagramma seguente illustra un esempio di buffer assemblato di intestazioni CIP a 8 byte.
Tutte le intestazioni in un descrittore specificato devono essere della stessa lunghezza. Ciò consente al driver di porta OHCI (ohci1394.sys) di analizzare il descrittore di intestazione come una matrice di elementi di dimensioni fisse. I pacchetti di dati possono variare in dimensioni, ma devono essere contigui, senza "fori".
I dati in intestazione e descrittori di dati devono essere allineati alla pagina. Non esiste alcuna restrizione sulle dimensioni dei pacchetti di dati, ma non sono consentiti limiti di pagina di intestazione o pacchetti di dati. I driver devono allineare correttamente i buffer del descrittore prima di configurare MDL per il buffer.
Se, ad esempio, il driver assembla un descrittore di intestazione con intestazioni da 12 byte e elementi intestazioni a 4 byte, ogni pacchetto di dati avrà 16 byte di dati prependati. Poiché 16 byte si adatta a una pagina di 4.096 byte esattamente 256 volte, nessuno dei dati prependati si allontana mai da un limite di pagina.
Se, d'altra parte, il driver assembla un descrittore di intestazione con intestazioni a 8 byte e elementi di intestazione a 4 byte, ogni pacchetto di dati avrà 12 byte di dati prependati. Poiché una pagina di 4.096 byte non è un numero intero multiplo di 12, il descrittore di intestazione deve essere inferiore a 4.096 byte per impedire che un'intestazione straddling un limite di pagina. Tuttavia, le dimensioni del buffer descrittore di intestazione possono essere estese fino a due pagine modificando l'indirizzo di base del buffer, come illustrato nel pseudocode che segue.
// First find the number of headers (together with header elements)
// that will fit in a page. Use a floor function that rounds down to
// the nearest integer
PrependData = sizeof(header) + 8; // First two fields of header element take up 8 bytes
NumHeaders =floor(PAGE_SIZE/PrependData);
// By forcing the buffer address defined in the MDL to begin at the appropriate offset,
// the driver can guarantee that the last header in the buffer will be aligned on a page
// boundary. That way, DMA can continue across at least one page boundary.
r = PAGE_SIZE - (NumHeaders*12).
// BufferAddress = the page-aligned address returned by a memory allocation routine
// Adjust buffer starting address
BufferAddress += r;
isochDescriptor->mdl = IoAllocateMdl(BufferAddress, ... and so on.)