Cara mengirim transfer kontrol USB

Artikel ini menjelaskan struktur transfer kontrol dan bagaimana driver klien harus mengirim permintaan kontrol ke perangkat.

Tentang titik akhir default

Semua perangkat USB harus mendukung setidaknya satu titik akhir yang disebut titik akhir default. Setiap transfer yang menargetkan titik akhir default disebut transfer kontrol. Tujuan transfer kontrol adalah untuk memungkinkan host mendapatkan informasi perangkat, mengonfigurasi perangkat, atau melakukan operasi kontrol yang unik untuk perangkat.

Mari kita mulai dengan mempelajari karakteristik titik akhir default ini.

  • Alamat titik akhir default adalah 0.
  • Titik akhir default bersifat dua arah, yaitu host dapat mengirim data ke titik akhir dan menerima data darinya dalam satu transfer.
  • Titik akhir default tersedia di tingkat perangkat dan tidak didefinisikan dalam antarmuka perangkat apa pun.
  • Titik akhir default aktif segera setelah koneksi dibuat antara host dan perangkat. Ini aktif bahkan sebelum konfigurasi dipilih.
  • Ukuran paket maksimum titik akhir default tergantung pada kecepatan bus perangkat. Kecepatan rendah, 8 byte; kecepatan penuh dan tinggi, 64 byte; SuperSpeed, 512 byte.

Tata letak transfer kontrol

Karena transfer kontrol adalah transfer prioritas tinggi, jumlah bandwidth tertentu dicadangkan di bus oleh host. Untuk perangkat berkecepatan rendah dan penuh, 10% dari bandwidth; 20% untuk perangkat transfer tinggi dan SuperSpeed. Sekarang, mari kita lihat tata letak transfer kontrol.

Diagram transfer kontrol USB.

Transfer kontrol dibagi menjadi tiga transaksi: transaksi penyiapan, transaksi data, dan transaksi status. Setiap transaksi berisi tiga jenis paket: paket token, paket data, dan paket jabat tangan.

Bidang tertentu umum untuk semua paket. Bidang-bidang ini adalah:

  • Bidang sinkronisasi yang menunjukkan awal paket.
  • Pengidentifikasi paket (PID) yang menunjukkan jenis paket, arah transaksi, dan dalam kasus paket jabat tangan, itu menunjukkan keberhasilan atau kegagalan transaksi.
  • Bidang EOP menunjukkan akhir paket.

Bidang lain bergantung pada jenis paket.

Paket token

Setiap transaksi penyiapan dimulai dengan paket token. Berikut adalah struktur paket. Host selalu mengirim paket token.

Diagram tata letak paket token.

Nilai PID menunjukkan jenis paket token. Berikut adalah nilai yang mungkin:

  • PENYIAPAN: Menunjukkan awal transaksi penyiapan dalam transfer kontrol.
  • IN: Menunjukkan bahwa host meminta data dari perangkat (kasus baca).
  • OUT: Menunjukkan bahwa host mengirim data ke perangkat (tulis kasus).
  • SOF: Menunjukkan awal bingkai. Jenis paket token ini berisi nomor bingkai 11-bit. Host mengirimkan paket SOF. Frekuensi pengiriman paket ini tergantung pada kecepatan bus. Untuk kecepatan penuh, host mengirimkan paket setiap 1millisecond; setiap 125 mikro detik pada bus berkecepatan tinggi.

Paket data

Segera setelah paket token adalah paket data yang berisi payload. Jumlah byte yang dapat dimuat setiap paket data tergantung pada ukuran paket maksimum titik akhir default. Paket data dapat dikirim oleh host atau perangkat, tergantung pada arah transfer.

Diagram tata letak paket data.

Paket jabat tangan

Segera setelah paket data adalah paket jabat tangan. PID paket menunjukkan apakah paket diterima oleh host atau perangkat atau tidak. Paket jabat tangan dapat dikirim oleh host atau perangkat, tergantung pada arah transfer.

Diagram tata letak paket jabat tangan.

Anda dapat melihat struktur transaksi dan paket dengan menggunakan penganalisis USB apa pun, seperti Beagle, Ellisys, penganalisis protokol USB LeCroy. Perangkat penganalisis menunjukkan bagaimana data dikirim atau diterima dari perangkat USB melalui kabel. Dalam contoh ini, mari kita periksa beberapa jejak yang ditangkap oleh penganalisis USB LeCroy. Contoh ini hanya untuk informasi. Ini bukan dukungan oleh Microsoft.

Menyiapkan transaksi

Host selalu memulai transfer kontrol. Ini melakukannya dengan mengirim transaksi penyiapan. Transaksi ini berisi paket token yang disebut token penyiapan diikuti dengan paket data 8-byte. Cuplikan layar ini menunjukkan contoh transaksi penyiapan.

Cuplikan layar jejak transaksi penyiapan.

Pada jejak sebelumnya, host memulai (ditunjukkan oleh H↓) transfer kontrol dengan mengirim paket token penyiapan #434. Perhatikan bahwa PID menentukan PENYIAPAN yang menunjukkan token penyiapan. PID diikuti oleh alamat perangkat dan alamat titik akhir. Untuk transfer kontrol, alamat titik akhir tersebut selalu 0.

Selanjutnya, host mengirimkan paket data #435. PID adalah DATA0 dan nilai tersebut digunakan untuk pengurutan paket (yang akan dibahas). PID diikuti oleh 8 byte yang berisi informasi utama tentang permintaan ini. 8 byte tersebut menunjukkan jenis permintaan dan ukuran buffer tempat perangkat akan menulis responsnya.

Semua byte diterima dalam urutan terbalik. Seperti yang dijelaskan di bagian 9.3, kita melihat bidang dan nilai ini:

Bidang Ukuran Nilai Deskripsi
bmRequestType (Lihat 9.3.1 bmRequestType) 1 0x80 Arah transfer data berasal dari perangkat ke host (D7 adalah 1)

Permintaan adalah permintaan standar (D6... D5 adalah 0)

Penerima permintaan adalah PERANGKAT (D4 adalah 0)
bRequest (Lihat bagian 9.3.2 dan Tabel 9-4) 1 0x06 Jenis permintaan GET_DESCRIPTOR.
wValue (Lihat Tabel 9-5) 2 0x0100 Nilai permintaan menunjukkan bahwa jenis deskriptor adalah DEVICE.
wIndex (Lihat bagian 9.3.4) 2 0x0000 Arahnya adalah dari host ke perangkat (D7 adalah 1)

Nomor titik akhir adalah 0.
wLength (Lihat bagian 9.3.5) 2 0x0012 Permintaannya adalah mengambil 18 byte.

Dengan demikian, kita dapat menyimpulkan bahwa dalam transfer kontrol ini (baca), host mengirim permintaan untuk mengambil deskriptor perangkat dan menentukan 18 byte sebagai panjang transfer untuk menahan deskriptor tersebut. Cara perangkat mengirim 18 byte tersebut tergantung pada berapa banyak data yang dapat dikirim titik akhir default dalam satu transaksi. Informasi tersebut disertakan dalam deskriptor perangkat yang dikembalikan oleh perangkat dalam transaksi data.

Sebagai tanggapan, perangkat mengirim paket jabat tangan (#436 yang ditunjukkan oleh D↓). Perhatikan bahwa nilai PID adalah ACK (paket ACK). Ini menunjukkan bahwa perangkat mengakui transaksi.

Transaksi data

Sekarang, mari kita lihat apa yang dikembalikan perangkat sebagai respons terhadap permintaan. Data aktual ditransfer dalam transaksi data.

Berikut adalah jejak untuk transaksi data.

Cuplikan layar yang memperlihatkan jejak contoh transaksi data.

Setelah menerima paket ACK, host memulai transaksi data. Untuk memulai transaksi, ia mengirim paket token (#450) dengan arah sebagai IN (disebut token IN).

Sebagai tanggapan, perangkat mengirim paket data (#451) yang mengikuti token IN. Paket data ini berisi pendeskripsi perangkat yang sebenarnya. Byte pertama menunjukkan panjang deskriptor perangkat, 18 byte (0x12). Byte terakhir dalam paket data ini menunjukkan ukuran paket maksimum yang didukung oleh titik akhir default. Dalam hal ini, kita melihat bahwa perangkat dapat mengirim 8 byte pada satu waktu melalui titik akhir defaultnya.

Catatan

Ukuran paket maksimum titik akhir default tergantung pada kecepatan perangkat. Titik akhir default perangkat berkecepatan tinggi adalah 64 byte; perangkat berkecepatan rendah adalah 8 byte.

Host mengakui transaksi data dengan mengirim paket ACK (#452) ke perangkat.

Mari kita hitung jumlah data yang dikembalikan. Di bidang wLength paket data (#435) dalam transaksi penyiapan, host meminta 18 byte. Dalam transaksi data, kita melihat bahwa hanya 8 byte pertama dari deskriptor perangkat yang diterima dari perangkat. Jadi, bagaimana host menerima informasi yang disimpan di sisa 10 byte? Perangkat melakukannya dalam dua transaksi: 8 byte dan kemudian terakhir 2 byte.

Sekarang setelah host mengetahui ukuran paket maksimum titik akhir default, host memulai transaksi data baru dan meminta bagian berikutnya berdasarkan ukuran paket.

Berikut adalah transaksi data berikutnya:

Cuplikan layar yang memperlihatkan jejak transaksi data baru.

Host memulai transaksi data sebelumnya dengan mengirim token IN (#463) dan meminta 8 byte berikutnya dari perangkat. Perangkat merespons dengan paket data (#464) yang berisi 8 byte deskriptor perangkat berikutnya.

Setelah menerima 8 byte, host mengirimkan paket ACK (#465) ke perangkat.

Selanjutnya, host meminta 2 byte terakhir dalam transaksi data lain sebagai berikut:

Cuplikan layar yang memperlihatkan jejak contoh transaksi data baru di mana host meminta 2 byte terakhir.

Oleh karena itu, kami melihat bahwa untuk mentransfer 18 byte dari perangkat ke host, host melacak jumlah byte yang ditransfer dan memulai tiga transaksi data (8+8+2).

Catatan

Perhatikan PID paket data dalam transaksi data 19, 23, 26. PID bergantian antara DATA0 dan DATA1. Urutan ini disebut pengalih data. Dalam kasus di mana ada beberapa transaksi data, pengalih data digunakan untuk memverifikasi urutan paket. Metode ini memastikan bahwa paket data tidak diduplikasi atau hilang.

Dengan memetakan paket data konsolidasi ke struktur deskriptor perangkat (Lihat Tabel 9-8), kita melihat bidang dan nilai ini:

Bidang Ukuran Nilai Deskripsi
bLength 1 0x12 Panjang deskriptor perangkat, yaitu 18 byte.
bDescriptorType 1 0x01 Jenis deskriptor adalah perangkat.
bcdUSB 2 0x0100 Nomor versi spesifikasi adalah 1.00.
bDeviceClass 1 0x00 Kelas perangkat adalah 0. Setiap antarmuka dalam konfigurasi memiliki informasi kelas.
bDeviceSubClass 1 0x00 Subkelas adalah 0 karena kelas perangkat adalah 0.
bProtocol 1 0x00 Protokol adalah 0. Perangkat ini tidak menggunakan protokol khusus kelas apa pun.
bMaxPacketSize0 1 0x08 Ukuran paket maksimum titik akhir adalah 8 byte.
idVendor 2 0x0562 Telex Communications.
idProduct 2 0x0002 Mikrofon USB.
bcdDevice 2 0x0100 Menunjukkan nomor rilis perangkat.
iManufacturer 1 0x01 String produsen.
iProduct 1 0x02 String produk.
iSerialNumber 1 0x03 Nomor seri.
bNumConfigurations 1 0x01 Jumlah konfigurasi.

Dengan memeriksa nilai-nilai tersebut, kami memiliki beberapa informasi awal tentang perangkat. Perangkat ini adalah mikrofon USB berkecepatan rendah. Ukuran paket maksimum titik akhir default adalah 8 byte. Perangkat mendukung satu konfigurasi.

Transaksi status

Terakhir, host menyelesaikan transfer kontrol dengan memulai transaksi terakhir: transaksi status.

Cuplikan layar jejak contoh transaksi data.

Host memulai transaksi dengan paket token OUT (#481). Tujuan dari paket ini adalah untuk memverifikasi bahwa perangkat mengirim semua data yang diminta. Tidak ada paket data yang dikirim dalam transaksi status ini. Perangkat merespons dengan paket ACK. Jika terjadi kesalahan, PID bisa saja NAK atau STALL.

Model driver

Prasyarat

Sebelum driver klien dapat menghitung pipa, pastikan bahwa persyaratan ini terpenuhi:

  • Driver klien harus telah membuat objek perangkat target USB kerangka kerja.

    Jika Anda menggunakan templat USB yang disediakan dengan Microsoft Visual Studio Professional 2012, kode templat melakukan tugas tersebut. Kode templat mendapatkan handel ke objek perangkat target dan disimpan dalam konteks perangkat.

Driver klien KMDF

Driver klien KMDF harus mendapatkan handel WDFUSBDEVICE dengan memanggil metode WdfUsbTargetDeviceCreateWithParameters . Untuk informasi selengkapnya, lihat "Kode sumber perangkat" dalam Memahami struktur kode driver klien USB (KMDF).

Driver klien UMDF

Driver klien UMDF harus mendapatkan penunjuk IWDFUsbTargetDevice dengan mengkueri objek perangkat target kerangka kerja. Untuk informasi selengkapnya, lihat "Implementasi IPnpCallbackHardware dan tugas khusus USB" dalam Memahami struktur kode driver klien USB (UMDF).

Aspek terpenting untuk transfer kontrol adalah memformat token penyiapan dengan tepat. Sebelum mengirim permintaan, kumpulkan kumpulan informasi ini:

  • Arah permintaan: host ke perangkat atau perangkat yang akan dihosting.
  • Penerima permintaan: perangkat, antarmuka, titik akhir, atau lainnya.
  • Kategori permintaan: standar, kelas, atau vendor.
  • Jenis permintaan, seperti permintaan GET_DESCRIPTPOR. Untuk informasi selengkapnya, lihat bagian 9.5 dalam spesifikasi USB.
  • nilai wValue dan wIndex . Nilai-nilai tersebut bergantung pada jenis permintaan.

Anda dapat memperoleh semua informasi tersebut dari spesifikasi USB resmi.

Jika Anda menulis driver UMDF, dapatkan file header, Usb_hw.h dari Driver Sampel UMDF untuk OSR USB Fx2 Learning Kit. File header ini berisi makro dan struktur yang berguna untuk memformat paket penyetelan untuk transfer kontrol.

Semua driver UMDF harus berkomunikasi dengan driver mode kernel untuk mengirim dan menerima data dari perangkat. Untuk driver USB UMDF, driver mode kernel selalu merupakan driver WinUSB (Winusb.sys) yang disediakan Microsoft.

Setiap kali driver UMDF membuat permintaan untuk tumpukan driver USB, manajer I/O Windows mengirimkan permintaan ke WinUSB. Setelah menerima permintaan, WinUSB memproses permintaan atau meneruskannya ke tumpukan driver USB.

Metode yang ditentukan Microsoft untuk mengirim permintaan transfer kontrol

Driver klien USB pada host memulai sebagian besar permintaan kontrol untuk mendapatkan informasi tentang perangkat, mengonfigurasi perangkat, atau mengirim perintah kontrol vendor. Semua permintaan tersebut dapat dikategorikan ke dalam:

  • Permintaan standar ditentukan dalam spesifikasi USB. Tujuan pengiriman permintaan standar adalah untuk mendapatkan informasi tentang perangkat, konfigurasi, antarmuka, dan titik akhirnya. Penerima setiap permintaan tergantung pada jenis permintaan. Penerima dapat berupa perangkat, antarmuka, atau titik akhir.

    Catatan

    Target transfer kontrol apa pun selalu menjadi titik akhir default. Penerima adalah entitas perangkat yang informasinya (deskriptor, status, dan sebagainya) yang diminati host.

    Permintaan dapat diklasifikasikan lebih lanjut ke dalam: permintaan konfigurasi, permintaan fitur, dan permintaan status.

    • Permintaan konfigurasi dikirim untuk mendapatkan informasi dari perangkat sehingga host dapat mengonfigurasinya, seperti permintaan GET_DESCRIPTOR. Permintaan ini juga dapat berupa permintaan tulis yang dikirim oleh host untuk mengatur konfigurasi tertentu atau pengaturan alternatif di perangkat.
    • Permintaan fitur dikirim oleh driver klien untuk mengaktifkan atau menonaktifkan pengaturan perangkat Boolean tertentu yang didukung oleh perangkat, antarmuka, atau titik akhir.
    • Permintaan status memungkinkan host mendapatkan atau mengatur bit status yang ditentukan USB dari perangkat, titik akhir, atau antarmuka.

    Untuk informasi selengkapnya, lihat Bagian 9.4 dalam spesifikasi USB, versi 2.0. Jenis permintaan standar ditentukan file header, Usbspec.h.

  • Permintaan kelas ditentukan oleh spesifikasi kelas perangkat tertentu.

  • Permintaan vendor disediakan oleh vendor dan bergantung pada permintaan yang didukung oleh perangkat.

Tumpukan USB yang disediakan Microsoft menangani semua komunikasi protokol dengan perangkat seperti yang ditunjukkan pada jejak sebelumnya. Driver mengekspos antarmuka driver perangkat (DDIs) yang memungkinkan driver klien untuk mengirim transfer kontrol dalam banyak cara. Jika driver klien Anda adalah driver Windows Driver Foundation (WDF), driver ini dapat memanggil rutinitas secara langsung untuk mengirim jenis permintaan kontrol umum. WDF mendukung transfer kontrol secara intrinsik untuk KMDF dan UMDF.

Jenis permintaan kontrol tertentu tidak diekspos melalui WDF. Untuk permintaan tersebut, driver klien dapat menggunakan model WDF-hybrid. Model ini memungkinkan driver klien untuk membangun dan memformat permintaan gaya URB WDM dan kemudian mengirim permintaan tersebut dengan menggunakan objek kerangka kerja WDF. Model hibrid hanya berlaku untuk driver mode kernel.

Untuk driver UMDF:

Gunakan makro dan struktur pembantu yang ditentukan dalam usb_hw.h. Header ini disertakan dengan Contoh Driver UMDF untuk OSR USB Fx2 Learning Kit.

Gunakan tabel ini untuk menentukan cara terbaik untuk mengirim permintaan kontrol ke tumpukan driver USB. Jika Anda tidak dapat melihat tabel ini, lihat tabel di artikel ini.

Jika Anda ingin mengirim permintaan kontrol ke... Untuk driver KMDF... Untuk driver UMDF... Untuk driver WDM, bangun struktur URB (rutinitas Helper)
CLEAR_FEATURE: Nonaktifkan pengaturan fitur tertentu di perangkat, konfigurasi, antarmuka, dan titik akhirnya. Lihat bagian 9.4.1 dalam spesifikasi USB.
  1. Mendeklarasikan paket penyiapan. Lihat struktur WDF_USB_CONTROL_SETUP_PACKET .
  2. Inisialisasi paket penyiapan dengan memanggil WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE.
  3. Tentukan nilai penerima yang ditentukan dalam WDF_USB_BMREQUEST_RECIPIENT.
  4. Tentukan pemilih fitur (wValue). Lihat konstanta USB_FEATURE_XXX di Usbspec.h. Lihat juga Tabel 9-6 dalam spesifikasi USB.
  5. Atur SetFeature ke FALSE.
  6. Kirim permintaan dengan memanggil WdfUsbTargetDeviceSendControlTransferSynchronously atau WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Mendeklarasikan paket penyiapan. Lihat struktur WINUSB_CONTROL_SETUP_PACKET yang dinyatakan dalam usb_hw.h.
  2. Inisialisasi paket penyiapan dengan memanggil makro pembantu, WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE, yang ditentukan dalam usb_hw.h.
  3. Tentukan nilai penerima yang ditentukan dalam WINUSB_BMREQUEST_RECIPIENT.
  4. Tentukan pemilih fitur (wValue). Lihat konstanta USB_FEATURE_XXX di Usbspec.h. Lihat juga Tabel 9-6 dalam spesifikasi USB.
  5. Atur SetFeature ke FALSE.
  6. Buat permintaan dengan mengaitkan paket penyiapan yang diinisialisasi dengan objek permintaan kerangka kerja dan buffer transfer dengan memanggil metode IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  7. Kirim permintaan dengan memanggil metode IWDFIoRequest::Send .
_URB_CONTROL_FEATURE_REQUEST

(UsbBuildFeatureRequest)

URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE

URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE

URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT

URB_FUNCTION_CLEAR_FEATURE_TO_OTHER
GET_CONFIGURATION: Dapatkan konfigurasi USB saat ini. Lihat bagian 9.4.2 dalam spesifikasi USB. KMDF memilih konfigurasi pertama secara default. Untuk mengambil nomor konfigurasi yang ditentukan perangkat:

  1. Format WDF_USB_CONTROL_SETUP_PACKET dan atur anggota bRequest-nya ke USB_REQUEST_GET_CONFIGURATION.
  2. Kirim permintaan dengan memanggil WdfUsbTargetDeviceSendControlTransferSynchronously atau WdfUsbTargetDeviceFormatRequestForControlTransfer.
UMDF memilih konfigurasi pertama secara default. Untuk mengambil nomor konfigurasi yang ditentukan perangkat:

  1. Mendeklarasikan paket penyiapan. Lihat struktur WINUSB_CONTROL_SETUP_PACKET yang dideklarasikan dalam usb_hw.h.
  2. Inisialisasi paket penyiapan dengan memanggil makro pembantu, WINUSB_CONTROL_SETUP_PACKET_INIT, yang ditentukan dalam usb_hw.h.
  3. Tentukan BmRequestToDevice sebagai arah, BmRequestToDevice sebagai penerima, dan USB_REQUEST_GET_CONFIGURATION sebagai permintaan.
  4. Buat permintaan dengan mengaitkan paket penyiapan yang diinisialisasi dengan objek permintaan kerangka kerja dan buffer transfer dengan memanggil metode IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  5. Kirim permintaan dengan memanggil metode IWDFIoRequest::Send .
  6. Terima nomor konfigurasi di buffer transfer. Akses buffer tersebut dengan memanggil metode IWDFMemory .
_URB_CONTROL_GET_CONFIGURATION_REQUEST

URB_FUNCTION_GET_CONFIGURATION
GET_DESCRIPTOR: Mendapatkan perangkat, konfigurasi, antarmuka, dan deskriptor titik akhir. Lihat bagian 9.4.3 dalam spesifikasi USB.

Untuk informasi selengkapnya, lihat Deskriptor USB.
Panggil metode ini:

Panggil metode ini:

_URB_CONTROL_DESCRIPTOR_REQUEST

(UsbBuildGetDescriptorRequest)

URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE

URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT

URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE
GET_INTERFACE: Dapatkan pengaturan alternatif saat ini untuk antarmuka. Lihat bagian 9.4.4 dalam spesifikasi USB.

  1. Dapatkan handel WDFUSBINTERFACE ke objek antarmuka target dengan memanggil metode WdfUsbTargetDeviceGetInterface .
  2. Panggil metode WdfUsbInterfaceGetConfiguredSettingIndex .
  1. Dapatkan penunjuk IWDFUsbInterface ke objek antarmuka target.
  2. Panggil metode IWDFUsbInterface::GetConfiguredSettingIndex .
_URB_CONTROL_GET_INTERFACE_REQUEST

URB_FUNCTION_GET_INTERFACE
GET_STATUS: Dapatkan bit status dari perangkat, titik akhir, atau antarmuka. Lihat bagian 9.4.5. dalam spesifikasi USB.
  1. Mendeklarasikan paket penyiapan. Lihat struktur WDF_USB_CONTROL_SETUP_PACKET .
  2. Inisialisasi paket penyiapan dengan memanggil WDF_USB_CONTROL_SETUP_PACKET_INIT_GET_STATUS.
  3. Tentukan nilai penerima yang ditentukan dalam WDF_USB_BMREQUEST_RECIPIENT.
  4. Tentukan status mana yang ingin Anda dapatkan: perangkat, antarmuka, atau titik akhir (wIndex).
  5. Kirim permintaan dengan memanggil WdfUsbTargetDeviceSendControlTransferSynchronously atau WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Mendeklarasikan paket penyiapan. Lihat struktur WINUSB_CONTROL_SETUP_PACKET yang dideklarasikan dalam usb_hw.h.
  2. Inisialisasi paket penyiapan dengan memanggil makro pembantu, WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS, yang ditentukan dalam usb_hw.h.
  3. Tentukan nilai penerima yang ditentukan dalam WINUSB_BMREQUEST_RECIPIENT.
  4. Tentukan status mana yang ingin Anda dapatkan: perangkat, antarmuka, atau titik akhir (wIndex).
  5. Buat permintaan dengan mengaitkan paket penyiapan yang diinisialisasi dengan objek permintaan kerangka kerja dan buffer transfer dengan memanggil metode IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  6. Kirim permintaan dengan memanggil metode IWDFIoRequest::Send .
  7. Terima nilai status di buffer transfer. Akses buffer tersebut dengan memanggil metode IWDFMemory .
  8. Untuk menentukan apakah status menunjukkan bangun jarak jauh yang didukung sendiri, gunakan nilai thee yang ditentukan dalam enumerasi WINUSB_DEVICE_TRAITS :
_URB_CONTROL_GET_STATUS_REQUEST

(UsbBuildGetStatusRequest)

URB_FUNCTION_GET_STATUS_FROM_DEVICE

URB_FUNCTION_GET_STATUS_FROM_INTERFACE

URB_FUNCTION_GET_STATUS_FROM_ENDPOINT

URB_FUNCTION_GET_STATUS_FROM_OTHER.
SET_ADDRESS: Lihat bagian 9.4.6 dalam spesifikasi USB. Permintaan ini ditangani oleh tumpukan driver USB; driver klien tidak dapat melakukan operasi ini. Permintaan ini ditangani oleh tumpukan driver USB; driver klien tidak dapat melakukan operasi ini. Permintaan ini ditangani oleh tumpukan driver USB; driver klien tidak dapat melakukan operasi ini.
SET_CONFIGURATION: Mengatur konfigurasi. Lihat bagian 9.4.7 dalam spesifikasi USB.

Untuk informasi selengkapnya, lihat Cara memilih konfigurasi untuk perangkat USB.
Secara default KMDF memilih konfigurasi default dan pengaturan alternatif pertama di setiap antarmuka. Driver klien dapat mengubah konfigurasi default dengan memanggil metode WdfUsbTargetDeviceSelectConfigType dan menentukan WdfUsbTargetDeviceSelectConfigTypeUrb sebagai opsi permintaan. Anda kemudian harus memformat URB untuk permintaan ini dan mengirimkannya ke tumpukan driver USB. Secara default UMDF memilih konfigurasi default dan pengaturan alternatif pertama di setiap antarmuka. Driver klien tidak dapat mengubah konfigurasi. _URB_SELECT_CONFIGURATION

(USBD_SelectConfigUrbAllocateAndBuild)

URB_FUNCTION_SELECT_CONFIGURATION
SET_DESCRIPTOR: Memperbarui perangkat, konfigurasi, atau deskriptor string yang ada. Lihat bagian 9.4.8 dalam spesifikasi USB.

Permintaan ini tidak umum digunakan. Namun, tumpukan driver USB menerima permintaan tersebut dari driver klien.
  1. Alokasikan dan buat URB untuk permintaan tersebut.
  2. Tentukan informasi transfer dalam struktur _URB_CONTROL_DESCRIPTOR_REQUEST .
  3. Kirim permintaan dengan memanggil WdfUsbTargetDeviceFormatRequestForUrb atau WdfUsbTargetDeviceSendUrbSynchronously .
  1. Mendeklarasikan paket penyiapan. Lihat struktur WINUSB_CONTROL_SETUP_PACKET yang dideklarasikan dalam usb_hw.h.
  2. Tentukan informasi transfer sesuai spesifikasi USB.
  3. Buat permintaan dengan mengaitkan paket penyiapan yang diinisialisasi dengan objek permintaan kerangka kerja dan buffer transfer dengan memanggil metode IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  4. Kirim permintaan dengan memanggil metode IWDFIoRequest::Send .
_URB_CONTROL_DESCRIPTOR_REQUEST

URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE

URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT

URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE
SET_FEATURE: Aktifkan pengaturan fitur tertentu di perangkat, konfigurasi, antarmuka, dan titik akhirnya. Lihat bagian 9.4.9 dalam spesifikasi USB.
  1. Mendeklarasikan paket penyiapan. Lihat struktur WDF_USB_CONTROL_SETUP_PACKET .
  2. Inisialisasi paket penyiapan dengan memanggil WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE.
  3. Tentukan nilai penerima (perangkat, antarmuka, titik akhir) yang ditentukan dalam WDF_USB_BMREQUEST_RECIPIENT.
  4. Tentukan pemilih fitur (wValue). Lihat konstanta USB_FEATURE_XXX di Usbspec.h. Lihat juga Tabel 9-6 dalam spesifikasi USB.
  5. Atur SetFeature ke TRUE
  6. Kirim permintaan dengan memanggil WdfUsbTargetDeviceSendControlTransferSynchronously atau WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Mendeklarasikan paket penyiapan. Lihat struktur WINUSB_CONTROL_SETUP_PACKET yang dideklarasikan dalam usb_hw.h.
  2. Inisialisasi paket penyetelan dengan memanggil makro pembantu, WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE, yang ditentukan dalam usb_hw.h.
  3. Tentukan nilai penerima yang ditentukan dalam WINUSB_BMREQUEST_RECIPIENT.
  4. Tentukan pemilih fitur (wValue). Lihat konstanta USB_FEATURE_XXX di Usbspec.h. Lihat juga Tabel 9-6 dalam spesifikasi USB.
  5. Atur SetFeature ke TRUE.
  6. Buat permintaan dengan mengaitkan paket penyiapan yang diinisialisasi dengan objek permintaan kerangka kerja dan buffer transfer dengan memanggil metode IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  7. Kirim permintaan dengan memanggil metode IWDFIoRequest::Send .
_URB_CONTROL_FEATURE_REQUEST

(UsbBuildFeatureRequest)

URB_FUNCTION_SET_FEATURE_TO_DEVICE

URB_FUNCTION_SET_FEATURE_TO_INTERFACE

URB_FUNCTION_SET_FEATURE_TO_ENDPOINT

URB_FUNCTION_SET_FEATURE_TO_OTHER
SET_INTERFACE: Mengubah pengaturan alternatif dalam antarmuka. Lihat bagian 9.4.9 dalam spesifikasi USB.

Untuk informasi selengkapnya, lihat Cara memilih pengaturan alternatif di antarmuka USB.
WdfUsbTargetDeviceSelectConfig
  1. Dapatkan handel WDFUSBINTERFACE ke objek antarmuka target.
  2. Panggil metode WdfUsbInterfaceSelectSetting .
  1. Dapatkan penunjuk IWDFUsbInterface ke objek antarmuka target.
  2. Panggil metode IWDFUsbInterface::SelectSetting .
_URB_SELECT_INTERFACE

(USBD_SelectInterfaceUrbAllocateAndBuild)

URB_FUNCTION_SELECT_INTERFACE
SYNC_FRAME: Atur dan dapatkan dan nomor bingkai sinkronisasi titik akhir. Lihat bagian 9.4.10 dalam spesifikasi USB. Permintaan ini ditangani oleh tumpukan driver USB; driver klien tidak dapat melakukan operasi ini. Permintaan ini ditangani oleh tumpukan driver USB; driver klien tidak dapat melakukan operasi ini. Permintaan ini ditangani oleh tumpukan driver USB; driver klien tidak dapat melakukan operasi ini.
Untuk permintaan khusus kelas perangkat dan perintah vendor.
  1. Mendeklarasikan paket penyiapan. Lihat struktur WDF_USB_CONTROL_SETUP_PACKET .
  2. Inisialisasi paket penyiapan dengan memanggil permintaan khusus WDF_USB_CONTROL_SETUP_PACKET_INIT_CLASS atau WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR untuk perintah vendor.
  3. Tentukan nilai penerima (perangkat, antarmuka, titik akhir) yang ditentukan dalam WDF_USB_BMREQUEST_RECIPIENT.
  4. Kirim permintaan dengan memanggil WdfUsbTargetDeviceSendControlTransferSynchronously atau WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Mendeklarasikan paket penyiapan. Lihat struktur WINUSB_CONTROL_SETUP_PACKET yang dideklarasikan dalam usb_hw.h.
  2. Inisialisasi paket penyiapan dengan memanggil makro pembantu, WINUSB_CONTROL_SETUP_PACKET_INIT_CLASS atau WINUSB_CONTROL_SETUP_PACKET_INIT_VENDOR, yang ditentukan dalam usb_hw.h.
  3. Tentukan arah (lihat enumerasi WINUSB_BMREQUEST_DIRECTION ), penerima ( lihat enumerasi WINUSB_BMREQUEST_RECIPIENT ), dan permintaan, seperti yang dijelaskan di kelas atau spesifikasi perangkat keras.
  4. Buat permintaan dengan mengaitkan paket penyiapan yang diinisialisasi dengan objek permintaan kerangka kerja dan buffer transfer dengan memanggil metode IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  5. Kirim permintaan dengan memanggil metode IWDFIoRequest::Send .
  6. Terima informasi dari perangkat di buffer transfer. Akses buffer tersebut dengan memanggil metode IWDFMemory .
_URB_CONTROL_VENDOR_OR_CLASS_REQUEST

(UsbBuildVendorRequest)

URB_FUNCTION_VENDOR_DEVICE

URB_FUNCTION_VENDOR_INTERFACE

URB_FUNCTION_VENDOR_ENDPOINT

URB_FUNCTION_VENDOR_OTHER

URB_FUNCTION_CLASS_DEVICE

URB_FUNCTION_CLASS_INTERFACE

URB_FUNCTION_CLASS_ENDPOINT

URB_FUNCTION_CLASS_OTHER

Cara mengirim transfer kontrol untuk perintah vendor - KMDF

Prosedur ini menunjukkan bagaimana driver klien dapat mengirim transfer kontrol. Dalam contoh ini, driver klien mengirim perintah vendor yang mengambil versi firmware dari perangkat.

  1. Deklarasikan konstanta untuk perintah vendor. Pelajari spesifikasi perangkat keras dan tentukan perintah vendor yang ingin Anda gunakan.

  2. Deklarasikan struktur WDF_MEMORY_DESCRIPTOR dan inisialisasi dengan memanggil makro WDF_MEMORY_DESCRIPTOR_INIT_BUFFER . Struktur ini akan menerima respons dari perangkat setelah driver USB menyelesaikan permintaan.

  3. Bergantung pada apakah Anda mengirim permintaan secara sinkron atau asinkron, tentukan opsi kirim Anda:

  4. Deklarasikan struktur WDF_USB_CONTROL_SETUP_PACKET untuk memuat token penyiapan dan memformat struktur. Untuk melakukannya, panggil makro WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR untuk memformat paket penyetelan. Dalam panggilan tentukan, arah permintaan, penerima, opsi permintaan terkirim (diinisialisasi di langkah3), dan konstanta untuk perintah vendor.

  5. Kirim permintaan dengan memanggil WdfUsbTargetDeviceSendControlTransferSynchronously atau WdfUsbTargetDeviceFormatRequestForControlTransfer.

  6. Periksa nilai NTSTATUS yang dikembalikan oleh kerangka kerja dan periksa nilai yang diterima.

Contoh kode ini mengirimkan permintaan transfer kontrol ke perangkat USB untuk mengambil versi firmware-nya. Permintaan dikirim secara sinkron dan driver klien menentukan nilai batas waktu relatif 5 detik (dalam unit 100 nanodetik). Driver menyimpan respons yang diterima dalam konteks perangkat yang ditentukan driver.

enum {
    USBFX2_GET_FIRMWARE_VERSION = 0x1,
....

} USBFX2_VENDOR_COMMANDS; 

#define WDF_TIMEOUT_TO_SEC              ((LONGLONG) 1 * 10 * 1000 * 1000)  // defined in wdfcore.h

const __declspec(selectany) LONGLONG
            DEFAULT_CONTROL_TRANSFER_TIMEOUT = 5 * -1 * WDF_TIMEOUT_TO_SEC; 


typedef struct _DEVICE_CONTEXT
{

    ...
       union {
        USHORT      VersionAsUshort;
        struct {
            BYTE Minor;
            BYTE Major;
        } Version;
    } Firmware; // Firmware version.

} DEVICE_CONTEXT, *PDEVICE_CONTEXT;


__drv_requiresIRQL(PASSIVE_LEVEL)
VOID  GetFirmwareVersion(
    __in PDEVICE_CONTEXT DeviceContext
)
{
    NTSTATUS                        status;
    WDF_USB_CONTROL_SETUP_PACKET    controlSetupPacket;
    WDF_REQUEST_SEND_OPTIONS        sendOptions;
    USHORT                          firmwareVersion;
    WDF_MEMORY_DESCRIPTOR           memoryDescriptor;

    PAGED_CODE();

    firmwareVersion = 0;

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor, (PVOID) &firmwareVersion, sizeof(firmwareVersion));

    WDF_REQUEST_SEND_OPTIONS_INIT(
                                  &sendOptions,
                                  WDF_REQUEST_SEND_OPTION_TIMEOUT
                                  );

    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
                                         &sendOptions,
                                         DEFAULT_CONTROL_TRANSFER_TIMEOUT
                                         );

    WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
                                        BmRequestDeviceToHost,       // Direction of the request
                                        BmRequestToDevice,           // Recipient
                                        USBFX2_GET_FIRMWARE_VERSION, // Vendor command
                                        0,                           // Value
                                        0);                          // Index 

    status = WdfUsbTargetDeviceSendControlTransferSynchronously(
                                        DeviceContext->UsbDevice,
                                        WDF_NO_HANDLE,               // Optional WDFREQUEST
                                        &sendOptions,
                                        &controlSetupPacket,
                                        &memoryDescriptor,           // MemoryDescriptor
                                        NULL);                       // BytesTransferred 

    if (!NT_SUCCESS(status)) 
    {
        KdPrint(("Device %d: Failed to get device firmware version 0x%x\n", DeviceContext->DeviceNumber, status));
        TraceEvents(DeviceContext->DebugLog,
                    TRACE_LEVEL_ERROR,
                    DBG_RUN,
                    "Device %d: Failed to get device firmware version 0x%x\n",
                    DeviceContext->DeviceNumber,
                    status);
    }
    else 
    {
        DeviceContext->Firmware.VersionAsUshort = firmwareVersion;
        TraceEvents(DeviceContext->DebugLog,
                    TRACE_LEVEL_INFORMATION,
                    DBG_RUN,
                    "Device %d: Get device firmware version : 0x%x\n",
                    DeviceContext->DeviceNumber,
                    firmwareVersion);
    }

    return;
}

Cara mengirim transfer kontrol untuk GET_STATUS - UMDF

Prosedur ini menunjukkan bagaimana driver klien dapat mengirim transfer kontrol untuk perintah GET_STATUS. Penerima permintaan adalah perangkat dan permintaan mendapatkan informasi di bit D1-D0. Untuk informasi selengkapnya, lihat Gambar 9-4 dalam spesifikasi USB.

  1. Sertakan file header Usb_hw.h yang tersedia dengan Contoh Driver UMDF untuk OSR USB Fx2 Learning Kit.

  2. Deklarasikan struktur WINUSB_CONTROL_SETUP_PACKET .

  3. Inisialisasi paket penyetelan dengan memanggil makro pembantu, WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS.

  4. Tentukan BmRequestToDevice sebagai penerima.

  5. Tentukan 0 dalam nilai Indeks .

  6. Panggil metode pembantu SendControlTransferSynchronously untuk mengirim permintaan secara sinkron.

    Metode pembantu membangun permintaan dengan mengaitkan paket penyiapan yang diinisialisasi dengan objek permintaan kerangka kerja dan buffer transfer dengan memanggil metode IWDFUsbTargetDevice::FormatRequestForControlTransfer . Metode pembantu kemudian mengirim permintaan dengan memanggil metode IWDFIoRequest::Send . Setelah metode kembali, periksa nilai yang dikembalikan.

  7. Untuk menentukan apakah status menunjukkan bangun jarak jauh yang didukung sendiri, gunakan nilai-nilai ini yang ditentukan dalam enumerasi WINUSB_DEVICE_TRAITS :

Contoh kode ini mengirimkan permintaan transfer kontrol untuk mendapatkan status perangkat. Contoh mengirim permintaan secara sinkron dengan memanggil metode pembantu bernama SendControlTransferSynchronously.

HRESULT
CDevice::GetDeviceStatus ()
{

    HRESULT hr = S_OK;

    USHORT deviceStatus;
    ULONG bytesTransferred;

    TraceEvents(TRACE_LEVEL_INFORMATION,
                DRIVER_ALL_INFO,
                "%!FUNC!: entry");

    // Setup the control packet.

    WINUSB_CONTROL_SETUP_PACKET setupPacket;

    WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS(
                                      &setupPacket,
                                      BmRequestToDevice,
                                      0);

    hr = SendControlTransferSynchronously(
                 &(setupPacket.WinUsb),
                 & deviceStatus,
                 sizeof(USHORT),
                 &bytesReturned
                );

     if (SUCCEEDED(hr))
    {
        if (deviceStatus & USB_GETSTATUS_SELF_POWERED)
        {
             m_Self_Powered = true;
        } 
        if (deviceStatus & USB_GETSTATUS_REMOTE_WAKEUP_ENABLED)
        {
             m_remote_wake-enabled = true;
        }
    }

    return hr;
 }

Contoh kode berikut menunjukkan implementasi metode pembantu bernama SendControlTransferSynchronously. Metode ini mengirimkan permintaan secara sinkron.

HRESULT
CDevice::SendControlTransferSynchronously(
    _In_ PWINUSB_SETUP_PACKET SetupPacket,
    _Inout_ PBYTE Buffer,
    _In_ ULONG BufferLength,
    _Out_ PULONG LengthTransferred
    )
{
    HRESULT hr = S_OK;
    IWDFIoRequest *pWdfRequest = NULL;
    IWDFDriver * FxDriver = NULL;
    IWDFMemory * FxMemory = NULL;
    IWDFRequestCompletionParams * FxComplParams = NULL;
    IWDFUsbRequestCompletionParams * FxUsbComplParams = NULL;

    *LengthTransferred = 0;

    hr = m_FxDevice->CreateRequest( NULL, //pCallbackInterface
                                    NULL, //pParentObject
                                    &pWdfRequest);

    if (SUCCEEDED(hr))
    {
        m_FxDevice->GetDriver(&FxDriver);

        hr = FxDriver->CreatePreallocatedWdfMemory( Buffer,
                                                    BufferLength,
                                                    NULL,        //pCallbackInterface
                                                    pWdfRequest, //pParetObject
                                                    &FxMemory );
    }

    if (SUCCEEDED(hr))
    {
        hr = m_pIUsbTargetDevice->FormatRequestForControlTransfer( pWdfRequest,
                                                                   SetupPacket,
                                                                   FxMemory,
                                                                   NULL); //TransferOffset
    }

    if (SUCCEEDED(hr))
    {
        hr = pWdfRequest->Send( m_pIUsbTargetDevice,
                                WDF_REQUEST_SEND_OPTION_SYNCHRONOUS,
                                0); //Timeout
    }

    if (SUCCEEDED(hr))
    {
        pWdfRequest->GetCompletionParams(&FxComplParams);

        hr = FxComplParams->GetCompletionStatus();
    }

    if (SUCCEEDED(hr))
    {
        HRESULT hrQI = FxComplParams->QueryInterface(IID_PPV_ARGS(&FxUsbComplParams));
        WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrQI));

        WUDF_TEST_DRIVER_ASSERT( WdfUsbRequestTypeDeviceControlTransfer ==
                            FxUsbComplParams->GetCompletedUsbRequestType() );

        FxUsbComplParams->GetDeviceControlTransferParameters( NULL,
                                                             LengthTransferred,
                                                             NULL,
                                                             NULL );
    }

    SAFE_RELEASE(FxUsbComplParams);
    SAFE_RELEASE(FxComplParams);
    SAFE_RELEASE(FxMemory);

    pWdfRequest->DeleteWdfObject(); 
    SAFE_RELEASE(pWdfRequest);

    SAFE_RELEASE(FxDriver);

    return hr;
}

Jika Anda menggunakan Winusb.sys sebagai driver fungsi untuk perangkat Anda, Anda dapat mengirim transfer kontrol dari aplikasi. Untuk memformat paket penyiapan di WinUSB, gunakan makro dan struktur pembantu UMDF, yang dijelaskan dalam tabel dalam artikel ini. Untuk mengirim permintaan, panggil fungsi WinUsb_ControlTransfer .