24 poin oleh GN⁺ 11 hari lalu | Belum ada komentar. | Bagikan ke WhatsApp
  • Pengembangan driver USB sering dianggap sebagai pekerjaan tingkat kernel, tetapi pada praktiknya tingkat kesulitannya mirip dengan pemrograman soket dan dapat diimplementasikan juga di ruang pengguna
  • Dengan libusb, semua hal mulai dari enumerasi perangkat, transfer kontrol, hingga kirim-terima data bisa dilakukan tanpa menulis kode kernel
  • Komunikasi USB terdiri dari empat jenis transfer: Control, Bulk, Interrupt, Isochronous, serta arah IN/OUT, dan setiap endpoint bekerja sebagai jalur satu arah
  • Dengan protokol Fastboot pada perangkat Android sebagai contoh, artikel ini mendemonstrasikan lewat kode proses pertukaran perintah dan respons melalui endpoint Bulk
  • Bahkan di ruang pengguna, driver USB yang lengkap dapat diimplementasikan, dan semua protokol USB berbagi struktur dasar yang sama

Pengenalan

  • Driver untuk perangkat USB sering terasa sulit karena ada anggapan bahwa kita harus menangani kode kernel, padahal kenyataannya kompleksitasnya setara dengan aplikasi yang menggunakan soket
  • Pengembang yang tidak memiliki banyak pengalaman hardware pun dapat mempelajari cara menangani USB di ruang pengguna
  • Memang ada banyak materi yang membahas detail kerja USB, tetapi bagi pemula materi seperti itu sering sulit diakses
  • Menggunakan USB tidak memerlukan pengetahuan setingkat sistem embedded, dan bisa didekati seperti soket jaringan

Perangkat USB

  • Sebagai contoh digunakan smartphone Android dalam mode bootloader
    • Mudah didapat, protokolnya sederhana, dan cocok untuk eksperimen karena OS tidak memiliki driver bawaan untuknya
  • Cara masuk ke mode bootloader berbeda untuk tiap perangkat, tetapi umumnya bisa dilakukan dengan kombinasi tombol daya dan volume

Enumerasi perangkat secara manual

  • Enumeration adalah proses saat host meminta informasi perangkat agar perangkat bisa mengidentifikasi dirinya, dan proses ini berjalan otomatis ketika perangkat dihubungkan
  • Untuk perangkat standar, driver dimuat otomatis berdasarkan kelas USB, sedangkan perangkat khusus vendor menggunakan VID (Vendor ID) dan PID (Product ID)
  • Di Linux, informasi perangkat dapat dilihat dengan perintah lsusb
    • Contoh: ID 18d1:4ee0 Google Inc. Nexus/Pixel Device (fastboot)
    • 18d1 adalah VID milik Google, dan 4ee0 adalah PID untuk bootloader Nexus/Pixel
  • Dengan perintah lsusb -t, kita bisa memeriksa kelas dan status driver
    • Jika tampil Class=Vendor Specific Class, Driver=[none], berarti OS tidak memuat driver
  • Di Windows, informasi yang sama bisa dilihat melalui Device Manager atau USB Device Tree Viewer

Enumerasi perangkat dengan libusb

  • Dengan library libusb, kita dapat berkomunikasi dengan perangkat USB di ruang pengguna tanpa menulis kode kernel
  • libusb_hotplug_register_callback() dapat digunakan untuk menyiapkan callback agar dijalankan saat perangkat dengan kombinasi VID:PID tertentu terhubung
  • Setelah program berjalan, saat perangkat disambungkan akan muncul pesan "Device plugged in!"
  • Di Linux ini bekerja secara bawaan, dan bila perlu driver kernel bisa dilepas dengan libusb_detach_kernel_driver()
  • Di Windows dibutuhkan driver Winusb.sys, dan jika belum ada dapat diganti secara manual menggunakan alat Zadig

Berkomunikasi dengan perangkat

  • Komunikasi pertama dengan perangkat USB dilakukan melalui endpoint Control (alamat 0x00)
  • Dengan libusb_control_transfer(), kita dapat mengirim permintaan standar (GET_STATUS) untuk membaca status perangkat
    • Contoh respons: 01 00 → byte pertama berarti Self-Powered, byte kedua berarti tidak mendukung Remote Wakeup
  • Setelah itu kita bisa mengambil deskriptor perangkat melalui permintaan GET_DESCRIPTOR
    • Data yang dikembalikan mencakup informasi perangkat seperti idVendor, idProduct, bDeviceClass, dan lainnya
  • Dengan perintah lsusb -v, semua deskriptor (perangkat, konfigurasi, antarmuka, endpoint, dll.) dapat dilihat secara rinci
    • Contoh: antarmuka Android Fastboot memiliki endpoint Bulk IN (0x81) dan Bulk OUT (0x02)

Endpoint

  • Endpoint adalah konsep yang mirip dengan port jaringan, yaitu jalur tempat perangkat mengirim dan menerima data
  • Jenis dan arah setiap endpoint didefinisikan di dalam deskriptor
  • Jenis transfer Control

    • Ada satu pada setiap perangkat dan alamatnya selalu 0x00
    • Digunakan untuk konfigurasi awal dan permintaan informasi perangkat
    • Tidak termasuk dalam antarmuka, melainkan merupakan bagian dari perangkat itu sendiri
  • Jenis transfer Bulk

    • Digunakan untuk transfer data besar yang tidak real-time
    • Contoh: Mass Storage, CDC-ACM (serial), RNDIS (ethernet)
    • Bandwidth tinggi, tetapi prioritas rendah
  • Jenis transfer Interrupt

    • Digunakan untuk transfer data kecil dengan latensi rendah
    • Dipakai pada keyboard, mouse, dan perangkat serupa untuk melakukan polling input tombol dengan cepat
    • Ini bukan interupsi hardware sungguhan; host yang meminta secara berkala
  • Jenis transfer Isochronous

    • Digunakan untuk data besar yang sensitif terhadap waktu (streaming audio, video)
    • Jika terjadi jeda, penurunan kualitas akan langsung terlihat
    • Di libusb, jenis ini ditangani secara asinkron
  • Arah IN / OUT

    • USB memiliki arsitektur yang berpusat pada host, sehingga perangkat tidak mengirim data sebelum menerima permintaan
    • IN: arah saat host menerima data
    • OUT: arah saat host mengirim data
    • Jika bit paling signifikan (MSB) pada alamat endpoint bernilai 1, berarti IN; jika 0, berarti OUT
    • Maksimal 127 endpoint kustom dapat digunakan (0x00 khusus untuk Control)
    • Endpoint bersifat satu arah, dan dapat dibentuk sebagai pasangan IN/OUT seperti pada antarmuka Fastboot

Protokol Fastboot

  • Fastboot adalah protokol komunikasi bootloader Android dengan struktur mengirim string perintah lalu menerima kode status 4 byte beserta data
    • Contoh:
      • Host: "getvar:version"Client: "OKAY0.4"
      • Host: "getvar:nonexistant"Client: "OKAY"
  • Contoh kode pengiriman perintah Fastboot menggunakan libusb
    • Antarmuka 0 diambil dengan libusb_claim_interface()
    • Perintah "getvar:version" dikirim ke endpoint Bulk OUT (0x02)
    • Respons diterima dari endpoint Bulk IN (0x81)
    • Contoh output:
      Request: getvar:version
      Response: OKAY0.4
      
    • OKAY adalah status berhasil, 0.4 adalah versi Fastboot

Penutup

  • Tanpa menulis kode kernel, kita tetap bisa mengimplementasikan driver USB yang lengkap di ruang pengguna
  • Semua driver USB mengikuti prinsip dasar yang sama; yang berbeda hanyalah protokolnya
  • Bahkan untuk protokol yang kompleks (seperti MTP), struktur dasarnya tetap sama dan dapat didekati dengan konsep yang mirip komunikasi soket

Belum ada komentar.

Belum ada komentar.