Start to implement a basic emulated PC speaker, using the Beep driver.

svn path=/branches/ntvdm/; revision=60853
This commit is contained in:
Hermès Bélusca-Maïto 2013-11-03 20:31:19 +00:00
parent 6ecc2dfd24
commit e9f8b230a6
8 changed files with 218 additions and 1 deletions

View file

@ -12,6 +12,7 @@ list(APPEND SOURCE
registers.c
timer.c
ps2.c
speaker.c
vga.c
ntvdm.c
ntvdm.rc

View file

@ -14,6 +14,7 @@
#include "bios.h"
#include "bop.h"
#include "dos.h"
#include "speaker.h"
#include "vga.h"
#include "pic.h"
#include "ps2.h"
@ -125,6 +126,12 @@ static VOID WINAPI EmulatorReadIo(PFAST486_STATE State, ULONG Port, PVOID Buffer
break;
}
case SPEAKER_CONTROL_PORT:
{
*(Address++) = SpeakerReadStatus();
break;
}
case VGA_AC_WRITE:
case VGA_AC_READ:
case VGA_SEQ_INDEX:
@ -204,6 +211,12 @@ static VOID WINAPI EmulatorWriteIo(PFAST486_STATE State, ULONG Port, PVOID Buffe
break;
}
case SPEAKER_CONTROL_PORT:
{
SpeakerWriteCommand(*(Address++));
break;
}
case VGA_AC_WRITE:
case VGA_AC_READ:
case VGA_SEQ_INDEX:

View file

@ -13,6 +13,7 @@
#include "ntvdm.h"
#include "emulator.h"
#include "bios.h"
#include "speaker.h"
#include "vga.h"
#include "dos.h"
#include "timer.h"
@ -117,6 +118,9 @@ INT wmain(INT argc, WCHAR *argv[])
goto Cleanup;
}
/* Initialize the PC Speaker */
SpeakerInitialize();
/* Initialize the VDM DOS kernel */
if (!DosInitialize())
{
@ -133,7 +137,7 @@ INT wmain(INT argc, WCHAR *argv[])
/* Start the input thread */
InputThread = CreateThread(NULL, 0, &InputThreadProc, NULL, 0, NULL);
/* Set the last timer tick to the current time */
QueryPerformanceCounter(&LastTimerTick);
@ -187,6 +191,7 @@ INT wmain(INT argc, WCHAR *argv[])
Cleanup:
if (InputThread != NULL) CloseHandle(InputThread);
SpeakerCleanup();
BiosCleanup();
EmulatorCleanup();

View file

@ -15,6 +15,7 @@
#include <stdarg.h>
#include <conio.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <debug.h>

165
subsystems/ntvdm/speaker.c Normal file
View file

@ -0,0 +1,165 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: speaker.c
* PURPOSE: PC Speaker emulation
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "speaker.h"
#include "emulator.h"
#include "timer.h"
/* Extra PSDK/NDK Headers */
#include <ndk/iofuncs.h>
#include <ndk/obfuncs.h>
#include <ndk/rtlfuncs.h>
/* DDK Driver Headers */
#include <ntddbeep.h>
/* PRIVATE VARIABLES **********************************************************/
static BYTE Port61hState = 0x00;
HANDLE hBeep = NULL;
/* PUBLIC FUNCTIONS ***********************************************************/
VOID SpeakerInitialize(VOID)
{
NTSTATUS Status;
UNICODE_STRING BeepDevice;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
/* Adapted from kernel32:Beep() */
//
// On TS systems, we need to Load Winsta.dll and call WinstationBeepOpen
// after doing a GetProcAddress for it
//
/* Open the device */
RtlInitUnicodeString(&BeepDevice, L"\\Device\\Beep");
InitializeObjectAttributes(&ObjectAttributes, &BeepDevice, 0, NULL, NULL);
Status = NtCreateFile(&hBeep,
FILE_READ_DATA | FILE_WRITE_DATA,
&ObjectAttributes,
&IoStatusBlock,
NULL,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
0,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to open Beep driver, Status 0x%08lx\n", Status);
}
}
VOID SpeakerCleanup(VOID)
{
NtClose(hBeep);
}
BYTE SpeakerReadStatus(VOID)
{
// DPRINT1("SpeakerReadStatus() == 0x%x\n", Port61hState);
return Port61hState;
}
VOID SpeakerWriteCommand(BYTE Value)
{
BOOLEAN IsConnectedToPITChannel2;
UCHAR SpeakerData;
// DPRINT1("SpeakerWriteCommand(0x%x)\n", Value);
Port61hState = Value;
IsConnectedToPITChannel2 = ((Port61hState & 0x01) != 0);
SpeakerData = (Port61hState & 0x02);
if (PitChannel2 && IsConnectedToPITChannel2)
{
/* Set bit 5 of Port 61h */
Port61hState |= 1 << 5;
}
else
{
/* Clear bit 5 of Port 61h */
Port61hState &= ~(1 << 5);
}
if (PitChannel2 && IsConnectedToPITChannel2 && (SpeakerData != 0))
{
/* Start beeping - Adapted from kernel32:Beep() */
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
BEEP_SET_PARAMETERS BeepSetParameters;
DWORD PitChannel2ReloadValue = PitChannel2->ReloadValue;
if (PitChannel2ReloadValue == 0) PitChannel2ReloadValue = 65536;
/* Set beep data */
BeepSetParameters.Frequency = (PIT_BASE_FREQUENCY / PitChannel2ReloadValue) *
(PitChannel2->Mode == PIT_MODE_SQUARE_WAVE ? 2 : 1);
BeepSetParameters.Duration = INFINITE;
/* Send the beep */
Status = NtDeviceIoControlFile(hBeep,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_BEEP_SET,
&BeepSetParameters,
sizeof(BeepSetParameters),
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("Beep (%lu, %lu) failed, Status 0x%08lx\n",
BeepSetParameters.Frequency,
BeepSetParameters.Duration,
Status);
}
}
else
{
/* Stop beeping */
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
BEEP_SET_PARAMETERS BeepSetParameters;
/* Set beep data */
BeepSetParameters.Frequency = 0x00;
BeepSetParameters.Duration = 0x00;
/* Send the beep */
Status = NtDeviceIoControlFile(hBeep,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_BEEP_SET,
&BeepSetParameters,
sizeof(BeepSetParameters),
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("Beep (%lu, %lu) failed, Status 0x%08lx\n",
BeepSetParameters.Frequency,
BeepSetParameters.Duration,
Status);
}
}
}
/* EOF */

View file

@ -0,0 +1,29 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: speaker.h
* PURPOSE: PC Speaker emulation
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
#ifndef _SPEAKER_H_
#define _SPEAKER_H_
/* INCLUDES *******************************************************************/
#include "ntvdm.h"
/* DEFINES ********************************************************************/
#define SPEAKER_CONTROL_PORT 0x61
/* FUNCTIONS ******************************************************************/
VOID SpeakerInitialize(VOID);
VOID SpeakerCleanup(VOID);
BYTE SpeakerReadStatus(VOID);
VOID SpeakerWriteCommand(BYTE Value);
#endif // _SPEAKER_H_
/* EOF */

View file

@ -16,6 +16,7 @@
/* PRIVATE VARIABLES **********************************************************/
static PIT_CHANNEL PitChannels[PIT_CHANNELS];
PPIT_CHANNEL PitChannel2 = &PitChannels[2];
/* PUBLIC FUNCTIONS ***********************************************************/

View file

@ -43,6 +43,8 @@ typedef struct _PIT_CHANNEL
BYTE AccessMode;
} PIT_CHANNEL, *PPIT_CHANNEL;
extern PPIT_CHANNEL PitChannel2; // Needed for PC Speaker
/* FUNCTIONS ******************************************************************/
VOID PitWriteCommand(BYTE Value);