
Pendahuluan
Saya menyambut semua orang. Hari ini saya ingin berbagi pengalaman saya dan masih, menurut pendapat saya, jelas menjelaskan tentang itu, pada pandangan pertama, standar sederhana untuk pengontrol host USB 2.0.
Awalnya, Anda dapat membayangkan bahwa port USB 2.0 hanya 4 pin, dua di antaranya hanya mentransmisikan data (Seperti, misalnya, port COM), tetapi pada kenyataannya, semuanya tidak begitu, dan bahkan sebaliknya. Pengontrol USB, pada prinsipnya, tidak memungkinkan kami untuk mentransfer data melalui port COM biasa. EHCI adalah standar yang agak canggih yang memungkinkan transfer data yang andal dan cepat dari perangkat lunak ke perangkat itu sendiri, dan dalam arah yang berlawanan.
Anda mungkin menemukan artikel ini berguna jika, misalnya, Anda tidak memiliki keterampilan menulis yang cukup untuk driver dan membaca dokumentasi untuk perangkat keras. Contoh sederhana: Anda ingin menulis OS untuk mini-PC, sehingga beberapa Windows atau distribusi Linux lainnya tidak mengunduh perangkat keras, dan Anda menggunakan semua kekuatannya secara eksklusif untuk keperluan Anda sendiri.
Apa itu EHCI?
Baiklah, mari kita mulai. EHCI - Enhanced Host Controller Interface, dirancang untuk mentransfer data dan mengontrol permintaan ke perangkat USB, dan ke arah lain, dan dalam 99% kasus, ini merupakan tautan antara perangkat lunak apa pun dan perangkat fisik. EHCI berfungsi sebagai perangkat PCI, dan karenanya menggunakan MMIO (Memory-Mapped-IO) untuk mengontrol pengontrol (ya, saya tahu bahwa beberapa perangkat PCI menggunakan porta, tapi di sini saya menggeneralisasi semuanya). Dokumentasi dari Intel hanya menjelaskan prinsip operasi, dan tidak ada petunjuk sama sekali tentang algoritma yang ditulis setidaknya dalam pseudo-code. EHCI memiliki 2 jenis register MMIO: Kemampuan dan Operasional. Yang pertama berfungsi untuk mendapatkan karakteristik controller, sedangkan yang kedua berfungsi untuk mengendalikannya. Sebenarnya, saya akan melampirkan esensi koneksi antara perangkat lunak dan pengontrol EHCI:

Setiap pengontrol EHCI memiliki beberapa port, yang masing-masing dapat dihubungkan ke perangkat USB apa pun. Perlu diketahui juga bahwa EHCI adalah versi perbaikan dari UHCI, yang juga dikembangkan oleh Intel beberapa tahun sebelumnya. Untuk kompatibilitas mundur, setiap pengontrol UHCI / OHCI yang memiliki versi lebih rendah dari EHCI akan menjadi pendamping EHCI. Misalnya, Anda memiliki keyboard USB (dan sebagian besar keyboard tahun ini seperti itu) yang bekerja pada USB 1.1 (perhatikan bahwa kecepatan maksimum USB 1.1 adalah 12 megabit per detik, dan FullSpeed USB 2.0 memiliki bandwidth sebanyak 480 Mbps), dan Anda memiliki komputer dengan port USB 2.0, saat Anda menyambungkan keyboard ke komputer, pengontrol host EHCI entah bagaimana akan bekerja dengan USB 1.1. Model ini ditunjukkan pada diagram berikut:

Juga, untuk masa depan saya ingin segera memperingatkan Anda bahwa driver Anda mungkin tidak berfungsi dengan benar karena situasi yang absurd: Anda menginisialisasi UHCI, dan kemudian EHCI, sambil menambahkan dua perangkat yang sama, mengatur bit Kontrol Pemilik Port ke register port, dan kemudian UHCI berhenti bekerja, karena EHCI secara otomatis menyeret port ke dirinya sendiri, dan port pada UHCI berhenti merespons, situasi ini perlu dipantau.
Juga, mari kita lihat diagram yang menunjukkan arsitektur EHCI itu sendiri:

Di sebelah kanan ditulis tentang antrian - tentang mereka sedikit kemudian.
Register pengendali EHCI
Untuk mulai dengan, saya ingin mengklarifikasi sekali lagi bahwa melalui register ini Anda akan mengontrol perangkat Anda, oleh karena itu mereka sangat penting - dan tanpa mereka pemrograman EHCI tidak mungkin.
Pertama, Anda perlu mendapatkan alamat MMIO yang diberikan kepada pengontrol ini, di offset + 0x10 akan menjadi alamat register lama kami. Ada satu hal: pertama, register Kemampuan pergi, dan hanya setelah mereka - Operasional, oleh karena itu, pada offset 0 (dari alamat sebelumnya, yang kami terima pada offset 0x10 relatif terhadap awal MMIO EHCI kami), ada satu byte - panjang register Kemampuan.
Register kemampuan
Pada offset 2, register
HCIVERSION berada - nomor revisi HC ini, yang menempati 2 byte dan berisi versi revisi BCD (BCD apa yang dapat ditemukan di Wikipedia).
Pada offset +4, register
HCSPARAMS berada , ukurannya 2 kata, berisi parameter struktural perangkat dan bitnya menunjukkan yang berikut:
- Bit 16 - Indikator Port - LED yang tersedia untuk perangkat USB yang terhubung.
- Bit 15:12 - jumlah pengontrol pengiring yang ditugaskan untuk pengontrol ini
- Bit 11: 8 - jumlah port pada pengontrol pendamping
- Bit 7 - Aturan Routing Port - menunjukkan bagaimana port ini dipetakan ke port pendamping
- Bit 4 - Port Power Control - menunjukkan apakah perlu menyalakan daya untuk setiap port, 0 - daya disediakan secara otomatis
- Bits 3: 0 - jumlah port untuk pengontrol ini.
- Pada offset +8 terletak register HCCPARAMS - ia menunjukkan parameter kompatibilitas, bitnya berarti sebagai berikut:
- Bit 2 - ketersediaan antrian sinkron,
- Bit 1 - ketersediaan antrian periodik (berurutan)
- Kompatibilitas bit 0 - 64 bit
Register operasi
Pada offset 0, register
USBCMD adalah register perintah controller, bit-bitnya berarti sebagai berikut:
- Bit 23:16 - Interrupt Threshold Control - menunjukkan berapa banyak mikro-frame yang akan digunakan untuk satu frame biasa. Semakin banyak, semakin cepat, tetapi jika lebih dari 8, maka mikro-frame akan diproses pada kecepatan yang sama seperti untuk 8.
- Bit 6 - interupsi setelah setiap transaksi dalam antrian asinkron,
- Bit 5 - adalah antrian asinkron yang digunakan
- Bit 4 - penggunaan antrian berurutan,
- Bit 3: 2 - ukuran FrameList'a (lebih lanjut tentang itu nanti). 0 berarti 1024 elemen, 1 - 512, 2 - 256, 3 - dicadangkan
- Bit 1 - Set untuk mengatur ulang pengontrol host.
- Bit 0 - Run / Stop
.
Selanjutnya, pada offset +4, ada register
USBSTS - status pengontrol host,
- Bit 15 menunjukkan apakah antrian asinkron digunakan.
- Bit 14 menunjukkan apakah antrian berurutan sedang digunakan,
- Bit 13 - menunjukkan bahwa antrian asinkron kosong telah terdeteksi,
- Bit 12 diatur ke 1, jika terjadi kesalahan saat memproses transaksi, maka pengontrol host akan menghentikan semua antrian.
- Bit 4 diatur ke 1, jika kesalahan serius terjadi, pengontrol host menghentikan semua antrian.
- Bit 3 FrameList (Register) Rollover - atur ke 1 ketika pengontrol host memproses seluruh frameList.
- Bit 1 - USB Error Interrupt - Apakah saya menghasilkan interupsi kesalahan?
- Bit 0 - USB Interrupt - ditetapkan setelah pemrosesan transaksi berhasil, jika IOC diinstal pada TD
Tidak lelah? Anda dapat menuangkan burung camar yang kuat dan membawa hati, kami berada di awal!
Pada offset +8, ada register
USBINTR - interrupt enable register
Agar tidak menulis untuk waktu yang lama, dan lebih dari itu, agar Anda tidak membaca untuk waktu yang lama, nilai bit register ini dapat ditemukan dalam spesifikasi, tautan ke sana akan tertinggal di bawah. Di sini saya hanya menulis 0, karena Saya sama sekali tidak memiliki keinginan untuk menulis penangan, interupsi peta, dll., Jadi ini saya pikir hampir tidak ada gunanya.
Pada offset +12 (0x0C), register
FRINDEX berada , di mana nomor frame saat ini terletak, dan saya ingin mencatat bahwa 4 bit terakhir menunjukkan nomor frame mikro, di bagian atas 28 bit nomor frame (nilainya juga belum tentu lebih kecil dari ukuran frameList) Tetapi jika Anda membutuhkan indeks, lebih baik membawanya dengan mask 0x3FF (atau 0x1FF, dll.).
Register
CTRLDSSEGMENT berada pada offset + 0x10, ini menunjukkan pengendali host 32 bit paling signifikan dari alamat frame sheet.
Register
PERIODICLISTBASE memiliki offset + 0x14, Anda dapat memasukkan 32 bit frame sheet yang lebih rendah ke dalamnya, perhatikan bahwa alamat tersebut harus disejajarkan dengan ukuran halaman memori (4096).
Register
ASYNCLISTADDR memiliki offset + 0x18, Anda dapat memasukkan alamat antrian asinkron di dalamnya, perhatikan bahwa itu harus disejajarkan pada batas 32 byte, sementara itu harus dalam empat gigabytes pertama dari memori fisik.
Register
CONFIGFLAG menunjukkan apakah perangkat dikonfigurasi. Anda harus menetapkan bit 0 setelah menyelesaikan pengaturan perangkat, ia memiliki offset + 0x40.
Mari kita beralih ke register port. Setiap port memiliki register status-perintahnya sendiri, setiap register port diimbangi
+ 0x44 + (PortNumber - 1) * 4 , bit-bitnya berarti sebagai berikut:
- Bit 12 - port power, 1 - power dipasok, 0 - no.
- Bit 8 - Port Rest - diatur untuk mengatur ulang perangkat.
- Bit 3 - Port Enable / Disable Change - atur ketika mengubah status "inklusi" port.
- Bit 2 - port on / off.
- Bit 1 - Mengubah status koneksi, diatur ke 1, misalnya, jika Anda menghubungkan atau melepas perangkat USB.
- Bit 0 - status koneksi, 1 - terhubung, 0 - no.
Sekarang mari kita beralih ke jus itu sendiri.
Transfer Data dan Struktur Permintaan
Mengatur struktur untuk memproses permintaan termasuk antrian dan transfer deskriptor (TDs).
Saat ini, kami hanya akan mempertimbangkan 3 struktur.
Daftar berurutan
Daftar berurutan (Periodik, Pereodik) disusun sebagai berikut:

Seperti yang Anda lihat dalam diagram, pemrosesan dimulai dengan memperoleh bingkai yang diinginkan dari bingkai sheet, masing-masing elemennya menempati 4 byte dan memiliki struktur sebagai berikut:

Seperti yang dapat Anda lihat dalam gambar, transfer antrian / descriptor diselaraskan pada batas 32 byte, bit 0 berarti bahwa pengontrol host tidak akan memproses elemen ini, bit 3: 1 menunjukkan jenis apa yang akan diproses oleh pengontrol host: 0 - isosynchronous TD (iTD), 1 - turn, 2 dan 3 dalam artikel ini saya tidak akan pertimbangkan.
Antrian asinkron
Pengontrol host memproses antrian ini hanya ketika frame berurutan kosong atau pengontrol host telah memproses seluruh daftar seri.
Antrian asinkron adalah penunjuk ke antrian yang berisi antrian lain yang perlu diproses. Skema:

qTD (Penjelasan Transfer Elemen Antrian)
TD ini memiliki struktur berikut:
Next qTD Pointer - pointer ke kelanjutan antrian untuk diproses (untuk Eksekusi Horizontal), bit 0 Next qTD Pointer menunjukkan bahwa tidak ada lagi antrian.
qTD Token - TD token, menunjukkan parameter transfer data:
- Bit 31 - Data Toggle (lebih lanjut tentang itu nanti)
- Bit 30:16 - jumlah data yang ditransfer, setelah penyelesaian transaksi, nilainya berkurang dengan jumlah data yang ditransfer.
- Bit 15 - IOC - Interrupt On Complete - menyebabkan gangguan setelah pemrosesan deskriptor selesai.
- Bit 14:12 menunjukkan jumlah buffer saat ini ke / dari mana data dipertukarkan, lebih lanjut tentang ini nanti.
- Bit 11:10 - jumlah kesalahan yang diizinkan. Tabel ini menunjukkan kapan jumlah kesalahan berkurang:

Catatan Kaki 1 - mendeteksi Babble atau Stall secara otomatis menghentikan eksekusi kepala antrian. Catatan Kaki 3 - Kesalahan buffer data adalah masalah dengan host. Mereka tidak memperhitungkan coba ulang perangkat. - 9: 8 - Kode PID - jenis token: 0 - token ke input (dari host ke perangkat), 1 - token ke output (dari perangkat ke host), 2 - token “SETUP”
- Bits 7: 0 menunjukkan status TD:
Bit 7 menunjukkan bahwa TD dalam keadaan aktif (mis., Pengendali host memproses TD ini)
Bit 6 - Dihentikan - menunjukkan bahwa kesalahan telah terjadi dan eksekusi TD telah berhenti.
Bit 4 - Babble Detected - jumlah data yang kami kirim ke perangkat, atau per revolusi, kurang dari yang kami kirimkan, mis., Perangkat mengirimi kami 100 byte data, dan kami hanya membaca 50 byte, dan kemudian 50 lainnya, Bit yang Dihentikan juga akan diatur jika bit ini disetel ke 1.
Bit 3 - Kesalahan Transaksi - Kesalahan terjadi selama transaksi.
qTD Buffer Page Pointer List - salah satu dari 5 buffer. Ini berisi tautan ke mana dalam memori transaksi harus dilakukan (mengirim data ke perangkat / menerima data dari perangkat), semua alamat dalam buffer, kecuali yang pertama, harus disejajarkan dengan ukuran halaman (4096 byte).
Kepala baris
Kepala Antrian memiliki struktur berikut:
Queue Head Horizontal Link Pointer - penunjuk ke antrian berikutnya, bit 2: 1 memiliki nilai berikut tergantung pada jenis antrian:
Kemampuan / Karakteristik Endpoint - karakteristik antrian:
- Bit 26:16 berisi ukuran paket maksimum untuk transmisi
- Bit 14: Data Toggle Control - menunjukkan di mana pengontrol host harus mengambil nilai Data Toggle awal, 0 - mengabaikan bit DT dalam qTD, menyimpan bit DT untuk kepala antrian.
- Bit 13:12 - karakteristik laju transmisi:

- Bits 11: 8 - nomor titik akhir yang diminta permintaannya
- Bit 6: 0 - alamat perangkat
Kemampuan Endpoint: Antrian Kepala DWord 2 - kelanjutan dari kata ganda sebelumnya:
- Bit 29:23 - Nomor Hub
- Bit 22:16 - Alamat hub
Current qTD Link Pointer - penunjuk ke qTD saat ini.
Kami lolos ke yang paling menarik.
Pengemudi EHCI
Mari kita mulai dengan pertanyaan apa yang bisa dipenuhi EHCI. Ada 2 jenis permintaan: Kontrol - perintah ala, dan Massal - ke titik akhir, untuk pertukaran data, misalnya, sebagian besar drive flash USB (USB MassStorage) menggunakan tipe transfer data Massal / Massal / Massal. Mouse dan keyboard juga menggunakan permintaan Massal untuk transfer data.
Inisialisasi EHCI dan konfigurasikan antrian asinkron dan berurutan:
Sebenarnya, kode untuk mengatur ulang port ke keadaan semula:
volatile u32 *reg = &hc->opRegs->ports[port];
Kontrol permintaan ke perangkat:
static void EhciDevControl(UsbDevice *dev, UsbTransfer *t) { EhciController *hc = (EhciController *)dev->hc; UsbDevReq *req = t->req;
Kode Pemrosesan Antrian:
if (qh->token & TD_TOK_HALTED) { t->success = false; t->complete = true; } else if (qh->nextLink & PTR_TERMINATE) if (~qh->token & TD_TOK_ACTIVE) { if (qh->token & TD_TOK_DATABUFFER) kprintf(" Data Buffer Error\n"); if (qh->token & TD_TOK_BABBLE) kprintf(" Babble Detected\n"); if (qh->token & TD_TOK_XACT) kprintf(" Transaction Error\n"); if (qh->token & TD_TOK_MMF) kprintf(" Missed Micro-Frame\n"); t->success = true; t->complete = true; } if (t->complete) ....
Dan sekarang permintaan titik akhir (permintaan massal)
static void EhciDevIntr(UsbDevice *dev, UsbTransfer *t) { EhciController *hc = (EhciController *)dev->hc;
Saya pikir topiknya cukup menarik, di Internet dalam bahasa Rusia hampir tidak ada dokumentasi, deskripsi, dan artikel tentang topik ini, dan jika ada, itu sangat kabur. Jika topik bekerja dengan pengembangan perangkat keras dan OS menarik, maka ada banyak yang bisa diceritakan.
Dermaga:
Spesifikasi