Cómo obtener la información de configuración y ubicación de un dispositivo PCI
En Windows 2000 y posteriores, los controladores no necesitan consultar el dispositivo para encontrar recursos. Los controladores obtienen estos recursos a través de solicitudes IRP_MN_START_DEVICE emitidas por el administrador Plug and Play (PnP). Normalmente, un controlador escrito correctamente se ejecutará sin dicha información. Si el controlador necesita obtener esta información por algún motivo, consulte el siguiente ejemplo de código para obtener el recurso. El controlador debe ser parte de la pila de controladores del dispositivo porque requiere que el objeto de dispositivo físico (PDO) subyacente del dispositivo envíe solicitudes PnP.
El siguiente ejemplo de código demuestra cómo obtener información de configuración: NTSTATUS ReadWriteConfigSpace(IN PDEVICE_OBJECT DeviceObject, IN ULONG ReadOrWrite, // 0 significa leer 1 significa escribir EN PVOID Buffer, IN ULONG Offset, IN ULONG Longitud) { evento KEVENT; estado NTSTATUS; PIRP irp; IO_STATUS_BLOCK ioStatusBlock; PIO_STACK_LOCATION irpStack; PDEVICE_OBJECT DeviceObject, IN ULONG ReadOrWrite, // 0 significa leer 1 significa escribir EN PVOID PDEVICE_OBJECT targetObject(); FALSO); objeto objetivo = IoGetAttachedDeviceReference( DeviceObject ); irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP, targetObject, NULL, 0, NULL, &event, & ioStatusBlock ); ); si ( ReadOrWrite == 0) { irpStack = IoGetNextIrpStackLocation(irp); if (ReadOrWrite == 0) { irpStack = IoGetNextIrpStackLocation(irp} = 0) { irpStack->MinorFunction = IRP_MN_READ_CONFIG } else { irpStack-> MinorFunction = IRP_MN_WRITE_CONFIG; ; } irpStack->Parameters.ReadWriteConfig.Offset = Offset; irpStack->Parameters.ReadWriteConfig.Length=Longitud /// Inicializa el estado en error en caso de que el controlador del bus // no esté configurado correctamente.
// irp->IoStatus.Status = STATUS_NOT_SUPPORTED ; estado = IoCallDriver(targetObject, irp ); if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL ); Fin: // // Referencia completa // ObDereferenceObject(targetObject); return status; } Dado que los paquetes de solicitud de E/S de PnP (IRP) solo se pueden enviar en el nivel PASSIVE_LEVEL, la función anterior no se puede utilizar para obtener la información de configuración en el nivel DISPATCH_LEVEL.
Para acceder al espacio de configuración en el nivel DISPATCH_LEVEL, realice los siguientes pasos: 1. Envíe IRP_MN_QUERY_INTERFACE en el nivel PASSIVE_LEVEL para obtener una llamada directa a la estructura de la interfaz (BUS_INTERFACE_STANDARD) desde el controlador del bus PCI. ).2. Llame a SetBusData y GetBusData en la capa DISPATCH_LEVEL para acceder al espacio de configuración. 3. Debido a que el controlador del bus PCI obtiene el recuento de referencias de la interfaz antes de regresar, debe afirmarse cuando la interfaz ya no sea necesaria. 4. Obtenga el valor BUS_INTERFACE_STANDARD para la capa PASSIVE_LEVEL usando la siguiente función: NTSTATUS GetPCIBusInterfaceStandard(IN PDEVICE_OBJECT DeviceObject, OUT PBUS_INTERFACE_STANDARD). OUT PBUS_INTERFACE_STANDARD BusInterfaceStandard )/*++ Descripción de la rutina: Esta rutina obtiene información estándar de la interfaz de bus de PDO. Parámetros DeviceObject: el objeto del dispositivo para el cual se consultará esta información. BusInterface: proporciona un puntero a la información obtenida. Valor de retorno: estado NT.
--*/ { evento KEVENT; estado NTSTATUS; PIRP irp; IO_STATUS_BLOCK ioStatusBlock; PIO_STACK_LOCATION PDEVICE_OBJECT targetObject.Bus_KdPrint(("GetPciBusInterfaceStandard ingresado./n")); ttachedDeviceReference (DeviceObject ; } irpStack = IoGetNextIrpStackLocation(irp); irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE; irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_BUS_INTERFACE_STANDARD; .QueryInterface.InterfaceSpecificData = NULL; // // Inicializa el estado a error en caso de que el controlador del bus // no esté configurado correctamente. // irp-> IoStatus.Status = STATUS_NOT_SUPPORTED; estado = IoCallDriver(targetObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject( &. event, Executive, KernelMode, FALSE, NULL ); End.End: // // Referencia completa // ObDereferenceObject (targetObject); estado de retorno; }bytes = busInterfaceStandard.GetBusData(
busInterfaceStandard.Context, PCI_WHICHSPACE_CONFIG, Buffer Offset, Longitud); , utilice el siguiente código para eliminar la referencia. Después de eliminar la referencia a una interfaz, no llame a ninguna rutina de interfaz.
(busInterfaceStandard.InterfaceDereference) ((PVOID) busInterfaceStandard.Context); utilice la función IoGetDeviceProperty en el PDO del dispositivo de destino para obtener el número de bus, el número de función y el número de dispositivo de la siguiente manera: dirección de propiedad ULONG, compensación de búfer, dirección de propiedad ULONG, longitud; USHORT FunctionNumber; DeviceNumber; // // Obtener el número de bus. Lea las advertencias que siguen. // La función IoGetDeviceProperty se utiliza para el dispositivo de destino PDO.IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyBusNumber, sizeof(ULONG), (PVOID)&BusNumber, &length // Obtener DevicePropertyAddress // // Obtener DevicePropertyAddress.IoGetDeviceProperty(PhysicalDeviceObject); , DevicePropertyAddress, sizeof(ULONG), (PVOID)&propertyAddress, &length); // // Obtenga DevicePropertyAddress.// FunctionNumber = (USHORT) ((propertyAddress) & 0x0000FFFF DeviceNumber = (USHORT) ((propertyAddress) 》16); ) & 0x0000FFFF ); IMPORTANTE: Los números de bus PCI pueden ser dinámicos y pueden cambiar en cualquier momento. Por lo tanto, no se recomienda acceder directamente a los puertos PCI según el número de bus ni utilizar esta información. Esto puede provocar un fallo del sistema.