mirror of
https://github.com/reactos/reactos.git
synced 2024-09-11 21:34:09 +00:00
409 lines
11 KiB
C
409 lines
11 KiB
C
/*
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: services/dd/mpu401/mpu401.c
|
|
* PURPOSE: MPU-401 MIDI device driver
|
|
* PROGRAMMER: Andrew Greenwood
|
|
* UPDATE HISTORY:
|
|
* Sept 26, 2003: Copied from beep.c as template
|
|
* Sept 27, 2003: Implemented MPU-401 init & playback
|
|
*/
|
|
|
|
/* INCLUDES ****************************************************************/
|
|
|
|
#include <ntddk.h>
|
|
//#include <ntddbeep.h>
|
|
|
|
//#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#include "mpu401.h"
|
|
|
|
|
|
/* INTERNAL VARIABLES ******************************************************/
|
|
|
|
ULONG DeviceCount = 0;
|
|
|
|
|
|
/* FUNCTIONS ***************************************************************/
|
|
|
|
static NTSTATUS InitDevice(
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PVOID Context)
|
|
{
|
|
// PDEVICE_INSTANCE Instance = Context;
|
|
PDEVICE_OBJECT DeviceObject; // = Context;
|
|
PDEVICE_EXTENSION Parameters; // = DeviceObject->DeviceExtension;
|
|
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\MidiOut0");
|
|
UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\MidiOut0");
|
|
// CONFIG Config;
|
|
RTL_QUERY_REGISTRY_TABLE Table[2];
|
|
NTSTATUS s;
|
|
|
|
// This is TEMPORARY, to ensure that we don't process more than 1 device.
|
|
// I'll remove this limitation in the future.
|
|
if (DeviceCount > 0)
|
|
{
|
|
DPRINT("Sorry - only 1 device supported by MPU401 driver at present :(\n");
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
DPRINT("Creating IO device\n");
|
|
|
|
s = IoCreateDevice(Context, // driverobject
|
|
sizeof(DEVICE_EXTENSION),
|
|
&DeviceName,
|
|
FILE_DEVICE_SOUND, // Correct?
|
|
0,
|
|
FALSE,
|
|
&DeviceObject);
|
|
|
|
if (!NT_SUCCESS(s))
|
|
return s;
|
|
|
|
DPRINT("Device Extension at 0x%x\n", DeviceObject->DeviceExtension);
|
|
Parameters = DeviceObject->DeviceExtension;
|
|
|
|
DPRINT("Creating DOS link\n");
|
|
|
|
/* Create the dos device link */
|
|
IoCreateSymbolicLink(&SymlinkName,
|
|
&DeviceName);
|
|
|
|
DPRINT("Initializing device\n");
|
|
|
|
// DPRINT("Allocating memory for parameters structure\n");
|
|
// Bodged:
|
|
// Parameters = (PDEVICE_EXTENSION)ExAllocatePool(NonPagedPool, sizeof(DEVICE_EXTENSION));
|
|
// DeviceObject->DeviceExtension = Parameters;
|
|
// Parameters = Instance->DriverObject->DriverExtension;
|
|
|
|
DPRINT("DeviceObject at 0x%x, DeviceExtension at 0x%x\n", DeviceObject, Parameters);
|
|
|
|
if (! Parameters)
|
|
{
|
|
DPRINT("NULL POINTER!\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Instance->DriverObject->DriverExtension = Parameters;
|
|
|
|
DPRINT("Setting reg path\n");
|
|
Parameters->RegistryPath = RegistryPath;
|
|
// Parameters->DriverObject = Instance->DriverObject;
|
|
|
|
DPRINT("Zeroing table memory and setting query routine\n");
|
|
RtlZeroMemory(Table, sizeof(Table));
|
|
Table[0].QueryRoutine = LoadSettings;
|
|
|
|
DPRINT("Setting port and IRQ defaults\n");
|
|
Parameters->Port = DEFAULT_PORT;
|
|
Parameters->IRQ = DEFAULT_IRQ;
|
|
|
|
// Only to be enabled once we can get support for multiple cards working :)
|
|
/*
|
|
DPRINT("Loading settings from: %S\n", RegistryPath);
|
|
|
|
s = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, RegistryPath, Table,
|
|
&Parameters, NULL);
|
|
*/
|
|
|
|
if (! NT_SUCCESS(s))
|
|
return s;
|
|
|
|
DPRINT("Port 0x%x IRQ %d\n", Parameters->Port, Parameters->IRQ);
|
|
|
|
// Instance->P
|
|
|
|
// Enter UART mode (should be done in init phase
|
|
if (! InitUARTMode(Parameters->Port))
|
|
{
|
|
DPRINT("UART mode initialization FAILED!\n");
|
|
// Set state indication somehow
|
|
// Failure - what error code do we give?!
|
|
// return STATUS_????
|
|
}
|
|
|
|
DeviceCount ++;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static NTSTATUS NTAPI
|
|
MPU401Create(PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: Handles user mode requests
|
|
* ARGUMENTS:
|
|
* DeviceObject = Device for request
|
|
* Irp = I/O request packet describing request
|
|
* RETURNS: Success or failure
|
|
*/
|
|
{
|
|
DPRINT("MPU401Create() called!\n");
|
|
|
|
// Initialize the MPU-401?
|
|
// ... do stuff ...
|
|
|
|
|
|
// Play a note to say we're alive:
|
|
WaitToSend(MPU401_PORT);
|
|
MPU401_WRITE_DATA(MPU401_PORT, 0x90);
|
|
WaitToSend(MPU401_PORT);
|
|
MPU401_WRITE_DATA(MPU401_PORT, 0x50);
|
|
WaitToSend(MPU401_PORT);
|
|
MPU401_WRITE_DATA(MPU401_PORT, 0x7f);
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
static NTSTATUS NTAPI
|
|
MPU401Close(PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: Handles user mode requests
|
|
* ARGUMENTS:
|
|
* DeviceObject = Device for request
|
|
* Irp = I/O request packet describing request
|
|
* RETURNS: Success or failure
|
|
*/
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("MPU401Close() called!\n");
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
static NTSTATUS NTAPI
|
|
MPU401Cleanup(PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: Handles user mode requests
|
|
* ARGUMENTS:
|
|
* DeviceObject = Device for request
|
|
* Irp = I/O request packet describing request
|
|
* RETURNS: Success or failure
|
|
*/
|
|
{
|
|
ULONG Channel;
|
|
DPRINT("MPU401Cleanup() called!\n");
|
|
|
|
// Reset the device (should we do this?)
|
|
for (Channel = 0; Channel <= 15; Channel ++)
|
|
{
|
|
// All notes off
|
|
// MPU401_WRITE_MESSAGE(MPU401_PORT, 0xb0 + Channel, 123, 0);
|
|
// All controllers off
|
|
// MPU401_WRITE_MESSAGE(MPU401_PORT, 0xb0 + Channel, 121, 0);
|
|
}
|
|
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
static NTSTATUS NTAPI
|
|
MPU401DeviceControl(PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: Handles user mode requests
|
|
* ARGUMENTS:
|
|
* DeviceObject = Device for request
|
|
* Irp = I/O request packet describing request
|
|
* RETURNS: Success or failure
|
|
*/
|
|
{
|
|
PIO_STACK_LOCATION Stack;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
ULONG ByteCount;
|
|
PUCHAR Data;
|
|
|
|
DPRINT("MPU401DeviceControl() called!\n");
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DPRINT("Control code %d [0x%x]\n", Stack->Parameters.DeviceIoControl.IoControlCode,
|
|
Stack->Parameters.DeviceIoControl.IoControlCode);
|
|
|
|
switch(Stack->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_MIDI_PLAY :
|
|
{
|
|
DPRINT("Received IOCTL_MIDI_PLAY\n");
|
|
Data = (PUCHAR) Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
DPRINT("Sending %d bytes of MIDI data to 0x%x:\n", Stack->Parameters.DeviceIoControl.InputBufferLength, DeviceExtension->Port);
|
|
|
|
for (ByteCount = 0; ByteCount < Stack->Parameters.DeviceIoControl.InputBufferLength; ByteCount ++)
|
|
{
|
|
DPRINT("0x%x ", Data[ByteCount]);
|
|
|
|
MPU401_WRITE_BYTE(DeviceExtension->Port, Data[ByteCount]);
|
|
// if (WaitToSend(MPU401_PORT))
|
|
// MPU401_WRITE_DATA(MPU401_PORT, Data[ByteCount]);
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
/*
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
BeepParam = (PBEEP_SET_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
if (Stack->Parameters.DeviceIoControl.IoControlCode != IOCTL_BEEP_SET)
|
|
{
|
|
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
return(STATUS_NOT_IMPLEMENTED);
|
|
}
|
|
|
|
if ((Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(BEEP_SET_PARAMETERS))
|
|
|| (BeepParam->Frequency < BEEP_FREQUENCY_MINIMUM)
|
|
|| (BeepParam->Frequency > BEEP_FREQUENCY_MAXIMUM))
|
|
{
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
DueTime.QuadPart = 0;
|
|
*/
|
|
/* do the beep!! */
|
|
/* DPRINT("Beep:\n Freq: %lu Hz\n Dur: %lu ms\n",
|
|
pbsp->Frequency,
|
|
pbsp->Duration);
|
|
|
|
if (BeepParam->Duration >= 0)
|
|
{
|
|
DueTime.QuadPart = (LONGLONG)BeepParam->Duration * -10000;
|
|
|
|
KeSetTimer(&DeviceExtension->Timer,
|
|
DueTime,
|
|
&DeviceExtension->Dpc);
|
|
|
|
HalMakeBeep(BeepParam->Frequency);
|
|
DeviceExtension->BeepOn = TRUE;
|
|
KeWaitForSingleObject(&DeviceExtension->Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
else if (BeepParam->Duration == (DWORD)-1)
|
|
{
|
|
if (DeviceExtension->BeepOn != FALSE)
|
|
{
|
|
HalMakeBeep(0);
|
|
DeviceExtension->BeepOn = FALSE;
|
|
}
|
|
else
|
|
{
|
|
HalMakeBeep(BeepParam->Frequency);
|
|
DeviceExtension->BeepOn = TRUE;
|
|
}
|
|
}
|
|
|
|
DPRINT("Did the beep!\n");
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
return(STATUS_SUCCESS);
|
|
*/
|
|
}
|
|
|
|
|
|
static VOID NTAPI
|
|
MPU401Unload(PDRIVER_OBJECT DriverObject)
|
|
{
|
|
DPRINT("MPU401Unload() called!\n");
|
|
}
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
DriverEntry(PDRIVER_OBJECT DriverObject,
|
|
PUNICODE_STRING RegistryPath)
|
|
/*
|
|
* FUNCTION: Called by the system to initialize the driver
|
|
* ARGUMENTS:
|
|
* DriverObject = object describing this driver
|
|
* RegistryPath = path to our configuration entries
|
|
* RETURNS: Success or failure
|
|
*/
|
|
{
|
|
// PDEVICE_EXTENSION DeviceExtension;
|
|
// PDEVICE_OBJECT DeviceObject;
|
|
// DEVICE_INSTANCE Instance;
|
|
// Doesn't support multiple instances (yet ...)
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("MPU401 Device Driver 0.0.1\n");
|
|
|
|
// Is this really necessary? Yes! (Talking to myself again...)
|
|
// Instance.DriverObject = DriverObject;
|
|
// previous instance = NULL...
|
|
|
|
// DeviceExtension->RegistryPath = RegistryPath;
|
|
|
|
DriverObject->Flags = 0;
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = MPU401Create;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MPU401Close;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MPU401Cleanup;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MPU401DeviceControl;
|
|
DriverObject->DriverUnload = MPU401Unload;
|
|
|
|
// Major hack to just get this damn thing working:
|
|
Status = InitDevice(RegistryPath, DriverObject); // ????
|
|
|
|
// DPRINT("Enumerating devices at %wZ\n", RegistryPath);
|
|
|
|
// Status = EnumDeviceKeys(RegistryPath, PARMS_SUBKEY, InitDevice, (PVOID)&DeviceObject); // &Instance;
|
|
|
|
// check error
|
|
|
|
/* set up device extension */
|
|
// DeviceExtension = DeviceObject->DeviceExtension;
|
|
// DeviceExtension->BeepOn = FALSE;
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
/* EOF */
|