Mengaktifkan akses mode pengguna ke GPIO, I2C, dan SPI

Di Windows 10 dan yang lebih baru, API disediakan dengan akses langsung dari mode pengguna ke input/output tujuan umum (GPIO), Inter-Integrated Circuit (I2C), Serial Peripheral Interface (SPI), dan universal asynchronous receiver-transmitter (UART). Papan pengembangan seperti Raspberry Pi 2 mengekspos subset koneksi ini, yang memungkinkan Anda memperluas modul komputasi dasar dengan sirkuit kustom untuk mengatasi aplikasi tertentu. Bus tingkat rendah ini biasanya dibagikan dengan fungsi onboard penting lainnya, hanya dengan subset pin GPIO dan bus yang terekspos pada header. Untuk mempertahankan stabilitas sistem, perlu untuk menentukan pin dan bus mana yang aman untuk modifikasi oleh aplikasi mode pengguna.

Dokumen ini menjelaskan cara menentukan konfigurasi ini di Konfigurasi Tingkat Lanjut dan Antarmuka Daya (ACPI), dan menyediakan alat untuk memvalidasi bahwa konfigurasi ditentukan dengan benar.

Penting

Audiens untuk dokumen ini adalah Pengembang Unified Extensible Firmware Interface (UEFI) dan ACPI. Beberapa keakraban dengan ACPI, penulisan Bahasa Sumber ACPI (ASL), dan SpbCx/GpioClx diasumsikan.

Akses mode pengguna ke bus tingkat rendah di Windows di-pipa melalui kerangka kerja dan SpbCx yang adaGpioClx. Driver baru bernama RhProxy, tersedia di Windows IoT Core dan Windows Enterprise, mengekspos GpioClx dan SpbCx sumber daya ke mode pengguna. Untuk mengaktifkan API, simpul perangkat untuk rhproxy harus dideklarasikan dalam tabel ACPI Anda dengan setiap sumber daya GPIO dan SPB yang harus diekspos ke mode pengguna. Dokumen ini menjelaskan penulisan dan verifikasi ASL.

ASL menurut contoh

Mari kita berjalan melalui deklarasi simpul perangkat rhproxy pada Raspberry Pi 2. Pertama, buat deklarasi perangkat ACPI dalam cakupan \_SB.

Device(RHPX)
{
    Name(_HID, "MSFT8000")
    Name(_CID, "MSFT8000")
    Name(_UID, 1)
}
  • _HID – Id Perangkat Keras. Atur ini ke ID perangkat keras khusus vendor.
  • _CID – Id yang Kompatibel. Harus "MSFT8000".
  • _UID – Id Unik. Atur ke 1.

Selanjutnya kami mendeklarasikan masing-masing sumber daya GPIO dan SPB yang harus diekspos ke mode pengguna. Urutan di mana sumber daya dideklarasikan penting karena indeks sumber daya digunakan untuk mengaitkan properti dengan sumber daya. Jika ada beberapa bus I2C atau SPI yang terekspos, bus pertama yang dideklarasikan dianggap sebagai bus 'default' untuk jenis tersebut GetDefaultAsync() , dan akan menjadi instans yang dikembalikan oleh metode Windows.Devices.I2c.I2cController dan Windows.Devices.Spi.SpiController.

SPI

Raspberry Pi memiliki dua bus SPI yang terekspos. SPI0 memiliki dua baris pilihan chip perangkat keras dan SPI1 memiliki satu baris pilihan chip perangkat keras. Satu deklarasi sumber daya SPISerialBus() diperlukan untuk setiap jalur pemilihan chip untuk setiap bus. Dua deklarasi sumber daya SPISerialBus berikut adalah untuk dua baris pemilihan chip pada SPI0. Bidang DeviceSelection berisi nilai unik yang ditafsirkan driver sebagai pengidentifikasi baris pilih chip perangkat keras. Nilai persis yang Anda masukkan ke bidang DeviceSelection tergantung pada bagaimana driver Anda menginterpretasikan bidang pendeskripsi koneksi ACPI ini.

Catatan

Artikel ini berisi referensi ke istilah budak—istilah yang tidak disambungkan microsoft, dan telah berhenti menggunakan dalam produk dan dokumentasi baru. Ketika istilah ini dihapus dari perangkat lunak, kami akan menghapusnya dari artikel ini.

// Index 0
SPISerialBus(              // SCKL - GPIO 11 - Pin 23
                           // MOSI - GPIO 10 - Pin 19
                           // MISO - GPIO 9  - Pin 21
                           // CE0  - GPIO 8  - Pin 24
    0,                     // Device selection (CE0)
    PolarityLow,           // Device selection polarity
    FourWireMode,          // wiremode
    0,                     // databit len: placeholder
    ControllerInitiated,   // slave mode
    0,                     // connection speed: placeholder
    ClockPolarityLow,      // clock polarity: placeholder
    ClockPhaseFirst,       // clock phase: placeholder
    "\\_SB.SPI0",          // ResourceSource: SPI bus controller name
    0,                     // ResourceSourceIndex
                           // Resource usage
    )                      // Vendor Data

// Index 1
SPISerialBus(              // SCKL - GPIO 11 - Pin 23
                           // MOSI - GPIO 10 - Pin 19
                           // MISO - GPIO 9  - Pin 21
                           // CE1  - GPIO 7  - Pin 26
    1,                     // Device selection (CE1)
    PolarityLow,           // Device selection polarity
    FourWireMode,          // wiremode
    0,                     // databit len: placeholder
    ControllerInitiated,   // slave mode
    0,                     // connection speed: placeholder
    ClockPolarityLow,      // clock polarity: placeholder
    ClockPhaseFirst,       // clock phase: placeholder
    "\\_SB.SPI0",          // ResourceSource: SPI bus controller name
    0,                     // ResourceSourceIndex
                           // Resource usage
    )                      // Vendor Data

Bagaimana perangkat lunak tahu bahwa kedua sumber daya ini harus dikaitkan dengan bus yang sama? Pemetaan antara nama ramah bus dan indeks sumber daya ditentukan dalam DSD:

Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }},

Ini membuat bus bernama "SPI0" dengan dua baris pilihan chip - indeks sumber daya 0 dan 1. Beberapa properti lagi diperlukan untuk mendeklarasikan kemampuan bus SPI.

Package(2) { "SPI0-MinClockInHz", 7629 },
Package(2) { "SPI0-MaxClockInHz", 125000000 },

Properti MinClockInHz dan MaxClockInHz menentukan kecepatan jam minimum dan maksimum yang didukung oleh pengontrol. API akan mencegah pengguna menentukan nilai di luar rentang ini. Kecepatan jam diteruskan ke driver SPB Anda di bidang _SPE deskriptor koneksi (acpi bagian 6.4.3.8.2.2).

Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }},

Properti SupportedDataBitLengths mencantumkan panjang bit data yang didukung oleh pengontrol. Beberapa nilai dapat ditentukan dalam daftar yang dipisahkan koma. API akan mencegah pengguna menentukan nilai di luar daftar ini. Panjang bit data diteruskan ke driver SPB Anda di bidang _LEN deskriptor koneksi (ACPI bagian 6.4.3.8.2.2).

Anda dapat menganggap deklarasi sumber daya ini sebagai "templat." Beberapa bidang diperbaiki pada boot sistem sementara yang lain ditentukan secara dinamis pada runtime. Bidang deskriptor SPISerialBus berikut diperbaiki:

  • DeviceSelection
  • DeviceSelectionPolarity
  • WireMode
  • SlaveMode
  • ResourceSource

Bidang berikut adalah tempat penampung untuk nilai yang ditentukan oleh pengguna saat runtime:

  • DataBitLength
  • Koneksi ionSpeed
  • ClockPolarity
  • ClockPhase

Karena SPI1 hanya berisi satu baris pemilihan chip, satu SPISerialBus() sumber daya dinyatakan:

// Index 2
SPISerialBus(              // SCKL - GPIO 21 - Pin 40
                           // MOSI - GPIO 20 - Pin 38
                           // MISO - GPIO 19 - Pin 35
                           // CE1  - GPIO 17 - Pin 11
    1,                     // Device selection (CE1)
    PolarityLow,           // Device selection polarity
    FourWireMode,          // wiremode
    0,                     // databit len: placeholder
    ControllerInitiated,   // slave mode
    0,                     // connection speed: placeholder
    ClockPolarityLow,      // clock polarity: placeholder
    ClockPhaseFirst,       // clock phase: placeholder
    "\\_SB.SPI1",          // ResourceSource: SPI bus controller name
    0,                     // ResourceSourceIndex
                           // Resource usage
    )                      // Vendor Data

Deklarasi nama ramah yang menyertainya – yang diperlukan – ditentukan dalam DSD dan mengacu pada indeks deklarasi sumber daya ini.

Package(2) { "bus-SPI-SPI1", Package() { 2 }},

Ini membuat bus bernama "SPI1" dan mengaitkannya dengan indeks sumber daya 2.

Persyaratan Driver SPI

  • Harus menggunakan SpbCx atau kompatibel dengan SpbCx
  • Pasti lulus Tes MITT SPI
  • Harus mendukung kecepatan jam 4Mhz
  • Harus mendukung panjang data 8-bit
  • Harus mendukung semua Mode SPI: 0, 1, 2, 3

I2C

Selanjutnya, kami mendeklarasikan sumber daya I2C. Raspberry Pi mengekspos satu bus I2C pada pin 3 dan 5.

// Index 3
I2CSerialBus(              // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1)
    0xFFFF,                // SlaveAddress: placeholder
    ,                      // SlaveMode: default to ControllerInitiated
    0,                     // ConnectionSpeed: placeholder
    ,                      // Addressing Mode: placeholder
    "\\_SB.I2C1",          // ResourceSource: I2C bus controller name
    ,
    ,
    )                      // VendorData

Deklarasi nama ramah yang menyertainya – yang diperlukan – ditentukan dalam DSD:

Package(2) { "bus-I2C-I2C1", Package() { 3 }},

Ini mendeklarasikan bus I2C dengan nama ramah "I2C1" yang mengacu pada indeks sumber daya 3, yang merupakan indeks sumber daya I2CSerialBus() yang kami deklarasikan di atas.

Bidang deskriptor I2CSerialBus() berikut diperbaiki:

  • SlaveMode
  • ResourceSource

Bidang berikut adalah tempat penampung untuk nilai yang ditentukan oleh pengguna saat runtime.

  • SlaveAddress
  • Koneksi ionSpeed
  • AddressingMode

Persyaratan Driver I2C

  • Harus menggunakan SpbCx atau kompatibel dengan SpbCx
  • Pasti lulus Tes MITT I2C
  • Harus mendukung alamat 7-bit
  • Harus mendukung kecepatan jam 100kHz
  • Harus mendukung kecepatan jam 400kHz

GPIO

Selanjutnya, kami mendeklarasikan semua pin GPIO yang terekspos ke mode pengguna. Kami menawarkan panduan berikut dalam memutuskan pin mana yang akan diekspos:

  • Deklarasikan semua pin pada header yang diekspos.
  • Deklarasikan pin yang terhubung ke fungsi onboard yang berguna seperti tombol dan LED.
  • Jangan nyatakan pin yang dicadangkan untuk fungsi sistem atau tidak terhubung ke apa pun.

Blok ASL berikut mendeklarasikan dua pin – GPIO4 dan GPIO5. Pin lain tidak ditampilkan di sini untuk brevity. Lampiran C berisi sampel skrip powershell yang dapat digunakan untuk menghasilkan sumber daya GPIO.

// Index 4 – GPIO 4
GpioIO(Shared, PullUp, , , , “\\_SB.GPI0”, , , , ) { 4 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, “\\_SB.GPI0”,) { 4 }

// Index 6 – GPIO 5
GpioIO(Shared, PullUp, , , , “\\_SB.GPI0”, , , , ) { 5 }
GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, “\\_SB.GPI0”,) { 5 }

Persyaratan berikut harus diamati saat mendeklarasikan pin GPIO:

  • Hanya pengontrol GPIO yang dipetakan memori yang didukung. Pengontrol GPIO yang berinteraksi melalui I2C/SPI tidak didukung. Driver pengontrol adalah pengontrol yang dipetakan memori jika mengatur bendera MemoryMappedController dalam struktur CLIENT_CONTROLLER_BASIC_INFORMATION sebagai respons terhadap panggilan balik CLIENT_QueryControllerBasicInformation .
  • Setiap pin memerlukan sumber daya GpioIO dan GpioInt. Sumber daya GpioInt harus segera mengikuti sumber daya GpioIO dan harus merujuk ke nomor pin yang sama.
  • Sumber daya GPIO harus diurutkan dengan menambah nomor pin.
  • Setiap sumber daya GpioIO dan GpioInt harus berisi tepat satu nomor pin dalam daftar pin.
  • Bidang ShareType dari kedua deskriptor harus Dibagikan
  • Bidang EdgeLevel dari deskriptor GpioInt harus Edge
  • Bidang ActiveLevel dari deskriptor GpioInt harus ActiveBoth
  • Bidang PinConfig
    • Harus sama dalam deskriptor GpioIO dan GpioInt
    • Harus salah satu PullUp, PullDown, atau PullNone. Ini tidak dapat berupa PullDefault.
    • Konfigurasi penarikan harus cocok dengan status power-on pin. Menempatkan pin dalam mode penarikan yang ditentukan dari status daya aktif tidak boleh mengubah status pin. Misalnya, jika lembar data menentukan bahwa pin muncul dengan penarikan, tentukan PinConfig sebagai PullUp.

Kode inisialisasi firmware, UEFI, dan driver tidak boleh mengubah status pin dari status aktifnya selama boot. Hanya pengguna yang tahu apa yang terpasang pada pin dan oleh karena itu transisi status mana yang aman. Status daya pada setiap pin harus didokumentasikan sehingga pengguna dapat merancang perangkat keras yang berinteraksi dengan benar dengan pin. Pin tidak boleh mengubah status secara tak terduga selama boot.

Mode Drive yang Didukung

Jika pengontrol GPIO Anda mendukung penarikan bawaan dan menarik resistor selain input impedansi tinggi dan output CMOS, Anda harus menentukan ini dengan properti SupportedDriveModes opsional.

Package (2) { “GPIO-SupportedDriveModes”, 0xf },

Properti SupportedDriveModes menunjukkan mode drive mana yang didukung oleh pengontrol GPIO. Dalam contoh di atas, semua mode drive berikut didukung. Properti adalah bitmask dari nilai berikut:

Nilai Bendera Drive Mode Deskripsi
0x1 InputHighImpedance Pin mendukung input impedansi tinggi, yang sesuai dengan nilai "PullNone" di ACPI.
0x2 InputPullUp Pin mendukung resistor pull-up bawaan, yang sesuai dengan nilai "PullUp" di ACPI.
0x4 InputPullDown Pin mendukung resistor pull-down bawaan, yang sesuai dengan nilai "PullDown" di ACPI.
0x8 OutputCmos Pin mendukung menghasilkan tinggi yang kuat dan rendah yang kuat (dibandingkan dengan pengosongan terbuka).

InputHighImpedance dan OutputCmos didukung oleh hampir semua pengontrol GPIO. Jika properti SupportedDriveModes tidak ditentukan, ini adalah defaultnya.

Jika sinyal GPIO melewati shifter tingkat sebelum mencapai header yang terekspos, nyatakan mode drive yang didukung oleh SOC, bahkan jika mode drive tidak akan dapat diamati pada header eksternal. Misalnya, jika pin melewati pergeser tingkat dua arah yang membuat pin muncul sebagai pengurasan terbuka dengan pull up resistif, Anda tidak akan pernah mengamati status impedansi tinggi pada header yang diekspos bahkan jika pin dikonfigurasi sebagai input impedansi tinggi. Anda masih harus menyatakan bahwa pin mendukung input impedansi tinggi.

Sematkan Penomoran

Windows mendukung dua skema penomoran pin:

  • Penomoran Pin Berurutan - Pengguna melihat angka seperti 0, 1, 2... hingga jumlah pin yang terekspos. 0 adalah sumber daya GpioIo pertama yang dideklarasikan dalam ASL, 1 adalah sumber daya GpioIo kedua yang dideklarasikan dalam ASL, dan sebagainya.
  • Penomoran Pin Asli – Pengguna melihat nomor pin yang ditentukan dalam deskriptor GpioIo, misalnya, 4, 5, 12, 13, ...
Package (2) { “GPIO-UseDescriptorPinNumbers”, 1 },

Properti UseDescriptorPinNumbers memberi tahu Windows untuk menggunakan penomoran pin asli alih-alih penomoran pin berurutan. Jika properti UseDescriptorPinNumbers tidak ditentukan atau nilainya nol, Windows akan default ke penomoran pin berurutan.

Jika penomoran pin asli digunakan, Anda juga harus menentukan properti PinCount .

Package (2) { “GPIO-PinCount”, 54 },

Properti PinCount harus cocok dengan nilai yang dikembalikan melalui properti TotalPins dalam panggilan balik GpioClx CLIENT_QueryControllerBasicInformation driver.

Pilih skema penomoran yang paling kompatibel dengan dokumentasi yang diterbitkan yang ada untuk papan Anda. Misalnya, Raspberry Pi menggunakan penomoran pin asli karena banyak diagram pinout yang ada menggunakan nomor pin BCM2835. MinnowBoardMax menggunakan penomoran pin berurutan karena ada beberapa diagram pinout yang ada, dan penomoran pin berurutan menyederhanakan pengalaman pengembang karena hanya 10 pin yang terekspos dari lebih dari 200 pin. Keputusan untuk menggunakan penomoran pin berurutan atau asli harus bertujuan untuk mengurangi kebingungan pengembang.

Persyaratan Driver GPIO

  • Harus digunakan GpioClx
  • Harus dipetakan memori di SOC
  • Harus menggunakan penanganan gangguan ActiveBoth yang ditiru

UART

Jika driver UART Anda menggunakan SerCx atau SerCx2, Anda dapat menggunakan rhproxy untuk mengekspos driver ke mode pengguna. Driver UART yang membuat antarmuka perangkat bertipe GUID_DEVINTERFACE_COMPORT tidak perlu menggunakan rhproxy. Driver kotak masuk Serial.sys adalah salah satu kasus ini.

Untuk mengekspos SerCxUART -style ke mode pengguna, deklarasikan UARTSerialBus sumber daya sebagai berikut.

// Index 2
UARTSerialBus(           // Pin 17, 19 of JP1, for SIO_UART2
    115200,                // InitialBaudRate: in bits ber second
    ,                      // BitsPerByte: default to 8 bits
    ,                      // StopBits: Defaults to one bit
    0xfc,                  // LinesInUse: 8 1-bit flags to declare line enabled
    ,                      // IsBigEndian: default to LittleEndian
    ,                      // Parity: Defaults to no parity
    ,                      // FlowControl: Defaults to no flow control
    32,                    // ReceiveBufferSize
    32,                    // TransmitBufferSize
    "\\_SB.URT2",          // ResourceSource: UART bus controller name
    ,
    ,
    ,
    )

Hanya bidang ResourceSource yang diperbaiki sementara semua bidang lain adalah tempat penampung untuk nilai yang ditentukan pada runtime oleh pengguna.

Deklarasi nama ramah yang menyertainya adalah:

Package(2) { "bus-UART-UART2", Package() { 2 }},

Ini menetapkan nama ramah "UART2" ke pengontrol, yang merupakan pengidentifikasi yang akan digunakan pengguna untuk mengakses bus dari mode pengguna.

Runtime Pin Muxing

Pin muxing adalah kemampuan untuk menggunakan pin fisik yang sama untuk fungsi yang berbeda. Beberapa periferal on-chip yang berbeda, seperti pengontrol I2C, pengontrol SPI, dan pengontrol GPIO, mungkin dirutekan ke pin fisik yang sama pada SOC. Blok mux mengontrol fungsi mana yang aktif pada pin pada waktu tertentu. Secara tradisional, firmware bertanggung jawab untuk membuat penetapan fungsi saat boot, dan penugasan ini tetap statis melalui sesi boot. Muxing pin runtime menambahkan kemampuan untuk mengonfigurasi ulang penetapan fungsi pin saat runtime. Memungkinkan pengguna untuk memilih fungsi pin pada pengembangan kecepatan runtime dengan memungkinkan pengguna untuk dengan cepat mengonfigurasi ulang pin papan, dan memungkinkan perangkat keras untuk mendukung berbagai aplikasi yang lebih luas daripada konfigurasi statis.

Pengguna menggunakan dukungan muxing untuk GPIO, I2C, SPI, dan UART tanpa menulis kode tambahan apa pun. Saat pengguna membuka GPIO atau bus menggunakan OpenPin() atau FromIdAsync(), pin fisik yang mendasar secara otomatis di-mux ke fungsi yang diminta. Jika pin sudah digunakan oleh fungsi yang berbeda, panggilan OpenPin() atau FromIdAsync() akan gagal. Ketika pengguna menutup perangkat dengan membuang objek GpioPin, I2cDevice, SpiDevice, atau SerialDevice , pin dirilis, memungkinkan mereka untuk kemudian dibuka untuk fungsi yang berbeda.

Windows berisi dukungan bawaan untuk pin muxing dalam kerangka kerja GpioClx, SpbCx, dan SerCx . Kerangka kerja ini bekerja sama untuk secara otomatis mengalihkan pin ke fungsi yang benar saat pin atau bus GPIO diakses. Akses ke pin di arbitrase untuk mencegah konflik di antara beberapa klien. Selain dukungan bawaan ini, antarmuka dan protokol untuk pin muxing adalah tujuan umum dan dapat diperluas untuk mendukung perangkat dan skenario tambahan.

Dokumen ini pertama-tama menjelaskan antarmuka dan protokol yang mendasar yang terlibat dalam pin muxing, lalu menjelaskan cara menambahkan dukungan untuk pin muxing ke driver pengontrol GpioClx, SpbCx, dan SerCx.

Sematkan Arsitektur Muxing

Bagian ini menjelaskan antarmuka dan protokol yang mendasar yang terlibat dalam pin muxing. Pengetahuan tentang protokol yang mendasar belum tentu diperlukan untuk mendukung pin muxing dengan driver GpioClx/SpbCx/SerCx. Untuk detail tentang cara mendukung pin muxing dengan driver GpioCls/SpbCx/SerCx, lihat Menerapkan dukungan pin muxing di driver klien GpioClx dan Mengonsumsi dukungan muxing di driver pengontrol SpbCx dan SerCx.

Pin muxing dicapai dengan kerja sama beberapa komponen.

  • Sematkan server muxing – ini adalah driver yang mengontrol blok kontrol pin muxing. Sematkan server muxing menerima permintaan pin muxing dari klien melalui permintaan untuk memesan sumber daya muxing (melalui permintaan IRP_MJ_CREATE), dan permintaan untuk mengalihkan fungsi pin (melalui *IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS- permintaan). Server pin muxing biasanya merupakan driver GPIO, karena blok muxing terkadang merupakan bagian dari blok GPIO. Bahkan jika blok muxing adalah periferal terpisah, driver GPIO adalah tempat logis untuk menempatkan fungsionalitas muxing.
  • Sematkan klien muxing – ini adalah driver yang mengonsumsi pin muxing. Menyematkan klien muxing menerima sumber daya pin muxing dari firmware ACPI. Sumber daya pin muxing adalah jenis sumber daya koneksi dan dikelola oleh hub sumber daya. Sematkan klien yang mencadangkan sumber daya pin muxing dengan membuka handel ke sumber daya. Untuk memengaruhi perubahan perangkat keras, klien harus menerapkan konfigurasi dengan mengirim permintaan IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS . Klien merilis sumber daya muxing pin dengan menutup handel, di mana konfigurasi muxing titik dikembalikan ke status defaultnya.
  • Firmware ACPI – menentukan konfigurasi muxing dengan MsftFunctionConfig() sumber daya. Sumber daya MsftFunctionConfig mengekspresikan pin mana, di mana konfigurasi muxing, diperlukan oleh klien. Sumber daya MsftFunctionConfig berisi nomor fungsi, konfigurasi penarikan, dan daftar nomor pin. Sumber daya MsftFunctionConfig disediakan untuk menyematkan klien muxing sebagai sumber daya perangkat keras, yang diterima oleh driver dalam callback PrepareHardware mereka mirip dengan sumber daya koneksi GPIO dan SPB. Klien menerima ID hub sumber daya yang dapat digunakan untuk membuka handel ke sumber daya.

Anda harus meneruskan /MsftInternal pengalihan baris perintah ke asl.exe untuk mengkompilasi file ASL yang berisi MsftFunctionConfig() deskriptor karena deskriptor ini saat ini sedang ditinjau oleh komite kerja ACPI. Misalnya: asl.exe /MsftInternal dsdt.asl

Urutan operasi yang terlibat dalam pin muxing ditunjukkan di bawah ini.

Pin muxing client server interaction

  1. Klien menerima sumber daya MsftFunctionConfig dari firmware ACPI dalam panggilan balik EvtDevicePrepareHardware().
  2. Klien menggunakan fungsi RESOURCE_HUB_CREATE_PATH_FROM_ID() pembantu hub sumber daya untuk membuat jalur dari ID sumber daya, lalu membuka handel ke jalur (menggunakan ZwCreateFile(), IoGetDeviceObjectPointer(), atau WdfIoTargetOpen()).
  3. Server mengekstrak ID hub sumber daya dari jalur file menggunakan fungsi RESOURCE_HUB_ID_FROM_FILE_NAME()pembantu hub sumber daya , lalu meminta hub sumber daya untuk mendapatkan pendeskripsi sumber daya.
  4. Server melakukan arbitrase berbagi untuk setiap pin di deskriptor dan menyelesaikan permintaan IRP_MJ_CREATE.
  5. Klien mengeluarkan permintaan IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS pada handel yang diterima.
  6. Sebagai respons terhadap IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, server melakukan operasi muxing perangkat keras dengan membuat fungsi yang ditentukan aktif pada setiap pin.
  7. Klien melanjutkan operasi yang bergantung pada konfigurasi pin muxing yang diminta.
  8. Ketika klien tidak lagi memerlukan pin untuk di-mux, itu menutup handel.
  9. Sebagai respons terhadap handel yang ditutup, server mengembalikan pin kembali ke status awalnya.

Deskripsi protokol untuk menyematkan klien muxing

Bagian ini menjelaskan bagaimana klien menggunakan fungsionalitas pin muxing. Ini tidak berlaku untuk SerCx driver pengontrol dan SpbCx , karena kerangka kerja menerapkan protokol ini atas nama driver pengontrol.

Mengurai sumber daya

Driver WDF menerima MsftFunctionConfig() sumber daya dalam rutinitas EvtDevicePrepareHardware(). Sumber daya MsftFunctionConfig dapat diidentifikasi dengan bidang berikut:

CM_PARTIAL_RESOURCE_DESCRIPTOR::Type = CmResourceTypeConnection
CM_PARTIAL_RESOURCE_DESCRIPTOR::u.Connection.Class = CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG
CM_PARTIAL_RESOURCE_DESCRIPTOR::u.Connection.Type = CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG

Rutinitas EvtDevicePrepareHardware() mungkin mengekstrak sumber daya MsftFunctionConfig sebagai berikut:

EVT_WDF_DEVICE_PREPARE_HARDWARE evtDevicePrepareHardware;

_Use_decl_annotations_
NTSTATUS
evtDevicePrepareHardware (
    WDFDEVICE WdfDevice,
    WDFCMRESLIST ResourcesTranslated
    )
{
    PAGED_CODE();

    LARGE_INTEGER connectionId;
    ULONG functionConfigCount = 0;

    const ULONG resourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
    for (ULONG index = 0; index < resourceCount; ++index) {
        const CM_PARTIAL_RESOURCE_DESCRIPTOR* resDescPtr =
            WdfCmResourceListGetDescriptor(ResourcesTranslated, index);

        switch (resDescPtr->Type) {
        case CmResourceTypeConnection:
            switch (resDescPtr->u.Connection.Class) {
            case CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG:
                switch (resDescPtr->u.Connection.Type) {
                case CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG:
                    switch (functionConfigCount) {
                    case 0:
                        // save the connection ID
                        connectionId.LowPart = resDescPtr->u.Connection.IdLowPart;
                        connectionId.HighPart = resDescPtr->u.Connection.IdHighPart;
                        break;
                    } // switch (functionConfigCount)
                    ++functionConfigCount;
                    break; // CM_RESOURCE_CONNECTION_TYPE_FUNCTION_CONFIG

                } // switch (resDescPtr->u.Connection.Type)
                break; // CM_RESOURCE_CONNECTION_CLASS_FUNCTION_CONFIG
            } // switch (resDescPtr->u.Connection.Class)
            break;
        } // switch
    } // for (resource list)

    if (functionConfigCount < 1) {
        return STATUS_INVALID_DEVICE_CONFIGURATION;
    }
    // TODO: save connectionId in the device context for later use

    return STATUS_SUCCESS;
}

Mempertahankan dan menerapkan sumber daya

Ketika klien ingin memux pin, klien memesan dan menerapkan sumber daya MsftFunctionConfig. Contoh berikut menunjukkan bagaimana klien mungkin memesan dan menerapkan sumber daya MsftFunctionConfig.

_IRQL_requires_max_(PASSIVE_LEVEL)
NTSTATUS AcquireFunctionConfigResource (
    WDFDEVICE WdfDevice,
    LARGE_INTEGER ConnectionId,
    _Out_ WDFIOTARGET* ResourceHandlePtr
    )
{
    PAGED_CODE();

    //
    // Form the resource path from the connection ID
    //
    DECLARE_UNICODE_STRING_SIZE(resourcePath, RESOURCE_HUB_PATH_CHARS);
    NTSTATUS status = RESOURCE_HUB_CREATE_PATH_FROM_ID(
            &resourcePath,
            ConnectionId.LowPart,
            ConnectionId.HighPart);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    //
    // Create a WDFIOTARGET
    //
    WDFIOTARGET resourceHandle;
    status = WdfIoTargetCreate(WdfDevice, WDF_NO_ATTRIBUTES, &resourceHandle);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    //
    // Reserve the resource by opening a WDFIOTARGET to the resource
    //
    WDF_IO_TARGET_OPEN_PARAMS openParams;
    WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(
        &openParams,
        &resourcePath,
        FILE_GENERIC_READ | FILE_GENERIC_WRITE);

    status = WdfIoTargetOpen(resourceHandle, &openParams);
    if (!NT_SUCCESS(status)) {
        return status;
    }
    //
    // Commit the resource
    //
    status = WdfIoTargetSendIoctlSynchronously(
            resourceHandle,
            WDF_NO_HANDLE,      // WdfRequest
            IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS,
            nullptr,            // InputBuffer
            nullptr,            // OutputBuffer
            nullptr,            // RequestOptions
            nullptr);           // BytesReturned

    if (!NT_SUCCESS(status)) {
        WdfIoTargetClose(resourceHandle);
        return status;
    }

    //
    // Pins were successfully muxed, return the handle to the caller
    //
    *ResourceHandlePtr = resourceHandle;
    return STATUS_SUCCESS;
}

Driver harus menyimpan WDFIOTARGET di salah satu area konteksnya sehingga dapat ditutup nanti. Ketika driver siap untuk merilis konfigurasi muxing, driver harus menutup handel sumber daya dengan memanggil WdfObjectDelete(), atau WdfIoTargetClose() jika Anda ingin menggunakan kembali WDFIOTARGET.

    WdfObjectDelete(resourceHandle);

Ketika klien menutup handel sumber dayanya, pin di-mux kembali ke status awal mereka, dan sekarang dapat diperoleh oleh klien yang berbeda.

Deskripsi protokol untuk menyematkan server muxing

Bagian ini menjelaskan bagaimana server pin muxing mengekspos fungsionalitasnya kepada klien. Ini tidak berlaku untuk GpioClx driver miniport, karena kerangka kerja menerapkan protokol ini atas nama driver klien. Untuk detail tentang cara mendukung pin muxing pada GpioClx driver klien, lihat Menerapkan dukungan muxing di Driver Klien GpioClx.

Menangani permintaan IRP_MJ_CREATE

Klien membuka handel ke sumber daya saat mereka ingin memesan sumber daya pin muxing. Server pin muxing menerima permintaan IRP_MJ_CREATE dengan cara operasi pemisahan ulang dari hub sumber daya. Komponen jalur berikutnya dari permintaan IRP_MJ_CREATE berisi ID hub sumber daya, yang merupakan bilangan bulat 64-bit dalam format heksadesimal. Server harus mengekstrak ID hub sumber daya dari nama file menggunakan RESOURCE_HUB_ID_FROM_FILE_NAME() dari reshub.h, dan mengirim IOCTL_RH_QUERY_CONNECTION_PROPERTIES ke hub sumber daya untuk mendapatkan MsftFunctionConfig() deskriptor.

Server harus memvalidasi deskriptor dan mengekstrak mode berbagi dan menyematkan daftar dari deskriptor. Kemudian harus melakukan arbitrase berbagi untuk pin, dan jika berhasil, tandai pin sebagai dipesan sebelum menyelesaikan permintaan.

Arbitrase berbagi berhasil secara keseluruhan jika berbagi arbitrase berhasil untuk setiap pin dalam daftar pin. Setiap pin harus di arbitrase sebagai berikut:

  • Jika pin belum dicadangkan, arbitrase berbagi berhasil.
  • Jika pin sudah dicadangkan sebagai eksklusif, arbitrase berbagi gagal.
  • Jika pin sudah dicadangkan sebagai dibagikan,
    • dan permintaan masuk dibagikan, arbitrase berbagi berhasil.
    • dan permintaan masuk bersifat eksklusif, arbitrase berbagi gagal.

Jika arbitrase berbagi gagal, permintaan harus diselesaikan dengan STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE. Jika arbitrase berbagi berhasil, permintaan harus diselesaikan dengan STATUS_SUCCESS.

Perhatikan bahwa mode berbagi permintaan masuk harus diambil dari deskriptor MsftFunctionConfig, bukan IrpSp-Parameters.Create.ShareAccess>.

Menangani permintaan IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS

Setelah klien berhasil mencadangkan sumber daya MsftFunctionConfig dengan membuka handel, klien dapat mengirim IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS untuk meminta server melakukan operasi muxing perangkat keras yang sebenarnya. Ketika server menerima IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, untuk setiap pin dalam daftar pin seharusnya

  • Atur mode penarikan yang ditentukan dalam anggota PinConfiguration dari struktur PNP_FUNCTION_CONFIG_DESCRIPTOR ke perangkat keras.
  • Mux pin ke fungsi yang ditentukan oleh anggota FunctionNumber dari struktur PNP_FUNCTION_CONFIG_DESCRIPTOR.

Server kemudian harus menyelesaikan permintaan dengan STATUS_SUCCESS.

Arti FunctionNumber didefinisikan oleh server, dan dipahami bahwa deskriptor MsftFunctionConfig ditulis dengan pengetahuan tentang bagaimana server menginterpretasikan bidang ini.

Ingatlah bahwa ketika handel ditutup, server harus mengembalikan pin ke konfigurasi tempat mereka berada ketika IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS diterima, sehingga server mungkin perlu menyimpan status pin sebelum memodifikasinya.

Menangani permintaan IRP_MJ_CLOSE

Ketika klien tidak lagi memerlukan sumber daya muxing, klien menutup handelnya. Ketika server menerima permintaan IRP_MJ_CLOSE , server harus mengembalikan pin ke status saat IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS diterima. Jika klien tidak pernah mengirim IOCTL_GPIO_COMMIT_FUNCTION_CONFIG_PINS, tidak ada tindakan yang diperlukan. Server kemudian harus menandai pin sebagai tersedia sehubungan dengan berbagi arbitrase, dan menyelesaikan permintaan dengan STATUS_SUCCESS. Pastikan untuk menyinkronkan penanganan IRP_MJ_CLOSE dengan benar dengan penanganan IRP_MJ_CREATE .

Panduan penulisan untuk tabel ACPI

Bagian ini menjelaskan cara menyediakan sumber daya muxing ke driver klien. Perhatikan bahwa Anda akan memerlukan microsoft ASL compiler build 14327 atau yang lebih baru untuk mengkompilasi tabel yang berisi MsftFunctionConfig() sumber daya. MsftFunctionConfig() sumber daya disediakan untuk menyematkan klien muxing sebagai sumber daya perangkat keras. MsftFunctionConfig() sumber daya harus diberikan ke driver yang memerlukan perubahan muxing pin, yang biasanya spb dan driver pengontrol serial, tetapi tidak boleh disediakan ke SPB dan driver periferal serial, karena driver pengontrol menangani konfigurasi muxing. Makro MsftFunctionConfig() ACPI didefinisikan sebagai berikut:

  MsftFunctionConfig(Shared/Exclusive
                PinPullConfig,
                FunctionNumber,
                ResourceSource,
                ResourceSourceIndex,
                ResourceConsumer/ResourceProducer,
                VendorData) { Pin List }

  • Bersama/Eksklusif – Jika eksklusif, pin ini dapat diperoleh oleh satu klien pada satu waktu. Jika dibagikan, beberapa klien bersama dapat memperoleh sumber daya. Selalu atur ini ke eksklusif karena memungkinkan beberapa klien yang tidak terkoordinasi untuk mengakses sumber daya yang dapat diubah dapat menyebabkan perlombaan data dan oleh karena itu hasil yang tidak dapat diprediksi.
  • PinPullConfig – salah satu
    • PullDefault – gunakan konfigurasi penarikan default yang ditentukan SOC
    • PullUp – aktifkan resistor pull-up
    • PullDown – aktifkan resistor pull-down
    • PullNone - nonaktifkan semua resistor penarikan
  • FunctionNumber – nomor fungsi untuk diprogram ke dalam mux.
  • ResourceSource – Jalur namespace ACPI dari server pin muxing
  • ResourceSourceIndex – atur ini ke 0
  • ResourceConsumer/ResourceProducer – atur ini ke ResourceConsumer
  • VendorData – data biner opsional yang maknanya ditentukan oleh server pin muxing. Ini biasanya harus dibiarkan kosong
  • Sematkan Daftar – daftar nomor pin yang dipisahkan koma tempat konfigurasi diterapkan. Ketika server pin muxing adalah driver GpioClx, ini adalah nomor pin GPIO dan memiliki arti yang sama dengan nomor pin dalam deskriptor GpioIo.

Contoh berikut menunjukkan bagaimana seseorang mungkin menyediakan sumber daya MsftFunctionConfig() ke driver pengontrol I2C.

Device(I2C1)
{
    Name(_HID, "BCM2841")
    Name(_CID, "BCMI2C")
    Name(_UID, 0x1)
    Method(_STA)
    {
        Return(0xf)
    }
    Method(_CRS, 0x0, NotSerialized)
    {
        Name(RBUF, ResourceTemplate()
        {
            Memory32Fixed(ReadWrite, 0x3F804000, 0x20)
            Interrupt(ResourceConsumer, Level, ActiveHigh, Shared) { 0x55 }
            MsftFunctionConfig(Exclusive, PullUp, 4, "\\_SB.GPI0", 0, ResourceConsumer, ) { 2, 3 }
        })
        Return(RBUF)
    }
}

Selain memori dan sumber daya interupsi yang biasanya diperlukan oleh driver pengontrol, MsftFunctionConfig() sumber daya juga ditentukan. Sumber daya ini memungkinkan driver pengontrol I2C untuk menempatkan pin 2 dan 3 - dikelola oleh simpul perangkat di \_SB. GPIO0 – dalam fungsi 4 dengan resistor pull-up diaktifkan.

Mendukung dukungan muxing di driver klien GpioClx

GpioClx memiliki dukungan bawaan untuk pin muxing. Driver miniport GpioClx (juga disebut sebagai "driver klien GpioClx"), mendorong perangkat keras pengontrol GPIO. Pada Windows 10 build 14327, driver miniport GpioClx dapat menambahkan dukungan untuk pin muxing dengan menerapkan dua DDI baru:

  • CLIENT_Koneksi FunctionConfigPins – dipanggil oleh GpioClx untuk memerintahkan driver miniport untuk menerapkan konfigurasi muxing yang ditentukan.
  • CLIENT_DisconnectFunctionConfigPins – dipanggil oleh GpioClx untuk memerintahkan driver miniport untuk mengembalikan konfigurasi muxing.

Lihat Fungsi Panggilan Balik Peristiwa GpioClx untuk deskripsi rutinitas ini.

Selain kedua DDI baru ini, DDI yang ada harus diaudit untuk kompatibilitas pin muxing:

  • CLIENT_Koneksi IoPins/CLIENT_Koneksi Interrupt – CLIENT_Koneksi IoPins dipanggil oleh GpioClx untuk memerintahkan driver miniport untuk mengonfigurasi pin yang ditetapkan untuk input atau output GPIO. GPIO saling eksklusif dengan MsftFunctionConfig, yang berarti pin tidak akan pernah terhubung untuk GPIO dan MsftFunctionConfig secara bersamaan. Karena fungsi default pin tidak diperlukan untuk menjadi GPIO, pin mungkin belum tentu dimuksasi ke GPIO ketika Koneksi IoPins dipanggil. Koneksi IoPins diperlukan untuk melakukan semua operasi yang diperlukan untuk membuat pin siap untuk GPIO IO, termasuk operasi muxing. CLIENT_Koneksi Interrupt harus berperilaku sama, karena gangguan dapat dianggap sebagai kasus khusus input GPIO.
  • CLIENT_DisconnectIoPins/CLIENT_DisconnectInterrupt – Rutinitas ini harus mengembalikan pin ke status saat CLIENT_Koneksi IoPins/CLIENT_Koneksi Interrupt dipanggil, kecuali bendera PreserveConfiguration ditentukan. Selain mengembalikan arah pin ke status defaultnya, miniport juga harus mengembalikan status muxing setiap pin ke status saat _Koneksi rutin dipanggil.

Misalnya, asumsikan bahwa konfigurasi muxing default pin adalah UART, dan pin juga dapat digunakan sebagai GPIO. Ketika CLIENT_Koneksi IoPins dipanggil untuk menyambungkan pin untuk GPIO, itu harus memudulkan pin ke GPIO, dan di CLIENT_DisconnectIoPins, itu harus men-mux pin kembali ke UART. Secara umum, rutinitas Putuskan sambungan harus membatalkan operasi yang dilakukan oleh rutinitas Koneksi.

Mendukung muxing di driver pengontrol SpbCx dan SerCx

Pada Windows 10 build 14327, SpbCx kerangka kerja dan SerCx berisi dukungan bawaan untuk pin muxing yang memungkinkan SpbCx driver pengontrol SerCx untuk menyematkan klien muxing tanpa perubahan kode pada driver pengontrol itu sendiri. Dengan ekstensi, driver periferal SpbCx/SerCx apa pun yang terhubung ke driver pengontrol SpbCx/SerCx berkemampuan muxing akan memicu aktivitas pin muxing.

Diagram berikut menunjukkan dependensi antara masing-masing komponen ini. Seperti yang Anda lihat, pin muxing memperkenalkan dependensi dari driver pengontrol SerCx dan SpbCx ke driver GPIO, yang biasanya bertanggung jawab atas muxing.

Pin muxing dependency

Pada waktu inisialisasi perangkat, SpbCx kerangka kerja dan SerCx mengurai semua MsftFunctionConfig() sumber daya yang disediakan sebagai sumber daya perangkat keras ke perangkat. SpbCx/SerCx kemudian memperoleh dan melepaskan sumber daya pin muxing sesuai permintaan.

SpbCxmenerapkan konfigurasi pin muxing di handler IRP_MJ_CREATE, tepat sebelum memanggil panggilan balik EvtSpbTarget Koneksi() driver klien. Jika konfigurasi muxing tidak dapat diterapkan, panggilan balik driver EvtSpbTargetConnect() pengontrol tidak akan dipanggil. Oleh karena itu, driver pengontrol SPB dapat mengasumsikan bahwa pin di-mux ke fungsi SPB pada saat EvtSpbTargetConnect() dipanggil.

SpbCxmengembalikan konfigurasi pin muxing di handler IRP_MJ_CLOSE, tepat setelah memanggil panggilan balik EvtSpbTargetDisconnect() driver pengontrol. Hasilnya adalah bahwa pin di-mux ke fungsi SPB setiap kali driver periferal membuka handel ke driver pengontrol SPB, dan diledakkan ketika driver periferal menutup handel mereka.

SerCx bertempur sama. SerCxmemperoleh semua MsftFunctionConfig() sumber daya dalam handler IRP_MJ_CREATE tepat sebelum memanggil callback EvtSerCx2FileOpen() driver pengontrol, dan merilis semua sumber daya di handler IRP_MJ_CLOSE, tepat setelah memanggil callback EvtSerCx2FileClose driver pengontrol.

Implikasi dari muxing pin dinamis untuk SerCx driver pengontrol dan SpbCx adalah bahwa mereka harus dapat mentolerir pin yang diledakkan dari fungsi SPB/UART pada waktu tertentu. Driver pengontrol perlu mengasumsikan bahwa pin tidak akan di-mux sampai EvtSpbTargetConnect() atau EvtSerCx2FileOpen() dipanggil. Pin tidak perlu dimuks ke fungsi SPB/UART selama panggilan balik berikut. Berikut ini bukan daftar lengkap, tetapi mewakili rutinitas PNP yang paling umum yang diterapkan oleh driver pengontrol.

  • DriverEntry
  • EvtDriverDeviceAdd
  • EvtDevicePrepareHardware/EvtDeviceReleaseHardware
  • EvtDeviceD0Entry/EvtDeviceD0Exit

Verifikasi

Ketika Anda siap untuk menguji rhproxy, sangat membantu untuk menggunakan prosedur langkah demi langkah berikut.

  1. Verifikasi bahwa setiap SpbCxdriver pengontrol , GpioClx, dan SerCx memuat dan beroperasi dengan benar
  2. Verifikasi bahwa rhproxy ada pada sistem. Beberapa edisi dan build Windows tidak memilikinya.
  3. Mengkompilasi dan memuat simpul rhproxy Anda menggunakan ACPITABL.dat
  4. Verifikasi bahwa simpul rhproxy perangkat ada
  5. Verifikasi bahwa rhproxy sedang memuat dan memulai
  6. Verifikasi bahwa perangkat yang diharapkan terekspos ke mode pengguna
  7. Verifikasi bahwa Anda dapat berinteraksi dengan setiap perangkat dari baris perintah
  8. Verifikasi bahwa Anda dapat berinteraksi dengan setiap perangkat dari aplikasi UWP
  9. Menjalankan pengujian HLK

Memverifikasi driver pengontrol

Karena rhproxy mengekspos perangkat lain pada sistem ke mode pengguna, rhproxy hanya berfungsi jika perangkat tersebut sudah berfungsi. Langkah pertama adalah memverifikasi bahwa perangkat tersebut - pengontrol I2C, SPI, GPIO yang ingin Anda ekspos - sudah berfungsi.

Pada prompt perintah, jalankan

devcon status *

Lihat output dan verifikasi bahwa semua perangkat yang menarik dimulai. Jika perangkat memiliki kode masalah, Anda perlu memecahkan masalah mengapa perangkat tersebut tidak dimuat. Semua perangkat harus diaktifkan selama bringup platform awal. Pemecahan SpbCxmasalah , GpioClx, atau SerCx driver pengontrol berada di luar cakupan dokumen ini.

Verifikasi bahwa rhproxy ada di sistem

Verifikasi bahwa rhproxy layanan ada di sistem.

reg query HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\rhproxy

Jika kunci reg tidak ada, rhproxy tidak ada di sistem Anda. Rhproxy hadir di semua build IoT Core dan Windows Enterprise build 15063 dan yang lebih baru.

Mengkompilasi dan memuat ASL dengan ACPITABL.dat

Sekarang setelah Anda menulis simpul ASL rhproxy, saatnya untuk mengkompilasi dan memuatnya. Anda dapat mengkompilasi simpul rhproxy ke dalam file AML mandiri yang dapat ditambahkan ke tabel ACPI sistem. Atau, jika Anda memiliki akses ke sumber ACPI sistem, Anda dapat memasukkan simpul rhproxy langsung ke tabel ACPI platform Anda. Namun, selama bringup awal mungkin lebih mudah digunakan ACPITABL.dat.

  1. Buat file bernama yourboard.asl dan letakkan simpul perangkat RHPX di dalam DefinitionBlock:

    DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
    {
        Scope (\_SB)
        {
            Device(RHPX)
            {
            ...
            }
        }
    }
    
  2. Unduh WDK dan temukan asl.exe diC:\Program Files (x86)\Windows Kits\10\Tools\x64\ACPIVerify

  3. Jalankan perintah berikut untuk menghasilkan ACPITABL.dat:

    asl.exe yourboard.asl
    
  4. Salin file ACPITABL.dat yang dihasilkan ke c:\windows\system32 pada sistem Anda yang sedang diuji.

  5. Aktifkan testsigning pada sistem Anda saat pengujian:

    bcdedit /set testsigning on
    
  6. Reboot sistem yang sedang diuji. Sistem akan menambahkan tabel ACPI yang ditentukan dalam ACPITABL.dat ke tabel firmware sistem.

Verifikasi bahwa simpul perangkat rhproxy ada

Jalankan perintah berikut untuk menghitung simpul perangkat rhproxy.

devcon status *msft8000

Output devcon harus menunjukkan bahwa perangkat ada. Jika simpul perangkat tidak ada, tabel ACPI tidak berhasil ditambahkan ke sistem.

Verifikasi bahwa rhproxy memuat dan memulai

Periksa status rhproxy:

devcon status *msft8000

Jika output menunjukkan bahwa rhproxy dimulai, rhproxy telah dimuat dan berhasil dimulai. Jika Anda melihat kode masalah, Anda perlu menyelidikinya. Beberapa kode masalah umum adalah:

  • Masalah 51 - CM_PROB_WAITING_ON_DEPENDENCY - Sistem tidak memulai rhproxy karena salah satu dependensinya gagal dimuat. Ini berarti bahwa sumber daya yang diteruskan ke rhproxy menunjuk ke simpul ACPI yang tidak valid, atau perangkat target tidak dimulai. Pertama, periksa kembali apakah semua perangkat berhasil berjalan (lihat 'Verifikasi driver pengontrol' di atas). Kemudian, periksa kembali ASL Anda dan pastikan bahwa semua jalur sumber daya Anda (misalnya, \_SB.I2C1) sudah benar dan arahkan ke simpul yang valid di DSDT Anda.
  • Masalah 10 - CM_PROB_FAILED_START - Rhproxy gagal dimulai, kemungkinan besar karena masalah penguraian sumber daya. Buka ASL Anda dan periksa kembali indeks sumber daya di DSD, dan verifikasi bahwa sumber daya GPIO ditentukan dalam meningkatkan urutan nomor pin.

Verifikasi bahwa perangkat yang diharapkan terekspos ke mode pengguna

Sekarang rhproxy berjalan, rhproxy seharusnya telah membuat antarmuka perangkat yang dapat diakses oleh mode pengguna. Kami akan menggunakan beberapa alat baris perintah untuk menghitung perangkat dan melihat bahwa perangkat tersebut ada.

https://github.com/ms-iot/samples Kloning repositori dan buat GpioTestToolsampel , , I2cTestToolSpiTestTool, dan Mincomm . Salin alat ke perangkat Anda di bawah pengujian dan gunakan perintah berikut untuk menghitung perangkat.

I2cTestTool.exe -list
SpiTestTool.exe -list
GpioTestTool.exe -list
MinComm.exe -list

Anda akan melihat perangkat dan nama yang mudah diingat tercantum. Jika Anda tidak melihat perangkat yang tepat dan nama yang mudah diingat, periksa kembali ASL Anda.

Memverifikasi setiap perangkat pada baris perintah

Langkah selanjutnya adalah menggunakan alat baris perintah untuk membuka dan berinteraksi dengan perangkat.

Contoh I2CTestTool:

I2cTestTool.exe 0x55 I2C1
> write {1 2 3}
> read 3
> writeread {1 2 3} 3

Contoh SpiTestTool:

SpiTestTool.exe -n SPI1
> write {1 2 3}
> read 3

Contoh GpioTestTool:

GpioTestTool.exe 12
> setdrivemode output
> write 0
> write 1
> setdrivemode input
> read
> interrupt on
> interrupt off

Contoh MinComm (serial). Koneksi Rx ke Tx sebelum menjalankan:

MinComm "\\?\ACPI#FSCL0007#3#{86e0d1e0-8089-11d0-9ce4-08003e301f73}\0000000000000006"
(type characters and see them echoed back)

Memverifikasi setiap perangkat dari aplikasi UWP

Gunakan sampel berikut untuk memvalidasi bahwa perangkat berfungsi dari UWP.

Jalankan Pengujian HLK

Unduh Hardware Lab Kit (HLK). Tes berikut tersedia:

Ketika Anda memilih simpul perangkat rhproxy di manajer HLK, pengujian yang berlaku akan secara otomatis dipilih.

Di manajer HLK, pilih "Perangkat Proksi Hub Sumber Daya":

Screenshot of the Windows Hardware Lab Kit showing the Selection tab with the Resource Hub proxy device option selected.

Lalu klik tab Pengujian, dan pilih tes I2C WinRT, Gpio WinRT, dan Spi WinRT.

Screenshot of the Windows Hardware Lab Kit showing the Tests tab with the G P I O Win R T Functional and Stress Tests option selected.

Klik Jalankan Dipilih. Dokumentasi lebih lanjut tentang setiap pengujian tersedia dengan mengklik kanan pada pengujian dan mengklik "Deskripsi Pengujian."

Sumber daya

Lampiran

Lampiran A - Daftar Raspberry Pi ASL

Lihat juga Pemetaan Raspberry Pi 2 & 3 Pin

DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{

    Scope (\_SB)
    {
        //
        // RHProxy Device Node to enable WinRT API
        //
        Device(RHPX)
        {
            Name(_HID, "MSFT8000")
            Name(_CID, "MSFT8000")
            Name(_UID, 1)

            Name(_CRS, ResourceTemplate()
            {
                // Index 0
                SPISerialBus(              // SCKL - GPIO 11 - Pin 23
                                           // MOSI - GPIO 10 - Pin 19
                                           // MISO - GPIO 9  - Pin 21
                                           // CE0  - GPIO 8  - Pin 24
                    0,                     // Device selection (CE0)
                    PolarityLow,           // Device selection polarity
                    FourWireMode,          // wiremode
                    0,                     // databit len: placeholder
                    ControllerInitiated,   // slave mode
                    0,                     // connection speed: placeholder
                    ClockPolarityLow,      // clock polarity: placeholder
                    ClockPhaseFirst,       // clock phase: placeholder
                    "\\_SB.SPI0",          // ResourceSource: SPI bus controller name
                    0,                     // ResourceSourceIndex
                                           // Resource usage
                    )                      // Vendor Data

                // Index 1
                SPISerialBus(              // SCKL - GPIO 11 - Pin 23
                                           // MOSI - GPIO 10 - Pin 19
                                           // MISO - GPIO 9  - Pin 21
                                           // CE1  - GPIO 7  - Pin 26
                    1,                     // Device selection (CE1)
                    PolarityLow,           // Device selection polarity
                    FourWireMode,          // wiremode
                    0,                     // databit len: placeholder
                    ControllerInitiated,   // slave mode
                    0,                     // connection speed: placeholder
                    ClockPolarityLow,      // clock polarity: placeholder
                    ClockPhaseFirst,       // clock phase: placeholder
                    "\\_SB.SPI0",          // ResourceSource: SPI bus controller name
                    0,                     // ResourceSourceIndex
                                           // Resource usage
                    )                      // Vendor Data

                // Index 2
                SPISerialBus(              // SCKL - GPIO 21 - Pin 40
                                           // MOSI - GPIO 20 - Pin 38
                                           // MISO - GPIO 19 - Pin 35
                                           // CE1  - GPIO 17 - Pin 11
                    1,                     // Device selection (CE1)
                    PolarityLow,           // Device selection polarity
                    FourWireMode,          // wiremode
                    0,                     // databit len: placeholder
                    ControllerInitiated,   // slave mode
                    0,                     // connection speed: placeholder
                    ClockPolarityLow,      // clock polarity: placeholder
                    ClockPhaseFirst,       // clock phase: placeholder
                    "\\_SB.SPI1",          // ResourceSource: SPI bus controller name
                    0,                     // ResourceSourceIndex
                                           // Resource usage
                    )                      // Vendor Data
                // Index 3
                I2CSerialBus(              // Pin 3 (GPIO2, SDA1), 5 (GPIO3, SCL1)
                    0xFFFF,                // SlaveAddress: placeholder
                    ,                      // SlaveMode: default to ControllerInitiated
                    0,                     // ConnectionSpeed: placeholder
                    ,                      // Addressing Mode: placeholder
                    "\\_SB.I2C1",          // ResourceSource: I2C bus controller name
                    ,
                    ,
                    )                      // VendorData

                // Index 4 - GPIO 4 -
                GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 4 }
                GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 4 }
                // Index 6 - GPIO 5 -
                GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 5 }
                GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 5 }
                // Index 8 - GPIO 6 -
                GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 6 }
                GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 6 }
                // Index 10 - GPIO 12 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 12 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 12 }
                // Index 12 - GPIO 13 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 13 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 13 }
                // Index 14 - GPIO 16 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 16 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 16 }
                // Index 16 - GPIO 18 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 18 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 18 }
                // Index 18 - GPIO 22 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 22 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 22 }
                // Index 20 - GPIO 23 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 23 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 23 }
                // Index 22 - GPIO 24 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 24 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 24 }
                // Index 24 - GPIO 25 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 25 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 25 }
                // Index 26 - GPIO 26 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 26 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 26 }
                // Index 28 - GPIO 27 -
                GpioIO(Shared, PullDown, , , , "\\_SB.GPI0", , , , ) { 27 }
                GpioInt(Edge, ActiveBoth, Shared, PullDown, 0, "\\_SB.GPI0",) { 27 }
                // Index 30 - GPIO 35 -
                GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 35 }
                GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 35 }
                // Index 32 - GPIO 47 -
                GpioIO(Shared, PullUp, , , , "\\_SB.GPI0", , , , ) { 47 }
                GpioInt(Edge, ActiveBoth, Shared, PullUp, 0, "\\_SB.GPI0",) { 47 }
            })

            Name(_DSD, Package()
            {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package()
                {
                    // Reference http://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
                    // SPI 0
                    Package(2) { "bus-SPI-SPI0", Package() { 0, 1 }},                       // Index 0 & 1
                    Package(2) { "SPI0-MinClockInHz", 7629 },                               // 7629 Hz
                    Package(2) { "SPI0-MaxClockInHz", 125000000 },                          // 125 MHz
                    Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8 }},          // Data Bit Length
                    // SPI 1
                    Package(2) { "bus-SPI-SPI1", Package() { 2 }},                          // Index 2
                    Package(2) { "SPI1-MinClockInHz", 30518 },                              // 30518 Hz
                    Package(2) { "SPI1-MaxClockInHz", 125000000 },                          // 125 MHz
                    Package(2) { "SPI1-SupportedDataBitLengths", Package() { 8 }},          // Data Bit Length
                    // I2C1
                    Package(2) { "bus-I2C-I2C1", Package() { 3 }},
                    // GPIO Pin Count and supported drive modes
                    Package (2) { "GPIO-PinCount", 54 },
                    Package (2) { "GPIO-UseDescriptorPinNumbers", 1 },
                    Package (2) { "GPIO-SupportedDriveModes", 0xf },                        // InputHighImpedance, InputPullUp, InputPullDown, OutputCmos
                }
            })
        }
    }
}

Lampiran B - MinnowBoardMax ASL Listing

Lihat juga Pemetaan Pin Maks MinnowBoard

DefinitionBlock ("ACPITABL.dat", "SSDT", 1, "MSFT", "RHPROXY", 1)
{
    Scope (\_SB)
    {
        Device(RHPX)
        {
            Name(_HID, "MSFT8000")
            Name(_CID, "MSFT8000")
            Name(_UID, 1)

            Name(_CRS, ResourceTemplate()
            {
                // Index 0
                SPISerialBus(            // Pin 5, 7, 9 , 11 of JP1 for SIO_SPI
                    1,                     // Device selection
                    PolarityLow,           // Device selection polarity
                    FourWireMode,          // wiremode
                    8,                     // databit len
                    ControllerInitiated,   // slave mode
                    8000000,               // Connection speed
                    ClockPolarityLow,      // Clock polarity
                    ClockPhaseSecond,      // clock phase
                    "\\_SB.SPI1",          // ResourceSource: SPI bus controller name
                    0,                     // ResourceSourceIndex
                    ResourceConsumer,      // Resource usage
                    JSPI,                  // DescriptorName: creates name for offset of resource descriptor
                    )                      // Vendor Data

                // Index 1
                I2CSerialBus(            // Pin 13, 15 of JP1, for SIO_I2C5 (signal)
                    0xFF,                  // SlaveAddress: bus address
                    ,                      // SlaveMode: default to ControllerInitiated
                    400000,                // ConnectionSpeed: in Hz
                    ,                      // Addressing Mode: default to 7 bit
                    "\\_SB.I2C6",          // ResourceSource: I2C bus controller name (For MinnowBoard Max, hardware I2C5(0-based) is reported as ACPI I2C6(1-based))
                    ,
                    ,
                    JI2C,                  // Descriptor Name: creates name for offset of resource descriptor
                    )                      // VendorData

                // Index 2
                UARTSerialBus(           // Pin 17, 19 of JP1, for SIO_UART2
                    115200,                // InitialBaudRate: in bits ber second
                    ,                      // BitsPerByte: default to 8 bits
                    ,                      // StopBits: Defaults to one bit
                    0xfc,                  // LinesInUse: 8 1-bit flags to declare line enabled
                    ,                      // IsBigEndian: default to LittleEndian
                    ,                      // Parity: Defaults to no parity
                    ,                      // FlowControl: Defaults to no flow control
                    32,                    // ReceiveBufferSize
                    32,                    // TransmitBufferSize
                    "\\_SB.URT2",          // ResourceSource: UART bus controller name
                    ,
                    ,
                    UAR2,                  // DescriptorName: creates name for offset of resource descriptor
                    )

                // Index 3
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {0}  // Pin 21 of JP1 (GPIO_S5[00])
                // Index 4
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {0}

                // Index 5
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {1}  // Pin 23 of JP1 (GPIO_S5[01])
                // Index 6
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {1}

                // Index 7
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO2",) {2}  // Pin 25 of JP1 (GPIO_S5[02])
                // Index 8
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO2",) {2}

                // Index 9
                UARTSerialBus(           // Pin 6, 8, 10, 12 of JP1, for SIO_UART1
                    115200,                // InitialBaudRate: in bits ber second
                    ,                      // BitsPerByte: default to 8 bits
                    ,                      // StopBits: Defaults to one bit
                    0xfc,                  // LinesInUse: 8 1-bit flags to declare line enabled
                    ,                      // IsBigEndian: default to LittleEndian
                    ,                      // Parity: Defaults to no parity
                    FlowControlHardware,   // FlowControl: Defaults to no flow control
                    32,                    // ReceiveBufferSize
                    32,                    // TransmitBufferSize
                    "\\_SB.URT1",          // ResourceSource: UART bus controller name
                    ,
                    ,
                    UAR1,              // DescriptorName: creates name for offset of resource descriptor
                    )

                // Index 10
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {62}  // Pin 14 of JP1 (GPIO_SC[62])
                // Index 11
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {62}

                // Index 12
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {63}  // Pin 16 of JP1 (GPIO_SC[63])
                // Index 13
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {63}

                // Index 14
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {65}  // Pin 18 of JP1 (GPIO_SC[65])
                // Index 15
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {65}

                // Index 16
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {64}  // Pin 20 of JP1 (GPIO_SC[64])
                // Index 17
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {64}

                // Index 18
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {94}  // Pin 22 of JP1 (GPIO_SC[94])
                // Index 19
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {94}

                // Index 20
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {95}  // Pin 24 of JP1 (GPIO_SC[95])
                // Index 21
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {95}

                // Index 22
                GpioIo (Shared, PullNone, 0, 0, IoRestrictionNone, "\\_SB.GPO0",) {54}  // Pin 26 of JP1 (GPIO_SC[54])
                // Index 23
                GpioInt(Edge, ActiveBoth, SharedAndWake, PullNone, 0,"\\_SB.GPO0",) {54}
            })

            Name(_DSD, Package()
            {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package()
                {
                    // SPI Mapping
                    Package(2) { "bus-SPI-SPI0", Package() { 0 }},

                    Package(2) { "SPI0-MinClockInHz", 100000 },
                    Package(2) { "SPI0-MaxClockInHz", 15000000 },
                    // SupportedDataBitLengths takes a list of support data bit length
                    // Example : Package(2) { "SPI0-SupportedDataBitLengths", Package() { 8, 7, 16 }},
                    Package(2) { "SPI0-SupportedDataBitLengths", Package() { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }},
                     // I2C Mapping
                    Package(2) { "bus-I2C-I2C5", Package() { 1 }},
                    // UART Mapping
                    Package(2) { "bus-UART-UART2", Package() { 2 }},
                    Package(2) { "bus-UART-UART1", Package() { 9 }},
                }
            })
        }
    }
}

Lampiran C - Sampel skrip Powershell untuk menghasilkan sumber daya GPIO

Skrip berikut dapat digunakan untuk menghasilkan deklarasi sumber daya GPIO untuk Raspberry Pi:

$pins = @(
    @{PinNumber=4;PullConfig='PullUp'},
    @{PinNumber=5;PullConfig='PullUp'},
    @{PinNumber=6;PullConfig='PullUp'},
    @{PinNumber=12;PullConfig='PullDown'},
    @{PinNumber=13;PullConfig='PullDown'},
    @{PinNumber=16;PullConfig='PullDown'},
    @{PinNumber=18;PullConfig='PullDown'},
    @{PinNumber=22;PullConfig='PullDown'},
    @{PinNumber=23;PullConfig='PullDown'},
    @{PinNumber=24;PullConfig='PullDown'},
    @{PinNumber=25;PullConfig='PullDown'},
    @{PinNumber=26;PullConfig='PullDown'},
    @{PinNumber=27;PullConfig='PullDown'},
    @{PinNumber=35;PullConfig='PullUp'},
    @{PinNumber=47;PullConfig='PullUp'})

# generate the resources
$FIRST_RESOURCE_INDEX = 4
$resourceIndex = $FIRST_RESOURCE_INDEX
$pins | % {
    $a = @"
// Index $resourceIndex - GPIO $($_.PinNumber) - $($_.Name)
GpioIO(Shared, $($_.PullConfig), , , , "\\_SB.GPI0", , , , ) { $($_.PinNumber) }
GpioInt(Edge, ActiveBoth, Shared, $($_.PullConfig), 0, "\\_SB.GPI0",) { $($_.PinNumber) }
"@
    Write-Host $a
    $resourceIndex += 2;
}