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