/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Serial enumerator driver * FILE: drivers/bus/serenum/fdo.c * PURPOSE: IRP_MJ_PNP operations for FDOs * * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) */ #include "serenum.h" #include NTSTATUS NTAPI SerenumAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT Pdo) { PDEVICE_OBJECT Fdo; PFDO_DEVICE_EXTENSION DeviceExtension; NTSTATUS Status; TRACE_(SERENUM, "SerenumAddDevice called. Pdo = %p\n", Pdo); /* Create new device object */ Status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_SECURE_OPEN, FALSE, &Fdo); if (!NT_SUCCESS(Status)) { WARN_(SERENUM, "IoCreateDevice() failed with status 0x%08lx\n", Status); return Status; } DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension; RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION)); /* Register device interface */ Status = IoRegisterDeviceInterface( Pdo, &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, NULL, &DeviceExtension->SerenumInterfaceName); if (!NT_SUCCESS(Status)) { WARN_(SERENUM, "IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status); IoDeleteDevice(Fdo); return Status; } DeviceExtension->Common.IsFDO = TRUE; DeviceExtension->Common.PnpState = dsStopped; DeviceExtension->Pdo = Pdo; IoInitializeRemoveLock(&DeviceExtension->RemoveLock, SERENUM_TAG, 0, 0); Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice); if (!NT_SUCCESS(Status)) { WARN_(SERENUM, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status); IoDeleteDevice(Fdo); return Status; } if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE) Fdo->Flags |= DO_POWER_PAGABLE; if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO) Fdo->Flags |= DO_BUFFERED_IO; if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO) Fdo->Flags |= DO_DIRECT_IO; Fdo->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; } static NTSTATUS NTAPI SerenumFdoStartDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PFDO_DEVICE_EXTENSION DeviceExtension; NTSTATUS Status; TRACE_(SERENUM, "SerenumFdoStartDevice() called\n"); DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(DeviceExtension->Common.PnpState == dsStopped); Status = IoSetDeviceInterfaceState(&DeviceExtension->SerenumInterfaceName, TRUE); if (!NT_SUCCESS(Status)) { WARN_(SERENUM, "IoSetDeviceInterfaceState() failed with status 0x%08lx\n", Status); return Status; } DeviceExtension->Common.PnpState = dsStarted; return STATUS_SUCCESS; } static NTSTATUS SerenumFdoQueryBusRelations( IN PDEVICE_OBJECT DeviceObject, OUT PDEVICE_RELATIONS* pDeviceRelations) { PFDO_DEVICE_EXTENSION DeviceExtension; PDEVICE_RELATIONS DeviceRelations; ULONG NumPDO; ULONG i; NTSTATUS Status = STATUS_SUCCESS; DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(DeviceExtension->Common.IsFDO); /* Do enumeration if needed */ if (!(DeviceExtension->Flags & FLAG_ENUMERATION_DONE)) { ASSERT(DeviceExtension->AttachedPdo == NULL); /* Detect plug-and-play devices */ Status = SerenumDetectPnpDevice(DeviceObject, DeviceExtension->LowerDevice); if (Status == STATUS_DEVICE_NOT_CONNECTED) { /* Detect legacy devices */ Status = SerenumDetectLegacyDevice(DeviceObject, DeviceExtension->LowerDevice); if (Status == STATUS_DEVICE_NOT_CONNECTED) Status = STATUS_SUCCESS; } DeviceExtension->Flags |= FLAG_ENUMERATION_DONE; } NumPDO = (DeviceExtension->AttachedPdo != NULL ? 1 : 0); DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag( PagedPool, sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (NumPDO - 1), SERENUM_TAG); if (!DeviceRelations) return STATUS_INSUFFICIENT_RESOURCES; /* Fill returned structure */ DeviceRelations->Count = NumPDO; for (i = 0; i < NumPDO; i++) { ObReferenceObject(DeviceExtension->AttachedPdo); DeviceRelations->Objects[i] = DeviceExtension->AttachedPdo; } *pDeviceRelations = DeviceRelations; return Status; } NTSTATUS SerenumFdoPnp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { ULONG MinorFunction; PIO_STACK_LOCATION Stack; ULONG_PTR Information = 0; NTSTATUS Status; Stack = IoGetCurrentIrpStackLocation(Irp); MinorFunction = Stack->MinorFunction; switch (MinorFunction) { /* FIXME: do all these minor functions IRP_MN_QUERY_REMOVE_DEVICE 0x1 IRP_MN_REMOVE_DEVICE 0x2 IRP_MN_CANCEL_REMOVE_DEVICE 0x3 IRP_MN_STOP_DEVICE 0x4 IRP_MN_QUERY_STOP_DEVICE 0x5 IRP_MN_CANCEL_STOP_DEVICE 0x6 IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7 IRP_MN_QUERY_INTERFACE (optional) 0x8 IRP_MN_QUERY_CAPABILITIES (optional) 0x9 IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14 IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16 IRP_MN_SURPRISE_REMOVAL 0x17 */ case IRP_MN_START_DEVICE: /* 0x0 */ { TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); /* Call lower driver */ Status = ForwardIrpAndWait(DeviceObject, Irp); if (NT_SUCCESS(Status)) Status = SerenumFdoStartDevice(DeviceObject, Irp); break; } case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */ { switch (Stack->Parameters.QueryDeviceRelations.Type) { case BusRelations: { PDEVICE_RELATIONS DeviceRelations = NULL; TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n"); Status = SerenumFdoQueryBusRelations(DeviceObject, &DeviceRelations); Information = (ULONG_PTR)DeviceRelations; break; } default: TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n", Stack->Parameters.QueryDeviceRelations.Type); return ForwardIrpAndForget(DeviceObject, Irp); } break; } case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0xd */ { TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); return ForwardIrpAndForget(DeviceObject, Irp); } default: { TRACE_(SERENUM, "IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction); return ForwardIrpAndForget(DeviceObject, Irp); } } Irp->IoStatus.Information = Information; Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }