mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 04:11:30 +00:00
469 lines
12 KiB
C
469 lines
12 KiB
C
/*
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: services/dd/sndblst/sndblst.c
|
|
* PURPOSE: Sound Blaster / SB Pro / SB 16 driver
|
|
* PROGRAMMER: Andrew Greenwood
|
|
* UPDATE HISTORY:
|
|
* Sept 28, 2003: Copied from mpu401.c as a template
|
|
*/
|
|
|
|
/* INCLUDES ****************************************************************/
|
|
|
|
#include <ntddk.h>
|
|
#include "sndblst.h"
|
|
|
|
NTSTATUS NTAPI
|
|
DriverEntry(PDRIVER_OBJECT DriverObject,
|
|
PUNICODE_STRING RegistryPath);
|
|
|
|
/* INTERNAL VARIABLES ******************************************************/
|
|
|
|
ULONG DeviceCount = 0;
|
|
|
|
|
|
/* FUNCTIONS ***************************************************************/
|
|
|
|
static NTSTATUS InitDevice(
|
|
IN PWSTR 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\\WaveOut0"); // CHANGE THESE?
|
|
UNICODE_STRING SymlinkName = RTL_CONSTANT_STRING(L"\\??\\WaveOut0");
|
|
|
|
// CONFIG Config;
|
|
RTL_QUERY_REGISTRY_TABLE Table[2];
|
|
NTSTATUS s;
|
|
USHORT DSP_Version = 0;
|
|
UCHAR DSP_Major = 0, DSP_Minor = 0;
|
|
|
|
// This is TEMPORARY, to ensure that we don't process more than 1 device.
|
|
// This limitation should be removed in future.
|
|
if (DeviceCount > 0)
|
|
{
|
|
DPRINT("Sorry - only 1 device supported by Sound Blaster 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 */
|
|
s = IoCreateSymbolicLink(&SymlinkName,
|
|
&DeviceName);
|
|
|
|
if (!NT_SUCCESS(s))
|
|
{
|
|
IoDeleteDevice(DeviceObject);
|
|
return s;
|
|
}
|
|
|
|
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;
|
|
Parameters->DMA = DEFAULT_DMA;
|
|
Parameters->BufferSize = DEFAULT_BUFSIZE;
|
|
|
|
// 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 DMA %d\n", Parameters->Port, Parameters->IRQ, Parameters->DMA);
|
|
|
|
// Instance->P
|
|
|
|
// Initialize the card
|
|
DSP_Version = InitSoundCard(Parameters->Port);
|
|
if (! DSP_Version)
|
|
{
|
|
DPRINT("Sound card initialization FAILED!\n");
|
|
// Set state indication somehow
|
|
// Failure - what error code do we give?!
|
|
// return STATUS_????
|
|
IoDeleteDevice(DeviceObject);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
DSP_Major = DSP_Version / 256;
|
|
DSP_Minor = DSP_Version % 256;
|
|
|
|
// Do stuff related to version here...
|
|
|
|
DPRINT("Allocating DMA\n");
|
|
if (! CreateDMA(DeviceObject))
|
|
DPRINT("FAILURE!\n");
|
|
|
|
// TEMPORARY TESTING STUFF: should be in BlasterCreate
|
|
EnableSpeaker(Parameters->Port, TRUE);
|
|
SetOutputSampleRate(Parameters->Port, 2205);
|
|
BeginPlayback(Parameters->Port, 16, 2, Parameters->BufferSize);
|
|
|
|
DeviceCount ++;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
static NTSTATUS NTAPI
|
|
BlasterCreate(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("BlasterCreate() 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;
|
|
|
|
DPRINT("IoCompleteRequest()\n");
|
|
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
|
|
DPRINT("BlasterCreate() completed\n");
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
static NTSTATUS NTAPI
|
|
BlasterClose(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("BlasterClose() 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
|
|
BlasterCleanup(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("BlasterCleanup() 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
|
|
BlasterWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION Stack;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
ULONG ByteCount;
|
|
PUCHAR Data;
|
|
|
|
DPRINT("BlasterWrite() called!\n");
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DPRINT("%d bytes\n", Stack->Parameters.Write.Length);
|
|
|
|
Data = (PUCHAR) Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
for (ByteCount = 0; ByteCount < Stack->Parameters.Write.Length; ByteCount ++)
|
|
{
|
|
// DPRINT("0x%x ", Data[ByteCount]);
|
|
|
|
// MPU401_WRITE_BYTE(DeviceExtension->Port, Data[ByteCount]);
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest(Irp,
|
|
IO_NO_INCREMENT);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
static NTSTATUS NTAPI
|
|
BlasterDeviceControl(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;
|
|
|
|
DPRINT("BlasterDeviceControl() called!\n");
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
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
|
|
BlasterUnload(PDRIVER_OBJECT DriverObject)
|
|
{
|
|
DPRINT("BlasterUnload() 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("Sound Blaster Device Driver 0.0.2\n");
|
|
|
|
// Instance.DriverObject = DriverObject;
|
|
// previous instance = NULL...
|
|
|
|
// DeviceExtension->RegistryPath = RegistryPath;
|
|
|
|
DriverObject->Flags = 0;
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = BlasterCreate;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = BlasterClose;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = BlasterCleanup;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = BlasterDeviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = BlasterWrite;
|
|
DriverObject->DriverUnload = BlasterUnload;
|
|
|
|
// Major hack to just get this damn thing working:
|
|
Status = InitDevice(RegistryPath->Buffer, 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);
|
|
return(Status);
|
|
}
|
|
|
|
/* EOF */
|