create sound folder
[reactos.git] / reactos / drivers / base / sndblst / sndblst.c
1 /*
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/dd/sndblst/sndblst.c
6 * PURPOSE: Sound Blaster / SB Pro / SB 16 driver
7 * PROGRAMMER: Andrew Greenwood
8 * UPDATE HISTORY:
9 * Sept 28, 2003: Copied from mpu401.c as a template
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ntddk.h>
15 #include "sndblst.h"
16
17 NTSTATUS STDCALL
18 DriverEntry(PDRIVER_OBJECT DriverObject,
19 PUNICODE_STRING RegistryPath);
20
21 /* INTERNAL VARIABLES ******************************************************/
22
23 ULONG DeviceCount = 0;
24
25
26 /* FUNCTIONS ***************************************************************/
27
28 static NTSTATUS InitDevice(
29 IN PWSTR RegistryPath,
30 IN PVOID Context)
31 {
32 // PDEVICE_INSTANCE Instance = Context;
33 PDEVICE_OBJECT DeviceObject; // = Context;
34 PDEVICE_EXTENSION Parameters; // = DeviceObject->DeviceExtension;
35 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\WaveOut0"); // CHANGE THESE?
36 UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\WaveOut0");
37
38 // CONFIG Config;
39 RTL_QUERY_REGISTRY_TABLE Table[2];
40 NTSTATUS s;
41 USHORT DSP_Version = 0;
42 UCHAR DSP_Major = 0, DSP_Minor = 0;
43
44 // This is TEMPORARY, to ensure that we don't process more than 1 device.
45 // This limitation should be removed in future.
46 if (DeviceCount > 0)
47 {
48 DPRINT("Sorry - only 1 device supported by Sound Blaster driver at present :(\n");
49 return STATUS_NOT_IMPLEMENTED;
50 }
51
52 DPRINT("Creating IO device\n");
53
54 s = IoCreateDevice(Context, // driverobject
55 sizeof(DEVICE_EXTENSION),
56 &DeviceName,
57 FILE_DEVICE_SOUND, // Correct?
58 0,
59 FALSE,
60 &DeviceObject);
61
62 if (!NT_SUCCESS(s))
63 return s;
64
65 DPRINT("Device Extension at 0x%x\n", DeviceObject->DeviceExtension);
66 Parameters = DeviceObject->DeviceExtension;
67
68 DPRINT("Creating DOS link\n");
69
70 /* Create the dos device link */
71 IoCreateSymbolicLink(&SymlinkName,
72 &DeviceName);
73
74 DPRINT("Initializing device\n");
75
76 // DPRINT("Allocating memory for parameters structure\n");
77 // Bodged:
78 // Parameters = (PDEVICE_EXTENSION)ExAllocatePool(NonPagedPool, sizeof(DEVICE_EXTENSION));
79 // DeviceObject->DeviceExtension = Parameters;
80 // Parameters = Instance->DriverObject->DriverExtension;
81
82 DPRINT("DeviceObject at 0x%x, DeviceExtension at 0x%x\n", DeviceObject, Parameters);
83
84 if (! Parameters)
85 {
86 DPRINT("NULL POINTER!\n");
87 return STATUS_INSUFFICIENT_RESOURCES;
88 }
89
90 // Instance->DriverObject->DriverExtension = Parameters;
91
92 DPRINT("Setting reg path\n");
93 Parameters->RegistryPath = RegistryPath;
94 // Parameters->DriverObject = Instance->DriverObject;
95
96 DPRINT("Zeroing table memory and setting query routine\n");
97 RtlZeroMemory(Table, sizeof(Table));
98 Table[0].QueryRoutine = LoadSettings;
99
100 DPRINT("Setting port and IRQ defaults\n");
101 Parameters->Port = DEFAULT_PORT;
102 Parameters->IRQ = DEFAULT_IRQ;
103 Parameters->DMA = DEFAULT_DMA;
104 Parameters->BufferSize = DEFAULT_BUFSIZE;
105
106 // Only to be enabled once we can get support for multiple cards working :)
107 /*
108 DPRINT("Loading settings from: %S\n", RegistryPath);
109
110 s = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, RegistryPath, Table,
111 &Parameters, NULL);
112
113 if (! NT_SUCCESS(s))
114 return s;
115 */
116
117 DPRINT("Port 0x%x IRQ %d DMA %d\n", Parameters->Port, Parameters->IRQ, Parameters->DMA);
118
119 // Instance->P
120
121 // Initialize the card
122 DSP_Version = InitSoundCard(Parameters->Port);
123 if (! DSP_Version)
124 {
125 DPRINT("Sound card initialization FAILED!\n");
126 // Set state indication somehow
127 // Failure - what error code do we give?!
128 // return STATUS_????
129 return STATUS_UNSUCCESSFUL;
130 }
131
132 DSP_Major = DSP_Version / 256;
133 DSP_Minor = DSP_Version % 256;
134
135 // Do stuff related to version here...
136
137 DPRINT("Allocating DMA\n");
138 if (! CreateDMA(DeviceObject))
139 DPRINT("FAILURE!\n");
140
141 // TEMPORARY TESTING STUFF: should be in BlasterCreate
142 EnableSpeaker(Parameters->Port, TRUE);
143 SetOutputSampleRate(Parameters->Port, 2205);
144 BeginPlayback(Parameters->Port, 16, 2, Parameters->BufferSize);
145
146 DeviceCount ++;
147
148 return STATUS_SUCCESS;
149 }
150
151
152 static NTSTATUS STDCALL
153 BlasterCreate(PDEVICE_OBJECT DeviceObject,
154 PIRP Irp)
155 /*
156 * FUNCTION: Handles user mode requests
157 * ARGUMENTS:
158 * DeviceObject = Device for request
159 * Irp = I/O request packet describing request
160 * RETURNS: Success or failure
161 */
162 {
163 DPRINT("BlasterCreate() called!\n");
164
165 // Initialize the MPU-401
166 // ... do stuff ...
167
168
169 // Play a note to say we're alive:
170 // WaitToSend(MPU401_PORT);
171 // MPU401_WRITE_DATA(MPU401_PORT, 0x90);
172 // WaitToSend(MPU401_PORT);
173 // MPU401_WRITE_DATA(MPU401_PORT, 0x50);
174 // WaitToSend(MPU401_PORT);
175 // MPU401_WRITE_DATA(MPU401_PORT, 0x7f);
176
177 Irp->IoStatus.Status = STATUS_SUCCESS;
178 Irp->IoStatus.Information = 0;
179
180 DPRINT("IoCompleteRequest()\n");
181
182 IoCompleteRequest(Irp,
183 IO_NO_INCREMENT);
184
185 DPRINT("BlasterCreate() completed\n");
186
187 return(STATUS_SUCCESS);
188 }
189
190
191 static NTSTATUS STDCALL
192 BlasterClose(PDEVICE_OBJECT DeviceObject,
193 PIRP Irp)
194 /*
195 * FUNCTION: Handles user mode requests
196 * ARGUMENTS:
197 * DeviceObject = Device for request
198 * Irp = I/O request packet describing request
199 * RETURNS: Success or failure
200 */
201 {
202 PDEVICE_EXTENSION DeviceExtension;
203 NTSTATUS Status;
204
205 DPRINT("BlasterClose() called!\n");
206
207 DeviceExtension = DeviceObject->DeviceExtension;
208
209 Status = STATUS_SUCCESS;
210
211 Irp->IoStatus.Status = Status;
212 Irp->IoStatus.Information = 0;
213 IoCompleteRequest(Irp,
214 IO_NO_INCREMENT);
215
216 return(Status);
217 }
218
219
220 static NTSTATUS STDCALL
221 BlasterCleanup(PDEVICE_OBJECT DeviceObject,
222 PIRP Irp)
223 /*
224 * FUNCTION: Handles user mode requests
225 * ARGUMENTS:
226 * DeviceObject = Device for request
227 * Irp = I/O request packet describing request
228 * RETURNS: Success or failure
229 */
230 {
231 ULONG Channel;
232 DPRINT("BlasterCleanup() called!\n");
233
234 // Reset the device (should we do this?)
235 for (Channel = 0; Channel <= 15; Channel ++)
236 {
237 // All notes off
238 // MPU401_WRITE_MESSAGE(MPU401_PORT, 0xb0 + Channel, 123, 0);
239 // All controllers off
240 // MPU401_WRITE_MESSAGE(MPU401_PORT, 0xb0 + Channel, 121, 0);
241 }
242
243
244 Irp->IoStatus.Status = STATUS_SUCCESS;
245 Irp->IoStatus.Information = 0;
246 IoCompleteRequest(Irp,
247 IO_NO_INCREMENT);
248
249 return(STATUS_SUCCESS);
250 }
251
252
253 static NTSTATUS STDCALL
254 BlasterWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
255 {
256 PIO_STACK_LOCATION Stack;
257 PDEVICE_EXTENSION DeviceExtension;
258 ULONG ByteCount;
259 PUCHAR Data;
260
261 DPRINT("BlasterWrite() called!\n");
262
263 DeviceExtension = DeviceObject->DeviceExtension;
264 Stack = IoGetCurrentIrpStackLocation(Irp);
265
266 DPRINT("%d bytes\n", Stack->Parameters.Write.Length);
267
268 Data = (PUCHAR) Irp->AssociatedIrp.SystemBuffer;
269
270 for (ByteCount = 0; ByteCount < Stack->Parameters.Write.Length; ByteCount ++)
271 {
272 // DPRINT("0x%x ", Data[ByteCount]);
273
274 // MPU401_WRITE_BYTE(DeviceExtension->Port, Data[ByteCount]);
275 }
276
277 Irp->IoStatus.Status = STATUS_SUCCESS;
278 Irp->IoStatus.Information = 0;
279 IoCompleteRequest(Irp,
280 IO_NO_INCREMENT);
281
282 return(STATUS_SUCCESS);
283 }
284
285
286 static NTSTATUS STDCALL
287 BlasterDeviceControl(PDEVICE_OBJECT DeviceObject,
288 PIRP Irp)
289 /*
290 * FUNCTION: Handles user mode requests
291 * ARGUMENTS:
292 * DeviceObject = Device for request
293 * Irp = I/O request packet describing request
294 * RETURNS: Success or failure
295 */
296 {
297 PIO_STACK_LOCATION Stack;
298 PDEVICE_EXTENSION DeviceExtension;
299
300 DPRINT("BlasterDeviceControl() called!\n");
301
302 DeviceExtension = DeviceObject->DeviceExtension;
303 Stack = IoGetCurrentIrpStackLocation(Irp);
304
305 switch(Stack->Parameters.DeviceIoControl.IoControlCode)
306 {
307 /* case IOCTL_MIDI_PLAY :
308 {
309 DPRINT("Received IOCTL_MIDI_PLAY\n");
310 Data = (PUCHAR) Irp->AssociatedIrp.SystemBuffer;
311
312 DPRINT("Sending %d bytes of MIDI data to 0x%d:\n", Stack->Parameters.DeviceIoControl.InputBufferLength, DeviceExtension->Port);
313
314 for (ByteCount = 0; ByteCount < Stack->Parameters.DeviceIoControl.InputBufferLength; ByteCount ++)
315 {
316 DPRINT("0x%x ", Data[ByteCount]);
317
318 MPU401_WRITE_BYTE(DeviceExtension->Port, Data[ByteCount]);
319 // if (WaitToSend(MPU401_PORT))
320 // MPU401_WRITE_DATA(MPU401_PORT, Data[ByteCount]);
321 }
322
323 Irp->IoStatus.Status = STATUS_SUCCESS;
324 IoCompleteRequest(Irp, IO_NO_INCREMENT);
325
326 return(STATUS_SUCCESS);
327 }
328 */
329 }
330
331 return(STATUS_SUCCESS);
332
333 /*
334 DeviceExtension = DeviceObject->DeviceExtension;
335 Stack = IoGetCurrentIrpStackLocation(Irp);
336 BeepParam = (PBEEP_SET_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
337
338 Irp->IoStatus.Information = 0;
339
340 if (Stack->Parameters.DeviceIoControl.IoControlCode != IOCTL_BEEP_SET)
341 {
342 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
343 IoCompleteRequest(Irp,
344 IO_NO_INCREMENT);
345 return(STATUS_NOT_IMPLEMENTED);
346 }
347
348 if ((Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(BEEP_SET_PARAMETERS))
349 || (BeepParam->Frequency < BEEP_FREQUENCY_MINIMUM)
350 || (BeepParam->Frequency > BEEP_FREQUENCY_MAXIMUM))
351 {
352 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
353 IoCompleteRequest(Irp,
354 IO_NO_INCREMENT);
355 return(STATUS_INVALID_PARAMETER);
356 }
357
358 DueTime.QuadPart = 0;
359 */
360 /* do the beep!! */
361 /* DPRINT("Beep:\n Freq: %lu Hz\n Dur: %lu ms\n",
362 pbsp->Frequency,
363 pbsp->Duration);
364
365 if (BeepParam->Duration >= 0)
366 {
367 DueTime.QuadPart = (LONGLONG)BeepParam->Duration * -10000;
368
369 KeSetTimer(&DeviceExtension->Timer,
370 DueTime,
371 &DeviceExtension->Dpc);
372
373 HalMakeBeep(BeepParam->Frequency);
374 DeviceExtension->BeepOn = TRUE;
375 KeWaitForSingleObject(&DeviceExtension->Event,
376 Executive,
377 KernelMode,
378 FALSE,
379 NULL);
380 }
381 else if (BeepParam->Duration == (DWORD)-1)
382 {
383 if (DeviceExtension->BeepOn == TRUE)
384 {
385 HalMakeBeep(0);
386 DeviceExtension->BeepOn = FALSE;
387 }
388 else
389 {
390 HalMakeBeep(BeepParam->Frequency);
391 DeviceExtension->BeepOn = TRUE;
392 }
393 }
394
395 DPRINT("Did the beep!\n");
396
397 Irp->IoStatus.Status = STATUS_SUCCESS;
398 IoCompleteRequest(Irp,
399 IO_NO_INCREMENT);
400 return(STATUS_SUCCESS);
401 */
402 }
403
404
405 static VOID STDCALL
406 BlasterUnload(PDRIVER_OBJECT DriverObject)
407 {
408 DPRINT("BlasterUnload() called!\n");
409 }
410
411
412 NTSTATUS STDCALL
413 DriverEntry(PDRIVER_OBJECT DriverObject,
414 PUNICODE_STRING RegistryPath)
415 /*
416 * FUNCTION: Called by the system to initalize the driver
417 * ARGUMENTS:
418 * DriverObject = object describing this driver
419 * RegistryPath = path to our configuration entries
420 * RETURNS: Success or failure
421 */
422 {
423 // PDEVICE_EXTENSION DeviceExtension;
424 // PDEVICE_OBJECT DeviceObject;
425 // DEVICE_INSTANCE Instance;
426 // Doesn't support multiple instances (yet ...)
427 NTSTATUS Status;
428
429 DPRINT("Sound Blaster Device Driver 0.0.2\n");
430
431 // Instance.DriverObject = DriverObject;
432 // previous instance = NULL...
433
434 // DeviceExtension->RegistryPath = RegistryPath;
435
436 DriverObject->Flags = 0;
437 DriverObject->MajorFunction[IRP_MJ_CREATE] = BlasterCreate;
438 DriverObject->MajorFunction[IRP_MJ_CLOSE] = BlasterClose;
439 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = BlasterCleanup;
440 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = BlasterDeviceControl;
441 DriverObject->MajorFunction[IRP_MJ_WRITE] = BlasterWrite;
442 DriverObject->DriverUnload = BlasterUnload;
443
444 // Major hack to just get this damn thing working:
445 Status = InitDevice(RegistryPath->Buffer, DriverObject); // ????
446
447 // DPRINT("Enumerating devices at %wZ\n", RegistryPath);
448
449 // Status = EnumDeviceKeys(RegistryPath, PARMS_SUBKEY, InitDevice, (PVOID)&DeviceObject); // &Instance;
450
451 // check error
452
453 /* set up device extension */
454 // DeviceExtension = DeviceObject->DeviceExtension;
455 // DeviceExtension->BeepOn = FALSE;
456
457 // return(STATUS_SUCCESS);
458 return(Status);
459 }
460
461 /* EOF */