1 /* 2 * PROJECT: ReactOS ISA PnP Bus driver 3 * FILE: pdo.c 4 * PURPOSE: PDO-specific code 5 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) 6 * Hervé Poussineau 7 */ 8 9 #include <isapnp.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 NTSTATUS 15 NTAPI 16 IsaPdoQueryDeviceRelations( 17 IN PISAPNP_PDO_EXTENSION PdoExt, 18 IN PIRP Irp, 19 IN PIO_STACK_LOCATION IrpSp) 20 { 21 PDEVICE_RELATIONS DeviceRelations; 22 23 if (IrpSp->Parameters.QueryDeviceRelations.Type == RemovalRelations && 24 PdoExt->Common.Self == PdoExt->FdoExt->DataPortPdo) 25 { 26 return IsaPnpFillDeviceRelations(PdoExt->FdoExt, Irp, FALSE); 27 } 28 29 if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) 30 return Irp->IoStatus.Status; 31 32 DeviceRelations = ExAllocatePool(PagedPool, sizeof(*DeviceRelations)); 33 if (!DeviceRelations) 34 return STATUS_NO_MEMORY; 35 36 DeviceRelations->Count = 1; 37 DeviceRelations->Objects[0] = PdoExt->Common.Self; 38 ObReferenceObject(PdoExt->Common.Self); 39 40 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; 41 42 return STATUS_SUCCESS; 43 } 44 45 NTSTATUS 46 NTAPI 47 IsaPdoQueryCapabilities( 48 IN PISAPNP_PDO_EXTENSION PdoExt, 49 IN PIRP Irp, 50 IN PIO_STACK_LOCATION IrpSp) 51 { 52 PDEVICE_CAPABILITIES DeviceCapabilities; 53 PISAPNP_LOGICAL_DEVICE LogDev = PdoExt->IsaPnpDevice; 54 ULONG i; 55 56 DeviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities; 57 if (DeviceCapabilities->Version != 1) 58 return STATUS_REVISION_MISMATCH; 59 60 if (LogDev) 61 { 62 DeviceCapabilities->UniqueID = TRUE; 63 DeviceCapabilities->Address = LogDev->CSN; 64 } 65 else 66 { 67 DeviceCapabilities->UniqueID = TRUE; 68 DeviceCapabilities->RawDeviceOK = TRUE; 69 DeviceCapabilities->SilentInstall = TRUE; 70 } 71 72 for (i = 0; i < POWER_SYSTEM_MAXIMUM; i++) 73 DeviceCapabilities->DeviceState[i] = PowerDeviceD3; 74 DeviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0; 75 76 return STATUS_SUCCESS; 77 } 78 79 NTSTATUS 80 NTAPI 81 IsaPdoQueryPnpDeviceState( 82 IN PISAPNP_PDO_EXTENSION PdoExt, 83 IN PIRP Irp, 84 IN PIO_STACK_LOCATION IrpSp) 85 { 86 Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE; 87 return STATUS_SUCCESS; 88 } 89 90 NTSTATUS 91 NTAPI 92 IsaPdoQueryId( 93 IN PISAPNP_PDO_EXTENSION PdoExt, 94 IN PIRP Irp, 95 IN PIO_STACK_LOCATION IrpSp) 96 { 97 PUNICODE_STRING Source; 98 PWCHAR Buffer; 99 100 switch (IrpSp->Parameters.QueryId.IdType) 101 { 102 case BusQueryDeviceID: 103 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n"); 104 Source = &PdoExt->DeviceID; 105 break; 106 107 case BusQueryHardwareIDs: 108 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n"); 109 Source = &PdoExt->HardwareIDs; 110 break; 111 112 case BusQueryCompatibleIDs: 113 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n"); 114 Source = &PdoExt->CompatibleIDs; 115 break; 116 117 case BusQueryInstanceID: 118 DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n"); 119 Source = &PdoExt->InstanceID; 120 break; 121 122 default: 123 DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", 124 IrpSp->Parameters.QueryId.IdType); 125 return Irp->IoStatus.Status; 126 } 127 128 if (!Source->Buffer) 129 return Irp->IoStatus.Status; 130 131 Buffer = ExAllocatePool(PagedPool, Source->MaximumLength); 132 if (!Buffer) 133 return STATUS_NO_MEMORY; 134 135 RtlCopyMemory(Buffer, Source->Buffer, Source->MaximumLength); 136 Irp->IoStatus.Information = (ULONG_PTR)Buffer; 137 return STATUS_SUCCESS; 138 } 139 140 NTSTATUS 141 NTAPI 142 IsaPdoQueryResources( 143 IN PISAPNP_PDO_EXTENSION PdoExt, 144 IN PIRP Irp, 145 IN PIO_STACK_LOCATION IrpSp) 146 { 147 ULONG ListSize; 148 PCM_RESOURCE_LIST ResourceList; 149 150 if (!PdoExt->ResourceList) 151 return Irp->IoStatus.Status; 152 153 ListSize = PdoExt->ResourceListSize; 154 ResourceList = ExAllocatePool(PagedPool, ListSize); 155 if (!ResourceList) 156 return STATUS_NO_MEMORY; 157 158 RtlCopyMemory(ResourceList, PdoExt->ResourceList, ListSize); 159 Irp->IoStatus.Information = (ULONG_PTR)ResourceList; 160 return STATUS_SUCCESS; 161 } 162 163 NTSTATUS 164 NTAPI 165 IsaPdoQueryResourceRequirements( 166 IN PISAPNP_PDO_EXTENSION PdoExt, 167 IN PIRP Irp, 168 IN PIO_STACK_LOCATION IrpSp) 169 { 170 ULONG ListSize; 171 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList; 172 173 if (!PdoExt->RequirementsList) 174 return Irp->IoStatus.Status; 175 176 ListSize = PdoExt->RequirementsList->ListSize; 177 RequirementsList = ExAllocatePool(PagedPool, ListSize); 178 if (!RequirementsList) 179 return STATUS_NO_MEMORY; 180 181 RtlCopyMemory(RequirementsList, PdoExt->RequirementsList, ListSize); 182 Irp->IoStatus.Information = (ULONG_PTR)RequirementsList; 183 return STATUS_SUCCESS; 184 } 185 186 static 187 NTSTATUS 188 NTAPI 189 IsaPdoStartReadPort( 190 IN PISAPNP_FDO_EXTENSION FdoExt, 191 IN PIO_STACK_LOCATION IrpSp) 192 { 193 PCM_RESOURCE_LIST ResourceList = IrpSp->Parameters.StartDevice.AllocatedResources; 194 NTSTATUS Status; 195 KIRQL OldIrql; 196 ULONG i; 197 198 if (!ResourceList || ResourceList->Count != 1) 199 { 200 DPRINT1("No resource list (%p) or bad count (%d)\n", ResourceList, ResourceList ? ResourceList->Count : 0); 201 return STATUS_INSUFFICIENT_RESOURCES; 202 } 203 if (ResourceList->List[0].PartialResourceList.Version != 1 204 || ResourceList->List[0].PartialResourceList.Revision != 1) 205 { 206 DPRINT1("Bad resource list version (%d.%d)\n", ResourceList->List[0].PartialResourceList.Version, ResourceList->List[0].PartialResourceList.Revision); 207 return STATUS_REVISION_MISMATCH; 208 } 209 for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++) 210 { 211 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i]; 212 if (PartialDescriptor->Type == CmResourceTypePort) 213 { 214 PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); 215 if (PartialDescriptor->u.Port.Length > 1 && !FdoExt->ReadDataPort && NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort))) 216 { 217 FdoExt->ReadDataPort = ReadDataPort; 218 KeAcquireSpinLock(&FdoExt->Lock, &OldIrql); 219 Status = IsaHwFillDeviceList(FdoExt); 220 KeReleaseSpinLock(&FdoExt->Lock, OldIrql); 221 if (FdoExt->DeviceCount > 0) 222 { 223 IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations); 224 IoInvalidateDeviceRelations(FdoExt->DataPortPdo, RemovalRelations); 225 } 226 } 227 } 228 } 229 return Status; 230 } 231 232 static 233 NTSTATUS 234 NTAPI 235 IsaPdoOnRepeaterComplete( 236 IN PDEVICE_OBJECT Tdo, 237 IN PIRP SubIrp, 238 PVOID NeedsVote) 239 { 240 PIO_STACK_LOCATION SubStack = IoGetCurrentIrpStackLocation(SubIrp); 241 PIRP Irp = (PIRP)SubStack->Parameters.Others.Argument1; 242 ObDereferenceObject(Tdo); 243 244 if (SubIrp->IoStatus.Status == STATUS_NOT_SUPPORTED) 245 { 246 if (NeedsVote) 247 { 248 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 249 } 250 } 251 else 252 { 253 Irp->IoStatus = SubIrp->IoStatus; 254 } 255 256 IoFreeIrp(SubIrp); 257 IoCompleteRequest(Irp, IO_NO_INCREMENT); 258 return STATUS_MORE_PROCESSING_REQUIRED; 259 } 260 261 NTSTATUS 262 NTAPI 263 IsaPdoRepeatRequest( 264 IN PISAPNP_PDO_EXTENSION PdoExt, 265 IN PIRP Irp, 266 IN BOOLEAN NeedsVote) 267 { 268 PDEVICE_OBJECT Fdo = PdoExt->FdoExt->Common.Self; 269 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); 270 271 PDEVICE_OBJECT Tdo = IoGetAttachedDeviceReference(Fdo); 272 PIRP SubIrp = IoAllocateIrp(Tdo->StackSize + 1, FALSE); 273 PIO_STACK_LOCATION SubStack = IoGetNextIrpStackLocation(SubIrp); 274 275 SubStack->DeviceObject = Tdo; 276 SubStack->Parameters.Others.Argument1 = (PVOID)Irp; 277 278 IoSetNextIrpStackLocation(SubIrp); 279 SubStack = IoGetNextIrpStackLocation(SubIrp); 280 RtlCopyMemory(SubStack, Stack, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); 281 SubStack->Control = 0; 282 IoSetCompletionRoutine(SubIrp, IsaPdoOnRepeaterComplete, (PVOID)(ULONG_PTR)NeedsVote, TRUE, TRUE, TRUE); 283 284 SubIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; 285 IoMarkIrpPending(Irp); 286 IoCallDriver(Tdo, SubIrp); 287 return STATUS_PENDING; 288 } 289 290 NTSTATUS 291 NTAPI 292 IsaPdoPnp( 293 IN PISAPNP_PDO_EXTENSION PdoExt, 294 IN PIRP Irp, 295 IN PIO_STACK_LOCATION IrpSp) 296 { 297 NTSTATUS Status = Irp->IoStatus.Status; 298 299 switch (IrpSp->MinorFunction) 300 { 301 case IRP_MN_START_DEVICE: 302 if (PdoExt->IsaPnpDevice) 303 Status = IsaHwActivateDevice(PdoExt->IsaPnpDevice); 304 else 305 Status = IsaPdoStartReadPort(PdoExt->FdoExt, IrpSp); 306 307 if (NT_SUCCESS(Status)) 308 PdoExt->Common.State = dsStarted; 309 break; 310 311 case IRP_MN_STOP_DEVICE: 312 if (PdoExt->IsaPnpDevice) 313 Status = IsaHwDeactivateDevice(PdoExt->IsaPnpDevice); 314 else 315 Status = STATUS_SUCCESS; 316 317 if (NT_SUCCESS(Status)) 318 PdoExt->Common.State = dsStopped; 319 break; 320 321 case IRP_MN_QUERY_DEVICE_RELATIONS: 322 Status = IsaPdoQueryDeviceRelations(PdoExt, Irp, IrpSp); 323 break; 324 325 case IRP_MN_QUERY_CAPABILITIES: 326 Status = IsaPdoQueryCapabilities(PdoExt, Irp, IrpSp); 327 break; 328 329 case IRP_MN_QUERY_PNP_DEVICE_STATE: 330 if (PdoExt->Common.Self == PdoExt->FdoExt->DataPortPdo) 331 Status = IsaPdoQueryPnpDeviceState(PdoExt, Irp, IrpSp); 332 break; 333 334 case IRP_MN_QUERY_RESOURCES: 335 Status = IsaPdoQueryResources(PdoExt, Irp, IrpSp); 336 break; 337 338 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: 339 Status = IsaPdoQueryResourceRequirements(PdoExt, Irp, IrpSp); 340 break; 341 342 case IRP_MN_QUERY_ID: 343 Status = IsaPdoQueryId(PdoExt, Irp, IrpSp); 344 break; 345 346 case IRP_MN_QUERY_REMOVE_DEVICE: 347 case IRP_MN_REMOVE_DEVICE: 348 case IRP_MN_CANCEL_REMOVE_DEVICE: 349 case IRP_MN_QUERY_STOP_DEVICE: 350 case IRP_MN_CANCEL_STOP_DEVICE: 351 case IRP_MN_QUERY_DEVICE_TEXT: 352 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 353 case IRP_MN_SURPRISE_REMOVAL: 354 Status = STATUS_SUCCESS; 355 break; 356 357 case IRP_MN_READ_CONFIG: 358 case IRP_MN_WRITE_CONFIG: 359 case IRP_MN_EJECT: 360 case IRP_MN_SET_LOCK: 361 case IRP_MN_QUERY_BUS_INFORMATION: 362 case IRP_MN_DEVICE_USAGE_NOTIFICATION: 363 return IsaPdoRepeatRequest(PdoExt, Irp, TRUE); 364 365 default: 366 DPRINT1("Unknown PnP code: %x\n", IrpSp->MinorFunction); 367 break; 368 } 369 370 Irp->IoStatus.Status = Status; 371 IoCompleteRequest(Irp, IO_NO_INCREMENT); 372 373 return Status; 374 } 375