Bagikan melalui


Cara mendaftarkan perangkat komposit

Artikel ini menjelaskan bagaimana driver perangkat multi-fungsi USB, yang disebut driver komposit, dapat mendaftar dan membatalkan pendaftaran perangkat komposit dengan tumpukan driver USB yang mendasar. Windows memuat driver yang disediakan Microsoft, Usbccgp.sys Sebagai driver komposit default. Prosedur dalam artikel ini berlaku untuk driver komposit berbasis Windows Driver Model (WDM) kustom yang menggantikan Usbccgp.sys.

Perangkat Universal Serial Bus (USB) dapat menyediakan beberapa fungsi yang aktif secara bersamaan. Perangkat multifungsi tersebut juga dikenal sebagai perangkat komposit. Misalnya, perangkat komposit mungkin menentukan fungsi untuk fungsionalitas keyboard dan fungsi lain untuk mouse. Driver komposit menghitung fungsi perangkat. Driver komposit dapat mengelola fungsi-fungsi itu sendiri dalam model monolitik atau membuat objek perangkat fisik (PDO) untuk setiap fungsi. Driver fungsi USB, seperti driver keyboard dan driver mouse, mengelola PDO individu masing-masing.

Spesifikasi USB 3.0 mendefinisikan penangguhan fungsi dan fungsi bangun jarak jauh yang memungkinkan fungsi individual beralih ke dan dari status daya rendah tanpa memengaruhi status daya fungsi lain atau seluruh perangkat. Untuk informasi selengkapnya tentang fitur ini, lihat Cara Menerapkan Fungsi Suspend di Driver Komposit.

Untuk menggunakan fitur ini, driver komposit perlu mendaftarkan perangkat dengan tumpukan driver USB dasar. Karena fitur ini berlaku untuk perangkat USB 3.0, driver komposit harus memastikan bahwa tumpukan yang mendasar mendukung versi USBD_INTERFACE_VERSION_602. Melalui permintaan pendaftaran, pengemudi gabungan:

  • Menginformasikan lapisan driver USB yang mendasar bahwa driver bertanggung jawab untuk mengirim permintaan mengaktifkan fungsi untuk aktivasi jarak jauh. Rangkaian driver USB memproses permintaan pemicu dari jarak jauh, yang mengirim permintaan protokol yang diperlukan ke perangkat.
  • Mendapatkan daftar handle fungsi (satu per fungsi) yang ditetapkan oleh stack driver USB. Driver komposit kemudian dapat menggunakan handle fungsi dalam permintaan driver untuk membangunkan fungsi terkait dengan handle tersebut dari jarak jauh.

Biasanya pengandar komposit mengirimkan permintaan pendaftaran dalam routine AddDevice dari pengandar atau memulai perangkat untuk menangani IRP_MN_START_DEVICE. Jadi, driver komposit merilis sumber daya yang dialokasikan untuk pendaftaran dalam rutinitas unload driver seperti penghentian perangkat (IRP_MN_STOP_DEVICE) atau rutinitas penghapusan perangkat (IRP_MN_REMOVE_DEVICE).

Prasyarat

Sebelum mengirim permintaan pendaftaran, pastikan bahwa:

  • Anda memiliki sejumlah fungsi di perangkat. Angka tersebut dapat diperoleh dari deskriptor yang diambil oleh permintaan get-konfigurasi.
  • Anda mendapatkan handle USBD pada panggilan sebelumnya ke USBD_CreateHandle.
  • Tumpukan driver USB yang mendasar mendukung perangkat USB 3.0. Untuk melakukannya, panggil USBD_IsInterfaceVersionSupported dan gunakan USBD_INTERFACE_VERSION_602 sebagai versi yang akan diperiksa.

Untuk contoh kode, lihat Cara Menerapkan Fungsi Suspend di Driver Komposit.

Mendaftarkan perangkat komposit

Prosedur berikut menjelaskan bagaimana Anda harus membangun dan mengirim permintaan pendaftaran untuk mengaitkan driver komposit dengan tumpukan driver USB.

  1. Alokasikan struktur COMPOSITE_DEVICE_CAPABILITIES dan inisialisasi dengan memanggil makro COMPOSITE_DEVICE_CAPABILITIES_INIT.

  2. Atur member CapabilityFunctionSuspend dari COMPOSITE_DEVICE_CAPABILITIES ke 1.

  3. Alokasikan struktur REGISTER_COMPOSITE_DEVICE dan inisialisasi struktur dengan memanggil rutinitas USBD_BuildRegisterCompositeDevice. Dalam panggilan, tentukan handel USBD, struktur COMPOSITE_DEVICE_CAPABILITIES yang diinisialisasi, dan jumlah fungsi.

  4. Alokasikan paket permintaan I/O (IRP) dengan memanggil IoAllocateIrp dan dapatkan pointer ke lokasi tumpukan pertama IRP (IO_STACK_LOCATION) dengan memanggil IoGetNextIrpStackLocation.

  5. Alokasikan memori untuk buffer yang cukup besar untuk menahan array handel fungsi (USBD_FUNCTION_HANDLE). Jumlah elemen dalam array harus berupa jumlah PDO.

  6. Buat permintaan dengan mengatur anggota IO_STACK_LOCATION berikut:

    • Tentukan jenis permintaan dengan mengatur Parameters.DeviceIoControl.IoControlCode ke IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DEVICE.
    • Tentukan parameter input dengan mengatur Parameters.Others.Argument1 ke alamat struktur REGISTER_COMPOSITE_DEVICE yang diinisialisasi.
    • Tentukan parameter output dengan mengatur AssociatedIrp.SystemBuffer ke buffer yang dialokasikan di langkah 5.
  7. Panggil IoCallDriver untuk mengirim permintaan dengan meneruskan IRP ke lokasi tumpukan berikutnya.

Setelah selesai, periksa array handel fungsi yang dikembalikan oleh tumpukan driver USB. Anda dapat menyimpan array dalam konteks perangkat driver untuk digunakan di masa mendatang.

Contoh kode berikut menunjukkan cara membuat dan mengirim permintaan pendaftaran. Contoh ini mengasumsikan bahwa driver komposit menyimpan jumlah fungsi yang diperoleh sebelumnya dan handle USBD dalam konteks perangkat driver.

VOID  RegisterCompositeDriver(PPARENT_FDO_EXT parentFdoExt)
{
    PIRP                            irp;
    REGISTER_COMPOSITE_DRIVER       registerInfo;
    COMPOSITE_DRIVER_CAPABILITIES   capabilities;
    NTSTATUS                        status;
    PVOID                           buffer;
    ULONG                           bufSize;
    PIO_STACK_LOCATION              nextSp;

    buffer = NULL;

    COMPOSITE_DRIVER_CAPABILITIES_INIT(&capabilities);
    capabilities.CapabilityFunctionSuspend = 1;

    USBD_BuildRegisterCompositeDriver(parentFdoExt->usbdHandle,
        capabilities,
        parentFdoExt->numFunctions,
        &registerInfo);

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

    if (irp == NULL)
    {
        //IoAllocateIrp failed.
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto ExitRegisterCompositeDriver;
    }

    nextSp = IoGetNextIrpStackLocation(irp);

    bufSize = parentFdoExt->numFunctions * sizeof(USBD_FUNCTION_HANDLE);

    buffer = ExAllocatePoolWithTag (NonPagedPool, bufSize, POOL_TAG);

    if (buffer == NULL)
    {
        // Memory alloc for function-handles failed.
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto ExitRegisterCompositeDriver;
    }

    nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
    nextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DRIVER;

    //Set the input buffer in Argument1
    nextSp->Parameters.Others.Argument1 = &registerInfo;

    //Set the output buffer in SystemBuffer field for USBD_FUNCTION_HANDLE.
    irp->AssociatedIrp.SystemBuffer = buffer;

    // Pass the IRP down to the next device object in the stack. Not shown.
    status = CallNextDriverSync(parentFdoExt, irp, FALSE);

    if (!NT_SUCCESS(status))
    {
        //Failed to register the composite driver.
        goto ExitRegisterCompositeDriver;
    }

    parentFdoExt->compositeDriverRegistered = TRUE;

    parentFdoExt->functionHandleArray = (PUSBD_FUNCTION_HANDLE) buffer;

End:
    if (!NT_SUCCESS(status))
    {
        if (buffer != NULL)
        {
            ExFreePoolWithTag (buffer, POOL_TAG);
            buffer = NULL;
        }
    }

    if (irp != NULL)
    {
        IoFreeIrp(irp);
        irp = NULL;
    }

    return;
}

Membatalkan pendaftaran perangkat komposit

  1. Alokasikan IRP dengan memanggil IoAllocateIrp dan dapatkan pointer ke lokasi tumpukan pertama IRP (IO_STACK_LOCATION) dengan memanggil IoGetNextIrpStackLocation.
  2. Buat permintaan dengan mengatur Parameters.DeviceIoControl.IoControlCode anggota IO_STACK_LOCATION ke IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE.
  3. Panggil IoCallDriver untuk mengirim permintaan dengan meneruskan IRP ke lokasi tumpukan berikutnya.

Permintaan IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE dikirim sekali oleh driver komposit dalam konteks rutinitas hapus perangkat. Tujuan permintaan adalah untuk menghapus hubungan antara tumpukan driver USB dan driver komposit dan fungsi enumerasinya. Permintaan ini juga membersihkan semua sumber daya yang dibuat untuk mempertahankan asosiasi tersebut dan semua pegangan fungsi yang dikembalikan dalam permintaan pendaftaran sebelumnya.

Contoh kode berikut menunjukkan cara membuat dan mengirim permintaan untuk membatalkan pendaftaran perangkat komposit. Contoh mengasumsikan bahwa driver komposit sebelumnya didaftarkan melalui permintaan pendaftaran seperti yang dijelaskan sebelumnya dalam artikel ini.

VOID  UnregisterCompositeDriver(
    PPARENT_FDO_EXT parentFdoExt )
{
    PIRP                irp;
    PIO_STACK_LOCATION  nextSp;
    NTSTATUS            status;

    PAGED_CODE();

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

    if (irp == NULL)
    {
        //IoAllocateIrp failed.
        status = STATUS_INSUFFICIENT_RESOURCES;
        return;
    }

    nextSp = IoGetNextIrpStackLocation(irp);

    nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
    nextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DRIVER;

    // Pass the IRP down to the next device object in the stack. Not shown.
    status = CallNextDriverSync(parentFdoExt, irp, FALSE);

    if (NT_SUCCESS(status))
    {
        parentFdoExt->compositeDriverRegistered = FALSE;
    }

    IoFreeIrp(irp);

    return;
}