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.
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.
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.
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.
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.
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.
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:
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:
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.
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. |
|
|
_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:
|
UMDF memilih konfigurasi pertama secara default. Untuk mengambil nomor konfigurasi yang ditentukan perangkat:
|
_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. |
|
|
_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. |
|
|
_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. |
|
|
_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. |
|
|
_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
|
|
_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. |
|
|
_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.
Deklarasikan konstanta untuk perintah vendor. Pelajari spesifikasi perangkat keras dan tentukan perintah vendor yang ingin Anda gunakan.
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.
Bergantung pada apakah Anda mengirim permintaan secara sinkron atau asinkron, tentukan opsi kirim Anda:
Jika Anda mengirim permintaan secara sinkron dengan memanggil WdfUsbTargetDeviceSendControlTransferSynchronously, tentukan nilai batas waktu. Nilai itu penting karena tanpa batas waktu, Anda dapat memblokir utas tanpa batas waktu.
Untuk ini, deklarasikan struktur WDF_REQUEST_SEND_OPTIONS dan inisialisasi dengan memanggil makro WDF_REQUEST_SEND_OPTIONS_INIT . Tentukan opsi sebagai WDF_REQUEST_SEND_OPTION_TIMEOUT.
Selanjutnya, atur nilai batas waktu dengan memanggil makro WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT .
Jika Anda mengirim permintaan secara asinkron, terapkan rutinitas penyelesaian. Gratis semua sumber daya yang dialokasikan dalam rutinitas penyelesaian.
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.
Kirim permintaan dengan memanggil WdfUsbTargetDeviceSendControlTransferSynchronously atau WdfUsbTargetDeviceFormatRequestForControlTransfer.
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.
Sertakan file header Usb_hw.h yang tersedia dengan Contoh Driver UMDF untuk OSR USB Fx2 Learning Kit.
Deklarasikan struktur WINUSB_CONTROL_SETUP_PACKET .
Inisialisasi paket penyetelan dengan memanggil makro pembantu, WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS.
Tentukan BmRequestToDevice sebagai penerima.
Tentukan 0 dalam nilai Indeks .
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.
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 .
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk