1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/legacy/stream/pnp.c 5 * PURPOSE: pnp handling 6 * PROGRAMMER: Johannes Anderwald 7 */ 8 9 #include "stream.h" 10 11 VOID 12 CompleteIrp( 13 IN PIRP Irp, 14 IN NTSTATUS Status, 15 IN ULONG_PTR Information) 16 { 17 Irp->IoStatus.Status = Status; 18 Irp->IoStatus.Information = Information; 19 IoCompleteRequest(Irp, IO_NO_INCREMENT); 20 } 21 22 VOID 23 NTAPI 24 StreamClassReleaseResources( 25 IN PDEVICE_OBJECT DeviceObject) 26 { 27 PSTREAM_DEVICE_EXTENSION DeviceExtension; 28 PLIST_ENTRY Entry; 29 PMEMORY_RESOURCE_LIST Mem; 30 31 /* Get device extension */ 32 DeviceExtension = (PSTREAM_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 33 34 /* Disconnect interrupt */ 35 if (DeviceExtension->Interrupt) 36 { 37 IoDisconnectInterrupt(DeviceExtension->Interrupt); 38 DeviceExtension->Interrupt = NULL; 39 } 40 41 /* Release DmaAdapter */ 42 if (DeviceExtension->DmaAdapter) 43 { 44 DeviceExtension->DmaAdapter->DmaOperations->PutDmaAdapter(DeviceExtension->DmaAdapter); 45 DeviceExtension->DmaAdapter = NULL; 46 } 47 48 /* Release mem mapped I/O */ 49 while(!IsListEmpty(&DeviceExtension->MemoryResourceList)) 50 { 51 Entry = RemoveHeadList(&DeviceExtension->MemoryResourceList); 52 Mem = (PMEMORY_RESOURCE_LIST)CONTAINING_RECORD(Entry, MEMORY_RESOURCE_LIST, Entry); 53 54 MmUnmapIoSpace(Mem->Start, Mem->Length); 55 ExFreePool(Entry); 56 } 57 } 58 59 BOOLEAN 60 NTAPI 61 StreamClassSynchronize( 62 IN PKINTERRUPT Interrupt, 63 IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, 64 IN PVOID SynchronizeContext) 65 { 66 /* This function is used when the driver either implements synchronization on its own 67 * or if there is no interrupt assigned 68 */ 69 return SynchronizeRoutine(SynchronizeContext); 70 } 71 72 VOID 73 NTAPI 74 StreamClassInterruptDpc( 75 IN PKDPC Dpc, 76 IN PVOID DeferredContext, 77 IN PVOID SystemArgument1, 78 IN PVOID SystemArgument2) 79 { 80 //TODO 81 //read/write data 82 } 83 84 85 BOOLEAN 86 NTAPI 87 StreamClassInterruptRoutine( 88 IN PKINTERRUPT Interrupt, 89 IN PVOID ServiceContext) 90 { 91 BOOLEAN Ret = FALSE; 92 PSTREAM_DEVICE_EXTENSION DeviceExtension = (PSTREAM_DEVICE_EXTENSION)ServiceContext; 93 94 /* Does the driver implement HwInterrupt routine */ 95 if (DeviceExtension->DriverExtension->Data.HwInterrupt) 96 { 97 /* Check if the interrupt was coming from this device */ 98 Ret = DeviceExtension->DriverExtension->Data.HwInterrupt(DeviceExtension->DeviceExtension); 99 if (Ret) 100 { 101 /* Interrupt has from this device, schedule a Dpc for us */ 102 KeInsertQueueDpc(&DeviceExtension->InterruptDpc, NULL, NULL); 103 } 104 } 105 /* Return result */ 106 return Ret; 107 } 108 109 110 111 NTSTATUS 112 NTAPI 113 StreamClassStartDevice( 114 IN PDEVICE_OBJECT DeviceObject, 115 IN PIRP Irp) 116 { 117 PHW_STREAM_REQUEST_BLOCK_EXT RequestBlock; 118 PPORT_CONFIGURATION_INFORMATION Config; 119 PSTREAM_DEVICE_EXTENSION DeviceExtension; 120 PIO_STACK_LOCATION IoStack; 121 PCM_RESOURCE_LIST List; 122 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; 123 PSTREAM_CLASS_DRIVER_EXTENSION DriverObjectExtension; 124 PDMA_ADAPTER Adapter; 125 DEVICE_DESCRIPTION DeviceDesc; 126 NTSTATUS Status = STATUS_SUCCESS; 127 ULONG ResultLength, Index; 128 BOOLEAN bUseDMA, bUseInterrupt; 129 ULONG MapRegisters; 130 KAFFINITY Affinity = 0; 131 PHW_STREAM_DESCRIPTOR StreamDescriptor; 132 PACCESS_RANGE Range; 133 PVOID MappedAddr; 134 PMEMORY_RESOURCE_LIST Mem; 135 136 /* Get current stack location */ 137 IoStack = IoGetCurrentIrpStackLocation(Irp); 138 139 /* Get resource list */ 140 List = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated; 141 /* Calculate request length */ 142 ResultLength = sizeof(HW_STREAM_REQUEST_BLOCK_EXT) + sizeof(PPORT_CONFIGURATION_INFORMATION) + List->List[0].PartialResourceList.Count * sizeof(ACCESS_RANGE); 143 144 /* Allocate Request Block */ 145 RequestBlock = ExAllocatePool(NonPagedPool, ResultLength); 146 147 if (!RequestBlock) 148 { 149 /* Not enough memory */ 150 CompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, 0); 151 return STATUS_INSUFFICIENT_RESOURCES; 152 } 153 154 /* Get device extension */ 155 DeviceExtension = (PSTREAM_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 156 157 /* Get driver object extension */ 158 DriverObjectExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, (PVOID)StreamClassAddDevice); 159 160 /* sanity checks */ 161 ASSERT(DeviceExtension); 162 ASSERT(DriverObjectExtension); 163 164 /* Zero request block */ 165 RtlZeroMemory(RequestBlock, ResultLength); 166 167 /* Locate Config struct */ 168 Config = (PPORT_CONFIGURATION_INFORMATION) (RequestBlock + 1); 169 Range = (PACCESS_RANGE) (Config + 1); 170 171 /* Initialize Request */ 172 RequestBlock->Block.SizeOfThisPacket = sizeof(HW_STREAM_REQUEST_BLOCK); 173 RequestBlock->Block.Command = SRB_INITIALIZE_DEVICE; 174 RequestBlock->Block.CommandData.ConfigInfo = Config; 175 KeInitializeEvent(&RequestBlock->Event, SynchronizationEvent, FALSE); 176 177 Config->SizeOfThisPacket = sizeof(PPORT_CONFIGURATION_INFORMATION); 178 Config->HwDeviceExtension = (PVOID) (DeviceExtension + 1); 179 Config->ClassDeviceObject = DeviceObject; 180 Config->PhysicalDeviceObject = DeviceExtension->LowerDeviceObject; 181 Config->RealPhysicalDeviceObject = DeviceExtension->PhysicalDeviceObject; 182 Config->AccessRanges = Range; 183 184 IoGetDeviceProperty(DeviceObject, DevicePropertyBusNumber, sizeof(ULONG), (PVOID)&Config->SystemIoBusNumber, &ResultLength); 185 IoGetDeviceProperty(DeviceObject, DevicePropertyLegacyBusType, sizeof(INTERFACE_TYPE), (PVOID)&Config->AdapterInterfaceType, &ResultLength); 186 187 /* Get resource list */ 188 List = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated; 189 190 /* Scan the translated resources */ 191 bUseDMA = FALSE; 192 bUseInterrupt = FALSE; 193 194 Range = (PACCESS_RANGE) (Config + 1); 195 196 for(Index = 0; Index < List->List[0].PartialResourceList.Count; Index++) 197 { 198 /* Locate partial descriptor */ 199 Descriptor = &List->List[0].PartialResourceList.PartialDescriptors[Index]; 200 201 switch(Descriptor->Type) 202 { 203 case CmResourceTypePort: 204 { 205 /* Store resource information in AccessRange struct */ 206 Range[Config->NumberOfAccessRanges].RangeLength = Descriptor->u.Port.Length; 207 Range[Config->NumberOfAccessRanges].RangeStart.QuadPart = Descriptor->u.Port.Start.QuadPart; 208 Range[Config->NumberOfAccessRanges].RangeInMemory = FALSE; 209 Config->NumberOfAccessRanges++; 210 break; 211 } 212 case CmResourceTypeInterrupt: 213 { 214 /* Store resource information */ 215 Config->BusInterruptLevel = Descriptor->u.Interrupt.Level; 216 Config->BusInterruptVector = Descriptor->u.Interrupt.Vector; 217 Config->InterruptMode = Descriptor->Flags; 218 Affinity = Descriptor->u.Interrupt.Affinity; 219 bUseInterrupt = TRUE; 220 break; 221 } 222 case CmResourceTypeMemory: 223 { 224 Mem = ExAllocatePool(NonPagedPool, sizeof(MEMORY_RESOURCE_LIST)); 225 MappedAddr = MmMapIoSpace(Descriptor->u.Memory.Start, Descriptor->u.Memory.Length, MmNonCached); 226 if (!MappedAddr || !Mem) 227 { 228 if (Mem) 229 { 230 /* Release Memory resource descriptor */ 231 ExFreePool(Mem); 232 } 233 234 if (MappedAddr) 235 { 236 /* Release mem mapped I/O */ 237 MmUnmapIoSpace(MappedAddr, Descriptor->u.Memory.Length); 238 } 239 240 /* Release resources */ 241 StreamClassReleaseResources(DeviceObject); 242 /* Complete irp */ 243 CompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, 0); 244 ExFreePool(RequestBlock); 245 return STATUS_INSUFFICIENT_RESOURCES; 246 } 247 /* Store range for driver */ 248 Range[Config->NumberOfAccessRanges].RangeLength = Descriptor->u.Memory.Length; 249 Range[Config->NumberOfAccessRanges].RangeStart.QuadPart = Descriptor->u.Memory.Start.QuadPart; 250 Range[Config->NumberOfAccessRanges].RangeInMemory = TRUE; 251 Config->NumberOfAccessRanges++; 252 /* Initialize Memory resource descriptor */ 253 Mem->Length = Descriptor->u.Memory.Length; 254 Mem->Start = MappedAddr; 255 InsertTailList(&DeviceExtension->MemoryResourceList, &Mem->Entry); 256 break; 257 } 258 case CmResourceTypeDma: 259 { 260 bUseDMA = TRUE; 261 Config->DmaChannel = Descriptor->u.Dma.Channel; 262 break; 263 } 264 } 265 } 266 267 if (!bUseInterrupt || DriverObjectExtension->Data.HwInterrupt == NULL || Config->BusInterruptLevel == 0 || Config->BusInterruptVector == 0) 268 { 269 /* requirements not satisfied */ 270 DeviceExtension->SynchronizeFunction = StreamClassSynchronize; 271 } 272 else 273 { 274 /* use real sync routine */ 275 DeviceExtension->SynchronizeFunction = KeSynchronizeExecution; 276 277 /* connect interrupt */ 278 Status = IoConnectInterrupt(&DeviceExtension->Interrupt, 279 StreamClassInterruptRoutine, 280 (PVOID)DeviceExtension, 281 NULL, 282 Config->BusInterruptVector, 283 Config->BusInterruptLevel, 284 Config->BusInterruptLevel, 285 Config->InterruptMode, 286 TRUE, 287 Affinity, 288 FALSE); 289 if (!NT_SUCCESS(Status)) 290 { 291 /* Release resources */ 292 StreamClassReleaseResources(DeviceObject); 293 /* Failed to connect interrupt */ 294 CompleteIrp(Irp, Status, 0); 295 /* Release request block */ 296 ExFreePool(RequestBlock); 297 return Status; 298 } 299 300 /* store interrupt object */ 301 Config->InterruptObject = DeviceExtension->Interrupt; 302 } 303 304 /* does the device use DMA */ 305 if (bUseDMA && DriverObjectExtension->Data.BusMasterDMA) 306 { 307 /* Zero device description */ 308 RtlZeroMemory(&DeviceDesc, sizeof(DEVICE_DESCRIPTION)); 309 310 DeviceDesc.Version = DEVICE_DESCRIPTION_VERSION; 311 DeviceDesc.Master = TRUE; 312 DeviceDesc.ScatterGather = TRUE; 313 DeviceDesc.AutoInitialize = FALSE; 314 DeviceDesc.DmaChannel = Config->DmaChannel; 315 DeviceDesc.InterfaceType = Config->AdapterInterfaceType; 316 DeviceDesc.DmaWidth = Width32Bits; 317 DeviceDesc.DmaSpeed = Compatible; 318 DeviceDesc.MaximumLength = MAXULONG; 319 DeviceDesc.Dma32BitAddresses = DriverObjectExtension->Data.Dma24BitAddresses; 320 321 Adapter = IoGetDmaAdapter(DeviceExtension->PhysicalDeviceObject, &DeviceDesc, &MapRegisters); 322 if (!Adapter) 323 { 324 /* Failed to claim DMA Adapter */ 325 CompleteIrp(Irp, Status, 0); 326 /* Release resources */ 327 StreamClassReleaseResources(DeviceObject); 328 /* Release request block */ 329 ExFreePool(RequestBlock); 330 return Status; 331 } 332 333 if (DeviceExtension->DriverExtension->Data.DmaBufferSize) 334 { 335 DeviceExtension->DmaCommonBuffer = Adapter->DmaOperations->AllocateCommonBuffer(Adapter, DeviceExtension->DriverExtension->Data.DmaBufferSize, &DeviceExtension->DmaPhysicalAddress, FALSE); 336 if (!DeviceExtension->DmaCommonBuffer) 337 { 338 /* Failed to allocate a common buffer */ 339 CompleteIrp(Irp, Status, 0); 340 /* Release resources */ 341 StreamClassReleaseResources(DeviceObject); 342 /* Release request block */ 343 ExFreePool(RequestBlock); 344 return Status; 345 } 346 } 347 348 349 DeviceExtension->MapRegisters = MapRegisters; 350 DeviceExtension->DmaAdapter = Adapter; 351 Config->DmaAdapterObject = (PADAPTER_OBJECT)Adapter; 352 } 353 354 355 /* First forward the request to lower attached device object */ 356 Status = ForwardIrpSynchronous(DeviceObject, Irp); 357 if (!NT_SUCCESS(Status)) 358 { 359 /* Failed to start lower devices */ 360 CompleteIrp(Irp, Status, 0); 361 /* Release resources */ 362 StreamClassReleaseResources(DeviceObject); 363 /* Release request block */ 364 ExFreePool(RequestBlock); 365 return Status; 366 } 367 368 Config->Irp = Irp; 369 370 /* FIXME SYNCHRONIZATION */ 371 372 /* Send the request */ 373 DriverObjectExtension->Data.HwReceivePacket((PHW_STREAM_REQUEST_BLOCK)RequestBlock); 374 if (RequestBlock->Block.Status == STATUS_PENDING) 375 { 376 /* Request is pending, wait for result */ 377 KeWaitForSingleObject(&RequestBlock->Event, Executive, KernelMode, FALSE, NULL); 378 /* Get final status code */ 379 Status = RequestBlock->Block.Status; 380 } 381 382 /* Copy stream descriptor size */ 383 DeviceExtension->StreamDescriptorSize = Config->StreamDescriptorSize; 384 385 /* check if the request has succeeded or if stream size is valid*/ 386 if (!NT_SUCCESS(Status)|| !Config->StreamDescriptorSize) 387 { 388 /* Failed to start device */ 389 CompleteIrp(Irp, Status, 0); 390 /* Release resources */ 391 StreamClassReleaseResources(DeviceObject); 392 /* Release request block */ 393 ExFreePool(RequestBlock); 394 return Status; 395 } 396 397 /* Allocate a stream Descriptor */ 398 StreamDescriptor = ExAllocatePool(NonPagedPool, DeviceExtension->StreamDescriptorSize); 399 if (!StreamDescriptor) 400 { 401 /* Not enough memory */ 402 CompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, 0); 403 /* Release resources */ 404 StreamClassReleaseResources(DeviceObject); 405 /* Release request block */ 406 ExFreePool(RequestBlock); 407 return STATUS_INSUFFICIENT_RESOURCES; 408 } 409 410 /* Zero stream descriptor */ 411 RtlZeroMemory(StreamDescriptor, DeviceExtension->StreamDescriptorSize); 412 413 /* Setup get stream info struct */ 414 RequestBlock->Block.Command = SRB_GET_STREAM_INFO; 415 RequestBlock->Block.CommandData.StreamBuffer = StreamDescriptor; 416 KeClearEvent(&RequestBlock->Event); 417 418 /* send the request */ 419 DriverObjectExtension->Data.HwReceivePacket((PHW_STREAM_REQUEST_BLOCK)RequestBlock); 420 if (RequestBlock->Block.Status == STATUS_PENDING) 421 { 422 /* Request is pending, wait for result */ 423 KeWaitForSingleObject(&RequestBlock->Event, Executive, KernelMode, FALSE, NULL); 424 /* Get final status code */ 425 Status = RequestBlock->Block.Status; 426 } 427 428 if (NT_SUCCESS(Status)) 429 { 430 /* store stream descriptor */ 431 DeviceExtension->StreamDescriptor = StreamDescriptor; 432 } 433 else 434 { 435 /* cleanup resources */ 436 ExFreePool(StreamDescriptor); 437 } 438 439 ExFreePool(RequestBlock); 440 /* Complete Irp */ 441 CompleteIrp(Irp, Status, 0); 442 /* Return result */ 443 return Status; 444 } 445 446 NTSTATUS 447 NTAPI 448 StreamClassPnp( 449 IN PDEVICE_OBJECT DeviceObject, 450 IN PIRP Irp) 451 { 452 PIO_STACK_LOCATION IoStack; 453 454 /* Get current irp stack location */ 455 IoStack = IoGetCurrentIrpStackLocation(Irp); 456 457 switch (IoStack->MinorFunction) 458 { 459 case IRP_MN_START_DEVICE: 460 { 461 return StreamClassStartDevice(DeviceObject, Irp); 462 } 463 } 464 465 IoCompleteRequest(Irp, IO_NO_INCREMENT); 466 return STATUS_NOT_SUPPORTED; 467 } 468 469 470