Yet more files I've been meaning to commit...

(and again they're mostly incomplete)


svn path=/trunk/; revision=26103
This commit is contained in:
Andrew Greenwood 2007-03-14 21:31:31 +00:00
parent b4da8c5ab8
commit 30bfd875a8
14 changed files with 1823 additions and 0 deletions

View file

@ -0,0 +1,137 @@
#include "sb16.h"
class CAdapterSB16 :
public IAdapterSB16,
public IAdapterPowerManagement,
public CUnknown
{
public :
DECLARE_STD_UNKNOWN();
DEFINE_STD_CONSTRUCTOR(CAdapterSB16);
~CAdapterSB16();
STDMETHODIMP_(NTSTATUS) Init(
IN PRESOURCELIST ResourceList,
IN PDEVICE_OBJECT DeviceObject);
STDMETHODIMP_(PINTERRUPTSYNC) GetInterruptSync(void);
STDMETHODIMP_(void) SetWaveMiniport(
IN PWAVEMINIPORTSB16 Miniport);
STDMETHODIMP_(BYTE) Read(void);
STDMETHODIMP_(BOOLEAN) Write(
IN BYTE Value);
STDMETHODIMP_(NTSTATUS) Reset(void);
STDMETHODIMP_(void) SetMixerValue(
IN BYTE Index,
IN BYTE Value);
STDMETHODIMP_(BYTE) GetMixerValue(
IN BYTE Index);
STDMETHODIMP_(void) ResetMixer(void);
//IMP_IAdapterPowerManagement;
};
NTSTATUS
NewAdapter(
OUT PUNKNOWN* Unknown,
IN REFCLSID,
IN PUNKNOWN UnknownOuter OPTIONAL,
IN POOL_TYPE PoolType)
{
STD_CREATE_BODY_( CAdapterSB16, Unknown, UnknownOuter, PoolType, PADAPTERSB16 );
}
NTSTATUS CAdapterSB16::Init(
IN PRESOURCELIST ResourceList,
IN PDEVICE_OBJECT DeviceObject)
{
return STATUS_UNSUCCESSFUL;
}
CAdapterSB16::~CAdapterSB16()
{
}
/*
STDMETHODIMP
CAdapterSB16::NonDelegatingQueryInterface(
REFIID Interface,
PVOID* Object)
{
return STATUS_UNSUCCESSFUL;
}
*/
STDMETHODIMP_(PINTERRUPTSYNC)
CAdapterSB16::GetInterruptSync()
{
return NULL;
}
STDMETHODIMP_(BYTE)
CAdapterSB16::Read()
{
return 0x00;
}
STDMETHODIMP_(BOOLEAN)
CAdapterSB16::Write(
IN BYTE Value)
{
return FALSE;
}
STDMETHODIMP_(NTSTATUS)
CAdapterSB16::Reset()
{
return STATUS_UNSUCCESSFUL;
}
STDMETHODIMP_(void)
CAdapterSB16::SetMixerValue(
IN BYTE Index,
IN BYTE Value)
{
}
STDMETHODIMP_(BYTE)
CAdapterSB16::GetMixerValue(
IN BYTE Index)
{
return 0x00;
}
STDMETHODIMP_(void)
CAdapterSB16::ResetMixer()
{
}
/*
STDMETHODIMP_(void)
CAdapterSB16::PowerChangeState(
IN POWER_STATE NewState)
{
}
STDMETHODIMP_(NTSTATUS)
CAdapterSB16::QueryPowerChangeState(
IN POWER_STATE NewStateQuery)
{
return STATUS_UNSUCCESSFUL;
}
STDMETHODIMP_(NTSTATUS)
CAdapterSB16::QueryDeviceCapabilities(
IN PDEVICE_CAPABILITIES)
{
return STATUS_UNSUCCESSFUL;
}
*/

View file

@ -0,0 +1,356 @@
/*
ReactOS Operating System
Sound Blaster KS Driver
AUTHORS:
Andrew Greenwood
NOTES:
WaveTable is not supported.
*/
#include <sb16.h>
/* How many miniports do we support? */
#define MAX_MINIPORTS 1
typedef struct
{
PRESOURCELIST Wave;
PRESOURCELIST WaveTable;
PRESOURCELIST FmSynth;
PRESOURCELIST Uart;
PRESOURCELIST Adapter;
} Resources;
DWORD
DetectPlatform(
PPORTTOPOLOGY Port)
{
/* ASSERT(Port); */
PPORTCLSVERSION portcls_version;
PDRMPORT drm_port;
PPORTEVENTS port_events;
DWORD version;
/*
TODO: This stuff needs IID impls
Port->QueryInterface( IID_IPortClsVersion, (PVOID*) &portcls_version);
Port->QueryInterface( IID_IDrmPort, (PVOID*) &drm_port);
Port->QueryInterface( IID_IPortEvents, (PVOID*) &port_events);
*/
if ( portcls_version )
{
version = portcls_version->GetVersion();
portcls_version->Release();
}
/* If we don't support portcls' GetVersion, we can try other methods */
else if ( drm_port )
{
version = kVersionWinME;
// ASSERT(IoIsWdmVersionAvailable(0x01, 0x05));
}
/* If portcls GetVersion and DRMPort not supported, it'll be Win98 */
else if ( port_events )
{
version = kVersionWin98SE;
}
/* IPortEvents was added in Win 98 SE so if not supported, it's not 98 SE */
else
{
version = kVersionWin98;
}
return version;
}
NTSTATUS
DetectFeatures(
IN PRESOURCELIST ResourceList,
OUT PBOOLEAN HasUart,
OUT PBOOLEAN HasFmSynth,
OUT PBOOLEAN HasWaveTable)
{
NTSTATUS status = STATUS_SUCCESS;
BOOLEAN DetectedWaveTable = FALSE;
BOOLEAN DetectedUart = FALSE;
BOOLEAN DetectedFmSynth = FALSE;
ULONG IoCount = ResourceList->NumberOfPorts();
ULONG IrqCount = ResourceList->NumberOfInterrupts();
ULONG DmaCount = ResourceList->NumberOfDmas();
switch ( IoCount )
{
case 1 : /* No FM / UART */
{
if ( ( ResourceList->FindTranslatedPort(0)->u.Port.Length < 16 ) ||
( IrqCount < 1 ) ||
( DmaCount < 1 ) )
{
status = STATUS_DEVICE_CONFIGURATION_ERROR;
}
break;
case 2 :
{
if ( ( ResourceList->FindTranslatedPort(0)->u.Port.Length < 16 ) ||
( IrqCount < 1 ) ||
( DmaCount < 1 ) )
{
status = STATUS_DEVICE_CONFIGURATION_ERROR;
}
else
{
/* The length of the port indicates the function provided */
switch ( ResourceList->FindTranslatedPort(1)->u.Port.Length )
{
case 2 :
{
DetectedUart = TRUE;
break;
}
case 4:
{
DetectedFmSynth = TRUE;
break;
}
default :
{
status = STATUS_DEVICE_CONFIGURATION_ERROR;
}
}
}
break;
}
case 3 :
{
if ( ( ResourceList->FindTranslatedPort(0)->u.Port.Length < 16 ) ||
( ResourceList->FindTranslatedPort(1)->u.Port.Length != 2 ) ||
( ResourceList->FindTranslatedPort(2)->u.Port.Length != 4 ) ||
( IrqCount < 1 ) ||
( DmaCount < 1 ) )
{
status = STATUS_DEVICE_CONFIGURATION_ERROR;
}
else
{
DetectedUart = TRUE;
DetectedFmSynth = TRUE;
}
break;
}
default :
{
status = STATUS_DEVICE_CONFIGURATION_ERROR;
break;
}
}
if ( HasUart )
*HasUart = DetectedUart;
if ( HasFmSynth )
*HasFmSynth = DetectedFmSynth;
if ( HasWaveTable )
*HasWaveTable = DetectedWaveTable;
return status;
}
NTSTATUS
AssignResources(
IN PRESOURCELIST ResourceList,
OUT Resources* Resources)
{
NTSTATUS status;
BOOLEAN HasUart, HasFmSynth, HasWaveTable;
Resources->Adapter = NULL;
Resources->Wave = NULL;
Resources->Uart = NULL;
Resources->FmSynth = NULL;
Resources->WaveTable = NULL;
status = DetectFeatures(ResourceList, &HasUart, &HasFmSynth, &HasWaveTable);
if ( ! NT_SUCCESS(status) )
{
return status;
}
/* Wave I/O resources */
status = PcNewResourceSublist(Resources->Wave,
NULL,
PagedPool,
ResourceList,
ResourceList->NumberOfDmas() +
ResourceList->NumberOfInterrupts + 1);
if ( NT_SUCCESS(status) )
{
ULONG i;
/* Base port address */
status = (*Resources->Wave)->AddPortFromParent(ResourceList, 0);
/* DMA channels */
if ( NT_SUCCESS(status) )
{
for ( i = 0; i < ResourceList->NumberOfDmas(); i ++ )
{
status = (*Resources->Wave)->AddDmaFromParent(ResourceList, i);
if ( ! NT_SUCCESS(status) )
break;
}
}
/* IRQs */
if ( NT_SUCCESS(status) )
{
for ( i = 0; i < ResourceList->NumberOfInterrupts(); i ++ )
{
status = (*Resources->Wave)->AddInterruptFromParent(ResourceList, i);
if ( ! NT_SUCCESS(status) )
break;
}
}
}
/* UART resources */
if ( NT_SUCCESS(status) && HasUart )
{
/* TODO */
}
/* FM Synth resources */
if ( NT_SUCCESS(status) && HasFmSynth )
{
/* TODO */
}
/* Adapter resources */
if ( NT_SUCCESS(status) )
{
status = PcNewResourceSublist(Resources->Adapter,
NULL,
PagedPool,
ResourceList,
3);
if ( NT_SUCCESS(status) )
{
status = (*Resources->Adapter)->AddInterruptFromParent(ResourceList, 0);
}
if ( NT_SUCCESS(status) )
{
status = (*Resources->Adapter)->AddPortFromParent(ResourceList, 0);
}
if ( NT_SUCCESS(status) && HasUart )
{
/* TODO */
}
}
/* Cleanup - TODO: Make this cleanup UART, FM etc. */
if ( ! NT_SUCCESS(status) )
{
if ( *Resources->Wave )
{
(*Resources->Wave)->Release();
*Resources->Wave = NULL;
}
if ( *Resources->Adapter )
{
(*Resources->Adapter)->Release();
*Resources->Adapter = NULL;
}
}
return status;
}
NTSTATUS
StartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PRESOURCELIST ResourceList)
{
NTSTATUS status = STATUS_SUCCESS;
Resources DeviceResources;
PUNKNOWN UnknownTopology = NULL;
PUNKNOWN UnknownWave = NULL;
PUNKNOWN UnknownWaveTable = NUL;
PUNKNOWN UnknownFmSynth = NULL;
PADAPTERCOMMON AdapterCommon = NULL;
PUNKNOWN UnknownCommon = NULL;
status = AssignResources(ResourceList, &DeviceResources);
if ( NT_SUCCESS(status) )
{
}
return status;
}
extern "C"
NSTATUS
AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
return PcAddAdapterDevice(DriverObject,
PhysicalDeviceObject,
StartDevice,
MAX_MINIPORTS,
0);
}
extern "C"
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPathName)
{
NTSTATUS status;
status = PcInitializeAdapterDriver(DriverObject,
RegistryPathName,
AddDevice);
/* TODO: Add our own IRP handlers here */
return status;
}

View file

@ -0,0 +1,141 @@
/*
ReactOS Operating System
Sound Blaster KS Driver
AUTHORS:
Andrew Greenwood
NOTES:
Ah, the Sound Blaster 16. I remember it well...
*/
#include <portcls.h>
#include <stdunk.h>
#ifndef SB16_H
#define SB16_H
#define MAX_DMA_BUFFER_SIZE 65536
enum DspRegister
{
DspRegCMSD0 = 0x00,
DspRegCMSR0 = 0x01,
DspRegCMSD1 = 0x02,
DspRegCMSR1 = 0x03,
DspRegMixerReg = 0x04,
DspRegMixerData = 0x05,
DspRegReset = 0x06,
DspRegFMD0 = 0x08,
DspRegFMR0 = 0x09,
DspRegRead = 0x0a,
DspRegWrite = 0x0c,
DspRegDataAvailable = 0x0e,
DspRegAck8 = 0x0e,
DspRegAck16 = 0x0f
};
enum DspCommand
{
DspWriteWaveProgrammedIo = 0x10,
DspWriteWave = 0x14,
DspWriteWaveAuto = 0x1c,
DspReadWave = 0x24,
DspReadWaveAuto = 0x2C,
DspWriteHighSpeedWave = 0x90,
DspReadHighSpeedWave = 0x98,
DspSetSampleRate = 0x40,
DspSetBlockSize = 0x48,
DspEnableOutput = 0xd1,
DspDisableOutput = 0xd3,
DspOutputStatus = 0xd8,
DspPauseDma = 0xd0,
DspContinueDma = 0xd4,
DspHaltAutoDma = 0xda,
DspInverter = 0xe0,
DspGetVersion = 0xe1,
DspGenerateInterrupt = 0xf2,
/* SB16 only */
DspSetDacRate = 0x41,
DspSetAdcRate = 0x42,
DspStartDac16 = 0xb6,
DspStartAdc16 = 0xbe,
DspStartDac8 = 0xc6,
DspStartAdc8 = 0xc3,
DspPauseDma16 = 0xd5,
DspContinueDma16 = 0xd6,
DspHaltAutoDma16 = 0xd9
};
enum DspMixerRegister
{
DspMixMasterVolumeLeft = 0x00,
DspMixMasterVolumeRight = 0x01,
DspMixVoiceVolumeLeft = 0x02,
DspMixVoiceVolumeRight = 0x03,
/* ... */
DspMixIrqConfig = 0x80,
DspMixDmaConfig = 0x81
};
#define MPU401_OUTPUT_READY 0x40
#define MPU401_INPUT_READY 0x80
#define MPU401_RESET 0xff
#define MPU401_UART_MODE 0x3f
DEFINE_GUID(IID_IWaveMiniportSB16,
0xbe23b2d7, 0xa760, 0x43ab, 0xb7, 0x6e, 0xbc, 0x3e, 0x93, 0xe6, 0xff, 0x54);
DECLARE_INTERFACE_(IWaveMiniportSB16, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
STDMETHOD_(void, RestoreSampleRate)( THIS ) PURE;
STDMETHOD_(void, ServiceWaveISR)( THIS ) PURE;
};
typedef IWaveMiniportSB16 *PWAVEMINIPORTSB16;
DEFINE_GUID(IID_IAdapterSB16,
0xfba9052c, 0x0544, 0x4bc4, 0x97, 0x3f, 0x70, 0xb7, 0x06, 0x46, 0x81, 0xe5);
DECLARE_INTERFACE_(IAdapterSB16, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
STDMETHOD_(NTSTATUS, Init)( THIS_
IN PRESOURCELIST ResourceList,
IN PDEVICE_OBJECT DeviceObject) PURE;
STDMETHOD_(PINTERRUPTSYNC, GetInterruptSync)( THIS ) PURE;
STDMETHOD_(void, SetWaveMiniport)( THIS_
IN PWAVEMINIPORTSB16 Miniport) PURE;
STDMETHOD_(BYTE, Read)( THIS ) PURE;
STDMETHOD_(BOOLEAN, Write)( THIS_
IN BYTE Value) PURE;
STDMETHOD_(NTSTATUS, Reset)( THIS ) PURE;
STDMETHOD_(void, SetMixerValue)( THIS_
IN BYTE Index,
IN BYTE Value) PURE;
STDMETHOD_(BYTE, GetMixerValue)( THIS_
IN BYTE Index) PURE;
STDMETHOD_(void, ResetMixer)( THIS ) PURE;
/* TODO - Save/load settings */
};
typedef IAdapterSB16 *PADAPTERSB16;
#endif

View file

@ -0,0 +1,11 @@
<module name="sb16_ks" type="exportdriver" installbase="system32/drivers" installname="sb16_ks.sys" allowwarnings="true">
<include base="sb16_ks">.</include>
<include base="sb16_ks">..</include>
<importlibrary definition="sb16_ks.def" />
<library>ntoskrnl</library>
<library>portcls</library>
<define name="__USE_W32API" />
<file>stdunk.cpp</file>
<file>adapter.cpp</file>
<file>main.cpp</file>
</module>

View file

@ -0,0 +1,6 @@
;
; Exports definition file for sb16_ks.sys
;
EXPORTS
DriverEntry@8

View file

@ -0,0 +1,68 @@
/*
ReactOS Kernel-Mode COM
IUnknown implementations
LICENSE
Please see COPYING in the top-level directory for license information.
AUTHORS
Andrew Greenwood
*/
#include <stdunk.h>
CUnknown::CUnknown(PUNKNOWN outer_unknown)
{
m_ref_count = 0;
if ( outer_unknown )
m_outer_unknown = outer_unknown;
else
m_outer_unknown = PUNKNOWN(dynamic_cast<PNONDELEGATINGUNKNOWN>(this));
}
CUnknown::~CUnknown()
{
}
STDMETHODIMP_(ULONG)
CUnknown::NonDelegatingAddRef()
{
InterlockedIncrement(&m_ref_count);
return m_ref_count;
}
STDMETHODIMP_(ULONG)
CUnknown::NonDelegatingRelease()
{
if ( InterlockedDecrement(&m_ref_count) == 0 )
{
m_ref_count ++;
delete this;
return 0;
}
return m_ref_count;
}
STDMETHODIMP_(NTSTATUS)
CUnknown::NonDelegatingQueryInterface(
IN REFIID iid,
PVOID* ppVoid)
{
/* FIXME */
#if 0
if ( IsEqualGUID(iid, IID_IUnknown) ) /* TODO: Aligned? */
*ppVoid = PVOID(PUNKNOWN(this));
else
*ppVoid = NULL;
#endif
if ( *ppVoid )
{
PUNKNOWN(*ppVoid)->AddRef();
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}

View file

@ -0,0 +1,222 @@
#include <sndblst.h>
/*
TODO: MmMapIoSpace()
*/
/*
This checks the read or write status port of the device.
*/
BOOLEAN
WaitForReady(
PSOUND_BLASTER_PARAMETERS SBDevice,
UCHAR Port)
{
ULONG timeout = SB_TIMEOUT;
BOOL ready = FALSE;
while ( ( ! ready ) && ( timeout > 0 ) )
{
if ( SbRead(SBDevice, Port) & 0x80 )
return TRUE;
timeout --;
}
return FALSE;
}
BOOLEAN
SbWriteData(
PSOUND_BLASTER_PARAMETERS SBDevice,
UCHAR Data)
{
if ( ! WaitToWrite(SBDevice) )
return FALSE;
DPRINT("Writing 0x%x to Sound Blaster card (data)\n", Data);
SbWrite(SBDevice, SB_WRITE_DATA_PORT, Data);
return TRUE;
}
BOOLEAN
SbReadData(
PSOUND_BLASTER_PARAMETERS SBDevice,
PUCHAR Data)
{
if ( ! WaitToWrite(SBDevice) )
return FALSE;
*Data = SbRead(SBDevice, SB_READ_DATA_PORT);
DPRINT("Read 0x%x from Sound Blaster card (data)\n", *Data);
return TRUE;
}
BOOLEAN
ResetSoundBlaster(
PSOUND_BLASTER_PARAMETERS SBDevice)
{
BOOLEAN acked = FALSE;
ULONG timeout;
SbWriteReset(SBDevice, 0x01);
for (timeout = 0; timeout < 30000; timeout ++ );
SbWriteReset(SBDevice, 0x00);
DPRINT("Waiting for SB to acknowledge our reset request\n");
if ( ! WaitToRead(SBDevice) )
{
DPRINT("Didn't get an ACK :(\n");
return FALSE;
}
timeout = 0;
while ( ( ! acked ) && ( timeout < SB_TIMEOUT ) )
{
acked = ( SbReadDataWithoutWait(SBDevice) == SB_DSP_READY );
timeout ++;
}
if ( ! acked )
{
DPRINT("Didn't get an ACK :(\n");
return FALSE;
}
return TRUE;
}
ULONG
GetSoundBlasterModel(
PSOUND_BLASTER_PARAMETERS SBDevice)
{
UCHAR MajorVer, MinorVer;
DPRINT("Querying DSP version\n");
if ( ! SbWriteData(SBDevice, SbGetDspVersion) )
return NotDetected;
if ( ! WaitToRead(SBDevice) )
return NotDetected;
if ( SbReadData(SBDevice, &MajorVer) )
{
if ( SbReadData(SBDevice, &MinorVer) )
{
DPRINT("Version %d.%d\n", MajorVer, MinorVer);
SBDevice->dsp_version = (MajorVer * 256) + MinorVer;
if ( SBDevice->dsp_version < 0x0200 )
return SoundBlaster;
else if ( ( SBDevice->dsp_version & 0xFF00 ) == 0x0200 )
return SoundBlaster2;
else if ( ( SBDevice->dsp_version & 0xFF00 ) == 0x0300 )
return SoundBlasterPro;
else if ( SBDevice->dsp_version >= 0x0400 )
return SoundBlaster16;
return NotDetected;
}
}
return NotDetected;
}
BOOLEAN
IsSampleRateCompatible(
PSOUND_BLASTER_PARAMETERS SBDevice,
ULONG SampleRate)
{
/* TODO */
return TRUE;
}
BOOLEAN
SetOutputSampleRate(
PSOUND_BLASTER_PARAMETERS SBDevice,
ULONG SampleRate)
{
/* Only works for DSP v4.xx */
DPRINT("Setting sample rate\n");
SbWriteData(SBDevice, SbSetOutputRate);
SbWriteData(SBDevice, SampleRate / 256);
SbWriteData(SBDevice, SampleRate % 256);
return TRUE;
}
BOOLEAN
EnableSpeaker(
PSOUND_BLASTER_PARAMETERS SBDevice)
{
DPRINT("Enabling speaker\n");
return SbWriteData(SBDevice, SbEnableSpeaker);
}
BOOLEAN
DisableSpeaker(
PSOUND_BLASTER_PARAMETERS SBDevice)
{
DPRINT("Disabling speaker\n");
return SbWriteData(SBDevice, SbDisableSpeaker);
}
BOOLEAN
StartSoundOutput(
PSOUND_BLASTER_PARAMETERS SBDevice,
ULONG BitDepth,
ULONG Channels,
ULONG BlockSize)
{
DPRINT("Initializing output with %d channels at %d bits/sample\n", Channels, BitDepth);
UCHAR command = 0xc6, mode = 0x00;
if ( ( Channels < 1 ) || ( Channels > 2 ) )
return FALSE;
if ( ( BitDepth != 8 ) && ( BitDepth != 16 ) )
return FALSE;
switch ( BitDepth )
{
case 8 : command = 0xc6; break;
case 16 : command = 0xb6; break;
};
switch ( Channels )
{
case 1 : mode = 0x00; break;
case 2 : mode = 0x20; break;
}
#if 0
first_byte = (BitDepth == 16) ? 0xb6 : 0xc6;
second_byte = (Channels == 1) ? 0x20 : 0x00;
#endif
if ( SBDevice->dsp_version < 0x0400 )
{
/* TODO: Additional programming required */
}
/* Send freq */
SbWriteData(SBDevice, command);
SbWriteData(SBDevice, mode);
SbWriteData(SBDevice, BlockSize % 256);
SbWriteData(SBDevice, BlockSize / 256);
DPRINT("Finished programming the DSP\n");
return TRUE;
}

View file

@ -0,0 +1,61 @@
/*
*/
#include <sndblst.h>
BOOLEAN
CheckIrq(
PDEVICE_OBJECT DeviceObject)
{
/* PSOUND_BLASTER_PARAMETERS parameters = DeviceObject->DriverExtension;*/
/* TODO */
return TRUE;
}
BOOLEAN
ServiceSoundBlasterInterrupt(
IN PKINTERRUPT Interrupt,
IN PVOID Context)
{
DPRINT("* Processing ISR *\n");
return FALSE;
}
NTSTATUS
EnableIrq(
PDEVICE_OBJECT DeviceObject)
{
PSOUND_BLASTER_PARAMETERS parameters = DeviceObject->DeviceExtension;
ULONG vector;
KIRQL irq_level;
KAFFINITY affinity;
NTSTATUS status = STATUS_SUCCESS;
vector = HalGetInterruptVector(Isa,
0,
parameters->irq,
parameters->irq,
&irq_level,
&affinity);
DPRINT("Vector is 0x%x\n", vector);
status = IoConnectInterrupt(parameters->interrupt,
ServiceSoundBlasterInterrupt,
DeviceObject,
(PKSPIN_LOCK) NULL,
vector,
irq_level,
irq_level,
Latched, /* Latched / LevelSensitive */
FALSE, /* shareable */
affinity,
FALSE);
if ( status == STATUS_INVALID_PARAMETER )
status = STATUS_DEVICE_CONFIGURATION_ERROR;
return status;
}

View file

@ -0,0 +1,489 @@
/*
ReactOS
Sound Blaster driver
Programmers:
Andrew Greenwood
Notes:
Compatible with NT4
*/
#include <sndblst.h>
/*
IRP DISPATCH ROUTINES
*/
NTSTATUS STDCALL
CreateSoundBlaster(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension;
DPRINT("CreateSoundBlaster() called - extension 0x%x\n", sb_device);
EnableSpeaker(sb_device);
/*SetOutputSampleRate(sb_device, 22*/
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS STDCALL
CloseSoundBlaster(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension;
DPRINT("CloseSoundBlaster() called\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS STDCALL
CleanupSoundBlaster(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension;
DPRINT("CleanupSoundBlaster() called\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS STDCALL
ControlSoundBlaster(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PIO_STACK_LOCATION stack;
PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension;
DPRINT("ControlSoundBlaster() called\n");
stack = IoGetCurrentIrpStackLocation(Irp);
switch ( stack->Parameters.DeviceIoControl.IoControlCode)
{
/* TODO */
};
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS STDCALL
WriteSoundBlaster(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension;
DPRINT("WriteSoundBlaster() called\n");
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID STDCALL
UnloadSoundBlaster(
PDRIVER_OBJECT DriverObject)
{
DPRINT("Sound Blaster driver unload\n");
}
NTSTATUS STDCALL
OpenSubkey(
PUNICODE_STRING RegistryPath,
PWSTR Subkey,
ACCESS_MASK DesiredAccess,
OUT HANDLE* DevicesKeyHandle)
{
NTSTATUS status;
OBJECT_ATTRIBUTES attribs;
UNICODE_STRING subkey_name;
HANDLE key_handle;
/* TODO: Check for NULL ptr in DevicesKeyHandle */
InitializeObjectAttributes(&attribs,
RegistryPath,
OBJ_CASE_INSENSITIVE,
NULL,
(PSECURITY_DESCRIPTOR) NULL);
status = ZwOpenKey(&key_handle, KEY_READ, &attribs);
if ( ! NT_SUCCESS(status) )
{
DPRINT("Couldn't open subkey %wZ\n", Subkey);
return status;
}
RtlInitUnicodeString(&subkey_name, Subkey);
InitializeObjectAttributes(&attribs,
&subkey_name,
OBJ_CASE_INSENSITIVE,
key_handle,
(PSECURITY_DESCRIPTOR) NULL);
status = ZwOpenKey(*DevicesKeyHandle, DesiredAccess, &attribs);
ZwClose(key_handle);
return status;
}
PWSTR STDCALL
AllocateRegistryPathInfo(
PUNICODE_STRING BasePath,
PUNICODE_STRING ParametersPath,
PKEY_BASIC_INFORMATION KeyInfo)
{
PWSTR name;
PWSTR pos;
DPRINT("Allocating memory for path info\n");
name = ExAllocatePool(PagedPool,
BasePath->Length + sizeof(WCHAR) +
ParametersPath->Length + sizeof(WCHAR) +
KeyInfo->NameLength + sizeof(UNICODE_NULL));
if ( ! name )
return NULL;
DPRINT("Copying info\n");
pos = name;
RtlCopyMemory((PVOID)Pos, (PVOID)BasePath->Buffer, BasePath->Length);
pos += BasePath->Length / sizeof(WCHAR);
pos[0] = '\\';
pos ++;
RtlCopyMemory((PVOID)Pos, (PVOID)ParametersPath->Buffer, ParametersPath->Length);
pos += ParametersPath->Length / sizeof(WCHAR);
pos[0] = '\\';
pos ++;
RtlCopyMemory((PVOID)Pos, (PVOID)ParametersPath->Buffer, ParametersPath->Length);
pos += KeyInfo->NameLength / sizeof(WCHAR);
pos[0] = UNICODE_NULL;
DPRINT("All OK\n");
return name;
}
#define FreeRegistryPathInfo(ptr) \
ExFreePool(ptr)
#define TAG_REG_INFO (ULONG)'IgeR'
#define TAG_REG_NAME (ULONG)'NgeR'
NTSTATUS STDCALL
EnumerateSubkey(
PUNICODE_STRING RegistryPath,
PWSTR Subkey,
PREGISTRY_CALLBACK_ROUTINE Callback,
PDRIVER_OBJECT DriverObject)
{
NTSTATUS status;
UNICODE_STRING subkey_name;
HANDLE devices_key_handle;
ULONG key_index = 0;
ULONG result_length;
status = OpenSubkey(RegistryPath, Subkey, KEY_ENUMERATE_SUB_KEYS, &devices_key_handle);
if ( ! NT_SUCCESS(status) )
return status;
while ( TRUE )
{
KEY_BASIC_INFORMATION test_info;
PKEY_BASIC_INFORMATION info;
ULONG size;
PWSTR name;
status = ZwEnumerateKey(devices_key_handle,
key_index,
KeyBasicInformation,
&test_info,
sizeof(test_info),
&result_length);
if ( status == STATUS_NO_MORE_ENTRIES )
break;
size = result_length + FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
info = (PKEY_BASIC_INFORMATION) ExAllocatePoolWithTag(PagedPool, size, TAG_REG_INFO);
if ( ! info )
{
DPRINT("Out of memory\n");
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
status = ZwEnumerateKey(devices_key_handle,
key_index,
KeyBasicInformation,
info,
size,
&result_length);
if ( ! NT_SUCCESS(status) )
{
DPRINT("Unable to enumerate keys\n");
ExFreePoolWithTag(info, TAG_REG_INFO);
status = STATUS_INTERNAL_ERROR;
break;
}
/* Is this ok? */
RtlInitUnicodeString(&subkey_name, Subkey);
name = AllocateRegistryPathInfo(RegistryPath, &subkey_name, info);
if ( ! name )
{
DPRINT("Out of memory\n");
ExFreePoolWithTag(info, TAG_REG_INFO);
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
ExFreePoolWithTag(info, TAG_REG_INFO);
/* Call the callback */
status = Callback(DriverObject, name);
FreeRegistryPathInfo(name);
if ( ! NT_SUCCESS(status) )
{
DPRINT("Callback FAILED\n");
break;
}
key_index ++;
}
ZwClose(devices_key_handle);
DPRINT("Found %d subkey entries\n", key_index);
if ( ( key_index == 0 ) && ( status == STATUS_NO_MORE_ENTRIES ) )
return STATUS_DEVICE_CONFIGURATION_ERROR;
if ( status == STATUS_NO_MORE_ENTRIES )
status = STATUS_SUCCESS;
return status;
}
#define EnumerateDeviceKeys(path, callback, driver_obj) \
EnumerateSubkey(path, L"Devices", callback, driver_obj)
NTSTATUS
CreateDeviceName(
PCWSTR PrePrefix,
PCWSTR Prefix,
UCHAR Index,
PUNICODE_STRING DeviceName)
{
UNICODE_STRING number;
WCHAR number_buffer[5];
UNICODE_STRING unicode_pre_prefix;
UNICODE_STRING unicode_prefix;
ULONG size;
RtlInitUnicodeString(&unicode_pre_prefix, PrePrefix);
RtlInitUnicodeString(&unicode_prefix, Prefix);
size = unicode_pre_prefix.Length +
unicode_prefix.Length +
sizeof(number_buffer) +
sizeof(UNICODE_NULL);
DeviceName->Buffer = ExAllocatePool(PagedPool, size);
DeviceName->MaximumLength = (USHORT) size;
if ( ! DeviceName->Buffer )
return STATUS_INSUFFICIENT_RESOURCES;
RtlCopyUnicodeString(DeviceName, &unicode_pre_prefix);
RtlAppendUnicodeStringToString(DeviceName, &unicode_prefix);
if ( Index != 255 )
{
number.Buffer = number_buffer;
number.MaximumLength = sizeof(number_buffer);
RtlIntegerToUnicodeString((ULONG) Index, 10, &number);
RtlAppendUnicodeStringToString(DeviceName, &number);
}
DeviceName->Buffer[DeviceName->Length / sizeof(UNICODE_NULL)] = UNICODE_NULL;
return STATUS_SUCCESS;
}
NTSTATUS STDCALL
InitializeSoundBlaster(
PDRIVER_OBJECT DriverObject,
PWSTR RegistryPath)
{
NTSTATUS status;
PDEVICE_OBJECT device_object;
PSOUND_BLASTER_PARAMETERS parameters = NULL;
UNICODE_STRING device_name;
UNICODE_STRING dos_device_name;
UCHAR device_index = 0;
DPRINT("Initializing a Sound Blaster device\n");
/* Change these later */
status = CreateDeviceName(L"",
L"\\Device\\WaveOut",
device_index,
&device_name);
if ( ! NT_SUCCESS(status) )
return status;
status = CreateDeviceName(L"\\DosDevices\\",
L"\\Device\\WaveOut" + wcslen(L"\\Device\\"),
device_index,
&dos_device_name);
if ( ! NT_SUCCESS(status) )
{
/* TODO */
return status;
}
DPRINT("Device: %wZ\n", device_name);
DPRINT("Symlink: %wZ\n", dos_device_name);
/*
Create the device and DOS symlink
*/
status = IoCreateDevice(DriverObject,
sizeof(SOUND_BLASTER_PARAMETERS),
&device_name,
FILE_DEVICE_SOUND,
0,
FALSE,
&device_object);
if ( ! NT_SUCCESS(status) )
return status;
DPRINT("Created a device extension at 0x%x\n", device_object->DeviceExtension);
parameters = device_object->DeviceExtension;
status = IoCreateSymbolicLink(&dos_device_name, &device_name);
ExFreePool(dos_device_name.Buffer);
ExFreePool(device_name.Buffer);
if ( ! NT_SUCCESS(status) )
{
IoDeleteDevice(device_object);
device_object = NULL;
return status;
}
/* IoRegisterShutdownNotification( */
/*
Settings
*/
device_object->AlignmentRequirement = FILE_BYTE_ALIGNMENT;
parameters->driver = DriverObject;
parameters->registry_path = RegistryPath;
parameters->port = DEFAULT_PORT;
parameters->irq = DEFAULT_IRQ;
parameters->dma = DEFAULT_DMA;
parameters->buffer_size = DEFAULT_BUFFER_SIZE;
/* TODO: Load the settings from the registry */
DPRINT("Port %x IRQ %d DMA %d\n", parameters->port, parameters->irq, parameters->dma);
DPRINT("Resetting the sound card\n");
if ( ! ResetSoundBlaster(parameters) )
{
/* TODO */
return STATUS_UNSUCCESSFUL;
}
/*
DPRINT("What kind of SB card is this?\n");
GetSoundBlasterModel(parameters);
*/
return STATUS_SUCCESS;
}
NTSTATUS STDCALL
DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
DPRINT("Sound Blaster driver 0.1 by Silver Blade\n");
DriverObject->Flags = 0;
DriverObject->MajorFunction[IRP_MJ_CREATE] = CreateSoundBlaster;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseSoundBlaster;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CleanupSoundBlaster;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlSoundBlaster;
DriverObject->MajorFunction[IRP_MJ_WRITE] = WriteSoundBlaster;
DriverObject->DriverUnload = UnloadSoundBlaster;
DPRINT("Beginning device key enumeration\n");
status = EnumerateDeviceKeys(RegistryPath, *InitializeSoundBlaster, DriverObject);
return status;
}

View file

@ -0,0 +1,6 @@
;
; Exports definition file for sb16_ks.sys
;
EXPORTS
DriverEntry@8

View file

@ -0,0 +1,11 @@
<module name="sb16_nt4" type="exportdriver" installbase="system32/drivers" installname="sndblst.sys" allowwarnings="true">
<include base="sb16_nt4">.</include>
<include base="sb16_nt4">..</include>
<importlibrary definition="sb16_nt4.def" />
<library>ntoskrnl</library>
<library>hal</library>
<define name="__USE_W32API" />
<file>main.c</file>
<file>control.c</file>
<file>interrupt.c</file>
</module>

View file

@ -0,0 +1,155 @@
#ifndef SNDBLST_H
#define SNDBLST_H
#include <debug.h>
#include <ntddk.h>
#define SB_WAVE_IN_DEVICE_NAME L"\\Device\\SBWaveIn"
#define SB_WAVE_OUT_DEVICE_NAME L"\\Device\\SBWaveOut"
/* TODO: MIDI */
#define SB_AUX_DEVICE_NAME L"\\Device\\SBAux"
#define SB_MIXER_DEVICE_NAME L"\\Device\\SBMixer"
#define DEFAULT_PORT 0x220
#define DEFAULT_IRQ 5
#define DEFAULT_DMA 1
#define DEFAULT_BUFFER_SIZE 65535
#define SB_TIMEOUT 1000000
#define SB_DSP_READY 0xaa
enum
{
NotDetected,
SoundBlaster,
SoundBlasterPro,
SoundBlaster2,
SoundBlasterPro2,
SoundBlasterProMCV,
SoundBlaster16
};
enum
{
SB_RESET_PORT = 0x06,
SB_READ_DATA_PORT = 0x0a,
SB_WRITE_DATA_PORT = 0x0c,
SB_WRITE_STATUS_PORT = 0x0c,
SB_READ_STATUS_PORT = 0x0e
};
enum
{
SbAutoInitDmaOutput = 0x1c,
SbAutoInitDmaInput = 0x2c,
SbSetOutputRate = 0x41, /* DSP v4.xx */
SbSetInputRate = 0x42, /* DSP v4.xx */
SbSetBlockSize = 0x48, /* DSP v2.00 + */
SbPauseDac = 0x80,
SbPauseDmaOutput = 0xd0,
SbEnableSpeaker = 0xd1,
SbDisableSpeaker = 0xd3,
SbGetSpeakerStatus = 0xd8, /* DSP v2.00 + */
SbGetDspVersion = 0xe1
};
typedef struct _SOUND_BLASTER_PARAMETERS
{
PDRIVER_OBJECT driver;
PWSTR registry_path;
PKINTERRUPT interrupt;
ULONG port;
ULONG irq;
ULONG dma;
ULONG buffer_size;
USHORT dsp_version;
} SOUND_BLASTER_PARAMETERS, *PSOUND_BLASTER_PARAMETERS;
typedef STDCALL NTSTATUS REGISTRY_CALLBACK_ROUTINE(PDRIVER_OBJECT DriverObject, PWSTR RegistryPath);
typedef REGISTRY_CALLBACK_ROUTINE *PREGISTRY_CALLBACK_ROUTINE;
/*
Port I/O
*/
#define SbWrite(sbdevice, subport, data) \
WRITE_PORT_UCHAR((PUCHAR) sbdevice->port + subport, data)
#define SbRead(sbdevice, subport) \
READ_PORT_UCHAR((PUCHAR) sbdevice->port + subport)
#define SbWriteReset(sbdevice, data) \
SbWrite(sbdevice, SB_RESET_PORT, data)
#define SbWriteDataWithoutWait(sbdevice, data) \
SbWrite(sbdevice, SB_WRITE_DATA_PORT, data)
#define SbReadDataWithoutWait(sbdevice) \
SbRead(sbdevice, SB_READ_DATA_PORT)
#define SbGetWriteStatus(sbdevice) \
SbRead(sbdevice, SB_WRITE_STATUS_PORT)
#define SbGetReadStatus(sbdevice) \
SbRead(sbdevice, SB_READ_STATUS_PORT)
BOOLEAN
WaitForReady(
PSOUND_BLASTER_PARAMETERS SBDevice,
UCHAR Port);
#define WaitToWrite(sbdevice) \
WaitForReady(sbdevice, SB_WRITE_STATUS_PORT)
#define WaitToRead(sbdevice) \
WaitForReady(sbdevice, SB_READ_STATUS_PORT)
BOOLEAN
ResetSoundBlaster(
PSOUND_BLASTER_PARAMETERS SBDevice);
ULONG
GetSoundBlasterModel(
PSOUND_BLASTER_PARAMETERS SBDevice);
BOOLEAN
IsSampleRateCompatible(
PSOUND_BLASTER_PARAMETERS SBDevice,
ULONG SampleRate);
BOOLEAN
SetOutputSampleRate(
PSOUND_BLASTER_PARAMETERS SBDevice,
ULONG SampleRate);
BOOLEAN
EnableSpeaker(
PSOUND_BLASTER_PARAMETERS SBDevice);
BOOLEAN
DisableSpeaker(
PSOUND_BLASTER_PARAMETERS SBDevice);
BOOLEAN
StartSoundOutput(
PSOUND_BLASTER_PARAMETERS SBDevice,
ULONG BitDepth,
ULONG Channels,
ULONG BlockSize);
/*
interrupt.c
*/
NTSTATUS
EnableIrq(
PDEVICE_OBJECT DeviceObject);
#endif

View file

@ -0,0 +1,62 @@
/*
"Unknown" implementation, in C
by Andrew Greenwood
Not quite sure how this is used, but the C++ variant is intended for
implementing a NonDelegatingUnknown object
*/
#include <stdunk.h>
STDMETHODCALLTYPE
NTSTATUS
Unknown_QueryInterface(
IUnknown* this,
IN REFIID refiid,
OUT PVOID* output)
{
/* TODO */
return STATUS_SUCCESS;
}
STDMETHODCALLTYPE
ULONG
Unknown_AddRef(
IUnknown* unknown_this)
{
struct CUnknown* this = CONTAINING_RECORD(unknown_this, struct CUnknown, IUnknown);
InterlockedIncrement(&this->m_ref_count);
return this->m_ref_count;
}
STDMETHODCALLTYPE
ULONG
Unknown_Release(
IUnknown* unknown_this)
{
struct CUnknown* this = CONTAINING_RECORD(unknown_this, struct CUnknown, IUnknown);
InterlockedDecrement(&this->m_ref_count);
if ( this->m_ref_count == 0 )
{
ExFreePool(this);
return 0;
}
return this->m_ref_count;
}
/*
The vtable for Unknown
*/
const IUnknownVtbl UnknownVtbl =
{
Unknown_QueryInterface,
Unknown_AddRef,
Unknown_Release
};

View file

@ -0,0 +1,98 @@
/*
TODO:
Need to call ASSERT on m_ref_count to ensure it is valid.
*/
#define PUT_GUIDS_HERE
//#include <portcls.h>
#include <punknown.h>
#include <stdunk.h>
#include <ntddk.h>
/*
HACK ALERT
This is a little bit of a hack, but ReactOS doesn't seem to have this
defined. TODO: Make the aligned test truly aligned.
*/
#define IsEqualGUID(a, b) \
RtlEqualMemory(&a, &b, sizeof(GUID))
#define IsEqualGUIDAligned(a, b) \
IsEqualGUID(a, b)
/*
Shut the linker up - can also pass -defsym ___cxa_pure_virtual=0
*/
extern "C" void __cxa_pure_virtual(void) {}
/*
IUnknown
*/
CUnknown::CUnknown(PUNKNOWN outer_unknown)
{
m_ref_count = 0;
if ( outer_unknown )
{
m_outer_unknown = outer_unknown;
}
else
{
m_outer_unknown = PUNKNOWN(dynamic_cast<PNONDELEGATINGUNKNOWN>(this));
}
}
CUnknown::~CUnknown()
{
}
/*
INonDelegatingUnknown
*/
STDMETHODIMP_(ULONG)
CUnknown::NonDelegatingAddRef(void)
{
InterlockedIncrement(&m_ref_count);
return m_ref_count;
}
STDMETHODIMP_(ULONG)
CUnknown::NonDelegatingRelease(void)
{
if ( InterlockedDecrement(&m_ref_count) == 0 )
{
delete this;
return 0;
}
return m_ref_count;
}
STDMETHODIMP_(NTSTATUS)
CUnknown::NonDelegatingQueryInterface(
IN REFIID iid,
IN PVOID* ppvoid)
{
//if ( RtlEqualMemory(&iid, &IID_IUnknown, sizeof(GUID)) )
{
*ppvoid = (PVOID)((PUNKNOWN) this);
}
// else
{
*ppvoid = NULL;
}
if ( *ppvoid )
{
((PUNKNOWN)(*ppvoid))->AddRef();
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}