Bagikan melalui


Cara mengimplementasikan fungsi suspend dalam driver komposit

Artikel ini memberikan gambaran umum tentang fitur suspend dan fungsi remote wake-up untuk perangkat multifungsi Universal Serial Bus (USB) 3.0 (perangkat komposit). Dalam artikel ini, Anda akan mempelajari tentang menerapkan fitur tersebut dalam driver yang mengontrol perangkat komposit. Artikel ini berlaku untuk driver komposit yang menggantikan Usbccgp.sys.

Spesifikasi Universal Serial Bus (USB) 3.0 mendefinisikan fitur baru yang disebut fungsi ditangguhkan. Fitur ini memungkinkan fungsi individual perangkat komposit untuk memasuki status berdaya rendah, secara independen dari fungsi lain. Pertimbangkan perangkat komposit yang menentukan fungsi untuk keyboard dan fungsi lain untuk mouse. Pengguna menyimpan fungsi keyboard dalam status berfungsi tetapi tidak memindahkan mouse untuk jangka waktu tertentu. Driver klien untuk mouse dapat mendeteksi status diam fungsi dan mengirim fungsi untuk menangguhkan status sementara fungsi keyboard tetap dalam status kerja.

Seluruh perangkat dapat beralih ke status ditangguhkan terlepas dari status daya fungsi apa pun dalam perangkat. Jika fungsi tertentu dan semua perangkat memasuki mode suspensi, mode suspensi fungsi dipertahankan sementara perangkat berada dalam mode suspensi, dan selama proses masuk dan keluar dari mode suspensi perangkat.

Mirip dengan fitur bangun jarak jauh perangkat USB 2.0 (lihat Remote Wake-up Perangkat USB), fungsi individual dalam perangkat komposit USB 3.0 dapat bangun dari status daya rendah tanpa memengaruhi status daya fungsi lain. Fitur ini disebut fungsi bangun jarak jauh. Fitur ini secara eksplisit diaktifkan oleh host dengan mengirim perintah protokol yang mengatur bit remote wake-up di firmware perangkat. Proses ini disebut mengaktifkan fungsi untuk penyalaan dari jauh. Untuk informasi tentang bit terkait pemicu bangun dari jarak jauh, lihat Gambar 9-6 dalam spesifikasi USB resmi.

Jika fungsi diaktifkan untuk membangunkan dari jarak jauh, fungsi (ketika dalam mode suspend) mempertahankan daya yang cukup untuk menghasilkan sinyal resume bangun saat aksi pengguna terjadi pada perangkat fisik. Sebagai hasil dari sinyal resume tersebut, driver klien kemudian dapat keluar dari status tangguhan fungsi terkait. Dalam contoh untuk fungsi mouse pada perangkat komposit, ketika pengguna menggerakkan mouse yang berada dalam keadaan diam, fungsi mouse mengirimkan sinyal melanjutkan ke host. Pada host, tumpukan driver USB mendeteksi fungsi mana yang terbangun dan menyebarkan pemberitahuan ke driver klien untuk fungsi yang bersangkutan. Driver klien kemudian dapat membangunkan fungsi dan memasuki status kerja.

Untuk driver klien, langkah-langkah untuk mengirim fungsi untuk menangguhkan status dan membangunkan fungsi mirip dengan driver perangkat fungsi tunggal yang mengirim seluruh perangkat untuk menangguhkan status. Prosedur berikut ini meringkas langkah-langkah tersebut.

  1. Deteksi kapan fungsi terkait dalam status diam.
  2. Kirim paket permintaan operasi I/O tidak aktif (IRP).
  3. Kirim permintaan untuk mengaktifkan fungsinya untuk membangunkan dari jarak jauh menggunakan paket permintaan I/O tunggu-bangun (IRP).
  4. Transisikan fungsi ke status daya rendah dengan mengirim permintaan daya IRP Dx (D2 atau D3).

Untuk informasi selengkapnya tentang langkah-langkah sebelumnya, lihat "Mengirim USB Idle Request IRP" di USB Selective Suspend. Driver komposit membuat objek perangkat fisik (PDO) untuk setiap fungsi di perangkat komposit dan menangani permintaan daya yang dikirim oleh driver klien (FDO tumpukan perangkat fungsi). Agar pengandar klien berhasil masuk dan keluar dari status penangguhan untuk fungsinya, pengandar komposit harus mendukung penangguhan fungsi dan fitur pembangkitan jarak jauh, serta memproses permintaan daya masuk.

Di Windows 8, tumpukan driver USB untuk perangkat USB 3.0 mendukung fitur tersebut. Selain itu, fungsi suspend dan fungsi bangun jarak jauh serta implementasinya telah ditambahkan ke driver induk generik USB yang disediakan Microsoft (Usbccgp.sys), yang merupakan driver default komposit Windows. Jika Anda menulis driver komposit kustom, driver Anda harus menangani permintaan terkait penangguhan fungsi dan pembangkitan jarak jauh, sesuai dengan prosedur berikut.

Langkah 1: Tentukan apakah tumpukan driver USB mendukung fungsi ditangguhkan

Dalam rutinitas memulai perangkat (IRP_MN_START_DEVICE) driver komposit Anda, lakukan langkah-langkah berikut:

  1. Panggil rutinitas USBD_QueryUsbCapability untuk menentukan apakah tumpukan driver USB yang mendasar mendukung kemampuan penangguhan fungsi. Panggilan memerlukan handel USBD valid yang Anda peroleh dalam panggilan sebelumnya ke rutinitas USBD_CreateHandle .

Panggilan yang berhasil ke USBD_QueryUsbCapability menentukan apakah stack driver USB dasar mendukung penangguhan fungsi. Panggilan dapat mengembalikan kode kesalahan yang menunjukkan bahwa tumpukan driver USB tidak mendukung fungsi suspend atau perangkat yang terpasang bukan perangkat multi-fungsi USB 3.0.

  1. Jika panggilan USBD_QueryUsbCapability menunjukkan bahwa fungsi suspend didukung, daftarkan perangkat komposit dengan lapisan driver USB yang mendasar. Untuk mendaftarkan perangkat komposit, Anda harus mengirim permintaan kontrol I/O IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DEVICE . Untuk informasi selengkapnya tentang permintaan ini, lihat Cara Mendaftarkan Perangkat Komposit.

Permintaan pendaftaran menggunakan struktur REGISTER_COMPOSITE_DEVICE untuk menentukan informasi tersebut tentang driver komposit. Pastikan Anda mengatur CapabilityFunctionSuspend ke 1 untuk menunjukkan bahwa driver komposit mendukung penundaan fungsi.

Untuk contoh kode yang menunjukkan cara menentukan apakah tumpukan driver USB mendukung penangguhan fungsi, lihat USBD_QueryUsbCapability.

Langkah 2: Menangani IRP dalam keadaan idle

Driver klien dapat mengirimkan IRP dalam keadaan idle (lihat IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION). Permintaan dikirim setelah driver klien mendeteksi status menganggur untuk fungsi tersebut. IRP berisi penunjuk ke rutinitas penyelesaian panggilan balik (disebut panggilan balik menganggur) yang diimplementasikan oleh driver klien. Dalam panggilan balik diam, klien melakukan tugas, seperti membatalkan transfer I/O yang tertunda, tepat sebelum mengirim fungsi ke status ditangguhkan.

Nota

Mekanisme IRP yang tidak aktif bersifat opsional untuk driver klien dari perangkat USB 3.0. Namun, sebagian besar driver klien ditulis untuk mendukung perangkat USB 2.0 dan USB 3.0. Untuk mendukung perangkat USB 2.0, driver harus mengirim IRP diam, karena driver komposit bergantung pada IRP tersebut untuk melacak status daya setiap fungsi. Jika semua fungsi tidak aktif, driver komposit mengirimkan seluruh perangkat ke dalam keadaan suspensi.

Setelah menerima IRP idle dari driver klien, driver komposit harus segera memanggil callback idle untuk memberi tahu driver klien bahwa driver klien dapat mengirim fungsi ke status suspend.

Langkah 3: Mengirim permintaan untuk pemberitahuan bangun jarak jauh

Driver klien dapat mengirimkan permintaan untuk mengaktifkan fungsinya untuk bangun dari jarak jauh dengan mengirimkan IRP IRP_MJ_POWER dengan kode fungsi minor yang diatur ke IRP_MN_WAIT_WAKE (IRP tunggu-bangun). Driver klien mengirimkan permintaan ini hanya jika driver ingin memasuki status kerja sebagai akibat dari peristiwa pengguna.

Setelah menerima IRP wait-wake, driver komposit harus mengirimkan sebuah permintaan I/O kontrol IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION ke tumpukan driver USB. Permintaan ini memungkinkan tumpukan driver USB untuk memberi tahu driver komposit ketika tumpukan tersebut menerima pemberitahuan tentang sinyal melanjutkan. IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION menggunakan struktur REQUEST_REMOTE_WAKE_NOTIFICATION untuk menentukan parameter permintaan. Salah satu nilai yang harus ditentukan driver komposit adalah handle fungsi untuk fungsi yang disiapkan untuk bangun dari jarak jauh. Driver komposit memperoleh handel tersebut dalam permintaan sebelumnya untuk mendaftarkan perangkat komposit dengan tumpukan driver USB. Untuk informasi selengkapnya tentang permintaan pendaftaran driver komposit, lihat Cara Mendaftarkan Perangkat Komposit.

Dalam IRP untuk permintaan, driver komposit memasok pointer ke rutinitas penyelesaian tugas (bangun dari jarak jauh), yang diimplementasikan oleh driver komposit.

Contoh kode berikut menunjukkan cara mengirim permintaan bangun jarak jauh.

/*++

Description:
    This routine sends a IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION request
    to the USB driver stack. The IOCTL is completed by the USB driver stack
    when the function wakes up from sleep.

    Parameters:
    parentFdoExt: The device context associated with the FDO for the
    composite driver.

    functionPdoExt: The device context associated with the PDO (created by
    the composite driver) for the client driver.
--*/

VOID
SendRequestForRemoteWakeNotification(
    __inout PPARENT_FDO_EXT parentFdoExt,
    __inout PFUNCTION_PDO_EXT functionPdoExt
)

{
    PIRP                                irp;
    REQUEST_REMOTE_WAKE_NOTIFICATION    remoteWake;
    PIO_STACK_LOCATION                  nextStack;
    NTSTATUS                            status;

    // Allocate an IRP
    irp =  IoAllocateIrp(parentFdoExt->topDevObj->StackSize, FALSE);

    if (irp)
    {

        //Initialize the USBDEVICE_REMOTE_WAKE_NOTIFICATION structure
        remoteWake.Version = 0;
        remoteWake.Size = sizeof(REQUEST_REMOTE_WAKE_NOTIFICATION);
        remoteWake.UsbdFunctionHandle = functionPdoExt->functionHandle;
        remoteWake.Interface = functionPdoExt->baseInterfaceNumber;

        nextStack = IoGetNextIrpStackLocation(irp);

        nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
        nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION;

        nextStack->Parameters.Others.Argument1 = &remoteWake;

        // Caller's completion routine will free the IRP when it completes.

        SetCompletionRoutine(functionPdoExt->debugLog,
                             parentFdoExt->fdo,
                             irp,
                             CompletionRemoteWakeNotication,
                             (PVOID)functionPdoExt,
                             TRUE, TRUE, TRUE);

        // Pass the IRP
        IoCallDriver(parentFdoExt->topDevObj, irp);

    }

    return;
}

Permintaan IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION diselesaikan oleh lapisan driver USB selama proses pembangkitan ketika menerima pemberitahuan tentang sinyal melanjutkan. Selama waktu itu, tumpukan driver USB juga memanggil proses penyelesaian pemulihan jarak jauh.

Driver komposit harus menjaga wait-wake IRP tetap tertunda dan memasukkannya ke dalam antrian untuk diproses nanti. Driver komposit harus menyelesaikan IRP itu ketika rutinitas penyelesaian bangun jarak jauh driver dipanggil oleh stack driver USB.

Langkah 4: Kirim permintaan untuk menyiapkan fungsi bangun jarak jauh

Untuk mengirim fungsi ke status daya rendah, driver klien mengirimkan IRP IRP_MN_SET_POWER dengan permintaan untuk mengubah status daya perangkat Windows Driver Model (WDM) ke D2 atau D3. Biasanya, driver klien mengirim D2 IRP jika driver mengirim IRP tunggu-bangun sebelumnya untuk meminta bangun jarak jauh. Jika tidak, driver klien mengirimkan D3 IRP.

Setelah menerima D2 IRP, driver komposit harus terlebih dahulu menentukan apakah IRP tunggu-bangun tertunda dari permintaan sebelumnya yang dikirim oleh driver klien. Jika IRP tertunda, driver komposit harus mengaktifkan fungsi untuk bangun jarak jauh. Untuk melakukannya, driver komposit harus mengirim permintaan kontrol SET_FEATURE ke antarmuka pertama fungsi, untuk memungkinkan perangkat mengirim sinyal resume. Untuk mengirim permintaan kontrol, alokasikan struktur URB dengan memanggil rutinitas USBD_UrbAllocate dan memanggil makro UsbBuildFeatureRequest untuk memformat URB untuk permintaan SET_FEATURE. Dalam panggilan, tentukan URB_FUNCTION_SET_FEATURE_TO_INTERFACE sebagai kode operasi dan USB_FEATURE_FUNCTION_SUSPEND sebagai pemilih fitur. Dalam parameter Indeks , atur Bit 1 dari byte yang paling signifikan. Nilai tersebut disalin ke bidang wIndex dalam paket penyiapan transfer.

Contoh berikut menunjukkan cara mengirim permintaan kontrol SET_FEATURE.

/*++

Routine Description:

Sends a SET_FEATURE for REMOTE_WAKEUP to the device using a standard control request.

Parameters:
parentFdoExt: The device context associated with the FDO for the
composite driver.

functionPdoExt: The device context associated with the PDO (created by
the composite driver) for the client driver.

Returns:

NTSTATUS code.

--*/
VOID
    NTSTATUS SendSetFeatureControlRequestToSuspend(
    __inout PPARENT_FDO_EXT parentFdoExt,
    __inout PFUNCTION_PDO_EXT functionPdoExt,
    )

{
    PURB                            urb
    PIRP                            irp;
    PIO_STACK_LOCATION              nextStack;
    NTSTATUS                        status;

    status = USBD_UrbAllocate(parentFdoExt->usbdHandle, &urb);

    if (!NT_SUCCESS(status))
    {
        //USBD_UrbAllocate failed.
        goto Exit;
    }

    //Format the URB structure.
    UsbBuildFeatureRequest (
        urb,
        URB_FUNCTION_SET_FEATURE_TO_INTERFACE, // Operation code
        USB_FEATURE_FUNCTION_SUSPEND,          // feature selector
        functionPdoExt->firstInterface,           // first interface of the function
        NULL);

    irp =  IoAllocateIrp(parentFdoExt->topDevObj->StackSize, FALSE);

    if (!irp)
    {
        // IoAllocateIrp failed.
        status = STATUS_INSUFFICIENT_RESOURCES;

        goto Exit;
    }

    nextStack = IoGetNextIrpStackLocation(irp);

    nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;

    nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;

    //  Attach the URB to the IRP.
    USBD_AssignUrbToIoStackLocation(nextStack, (PURB)urb);

    // Caller's completion routine will free the IRP when it completes.
    SetCompletionRoutine(functionPdoExt->debugLog,
        parentFdoExt->fdo,
        irp,
        CompletionForSuspendControlRequest,
        (PVOID)functionPdoExt,
        TRUE, TRUE, TRUE);


    // Pass the IRP
    IoCallDriver(parentFdoExt->topDevObj, irp);


Exit:
    if (urb)
    {
        USBD_UrbFree( parentFdoExt->usbdHandle, urb);
    }

    return status;

}

Driver komposit kemudian mengirim IRP D2 ke tumpukan driver USB. Jika semua fungsi lain dalam status ditangguhkan, tumpukan driver USB menangguhkan port dengan memanipulasi register port tertentu pada pengontrol.

Komentar

Dalam contoh fungsi mouse, karena fitur bangun jarak jauh diaktifkan (lihat langkah 4), fungsi mouse menghasilkan sinyal resume pada kawat upstream ke pengontrol host saat pengguna menggulung mouse. Pengontrol kemudian memberi tahu tumpukan driver USB dengan mengirim paket pemberitahuan yang berisi informasi tentang fungsi yang terbangun. Untuk informasi tentang Pemberitahuan Bangun Fungsi, lihat Gambar 8-17 dalam spesifikasi USB 3.0.

Setelah menerima paket pemberitahuan, tumpukan driver USB menyelesaikan permintaan IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION yang tertunda (lihat langkah 3) dan memanggil rutinitas panggilan balik penyelesaian (bangun jarak jauh) yang ditentukan dalam permintaan dan diimplementasikan oleh driver komposit. Ketika pemberitahuan mencapai driver komposit, pemberitahuan memberi tahu driver klien yang sesuai bahwa fungsi telah memasuki status kerja dengan menyelesaikan IRP tunggu-bangun yang telah dikirim driver klien sebelumnya.

Dalam rutinitas penyelesaian (bangun jarak jauh), driver komposit harus mengantre item kerja untuk menyelesaikan IRP tunggu-bangun yang tertunda. Untuk perangkat USB 3.0, driver komposit membangunkan hanya fungsi yang mengirimkan sinyal melanjutkan dan membiarkan fungsi lainnya dalam keadaan ditangguhkan. Mengantre item kerja memastikan kompatibilitas dengan implementasi yang ada untuk driver fungsi perangkat USB 2.0. Untuk informasi tentang mengantre item kerja, lihat IoQueueWorkItem.

Thread pekerja menyelesaikan IRP tunggu-bangkit dan memanggil rutin penyelesaian dari driver klien. Rutinitas penyelesaian kemudian mengirim D0 IRP untuk memasukkan fungsi dalam status kerja. Sebelum menyelesaikan IRP wait-wake, driver komposit harus memanggil PoSetSystemWake untuk menandai IRP wait-wake sebagai yang berkontribusi membangunkan sistem dari keadaan suspend. Manajer daya mencatat peristiwa Event Tracing for Windows (ETW) (yang dapat dilihat di saluran sistem global) yang berisi informasi tentang perangkat yang membangunkan sistem.