mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 05:55:42 +00:00
2nd time lucky - MPU401 driver. Sorry about the previous breakage of blue :(
svn path=/trunk/; revision=7789
This commit is contained in:
parent
5c32f0ba7f
commit
9e88919457
10 changed files with 1144 additions and 0 deletions
8
reactos/drivers/dd/mpu401/.cvsignore
Normal file
8
reactos/drivers/dd/mpu401/.cvsignore
Normal file
|
@ -0,0 +1,8 @@
|
|||
*.tmp
|
||||
*.exp
|
||||
*.coff
|
||||
*.d
|
||||
*.o
|
||||
*.sym
|
||||
*.sys
|
||||
*.map
|
22
reactos/drivers/dd/mpu401/makefile
Normal file
22
reactos/drivers/dd/mpu401/makefile
Normal file
|
@ -0,0 +1,22 @@
|
|||
# $Id: makefile,v 1.1 2004/01/20 19:58:48 silverblade Exp $
|
||||
|
||||
PATH_TO_TOP = ../../..
|
||||
|
||||
TARGET_BOOTSTRAP = yes
|
||||
|
||||
TARGET_TYPE = driver
|
||||
|
||||
TARGET_NAME = mpu401
|
||||
|
||||
TARGET_OBJECTS = mpu401.o \
|
||||
portio.o \
|
||||
settings.o
|
||||
|
||||
TARGET_CFLAGS = -Wall -Werror
|
||||
|
||||
include $(PATH_TO_TOP)/rules.mak
|
||||
|
||||
include $(TOOLS_PATH)/helper.mk
|
||||
|
||||
DEP_OBJECTS := $(TARGET_OBJECTS)
|
||||
include $(PATH_TO_TOP)/tools/depend.mk
|
406
reactos/drivers/dd/mpu401/mpu401.c
Normal file
406
reactos/drivers/dd/mpu401/mpu401.c
Normal file
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
*
|
||||
* 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 <ddk/ntddk.h>
|
||||
//#include <ddk/ntddbeep.h>
|
||||
|
||||
//#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#include "mpu401.h"
|
||||
|
||||
|
||||
/* INTERNAL VARIABLES ******************************************************/
|
||||
|
||||
UINT DeviceCount = 0;
|
||||
|
||||
|
||||
/* FUNCTIONS ***************************************************************/
|
||||
|
||||
NTSTATUS InitDevice(
|
||||
IN PWSTR RegistryPath,
|
||||
IN PVOID Context)
|
||||
{
|
||||
// PDEVICE_INSTANCE Instance = Context;
|
||||
PDEVICE_OBJECT DeviceObject; // = Context;
|
||||
PDEVICE_EXTENSION Parameters; // = DeviceObject->DeviceExtension;
|
||||
UNICODE_STRING DeviceName = UNICODE_STRING_INITIALIZER(L"\\Device\\MPU401_Out_0");
|
||||
UNICODE_STRING SymlinkName = UNICODE_STRING_INITIALIZER(L"\\??\\MPU401_Out_0");
|
||||
// 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 STDCALL
|
||||
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 STDCALL
|
||||
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 STDCALL
|
||||
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
|
||||
*/
|
||||
{
|
||||
UINT 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 STDCALL
|
||||
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;
|
||||
UINT ByteCount;
|
||||
PBYTE Data;
|
||||
|
||||
DPRINT("MPU401DeviceControl() called!\n");
|
||||
|
||||
DeviceExtension = DeviceObject->DeviceExtension;
|
||||
Stack = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
switch(Stack->Parameters.DeviceIoControl.IoControlCode)
|
||||
{
|
||||
case IOCTL_MIDI_PLAY :
|
||||
{
|
||||
DPRINT("Received IOCTL_MIDI_PLAY\n");
|
||||
Data = (PBYTE) Irp->AssociatedIrp.SystemBuffer;
|
||||
|
||||
DPRINT("Sending %d bytes of MIDI data to 0x%d:\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 == TRUE)
|
||||
{
|
||||
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 NTSTATUS STDCALL
|
||||
MPU401Unload(PDRIVER_OBJECT DriverObject)
|
||||
{
|
||||
DPRINT("MPU401Unload() called!\n");
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
DriverEntry(PDRIVER_OBJECT DriverObject,
|
||||
PUNICODE_STRING RegistryPath)
|
||||
/*
|
||||
* FUNCTION: Called by the system to initalize 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] = (PDRIVER_DISPATCH)MPU401Create;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)MPU401Close;
|
||||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)MPU401Cleanup;
|
||||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)MPU401DeviceControl;
|
||||
DriverObject->DriverUnload = (PDRIVER_UNLOAD)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 */
|
145
reactos/drivers/dd/mpu401/mpu401.h
Normal file
145
reactos/drivers/dd/mpu401/mpu401.h
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: services/dd/mpu401/mpu401.h
|
||||
* PURPOSE: MPU-401 MIDI device driver header
|
||||
* PROGRAMMER: Andrew Greenwood
|
||||
* UPDATE HISTORY:
|
||||
* Sept 26, 2003: Created
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDES_MPU401_H__
|
||||
#define __INCLUDES_MPU401_H__
|
||||
|
||||
#define DEFAULT_PORT 0x330
|
||||
#define DEFAULT_IRQ 9
|
||||
|
||||
#define DEVICE_SUBKEY L"Devices"
|
||||
#define PARMS_SUBKEY L"Parameters"
|
||||
|
||||
#define REGISTRY_PORT L"Port"
|
||||
|
||||
// At the moment, we just support a single device with fixed parameters:
|
||||
#define MPU401_PORT DEFAULT_PORT
|
||||
#define MPU401_IRQ DEFAULT_IRQ
|
||||
|
||||
#define MPU401_TIMEOUT 10000
|
||||
|
||||
#define IOCTL_SOUND_BASE FILE_DEVICE_SOUND
|
||||
// wave base 0
|
||||
#define IOCTL_MIDI_BASE 0x0080
|
||||
|
||||
#define IOCTL_MIDI_GET_CAPABILITIES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MIDI_SET_STATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MIDI_GET_STATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0003, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MIDI_SET_VOLUME CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MIDI_GET_VOLUME CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MIDI_PLAY CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MIDI_RECORD CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0007, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MIDI_CACHE_PATCHES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0008, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MIDI_CACHE_DRUM_PATCHES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
|
||||
|
||||
// The MPU-401 has 2 ports, usually 0x330 and 0x331, which are known as
|
||||
// "data" and "status/command", respectively. These macros deal with
|
||||
// reading from and writing to these ports:
|
||||
|
||||
#define MPU401_WRITE_DATA(bp, x) WRITE_PORT_UCHAR((PUCHAR) bp, x)
|
||||
#define MPU401_READ_DATA(bp) READ_PORT_UCHAR((PUCHAR) bp)
|
||||
#define MPU401_WRITE_COMMAND(bp, x) WRITE_PORT_UCHAR((PUCHAR) bp+1, x)
|
||||
#define MPU401_READ_STATUS(bp) READ_PORT_UCHAR((PUCHAR) bp+1)
|
||||
|
||||
|
||||
// Flow control
|
||||
|
||||
#define MPU401_READY_TO_SEND(bp) \
|
||||
MPU401_READ_STATUS(bp) & 0x80
|
||||
|
||||
#define MPU401_READY_TO_RECEIVE(bp) \
|
||||
MPU401_READ_STATUS(bp) & 0x40
|
||||
|
||||
|
||||
#define MPU401_WRITE_BYTE(bp, x) \
|
||||
if (WaitToSend(bp)) MPU401_WRITE_DATA(bp, x)
|
||||
|
||||
#define MPU401_WRITE_MESSAGE(bp, status, da, db) \
|
||||
MPU401_WRITE(bp, status); \
|
||||
MPU401_WRITE(bp, da); \
|
||||
MPU401_WRITE(bp, db)
|
||||
|
||||
//#define MPU401_READ(bp)
|
||||
// if (WaitToRead(bp)) ... ???
|
||||
|
||||
/*
|
||||
DEVICE_EXTENSION contains the settings for each individual device
|
||||
*/
|
||||
|
||||
typedef struct _DEVICE_EXTENSION
|
||||
{
|
||||
PWSTR RegistryPath;
|
||||
PDRIVER_OBJECT DriverObject;
|
||||
UINT Port;
|
||||
UINT IRQ;
|
||||
// KDPC Dpc;
|
||||
// KTIMER Timer;
|
||||
// KEVENT Event;
|
||||
// BOOLEAN BeepOn;
|
||||
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
||||
|
||||
/*
|
||||
DEVICE_INSTANCE contains ???
|
||||
*/
|
||||
|
||||
typedef struct _DEVICE_INSTANCE
|
||||
{
|
||||
// pPrevGDI
|
||||
PDRIVER_OBJECT DriverObject;
|
||||
} DEVICE_INSTANCE, *PDEVICE_INSTANCE;
|
||||
|
||||
/*
|
||||
CONFIG contains device parameters (port/IRQ)
|
||||
THIS STRUCTURE IS REDUNDANT
|
||||
*/
|
||||
|
||||
//typedef struct _CONFIG
|
||||
//{
|
||||
// UINT Port;
|
||||
// UINT IRQ;
|
||||
//} CONFIG, *PCONFIG;
|
||||
|
||||
/*
|
||||
Some callback typedefs
|
||||
*/
|
||||
|
||||
typedef NTSTATUS REGISTRY_CALLBACK_ROUTINE(PWSTR RegistryPath, PVOID Context);
|
||||
typedef REGISTRY_CALLBACK_ROUTINE *PREGISTRY_CALLBACK_ROUTINE;
|
||||
|
||||
|
||||
/*
|
||||
Prototypes for functions in portio.c :
|
||||
*/
|
||||
|
||||
BOOLEAN WaitToSend(UINT BasePort);
|
||||
BOOLEAN WaitToReceive(UINT BasePort);
|
||||
BOOLEAN InitUARTMode(UINT BasePort);
|
||||
|
||||
/*
|
||||
Prototypes for functions in settings.c :
|
||||
*/
|
||||
|
||||
NTSTATUS EnumDeviceKeys(
|
||||
IN PUNICODE_STRING RegistryPath,
|
||||
IN PWSTR SubKey,
|
||||
IN PREGISTRY_CALLBACK_ROUTINE Callback,
|
||||
IN PVOID Context);
|
||||
|
||||
NTSTATUS LoadSettings(
|
||||
IN PWSTR ValueName,
|
||||
IN ULONG ValueType,
|
||||
IN PVOID ValueData,
|
||||
IN ULONG ValueLength,
|
||||
IN PVOID Context,
|
||||
IN PVOID EntryContext);
|
||||
|
||||
#endif
|
38
reactos/drivers/dd/mpu401/mpu401.rc
Normal file
38
reactos/drivers/dd/mpu401/mpu401.rc
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <defines.h>
|
||||
#include <reactos/resource.h>
|
||||
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
|
||||
PRODUCTVERSION RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", RES_STR_COMPANY_NAME
|
||||
VALUE "FileDescription", "MPU-401 MIDI Driver\0"
|
||||
VALUE "FileVersion", "0.0.1\0"
|
||||
VALUE "InternalName", "mpu401\0"
|
||||
VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT
|
||||
VALUE "OriginalFilename", "mpu401.sys\0"
|
||||
VALUE "ProductName", RES_STR_PRODUCT_NAME
|
||||
VALUE "ProductVersion", RES_STR_PRODUCT_VERSION
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
97
reactos/drivers/dd/mpu401/portio.c
Normal file
97
reactos/drivers/dd/mpu401/portio.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: services/dd/mpu401/portio.c (see also mpu401.h)
|
||||
* PURPOSE: MPU-401 MIDI port I/O helper
|
||||
* PROGRAMMER: Andrew Greenwood
|
||||
* UPDATE HISTORY:
|
||||
* Sept 26, 2003: Created
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <ddk/ntddk.h>
|
||||
#include "mpu401.h"
|
||||
|
||||
|
||||
BOOLEAN WaitToSend(UINT BasePort)
|
||||
{
|
||||
int TimeOut;
|
||||
|
||||
DbgPrint("WaitToSend ");
|
||||
|
||||
// Check if it's OK to send
|
||||
for (TimeOut = MPU401_TIMEOUT;
|
||||
! MPU401_READY_TO_SEND(BasePort) && TimeOut > 0;
|
||||
TimeOut --);
|
||||
|
||||
// If a time-out occurs, we report failure
|
||||
if (! TimeOut)
|
||||
{
|
||||
DbgPrint("FAILED\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DbgPrint("SUCCEEDED\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN WaitToReceive(UINT BasePort)
|
||||
{
|
||||
int TimeOut;
|
||||
|
||||
DbgPrint("WaitToSend ");
|
||||
|
||||
// Check if it's OK to receive
|
||||
for (TimeOut = MPU401_TIMEOUT;
|
||||
! MPU401_READY_TO_RECEIVE(BasePort) && TimeOut > 0;
|
||||
TimeOut --);
|
||||
|
||||
// If a time-out occurs, we report failure
|
||||
if (! TimeOut)
|
||||
{
|
||||
DbgPrint("FAILED\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DbgPrint("SUCCEEDED\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN InitUARTMode(UINT BasePort)
|
||||
{
|
||||
UINT TimeOut;
|
||||
UCHAR Status = 0;
|
||||
|
||||
DbgPrint("InitUARTMode() called\n");
|
||||
|
||||
// Check if it's OK to send
|
||||
if (! WaitToSend(BasePort))
|
||||
return FALSE;
|
||||
|
||||
DbgPrint("Resetting MPU401\n");
|
||||
|
||||
// Send an MPU reset:
|
||||
MPU401_WRITE_COMMAND(BasePort, 0xff);
|
||||
|
||||
// Check if it's OK to receive (some cards will ignore the above reset
|
||||
// command and so will not issue an ACK, so time out is NOT an error)
|
||||
DbgPrint("Waiting for an ACK\n");
|
||||
if (WaitToReceive(BasePort))
|
||||
{
|
||||
// Check to make sure the reset was acknowledged:
|
||||
for (TimeOut = MPU401_TIMEOUT;
|
||||
Status = (MPU401_READ_DATA(BasePort) & 0xfe) && TimeOut > 0;
|
||||
TimeOut --);
|
||||
}
|
||||
|
||||
DbgPrint("Entering UART mode\n");
|
||||
// Now we kick the MPU401 into UART ("dumb") mode
|
||||
MPU401_WRITE_COMMAND(BasePort, 0x3f);
|
||||
|
||||
return TRUE;
|
||||
}
|
28
reactos/drivers/dd/mpu401/readme.txt
Normal file
28
reactos/drivers/dd/mpu401/readme.txt
Normal file
|
@ -0,0 +1,28 @@
|
|||
----------------------------------
|
||||
REACTOS MPU-401 MIDI DEVICE DRIVER
|
||||
by Andrew Greenwood
|
||||
----------------------------------
|
||||
|
||||
This driver initializes the MPU-401 MIDI/joystick port found on
|
||||
most sound cards, and allows the sending of simple messages.
|
||||
|
||||
It's far from complete, and at present will only support 1 device.
|
||||
|
||||
In Bochs, the MIDI output will be played using whatever device is
|
||||
set up in Windows as your MIDI output.
|
||||
|
||||
For real hardware, the output will be played to whatever device is
|
||||
attached to your MIDI/joystick port, or, in some cases, the wave-table
|
||||
or other synth on-board your card (note: this is NOT an FM synth
|
||||
driver!)
|
||||
|
||||
|
||||
Thanks to Vizzini and all the other great ReactOS developers for
|
||||
helping me code this driver and also for giving me encouragement.
|
||||
|
||||
I'd also like to thank Jeff Glatt, whose MIDI and MPU-401
|
||||
documentation has been a valuable resource to me over the past few
|
||||
years, and who provided me with almost all of my knowledge of MIDI
|
||||
and MPU-401. His site is at: www.borg.com/~jglatt/
|
||||
|
||||
- Andrew "Silver Blade" Greenwood
|
24
reactos/drivers/dd/mpu401/sbdebug.h
Normal file
24
reactos/drivers/dd/mpu401/sbdebug.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef NDEBUG
|
||||
#define TEST_STATUS(s) \
|
||||
if (! NT_SUCCESS(s)) \
|
||||
{ \
|
||||
if (s == STATUS_NO_MORE_ENTRIES) \
|
||||
DPRINT("NTSTATUS == NO MORE ENTRIES\n") \
|
||||
else if (s == STATUS_BUFFER_OVERFLOW) \
|
||||
DPRINT("NTSTATUS == BUFFER OVERFLOW\n") \
|
||||
else if (s == STATUS_BUFFER_TOO_SMALL) \
|
||||
DPRINT("NTSTATUS == BUFFER TOO SMALL\n") \
|
||||
else if (s == STATUS_INVALID_PARAMETER) \
|
||||
DPRINT("NTSTATUS == INVALID PARAMETER\n") \
|
||||
else if (s == STATUS_OBJECT_NAME_NOT_FOUND) \
|
||||
DPRINT("NTSTATUS == OBJECT NAME NOT FOUND\n") \
|
||||
else if (s == STATUS_INVALID_HANDLE) \
|
||||
DPRINT("NTATATUS == INVALID_HANDLE\n") \
|
||||
else if (s == STATUS_ACCESS_DENIED) \
|
||||
DPRINT("NTSTATUS == ACCESS_DENIED\n") \
|
||||
else \
|
||||
DPRINT("NTSTATUS == FAILURE (???)\n"); \
|
||||
}
|
||||
#else
|
||||
#define TEST_STATUS(s)
|
||||
#endif
|
306
reactos/drivers/dd/mpu401/settings.c
Normal file
306
reactos/drivers/dd/mpu401/settings.c
Normal file
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: services/dd/mpu401/settings.c
|
||||
* PURPOSE: MPU-401 MIDI device driver setting management
|
||||
* PROGRAMMER: Andrew Greenwood
|
||||
* UPDATE HISTORY:
|
||||
* Sept 27, 2003: Created
|
||||
*/
|
||||
|
||||
#include <ntddk.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "mpu401.h"
|
||||
|
||||
// #define NDEBUG
|
||||
#include <debug.h>
|
||||
#include "sbdebug.h" // our own debug helper
|
||||
|
||||
|
||||
NTSTATUS
|
||||
OpenDevicesKey(
|
||||
IN PWSTR RegistryPath,
|
||||
OUT PHANDLE Key)
|
||||
/*
|
||||
Description:
|
||||
Create a volatile key under this driver's Services node to contain
|
||||
the device name list.
|
||||
|
||||
Parameters:
|
||||
RegistryPath The location of the registry entry
|
||||
Key The key in the registry
|
||||
|
||||
Return Value:
|
||||
NT status STATUS_SUCCESS if successful (duh...)
|
||||
*/
|
||||
{
|
||||
NTSTATUS s;
|
||||
HANDLE hKey;
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
UNICODE_STRING uStr;
|
||||
|
||||
// Attempt to open the key
|
||||
|
||||
RtlInitUnicodeString(&uStr, RegistryPath);
|
||||
|
||||
InitializeObjectAttributes(&oa, &uStr, OBJ_CASE_INSENSITIVE, NULL,
|
||||
(PSECURITY_DESCRIPTOR)NULL);
|
||||
|
||||
s = ZwOpenKey(&hKey, KEY_CREATE_SUB_KEY, &oa);
|
||||
|
||||
if (! NT_SUCCESS(s))
|
||||
return s; // Problem
|
||||
|
||||
|
||||
// Now create sub key
|
||||
|
||||
RtlInitUnicodeString(&uStr, (PWSTR) DEVICE_SUBKEY);
|
||||
|
||||
InitializeObjectAttributes(&oa, &uStr, OBJ_CASE_INSENSITIVE, hKey,
|
||||
(PSECURITY_DESCRIPTOR)NULL);
|
||||
|
||||
s = ZwCreateKey(Key, KEY_ALL_ACCESS, &oa, 0, NULL, REG_OPTION_VOLATILE,
|
||||
NULL);
|
||||
|
||||
ZwClose(hKey);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NTSTATUS EnumDeviceKeys(
|
||||
IN PUNICODE_STRING RegistryPath,
|
||||
IN PWSTR SubKey,
|
||||
IN PREGISTRY_CALLBACK_ROUTINE Callback,
|
||||
IN PVOID Context)
|
||||
/*
|
||||
Description:
|
||||
Enumerate the device subkeys in the driver's registry entry, and
|
||||
call the specified callback routine for each device.
|
||||
|
||||
Parameters:
|
||||
RegistryPath The location of the registry entry
|
||||
Subkey The device's subkey
|
||||
Callback A routine called for each device
|
||||
Context ???
|
||||
|
||||
Return Value:
|
||||
NT status STATUS_SUCCESS if successful
|
||||
*/
|
||||
{
|
||||
NTSTATUS s;
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
HANDLE hKey, hSubKey;
|
||||
UNICODE_STRING SubkeyName;
|
||||
ULONG i;
|
||||
|
||||
// Attempt to open the key
|
||||
|
||||
InitializeObjectAttributes(&oa, RegistryPath, OBJ_CASE_INSENSITIVE,
|
||||
NULL, (PSECURITY_DESCRIPTOR)NULL);
|
||||
|
||||
s = ZwOpenKey(&hKey, KEY_READ, &oa);
|
||||
|
||||
TEST_STATUS(s); // debugging
|
||||
|
||||
if (! NT_SUCCESS(s))
|
||||
return s; // Problem
|
||||
|
||||
RtlInitUnicodeString(&SubkeyName, SubKey);
|
||||
|
||||
DPRINT("Subkey: %wZ\n", &SubkeyName);
|
||||
|
||||
InitializeObjectAttributes(&oa, &SubkeyName, OBJ_CASE_INSENSITIVE,
|
||||
hKey, (PSECURITY_DESCRIPTOR)NULL);
|
||||
|
||||
s = ZwOpenKey(&hSubKey, KEY_ENUMERATE_SUB_KEYS, &oa);
|
||||
|
||||
ZwClose(hKey);
|
||||
|
||||
TEST_STATUS(s); // debugging
|
||||
|
||||
if (! NT_SUCCESS(s))
|
||||
return s;
|
||||
|
||||
|
||||
// And now, the enumeration
|
||||
|
||||
for (i = 0;; i ++)
|
||||
{
|
||||
KEY_BASIC_INFORMATION Info;
|
||||
PKEY_BASIC_INFORMATION pInfo;
|
||||
ULONG ResultLength = 0;
|
||||
ULONG Size = 0;
|
||||
PWSTR Pos;
|
||||
PWSTR Name;
|
||||
|
||||
// Find the length of the subkey data
|
||||
|
||||
// Info.NameLength = 0; // TEMPORARY!
|
||||
|
||||
s = ZwEnumerateKey(hSubKey, i, KeyBasicInformation, &Info,
|
||||
sizeof(Info), &ResultLength);
|
||||
|
||||
if (s == STATUS_NO_MORE_ENTRIES)
|
||||
break;
|
||||
|
||||
DPRINT("Found an entry, allocating memory...\n");
|
||||
|
||||
// Size = Info.NameLength + FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
|
||||
Size = ResultLength + FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
|
||||
|
||||
DPRINT("Size is %d\n", Size);
|
||||
|
||||
pInfo = (PKEY_BASIC_INFORMATION) ExAllocatePool(PagedPool, Size);
|
||||
|
||||
if (pInfo == NULL)
|
||||
{
|
||||
DPRINT("INSUFFICIENT RESOURCES!\n");
|
||||
s = STATUS_INSUFFICIENT_RESOURCES;
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINT("Re-enumerating...\n");
|
||||
|
||||
s = ZwEnumerateKey(hSubKey, i, KeyBasicInformation, pInfo, Size,
|
||||
&ResultLength);
|
||||
|
||||
// TEST_STATUS(s); // debugging
|
||||
|
||||
if (! NT_SUCCESS(s))
|
||||
{
|
||||
ExFreePool((PVOID) pInfo);
|
||||
s = STATUS_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINT("Allocating memory for name...\n");
|
||||
|
||||
Name = ExAllocatePool(PagedPool,
|
||||
RegistryPath->Length + sizeof(WCHAR) +
|
||||
SubkeyName.Length + sizeof(WCHAR) +
|
||||
pInfo->NameLength + sizeof(UNICODE_NULL));
|
||||
|
||||
if (Name == NULL)
|
||||
{
|
||||
DPRINT("INSUFFICIENT RESOURCES!");
|
||||
ExFreePool((PVOID) pInfo);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
// Copy the key name
|
||||
RtlCopyMemory((PVOID)Name, (PVOID)RegistryPath->Buffer, RegistryPath->Length);
|
||||
Pos = Name + (RegistryPath->Length / sizeof(WCHAR));
|
||||
Pos[0] = '\\';
|
||||
Pos++;
|
||||
|
||||
// Copy the parameters sub key name
|
||||
RtlCopyMemory((PVOID)Pos, (PVOID)SubKey, SubkeyName.Length); //SubkeyName?
|
||||
Pos += SubkeyName.Length / sizeof(WCHAR);
|
||||
Pos[0] = '\\';
|
||||
Pos ++;
|
||||
|
||||
// Copy the device sub key name
|
||||
RtlCopyMemory((PVOID)Pos, (PVOID)pInfo->Name, pInfo->NameLength);
|
||||
Pos += pInfo->NameLength / sizeof(WCHAR);
|
||||
Pos[0] = UNICODE_NULL;
|
||||
|
||||
ExFreePool((PVOID)pInfo);
|
||||
|
||||
DPRINT("Calling callback...\n");
|
||||
|
||||
s = (*Callback)(Name, Context);
|
||||
|
||||
if (! NT_SUCCESS(s))
|
||||
{ DPRINT("Callback FAILED\n");
|
||||
break;}
|
||||
}
|
||||
|
||||
ZwClose(hSubKey);
|
||||
|
||||
DPRINT("%d device registry keys found\n", i);
|
||||
|
||||
if ((i == 0) && (s == STATUS_NO_MORE_ENTRIES))
|
||||
return STATUS_DEVICE_CONFIGURATION_ERROR;
|
||||
|
||||
return s == STATUS_NO_MORE_ENTRIES ? STATUS_SUCCESS : s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NTSTATUS LoadSettings(
|
||||
IN PWSTR ValueName,
|
||||
IN ULONG ValueType,
|
||||
IN PVOID ValueData,
|
||||
IN ULONG ValueLength,
|
||||
IN PVOID Context,
|
||||
IN PVOID EntryContext)
|
||||
/*
|
||||
Description:
|
||||
Read the settings for a particular device
|
||||
|
||||
Parameters:
|
||||
ValueName The value to read from the registry
|
||||
ValueType ?
|
||||
ValueData ?
|
||||
ValueLength ?
|
||||
Context The configuration structure to write to
|
||||
EntryContext ?
|
||||
|
||||
Return Value:
|
||||
NT status STATUS_SUCCESS if successful
|
||||
*/
|
||||
{
|
||||
PDEVICE_EXTENSION DeviceInfo = Context;
|
||||
|
||||
if (ValueType == REG_DWORD)
|
||||
{
|
||||
if (! _wcsicmp(ValueName, REGISTRY_PORT))
|
||||
{
|
||||
DeviceInfo->Port = *(PULONG) ValueData;
|
||||
DPRINT("Registry port = 0x%x\n", DeviceInfo->Port);
|
||||
}
|
||||
|
||||
// More to come... (config.c)
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// ?
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NTSTATUS SaveSettings(
|
||||
IN PWSTR RegistryPath,
|
||||
IN ULONG Port,
|
||||
IN ULONG IRQ,
|
||||
IN ULONG DMA)
|
||||
/*
|
||||
Description:
|
||||
Saves the settings for a particular device
|
||||
|
||||
Parameters:
|
||||
RegistryPath Where to save the settings to
|
||||
Port The device's port number
|
||||
IRQ The device's interrupt number
|
||||
DMA The device's DMA channel
|
||||
|
||||
Return Value:
|
||||
NT status STATUS_SUCCESS if successful
|
||||
*/
|
||||
{
|
||||
NTSTATUS s;
|
||||
|
||||
DPRINT("SaveSettings() unimplemented\n");
|
||||
|
||||
// UNIMPLEMENTED;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
70
reactos/drivers/dd/mpu401/test.c
Normal file
70
reactos/drivers/dd/mpu401/test.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <ddk/ntddk.h>
|
||||
#include "mpu401.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
// NTSTATUS s;
|
||||
// PHANDLE Handle;
|
||||
// PIO_STATUS_BLOCK Status;
|
||||
DWORD BytesReturned;
|
||||
BYTE Test[3]; // Will store MIDI data
|
||||
BYTE Notes[] = {50, 52, 54, 55, 57, 59, 61};
|
||||
HANDLE Device;
|
||||
UINT Note;
|
||||
UINT Junk;
|
||||
|
||||
printf("Test program for MPU401 driver\n");
|
||||
|
||||
Device = CreateFile("\\\\.\\MPU401_Out_0", GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_NO_BUFFERING,
|
||||
NULL);
|
||||
|
||||
if (Device == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
printf("Device is busy or could not be found.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Device is open, let's play some music...\n");
|
||||
|
||||
Test[0] = 0x90;
|
||||
Test[2] = 0x7f;
|
||||
|
||||
for (Note = 0; Note < sizeof(Notes); Note ++)
|
||||
{
|
||||
Test[1] = Notes[Note];
|
||||
|
||||
DeviceIoControl(
|
||||
Device,
|
||||
IOCTL_MIDI_PLAY,
|
||||
&Test,
|
||||
sizeof(Test),
|
||||
NULL,
|
||||
0,
|
||||
&BytesReturned,
|
||||
NULL
|
||||
);
|
||||
|
||||
for (Junk = 0; Junk < 100000; Junk ++); // Pause
|
||||
}
|
||||
|
||||
|
||||
/* s = IoCreateFile(Handle, GENERIC_READ | GENERIC_WRITE,
|
||||
OBJ_KERNEL_HANDLE,
|
||||
Status,
|
||||
0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
FILE_OPEN,
|
||||
FILE_NON_DIRECTORY_FILE,
|
||||
NULL,
|
||||
0,
|
||||
CreateFileTypeNone,
|
||||
NULL,
|
||||
0);
|
||||
*/
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue