1 /*
2     ReactOS
3     Sound Blaster driver
4 
5     Programmers:
6         Andrew Greenwood
7 
8     Notes:
9         Compatible with NT4
10 */
11 
12 #define NDEBUG
13 #include <sndblst.h>
14 
15 
16 /*
17     IRP DISPATCH ROUTINES
18 */
19 
20 NTSTATUS NTAPI
CreateSoundBlaster(PDEVICE_OBJECT DeviceObject,PIRP Irp)21 CreateSoundBlaster(
22     PDEVICE_OBJECT DeviceObject,
23     PIRP Irp)
24 {
25     PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension;
26 
27     DPRINT("CreateSoundBlaster() called - extension 0x%x\n", sb_device);
28 
29     EnableSpeaker(sb_device);
30     /*SetOutputSampleRate(sb_device, 22*/
31 
32     Irp->IoStatus.Status = STATUS_SUCCESS;
33     Irp->IoStatus.Information = 0;
34 
35     IoCompleteRequest(Irp, IO_NO_INCREMENT);
36 
37     return STATUS_SUCCESS;
38 }
39 
40 NTSTATUS NTAPI
CloseSoundBlaster(PDEVICE_OBJECT DeviceObject,PIRP Irp)41 CloseSoundBlaster(
42     PDEVICE_OBJECT DeviceObject,
43     PIRP Irp)
44 {
45     //PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension;
46 
47     DPRINT("CloseSoundBlaster() called\n");
48 
49     Irp->IoStatus.Status = STATUS_SUCCESS;
50     Irp->IoStatus.Information = 0;
51 
52     IoCompleteRequest(Irp, IO_NO_INCREMENT);
53 
54     return STATUS_SUCCESS;
55 }
56 
57 NTSTATUS NTAPI
CleanupSoundBlaster(PDEVICE_OBJECT DeviceObject,PIRP Irp)58 CleanupSoundBlaster(
59     PDEVICE_OBJECT DeviceObject,
60     PIRP Irp)
61 {
62     //PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension;
63 
64     DPRINT("CleanupSoundBlaster() called\n");
65 
66     Irp->IoStatus.Status = STATUS_SUCCESS;
67     Irp->IoStatus.Information = 0;
68 
69     IoCompleteRequest(Irp, IO_NO_INCREMENT);
70 
71     return STATUS_SUCCESS;
72 }
73 
74 NTSTATUS NTAPI
ControlSoundBlaster(PDEVICE_OBJECT DeviceObject,PIRP Irp)75 ControlSoundBlaster(
76     PDEVICE_OBJECT DeviceObject,
77     PIRP Irp)
78 {
79     PIO_STACK_LOCATION stack;
80     //PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension;
81 
82     DPRINT("ControlSoundBlaster() called\n");
83 
84     stack = IoGetCurrentIrpStackLocation(Irp);
85 
86     switch ( stack->Parameters.DeviceIoControl.IoControlCode)
87     {
88         /* TODO */
89     };
90 
91     Irp->IoStatus.Status = STATUS_SUCCESS;
92     Irp->IoStatus.Information = 0;
93 
94     IoCompleteRequest(Irp, IO_NO_INCREMENT);
95 
96     return STATUS_SUCCESS;
97 }
98 
99 NTSTATUS NTAPI
WriteSoundBlaster(PDEVICE_OBJECT DeviceObject,PIRP Irp)100 WriteSoundBlaster(
101     PDEVICE_OBJECT DeviceObject,
102     PIRP Irp)
103 {
104     //PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension;
105 
106     DPRINT("WriteSoundBlaster() called\n");
107 
108     Irp->IoStatus.Status = STATUS_SUCCESS;
109     Irp->IoStatus.Information = 0;
110 
111     IoCompleteRequest(Irp, IO_NO_INCREMENT);
112 
113     return STATUS_SUCCESS;
114 }
115 
116 VOID NTAPI
UnloadSoundBlaster(PDRIVER_OBJECT DriverObject)117 UnloadSoundBlaster(
118     PDRIVER_OBJECT DriverObject)
119 {
120     DPRINT("Sound Blaster driver unload\n");
121 }
122 
123 NTSTATUS NTAPI
OpenSubkey(PUNICODE_STRING RegistryPath,PWSTR Subkey,ACCESS_MASK DesiredAccess,OUT HANDLE * DevicesKeyHandle)124 OpenSubkey(
125     PUNICODE_STRING RegistryPath,
126     PWSTR Subkey,
127     ACCESS_MASK DesiredAccess,
128     OUT HANDLE* DevicesKeyHandle)
129 {
130     NTSTATUS status;
131     OBJECT_ATTRIBUTES attribs;
132     UNICODE_STRING subkey_name;
133     HANDLE key_handle;
134 
135     /* TODO: Check for NULL ptr in DevicesKeyHandle */
136 
137     InitializeObjectAttributes(&attribs,
138                                RegistryPath,
139                                OBJ_CASE_INSENSITIVE,
140                                NULL,
141                                (PSECURITY_DESCRIPTOR) NULL);
142 
143     status = ZwOpenKey(&key_handle, KEY_READ, &attribs);
144 
145     if ( ! NT_SUCCESS(status) )
146     {
147         DPRINT("Couldn't open key %wZ\n", RegistryPath);
148         return status;
149     }
150 
151     RtlInitUnicodeString(&subkey_name, Subkey);
152 
153     InitializeObjectAttributes(&attribs,
154                                &subkey_name,
155                                OBJ_CASE_INSENSITIVE,
156                                key_handle,
157                                (PSECURITY_DESCRIPTOR) NULL);
158 
159     status = ZwOpenKey(*DevicesKeyHandle, DesiredAccess, &attribs);
160     ZwClose(key_handle);
161 
162     return status;
163 }
164 
165 
166 PWSTR NTAPI
AllocateRegistryPathInfo(PUNICODE_STRING BasePath,PUNICODE_STRING ParametersPath,PKEY_BASIC_INFORMATION KeyInfo)167 AllocateRegistryPathInfo(
168     PUNICODE_STRING BasePath,
169     PUNICODE_STRING ParametersPath,
170     PKEY_BASIC_INFORMATION KeyInfo)
171 {
172     PWSTR name;
173     PWSTR pos;
174 
175     DPRINT("Allocating memory for path info\n");
176     name = ExAllocatePool(PagedPool,
177                           BasePath->Length + sizeof(WCHAR) +
178                           ParametersPath->Length + sizeof(WCHAR) +
179                           KeyInfo->NameLength + sizeof(UNICODE_NULL));
180 
181     if ( ! name )
182         return NULL;
183 
184     DPRINT("Copying info\n");
185     pos = name;
186 
187     RtlCopyMemory((PVOID)Pos, (PVOID)BasePath->Buffer, BasePath->Length);
188     pos += BasePath->Length / sizeof(WCHAR);
189     pos[0] = '\\';
190     pos ++;
191 
192     RtlCopyMemory((PVOID)Pos, (PVOID)ParametersPath->Buffer, ParametersPath->Length);
193     pos += ParametersPath->Length / sizeof(WCHAR);
194     pos[0] = '\\';
195     pos ++;
196 
197     RtlCopyMemory((PVOID)Pos, (PVOID)ParametersPath->Buffer, ParametersPath->Length);
198     pos += KeyInfo->NameLength / sizeof(WCHAR);
199     pos[0] = UNICODE_NULL;
200 
201     DPRINT("All OK\n");
202     return name;
203 }
204 
205 #define FreeRegistryPathInfo(ptr) \
206     ExFreePool(ptr)
207 
208 
209 #define TAG_REG_INFO 'RegI'
210 #define TAG_REG_NAME 'RegN'
211 
212 NTSTATUS NTAPI
EnumerateSubkey(PUNICODE_STRING RegistryPath,PWSTR Subkey,PREGISTRY_CALLBACK_ROUTINE Callback,PDRIVER_OBJECT DriverObject)213 EnumerateSubkey(
214     PUNICODE_STRING RegistryPath,
215     PWSTR Subkey,
216     PREGISTRY_CALLBACK_ROUTINE Callback,
217     PDRIVER_OBJECT DriverObject)
218 {
219     NTSTATUS status;
220     UNICODE_STRING subkey_name;
221     HANDLE devices_key_handle;
222 
223     ULONG key_index = 0;
224     ULONG result_length;
225 
226     status = OpenSubkey(RegistryPath, Subkey, KEY_ENUMERATE_SUB_KEYS, &devices_key_handle);
227 
228     if ( ! NT_SUCCESS(status) )
229         return status;
230 
231     while ( TRUE )
232     {
233         KEY_BASIC_INFORMATION test_info;
234         PKEY_BASIC_INFORMATION info;
235         ULONG size;
236         PWSTR name;
237 
238         status = ZwEnumerateKey(devices_key_handle,
239                                 key_index,
240                                 KeyBasicInformation,
241                                 &test_info,
242                                 sizeof(test_info),
243                                 &result_length);
244 
245         if ( status == STATUS_NO_MORE_ENTRIES )
246             break;
247 
248         size = result_length + FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
249 
250         info = (PKEY_BASIC_INFORMATION) ExAllocatePoolWithTag(PagedPool, size, TAG_REG_INFO);
251 
252         if ( ! info )
253         {
254             DPRINT("Out of memory\n");
255             status = STATUS_INSUFFICIENT_RESOURCES;
256             break;
257         }
258 
259         status = ZwEnumerateKey(devices_key_handle,
260                                 key_index,
261                                 KeyBasicInformation,
262                                 info,
263                                 size,
264                                 &result_length);
265 
266         if ( ! NT_SUCCESS(status) )
267         {
268             DPRINT("Unable to enumerate keys\n");
269             ExFreePoolWithTag(info, TAG_REG_INFO);
270             status = STATUS_INTERNAL_ERROR;
271             break;
272         }
273 
274         /* Is this ok? */
275         RtlInitUnicodeString(&subkey_name, Subkey);
276 
277         name = AllocateRegistryPathInfo(RegistryPath, &subkey_name, info);
278 
279         if ( ! name )
280         {
281             DPRINT("Out of memory\n");
282             ExFreePoolWithTag(info, TAG_REG_INFO);
283             status = STATUS_INSUFFICIENT_RESOURCES;
284             break;
285         }
286 
287         ExFreePoolWithTag(info, TAG_REG_INFO);
288 
289         /* Call the callback */
290         status = Callback(DriverObject, name);
291 
292         FreeRegistryPathInfo(name);
293 
294         if ( ! NT_SUCCESS(status) )
295         {
296             DPRINT("Callback FAILED\n");
297             break;
298         }
299 
300         key_index ++;
301     }
302 
303     ZwClose(devices_key_handle);
304 
305     DPRINT("Found %d subkey entries\n", key_index);
306 
307     if ( ( key_index == 0 ) && ( status == STATUS_NO_MORE_ENTRIES ) )
308         return STATUS_DEVICE_CONFIGURATION_ERROR;
309 
310     if ( status == STATUS_NO_MORE_ENTRIES )
311         status = STATUS_SUCCESS;
312 
313     return status;
314 }
315 
316 #define EnumerateDeviceKeys(path, callback, driver_obj) \
317     EnumerateSubkey(path, L"Devices", callback, driver_obj)
318 
319 
320 NTSTATUS
CreateDeviceName(PCWSTR PrePrefix,PCWSTR Prefix,UCHAR Index,PUNICODE_STRING DeviceName)321 CreateDeviceName(
322     PCWSTR PrePrefix,
323     PCWSTR Prefix,
324     UCHAR Index,
325     PUNICODE_STRING DeviceName)
326 {
327     UNICODE_STRING number;
328     WCHAR number_buffer[5];
329     UNICODE_STRING unicode_pre_prefix;
330     UNICODE_STRING unicode_prefix;
331     ULONG size;
332 
333     RtlInitUnicodeString(&unicode_pre_prefix, PrePrefix);
334     RtlInitUnicodeString(&unicode_prefix, Prefix);
335 
336     size = unicode_pre_prefix.Length +
337            unicode_prefix.Length +
338            sizeof(number_buffer) +
339            sizeof(UNICODE_NULL);
340 
341     DeviceName->Buffer = ExAllocatePool(PagedPool, size);
342     DeviceName->MaximumLength = (USHORT) size;
343 
344     if ( ! DeviceName->Buffer )
345         return STATUS_INSUFFICIENT_RESOURCES;
346 
347     RtlCopyUnicodeString(DeviceName, &unicode_pre_prefix);
348     RtlAppendUnicodeStringToString(DeviceName, &unicode_prefix);
349 
350     if ( Index != 255 )
351     {
352         number.Buffer = number_buffer;
353         number.MaximumLength = sizeof(number_buffer);
354 
355         RtlIntegerToUnicodeString((ULONG) Index, 10, &number);
356         RtlAppendUnicodeStringToString(DeviceName, &number);
357     }
358 
359     DeviceName->Buffer[DeviceName->Length / sizeof(UNICODE_NULL)] = UNICODE_NULL;
360 
361     return STATUS_SUCCESS;
362 }
363 
364 NTSTATUS NTAPI
InitializeSoundBlaster(PDRIVER_OBJECT DriverObject,PWSTR RegistryPath)365 InitializeSoundBlaster(
366     PDRIVER_OBJECT DriverObject,
367     PWSTR RegistryPath)
368 {
369     NTSTATUS status;
370     PDEVICE_OBJECT device_object;
371     PSOUND_BLASTER_PARAMETERS parameters = NULL;
372     UNICODE_STRING device_name;
373     UNICODE_STRING dos_device_name;
374 
375     UCHAR device_index = 0;
376 
377     DPRINT("Initializing a Sound Blaster device\n");
378 
379     /* Change these later */
380     status = CreateDeviceName(L"",
381                               L"\\Device\\WaveOut",
382                               device_index,
383                               &device_name);
384 
385     if ( ! NT_SUCCESS(status) )
386         return status;
387 
388     status = CreateDeviceName(L"\\DosDevices\\",
389                               L"\\Device\\WaveOut" + wcslen(L"\\Device\\"),
390                               device_index,
391                               &dos_device_name);
392 
393     if ( ! NT_SUCCESS(status) )
394     {
395         /* TODO */
396         return status;
397     }
398 
399     DPRINT("Device: %wZ\n", &device_name);
400     DPRINT("Symlink: %wZ\n", &dos_device_name);
401 
402     /*
403         Create the device and DOS symlink
404     */
405 
406     status = IoCreateDevice(DriverObject,
407                             sizeof(SOUND_BLASTER_PARAMETERS),
408                             &device_name,
409                             FILE_DEVICE_SOUND,
410                             0,
411                             FALSE,
412                             &device_object);
413 
414     if ( ! NT_SUCCESS(status) )
415         return status;
416 
417     DPRINT("Created a device extension at 0x%x\n", device_object->DeviceExtension);
418     parameters = device_object->DeviceExtension;
419 
420     status = IoCreateSymbolicLink(&dos_device_name, &device_name);
421 
422     ExFreePool(dos_device_name.Buffer);
423     ExFreePool(device_name.Buffer);
424 
425     if ( ! NT_SUCCESS(status) )
426     {
427         IoDeleteDevice(device_object);
428         device_object = NULL;
429         return status;
430     }
431 
432     /* IoRegisterShutdownNotification( */
433 
434     /*
435         Settings
436     */
437 
438     device_object->AlignmentRequirement = FILE_BYTE_ALIGNMENT;
439 
440     parameters->driver = DriverObject;
441     parameters->registry_path = RegistryPath;
442     parameters->port = DEFAULT_PORT;
443     parameters->irq = DEFAULT_IRQ;
444     parameters->dma = DEFAULT_DMA;
445     parameters->buffer_size = DEFAULT_BUFFER_SIZE;
446 
447     /* TODO: Load the settings from the registry */
448 
449     DPRINT("Port %x IRQ %d DMA %d\n", parameters->port, parameters->irq, parameters->dma);
450 
451     DPRINT("Resetting the sound card\n");
452 
453     if ( ! ResetSoundBlaster(parameters) )
454     {
455         /* TODO */
456         return STATUS_UNSUCCESSFUL;
457     }
458 
459     /*
460     DPRINT("What kind of SB card is this?\n");
461     GetSoundBlasterModel(parameters);
462     */
463 
464     return STATUS_SUCCESS;
465 }
466 
467 
468 NTSTATUS NTAPI
DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)469 DriverEntry(
470     PDRIVER_OBJECT DriverObject,
471     PUNICODE_STRING RegistryPath)
472 {
473     NTSTATUS status;
474 
475     DPRINT("Sound Blaster driver 0.1 by Silver Blade\n");
476 
477     DriverObject->Flags = 0;
478     DriverObject->MajorFunction[IRP_MJ_CREATE] = CreateSoundBlaster;
479     DriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseSoundBlaster;
480     DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CleanupSoundBlaster;
481     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlSoundBlaster;
482     DriverObject->MajorFunction[IRP_MJ_WRITE] = WriteSoundBlaster;
483     DriverObject->DriverUnload = UnloadSoundBlaster;
484 
485     DPRINT("Beginning device key enumeration\n");
486 
487     status = EnumerateDeviceKeys(RegistryPath, *InitializeSoundBlaster, DriverObject);
488 
489     return status;
490 }
491