Sync with trunk r63935.
[reactos.git] / drivers / wdm / audio / legacy / stream / pnp.c
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 KeResetEvent(&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