1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Serial enumerator driver 4 * FILE: drivers/bus/serenum/fdo.c 5 * PURPOSE: IRP_MJ_PNP operations for FDOs 6 * 7 * PROGRAMMERS: Herv� Poussineau (hpoussin@reactos.org) 8 */ 9 10 #include "serenum.h" 11 12 #include <debug.h> 13 14 NTSTATUS NTAPI 15 SerenumAddDevice( 16 IN PDRIVER_OBJECT DriverObject, 17 IN PDEVICE_OBJECT Pdo) 18 { 19 PDEVICE_OBJECT Fdo; 20 PFDO_DEVICE_EXTENSION DeviceExtension; 21 NTSTATUS Status; 22 23 TRACE_(SERENUM, "SerenumAddDevice called. Pdo = %p\n", Pdo); 24 25 /* Create new device object */ 26 Status = IoCreateDevice(DriverObject, 27 sizeof(FDO_DEVICE_EXTENSION), 28 NULL, 29 FILE_DEVICE_BUS_EXTENDER, 30 FILE_DEVICE_SECURE_OPEN, 31 FALSE, 32 &Fdo); 33 if (!NT_SUCCESS(Status)) 34 { 35 WARN_(SERENUM, "IoCreateDevice() failed with status 0x%08lx\n", Status); 36 return Status; 37 } 38 DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension; 39 RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION)); 40 41 /* Register device interface */ 42 Status = IoRegisterDeviceInterface( 43 Pdo, 44 &GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR, 45 NULL, 46 &DeviceExtension->SerenumInterfaceName); 47 if (!NT_SUCCESS(Status)) 48 { 49 WARN_(SERENUM, "IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status); 50 IoDeleteDevice(Fdo); 51 return Status; 52 } 53 54 DeviceExtension->Common.IsFDO = TRUE; 55 DeviceExtension->Common.PnpState = dsStopped; 56 DeviceExtension->Pdo = Pdo; 57 IoInitializeRemoveLock(&DeviceExtension->RemoveLock, SERENUM_TAG, 0, 0); 58 Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice); 59 if (!NT_SUCCESS(Status)) 60 { 61 WARN_(SERENUM, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status); 62 IoDeleteDevice(Fdo); 63 return Status; 64 } 65 if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE) 66 Fdo->Flags |= DO_POWER_PAGABLE; 67 if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO) 68 Fdo->Flags |= DO_BUFFERED_IO; 69 if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO) 70 Fdo->Flags |= DO_DIRECT_IO; 71 Fdo->Flags &= ~DO_DEVICE_INITIALIZING; 72 73 return STATUS_SUCCESS; 74 } 75 76 static NTSTATUS NTAPI 77 SerenumFdoStartDevice( 78 IN PDEVICE_OBJECT DeviceObject, 79 IN PIRP Irp) 80 { 81 PFDO_DEVICE_EXTENSION DeviceExtension; 82 NTSTATUS Status; 83 84 TRACE_(SERENUM, "SerenumFdoStartDevice() called\n"); 85 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 86 87 ASSERT(DeviceExtension->Common.PnpState == dsStopped); 88 89 Status = IoSetDeviceInterfaceState(&DeviceExtension->SerenumInterfaceName, TRUE); 90 if (!NT_SUCCESS(Status)) 91 { 92 WARN_(SERENUM, "IoSetDeviceInterfaceState() failed with status 0x%08lx\n", Status); 93 return Status; 94 } 95 96 DeviceExtension->Common.PnpState = dsStarted; 97 98 return STATUS_SUCCESS; 99 } 100 101 static NTSTATUS 102 SerenumFdoQueryBusRelations( 103 IN PDEVICE_OBJECT DeviceObject, 104 OUT PDEVICE_RELATIONS* pDeviceRelations) 105 { 106 PFDO_DEVICE_EXTENSION DeviceExtension; 107 PDEVICE_RELATIONS DeviceRelations; 108 ULONG NumPDO; 109 ULONG i; 110 NTSTATUS Status = STATUS_SUCCESS; 111 112 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 113 ASSERT(DeviceExtension->Common.IsFDO); 114 115 /* Do enumeration if needed */ 116 if (!(DeviceExtension->Flags & FLAG_ENUMERATION_DONE)) 117 { 118 ASSERT(DeviceExtension->AttachedPdo == NULL); 119 /* Detect plug-and-play devices */ 120 Status = SerenumDetectPnpDevice(DeviceObject, DeviceExtension->LowerDevice); 121 if (Status == STATUS_DEVICE_NOT_CONNECTED) 122 { 123 /* Detect legacy devices */ 124 Status = SerenumDetectLegacyDevice(DeviceObject, DeviceExtension->LowerDevice); 125 if (Status == STATUS_DEVICE_NOT_CONNECTED) 126 Status = STATUS_SUCCESS; 127 } 128 DeviceExtension->Flags |= FLAG_ENUMERATION_DONE; 129 } 130 NumPDO = (DeviceExtension->AttachedPdo != NULL ? 1 : 0); 131 132 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag( 133 PagedPool, 134 sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (NumPDO - 1), 135 SERENUM_TAG); 136 if (!DeviceRelations) 137 return STATUS_INSUFFICIENT_RESOURCES; 138 139 /* Fill returned structure */ 140 DeviceRelations->Count = NumPDO; 141 for (i = 0; i < NumPDO; i++) 142 { 143 ObReferenceObject(DeviceExtension->AttachedPdo); 144 DeviceRelations->Objects[i] = DeviceExtension->AttachedPdo; 145 } 146 147 *pDeviceRelations = DeviceRelations; 148 return Status; 149 } 150 151 NTSTATUS 152 SerenumFdoPnp( 153 IN PDEVICE_OBJECT DeviceObject, 154 IN PIRP Irp) 155 { 156 PFDO_DEVICE_EXTENSION FdoExtension; 157 ULONG MinorFunction; 158 PIO_STACK_LOCATION Stack; 159 ULONG_PTR Information = 0; 160 NTSTATUS Status; 161 162 Stack = IoGetCurrentIrpStackLocation(Irp); 163 MinorFunction = Stack->MinorFunction; 164 165 switch (MinorFunction) 166 { 167 /* FIXME: do all these minor functions 168 IRP_MN_QUERY_REMOVE_DEVICE 0x1 169 IRP_MN_REMOVE_DEVICE 0x2 170 IRP_MN_CANCEL_REMOVE_DEVICE 0x3 171 IRP_MN_STOP_DEVICE 0x4 172 IRP_MN_QUERY_STOP_DEVICE 0x5 173 IRP_MN_CANCEL_STOP_DEVICE 0x6 174 IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations (optional) 0x7 175 IRP_MN_QUERY_INTERFACE (optional) 0x8 176 IRP_MN_QUERY_CAPABILITIES (optional) 0x9 177 IRP_MN_QUERY_PNP_DEVICE_STATE (optional) 0x14 178 IRP_MN_DEVICE_USAGE_NOTIFICATION (required or optional) 0x16 179 IRP_MN_SURPRISE_REMOVAL 0x17 180 */ 181 case IRP_MN_START_DEVICE: /* 0x0 */ 182 { 183 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_START_DEVICE\n"); 184 /* Call lower driver */ 185 FdoExtension = DeviceObject->DeviceExtension; 186 Status = STATUS_UNSUCCESSFUL; 187 188 if (IoForwardIrpSynchronously(FdoExtension->LowerDevice, Irp)) 189 { 190 Status = Irp->IoStatus.Status; 191 if (NT_SUCCESS(Status)) 192 { 193 Status = SerenumFdoStartDevice(DeviceObject, Irp); 194 } 195 } 196 197 break; 198 } 199 case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x7 */ 200 { 201 switch (Stack->Parameters.QueryDeviceRelations.Type) 202 { 203 case BusRelations: 204 { 205 PDEVICE_RELATIONS DeviceRelations = NULL; 206 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n"); 207 Status = SerenumFdoQueryBusRelations(DeviceObject, &DeviceRelations); 208 Information = (ULONG_PTR)DeviceRelations; 209 break; 210 } 211 default: 212 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n", 213 Stack->Parameters.QueryDeviceRelations.Type); 214 return ForwardIrpAndForget(DeviceObject, Irp); 215 } 216 break; 217 } 218 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0xd */ 219 { 220 TRACE_(SERENUM, "IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n"); 221 return ForwardIrpAndForget(DeviceObject, Irp); 222 } 223 default: 224 { 225 TRACE_(SERENUM, "IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction); 226 return ForwardIrpAndForget(DeviceObject, Irp); 227 } 228 } 229 230 Irp->IoStatus.Information = Information; 231 Irp->IoStatus.Status = Status; 232 IoCompleteRequest(Irp, IO_NO_INCREMENT); 233 return Status; 234 } 235