Cara mentransfer data ke titik akhir isochronous USB

Topik ini menjelaskan bagaimana driver klien dapat membangun USB Request Block (URB) untuk mentransfer data ke dan dari titik akhir isochronous di perangkat USB.

Perangkat Universal Serial Bus (USB) dapat mendukung titik akhir isochronous untuk mentransfer data yang bergantung pada waktu dengan kecepatan stabil, seperti dengan streaming audio/video. Untuk mentransfer data, driver klien mengeluarkan permintaan untuk membaca atau menulis data ke titik akhir isochronous. Akibatnya, pengontrol host memulai transfer isochronous yang mengirim atau menerima data dengan melakukan polling perangkat secara berkala.

Untuk perangkat berkecepatan tinggi dan kecepatan penuh, polling dilakukan dengan menggunakan paket token (IN/OUT). Ketika titik akhir siap untuk mengirim data, perangkat merespons salah satu paket token IN dengan mengirim data. Untuk menulis ke perangkat, pengontrol host mengirimkan paket token OUT diikuti oleh paket data. Pengontrol atau perangkat host tidak mengirim paket jabat tangan apa pun, dan oleh karena itu, tidak ada pengiriman yang dijamin. Karena pengontrol host tidak mencoba lagi transfer, data mungkin hilang jika terjadi kesalahan.

Untuk transfer isochronous, pengontrol host mencadangkan periode waktu tertentu di bus. Untuk mengelola waktu yang dipesan untuk titik akhir isochronous, waktu dibagi menjadi chuck logis berturut-turut disebut interval bus. Unit interval bus tergantung pada kecepatan bus.

Untuk kecepatan penuh, interval bus adalah bingkai. Panjang bingkai adalah 1 milidetik.

Untuk kecepatan tinggi dan SuperSpeed, interval bus adalah mikroframe. Panjang mikroframe adalah 125 mikrosekon. Delapan mikroframe berturut-turut merupakan satu bingkai berkecepatan tinggi atau SuperSpeed.

Transfer isochronous berbasis paket. Istilah paket isochronous dalam topik ini mengacu pada jumlah data yang ditransfer dalam satu interval bus. Karakteristik titik akhir menentukan ukuran setiap paket diperbaiki dan ditentukan oleh karakteristik titik akhir.

Driver klien memulai transfer isochronous dengan membuat URB untuk permintaan dan mengirimkan URB ke tumpukan driver USB. Permintaan ditangani oleh salah satu driver yang lebih rendah di tumpukan driver USB. Setelah menerima URB, tumpukan driver USB melakukan serangkaian validasi dan menjadwalkan transaksi untuk permintaan tersebut. Untuk kecepatan penuh, paket isochronous yang akan ditransfer di setiap interval bus terkandung dalam satu transaksi pada kawat. Perangkat berkecepatan tinggi tertentu mengizinkan beberapa transaksi dalam interval bus. Dalam hal ini, driver klien dapat mengirim atau menerima lebih banyak data dalam paket isochronous dalam satu permintaan (URB). Perangkat SuperSpeed mendukung beberapa transaksi dan transfer ledakan, memungkinkan lebih banyak byte per interval bus. Untuk informasi selengkapnya tentang transfer ledakan, lihat halaman spesifikasi USB 3.0 9-42.

Sebelum memulai

Sebelum Anda membuat permintaan transfer isochronous, Anda harus memiliki informasi tentang pipa yang dibuka untuk titik akhir isochronous.

Driver klien yang menggunakan rutinitas Windows Driver Model (WDM) memiliki informasi pipa di salah satu struktur USBD_PIPE_INFORMATION array USBD_INTERFACE_LIST_ENTRY . Driver klien memperoleh array tersebut dalam permintaan driver sebelumnya untuk memilih konfigurasi atau antarmuka di perangkat.

Driver klien Windows Driver Framework (WDF) harus mendapatkan referensi ke objek pipa target kerangka kerja dan memanggil WdfUsbTargetPipeGetInformation untuk mendapatkan informasi pipa dalam struktur WDF_USB_PIPE_INFORMATION .

Berdasarkan informasi pipa, tentukan kumpulan informasi ini:

  • Berapa banyak data yang dapat dikirim pengontrol host ke pipa di setiap paket.

    Jumlah data yang dapat dikirim driver klien dalam permintaan tidak boleh melebihi jumlah maksimum byte yang dapat dikirim atau diterima pengontrol host dari titik akhir. Jumlah maksimum byte ditunjukkan oleh anggota MaximumPacketSize dari struktur USBD_PIPE_INFORMATION dan WDF_USB_PIPE_INFORMATION . Tumpukan driver USB menetapkan nilai MaximumPacketSize selama permintaan select-configuration atau select-interface.

    Untuk perangkat berkecepatan penuh, MaximumPacketSize berasal dari 11 bit pertama dari bidang wMaxPacketSize dari deskriptor titik akhir, yang menunjukkan jumlah maksimum byte yang dapat dikirim atau diterima titik akhir dalam transaksi. Untuk perangkat berkecepatan penuh, pengontrol mengirimkan satu transaksi per interval bus.

    Dalam transfer isochronous berkecepatan tinggi, pengontrol host dapat mengirim transaksi tambahan dalam interval bus jika titik akhir mengizinkannya. Jumlah transaksi tambahan diatur oleh perangkat dan ditunjukkan dalam bit 12..11 dari wMaxPacketSize. Angka itu bisa 0, 1, atau 2. Jika 12..11 menunjukkan 0, transaksi tambahan per mikroframe tidak didukung oleh titik akhir. Jika jumlahnya 1, maka pengontrol host dapat mengirim transaksi tambahan (total dua transaksi per mikroframe); 2 menunjukkan dua transaksi tambahan (total tiga transaksi per mikroframe). Nilai MaximumPacketSize yang ditetapkan oleh tumpukan driver USB mencakup jumlah byte yang dapat dikirim dalam transaksi tambahan.

    Untuk transfer isochronous SuperSpeed, nilai USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR tertentu (lihat Usbspec.h) penting. Tumpukan driver USB menggunakan nilai-nilai tersebut untuk menghitung jumlah maksimum byte dalam interval bus.

    • Bidang Isochronous.Mult dari deskriptor pendamping titik akhir. Dalam transfer isochronous SuperSpeed, transaksi tambahan (seperti perangkat berkecepatan tinggi) disebut sebagai transaksi ledakan. Nilai Mult menunjukkan jumlah maksimum transaksi ledakan yang didukung titik akhir. Mungkin ada hingga tiga transaksi burst (diindeks 0 hingga 2) dalam interval layanan.

    • Bidang bMaxBurst dari deskriptor pendamping titik akhir. Nilai ini menunjukkan jumlah potongan wMaxPacketSize yang dapat ada dalam satu transaksi ledakan. Mungkin ada hingga 16 gugus (diindeks 0 hingga 15) dalam transaksi ledakan.

    • wBytesPerInterval menunjukkan jumlah total byte yang dapat dikirim atau diterima host dalam interval bus. Meskipun jumlah maksimum byte per interval bus dapat dihitung sebagai (bMaxBurst+1) * (Mult+1) * wMaxPacketSize, spesifikasi USB 3.0 merekomendasikan penggunaan nilai wBytesPerInterval sebagai gantinya. Nilai wBytesPerInterval harus kurang dari atau sama dengan nilai terhitung tersebut.

      Penting

      Untuk driver klien, nilai yang dijelaskan di sebelumnya hanya untuk informasi. Driver harus selalu menggunakan nilai MaximumPacketSize dari deskriptor titik akhir untuk menentukan tata letak buffer transfer.

  • Seberapa sering titik akhir mengirim atau menerima data?

    Anggota Interval digunakan untuk menentukan seberapa sering titik akhir dapat mengirim atau menerima data. Perangkat menetapkan nilai tersebut dan driver klien tidak dapat mengubahnya. Tumpukan driver USB menggunakan nomor lain untuk menentukan frekuensi memasukkan paket isochronous ke dalam aliran data: periode polling, yang berasal dari nilai Interval .

    Untuk transmisi berkecepatan penuh, nilai Periode interval dan polling selalu 1; tumpukan driver USB mengabaikan nilai lain.

    Tabel berikut ini memperlihatkan Interval dan periode polling terhitung untuk transfer kecepatan tinggi dan SuperSpeed:

    Interval Periode polling (2Interval-1)
    1 1; Data ditransfer setiap interval bus.
    2 2; Data ditransfer setiap interval bus kedua.
    3 4; Data ditransfer setiap interval bus keempat.
    4 8; Data ditransfer setiap interval bus kedelapan.
  • Berapa batasan jumlah paket untuk setiap kecepatan bus.

    Dalam URB, Anda hanya dapat mengirim hingga 255 paket isochronous untuk perangkat berkecepatan penuh; 1024 paket dalam URB untuk perangkat berkecepatan tinggi dan SuperSpeed. Jumlah paket yang Anda kirim dalam URB harus kelipatan dari jumlah paket di setiap bingkai.

    Periode polling Jumlah Paket untuk kecepatan tinggi/SuperSpeed
    1 Kelipatan 8
    2 Kelipatan 4
    3 Kelipatan 2
    4 Apa pun

Pertimbangkan contoh titik akhir berkecepatan penuh dengan wMaxPacketSize adalah 1.023. Untuk contoh ini, aplikasi memasok buffer 25.575 byte. Transfer untuk buffer tersebut memerlukan 25 paket isochronous (25575/1023).

Pertimbangkan contoh titik akhir berkecepatan tinggi dengan karakteristik berikut yang ditunjukkan dalam deskriptor titik akhir.

  • wMaxPacketSize adalah 1.024.
  • Bit 12..11 menunjukkan dua transaksi tambahan.
  • Interval adalah 1.

Setelah driver klien memilih konfigurasi, MaximumPacketSize untuk pipa isochronous menunjukkan 3.072 byte (total transaksi * wMaxPacketSize). Transaksi tambahan memungkinkan driver klien untuk mentransfer 3.072 byte di setiap mikroframe, dan total 24.576 byte dalam satu bingkai. Ilustrasi berikut menunjukkan seberapa sering paket isochronous ditransfer dalam satu mikroframe untuk transmisi berkecepatan tinggi.

Diagram interval transfer isochronous, periode polling, dan paket.

Pertimbangkan contoh titik akhir SuperSpeed dengan karakteristik ini yang ditunjukkan di titik akhir dan deskriptor pendamping titik akhir SuperSpeed:

  • wMaxPacketSize adalah 1.024.
  • bMaxBurst adalah 15.
  • Interval adalah 1.
  • Isochronous.Mult adalah 2.
  • wBytesPerInterval adalah 45000.

Dalam contoh sebelumnya, meskipun jumlah maksimum byte dapat dihitung sebagai wMaxPacketSize * (bMaxBurst +1) * (Mult + 1) menghasilkan 49.152 byte, perangkat membatasi nilai ke nilai wBytesPerInterval yaitu 45.000 byte. Nilai tersebut juga tercermin dalam MaximumPacketSize 45.000. Driver klien hanya boleh menggunakan nilai MaximumPacketSize . Dalam contoh ini, permintaan dapat dibagi menjadi tiga transaksi burst. Dua transaksi ledakan pertama masing-masing berisi 16 gugus wMaxPacketSize. Transaksi ledakan terakhir berisi 12 gugus untuk menahan byte yang tersisa. Gambar ini menunjukkan interval polling dan byte yang ditransfer melalui paket isochronous untuk transmisi SuperSpeed.

Diagram interval transfer isochronous superspeed, periode polling, dan paket.

Untuk membangun permintaan transfer isochronous:

  1. Dapatkan ukuran setiap paket isochronous.
  2. Tentukan jumlah paket isochronous per bingkai.
  3. Hitung jumlah paket isochronous yang diperlukan untuk menahan seluruh buffer transfer.
  4. Alokasikan struktur URB untuk menjelaskan detail transfer.
  5. Tentukan detail setiap paket isochronous, seperti offset paket.

Untuk contoh kode lengkap tentang mengirim permintaan transfer isochronous, USBSAMP.

Contoh dalam topik ini menyederhanakan implementasi USBSAMP dari transfer isochronous. Sampel menghitung total bingkai angka yang diperlukan untuk transfer. Berdasarkan jumlah data yang dapat dikirim dalam bingkai, buffer transfer dibagi menjadi byte berukuran potongan yang lebih kecil.

Prosedur berikut menguraikan langkah-langkah sebelumnya dan menunjukkan perhitungan dan rutinitas yang dapat digunakan driver klien untuk membangun dan mengirim permintaan transfer isochronous untuk titik akhir isochronous berkecepatan tinggi. Nilai yang digunakan dalam prosedur didasarkan pada contoh karakteristik titik akhir yang dijelaskan sebelumnya.

Langkah 1: Dapatkan ukuran paket isochronous

Tentukan ukuran paket isochronous dengan memeriksa nilai MaximumPacketSize pipa.

Untuk transmisi berkecepatan penuh, ukuran paket isochronous adalah jumlah byte yang dapat Anda transfer dalam satu bingkai. Untuk transmisi berkecepatan tinggi dan SuperSpeed, ukuran paket isochronous adalah jumlah total byte yang dapat ditransfer dalam satu mikroframe. Nilai-nilai tersebut ditunjukkan dalam MaximumPacketSize pipa.

Dalam contoh, MaximumPacketSize adalah 1023 byte per bingkai (kecepatan penuh); 3072 byte per mikroframe (kecepatan tinggi); 45.000 byte per mikroframe (SuperSpeed).

Catatan

Nilai MaximumPacketSize menunjukkan ukuran maksimum yang diizinkan dari paket isochronous. Driver klien dapat mengatur ukuran setiap paket isochronous ke nilai apa pun yang kurang dari nilai MaximumPacketSize .

Langkah 2: Tentukan jumlah paket isochronous per bingkai

Untuk transmisi berkecepatan penuh, Anda mentransfer satu paket isochronous di setiap bingkai.

Untuk transmisi berkecepatan tinggi dan SuperSpeed, nilai ini harus berasal dari nilai Interval. Dalam contoh, Interval adalah 1. Oleh karena itu, jumlah paket isochronous harus delapan per bingkai. Untuk nilai Interval lainnya, lihat tabel di bagian Prasyarat.

Langkah 3: Hitung jumlah paket isochronous yang diperlukan untuk menahan seluruh buffer transfer

Hitung jumlah paket isochronous yang diperlukan untuk mentransfer seluruh buffer. Nilai ini dapat dihitung dengan membandingkan panjang buffer transfer dengan ukuran paket isochronous.

Dalam contoh ini, kami mengasumsikan bahwa ukuran setiap paket isochronous adalah MaximumPacketSize dan panjang buffer transfer adalah kelipatan nilai MaximumPacketSize .

Misalnya, untuk transfer kecepatan penuh, buffer yang disediakan sebesar 25.575 byte memerlukan 25 paket isochronous (25575/1023). Untuk transfer berkecepatan tinggi, buffer ukuran 24.576 dibagi menjadi delapan paket isochronous (24576 /3072) untuk transfer. Untuk SuperSpeed, buffer berukuran 360.000 byte cocok dalam delapan paket isochronous (360000/45000).

Driver klien harus memvalidasi persyaratan ini:

  • Jumlah paket isochronous harus kelipatan dari jumlah paket per bingkai.
  • Jumlah maksimum paket isochronous yang diperlukan untuk melakukan transfer tidak boleh melebihi 255 untuk perangkat berkecepatan penuh; 1024 untuk perangkat berkecepatan tinggi atau SuperSpeed.

Langkah 4: Alokasikan struktur URB untuk menjelaskan detail transfer

  1. Alokasikan struktur URB di kumpulan non-halaman.

    Jika driver klien Anda menggunakan rutinitas WDM, driver harus memanggil USBD_IsochUrbAllocate jika Anda memiliki Windows Driver Kit (WDK) untuk Windows 8. Driver klien dapat menggunakan rutinitas untuk menargetkan Windows Vista dan versi sistem operasi Windows yang lebih baru. Jika Anda tidak memiliki WDK untuk Windows 8 atau jika driver klien ditujukan untuk versi sistem operasi yang lebih lama, Anda dapat mengalokasikan struktur pada tumpukan atau di kumpulan non-halaman dengan memanggil ExAllocatePoolWithTag.

    Driver klien WDF dapat memanggil metode WdfUsbTargetDeviceCreateIsochUrb untuk mengalokasikan memori untuk struktur URB .

  2. Anggota UrbIsochronousTransfer dari struktur URB menunjuk ke struktur _URB_ISOCH_TRANSFER yang menjelaskan detail transfer isochronous. Inisialisasi anggota UrbIsochronousTransfer berikut sebagai berikut:

    • Atur anggota UrbIsochronousTransfer.Hdr.Length ke ukuran URB. Untuk mendapatkan ukuran URB, panggil makro GET_ISO_URB_SIZE dan tentukan jumlah paket.

    • Atur anggota UrbIsochronousTransfer.Hdr.Function ke URB_FUNCTION_ISOCH_TRANSFER.

    • Atur anggota UrbIsochronousTransfer.NumberOfPackets ke jumlah paket isochronous.

    • Atur UrbIsochronousTransfer.PipeHandle ke handel buram untuk pipa yang terkait dengan titik akhir. Pastikan bahwa handel pipa adalah handel pipa USBD yang digunakan oleh tumpukan driver Universal Serial Bus (USB).

      Untuk mendapatkan handel pipa USBD, driver klien WDF dapat memanggil metode WdfUsbTargetPipeWdmGetPipeHandle dan menentukan handel WDFUSBPIPE ke objek pipa kerangka kerja. Driver klien WDM harus menggunakan handel yang sama yang diperoleh di anggota PipeHandle dari struktur USBD_PIPE_INFORMATION .

    • Tentukan arah transfer. Atur UrbIsochronousTransfer.TransferFlags ke USBD_TRANSFER_DIRECTION_IN untuk transfer IN isochronous (membaca dari perangkat); USBD_TRANSFER_DIRECTION_OUT untuk transfer OUT isochronous (menulis ke perangkat).

    • Tentukan bendera USBD_START_ISO_TRANSFER_ASAP di UrbIsochronousTransfer. TransferFlags. Bendera menginstruksikan tumpukan driver USB untuk mengirim transfer dalam bingkai yang sesuai berikutnya. Untuk pertama kalinya driver klien mengirim URB isochronous untuk pipa ini, tumpukan driver mengirim paket isochronous dalam URB sesegera mungkin. Tumpukan driver USB melacak bingkai berikutnya yang akan digunakan untuk URL berikutnya pada pipa tersebut. Jika ada penundaan pengiriman URB isochronous berikutnya yang menggunakan bendera USBD_START_ISO_TRANSFER_ASAP, tumpukan driver menganggap beberapa atau semua paket URB tersebut terlambat dan tidak mentransfer paket tersebut.

      Tumpukan driver USB mengatur ulang USBD_START_ISO_TRANSFER_ASAP pelacakan bingkai mulai, jika tumpukan tidak menerima URB isochronous untuk 1024 bingkai setelah menyelesaikan URB sebelumnya untuk pipa tersebut. Alih-alih menentukan bendera USBD_START_ISO_TRANSFER_ASAP, Anda dapat menentukan bingkai mulai. Untuk informasi lebih lanjut, lihat bagian Keterangan.

    • Tentukan buffer transfer dan ukurannya. Anda dapat mengatur penunjuk ke buffer di UrbIsochronousTransfer.TransferBuffer atau MDL yang menjelaskan buffer di UrbIsochronousTransfer.TransferBufferMDL.

      Untuk mengambil MDL untuk buffer transfer, driver klien WDF dapat memanggil WdfRequestRetrieveOutputWdmMdl atau WdfRequestRetrieveInputWdmMdl, tergantung pada arah transfer.

Langkah 5: Tentukan detail setiap paket isochronous dalam transfer

Tumpukan driver USB mengalokasikan struktur URB baru yang cukup besar untuk menyimpan informasi tentang setiap paket isochronous, tetapi bukan data yang terkandung dalam paket. Dalam struktur URB , anggota UrbIsochronousTransfer.IsoPacket adalah array USBD_ISO_PACKET_DESCRIPTOR yang menjelaskan detail setiap paket isochronous dalam transfer. Paket harus berseberangan. Jumlah elemen dalam array harus berupa jumlah paket isochronous yang ditentukan dalam anggota UrbIsochronousTransfer.NumberOfPackets URB .

Untuk transfer berkecepatan tinggi, setiap elemen dalam array berkorelasi dengan satu paket isochronous dalam satu mikroframe. Untuk kecepatan penuh, setiap elemen berkorelasi dengan satu paket isochronous yang ditransfer dalam satu bingkai.

Untuk setiap elemen, tentukan offset byte dari setiap paket isochronous dari awal seluruh buffer transfer untuk permintaan tersebut. Anda dapat menentukan nilai tersebut dengan mengatur UrbIsochronousTransfer.IsoPacket[i]. Mengimbangi anggota. Tumpukan driver USB menggunakan nilai yang ditentukan untuk melacak jumlah data yang akan dikirim atau diterima.

Mengatur Offset untuk Transfer Full-Speed

Misalnya, ini adalah entri array untuk buffer transfer dalam kecepatan penuh. Dalam kecepatan penuh, driver klien memiliki satu bingkai untuk mentransfer satu paket isochronous hingga 1.023 byte. Buffer transfer 25.575 byte dapat menampung 25 paket isochronous, masing-masing panjang 1.023 byte. Total 25 bingkai diperlukan untuk seluruh buffer.

Frame 1 IsoPacket [0].Offset = 0 (start address)
Frame 2 IsoPacket [1].Offset = 1023
Frame 3 IsoPacket [2].Offset = 2046
Frame 4 IsoPacket [3].Offset = 3069
...
Frame 25 IsoPacket [24].Offset = 24552

Total length transferred is 25,575 bytes.

Mengatur Offset untuk Transfer High-Speed

Misalnya, ini adalah entri array untuk buffer transfer dalam kecepatan tinggi. Contohnya mengasumsikan bahwa buffer adalah 24.576 byte, dan driver klien memiliki satu bingkai untuk mentransfer delapan paket isochronous, masing-masing sepanjang 3.072 byte.

Microframe 1 IsoPacket [0].Offset = 0 (start address)
Microframe 2 IsoPacket [1].Offset = 3072
Microframe 3 IsoPacket [2].Offset = 6144
Microframe 4 IsoPacket [3].Offset = 9216
Microframe 5 IsoPacket [4].Offset = 12288
Microframe 6 IsoPacket [5].Offset = 15360
Microframe 7 IsoPacket [6].Offset = 18432
Microframe 8 IsoPacket [7].Offset = 21504

Total length transferred is 24,576 bytes.

Mengatur Offset untuk Transfer SuperSpeed

Misalnya, ini adalah offset array untuk SuperSpeed. Anda dapat mentransfer hingga 45.000 byte dalam satu bingkai. Buffer transfer ukuran 360.000 cocok dalam delapan mikroframe.

Microframe 1 IsoPacket [0].Offset = 0 (start address)
Microframe 2 IsoPacket [1].Offset = 45000
Microframe 3 IsoPacket [2].Offset = 90000
Microframe 4 IsoPacket [3].Offset = 135000
Microframe 5 IsoPacket [4].Offset = 180000
Microframe 6 IsoPacket [5].Offset = 225000
Microframe 7 IsoPacket [6].Offset = 270000
Microframe 8 IsoPacket [7].Offset = 315000

Total length transferred is 360,000 bytes.

UrbIsochronousTransfer.IsoPacket[i]. Anggota panjang tidak menyiratkan panjang setiap paket URB isochronous. IsoPacket[i]. Panjang diperbarui oleh tumpukan driver USB untuk menunjukkan jumlah byte aktual yang diterima dari perangkat untuk transfer IN isochronous. Untuk transfer OUT isochronous, tumpukan driver mengabaikan nilai yang diatur di IsoPacket[i]. Panjangnya.

Tentukan nomor bingkai USB awal untuk transfer

Anggota URB UrbIsochronousTransfer.StartFrame menentukan nomor bingkai USB awal untuk transfer. Selalu ada latensi antara waktu driver klien mengirimkan URB dan waktu tumpukan driver USB memproses URB. Oleh karena itu, driver klien harus selalu menentukan bingkai awal yang lebih baru dari bingkai yang saat ini ketika driver mengirimkan URB. Untuk mengambil nomor bingkai saat ini, driver klien dapat mengirim permintaan URB_FUNCTION_GET_CURRENT_FRAME_NUMBER ke tumpukan driver USB (_URB_GET_CURRENT_FRAME_NUMBER).

Untuk transfer isochronous, perbedaan absolut antara bingkai saat ini dan nilai StartFrame harus kurang dari USBD_ISO_START_FRAME_RANGE. Jika StartFrame tidak berada dalam rentang yang tepat, tumpukan driver USB mengatur anggota Status header URB (lihat _URB_HEADER) untuk USBD_STATUS_BAD_START_FRAME dan membuang seluruh URB.

Nilai StartFrame yang ditentukan dalam URB menunjukkan nomor bingkai tempat paket isochronous pertama URB ditransfer. Nomor bingkai untuk paket berikutnya tergantung pada kecepatan bus dan nilai periode polling titik akhir. Misalnya, untuk transmisi berkecepatan penuh, paket pertama ditransfer di StartFrame; paket kedua ditransfer di StartFrame+1, dan sebagainya. Cara tumpukan driver USB mentransfer paket isochronous, untuk kecepatan penuh, dalam bingkai ditampilkan sebagai berikut:

Frame (StartFrame)   IsoPacket [0]
Frame (StartFrame+1) IsoPacket [1]
Frame (StartFrame+2) IsoPacket [2]
Frame (StartFrame+3) IsoPacket [3]
...

Untuk perangkat berkecepatan tinggi dengan nilai Interval 1, nomor bingkai berubah setiap mikroframe kedelapan. Cara tumpukan driver USB mentransfer paket isochronous, untuk kecepatan tinggi, dalam bingkai ditampilkan sebagai berikut:

Frame (StartFrame) Microframe 1 IsoPacket [0]
...
Frame (StartFrame) Microframe 8 IsoPacket [7]
Frame (StartFrame+1) Microframe 1 IsoPacket [8]
...
Frame (StartFrame+1) Microframe 8 IsoPacket [15]
Frame (StartFrame+2) Microframe 1 IsoPacket [16]
...
Frame (StartFrame+2) Microframe 8 IsoPacket [23]

Ketika tumpukan driver USB memproses URB, driver membuang semua paket isochronous dalam URB yang jumlah bingkainya lebih rendah dari nomor bingkai saat ini. Tumpukan driver mengatur anggota Status deskriptor paket untuk setiap paket yang dibuang ke USBD_STATUS_ISO_NA_LATE_USBPORT, USBD_STATUS_ISO_NOT_ACCESSED_BY_HW, atau USBD_STATUS_ISO_NOT_ACCESSED_LATE. Meskipun beberapa paket dalam URB dibuang, tumpukan driver mencoba untuk mengirimkan hanya paket yang nomor bingkainya lebih tinggi dari nomor bingkai saat ini.

Pemeriksaan untuk anggota StartFrame yang valid sedikit lebih rumit dalam transmisi berkecepatan tinggi karena tumpukan driver USB memuat setiap paket isochronous ke dalam mikroframe berkecepatan tinggi; namun, nilai dalam StartFrame mengacu pada nomor bingkai 1 milidetik (kecepatan penuh), dan bukan mikroframe. Misalnya, jika nilai StartFrame yang dicatat dalam URB adalah satu kurang dari bingkai saat ini, tumpukan driver dapat membuang sebanyak delapan paket. Jumlah pasti paket yang dibuang tergantung pada periode polling yang terkait dengan pipa isochronous.

Contoh Transfer Isochronous

Contoh kode berikut menunjukkan cara membuat URB untuk transfer isochronous untuk kecepatan penuh, kecepatan tinggi, dan transmisi SuperSpeed.

#define MAX_SUPPORTED_PACKETS_FOR_HIGH_OR_SUPER_SPEED 1024
#define MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED 255

NTSTATUS CreateIsochURB  ( PDEVICE_OBJECT         DeviceObject,
                          PUSBD_PIPE_INFORMATION  PipeInfo,
                          ULONG                   TotalLength,
                          PMDL                    RequestMDL,
                          PURB                    Urb)
{
    PDEVICE_EXTENSION        deviceExtension;
    ULONG                    numberOfPackets;
    ULONG                    numberOfFrames;
    ULONG                    isochPacketSize = 0;
    ULONG                    transferSizePerFrame;
    ULONG                    currentFrameNumber;
    size_t                   urbSize;
    ULONG                    index;
    NTSTATUS                 ntStatus;

    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

    isochPacketSize = PipeInfo->MaximumPacketSize;

    // For high-speed transfers
    if (deviceExtension->IsDeviceHighSpeed || deviceExtension->IsDeviceSuperSpeed)
    {
        // Ideally you can pre-calculate numberOfPacketsPerFrame for the Pipe and
        // store it in the pipe context.

        switch (PipeInfo->Interval)
        {
        case 1:
            // Transfer period is every microframe (eight times a frame).
            numberOfPacketsPerFrame = 8;
            break;

        case 2:
            // Transfer period is every 2 microframes (four times a frame).
            numberOfPacketsPerFrame = 4;
            break;

        case 3:
            // Transfer period is every 4 microframes (twice in a frame).
            numperOfPacketsPerFrame = 2;
            break;

        case 4:
        default:
            // Transfer period is every 8 microframes (once in a frame).
            numberOfPacketsPerFrame = 1;
            break;
        }

        //Calculate the number of packets.
        numberOfPackets = TotalLength / isochPacketSize;

        if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_HIGH_OR_SUPER_SPEED)
        {
            // Number of packets cannot be  greater than 1021.
            ntStatus = STATUS_INVALID_PARAMETER;
            goto Exit;
        }

        if (numberOfPackets % numberOfPacketsPerFrame != 0)
        {

            // Number of packets should be a multiple of numberOfPacketsPerFrame
            ntStatus = STATUS_INVALID_PARAMETER;
            goto Exit;
        }

    }
    else if (deviceExtension->IsDeviceFullSpeed)
    {
        //For full-speed transfers
        // Microsoft USB stack only supports bInterval value of 1 for
        // full-speed isochronous endpoints.

        //Calculate the number of packets.
        numberOfPacketsPerFrame = 1;

        numberOfPackets = TotalLength / isochPacketSize;

        if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED)
        {
            // Number of packets cannot be greater than 255.
            ntStatus = STATUS_INVALID_PARAMETER;
            goto Exit;
        }
    }

    // Allocate an isochronous URB for the transfer
    ntStatus = USBD_IsochUrbAllocate (deviceExtension->UsbdHandle,
        numberOfPackets,
        &Urb);

    if (!NT_SUCCESS(ntStatus))
    {
        ntStatus = STATUS_INSUFFICIENT_RESOURCES;
        goto Exit;
    }

    urbSize = GET_ISO_URB_SIZE(numberOfPackets);

    Urb->UrbIsochronousTransfer.Hdr.Length = (USHORT) urbSize;
    Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
    Urb->UrbIsochronousTransfer.PipeHandle = PipeInfo->PipeHandle;

    if (USB_ENDPOINT_DIRECTION_IN(PipeInfo->EndpointAddress))
    {
        Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
    }
    else
    {
        Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT;
    }

    Urb->UrbIsochronousTransfer.TransferBufferLength = TotalLength;
    Urb->UrbIsochronousTransfer.TransferBufferMDL = RequestMDL;
    Urb->UrbIsochronousTransfer.NumberOfPackets = numberOfPackets;
    Urb->UrbIsochronousTransfer.UrbLink = NULL;

    // Set the offsets for every packet for reads/writes

    for (index = 0; index < numberOfPackets; index++)
    {
        Urb->UrbIsochronousTransfer.IsoPacket[index].Offset = index * isochPacketSize;
    }

    // Length is a return value for isochronous IN transfers.
    // Length is ignored by the USB driver stack for isochronous OUT transfers.

    Urb->UrbIsochronousTransfer.IsoPacket[index].Length = 0;
    Urb->UrbIsochronousTransfer.IsoPacket[index].Status = 0;

    // Set the USBD_START_ISO_TRANSFER_ASAP. The USB driver stack will calculate the start frame.
    // StartFrame value set by the client driver is ignored.
    Urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;

Exit:

    return ntStatus;
}