Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Metoda znázorněná v části Získání informací o konfiguraci zařízení v IRQL = PASSIVE_LEVEL využívá pakety žádostí o vstupně-výstupní operace (IRP), a proto je platná pouze pro ovladače spuštěné v IRQL = PASSIVE_LEVEL. Ovladače pracující na úrovni IRQL = DISPATCH_LEVEL musí k získání dat z konfiguračního prostoru zařízení použít rozhraní sběrnice. K získání těchto dat můžete použít rozhraní specifické pro sběrnici nebo rozhraní sběrnice nezávislé na systému BUS_INTERFACE_STANDARD.
Rozhraní GUID_BUS_INTERFACE_STANDARD (definované v wdmguid.h) umožňuje ovladačům zařízení provádět přímá volání rutin ovladačů nadřazené sběrnice namísto použití paketů vstupně-výstupních požadavků (IRP) ke komunikaci s ovladačem sběrnice. Konkrétně toto rozhraní umožňuje ovladačům přístup k rutinám, které ovladač sběrnice poskytuje pro následující funkce:
- Překlad adres počítačové sběrnice
- Načtení struktury adaptéru DMA v případech, kdy adaptér sběrnice podporuje DMA
- Čtení a nastavení prostoru konfigurace sběrnice pro konkrétní zařízení na této sběrnici
Pokud chcete toto rozhraní použít, odešlete IRP_MN_QUERY_INTERFACE IRP ovladači sběrnice pomocí InterfaceType = GUID_BUS_INTERFACE_STANDARD. Ovladač autobusového systému poskytuje ukazatel na strukturu typu BUS_INTERFACE_STANDARD, která obsahuje ukazatele na jednotlivé rutiny rozhraní.
Pokud je to možné, je vhodnější použít BUS_INTERFACE_STANDARD , protože číslo sběrnice není při použití BUS_INTERFACE_STANDARD nutné načíst informace o konfiguraci, zatímco ovladače musí při načítání rozhraní specifických pro sběrnici často identifikovat číslo sběrnice. Čísla autobusů pro některé autobusy, například PCI, se můžou dynamicky měnit. Proto by ovladače neměly záviset na čísle sběrnice pro přímý přístup k portům PCI. To může vést k selhání systému.
Při přístupu ke konfiguračnímu prostoru zařízení PCI v IRQL = DISPATCH_LEVEL se vyžadují tři kroky:
Odešlete IRP_MN_QUERY_INTERFACE požadavek na IRQL = PASSIVE_LEVEL, abyste získali strukturu rozhraní pro přímé volání (BUS_INTERFACE_STANDARD) od ovladače sběrnice PCI. Uložte ji do paměti nestránkového fondu (obvykle v rozšíření zařízení).
Zavolejte rutiny rozhraní BUS_INTERFACE_STANDARD, SetBusData a GetBusData, pro přístup k prostoru konfigurace PCI na úrovni IRQL = DISPATCH_LEVEL.
Odreferencovat rozhraní. Ovladač sběrnice PCI zaznamenává počet referencí na rozhraní před jeho uvolněním, takže ovladač, který přistupuje k rozhraní, musí ho dereferencovat, jakmile již není potřeba.
Následující ukázka kódu ukazuje, jak implementovat tyto tři kroky:
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;
}
Následující fragment kódu ukazuje, jak pomocí rutiny rozhraní GetBusData získat data konfiguračního prostoru (krok 2).
bytes = busInterfaceStandard.GetBusData(
busInterfaceStandard.Context,
PCI_WHICHSPACE_CONFIG,
Buffer
Offset,
Length);
Když ovladač skončí s používáním rozhraní, může použít kód, který je podobný následujícímu fragmentu a dereferencuje rozhraní (krok 3). Ovladače nesmí volat rutiny rozhraní po dereferencování rozhraní.
(busInterfaceStandard.InterfaceDereference)(
(PVOID)busInterfaceStandard.Context);
Rozhraní synchronizuje přístup volajícího k hardwaru sběrnice s přístupem ovladače sběrnice PCI. Zapisovač ovladačů si nemusí dělat starosti s vytvářením spinlocků, aby se zabránilo soupeření s ovladačem sběrnice PCI o přístup k hardwaru sběrnice.
Upozorňujeme, že pokud jsou potřebná jen čísla sběrnice, funkce a zařízení, obvykle není nutné používat rozhraní sběrnice pro získání těchto informací. Tato data lze načíst nepřímo předáním primárního objektu cílového zařízení do funkce IoGetDeviceProperty následujícím způsobem:
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);