Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Metode yang diilustrasikan dalam bagian Mendapatkan Informasi Konfigurasi Perangkat di IRQL = PASSIVE_LEVEL menggunakan paket permintaan I/O (IRP) dan oleh karena itu hanya berlaku untuk driver yang berjalan di IRQL = PASSIVE_LEVEL. Driver yang berjalan di IRQL = DISPATCH_LEVEL harus menggunakan antarmuka bus untuk mendapatkan data ruang konfigurasi perangkat. Untuk mendapatkan data ini, Anda dapat menggunakan antarmuka khusus bus atau antarmuka bus independen yang disediakan sistem, BUS_INTERFACE_STANDARD.
Antarmuka GUID_BUS_INTERFACE_STANDARD (didefinisikan dalam wdmguid.h) memungkinkan driver perangkat melakukan panggilan langsung ke rutinitas driver bus induk alih-alih menggunakan paket permintaan I/O (IRP) untuk berkomunikasi dengan pengemudi bus. Secara khusus, antarmuka ini memungkinkan driver mengakses rutinitas yang disediakan driver bus untuk fungsi-fungsi berikut:
- Menerjemahkan alamat bus
- Mengambil struktur adapter DMA pada kasus di mana adaptor bus mendukung DMA
- Membaca dan mengatur ruang konfigurasi bus untuk perangkat tertentu di bus
Untuk menggunakan antarmuka ini, kirimkan IRP_MN_QUERY_INTERFACE IRP ke driver bus Anda dengan InterfaceType = GUID_BUS_INTERFACE_STANDARD. Sopir bus memasok pointer ke struktur BUS_INTERFACE_STANDARD yang berisi pointer ke rutinitas masing-masing antarmuka.
Lebih baik menggunakan BUS_INTERFACE_STANDARD jika memungkinkan, karena nomor bus tidak diperlukan untuk mengambil informasi konfigurasi saat menggunakan BUS_INTERFACE_STANDARD, sedangkan pengemudi harus sering mengidentifikasi nomor bus saat mengambil antarmuka khusus bus. Nomor bus untuk beberapa bus, seperti PCI, dapat berubah secara dinamis. Oleh karena itu, pengemudi tidak boleh bergantung pada nomor bus untuk mengakses port PCI secara langsung. Melakukannya dapat menyebabkan kegagalan sistem.
Tiga langkah diperlukan saat mengakses ruang konfigurasi perangkat PCI di IRQL = DISPATCH_LEVEL:
Kirim permintaan IRP_MN_QUERY_INTERFACE di IRQL = PASSIVE_LEVEL untuk mendapatkan struktur antarmuka panggilan langsung (BUS_INTERFACE_STANDARD) dari driver bus PCI. Simpan ini dalam memori kumpulan yang tidak dipagasi (biasanya dalam ekstensi perangkat).
Panggil rutinitas antarmuka BUS_INTERFACE_STANDARD, SetBusData dan GetBusData, untuk mengakses ruang konfigurasi PCI di IRQL = DISPATCH_LEVEL.
Menghapus referensi antarmuka. Driver bus PCI mengambil hitungan referensi pada antarmuka sebelum kembali, sehingga driver yang mengakses antarmuka harus mendereferensikannya, setelah tidak lagi diperlukan.
Sampel kode berikut menunjukkan cara menerapkan tiga langkah ini:
NTSTATUS
GetPCIBusInterfaceStandard(
IN PDEVICE_OBJECT DeviceObject,
OUT PBUS_INTERFACE_STANDARD BusInterfaceStandard
)
/*++
Routine Description:
This routine gets the bus interface standard information from the PDO.
Arguments:
DeviceObject - Device object to query for this information.
BusInterface - Supplies a pointer to the retrieved information.
Return Value:
NT status.
--*/
{
KEVENT event;
NTSTATUS status;
PIRP irp;
IO_STATUS_BLOCK ioStatusBlock;
PIO_STACK_LOCATION irpStack;
PDEVICE_OBJECT targetObject;
Bus_KdPrint(("GetPciBusInterfaceStandard entered.\n"));
KeInitializeEvent(&event, NotificationEvent, FALSE);
targetObject = IoGetAttachedDeviceReference(DeviceObject);
irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
targetObject,
NULL,
0,
NULL,
&event,
&ioStatusBlock);
if (irp == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto End;
}
irpStack = IoGetNextIrpStackLocation( irp );
irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;
irpStack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
irpStack->Parameters.QueryInterface.Version = 1;
irpStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterfaceStandard;
irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
// Initialize the status to error in case the bus driver does not
// set it correctly.
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
status = IoCallDriver(targetObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatusBlock.Status;
}
End:
// Done with reference
ObDereferenceObject(targetObject);
return status;
}
Cuplikan kode berikut menunjukkan cara menggunakan rutinitas antarmukaGetBusDatauntuk mendapatkan data ruang konfigurasi (langkah 2).
bytes = busInterfaceStandard.GetBusData(
busInterfaceStandard.Context,
PCI_WHICHSPACE_CONFIG,
Buffer
Offset,
Length);
Ketika driver selesai dengan antarmuka, driver dapat menggunakan kode yang mirip dengan cuplikan berikut untuk mendereferensikan antarmuka (langkah 3). Driver tidak boleh memanggil rutinitas antarmuka setelah mendereferensikan antarmuka.
(busInterfaceStandard.InterfaceDereference)(
(PVOID)busInterfaceStandard.Context);
Antarmuka menyinkronkan akses penelepon ke perangkat keras bus dengan akses driver bus PCI. Penulis driver tidak perlu khawatir akan membuat spinlock untuk menghindari persaingan dengan driver bus PCI dalam mengakses perangkat keras bus.
Perhatikan bahwa jika semua yang diperlukan adalah nomor bus, fungsi, dan perangkat, biasanya tidak perlu menggunakan antarmuka bus untuk mendapatkan informasi ini. Data ini dapat diambil secara tidak langsung dengan meneruskan PDO perangkat target ke fungsiIoGetDeviceProperty sebagai berikut:
ULONG propertyAddress, length;
USHORT FunctionNumber, DeviceNumber;
// Get the BusNumber. Be warned that bus numbers may be
// dynamic and therefore subject to change unpredictably!!!
IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyBusNumber,
sizeof(ULONG),
(PVOID)&BusNumber,
&length);
// Get the DevicePropertyAddress
IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyAddress,
sizeof(ULONG),
(PVOID)&propertyAddress,
&length);
// For PCI, the DevicePropertyAddress has device number
// in the high word and the function number in the low word.
FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF);
DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);