1 /*
2  *
3  * COPYRIGHT:            See COPYING in the top level directory
4  * PROJECT:              ReactOS kernel
5  * FILE:                 services/dd/mpu401/mpu401.c
6  * PURPOSE:              MPU-401 MIDI device driver
7  * PROGRAMMER:           Andrew Greenwood
8  * UPDATE HISTORY:
9  *                       Sept 26, 2003: Copied from beep.c as template
10  *                       Sept 27, 2003: Implemented MPU-401 init & playback
11  */
12 
13 /* INCLUDES ****************************************************************/
14 
15 #include <ntddk.h>
16 //#include <ntddbeep.h>
17 
18 //#define NDEBUG
19 #include <debug.h>
20 
21 #include "mpu401.h"
22 
23 
24 /* INTERNAL VARIABLES ******************************************************/
25 
26 ULONG DeviceCount = 0;
27 
28 
29 /* FUNCTIONS ***************************************************************/
30 
31 static NTSTATUS InitDevice(
32     IN PUNICODE_STRING RegistryPath,
33     IN PVOID Context)
34 {
35 //    PDEVICE_INSTANCE Instance = Context;
36     PDEVICE_OBJECT DeviceObject; // = Context;
37     PDEVICE_EXTENSION Parameters; // = DeviceObject->DeviceExtension;
38     UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\MidiOut0");
39     UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\MidiOut0");
40 //    CONFIG Config;
41     RTL_QUERY_REGISTRY_TABLE Table[2];
42     NTSTATUS s;
43 
44     // This is TEMPORARY, to ensure that we don't process more than 1 device.
45     // I'll remove this limitation in the future.
46     if (DeviceCount > 0)
47     {
48         DPRINT("Sorry - only 1 device supported by MPU401 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 
104 // Only to be enabled once we can get support for multiple cards working :)
105 /*
106     DPRINT("Loading settings from: %S\n", RegistryPath);
107 
108     s = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, RegistryPath, Table,
109                                 &Parameters, NULL);
110 */
111 
112     if (! NT_SUCCESS(s))
113         return s;
114 
115     DPRINT("Port 0x%x  IRQ %d\n", Parameters->Port, Parameters->IRQ);
116 
117 //    Instance->P
118 
119     // Enter UART mode (should be done in init phase
120     if (! InitUARTMode(Parameters->Port))
121     {
122         DPRINT("UART mode initialization FAILED!\n");
123         // Set state indication somehow
124         // Failure - what error code do we give?!
125         // return STATUS_????
126     }
127 
128     DeviceCount ++;
129 
130     return STATUS_SUCCESS;
131 }
132 
133 
134 static NTSTATUS NTAPI
135 MPU401Create(PDEVICE_OBJECT DeviceObject,
136 	   PIRP Irp)
137 /*
138  * FUNCTION: Handles user mode requests
139  * ARGUMENTS:
140  *                       DeviceObject = Device for request
141  *                       Irp = I/O request packet describing request
142  * RETURNS: Success or failure
143  */
144 {
145     DPRINT("MPU401Create() called!\n");
146 
147     // Initialize the MPU-401?
148     // ... do stuff ...
149 
150 
151     // Play a note to say we're alive:
152     WaitToSend(MPU401_PORT);
153     MPU401_WRITE_DATA(MPU401_PORT, 0x90);
154     WaitToSend(MPU401_PORT);
155     MPU401_WRITE_DATA(MPU401_PORT, 0x50);
156     WaitToSend(MPU401_PORT);
157     MPU401_WRITE_DATA(MPU401_PORT, 0x7f);
158 
159     Irp->IoStatus.Status = STATUS_SUCCESS;
160     Irp->IoStatus.Information = 0;
161     IoCompleteRequest(Irp,
162 		    IO_NO_INCREMENT);
163 
164     return(STATUS_SUCCESS);
165 }
166 
167 
168 static NTSTATUS NTAPI
169 MPU401Close(PDEVICE_OBJECT DeviceObject,
170 	  PIRP Irp)
171 /*
172  * FUNCTION: Handles user mode requests
173  * ARGUMENTS:
174  *                       DeviceObject = Device for request
175  *                       Irp = I/O request packet describing request
176  * RETURNS: Success or failure
177  */
178 {
179   PDEVICE_EXTENSION DeviceExtension;
180   NTSTATUS Status;
181 
182   DPRINT("MPU401Close() called!\n");
183 
184   DeviceExtension = DeviceObject->DeviceExtension;
185 
186   Status = STATUS_SUCCESS;
187 
188   Irp->IoStatus.Status = Status;
189   Irp->IoStatus.Information = 0;
190   IoCompleteRequest(Irp,
191 		    IO_NO_INCREMENT);
192 
193   return(Status);
194 }
195 
196 
197 static NTSTATUS NTAPI
198 MPU401Cleanup(PDEVICE_OBJECT DeviceObject,
199 	    PIRP Irp)
200 /*
201  * FUNCTION: Handles user mode requests
202  * ARGUMENTS:
203  *                       DeviceObject = Device for request
204  *                       Irp = I/O request packet describing request
205  * RETURNS: Success or failure
206  */
207 {
208   ULONG Channel;
209   DPRINT("MPU401Cleanup() called!\n");
210 
211     // Reset the device (should we do this?)
212     for (Channel = 0; Channel <= 15; Channel ++)
213     {
214         // All notes off
215 //        MPU401_WRITE_MESSAGE(MPU401_PORT, 0xb0 + Channel, 123, 0);
216         // All controllers off
217 //        MPU401_WRITE_MESSAGE(MPU401_PORT, 0xb0 + Channel, 121, 0);
218     }
219 
220 
221   Irp->IoStatus.Status = STATUS_SUCCESS;
222   Irp->IoStatus.Information = 0;
223   IoCompleteRequest(Irp,
224 		    IO_NO_INCREMENT);
225 
226   return(STATUS_SUCCESS);
227 }
228 
229 
230 static NTSTATUS NTAPI
231 MPU401DeviceControl(PDEVICE_OBJECT DeviceObject,
232 		  PIRP Irp)
233 /*
234  * FUNCTION: Handles user mode requests
235  * ARGUMENTS:
236  *                       DeviceObject = Device for request
237  *                       Irp = I/O request packet describing request
238  * RETURNS: Success or failure
239  */
240 {
241     PIO_STACK_LOCATION Stack;
242     PDEVICE_EXTENSION DeviceExtension;
243     ULONG ByteCount;
244     PUCHAR Data;
245 
246     DPRINT("MPU401DeviceControl() called!\n");
247 
248     DeviceExtension = DeviceObject->DeviceExtension;
249     Stack = IoGetCurrentIrpStackLocation(Irp);
250 
251     DPRINT("Control code %d [0x%x]\n", Stack->Parameters.DeviceIoControl.IoControlCode,
252                 Stack->Parameters.DeviceIoControl.IoControlCode);
253 
254     switch(Stack->Parameters.DeviceIoControl.IoControlCode)
255     {
256         case IOCTL_MIDI_PLAY :
257         {
258             DPRINT("Received IOCTL_MIDI_PLAY\n");
259             Data = (PUCHAR) Irp->AssociatedIrp.SystemBuffer;
260 
261             DPRINT("Sending %d bytes of MIDI data to 0x%d:\n", Stack->Parameters.DeviceIoControl.InputBufferLength, DeviceExtension->Port);
262 
263             for (ByteCount = 0; ByteCount < Stack->Parameters.DeviceIoControl.InputBufferLength; ByteCount ++)
264             {
265                 DPRINT("0x%x ", Data[ByteCount]);
266 
267                 MPU401_WRITE_BYTE(DeviceExtension->Port, Data[ByteCount]);
268 //                if (WaitToSend(MPU401_PORT))
269 //                    MPU401_WRITE_DATA(MPU401_PORT, Data[ByteCount]);
270             }
271 
272             Irp->IoStatus.Status = STATUS_SUCCESS;
273             IoCompleteRequest(Irp, IO_NO_INCREMENT);
274 
275             return(STATUS_SUCCESS);
276         }
277     }
278 
279     return(STATUS_SUCCESS);
280 
281 /*
282   DeviceExtension = DeviceObject->DeviceExtension;
283   Stack = IoGetCurrentIrpStackLocation(Irp);
284   BeepParam = (PBEEP_SET_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
285 
286   Irp->IoStatus.Information = 0;
287 
288   if (Stack->Parameters.DeviceIoControl.IoControlCode != IOCTL_BEEP_SET)
289     {
290       Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
291       IoCompleteRequest(Irp,
292 			IO_NO_INCREMENT);
293       return(STATUS_NOT_IMPLEMENTED);
294     }
295 
296   if ((Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(BEEP_SET_PARAMETERS))
297       || (BeepParam->Frequency < BEEP_FREQUENCY_MINIMUM)
298       || (BeepParam->Frequency > BEEP_FREQUENCY_MAXIMUM))
299     {
300       Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
301       IoCompleteRequest(Irp,
302 			IO_NO_INCREMENT);
303       return(STATUS_INVALID_PARAMETER);
304     }
305 
306   DueTime.QuadPart = 0;
307 */
308   /* do the beep!! */
309 /*  DPRINT("Beep:\n  Freq: %lu Hz\n  Dur: %lu ms\n",
310 	 pbsp->Frequency,
311 	 pbsp->Duration);
312 
313   if (BeepParam->Duration >= 0)
314     {
315       DueTime.QuadPart = (LONGLONG)BeepParam->Duration * -10000;
316 
317       KeSetTimer(&DeviceExtension->Timer,
318 		 DueTime,
319 		 &DeviceExtension->Dpc);
320 
321       HalMakeBeep(BeepParam->Frequency);
322       DeviceExtension->BeepOn = TRUE;
323       KeWaitForSingleObject(&DeviceExtension->Event,
324 			    Executive,
325 			    KernelMode,
326 			    FALSE,
327 			    NULL);
328     }
329   else if (BeepParam->Duration == (DWORD)-1)
330     {
331       if (DeviceExtension->BeepOn == TRUE)
332 	{
333 	  HalMakeBeep(0);
334 	  DeviceExtension->BeepOn = FALSE;
335 	}
336       else
337 	{
338 	  HalMakeBeep(BeepParam->Frequency);
339 	  DeviceExtension->BeepOn = TRUE;
340 	}
341     }
342 
343   DPRINT("Did the beep!\n");
344 
345   Irp->IoStatus.Status = STATUS_SUCCESS;
346   IoCompleteRequest(Irp,
347 		    IO_NO_INCREMENT);
348   return(STATUS_SUCCESS);
349 */
350 }
351 
352 
353 static VOID NTAPI
354 MPU401Unload(PDRIVER_OBJECT DriverObject)
355 {
356   DPRINT("MPU401Unload() called!\n");
357 }
358 
359 
360 NTSTATUS NTAPI
361 DriverEntry(PDRIVER_OBJECT DriverObject,
362 	    PUNICODE_STRING RegistryPath)
363 /*
364  * FUNCTION:  Called by the system to initalize the driver
365  * ARGUMENTS:
366  *            DriverObject = object describing this driver
367  *            RegistryPath = path to our configuration entries
368  * RETURNS:   Success or failure
369  */
370 {
371 //  PDEVICE_EXTENSION DeviceExtension;
372 //  PDEVICE_OBJECT DeviceObject;
373 //  DEVICE_INSTANCE Instance;
374   // Doesn't support multiple instances (yet ...)
375   NTSTATUS Status;
376 
377   DPRINT("MPU401 Device Driver 0.0.1\n");
378 
379     // Is this really necessary? Yes! (Talking to myself again...)
380 //    Instance.DriverObject = DriverObject;
381     // previous instance = NULL...
382 
383 //    DeviceExtension->RegistryPath = RegistryPath;
384 
385   DriverObject->Flags = 0;
386   DriverObject->MajorFunction[IRP_MJ_CREATE] = MPU401Create;
387   DriverObject->MajorFunction[IRP_MJ_CLOSE] = MPU401Close;
388   DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MPU401Cleanup;
389   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MPU401DeviceControl;
390   DriverObject->DriverUnload = MPU401Unload;
391 
392     // Major hack to just get this damn thing working:
393     Status = InitDevice(RegistryPath, DriverObject);    // ????
394 
395 //    DPRINT("Enumerating devices at %wZ\n", RegistryPath);
396 
397 //    Status = EnumDeviceKeys(RegistryPath, PARMS_SUBKEY, InitDevice, (PVOID)&DeviceObject); // &Instance;
398 
399     // check error
400 
401   /* set up device extension */
402 //  DeviceExtension = DeviceObject->DeviceExtension;
403 //  DeviceExtension->BeepOn = FALSE;
404 
405   return(STATUS_SUCCESS);
406 }
407 
408 /* EOF */
409