1 /*
2  *
3  * COPYRIGHT:           See COPYING in the top level directory
4  * PROJECT:             ReactOS Sound System
5  * FILE:                drivers/multimedia/audio/sndblst/sndblst.c
6  * PURPOSE:             Sound Blaster / Pro / 16 driver
7  * PROGRAMMER:          Andrew Greenwood (silverblade@reactos.org)
8  *
9  * UPDATE HISTORY:      Feb 25, 2009: New rewrite started
10  *
11  */
12 
13 /* DEFINES AND INCLUDES ******************************************************/
14 
15 #include <ntddk.h>
16 #include <windef.h>
17 #include <mmsystem.h>
18 #include <debug.h>
19 
20 #define CompleteIrpAndReturn(irp, status) \
21     irp->IoStatus.Status = status; \
22     irp->IoStatus.Information = 0; \
23     IoCompleteRequest(Irp, IO_NO_INCREMENT); \
24     return status;
25 
26 
27 /* FORWARD DECLARATIONS *****************************************************/
28 
29 static VOID NTAPI
30 UnloadSoundBlaster(PDRIVER_OBJECT DriverObject);
31 
32 
33 /* DEVICE "DISCOVERY" *******************************************************/
34 /* Nb: These need to go in the helper lib */
35 
36 typedef NTSTATUS (*SOUNDDEVICEENUMERATIONCALLBACK)(
37     IN  PUNICODE_STRING DeviceRegistryPath);
38 
39 NTSTATUS
40 EnumerateSoundDevices(
41     IN  PUNICODE_STRING RegistryPath,
42     IN  PWSTR RegistrySubKey,
43     IN  SOUNDDEVICEENUMERATIONCALLBACK Callback)
44 {
45     NTSTATUS Status;
46     OBJECT_ATTRIBUTES RegAttributes;
47     HKEY MainKeyHandle, ChildKeyHandle;
48     UNICODE_STRING UnicodeSubkeyName, DeviceKeyName;
49     KEY_BASIC_INFORMATION KeyInfo, *FinalKeyInfo;
50     ULONG i = 0, NeededDataLength = 0, FinalDataLength = 0, NameLength = 0;
51 
52     /* Turn the subkey name into a Unicode string */
53     RtlInitUnicodeString(&UnicodeSubkeyName, RegistrySubKey);
54 
55     /* Open the registry key for the service */
56     InitializeObjectAttributes(&RegAttributes,
57                                RegistryPath,
58                                OBJ_CASE_INSENSITIVE,
59                                NULL,
60                                (PSECURITY_DESCRIPTOR) NULL);
61 
62     Status = ZwOpenKey(&MainKeyHandle, KEY_READ, &RegAttributes);
63 
64     if ( ! NT_SUCCESS(Status) )
65     {
66         DPRINT("Failed to open registry key\n");
67         return Status;
68     }
69 
70     /* Open the subkey usually named "Parameters" */
71     InitializeObjectAttributes(&RegAttributes,
72                                &UnicodeSubkeyName,
73                                OBJ_CASE_INSENSITIVE,
74                                MainKeyHandle,
75                                (PSECURITY_DESCRIPTOR) NULL);
76 
77     Status = ZwOpenKey(&ChildKeyHandle, KEY_ENUMERATE_SUB_KEYS, &RegAttributes);
78 
79     /* We're done with the main key now */
80     ZwClose(MainKeyHandle);
81 
82     if ( ! NT_SUCCESS(Status) )
83     {
84         DPRINT("Failed to open registry subkeys for enumeration\n");
85         return Status;
86     }
87 
88     /* Enumerate through the device keys */
89     while ( ( Status = ZwEnumerateKey(ChildKeyHandle,
90                                       i,
91                                       KeyBasicInformation,
92                                       &KeyInfo,
93                                       sizeof(KEY_BASIC_INFORMATION),
94                                       &NeededDataLength) ) != STATUS_NO_MORE_ENTRIES )
95     {
96         PWSTR EnumeratedKeyName, StartOfEnumeratedKeyName;
97 
98         DPRINT("Found subkey %d\n", i);
99 
100         FinalDataLength = NeededDataLength + FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
101         DPRINT("Allocating %d bytes\n", FinalDataLength);
102 
103         FinalKeyInfo = (PKEY_BASIC_INFORMATION) ExAllocatePool(PagedPool, FinalDataLength);
104 
105         if ( ! FinalKeyInfo )
106         {
107             Status = STATUS_INSUFFICIENT_RESOURCES;
108             break;
109         }
110 
111         /* This time we get the real info */
112         Status = ZwEnumerateKey(ChildKeyHandle,
113                                 i,
114                                 KeyBasicInformation,
115                                 FinalKeyInfo,
116                                 FinalDataLength,
117                                 &NeededDataLength);
118 
119         if ( ! NT_SUCCESS(Status) )
120         {
121             DPRINT("FAILED to enumerate key!\n");
122         }
123         else
124         {
125             NameLength = RegistryPath->Length + sizeof(WCHAR) +
126                          UnicodeSubkeyName.Length + sizeof(WCHAR) +
127                          FinalKeyInfo->NameLength + sizeof(UNICODE_NULL);
128 
129             DPRINT("Allocating memory for name (%d bytes)\n", NameLength);
130 
131             EnumeratedKeyName = (PWSTR) ExAllocatePool(PagedPool, NameLength);
132 
133             if ( ! EnumeratedKeyName )
134             {
135                 ExFreePool((PVOID)FinalKeyInfo);
136                 Status = STATUS_INSUFFICIENT_RESOURCES;
137                 break;
138             }
139 
140             StartOfEnumeratedKeyName = EnumeratedKeyName;
141 
142             /* Start building the registry path using the service key */
143             RtlCopyMemory(EnumeratedKeyName,
144                           RegistryPath->Buffer,
145                           RegistryPath->Length);
146 
147             EnumeratedKeyName += RegistryPath->Length / sizeof(WCHAR);
148             EnumeratedKeyName[0] = '\\';
149             ++ EnumeratedKeyName;
150 
151             /* Append the parameters subkey */
152             RtlCopyMemory(EnumeratedKeyName,
153                           RegistrySubKey,
154                           UnicodeSubkeyName.Length);
155 
156             EnumeratedKeyName += UnicodeSubkeyName.Length / sizeof(WCHAR);
157             EnumeratedKeyName[0] = '\\';
158             ++ EnumeratedKeyName;
159 
160             /* And finally append the enumerated key name */
161             RtlCopyMemory(EnumeratedKeyName,
162                           FinalKeyInfo->Name,
163                           FinalKeyInfo->NameLength);
164 
165             EnumeratedKeyName += FinalKeyInfo->NameLength / sizeof(WCHAR);
166             EnumeratedKeyName[0] = UNICODE_NULL;
167 
168             /* Reset pointer */
169             EnumeratedKeyName = StartOfEnumeratedKeyName;
170 
171             /* Convert into a Unicode string for the callback */
172             RtlInitUnicodeString(&DeviceKeyName, EnumeratedKeyName);
173 
174             Callback(&DeviceKeyName);
175 
176             /* No longer need the key name */
177             ExFreePool((PVOID)EnumeratedKeyName);
178             EnumeratedKeyName = NULL;
179         }
180 
181         /* No longer need the key info */
182         ExFreePool((PVOID)FinalKeyInfo);
183         FinalKeyInfo = NULL;
184 
185         ++ i;
186     }
187 
188     /* We're done with enumeration so close this */
189     ZwClose(ChildKeyHandle);
190 
191     /* This isn't an error */
192     if ( Status == STATUS_NO_MORE_ENTRIES )
193     {
194         Status = STATUS_SUCCESS;
195     }
196 
197     /* No devices configured? */
198     if ( i == 0 && Status == STATUS_NO_MORE_ENTRIES )
199     {
200         Status = STATUS_DEVICE_CONFIGURATION_ERROR;
201     }
202 
203     return Status;
204 }
205 
206 NTSTATUS
207 PublishWaveOutDevice(
208     IN  DWORD HardwareDeviceIndex,
209     IN  PWSTR BaseDeviceName,
210     IN  DWORD DeviceIndex,
211     IN  LPWAVEOUTCAPS Capabilities)
212 {
213     return STATUS_SUCCESS;
214 }
215 
216 
217 typedef struct _SOUND_BLASTER_DEVICE
218 {
219     DWORD   BasePort;
220     DWORD   MidiUartBasePort;
221 
222     DWORD   Irq;
223 
224     DWORD   DmaChannel_8;
225     DWORD   DmaChannel_16;
226 
227     DWORD   DspVersion;
228 
229     DWORD   ActualDmaBufferSize;
230     DWORD   DmaBufferSize;
231 } SOUND_BLASTER_DEVICE;
232 
233 
234 NTSTATUS
235 AllocateSoundBlasterStructure(OUT SOUND_BLASTER_DEVICE* SoundBlasterDevice)
236 {
237     return STATUS_NOT_IMPLEMENTED;
238 }
239 
240 /* callback */
241 /*
242     Configuration options within the registry:
243     REG_DWORD   Actual Dma Buffer Size      0x00004000
244     REG_DWORD   Configuration Error         0xffffffff
245     REG_DWORD   Dma Buffer Size             0x00004000
246     REG_DWORD   DmaChannel                  0x00000001
247     REG_DWORD   DmaChannel16                0x00000005
248     REG_DWORD   DSP Version                 0x00000405
249     REG_DWORD   Interrupt                   0x00000005
250     REG_DWORD   Load Type                   0x00000000
251     REG_BINARY  Mixer Settings              ??
252     REG_DWORD   MPU401 Port                 0xffffffff
253     REG_DWORD   Port                        0x00000220
254 */
255 
256 NTSTATUS
257 ConfigureSoundBlasterDevice(IN PUNICODE_STRING DeviceRegistryPath)
258 {
259     OBJECT_ATTRIBUTES RegAttributes;
260     NTSTATUS Status = STATUS_SUCCESS;
261     HKEY ConfigKeyHandle;
262 
263     DPRINT("Configuring Sound Blaster (config at %S)\n", DeviceRegistryPath->Buffer);
264 
265     if ( ! DeviceRegistryPath )
266     {
267         return STATUS_INVALID_PARAMETER;
268     }
269 
270     /* Open the registry key */
271     InitializeObjectAttributes(&RegAttributes,
272                                DeviceRegistryPath,
273                                OBJ_CASE_INSENSITIVE,
274                                NULL,
275                                (PSECURITY_DESCRIPTOR) NULL);
276 
277     Status = ZwOpenKey(&ConfigKeyHandle, KEY_READ, &RegAttributes);
278 
279     if ( ! NT_SUCCESS(Status) )
280     {
281         DPRINT("Failed to open config registry key\n");
282         return Status;
283     }
284 
285     /* Read configuration */
286     DPRINT("Reading configuration\n");
287 
288     //Status = ZwQueryValueKey(ConfigKeyHandle,
289 
290     return Status;
291 }
292 
293 
294 /* IRP DISPATCHERS **********************************************************/
295 
296 static NTSTATUS NTAPI
297 CreateSoundBlaster(
298     IN  PDEVICE_OBJECT DeviceObject,
299     IN  PIRP Irp)
300 {
301     DPRINT("Sound Blaster driver received IRP_MJ_CREATE\n");
302 
303     CompleteIrpAndReturn(Irp, STATUS_SUCCESS);
304 }
305 
306 static NTSTATUS NTAPI
307 CloseSoundBlaster(
308     IN  PDEVICE_OBJECT DeviceObject,
309     IN  PIRP Irp)
310 {
311     DPRINT("Sound Blaster driver received IRP_MJ_CLOSE\n");
312 
313     CompleteIrpAndReturn(Irp, STATUS_SUCCESS);
314 }
315 
316 static NTSTATUS NTAPI
317 CleanupSoundBlaster(
318     IN  PDEVICE_OBJECT DeviceObject,
319     IN  PIRP Irp)
320 {
321     DPRINT("Sound Blaster driver received IRP_MJ_CLEANUP\n");
322 
323     CompleteIrpAndReturn(Irp, STATUS_SUCCESS);
324 }
325 
326 static NTSTATUS NTAPI
327 ControlSoundBlaster(
328     IN  PDEVICE_OBJECT DeviceObject,
329     IN  PIRP Irp)
330 {
331     DPRINT("Sound Blaster driver received IRP_MJ_CONTROL\n");
332 
333     CompleteIrpAndReturn(Irp, STATUS_SUCCESS);
334 }
335 
336 static NTSTATUS NTAPI
337 WriteToSoundBlaster(
338     IN  PDEVICE_OBJECT DeviceObject,
339     IN  PIRP Irp)
340 {
341     DPRINT("Sound Blaster driver received IRP_MJ_WRITE\n");
342 
343     CompleteIrpAndReturn(Irp, STATUS_SUCCESS);
344 }
345 
346 
347 /* DRIVER ENTRYPOINT ********************************************************/
348 
349 NTSTATUS NTAPI
350 DriverEntry(
351     IN  PDRIVER_OBJECT DriverObject,
352     IN  PUNICODE_STRING RegistryPath)
353 {
354     NTSTATUS Status = STATUS_SUCCESS;
355 
356     DPRINT("Sound Blaster driver by silverblade\n");
357 
358     DriverObject->Flags = 0;
359     DriverObject->MajorFunction[IRP_MJ_CREATE] = CreateSoundBlaster;
360     DriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseSoundBlaster;
361     DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CleanupSoundBlaster;
362     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlSoundBlaster;
363     DriverObject->MajorFunction[IRP_MJ_WRITE] = WriteToSoundBlaster;
364     DriverObject->DriverUnload = UnloadSoundBlaster;
365 
366     EnumerateSoundDevices(RegistryPath, L"Parameters", ConfigureSoundBlasterDevice);
367 
368     return Status;
369 }
370 
371 static VOID NTAPI
372 UnloadSoundBlaster(IN PDRIVER_OBJECT DriverObject)
373 {
374     DPRINT("Sound Blaster driver is being unloaded\n");
375 }
376