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