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 = FALSE; 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 = STATUS_INSUFFICIENT_RESOURCES; 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 && PartialDescriptor->u.Port.Length > 1 && !FdoExt->ReadDataPort) 213 { 214 PUCHAR ReadDataPort = ULongToPtr(PartialDescriptor->u.Port.Start.u.LowPart + 3); 215 if (NT_SUCCESS(IsaHwTryReadDataPort(ReadDataPort))) 216 { 217 /* we detected some ISAPNP cards */ 218 FdoExt->ReadDataPort = ReadDataPort; 219 KeAcquireSpinLock(&FdoExt->Lock, &OldIrql); 220 Status = IsaHwFillDeviceList(FdoExt); 221 KeReleaseSpinLock(&FdoExt->Lock, OldIrql); 222 if (FdoExt->DeviceCount > 0) 223 { 224 IoInvalidateDeviceRelations(FdoExt->Pdo, BusRelations); 225 IoInvalidateDeviceRelations(FdoExt->DataPortPdo, RemovalRelations); 226 } 227 } 228 else 229 { 230 /* mark read data port as started, even if no card has been detected */ 231 Status = STATUS_SUCCESS; 232 } 233 } 234 } 235 return Status; 236 } 237 238 static 239 NTSTATUS 240 NTAPI 241 IsaPdoOnRepeaterComplete( 242 IN PDEVICE_OBJECT Tdo, 243 IN PIRP SubIrp, 244 PVOID NeedsVote) 245 { 246 PIO_STACK_LOCATION SubStack = IoGetCurrentIrpStackLocation(SubIrp); 247 PIRP Irp = (PIRP)SubStack->Parameters.Others.Argument1; 248 ObDereferenceObject(Tdo); 249 250 if (SubIrp->IoStatus.Status == STATUS_NOT_SUPPORTED) 251 { 252 if (NeedsVote) 253 { 254 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 255 } 256 } 257 else 258 { 259 Irp->IoStatus = SubIrp->IoStatus; 260 } 261 262 IoFreeIrp(SubIrp); 263 IoCompleteRequest(Irp, IO_NO_INCREMENT); 264 return STATUS_MORE_PROCESSING_REQUIRED; 265 } 266 267 NTSTATUS 268 NTAPI 269 IsaPdoRepeatRequest( 270 IN PISAPNP_PDO_EXTENSION PdoExt, 271 IN PIRP Irp, 272 IN BOOLEAN NeedsVote) 273 { 274 PDEVICE_OBJECT Fdo = PdoExt->FdoExt->Common.Self; 275 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); 276 277 PDEVICE_OBJECT Tdo = IoGetAttachedDeviceReference(Fdo); 278 PIRP SubIrp = IoAllocateIrp(Tdo->StackSize + 1, FALSE); 279 PIO_STACK_LOCATION SubStack = IoGetNextIrpStackLocation(SubIrp); 280 281 SubStack->DeviceObject = Tdo; 282 SubStack->Parameters.Others.Argument1 = (PVOID)Irp; 283 284 IoSetNextIrpStackLocation(SubIrp); 285 SubStack = IoGetNextIrpStackLocation(SubIrp); 286 RtlCopyMemory(SubStack, Stack, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); 287 SubStack->Control = 0; 288 IoSetCompletionRoutine(SubIrp, IsaPdoOnRepeaterComplete, (PVOID)(ULONG_PTR)NeedsVote, TRUE, TRUE, TRUE); 289 290 SubIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; 291 IoMarkIrpPending(Irp); 292 IoCallDriver(Tdo, SubIrp); 293 return STATUS_PENDING; 294 } 295 296 NTSTATUS 297 NTAPI 298 IsaPdoPnp( 299 IN PISAPNP_PDO_EXTENSION PdoExt, 300 IN PIRP Irp, 301 IN PIO_STACK_LOCATION IrpSp) 302 { 303 NTSTATUS Status = Irp->IoStatus.Status; 304 305 switch (IrpSp->MinorFunction) 306 { 307 case IRP_MN_START_DEVICE: 308 if (PdoExt->IsaPnpDevice) 309 Status = IsaHwActivateDevice(PdoExt->IsaPnpDevice); 310 else 311 Status = IsaPdoStartReadPort(PdoExt->FdoExt, IrpSp); 312 313 if (NT_SUCCESS(Status)) 314 PdoExt->Common.State = dsStarted; 315 break; 316 317 case IRP_MN_STOP_DEVICE: 318 if (PdoExt->IsaPnpDevice) 319 Status = IsaHwDeactivateDevice(PdoExt->IsaPnpDevice); 320 else 321 Status = STATUS_SUCCESS; 322 323 if (NT_SUCCESS(Status)) 324 PdoExt->Common.State = dsStopped; 325 break; 326 327 case IRP_MN_QUERY_DEVICE_RELATIONS: 328 Status = IsaPdoQueryDeviceRelations(PdoExt, Irp, IrpSp); 329 break; 330 331 case IRP_MN_QUERY_CAPABILITIES: 332 Status = IsaPdoQueryCapabilities(PdoExt, Irp, IrpSp); 333 break; 334 335 case IRP_MN_QUERY_PNP_DEVICE_STATE: 336 if (PdoExt->Common.Self == PdoExt->FdoExt->DataPortPdo) 337 Status = IsaPdoQueryPnpDeviceState(PdoExt, Irp, IrpSp); 338 break; 339 340 case IRP_MN_QUERY_RESOURCES: 341 Status = IsaPdoQueryResources(PdoExt, Irp, IrpSp); 342 break; 343 344 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: 345 Status = IsaPdoQueryResourceRequirements(PdoExt, Irp, IrpSp); 346 break; 347 348 case IRP_MN_QUERY_ID: 349 Status = IsaPdoQueryId(PdoExt, Irp, IrpSp); 350 break; 351 352 case IRP_MN_QUERY_REMOVE_DEVICE: 353 case IRP_MN_REMOVE_DEVICE: 354 case IRP_MN_CANCEL_REMOVE_DEVICE: 355 case IRP_MN_QUERY_STOP_DEVICE: 356 case IRP_MN_CANCEL_STOP_DEVICE: 357 case IRP_MN_QUERY_DEVICE_TEXT: 358 case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 359 case IRP_MN_SURPRISE_REMOVAL: 360 Status = STATUS_SUCCESS; 361 break; 362 363 case IRP_MN_READ_CONFIG: 364 case IRP_MN_WRITE_CONFIG: 365 case IRP_MN_EJECT: 366 case IRP_MN_SET_LOCK: 367 case IRP_MN_QUERY_BUS_INFORMATION: 368 case IRP_MN_DEVICE_USAGE_NOTIFICATION: 369 return IsaPdoRepeatRequest(PdoExt, Irp, TRUE); 370 371 default: 372 DPRINT1("Unknown PnP code: %x\n", IrpSp->MinorFunction); 373 break; 374 } 375 376 Irp->IoStatus.Status = Status; 377 IoCompleteRequest(Irp, IO_NO_INCREMENT); 378 379 return Status; 380 } 381