reactos/drivers/multimedia/audio/mpu401_nt4/mpu401.c

408 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 */