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
9 * Sept 26, 2003: Copied from beep.c as template
10 * Sept 27, 2003: Implemented MPU-401 init & playback
13 /* INCLUDES ****************************************************************/
15 #include <ddk/ntddk.h>
16 //#include <ddk/ntddbeep.h>
24 /* INTERNAL VARIABLES ******************************************************/
29 /* FUNCTIONS ***************************************************************/
31 static NTSTATUS
InitDevice(
32 IN PUNICODE_STRING RegistryPath
,
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");
41 RTL_QUERY_REGISTRY_TABLE Table
[2];
44 // This is TEMPORARY, to ensure that we don't process more than 1 device.
45 // I'll remove this limitation in the future.
48 DPRINT("Sorry - only 1 device supported by MPU401 driver at present :(\n");
49 return STATUS_NOT_IMPLEMENTED
;
52 DPRINT("Creating IO device\n");
54 s
= IoCreateDevice(Context
, // driverobject
55 sizeof(DEVICE_EXTENSION
),
57 FILE_DEVICE_SOUND
, // Correct?
65 DPRINT("Device Extension at 0x%x\n", DeviceObject
->DeviceExtension
);
66 Parameters
= DeviceObject
->DeviceExtension
;
68 DPRINT("Creating DOS link\n");
70 /* Create the dos device link */
71 IoCreateSymbolicLink(&SymlinkName
,
74 DPRINT("Initializing device\n");
76 // DPRINT("Allocating memory for parameters structure\n");
78 // Parameters = (PDEVICE_EXTENSION)ExAllocatePool(NonPagedPool, sizeof(DEVICE_EXTENSION));
79 // DeviceObject->DeviceExtension = Parameters;
80 // Parameters = Instance->DriverObject->DriverExtension;
82 DPRINT("DeviceObject at 0x%x, DeviceExtension at 0x%x\n", DeviceObject
, Parameters
);
86 DPRINT("NULL POINTER!\n");
87 return STATUS_INSUFFICIENT_RESOURCES
;
90 // Instance->DriverObject->DriverExtension = Parameters;
92 DPRINT("Setting reg path\n");
93 Parameters
->RegistryPath
= RegistryPath
;
94 // Parameters->DriverObject = Instance->DriverObject;
96 DPRINT("Zeroing table memory and setting query routine\n");
97 RtlZeroMemory(Table
, sizeof(Table
));
98 Table
[0].QueryRoutine
= LoadSettings
;
100 DPRINT("Setting port and IRQ defaults\n");
101 Parameters
->Port
= DEFAULT_PORT
;
102 Parameters
->IRQ
= DEFAULT_IRQ
;
104 // Only to be enabled once we can get support for multiple cards working :)
106 DPRINT("Loading settings from: %S\n", RegistryPath);
108 s = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, RegistryPath, Table,
115 DPRINT("Port 0x%x IRQ %d\n", Parameters
->Port
, Parameters
->IRQ
);
119 // Enter UART mode (should be done in init phase
120 if (! InitUARTMode(Parameters
->Port
))
122 DPRINT("UART mode initialization FAILED!\n");
123 // Set state indication somehow
124 // Failure - what error code do we give?!
125 // return STATUS_????
130 return STATUS_SUCCESS
;
134 static NTSTATUS STDCALL
135 MPU401Create(PDEVICE_OBJECT DeviceObject
,
138 * FUNCTION: Handles user mode requests
140 * DeviceObject = Device for request
141 * Irp = I/O request packet describing request
142 * RETURNS: Success or failure
145 DPRINT("MPU401Create() called!\n");
147 // Initialize the MPU-401?
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);
159 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
160 Irp
->IoStatus
.Information
= 0;
161 IoCompleteRequest(Irp
,
164 return(STATUS_SUCCESS
);
168 static NTSTATUS STDCALL
169 MPU401Close(PDEVICE_OBJECT DeviceObject
,
172 * FUNCTION: Handles user mode requests
174 * DeviceObject = Device for request
175 * Irp = I/O request packet describing request
176 * RETURNS: Success or failure
179 PDEVICE_EXTENSION DeviceExtension
;
182 DPRINT("MPU401Close() called!\n");
184 DeviceExtension
= DeviceObject
->DeviceExtension
;
186 Status
= STATUS_SUCCESS
;
188 Irp
->IoStatus
.Status
= Status
;
189 Irp
->IoStatus
.Information
= 0;
190 IoCompleteRequest(Irp
,
197 static NTSTATUS STDCALL
198 MPU401Cleanup(PDEVICE_OBJECT DeviceObject
,
201 * FUNCTION: Handles user mode requests
203 * DeviceObject = Device for request
204 * Irp = I/O request packet describing request
205 * RETURNS: Success or failure
209 DPRINT("MPU401Cleanup() called!\n");
211 // Reset the device (should we do this?)
212 for (Channel
= 0; Channel
<= 15; Channel
++)
215 // MPU401_WRITE_MESSAGE(MPU401_PORT, 0xb0 + Channel, 123, 0);
216 // All controllers off
217 // MPU401_WRITE_MESSAGE(MPU401_PORT, 0xb0 + Channel, 121, 0);
221 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
222 Irp
->IoStatus
.Information
= 0;
223 IoCompleteRequest(Irp
,
226 return(STATUS_SUCCESS
);
230 static NTSTATUS STDCALL
231 MPU401DeviceControl(PDEVICE_OBJECT DeviceObject
,
234 * FUNCTION: Handles user mode requests
236 * DeviceObject = Device for request
237 * Irp = I/O request packet describing request
238 * RETURNS: Success or failure
241 PIO_STACK_LOCATION Stack
;
242 PDEVICE_EXTENSION DeviceExtension
;
246 DPRINT("MPU401DeviceControl() called!\n");
248 DeviceExtension
= DeviceObject
->DeviceExtension
;
249 Stack
= IoGetCurrentIrpStackLocation(Irp
);
251 DPRINT("Control code %d [0x%x]\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
,
252 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
254 switch(Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
256 case IOCTL_MIDI_PLAY
:
258 DPRINT("Received IOCTL_MIDI_PLAY\n");
259 Data
= (PBYTE
) Irp
->AssociatedIrp
.SystemBuffer
;
261 DPRINT("Sending %d bytes of MIDI data to 0x%d:\n", Stack
->Parameters
.DeviceIoControl
.InputBufferLength
, DeviceExtension
->Port
);
263 for (ByteCount
= 0; ByteCount
< Stack
->Parameters
.DeviceIoControl
.InputBufferLength
; ByteCount
++)
265 DPRINT("0x%x ", Data
[ByteCount
]);
267 MPU401_WRITE_BYTE(DeviceExtension
->Port
, Data
[ByteCount
]);
268 // if (WaitToSend(MPU401_PORT))
269 // MPU401_WRITE_DATA(MPU401_PORT, Data[ByteCount]);
272 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
273 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
275 return(STATUS_SUCCESS
);
279 return(STATUS_SUCCESS
);
282 DeviceExtension = DeviceObject->DeviceExtension;
283 Stack = IoGetCurrentIrpStackLocation(Irp);
284 BeepParam = (PBEEP_SET_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
286 Irp->IoStatus.Information = 0;
288 if (Stack->Parameters.DeviceIoControl.IoControlCode != IOCTL_BEEP_SET)
290 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
291 IoCompleteRequest(Irp,
293 return(STATUS_NOT_IMPLEMENTED);
296 if ((Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(BEEP_SET_PARAMETERS))
297 || (BeepParam->Frequency < BEEP_FREQUENCY_MINIMUM)
298 || (BeepParam->Frequency > BEEP_FREQUENCY_MAXIMUM))
300 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
301 IoCompleteRequest(Irp,
303 return(STATUS_INVALID_PARAMETER);
306 DueTime.QuadPart = 0;
309 /* DPRINT("Beep:\n Freq: %lu Hz\n Dur: %lu ms\n",
313 if (BeepParam->Duration >= 0)
315 DueTime.QuadPart = (LONGLONG)BeepParam->Duration * -10000;
317 KeSetTimer(&DeviceExtension->Timer,
319 &DeviceExtension->Dpc);
321 HalMakeBeep(BeepParam->Frequency);
322 DeviceExtension->BeepOn = TRUE;
323 KeWaitForSingleObject(&DeviceExtension->Event,
329 else if (BeepParam->Duration == (DWORD)-1)
331 if (DeviceExtension->BeepOn == TRUE)
334 DeviceExtension->BeepOn = FALSE;
338 HalMakeBeep(BeepParam->Frequency);
339 DeviceExtension->BeepOn = TRUE;
343 DPRINT("Did the beep!\n");
345 Irp->IoStatus.Status = STATUS_SUCCESS;
346 IoCompleteRequest(Irp,
348 return(STATUS_SUCCESS);
354 MPU401Unload(PDRIVER_OBJECT DriverObject
)
356 DPRINT("MPU401Unload() called!\n");
361 DriverEntry(PDRIVER_OBJECT DriverObject
,
362 PUNICODE_STRING RegistryPath
)
364 * FUNCTION: Called by the system to initalize the driver
366 * DriverObject = object describing this driver
367 * RegistryPath = path to our configuration entries
368 * RETURNS: Success or failure
371 // PDEVICE_EXTENSION DeviceExtension;
372 // PDEVICE_OBJECT DeviceObject;
373 // DEVICE_INSTANCE Instance;
374 // Doesn't support multiple instances (yet ...)
377 DPRINT("MPU401 Device Driver 0.0.1\n");
379 // Is this really necessary? Yes! (Talking to myself again...)
380 // Instance.DriverObject = DriverObject;
381 // previous instance = NULL...
383 // DeviceExtension->RegistryPath = RegistryPath;
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
;
392 // Major hack to just get this damn thing working:
393 Status
= InitDevice(RegistryPath
, DriverObject
); // ????
395 // DPRINT("Enumerating devices at %wZ\n", RegistryPath);
397 // Status = EnumDeviceKeys(RegistryPath, PARMS_SUBKEY, InitDevice, (PVOID)&DeviceObject); // &Instance;
401 /* set up device extension */
402 // DeviceExtension = DeviceObject->DeviceExtension;
403 // DeviceExtension->BeepOn = FALSE;
405 return(STATUS_SUCCESS
);