Komunikasi antara driver dan perangkat dengan metode _HID ACPI menggunakan GPIO dari pengontrol Lynxpoint sebagai contoh

Pernyataan masalah


Linux memiliki antarmuka standar untuk bekerja dengan GPIO melalui sysfs. Dokumentasi untuk itu dapat ditemukan di sini .

Singkatnya, ada file "ekspor" dan "tidak ekspor" di folder "/ sys / class / gpio". Dengan menulis angka X ke file ekspor, Anda dapat membuka antarmuka di ruang pengguna untuk mengontrol GPIOX

#    user space   GPIO12 $ echo 12 > /sys/class/gpio/export 

Setelah membuka antarmuka, folder / sys / class / gpio / gpioX / akan muncul di mana akan ada file seperti "nilai" atau "arah", dan dengan menulis "dalam" atau "keluar" ke file "arah" dan menulis 1 atau 0 ke file "Nilai" dapat mengontrol keluaran GPIO langsung dari baris perintah.

 #  GPIO   $ echo "out" > /sys/class/gpio/gpio12/direction #  1   GPIO $ echo 1 > /sys/class/gpio/gpio12/value 

Agar perintah "echo X> / sys / class / gpio / export" untuk membuat folder "gpioX", driver pengontrol GPIO harus terdaftar di kernel, yang membuka antarmuka ke jalur GPIO.

Kebetulan saya sedang mengerjakan porting coreboot untuk custom board berdasarkan prosesor Intel Haswell i7 [Bagi mereka yang tidak tahu, coreboot adalah open source proyek open source proyek BIOS ( https://www.coreboot.org/ ) ] Jembatan selatan LynxpointLP di mana terdapat 94 garis GPIO dibangun ke prosesor saya. Dan saya ingin membukanya di sysfs ...

Pemecahan masalah (komunikasi driver dan perangkat di Linux)


Setelah pencarian singkat pada kode kernel, saya menemukan bahwa driver ini telah ditulis, terletak di file "drivers \ gpio \ gpio-lynxpoint.c" dan diaktifkan menggunakan Kconfig

 config GPIO_LYNXPOINT tristate "Intel Lynxpoint GPIO support" depends on ACPI && X86 select GPIOLIB_IRQCHIP help driver for GPIO functionality on Intel Lynxpoint PCH chipset Requires ACPI device enumeration code to set up a platform device. 

Opsi GPIO_LYNXPOINT diaktifkan di kernel yang saya kerjakan, namun, tidak ada folder "gpiochipN" tunggal untuk pengontrol GPIO di folder "/ sys / class / gpio /" (yang seharusnya), dan bahkan skrip seperti itu tidak mengarah ke ekspor semua garis.

 $ for i in {0..255}; do echo $i > /sys/class/gpio/export; done 

Melihat kode coreboot atau melihat dokumentasi untuk jembatan selatan ini, Anda dapat melihat bahwa pengontrol GPIO bukan perangkat PCI yang terpisah. Ini adalah bagian dari perangkat PCI lain: LPC Interface Bridge. Menggunakan register ruang konfigurasi PCI pada perangkat ini, Anda harus mengaktifkan pengendali GPIO dan menetapkannya BASE_ADDRESS di ruang I / O. Ini akan membuka jendela dalam ruang I / O 1KV. Dengan menulis / membaca byte di jendela ini, Anda dapat mengontrol baris GPIO.

Apa yang bisa kita lihat dalam kode coreboot:

southbridge \ intel \ lynxpoint \ pch.h:

 #define DEFAULT_GPIOBASE 0x1400 #define DEFAULT_GPIOSIZE 0x400 ... #define GPIO_BASE 0x48 /* LPC GPIO Base Address Register */ #define GPIO_CNTL 0x4C /* LPC GPIO Control Register */ ... /* PCI Configuration Space (D31:F0): LPC */ #define PCH_LPC_DEV PCI_DEV(0, 0x1f, 0) 

southbridge \ intel \ lynxpoint \ early_pch.c:

 /* Setup GPIO Base Address */ pci_write_config32(PCH_LPC_DEV, GPIO_BASE, DEFAULT_GPIOBASE|1); /* Enable GPIO functionality. */ pci_write_config8(PCH_LPC_DEV, GPIO_CNTL, 0x10); 

Jika kita melihat register perangkat LPC di Linux melalui "lspci -xxx", kita akan melihat bahwa data yang direkam oleh kita ada dalam register ini. Jadi semuanya tampaknya sudah diatur sebagaimana mestinya.

Melanjutkan melihat kode driver, saya perhatikan bahwa driver Linux berkomunikasi dengan perangkat melalui bidang .acpi_match_table. Karena perangkat kami tidak dapat disebutkan (tidak terletak pada PCI atau bus USB), driver platform diperlukan untuk itu, dan koneksi driver ini dengan perangkat adalah melalui tabel ACPI. Kasus biasa untuk x86, dalam kasus ARM, kami akan mendaftarkan perangkat kami di DeviceTree, atau menggunakan kode lama di kernel.

driver \ gpio \ gpio-lynxpoint.c:

 static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { { "INT33C7", 0 }, { "INT3437", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); static struct platform_driver lp_gpio_driver = { .probe = lp_gpio_probe, .remove = lp_gpio_remove, .driver = { .name = "lp_gpio", .pm = &lp_gpio_pm_ops, .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match), }, }; 

Ia bekerja seperti ini: jika kernel, ketika mem-parsing tabel ACPI, melihat perangkat dengan pengenal _HID "INT33C7" di dalamnya, maka itu akan mencoba untuk menemukan driver platform untuk itu dengan pengidentifikasi yang cocok di bidang struktur ".driver-> acpi_match_table".

Ketika kecocokan ditemukan, Linux akan menjalankan fungsi driver .probe.

Ternyata, kode ACPI untuk perangkat ini disajikan dalam coreboot, saya hanya berkomentar. Mengomentari karena fakta bahwa untuk perangkat ini Windows tidak dapat menemukan driver dan menampilkan "Perangkat tidak dikenal" di manajer perangkat. Lebih lanjut tentang ini di bawah ini.

Jadi kami tertarik pada informasi dari file tersebut
src \ southbridge \ intel \ lynxpoint \ acpi \ serialio.asl (kode ini sedikit disederhanakan):

 /*     * src\southbridge\intel\lynxpoint\pch.h * #define DEFAULT_GPIOBASE 0x1400 * #define DEFAULT_GPIOSIZE 0x400 */ Scope (\_SB) { Device (PCI0) { ... Device (GPIO) { // GPIO Controller Name (_HID, "INT33C7") Name (_CID, "INT33C7") Name (_UID, 1) Name (RBUF, ResourceTemplate() { DWordIo (ResourceProducer, MinFixed, // IsMinFixed MaxFixed, // IsMaxFixed PosDecode, // Decode EntireRange, // ISARanges 0x00000000, // AddressGranularity 0x00000000, // AddressMinimum 0x00000000, // AddressMaximum 0x00000000, // AddressTranslation 0x00000001, // RangeLength , // ResourceSourceIndex , // ResourceSource BAR0) Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, , , ) {14} }) Method (_CRS, 0, NotSerialized) { CreateDwordField (^RBUF, ^BAR0._MIN, BMIN) CreateDwordField (^RBUF, ^BAR0._MAX, BMAX) CreateDwordField (^RBUF, ^BAR0._LEN, BLEN) Store (DEFAULT_GPIOSIZE, BLEN) Store (DEFAULT_GPIOBASE, BMIN) Store (Subtract (Add (DEFAULT_GPIOBASE, DEFAULT_GPIOSIZE), 1), BMAX) Return (RBUF) } Method (_STA, 0, NotSerialized) { Return (0xF) } } ... } } 

Untuk memahami kode ini secara terperinci, Anda harus membiasakan diri dengan sintaks ASL dalam spesifikasi ACPI .

Namun singkatnya, kode ini menciptakan perangkat dengan pengenal "INT33C7" yang memiliki 2 sumber daya:

 I/O memory: 1400-17ff; IRQ: 14; 

Di dalam fungsi .probe Linux, driver menerima sumber daya perangkat di atas sebagai berikut:

 io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 

Berdasarkan data ini, kode driver akan mengisi struktur gpio_chip dan mendaftarkan pengendali gpio dalam sistem, yang akan membuatnya dapat diakses melalui antarmuka sysfs.

Setelah mengembalikan kode ASL perangkat dan mengkompilasi ulang citra BIOS, sistem berhasil mengakses GPIO melalui sysfs.

Untuk memulai, folder "gpiochip162" muncul di / sys / class / gpio. Folder ini berisi file "base" dan "ngpio". File dasar bertanggung jawab untuk jumlah GPIO pertama dari kontroler ini, ngpio untuk nomor mereka.

 $ cat /sys/class/gpio/gpiochip162/base 162 $ cat /sys/class/gpio/gpiochip162/ngpio 94 

Dengan demikian, semuanya diekspor sebagaimana mestinya. Kami menjalankan skrip:

 $ for i in {162..255}; do echo $i > /sys/class/gpio/export; done 

Setelah itu, subfolder gpioN akan muncul di folder / sys / class / gpio /, di dalamnya akan terdapat file untuk mengontrol status baris.

Beberapa komentar:

  • Folder / sys / class / gpio162 / bertanggung jawab untuk mengelola GPIO0, folder / sys / class / gpio163 / folder bertanggung jawab atas GPIO1 Pergeseran ini terjadi karena fakta bahwa driver selama inisialisasi struktur kontrol "struct gpio_chip" ditugaskan "gc-> base = -1;". Yaitu, saya meninggalkan kernel untuk memilih angka sendiri. Ini umumnya tidak kritis, tetapi perlu diingat tentang hal itu.
  • Akses diberikan hanya ke jalur GPIO yang dikonfigurasi sebagai GPIO, dan bukan sebagai fitur Southbridge asli. Untuk jalur seperti itu, driver menampilkan informasi dalam dmesg: "gpio% d dicadangkan untuk ACPI". Dalam kasus coreboot, GPIO dikonfigurasi dalam file "gpio.h" di folder dengan motherboard.
  • Perangkat dan driver juga dapat dipetakan menggunakan metode _CID (Compatible ID), dan dokumentasi untuk topik kami di kernel disajikan dalam dokumen โ€œenumerasi perangkat berbasis ACPIโ€

Perlu dicatat bahwa perangkat INT33C7 tidak memiliki 2 motherboard berpemilik pada chipset yang sama dalam tabel ACPI (dari IBASE dan DFI). Benar, ada kemungkinan garis GPIO tidak keluaran (saya tidak melihat dokumentasi pada saat itu secara rinci).

Identifier "INT33C7"


Setelah meningkatkan fungsionalitas sysfs, saya punya pertanyaan, dari mana nomor identifikasi "INT33C7" berasal?

Setelah melihat dokumentasi untuk metode _HID, menjadi jelas bahwa itu layak dilihat di http://www.uefi.org/PNP_ACPI_Registry

_HID (ID Perangkat Keras)
_HID (ID Perangkat Keras)
Objek ini digunakan untuk memasok OSPM dengan ID PNP perangkat atau ID ACPI *
Saat mendeskripsikan platform, penggunaan objek _HID apa pun adalah opsional. Namun, objek _HID harus
digunakan untuk menggambarkan perangkat apa pun yang akan disebutkan oleh OSPM. OSPM hanya menyebutkan perangkat
ketika tidak ada enumerator bus yang dapat mendeteksi ID perangkat. Misalnya, perangkat pada bus ISA
disebutkan oleh OSPM. Gunakan objek _ADR untuk menggambarkan perangkat yang disebutkan oleh enumerator bus
selain OSPM.

Argumen:
Tidak ada

Nilai Pengembalian:
Integer atau String yang berisi HID
Objek _HID mengevaluasi baik ID jenis EISA numerik terkompresi 32-bit atau string. Jika a
string, format harus berupa PNP alfanumerik atau ACPI ID tanpa tanda bintang atau terkemuka lainnya
karakter.

ID PNP yang valid harus dalam bentuk "AAA ####" di mana A adalah huruf besar dan # adalah hex
digit. ID ACPI yang valid harus dalam bentuk "NNNN ####" di mana N adalah huruf besar atau
digit ('0' - '9') dan # adalah digit hex. Spesifikasi ini mencadangkan string "ACPI" hanya untuk digunakan
dengan daftar perangkat yang ditentukan. Selanjutnya cadangan semua string yang mewakili 4 digit HEX untuk
penggunaan eksklusif dengan ID Vendor yang ditetapkan PCI.

* -PPN ID dan ACPI ID Registry ada di http://www.uefi.org/PNP_ACPI_Registry

Ada 3 poin di tautan ini:

  • semua jenis pengidentifikasi 3 huruf (PNP ID) ditunjukkan di sini
  • ID PNP dimulai dengan "PNP" yang disediakan oleh Microsoft ditunjukkan di sini.
  • semua jenis pengidentifikasi 4 huruf (ACPI ID) ditunjukkan di sini

Tidak terlalu jelas mengapa, tetapi dari daftar ID PNP Anda dapat menemukan bahwa pengidentifikasi โ€œINTโ€ dicadangkan di INTERPHASE CORPORATION:

 INTERPHASE CORPORATION INT 11/29/1996 

Rupanya, satu daftar pengidentifikasi perangkat lengkap (bagian huruf + digital) tidak dipublikasikan. Tetapi dengan bantuan Google adalah mungkin untuk menemukan daftar perangkat dan _HID mereka misalnya di sini atau di sini .

Mereka mengindikasikan:

 INT33C7=Intel Serial I/O GPIO Host Controller 

Dan dilihat dari sisa baris dari daftar ini, semua perangkat INTxxxx adalah perangkat Intel (sekarang kedengarannya cukup jelas, tetapi koneksi dengan INTERPHASE CORPORATION masih belum jelas; itu juga tidak terlalu jelas mengapa penomoran dimulai dengan jumlah yang begitu besar, tetapi terlihat pada Kebijaksanaan Intel).

Driver komunikasi dan perangkat di Windows


Setelah memuaskan rasa ingin tahu saya, saya memutuskan untuk mengunduh Windows di papan tulis saya. Seperti yang diharapkan, sistem tidak dapat menemukan driver untuk perangkat. Tidak ada bantuan dari driver untuk papan IBASE dan DFI, yang dapat dimengerti, karena di BIOS papan ini perangkat ini tidak ditunjukkan.

Saya berhasil menemukan driver di situs web Microsoft

Namun, di sana driver ini hanya disajikan untuk Windows 8.1 dan lebih tinggi. Saya masih bekerja dengan Windows 7.

Namun demikian, saya mencoba mengunduh salah satu driver dan menentukan foldernya ketika mencari driver untuk perangkat saya yang tidak dikenal.

Namun, operator tidak dapat memetakan driver ke perangkat. Meskipun file inf jelas berisi informasi tentang perangkat INT33C7.

 [Manufacturer] %INTEL%=Intel,NTamd64.6.3 [Intel.NTamd64.6.3] %iaLPSS_GPIO.DeviceDesc_LPT%=iaLPSS_GPIO_Device, ACPI\INT33C7 %iaLPSS_GPIO.DeviceDesc_WPT%=iaLPSS_GPIO_Device, ACPI\INT3437 

Dalam proses penguraian file INF, ternyata bagian [Pabrikan] dengan jelas menunjukkan bahwa itu tidak dimaksudkan untuk sistem saya:

Apa yang dimaksud Intel.NTamd64.6.3 dapat dipahami dari deskripsi :

 nt[Architecture][.[OSMajorVersion][.[OSMinorVersion] OSMajorVersion=6 => Windows 7/Windows 8.1/Windows Server 2012 R2/... OSMinorVersion=3 => Windows 8.1/Windows Server 2012 R2 

Mencoba untuk mendorong driver Windows 7 dengan mengganti Intel.NTamd64.6.3 dengan Intel.NTamd64.6.1, untuk membuatnya lebih ringan, gagal, karena memberi saya layar biru kematian dan OS yang tidak dapat di-boot, jadi saya harus melakukan pemulihan.

Driver untuk Win7 hanya ditemukan di situs web yang tidak dapat dipahami di Internet, dan kemudian setelah itu perangkat di manajer perangkat ditampilkan dengan tanda seru.

Menyadari ketidakberdayaannya, saya memutuskan untuk menguji fungsionalitas pada Windows 10. Ada kejutan yang menyenangkan. Perangkat Lunak Intel Chipset Device (INF Update Utility) menginstal driver untuk controller saya tanpa masalah.



Seperti yang Anda lihat, perangkat ini memiliki sumber daya yang ditunjukkan oleh kami.



Secara teori, setelah menginstal driver dengan pengontrol GPIO, kemungkinan besar akan memungkinkan untuk bekerja melalui fungsi IOCTL ( seperti dalam dokumen ini) .

Namun, tidak ada tugas pemrograman GPIO dari Windows, jadi pencarian dokumen yang sama untuk chipset saya ditunda.



Kesimpulan:


Artikel ini memeriksa koneksi antara driver dan perangkat menggunakan metode _HID ACPI. Komunikasi semacam itu mungkin diperlukan pada sistem x86 untuk perangkat yang tidak dapat disebutkan.

  • Dalam hal Linux, komunikasi dengan driver adalah via .acpi_match_table
  • Dalam kasus Windows, komunikasi dengan pengemudi adalah melalui file INF

Source: https://habr.com/ru/post/id429336/


All Articles