Sync with trunk head
[reactos.git] / drivers / multimedia / audio / sb16_nt4.old / main.c
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
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
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
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
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
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
117 UnloadSoundBlaster(
118 PDRIVER_OBJECT DriverObject)
119 {
120 DPRINT("Sound Blaster driver unload\n");
121 }
122
123 NTSTATUS NTAPI
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 subkey %wZ\n", Subkey);
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
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
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
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
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
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 }