- Fix a bug in KsAllocateDeviceHeader which copied the create item to the wrong offset
[reactos.git] / reactos / drivers / wdm / audio / legacy / wdmaud / control.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/legacy/wdmaud/deviface.c
5 * PURPOSE: System Audio graph builder
6 * PROGRAMMER: Andrew Greenwood
7 * Johannes Anderwald
8 */
9 #include "wdmaud.h"
10
11 const GUID KSPROPSETID_Connection = {0x1D58C920L, 0xAC9B, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
12 const GUID KSPROPSETID_Sysaudio = {0xCBE3FAA0L, 0xCC75, 0x11D0, {0xB4, 0x65, 0x00, 0x00, 0x1A, 0x18, 0x18, 0xE6}};
13 const GUID KSPROPSETID_General = {0x1464EDA5L, 0x6A8F, 0x11D1, {0x9A, 0xA7, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
14 const GUID KSINTERFACESETID_Standard = {0x1A8766A0L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
15 const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
16 const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
17 const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
18 const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
19
20
21 NTSTATUS
22 SetIrpIoStatus(
23 IN PIRP Irp,
24 IN NTSTATUS Status,
25 IN ULONG Length)
26 {
27 Irp->IoStatus.Information = Length;
28 Irp->IoStatus.Status = Status;
29 IoCompleteRequest(Irp, IO_NO_INCREMENT);
30 return Status;
31
32 }
33
34 NTSTATUS
35 WdmAudControlOpen(
36 IN PDEVICE_OBJECT DeviceObject,
37 IN PIRP Irp,
38 IN PWDMAUD_DEVICE_INFO DeviceInfo,
39 IN PWDMAUD_CLIENT ClientInfo)
40 {
41 PSYSAUDIO_INSTANCE_INFO InstanceInfo;
42 ULONG BytesReturned;
43 NTSTATUS Status;
44 ACCESS_MASK DesiredAccess = 0;
45 HANDLE PinHandle;
46 KSPIN_CONNECT * PinConnect;
47 KSDATAFORMAT_WAVEFORMATEX * DataFormat;
48
49 if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE)
50 {
51 DPRINT1("FIXME: only waveout devices are supported\n");
52 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
53 }
54
55 InstanceInfo = ExAllocatePool(NonPagedPool, sizeof(KSDATAFORMAT_WAVEFORMATEX) + sizeof(KSPIN_CONNECT));
56 if (!InstanceInfo)
57 {
58 /* no memory */
59 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
60 }
61
62 InstanceInfo->Property.Set = KSPROPSETID_Sysaudio;
63 InstanceInfo->Property.Id = KSPROPERTY_SYSAUDIO_INSTANCE_INFO;
64 InstanceInfo->Property.Flags = KSPROPERTY_TYPE_SET;
65 InstanceInfo->Flags = 0;
66 InstanceInfo->DeviceNumber = DeviceInfo->DeviceIndex;
67
68 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)InstanceInfo, sizeof(SYSAUDIO_INSTANCE_INFO), NULL, 0, &BytesReturned);
69
70 if (!NT_SUCCESS(Status))
71 {
72 /* failed to acquire audio device */
73 DPRINT1("KsSynchronousIoControlDevice failed with %x\n", Status);
74 ExFreePool(InstanceInfo);
75 return SetIrpIoStatus(Irp, Status, 0);
76 }
77
78 if (DeviceInfo->DeviceType == WAVE_IN_DEVICE_TYPE ||
79 DeviceInfo->DeviceType == MIDI_IN_DEVICE_TYPE ||
80 DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
81 {
82 DesiredAccess |= GENERIC_READ;
83 }
84
85 if (DeviceInfo->DeviceType == WAVE_OUT_DEVICE_TYPE ||
86 DeviceInfo->DeviceType == MIDI_OUT_DEVICE_TYPE ||
87 DeviceInfo->DeviceType == AUX_DEVICE_TYPE ||
88 DeviceInfo->DeviceType == MIXER_DEVICE_TYPE)
89 {
90 DesiredAccess |= GENERIC_WRITE;
91 }
92
93 PinConnect = (KSPIN_CONNECT*)InstanceInfo;
94
95
96 PinConnect->Interface.Set = KSINTERFACESETID_Standard;
97 PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
98 PinConnect->Interface.Flags = 0;
99 PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
100 PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
101 PinConnect->Medium.Flags = 0;
102 PinConnect->PinId = 0; //FIXME
103 PinConnect->PinToHandle = NULL;
104 PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
105 PinConnect->Priority.PrioritySubClass = 1;
106
107
108 DataFormat = (KSDATAFORMAT_WAVEFORMATEX*) (PinConnect + 1);
109 DataFormat->WaveFormatEx.wFormatTag = DeviceInfo->u.WaveFormatEx.wFormatTag;
110 DataFormat->WaveFormatEx.nChannels = DeviceInfo->u.WaveFormatEx.nChannels;
111 DataFormat->WaveFormatEx.nSamplesPerSec = DeviceInfo->u.WaveFormatEx.nSamplesPerSec;
112 DataFormat->WaveFormatEx.nBlockAlign = DeviceInfo->u.WaveFormatEx.nBlockAlign;
113 DataFormat->WaveFormatEx.nAvgBytesPerSec = DeviceInfo->u.WaveFormatEx.nAvgBytesPerSec;
114 DataFormat->WaveFormatEx.wBitsPerSample = DeviceInfo->u.WaveFormatEx.wBitsPerSample;
115 DataFormat->WaveFormatEx.cbSize = 0;
116 DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
117 DataFormat->DataFormat.Flags = 0;
118 DataFormat->DataFormat.Reserved = 0;
119 DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
120
121 if (DeviceInfo->u.WaveFormatEx.wFormatTag != WAVE_FORMAT_PCM)
122 DPRINT1("FIXME\n");
123
124 DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
125 DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
126 DataFormat->DataFormat.SampleSize = 4;
127
128
129 Status = KsCreatePin(ClientInfo->hSysAudio, PinConnect, DesiredAccess, &PinHandle);
130 DPRINT1("KsCreatePin Status %x\n", Status);
131
132
133 /* free buffer */
134 ExFreePool(InstanceInfo);
135
136 if (NT_SUCCESS(Status))
137 {
138 DeviceInfo->hDevice = PinHandle;
139 }
140 else
141 {
142 DeviceInfo->hDevice = NULL;
143 }
144
145 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
146 }
147
148 NTSTATUS
149 WdmAudControlDeviceType(
150 IN PDEVICE_OBJECT DeviceObject,
151 IN PIRP Irp,
152 IN PWDMAUD_DEVICE_INFO DeviceInfo,
153 IN PWDMAUD_CLIENT ClientInfo)
154 {
155 KSPROPERTY Property;
156 ULONG Result, BytesReturned;
157 NTSTATUS Status;
158
159 if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE)
160 {
161 DPRINT1("FIXME: only waveout devices are supported\n");
162 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
163 }
164
165 Property.Set = KSPROPSETID_Sysaudio;
166 Property.Id = KSPROPERTY_SYSAUDIO_DEVICE_COUNT;
167 Property.Flags = KSPROPERTY_TYPE_GET;
168
169 Status = KsSynchronousIoControlDevice(ClientInfo->FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Result, sizeof(ULONG), &BytesReturned);
170
171 if (NT_SUCCESS(Status))
172 DeviceInfo->DeviceCount = Result;
173 else
174 DeviceInfo->DeviceCount = 0;
175
176 DPRINT1("WdmAudControlDeviceType Status %x Devices %u\n", Status, DeviceInfo->DeviceCount);
177 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
178 }
179
180 NTSTATUS
181 WdmAudControlDeviceState(
182 IN PDEVICE_OBJECT DeviceObject,
183 IN PIRP Irp,
184 IN PWDMAUD_DEVICE_INFO DeviceInfo,
185 IN PWDMAUD_CLIENT ClientInfo)
186 {
187 KSPROPERTY Property;
188 KSSTATE State;
189 NTSTATUS Status;
190 ULONG BytesReturned;
191 PFILE_OBJECT FileObject;
192
193 if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE)
194 {
195 DPRINT1("FIXME: only waveout devices are supported\n");
196 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
197 }
198
199 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_READ | GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
200 if (!NT_SUCCESS(Status))
201 {
202 DPRINT1("Error: invalid device handle provided %p\n", DeviceInfo->hDevice);
203 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
204 }
205
206 Property.Set = KSPROPSETID_Connection;
207 Property.Id = KSPROPERTY_CONNECTION_STATE;
208 Property.Flags = KSPROPERTY_TYPE_SET;
209
210 State = DeviceInfo->State;
211
212 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
213
214 ObDereferenceObject(FileObject);
215
216 DPRINT1("WdmAudControlDeviceState Status %x\n", Status);
217 return SetIrpIoStatus(Irp, Status, sizeof(WDMAUD_DEVICE_INFO));
218 }
219
220 NTSTATUS
221 NTAPI
222 WdmAudWriteCompleted(
223 IN PDEVICE_OBJECT DeviceObject,
224 IN PIRP Irp,
225 IN PVOID Ctx)
226 {
227 PWRITE_CONTEXT Context = (PWRITE_CONTEXT)Ctx;
228
229 Context->Irp->IoStatus.Information = Context->Length;
230 Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
231 IoCompleteRequest(Context->Irp, IO_SOUND_INCREMENT);
232
233 ExFreePool(Context);
234 return STATUS_SUCCESS;
235 }
236
237 NTSTATUS
238 WdmAudControlWriteData(
239 IN PDEVICE_OBJECT DeviceObject,
240 IN PIRP Irp,
241 IN PWDMAUD_DEVICE_INFO DeviceInfo,
242 IN PWDMAUD_CLIENT ClientInfo)
243 {
244 PKSSTREAM_HEADER Packet;
245 NTSTATUS Status = STATUS_SUCCESS;
246 PFILE_OBJECT FileObject;
247 PWRITE_CONTEXT Context;
248 ULONG BytesReturned;
249 PUCHAR Buffer;
250
251 Status = ObReferenceObjectByHandle(DeviceInfo->hDevice, GENERIC_WRITE, IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
252 if (!NT_SUCCESS(Status))
253 {
254 DPRINT1("Invalid buffer handle %x\n", DeviceInfo->hDevice);
255 return SetIrpIoStatus(Irp, Status, 0);
256 }
257
258 if (DeviceInfo->DeviceType != WAVE_OUT_DEVICE_TYPE)
259 {
260 DPRINT1("FIXME: only waveout devices are supported\n");
261 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
262 }
263
264 _SEH2_TRY
265 {
266 ProbeForRead(DeviceInfo->Buffer, DeviceInfo->BufferSize, TYPE_ALIGNMENT(char));
267 }
268 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
269 {
270 /* Exception, get the error code */
271 Status = _SEH2_GetExceptionCode();
272 }
273 _SEH2_END;
274
275 if (!NT_SUCCESS(Status))
276 {
277 DPRINT1("Invalid buffer supplied\n");
278 return SetIrpIoStatus(Irp, Status, 0);
279 }
280
281 Buffer = ExAllocatePool(NonPagedPool, DeviceInfo->BufferSize);
282 if (!Buffer)
283 {
284 /* no memory */
285 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
286 }
287
288 RtlMoveMemory(Buffer, DeviceInfo->Buffer, DeviceInfo->BufferSize);
289
290
291 Context = ExAllocatePool(NonPagedPool, sizeof(WRITE_CONTEXT));
292 if (!Context)
293 {
294 /* no memory */
295 return SetIrpIoStatus(Irp, STATUS_NO_MEMORY, 0);
296 }
297
298 /* setup completion context */
299 Context->Irp = Irp;
300 Context->Length = DeviceInfo->BufferSize;
301
302 /* setup stream context */
303 Packet = (PKSSTREAM_HEADER)ExAllocatePool(NonPagedPool, sizeof(KSSTREAM_HEADER));
304 Packet->Data = Buffer;
305 Packet->FrameExtent = DeviceInfo->BufferSize;
306 Packet->DataUsed = DeviceInfo->BufferSize;
307 Packet->Size = sizeof(KSSTREAM_HEADER);
308 Packet->PresentationTime.Numerator = 1;
309 Packet->PresentationTime.Denominator = 1;
310 ASSERT(FileObject->FsContext != NULL);
311
312
313 Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_WRITE_STREAM, (PVOID)Packet, sizeof(KSSTREAM_HEADER), NULL, 0, &BytesReturned);
314
315 DPRINT1("KsSynchronousIoControlDevice result %x\n", Status);
316
317 IoMarkIrpPending(Irp);
318 Irp->IoStatus.Information = DeviceInfo->BufferSize;
319 Irp->IoStatus.Status = Status;
320
321 ExFreePool(Buffer);
322
323 return Status;
324 }
325
326
327
328 NTSTATUS
329 NTAPI
330 WdmAudDeviceControl(
331 IN PDEVICE_OBJECT DeviceObject,
332 IN PIRP Irp)
333 {
334 PIO_STACK_LOCATION IoStack;
335 PWDMAUD_DEVICE_INFO DeviceInfo;
336 PWDMAUD_CLIENT ClientInfo;
337
338 IoStack = IoGetCurrentIrpStackLocation(Irp);
339
340 DPRINT1("WdmAudDeviceControl entered\n");
341 DbgBreakPoint();
342
343 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(WDMAUD_DEVICE_INFO))
344 {
345 /* invalid parameter */
346 DPRINT1("Input buffer too small size %u expected %u\n", IoStack->Parameters.DeviceIoControl.InputBufferLength, sizeof(WDMAUD_DEVICE_INFO));
347 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
348 }
349
350 DeviceInfo = (PWDMAUD_DEVICE_INFO)Irp->AssociatedIrp.SystemBuffer;
351
352 if (DeviceInfo->DeviceType < MIN_SOUND_DEVICE_TYPE || DeviceInfo->DeviceType > MAX_SOUND_DEVICE_TYPE)
353 {
354 /* invalid parameter */
355 DPRINT1("Error: device type not set\n");
356 return SetIrpIoStatus(Irp, STATUS_INVALID_PARAMETER, 0);
357 }
358
359 if (!IoStack->FileObject)
360 {
361 /* file object parameter */
362 DPRINT1("Error: file object is not attached\n");
363 return SetIrpIoStatus(Irp, STATUS_UNSUCCESSFUL, 0);
364 }
365 ClientInfo = (PWDMAUD_CLIENT)IoStack->FileObject->FsContext;
366
367 DPRINT1("WdmAudDeviceControl entered\n");
368
369 switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
370 {
371 case IOCTL_OPEN_WDMAUD:
372 return WdmAudControlOpen(DeviceObject, Irp, DeviceInfo, ClientInfo);
373 case IOCTL_GETNUMDEVS_TYPE:
374 return WdmAudControlDeviceType(DeviceObject, Irp, DeviceInfo, ClientInfo);
375 case IOCTL_SETDEVICE_STATE:
376 return WdmAudControlDeviceState(DeviceObject, Irp, DeviceInfo, ClientInfo);
377 case IOCTL_WRITEDATA:
378 return WdmAudControlWriteData(DeviceObject, Irp, DeviceInfo, ClientInfo);
379
380 case IOCTL_CLOSE_WDMAUD:
381 case IOCTL_GETDEVID:
382 case IOCTL_GETVOLUME:
383 case IOCTL_SETVOLUME:
384 case IOCTL_GETCAPABILITIES:
385 DPRINT1("Unhandeled %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
386 break;
387 }
388
389 return SetIrpIoStatus(Irp, STATUS_NOT_IMPLEMENTED, 0);
390 }