xref: /reactos/drivers/wdm/audio/legacy/stream/pnp.c (revision 9d3c3a75)
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     if (IoForwardIrpSynchronously(DeviceExtension->LowerDeviceObject, Irp))
357     {
358         Status = Irp->IoStatus.Status;
359     }
360     else
361     {
362         Status = STATUS_UNSUCCESSFUL;
363     }
364 
365     if (!NT_SUCCESS(Status))
366     {
367         /* Failed to start lower devices */
368         CompleteIrp(Irp, Status, 0);
369         /* Release resources */
370         StreamClassReleaseResources(DeviceObject);
371         /* Release request block */
372         ExFreePool(RequestBlock);
373         return Status;
374     }
375 
376     Config->Irp = Irp;
377 
378     /* FIXME SYNCHRONIZATION */
379 
380     /* Send the request */
381     DriverObjectExtension->Data.HwReceivePacket((PHW_STREAM_REQUEST_BLOCK)RequestBlock);
382     if (RequestBlock->Block.Status == STATUS_PENDING)
383     {
384         /* Request is pending, wait for result */
385         KeWaitForSingleObject(&RequestBlock->Event, Executive, KernelMode, FALSE, NULL);
386         /* Get final status code */
387         Status = RequestBlock->Block.Status;
388     }
389 
390     /* Copy stream descriptor size */
391     DeviceExtension->StreamDescriptorSize = Config->StreamDescriptorSize;
392 
393     /* check if the request has succeeded or if stream size is valid*/
394     if (!NT_SUCCESS(Status)|| !Config->StreamDescriptorSize)
395     {
396         /* Failed to start device */
397         CompleteIrp(Irp, Status, 0);
398         /* Release resources */
399         StreamClassReleaseResources(DeviceObject);
400         /* Release request block */
401         ExFreePool(RequestBlock);
402         return Status;
403     }
404 
405     /* Allocate a stream Descriptor */
406     StreamDescriptor = ExAllocatePool(NonPagedPool, DeviceExtension->StreamDescriptorSize);
407     if (!StreamDescriptor)
408     {
409         /* Not enough memory */
410         CompleteIrp(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
411         /* Release resources */
412         StreamClassReleaseResources(DeviceObject);
413         /* Release request block */
414         ExFreePool(RequestBlock);
415         return STATUS_INSUFFICIENT_RESOURCES;
416     }
417 
418     /* Zero stream descriptor */
419     RtlZeroMemory(StreamDescriptor, DeviceExtension->StreamDescriptorSize);
420 
421     /* Setup get stream info struct */
422     RequestBlock->Block.Command = SRB_GET_STREAM_INFO;
423     RequestBlock->Block.CommandData.StreamBuffer = StreamDescriptor;
424     KeClearEvent(&RequestBlock->Event);
425 
426     /* send the request */
427     DriverObjectExtension->Data.HwReceivePacket((PHW_STREAM_REQUEST_BLOCK)RequestBlock);
428     if (RequestBlock->Block.Status == STATUS_PENDING)
429     {
430         /* Request is pending, wait for result */
431         KeWaitForSingleObject(&RequestBlock->Event, Executive, KernelMode, FALSE, NULL);
432         /* Get final status code */
433         Status = RequestBlock->Block.Status;
434     }
435 
436     if (NT_SUCCESS(Status))
437     {
438         /* store stream descriptor */
439         DeviceExtension->StreamDescriptor = StreamDescriptor;
440     }
441     else
442     {
443         /* cleanup resources */
444         ExFreePool(StreamDescriptor);
445     }
446 
447     ExFreePool(RequestBlock);
448     /* Complete Irp */
449     CompleteIrp(Irp, Status, 0);
450     /* Return result */
451     return Status;
452 }
453 
454 NTSTATUS
455 NTAPI
456 StreamClassPnp(
457     IN  PDEVICE_OBJECT DeviceObject,
458     IN  PIRP Irp)
459 {
460     PIO_STACK_LOCATION IoStack;
461 
462     /* Get current irp stack location */
463     IoStack = IoGetCurrentIrpStackLocation(Irp);
464 
465     switch (IoStack->MinorFunction)
466     {
467         case IRP_MN_START_DEVICE:
468         {
469             return StreamClassStartDevice(DeviceObject, Irp);
470         }
471     }
472 
473     IoCompleteRequest(Irp, IO_NO_INCREMENT);
474     return STATUS_NOT_SUPPORTED;
475 }
476 
477 
478