Bagikan melalui


Driver PWM untuk modul PWM on-SoC

Untuk menyediakan akses ke pengontrol modulasi lebar Pulse (PWM) yang merupakan bagian dari SoC dan memori yang dipetakan ke ruang alamat SoC, Anda perlu menulis driver mode kernel. Driver harus mendaftarkan antarmuka kelas perangkat pengontrol PWM sehingga aplikasi UWP dapat mengakses perangkat PWM yang diekspos sistem melalui API WinRT PWM yang ditentukan dalam namespace Layanan Windows.Devices.Pwm.

Catatan

Jika Anda memiliki modul PWM add-on melalui I2C, SPI, atau pengontrol UART, Anda dapat mengakses modul dari aplikasi UWP dengan menggunakan API yang ditentukan dalam namespace Windows.Devices.Pwm dan Windows.Devices.Pwm.Provider .

Perangkat PWM diabstraksi ke dalam satu pengontrol dan satu atau beberapa pin. Mengontrol pengontrol atau pin dilakukan melalui IOCTL yang ditentukan PWM. Misalnya, driver tampilan LCD mengirimkan permintaan tersebut ke driver PWM untuk mengontrol tingkat backlight LCD.

Pembuatan sinyal PWM multi-pengontrol dan multi-saluran dengan periode, polaritas, dan siklus tugas yang dapat dikonfigurasi yang memungkinkan tugas-tugas berikut:

  • Mengendarai motor servo.
  • Drive beban seperti LED atau DC disikat motor.
  • Hasilkan sinyal analog.
  • Menghasilkan jam yang tepat.

Topik ini menjelaskan,

  • Cara mengaktifkan akses UWP ke perangkat PWM yang diekspos sistem.

  • Cara menangani permintaan PWM IOCTL yang dikirim oleh aplikasi Win32 atau driver mode kernel pihak ke-3.

Audiens yang dituju

  • OEM dan IHV mengembangkan sistem dengan pengontrol PWM on-SoC.

Terakhir Diperbarui

  • Agustus 2017

Versi Windows

  • Versi Windows 10

API penting

Tentang PWM

PWM menjelaskan teknik dasar untuk menghasilkan gelombang pulsa persegi panjang dengan lebar pulsa terodulasi yang menghasilkan variasi nilai rata-rata bentuk gelombang.

Bentuk gelombang PWM dapat dikategorikan dengan 2 parameter: periode bentuk gelombang (T) dan siklus tugas. Frekuensi bentuk gelombang (f) adalah timbal balik dari periode bentuk gelombang f=1/T. Siklus tugas menjelaskan proporsi waktu 'aktif' atau 'Aktif' sehubungan dengan interval reguler atau 'Periode' waktu; siklus tugas rendah sesuai dengan rata-rata daya output rendah, karena daya mati untuk sebagian besar waktu. Siklus tugas dinyatakan dalam persen di mana 100% sepenuhnya aktif, 0% sepenuhnya off, 50% menjadi 'Aktif' 50% dari waktu.

Driver.

Mengakses pengontrol dan pin PWM yang diekspos sistem

Driver PWM harus mendaftar
GUID_DEVINTERFACE_PWM_CONTROLLER sebagai GUID antarmuka perangkat untuk mengekspos dan mengakses perangkat PWM.

// {60824B4C-EED1-4C9C-B49C-1B961461A819} 

DEFINE_GUID(GUID_DEVINTERFACE_PWM_CONTROLLER, 0x60824b4c, 0xeed1, 0x4c9c, 0xb4, 0x9c, 0x1b, 0x96, 0x14, 0x61, 0xa8, 0x19); 

#define GUID_DEVINTERFACE_PWM_CONTROLLER_WSZ L"{60824B4C-EED1-4C9C-B49C-1B961461A819}" 

Untuk mendaftarkan GUID antarmuka perangkat, driver harus memanggil WdfDeviceCreateDeviceInterface dalam implementasi driver dari fungsi panggilan balik EVT_WDF_DRIVER_DEVICE_ADD. Setelah pendaftaran, sistem menetapkan tautan simbolis ke pengontrol dan pin.

Aplikasi atau driver lain dapat mengontrol pengontrol atau pin melalui IOCTL yang ditentukan PWM. Sebelum mengirim IOCTL, aplikasi pengirim atau driver harus membuka handel file ke pengontrol dan pin dengan menentukan tautan simbolisnya. Ini mengharuskan driver untuk mendaftar untuk membuat file dan menutup peristiwa. Lihat (tautan)

Berikut adalah contoh jalur simbolis untuk pengontrol:

\??\ACPI#FSCL000E#1#{60824b4c-eed1-4c9c-b49c-1b961461a819}  

Demikian pula, format pin adalah sebagai berikut: Format jalur adalah sebagai berikut:

<DeviceInterfaceSymbolicLinkName>\<PinNumber>

di mana <PinNumber> adalah indeks berbasis 0 dari pin yang akan dibuka.

Berikut adalah contoh jalur simbolis untuk pin:

\??\ACPI#FSCL000E#1#{60824b4c-eed1-4c9c-b49c-1b961461a819}\0 ; Opens pin 0 

\??\ACPI#FSCL000E#1#{60824b4c-eed1-4c9c-b49c-1b961461a819}\0001 ; Opens pin 1 with the leading 0s have no effect.

Untuk membuka handel file, aplikasi harus memanggil API Configuration Manager (CM_Get_Device_Interface_*).

Setelah handel file dibuka, aplikasi dapat mengirim permintaan ini dengan memanggil fungsi DeviceIoControl. Lihat bagian PWM.

Driver harus menggunakan dukungan PWM yang disediakan rutin PwmParsePinPath untuk mengurai dan memvalidasi jalur pin dan mengekstrak nomor pin.

Mengatur properti antarmuka perangkat

Untuk menggunakan API PWM WinRT dari aplikasi UWP, properti antarmuka perangkat ini harus diatur.

  • DEVPKEY_DeviceInterface_Restricted

    Sesuai model akses perangkat UWP saat ini, mengatur properti Antarmuka perangkat terbatas ke FALSE diperlukan untuk memberi aplikasi UWP akses ke antarmuka perangkat PWM.

  • DEVPKEY_DeviceInterface_SchematicName (tautan???)

    Menetapkan nama skema ke antarmuka perangkat PWM dari perangkat PWM yang terhubung secara statis diperlukan untuk menggunakan metode pabrik PwmController.GetDeviceSelector (FriendlyName). Nama skema adalah nama yang diberikan ke perangkat PWM dalam skema desain sistem misalnya (PWM0, PWM_1, et..). Nama skema diasumsikan unik di seluruh sistem, tetapi itu tidak diberlakukan. Setidaknya, tidak boleh ada 2 perangkat PWM yang memiliki nama skema yang sama, jika tidak, perilaku WinRT PWM PwmController.GetDeviceSelector(FriendlyName) akan menjadi non-deterministik.

Properti dapat diatur dengan salah satu dari dua cara:

  1. Menggunakan file INF untuk driver PWM

    Gunakan direktif AddProperty untuk mengatur properti perangkat. File INF harus memungkinkan pengaturan nilai yang berbeda untuk properti yang sama pada satu atau subset instans perangkat PWM. Berikut adalah contoh pengaturan DEVPKEY_DeviceInterface_Restricted.

    ;***************************************** 
    ; Device interface installation 
    ;***************************************** 
    
    [PWM_Device.NT.Interfaces] 
    AddInterface={60824B4C-EED1-4C9C-B49C-1B961461A819},,PWM_Interface 
    
    [PWM_Interface] 
    AddProperty=PWM_Interface_AddProperty 
    
    ; Set DEVPKEY_DeviceInterface_Restricted property to false to allow UWP access 
    ; to the device interface without the need to be bound with device metadata. 
    ; If Restricted property is set to true, then only applications which are bound 
    ; with device metadata would be allowed access to the device interface. 
    
    [PWM_Interface_AddProperty] 
    {026e516e-b814-414b-83cd-856d6fef4822},6,0x11,,0 
    

    Tidak semua desain memiliki kebijakan yang sama untuk mengekspos perangkat PWM ke UWP. Misalnya, kebijakannya mungkin untuk mengizinkan akses UWP ke subset instans perangkat PWM. Mengekspos subset perangkat PWM atau menetapkan nilai properti yang berbeda ke satu atau subset instans perangkat PWM mengharuskan memiliki ID Perangkat Keras yang berbeda untuk setiap instans perangkat PWM dan mencocokkan bagian INF secara selektif berdasarkan kebijakan.

    Pertimbangkan desain berbasis SoC di mana ada empat instans perangkat PWM (Blok IP) yang identik bernama PWM0,...,PWM3 di mana ID Perangkat Keras yang ditetapkan ACPI (_HID) FSCL00E0 dan ID Unik (_UID) mereka adalah 0,...,3. Mengekspos semua perangkat PWM ke UWP akan memerlukan bagian INF yang mengatur DEVPKEY_DeviceInterface_Restricted agar cocok pada ID Perangkat Keras ACPI\FSCL00E0.

    Cara mengatur properti ini tidak memerlukan perubahan apa pun dalam kode driver. Ini adalah opsi yang lebih mudah karena melayani file INF lebih mudah daripada biner driver. Trade off adalah bahwa pendekatan ini memerlukan file INF yang disesuaikan untuk setiap desain.

  2. Secara terprogram di driver PWM

    Driver PWM dapat memanggil IoSetDeviceInterfacePropertyData untuk mengatur properti antarmuka perangkat dalam implementasi EVT_WDF_DRIVER_DEVICE_ADD mereka setelah membuat dan menerbitkan antarmuka perangkat PWM. Driver bertanggung jawab untuk memutuskan nilai yang akan ditetapkan dan properti perangkat. Informasi tersebut biasanya disimpan dalam sistem ACPI untuk desain berbasis SoC. Nilai setiap properti antarmuka perangkat dapat ditentukan di setiap simpul perangkat ACPI _DSD metode sebagai Properti Perangkat. Driver harus meminta the_DSD dari ACPI, mengurai data Properti Perangkat, mengekstrak nilai setiap properti, dan menetapkan antarmuka perangkatnya.

    Mengatur properti secara terprogram membuat driver dan file INF-nya portabel di seluruh desain dan karenanya BSP di mana satu-satunya perubahan akan berada di ACPI DSDT yang mendefinisikan setiap simpul perangkat PWM. Namun, membaca dan mengurai blok biner ACPI adalah melelahkan dan membutuhkan banyak kode yang dapat rentan terhadap kesalahan dan kerentanan yang mengakibatkan permukaan kesalahan yang lebih besar.

Menangani peristiwa buka/tutup file

Driver PWM perlu mendaftar untuk membuat file dan menutup peristiwa dengan menerapkan fungsi panggilan balik EVT_WDF_DEVICE_FILE_CREATE dan EVT_WDF_FILE_CLEANUP/EVT_WDF_FILE_CLOSE. Dalam implementasi, driver harus melakukan tugas-tugas ini:

  1. Tentukan apakah permintaan buat adalah untuk pengontrol atau pin.

  2. Jika permintaan adalah untuk pin, driver harus mengurai dan memvalidasi jalur pin untuk membuat permintaan pin dan memastikan bahwa nomor pin yang diminta berada dalam batas pengontrol.

  3. Memberikan atau menolak akses ke pengontrol dan pin membuat permintaan.

  4. Pertahankan pengontrol dan sematkan integritas status per komputer status yang terdefinisi dengan baik.

Dalam kumpulan tugas sebelumnya, tugas kedua validasi dapat dilakukan di EVT_WDF_DEVICE_FILE_CREATE, sebagai berikut:

  1. Jika nama file yang terkait dengan objek file permintaan null, selesaikan permintaan dengan STATUS_INVALID_DEVICE_REQUEST.

  2. Jika nama file yang terkait dengan objek file permintaan adalah string kosong, maka ini adalah permintaan pembuatan pengontrol, jika tidak itu adalah permintaan buat pin.

  3. Jika ini adalah permintaan buat pin, maka:

    1. Uraikan jalur pin berdasarkan format <DecimalName> dan ekstrak nomor pin dengan memanggil PwmParsePinPath.

    2. Jika penguraian dan validasi jalur pin gagal, selesaikan permintaan dengan STATUS_NO_SUCH_FILE.

    3. Jika nomor pin lebih besar dari atau sama dengan jumlah pin pengontrol, selesaikan permintaan dengan STATUS_NO_SUCH_FILE. Perhatikan bahwa nomor pin adalah indeks berbasis nol.

    4. Jika tidak, lanjutkan pemrosesan EVT_WDF_DEVICE_FILE_CREATE.

Berikut adalah kode sampel yang mengimplementasikan langkah-langkah validasi yang disebutkan sebelumnya untuk handler EVT_WDF_DEVICE_FILE_CREATE:

EVT_WDF_DEVICE_FILE_CREATE PwmEvtDeviceFileCreate;

VOID 

PwmEvtDeviceFileCreate ( 
    WDFDEVICE WdfDevice, 
    WDFREQUEST WdfRequest, 
    WDFFILEOBJECT WdfFileObject 
    ) 
{ 

    UNICODE_STRING* filenamePtr = WdfFileObjectGetFileName(WdfFileObject); 
    IMXPWM_DEVICE_CONTEXT* deviceContextPtr = PwmGetDeviceContext(WdfDevice); 
    NTSTATUS status; 
    ULONG pinNumber; 

    // 
    // Parse and validate the filename associated with the file object 
    // 

    bool isPinInterface; 

    if (filenamePtr == nullptr) { 

        WdfRequestComplete(WdfRequest, STATUS_INVALID_DEVICE_REQUEST); 

        return; 

    } else if (filenamePtr->Length > 0) { 

        // 
        // A non-empty filename means to open a pin under the controller namespace 
        // 

        status = PwmParsePinPath(filenamePtr, &pinNumber); 

        if (!NT_SUCCESS(status)) { 

            WdfRequestComplete(WdfRequest, status); 

            return; 

        } 


        if (pinNumber >= deviceContextPtr->ControllerInfo.PinCount) { 

            WdfRequestComplete(WdfRequest, STATUS_NO_SUCH_FILE); 

            return; 

        } 


        isPinInterface = true; 

    } else { 

        // 
        // An empty filename means that the create is against the root controller 
        // 

        isPinInterface = false; 
    } 

    // 
    // Continue request processing here 
    // 
} 

Pengontrol dan sematkan Berbagi

Model berbagi untuk pengontrol dan pin mengikuti beberapa pembaca, pola penulis tunggal. Pengontrol/pin dapat dibuka untuk dibaca oleh beberapa penelepon, tetapi hanya satu penelepon yang dapat membuka pengontrol/pin tersebut untuk ditulis pada satu waktu.

Model tersebut dapat diimplementasikan dengan menggunakan kombinasi bendera Akses yang Diinginkan dan Akses Berbagi saat membuka handel file. Model berbagi DDI memilih semantik berbagi yang lebih sederhana di mana hanya spesifikasi Akses yang Diinginkan yang digunakan untuk mengontrol akses. Spesifikasi Akses Berbagi tidak memainkan peran apa pun dalam model berbagi dan tidak dihormati jika ditentukan saat membuka pengontrol atau pin.

Dalam EVT_WDF_DEVICE_FILE_CREATE, permintaan pembuatan Akses yang Diinginkan dan Akses Berbagi harus diekstraksi dan divalidasi berdasarkan status pengontrol/pin atau sebagai berikut:

  1. Jika Akses Berbagi bukan 0, tolak akses, dan selesaikan permintaan dengan STATUS_SHARING_VIOLATION.

  2. Jika Akses yang Diinginkan adalah untuk baca-saja, berikan akses dan lanjutkan pemrosesan EVT_WDF_DEVICE_FILE_CREATE.

  3. Jika Akses yang Diinginkan adalah untuk menulis, maka:

Jika pengontrol/pin sudah dibuka untuk tulis, tolak akses, dan selesaikan permintaan dengan STATUS_SHARING_VIOLATION, jika tidak berikan akses, tandai pengontrol atau sematkan sebagai dibuka untuk menulis dan melanjutkan pemrosesan EVT_WDF_DEVICE_FILE_CREATE.

Berikut adalah contoh memperlihatkan cara mengekstrak Akses yang Diinginkan dan Berbagi Akses dari permintaan buat:

void 
PwmCreateRequestGetAccess( 
    _In_ WDFREQUEST WdfRequest, 
    _Out_ ACCESS_MASK* DesiredAccessPtr, 
    _Out_ ULONG* ShareAccessPtr 
    ) 
{ 

    NT_ASSERT(ARGUMENT_PRESENT(DesiredAccessPtr)); 

    NT_ASSERT(ARGUMENT_PRESENT(ShareAccessPtr)); 


    WDF_REQUEST_PARAMETERS wdfRequestParameters; 

    WDF_REQUEST_PARAMETERS_INIT(&wdfRequestParameters); 

    WdfRequestGetParameters(WdfRequest, &wdfRequestParameters); 


    NT_ASSERTMSG( 

        "Expected create request", 
        wdfRequestParameters.Type == WdfRequestTypeCreate); 


    *DesiredAccessPtr = 
        wdfRequestParameters.Parameters.Create.SecurityContext->DesiredAccess; 

    *ShareAccessPtr = wdfRequestParameters.Parameters.Create.ShareAccess; 
} 

Pengontrol dan menyematkan independensi

Pengontrol dan pin memiliki hubungan induk-anak. Untuk membuka pin, Anda harus terlebih dahulu membuka pengontrol induknya. Cara lain adalah melihat pin adalah sebagai entitas independen di mana pengontrol induknya hanya menyediakan satu layanan ke pin yang mengatur periode PWM global untuk semua pin yang terkandung pada pengontrol tersebut.

Berikut adalah beberapa contoh skenario:

  • Akses proses tunggal:

    • Proses A dapat membuka pin, mengatur siklus tugasnya, memulainya menggunakan periode default pengontrol dan kemudian membuka pengontrol dan mengatur periode sesuai permintaan. Mungkin tidak perlu membuka pengontrol jika periode default ok untuk aplikasi.

    • Proses dapat memiliki beberapa utas di mana masing-masing mengontrol pin yang berbeda di bawah pengontrol yang sama.

  • Akses multi-proses:

    • Utilitas baris perintah dapat membuka pengontrol dengan akses baca-saja untuk tujuan menampilkan informasi ke konsol. Pada saat yang sama, tugas UWP latar belakang dapat membuka pengontrol untuk menulis dan mengontrol beberapa LED dengan satu pin.

    • Driver tampilan mode kernel mengontrol lampu latar LCD melalui Pin0 sambil menahan pengontrol untuk menulis dan mengunci periode PWM. Pada saat yang sama, layanan Win32 menggunakan periode PWM yang ditetapkan oleh driver tampilan dan menggunakan Pin1 untuk meredupkan beberapa LED untuk mengomunikasikan beberapa status kepada pengguna.

Perhatikan bahwa ada beberapa implikasi penting untuk membuka dan menutup pengontrol secara independen dari pin-nya. Untuk informasi selengkapnya, lihat bagian komputer status.

Pengontrol dan sematkan mesin status

Definisi status pengontrol

Fitur status Nilai default Deskripsi
Is-opened-for-write Salah False menunjukkan bahwa pengontrol ditutup atau dibuka untuk dibaca; True menunjukkan bahwa itu dibuka untuk menulis.
Desired-Period MinimumPeriod

Mesin status pengontrol.

Komputer status pengontrol di bawah ini berpusat di sekitar status Is-Opened-For-Write saja. Nilai periode yang diinginkan juga dibiarkan karena tidak memengaruhi jenis operasi yang dapat dilakukan pada pengontrol. Perhatikan bahwa setiap kali pengontrol yang dibuka untuk tulis ditutup oleh pemanggil yang membukanya untuk ditulis, pengontrol akan direset ke defaultnya (periode default yang diinginkan).

Menyematkan definisi status

Fitur status Nilai default Deskripsi
Is-opened-for-write FALSE False menunjukkan bahwa pin ditutup atau dibuka untuk dibaca; True menunjukkan bahwa itu dibuka untuk menulis.
Siklus Tugas Aktif 0
Is-Started FALSE False menunjukkan berhenti; True menunjukkan dimulai.

Menyematkan mesin status.

Mesin status pin berpusat di sekitar kombinasi 2 status Is-Opened-For-Write dan Is-Started. Status pin lain seperti polaritas dan siklus tugas aktif dibiarkan karena nilainya tidak memengaruhi jenis operasi yang dapat dilakukan pada pin. Perhatikan bahwa setiap kali pin yang dibuka untuk tulis ditutup oleh pemanggil yang membukanya untuk menulis, pin beristirahat ke defaultnya (dihentikan, polaritas default, dan siklus tugas aktif). Perhatikan juga bahwa transisi Set-Polarity pada status dengan Is-Started = true dibiarkan karena tidak valid dalam status tersebut.

Setiap transisi yang tidak disebutkan untuk status tertentu menyiratkan bahwa transisi tersebut tidak valid atau tidak mungkin dan permintaan yang sesuai harus diselesaikan dengan status kesalahan yang sesuai.

Pertimbangan implementasi untuk transisi status

  • Dalam EVT_WDF_DEVICE_FILE_CREATE, driver harus memberikan atau menolak akses berdasarkan permintaan buat akses yang diinginkan dan pengontrol atau menyematkan status Is-Opened-For-Write sebagai berikut:

    Jika permintaan memiliki akses yang diinginkan tulis dan pengontrol/pin sudah dibuka untuk ditulis, maka selesaikan permintaan dengan STATUS_SHARING_VIOLATION, jika tidak tandai pengontrol/pin sebagai dibuka untuk tulis (Is-Opened-For-Write = true), berikan akses dan lanjutkan pemrosesan.

    Contoh ini mengimplementasikan langkah-langkah validasi akses yang disebutkan sebelumnya untuk handler EVT_WDF_DEVICE_FILE_CREATE di mana logika penguncian yang diperlukan untuk menangani permintaan pembuatan file bersamaan dihilangkan:

    //
    // Verify request desired access
    //
    
    const bool hasWriteAccess = desiredAccess & FILE_WRITE_DATA;
    
    if (isPinInterface) {
        PWM_PIN_STATE* pinPtr = deviceContextPtr->Pins + pinNumber;
        if (hasWriteAccess) {
            if (pinPtr->IsOpenForReadWrite) {
                PWM_LOG_TRACE("Pin%lu access denied.", pinNumber);
                WdfRequestComplete(WdfRequest, STATUS_SHARING_VIOLATION);
                return;
            }
            pinPtr->IsOpenForReadWrite = true;
        }
        PWM_LOG_TRACE(
            "Pin%lu Opened. (IsOpenForReadWrite = %lu)",
            pinNumber,
            (pinPtr->IsOpenForReadWrite ? 1 : 0));
    
    } else {
        if (hasWriteAccess) {
            if (deviceContextPtr->IsControllerOpenForReadWrite) {
                PWM_LOG_TRACE("Controller access denied.");
                WdfRequestComplete(WdfRequest, STATUS_SHARING_VIOLATION);
                return;
            }
            deviceContextPtr->IsControllerOpenForReadWrite = true;
        }
        PWM_LOG_TRACE(
            "Controller Opened. (IsControllerOpenForReadWrite = %lu)",
            (deviceContextPtr->IsControllerOpenForReadWrite ? 1 : 0));
    }
    
    //
    // Allocate and fill a file object context
    //
    IMXPWM_FILE_OBJECT_CONTEXT* fileObjectContextPtr;
    {
        WDF_OBJECT_ATTRIBUTES wdfObjectAttributes;
        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(
            &wdfObjectAttributes,
            IMXPWM_FILE_OBJECT_CONTEXT);
    
        void* contextPtr;
        NTSTATUS status = WdfObjectAllocateContext(
                WdfFileObject,
                &wdfObjectAttributes,
                &contextPtr);
        if (!NT_SUCCESS(status)) {
            IMXPWM_LOG_ERROR(
                "WdfObjectAllocateContext(...) failed. (status = %!STATUS!)",
                status);
            WdfRequestComplete(WdfRequest, status);
            return;
        }
    
        fileObjectContextPtr =
            static_cast<IMXPWM_FILE_OBJECT_CONTEXT*>(contextPtr);
    
        NT_ASSERT(fileObjectContextPtr != nullptr);
        fileObjectContextPtr->IsPinInterface = isPinInterface;
        fileObjectContextPtr->IsOpenForWrite = hasWriteAccess;
        fileObjectContextPtr->PinNumber = pinNumber;
    }
    
  • Dalam EVT_WDF_FILE_CLOSE/ EVT_WDF_FILE_CLEANUP, driver harus mempertahankan integritas status pengontrol/pin.

    Jika objek file milik pengontrol/pin yang membuka pengontrol/pin tersebut untuk tulis, maka reset pengontrol/sematkan ke status default dan hapus tanda pengontrol/pin agar tidak dibuka untuk tulis (Is-Opened-For-Write = false).

    Contoh ini mengimplementasikan langkah-langkah validasi akses yang disebutkan sebelumnya untuk handler EVT_WDF_DEVICE_FILE_CLOSE di mana logika penguncian yang diperlukan untuk menangani permintaan penutupan file bersamaan dihilangkan.

    EVT_WDF_DEVICE_FILE_CLOSE PwmEvtFileClose;
    
    VOID
    PwmEvtFileClose (
        WDFFILEOBJECT WdfFileObject
        )
    {
        WDFDEVICE wdfDevice = WdfFileObjectGetDevice(WdfFileObject);
        PWM_DEVICE_CONTEXT* deviceContextPtr = PwmGetDeviceContext(wdfDevice);
        PWM_FILE_OBJECT_CONTEXT* fileObjectContextPtr = PwmGetFileObjectContext(WdfFileObject);
    
        if (fileObjectContextPtr->IsPinInterface) {
            if (fileObjectContextPtr->IsOpenForReadWrite) {
                const ULONG pinNumber = fileObjectContextPtr->PinNumber;
    
                NTSTATUS status = PwmResetPinDefaults(deviceContextPtr, pinNumber);
                if (!NT_SUCCESS(status)) {
                    PWM_LOG_ERROR(
                        "PwmResetPinDefaults(...) failed. "
                        "(pinNumber = %lu, status = %!STATUS!)",
                        pinNumber,
                        status);
                    //
                    // HW Error Recovery
                    //
                }
    
                NT_ASSERT(deviceContextPtr->Pins[pinNumber].IsOpenForReadWrite);
                deviceContextPtr->Pins[pinNumber].IsOpenForReadWrite = false;
            }
    
            PWM_LOG_TRACE("Pin%lu Closed.", fileObjectContextPtr->PinNumber);
    
        } else {
            if (fileObjectContextPtr->IsOpenForReadWrite) {
                NTSTATUS status = PwmResetControllerDefaults(deviceContextPtr);
                if (!NT_SUCCESS(status)) {
                    IMXPWM_LOG_ERROR(
                        "PwmResetControllerDefaults(...) failed. (status = %!STATUS!)",
                        status);
                    //
                    // HW Error Recovery
                    //  
                }
    
                NT_ASSERT(deviceContextPtr->IsControllerOpenForReadWrite);
                deviceContextPtr->IsControllerOpenForReadWrite = false;
            }
    
            PWM_LOG_TRACE("Controller Closed.");
        }
    }
    

Permintaan PWM IOCTL

Permintaan PWM IOCTL dikirim oleh aplikasi atau driver lain dan ditargetkan untuk pengontrol atau pin tertentu.

IOCTL Pengontrol

Sematkan IOCTL

Untuk setiap permintaan IOCTL, driver PWM harus memverifikasi hal berikut:

  1. Operasi yang diminta (kode IOCTL) valid untuk permintaan objek file terkait.

  2. Minta buffer input dan output dan pastikan setidaknya ukuran minimum yang diharapkan.

  3. Validitas operasi yang diminta dalam status pengontrol/pin saat ini.

  4. Validitas parameter input individual. Misalnya: periode nol yang diinginkan adalah parameter yang tidak valid untuk IOCTL_PWM_CONTROLLER_SET_DESIRED_PERIOD.

Kode status penyelesaian IOCTL

Driver PWM harus menyelesaikan permintaan IOCTL dengan kode status yang sesuai. Berikut adalah kode status penyelesaian umum. Secara umum, IOCTL yang menetapkan properti dengan nilai yang sudah ditetapkan harus selalu berhasil. Contoh foe, mengatur periode yang sama persis yang sudah diatur, menghentikan pin yang sudah dihentikan, mengatur polaritas yang sudah diatur, dan sebagainya.

STATUS_NOT_SUPPORTED

Operasi IOCTL yang diminta tidak diimplementasikan atau didukung. Misalnya, beberapa pengontrol mungkin tidak mendukung pengaturan polaritas sinyal output, dalam hal ini IOCTL_PWM_PIN_SET_POLARITY harus diimplementasikan tetapi gagal dengan STATUS_NOT_SUPPORTED untuk polaritas non-default.

STATUS_INVALID_DEVICE_REQUEST

Permintaan IOCTL dikirim ke target yang salah. Misalnya, permintaan IOCTL pengontrol dikirim menggunakan handel file pin.

STATUS_BUFFER_TOO_SMALL

Ukuran buffer input atau output kurang dari ukuran buffer minimum yang diperlukan untuk memproses permintaan. Driver WDF yang menggunakan WdfRequestRetrieveInputBuffer atau WdfRequestRetrieveOutputBuffer untuk mengambil dan memvalidasi buffer input dan output dapat mengembalikan status kesalahan yang sesuai apa adanya. Semua IOCTL dengan buffer input dan/atau output yang ditentukan untuk mereka memiliki struct yang sesuai yang menjelaskan bahwa buffer, di mana nama struct input dan output masing-masing memiliki INPUT dan _OUTPUT postfix. Ukuran minimum buffer input adalah sizeof(PWMINPUT) sedangkan ukuran minimum buffer output adalah sizeof(PWM_OUTPUT).

Kode IOCTL Deskripsi
IOCTL_PWM_CONTROLLER_GET_ACTUAL_PERIOD Mengambil periode sinyal output efektif pengontrol Pulse Width Modulation (PWM) seperti yang akan diukur pada saluran outputnya. Mengembalikan nilai PWM_CONTROLLER_GET_ACTUAL_PERIOD_OUTPUT. Irp-IoStatus.Status> diatur ke salah satu nilai dalam daftar berikut.
  • STATUS_SUCCESS
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_CONTROLLER_GET_INFO Mengambil informasi tentang pengontrol Pulse Width Modulation (PWM). Informasi ini tidak berubah setelah pengontrol diinisialisasi.

Pemanggil harus melewati buffer output yang memiliki ukuran struct PWM_CONTROLLER_INFO. Driver menyimpulkan versi struktur dari ukuran buffer output permintaan.

Jika ukuran buffer kurang dari ukuran versi struktur terendah, permintaan diselesaikan dengan menggunakan status penyelesaian IOCTL STATUS_BUFFER_TOO_SMALL. Jika tidak, driver mengasumsikan versi struktur tertinggi yang dapat masuk ke dalam buffer output yang disediakan dan berhasil menyelesaikan permintaan.

Versi PWM_CONTROLLER_INFO yang lebih baru memiliki ukuran byte yang lebih besar dari versi sebelumnya

Irp-IoStatus.Status> diatur ke salah satu nilai dalam daftar berikut.
  • STATUS_SUCCESS
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_CONTROLLER_SET_DESIRED_PERIOD Mengatur periode sinyal output pengontrol Pulse Width Modulation (PWM) ke nilai yang disarankan.

Pengontrol PWM mencoba mengatur periode yang sedekat mungkin dengan nilai yang diminta berdasarkan kemampuannya. Periode efektif dikembalikan sebagai output IOCTL. Ini nantinya dapat diambil dengan menggunakan IOCTL_PWM_CONTROLLER_GET_ACTUAL_PERIOD.

Periode yang diinginkan harus lebih besar dari nol (0) dan dalam rentang periode yang didukung pengontrol. Artinya, harus dalam kisaran MinimumPeriod dan MaximumPeriod, inklusif, yang dapat diambil dengan menggunakan IOCTL_PWM_CONTROLLER_GET_INFO.

Irp-IoStatus.Status> diatur ke salah satu nilai dalam daftar berikut.
  • STATUS_SUCCESS
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_INVALID_PARAMETER
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_GET_ACTIVE_DUTY_CYCLE_PERCENTAGE Mengambil persentase siklus tugas saat ini untuk pin atau saluran. Kode kontrol mengembalikan persentase sebagai struktur PWM_PIN_GET_ACTIVE_DUTY_CYCLE_PERCENTAGE_OUTPUT.

Irp-IoStatus.Status> diatur ke salah satu nilai dalam daftar berikut.

  • STATUS_SUCCESS
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_SET_ACTIVE_DUTY_CYCLE_PERCENTAGE Tetapkan nilai persentase siklus tugas yang diinginkan untuk pin atau saluran pengontrol. Kode kontrol menentukan persentase sebagai struktur PWM_PIN_SET_ACTIVE_DUTY_CYCLE_PERCENTAGE_INPUT.

Irp-IoStatus.Status> diatur ke salah satu nilai dalam daftar berikut.

  • STATUS_SUCCESS
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_GET_POLARITY Mengambil polaritas sinyal saat ini dari pin atau saluran. Kode kontrol mendapatkan polaritas sinyal sebagai struktur PWM_PIN_GET_POLARITY_OUTPUT. Polaritas sinyal adalah Aktif Tinggi atau Aktif Rendah, seperti yang didefinisikan dalam enumerasi PWM_POLARITY.

Irp-IoStatus.Status> diatur ke salah satu nilai dalam daftar berikut.

  • STATUS_SUCCESS
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_SET_POLARITY Mengatur polaritas sinyal pin atau saluran. Kode kontrol mengatur polaritas sinyal berdasarkan struktur PWM_PIN_SET_POLARITY_INPUT. Polaritas sinyal adalah Aktif Tinggi atau Aktif Rendah, seperti yang didefinisikan dalam enum PWM_POLARITY.

Mengubah polaritas hanya diperbolehkan ketika pin dihentikan. Anda dapat mengetahui apakah pin dihentikan dengan menggunakan kode kontrol IOCTL_PWM_PIN_IS_STARTED. Jika pin dihentikan dan polaritas yang diminta berbeda dari polaritas pin saat ini, permintaan diselesaikan dengan nilai STATUS_INVALID_DEVICE_STATE.

Mengubah polaritas saat pin dimulai dapat menyebabkan gangguan pada beberapa pengontrol Pulse Width Modulation (PWM). Jika Anda ingin mengubah polaritas, hentikan pin terlebih dahulu, ubah polaritas, lalu mulai pin.

Irp-IoStatus.Status> diatur ke salah satu nilai dalam daftar berikut.

  • STATUS_SUCCESS
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_INVALID_PARAMETER
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_START Memulai pembuatan sinyal Pulse Width Modulation (PWM) pada pin atau saluran. Untuk memeriksa apakah pin dimulai, gunakan IOCTL_PWM_PIN_IS_STARTED.

Mengeluarkan IOCTL ini pada pin atau saluran yang sudah dimulai tidak berpengaruh, tetapi berhasil.

Irp-IoStatus.Status> diatur ke salah satu nilai dalam daftar berikut.

>
  • STATUS_SUCCESS
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_STOP Menghentikan pembuatan sinyal Pulse Width Modulation (PWM) pada pin atau saluran. Untuk memeriksa apakah pin dimulai, gunakan IOCTL_PWM_PIN_IS_STARTED.

Mengeluarkan IOCTL ini pada pin atau saluran yang sudah dihentikan tidak berpengaruh, tetapi berhasil.

Irp-IoStatus.Status> diatur ke salah satu nilai dalam daftar berikut.

  • STATUS_SUCCESS
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL
IOCTL_PWM_PIN_IS_STARTED Mengambil status pembuatan sinyal untuk pin atau saluran. Setiap pin memiliki status dimulai atau dihentikan sebagai struktur PWM_PIN_IS_STARTED_OUTPUT. Status dimulai memiliki nilai Boolean true. Status yang dihentikan adalah false.

Secara default, pin dihentikan saat dibuka dan kembali ke status berhenti saat ditutup atau dirilis.

Irp-IoStatus.Status> diatur ke salah satu nilai dalam daftar berikut.

  • STATUS_SUCCESS
  • STATUS_NOT_SUPPORTED
  • STATUS_INVALID_DEVICE_REQUEST
  • STATUS_BUFFER_TOO_SMALL