Moved sndblst in sound
[reactos.git] / reactos / drivers / sound / mpu401 / mpu401.c
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
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 STDCALL
354 MPU401Unload(PDRIVER_OBJECT DriverObject)
355 {
356 DPRINT("MPU401Unload() called!\n");
357 }
358
359
360 NTSTATUS STDCALL
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 */