Bagikan melalui


Sumber Daya Perangkat Keras untuk User-Mode Driver Periferal SPB

Contoh kode dalam topik ini menunjukkan bagaimana driver User-Mode Driver Framework (UMDF) untuk perangkat periferal pada bus periferal sederhana (SPB) mendapatkan sumber daya perangkat keras yang diperlukan untuk mengoperasikan perangkat. Termasuk dalam sumber daya ini adalah informasi yang digunakan driver untuk membuat koneksi logis ke perangkat. Sumber daya tambahan mungkin mencakup interupsi, dan satu atau beberapa pin input atau output GPIO. (Pin GPIO adalah pin pada perangkat pengontrol I/O tujuan umum yang dikonfigurasi sebagai input atau output; untuk informasi selengkapnya, lihat Driver Pengontrol GPIO.) Tidak seperti perangkat yang dipetakan memori, perangkat periferal yang terhubung dengan SPB tidak memerlukan blok alamat memori sistem untuk memetakan register-nya.

Driver ini mengimplementasikan antarmuka IPnpCallbackHardware2 , dan mendaftarkan antarmuka ini dengan UMDF selama panggilan ke metode IDriverEntry::OnDeviceAdd driver. Kerangka kerja memanggil metode di antarmuka IPnpCallbackHardware2 untuk memberi tahu driver perubahan dalam status daya perangkat.

Ketika daya dipulihkan ke perangkat periferal yang terhubung dengan SPB, kerangka kerja driver memanggil metode IPnpCallbackHardware2::OnPrepareHardware untuk memberi tahu driver bahwa perangkat ini harus disiapkan untuk digunakan. Selama panggilan ini, driver menerima dua daftar sumber daya perangkat keras sebagai parameter input. Parameter pWdfResourcesRaw menunjuk ke daftar sumber daya mentah, dan parameter pWdfResourcesTranslated menunjuk ke daftar sumber daya yang diterjemahkan. Kedua parameter adalah pointer ke objek IWDFCmResourceList . Sumber daya yang diterjemahkan mencakup ID koneksi yang dibutuhkan driver periferal SPB untuk membuat koneksi logis ke perangkat periferal yang terhubung dengan SPB. Untuk informasi selengkapnya, lihat ID Koneksi untuk Perangkat Periferal SPB.

Untuk mengaktifkan driver periferal UMDF untuk menerima ID koneksi dalam daftar sumber dayanya, file INF yang menginstal driver harus menyertakan direktif berikut di bagian DDInstall khusus WDF :

UmdfDirectHardwareAccess = AllowDirectHardwareAccess Untuk informasi selengkapnya tentang arahan ini, lihat Menentukan Arahan WDF dalam File INF.

Contoh kode berikut menunjukkan bagaimana metode OnPrepareHardware driver mendapatkan ID koneksi dari parameter pWdfResourcesTranslated .

BOOLEAN fConnectIdFound = FALSE;
BOOLEAN fDuplicateFound = FALSE;
LARGE_INTEGER connectionId = 0;
ULONG resourceCount;

resourceCount = pWdfResourcesTranslated->GetCount();

// Loop through the resources and save the relevant ones.
for (ULONG ix = 0; ix < resourceCount; ix++)
{
    PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;

    pDescriptor = pWdfResourcesTranslated->GetDescriptor(ix);

    if (pDescriptor == NULL)
    {
        hr = E_POINTER;
        break;
    }

    // Determine the resource type.
    switch (pDescriptor->Type)
    {
    case CmResourceTypeConnection:
        {
            // Check against the expected connection types.
            UCHAR Class = pDescriptor->u.Connection.Class;
            UCHAR Type = pDescriptor->u.Connection.Type;

            if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL)
            {
                if (Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C)
                {
                    if (fConnIdFound == FALSE)
                    {
                        // Save the SPB connection ID.
                        connectionId.LowPart = pDescriptor->u.Connection.IdLowPart;
                        connectionId.HighPart = pDescriptor->u.Connection.IdHighPart;
                        fConnectIdFound = TRUE;
                    }
                    else
                    {
                        fDuplicateFound = TRUE;
                    }
                }
            }

            if (Class == CM_RESOURCE_CONNECTION_CLASS_GPIO)
            {
                // Check for GPIO pin resource.
                ...
            }
        }
        break;

    case CmResourceTypeInterrupt:
        {
            // Check for interrupt resources.
            ...
        }
        break;

    default:
        // Ignore all other resource descriptors.
        break;
    }
}

Contoh kode sebelumnya menyalin ID koneksi untuk perangkat periferal yang terhubung dengan SPB ke dalam variabel bernama connectionId. Contoh kode berikut menunjukkan cara memasukkan ID koneksi ke dalam nama jalur perangkat yang dapat digunakan untuk mengidentifikasi perangkat periferal.

WCHAR szTargetPath[100];
HRESULT hres;

// Create the device path using the well-known resource hub
// path name and the connection ID.
//
// TODO: Replace this hardcoded string with the appropriate
//       helper method from Reshub.h when available.
hres = StringCbPrintfW(&szTargetPath[0],
                       sizeof(szTargetPath),
                       L"\\\\.\\RESOURCE_HUB\\%0*I64x",
                       (size_t)(sizeof(LARGE_INTEGER) * 2),
                       connectionId.QuadPart);
if (FAILED(hres))
{
     // Error handling
     ...
}

Contoh kode sebelumnya menulis nama jalur untuk perangkat periferal yang terhubung dengan SPB ke szTargetPath dalam array. Contoh kode berikut menggunakan nama jalur perangkat ini untuk membuka handel file ke perangkat periferal yang terhubung dengan SPB.

UMDF_IO_TARGET_OPEN_PARAMS openParams;

openParams.dwShareMode = 0;
openParams.dwCreationDisposition = OPEN_EXISTING;
openParams.dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED;
hres = pRemoteTarget->OpenFileByName(&szTargetPath[0],
                                     (GENERIC_READ | GENERIC_WRITE),
                                     &openParams);
if (FAILED(hres))
{
    // Error handling
    ...
}

Dalam contoh kode sebelumnya, pRemoteTarget variabel adalah penunjuk ke objek IWDFRemoteTarget . Jika panggilan ke metode IWDFRemoteTarget::OpenFileByName berhasil, driver untuk perangkat periferal yang terhubung dengan SPB dapat menggunakan objek IWDFRemoteTarget untuk mengirim permintaan I/O ke perangkat periferal. Sebelum driver mengirim permintaan baca, tulis, atau IOCTL ke perangkat periferal, driver memanggil metode IWDFRemoteTarget::FormatRequestForRead, IWDFRemoteTarget::FormatRequestForWrite, atau IWDFRemoteTarget::FormatRequestForIoctl untuk memformat permintaan I/O. Antarmuka IWDFRemoteTarget mewarisi ketiga metode ini dari antarmuka IWDFIoTarget . Selanjutnya, driver memanggil metode IWDFIoRequest::Send untuk mengirim permintaan I/O ke perangkat periferal yang terhubung dengan SPB.

Dalam contoh kode berikut, driver periferal SPB memanggil metode Kirim untuk mengirim permintaan IRP_MJ_WRITE ke perangkat periferal yang terhubung dengan SPB.

HRESULT hres;
IWDFMemory *pInputMemory = NULL;
IWDFRemoteTarget *pWdfIoRequest = NULL;

// Create a new I/O request.
if (SUCCEEDED(hres))
{
    hres = pWdfDevice->CreateRequest(NULL, 
                                     pWdfDevice, 
                                     &pWdfIoRequest);
    if (FAILED(hres))
    {
        // Error handling
        ...
    }
}

// Allocate memory for the input buffer.
if (SUCCEEDED(hres))
{
    hres = pWdfDriver->CreatePreallocatedWdfMemory(pInBuffer, 
                                                   inBufferSize, 
                                                   NULL,
                                                   pWdfIoRequest,
                                                   &pInputMemory);
    if (FAILED(hres))
    {
        // Error handling
        ...
    }

    // After this call, the parent holds the only reference.
    pWdfMemory->Release();
}

// Format the I/O request for a write operation.
if (SUCCEEDED(hres))
{
    hres = pRemoteTarget->FormatRequestForWrite(pWdfIoRequest,
                                                NULL,
                                                pInputMemory, 
                                                NULL, 
                                                0);
    if (FAILED(hres))
    {
        // Error handling
        ...
    }
}

// Send the request to the SPB controller.
if (SUCCEEDED(hres))
{
    ULONG Flags = fSynchronous ? WDF_REQUEST_SEND_OPTION_SYNCHRONOUS : 0;

    // Set the I/O completion callback.
    if (!fSynchronous)
    {
        pWdfIoRequest->SetCompletionCallback(pCallback, NULL);
    }

    hres = pWdfIoRequest->Send(pRemoteTarget, Flags, 0);
    if (FAILED(hres))
    {
        // Error handling
        ...
    }
}

if (fSynchronous || FAILED(hres))
{
    pWdfIoRequest->DeleteWdfObject();
    SAFE_RELEASE(pWdfIoRequest);
}

Contoh kode sebelumnya melakukan hal berikut:

  1. Variabel pWdfDevice adalah penunjuk ke antarmuka IWDFDevice dari objek perangkat kerangka kerja yang mewakili perangkat periferal yang terhubung dengan SPB. Metode IWDFDevice::CreateRequest membuat permintaan I/O dan merangkum permintaan ini dalam instans antarmuka IWDFIoRequest yang diarahkan oleh pWdfIoRequest variabel.
  2. Variabel pWdfDriver adalah penunjuk ke antarmuka IWDFDriver dari objek driver kerangka kerja yang mewakili driver periferal SPB. Variabel pInBuffer dan inBufferSize menentukan alamat dan ukuran buffer input yang berisi data untuk permintaan tulis. Metode IWDFDriver::CreatePreallocatedWdfMemory membuat objek memori kerangka kerja untuk buffer input, dan menunjuk objek IWDFIoRequest yang diarahkan oleh pWdfIoRequest sebagai objek induk objek memori (sehingga objek memori secara otomatis dirilis saat induknya dirilis). Setelah driver memanggil metode Rilis untuk merilis referensi lokalnya ke objek memori, induk memegang satu-satu referensi ke objek ini.
  3. Variabel pWdfRemoteTarget adalah penunjuk target jarak jauh yang diperoleh dari panggilan OpenFileByName dalam contoh kode sebelumnya. Metode IWDFRemoteTarget::FormatRequestForWrite memformat permintaan I/O untuk operasi tulis.
  4. Variabel fSynchronous adalah TRUE jika permintaan tulis akan dikirim secara sinkron, dan FALSE jika akan dikirim secara asinkron. Variabel pCallback adalah penunjuk ke antarmuka IRequestCallbackRequestCompletion yang dibuat sebelumnya. Jika permintaan akan dikirim secara asinkron, panggilan ke metode IWDFIoRequest::SetCompletionCallback mendaftarkan antarmuka ini. Kemudian, metode IRequestCallbackRequestCompletion::OnCompletion dipanggil untuk memberi tahu driver ketika permintaan selesai secara asinkron.
  5. Metode Kirim mengirimkan permintaan tulis yang diformat ke perangkat periferal yang terhubung dengan SPB. Variabel Flags menunjukkan apakah permintaan tulis akan dikirim secara sinkron atau asinkron.
  6. Jika permintaan dikirim secara sinkron, metode IWDFIoRequest::D eleteWdfObject menghapus objek permintaan I/O yang diarahkan oleh pWdfIoRequest dan objek anak yang ditunjukkan oleh pInputMemory. Antarmuka IWDFIoRequest mewarisi metode ini dari antarmuka IWDFObject . Jika permintaan dikirim secara asinkron, panggilan ke metode DeleteWdfObject akan terjadi nanti, dalam metode OnCompletion driver.

Implementasi alternatif dari contoh kode sebelumnya dapat membuat objek IWDFIoRequest dan IWDFMemory selama inisialisasi driver, dan berulang kali menggunakan objek yang sama ini alih-alih membuat dan menghapus objek baru setiap kali permintaan I/O dikirim. Untuk informasi selengkapnya, lihat IWDFIoRequest2::Reuse dan IWDFMemory::SetBuffer.

Selain itu, implementasi alternatif mungkin memeriksa kode status I/O dari permintaan I/O jika panggilan Kirim berhasil. Untuk informasi selengkapnya, lihat IWDFIoRequest::GetCompletionParams.